Skip to content

Commit 2bbc694

Browse files
Ram Paijbarnes993
authored andcommitted
PCI : ability to relocate assigned pci-resources
Currently pci-bridges are allocated enough resources to satisfy their immediate requirements. Any additional resource-requests fail if additional free space, contiguous to the one already allocated, is not available. This behavior is not reasonable since sufficient contiguous resources, that can satisfy the request, are available at a different location. This patch provides the ability to expand and relocate a allocated resource. v2: Changelog: Fixed size calculation in pci_reassign_resource() v3: Changelog : Split this patch. The resource.c changes are already upstream. All the pci driver changes are in here. Signed-off-by: Ram Pai <[email protected]> Signed-off-by: Jesse Barnes <[email protected]>
1 parent be76891 commit 2bbc694

File tree

3 files changed

+113
-67
lines changed

3 files changed

+113
-67
lines changed

drivers/pci/setup-bus.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ struct resource_list_x {
3434
resource_size_t start;
3535
resource_size_t end;
3636
resource_size_t add_size;
37+
resource_size_t min_align;
3738
unsigned long flags;
3839
};
3940

@@ -65,7 +66,7 @@ void pci_realloc(void)
6566
*/
6667
static void add_to_list(struct resource_list_x *head,
6768
struct pci_dev *dev, struct resource *res,
68-
resource_size_t add_size)
69+
resource_size_t add_size, resource_size_t min_align)
6970
{
7071
struct resource_list_x *list = head;
7172
struct resource_list_x *ln = list->next;
@@ -84,13 +85,16 @@ static void add_to_list(struct resource_list_x *head,
8485
tmp->end = res->end;
8586
tmp->flags = res->flags;
8687
tmp->add_size = add_size;
88+
tmp->min_align = min_align;
8789
list->next = tmp;
8890
}
8991

9092
static void add_to_failed_list(struct resource_list_x *head,
9193
struct pci_dev *dev, struct resource *res)
9294
{
93-
add_to_list(head, dev, res, 0);
95+
add_to_list(head, dev, res,
96+
0 /* dont care */,
97+
0 /* dont care */);
9498
}
9599

96100
static void __dev_sort_resources(struct pci_dev *dev,
@@ -159,13 +163,16 @@ static void adjust_resources_sorted(struct resource_list_x *add_head,
159163

160164
idx = res - &list->dev->resource[0];
161165
add_size=list->add_size;
162-
if (!resource_size(res) && add_size) {
163-
res->end = res->start + add_size - 1;
164-
if(pci_assign_resource(list->dev, idx))
166+
if (!resource_size(res)) {
167+
res->end = res->start + add_size - 1;
168+
if(pci_assign_resource(list->dev, idx))
165169
reset_resource(res);
166-
} else if (add_size) {
167-
adjust_resource(res, res->start,
168-
resource_size(res) + add_size);
170+
} else {
171+
resource_size_t align = list->min_align;
172+
res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
173+
if (pci_reassign_resource(list->dev, idx, add_size, align))
174+
dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n",
175+
res);
169176
}
170177
out:
171178
tmp = list;
@@ -619,7 +626,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
619626
b_res->end = b_res->start + size0 - 1;
620627
b_res->flags |= IORESOURCE_STARTALIGN;
621628
if (size1 > size0 && add_head)
622-
add_to_list(add_head, bus->self, b_res, size1-size0);
629+
add_to_list(add_head, bus->self, b_res, size1-size0, 4096);
623630
}
624631

625632
/**
@@ -722,7 +729,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
722729
b_res->end = size0 + min_align - 1;
723730
b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask;
724731
if (size1 > size0 && add_head)
725-
add_to_list(add_head, bus->self, b_res, size1-size0);
732+
add_to_list(add_head, bus->self, b_res, size1-size0, min_align);
726733
return 1;
727734
}
728735

drivers/pci/setup-res.c

Lines changed: 95 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -128,16 +128,16 @@ void pci_disable_bridge_window(struct pci_dev *dev)
128128
}
129129
#endif /* CONFIG_PCI_QUIRKS */
130130

131+
132+
131133
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
132-
int resno)
134+
int resno, resource_size_t size, resource_size_t align)
133135
{
134136
struct resource *res = dev->resource + resno;
135-
resource_size_t size, min, align;
137+
resource_size_t min;
136138
int ret;
137139

138-
size = resource_size(res);
139140
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
140-
align = pci_resource_alignment(dev, res);
141141

142142
/* First, try exact prefetching match.. */
143143
ret = pci_bus_alloc_resource(bus, res, size, align, min,
@@ -154,56 +154,101 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
154154
ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
155155
pcibios_align_resource, dev);
156156
}
157+
return ret;
158+
}
157159

158-
if (ret < 0 && dev->fw_addr[resno]) {
159-
struct resource *root, *conflict;
160-
resource_size_t start, end;
160+
static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
161+
int resno, resource_size_t size)
162+
{
163+
struct resource *root, *conflict;
164+
resource_size_t start, end;
165+
int ret = 0;
161166

162-
/*
163-
* If we failed to assign anything, let's try the address
164-
* where firmware left it. That at least has a chance of
165-
* working, which is better than just leaving it disabled.
166-
*/
167+
if (res->flags & IORESOURCE_IO)
168+
root = &ioport_resource;
169+
else
170+
root = &iomem_resource;
171+
172+
start = res->start;
173+
end = res->end;
174+
res->start = dev->fw_addr[resno];
175+
res->end = res->start + size - 1;
176+
dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
177+
resno, res);
178+
conflict = request_resource_conflict(root, res);
179+
if (conflict) {
180+
dev_info(&dev->dev,
181+
"BAR %d: %pR conflicts with %s %pR\n", resno,
182+
res, conflict->name, conflict);
183+
res->start = start;
184+
res->end = end;
185+
ret = 1;
186+
}
187+
return ret;
188+
}
189+
190+
static int _pci_assign_resource(struct pci_dev *dev, int resno, int size, resource_size_t min_align)
191+
{
192+
struct resource *res = dev->resource + resno;
193+
struct pci_bus *bus;
194+
int ret;
195+
char *type;
167196

168-
if (res->flags & IORESOURCE_IO)
169-
root = &ioport_resource;
197+
bus = dev->bus;
198+
while ((ret = __pci_assign_resource(bus, dev, resno, size, min_align))) {
199+
if (!bus->parent || !bus->self->transparent)
200+
break;
201+
bus = bus->parent;
202+
}
203+
204+
if (ret) {
205+
if (res->flags & IORESOURCE_MEM)
206+
if (res->flags & IORESOURCE_PREFETCH)
207+
type = "mem pref";
208+
else
209+
type = "mem";
210+
else if (res->flags & IORESOURCE_IO)
211+
type = "io";
170212
else
171-
root = &iomem_resource;
172-
173-
start = res->start;
174-
end = res->end;
175-
res->start = dev->fw_addr[resno];
176-
res->end = res->start + size - 1;
177-
dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
178-
resno, res);
179-
conflict = request_resource_conflict(root, res);
180-
if (conflict) {
181-
dev_info(&dev->dev,
182-
"BAR %d: %pR conflicts with %s %pR\n", resno,
183-
res, conflict->name, conflict);
184-
res->start = start;
185-
res->end = end;
186-
} else
187-
ret = 0;
213+
type = "unknown";
214+
dev_info(&dev->dev,
215+
"BAR %d: can't assign %s (size %#llx)\n",
216+
resno, type, (unsigned long long) resource_size(res));
188217
}
189218

219+
return ret;
220+
}
221+
222+
int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsize,
223+
resource_size_t min_align)
224+
{
225+
struct resource *res = dev->resource + resno;
226+
resource_size_t new_size;
227+
int ret;
228+
229+
if (!res->parent) {
230+
dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resouce %pR "
231+
"\n", resno, res);
232+
return -EINVAL;
233+
}
234+
235+
new_size = resource_size(res) + addsize + min_align;
236+
ret = _pci_assign_resource(dev, resno, new_size, min_align);
190237
if (!ret) {
191238
res->flags &= ~IORESOURCE_STARTALIGN;
192239
dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
193240
if (resno < PCI_BRIDGE_RESOURCES)
194241
pci_update_resource(dev, resno);
195242
}
196-
197243
return ret;
198244
}
199245

200246
int pci_assign_resource(struct pci_dev *dev, int resno)
201247
{
202248
struct resource *res = dev->resource + resno;
203-
resource_size_t align;
249+
resource_size_t align, size;
204250
struct pci_bus *bus;
205251
int ret;
206-
char *type;
207252

208253
align = pci_resource_alignment(dev, res);
209254
if (!align) {
@@ -213,34 +258,27 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
213258
}
214259

215260
bus = dev->bus;
216-
while ((ret = __pci_assign_resource(bus, dev, resno))) {
217-
if (bus->parent && bus->self->transparent)
218-
bus = bus->parent;
219-
else
220-
bus = NULL;
221-
if (bus)
222-
continue;
223-
break;
224-
}
261+
size = resource_size(res);
262+
ret = _pci_assign_resource(dev, resno, size, align);
225263

226-
if (ret) {
227-
if (res->flags & IORESOURCE_MEM)
228-
if (res->flags & IORESOURCE_PREFETCH)
229-
type = "mem pref";
230-
else
231-
type = "mem";
232-
else if (res->flags & IORESOURCE_IO)
233-
type = "io";
234-
else
235-
type = "unknown";
236-
dev_info(&dev->dev,
237-
"BAR %d: can't assign %s (size %#llx)\n",
238-
resno, type, (unsigned long long) resource_size(res));
239-
}
264+
/*
265+
* If we failed to assign anything, let's try the address
266+
* where firmware left it. That at least has a chance of
267+
* working, which is better than just leaving it disabled.
268+
*/
269+
if (ret < 0 && dev->fw_addr[resno])
270+
ret = pci_revert_fw_address(res, dev, resno, size);
240271

272+
if (!ret) {
273+
res->flags &= ~IORESOURCE_STARTALIGN;
274+
dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
275+
if (resno < PCI_BRIDGE_RESOURCES)
276+
pci_update_resource(dev, resno);
277+
}
241278
return ret;
242279
}
243280

281+
244282
/* Sort resources by alignment */
245283
void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
246284
{

include/linux/pci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,7 @@ int __pci_reset_function(struct pci_dev *dev);
813813
int pci_reset_function(struct pci_dev *dev);
814814
void pci_update_resource(struct pci_dev *dev, int resno);
815815
int __must_check pci_assign_resource(struct pci_dev *dev, int i);
816+
int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align);
816817
int pci_select_bars(struct pci_dev *dev, unsigned long flags);
817818

818819
/* ROM control related routines */

0 commit comments

Comments
 (0)