Skip to content

Commit

Permalink
Merge tag 'pci-v3.19-fixes-1' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/helgaas/pci

Pull PCI fixes from Bjorn Helgaas:
 "These are fixes for:

   - a resource management problem that causes a Radeon "Fatal error
     during GPU init" on machines where the BIOS programmed an invalid
     Root Port window.  This was a regression in v3.16.

   - an Atheros AR93xx device that doesn't handle PCI bus resets
     correctly.  This was a regression in v3.14.

   - an out-of-date email address"

* tag 'pci-v3.19-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
  MAINTAINERS: Update Richard Zhu's email address
  sparc/PCI: Clip bridge windows to fit in upstream windows
  powerpc/PCI: Clip bridge windows to fit in upstream windows
  parisc/PCI: Clip bridge windows to fit in upstream windows
  mn10300/PCI: Clip bridge windows to fit in upstream windows
  microblaze/PCI: Clip bridge windows to fit in upstream windows
  ia64/PCI: Clip bridge windows to fit in upstream windows
  frv/PCI: Clip bridge windows to fit in upstream windows
  alpha/PCI: Clip bridge windows to fit in upstream windows
  x86/PCI: Clip bridge windows to fit in upstream windows
  PCI: Add pci_claim_bridge_resource() to clip window if necessary
  PCI: Add pci_bus_clip_resource() to clip to fit upstream window
  PCI: Pass bridge device, not bus, when updating bridge windows
  PCI: Mark Atheros AR93xx to avoid bus reset
  PCI: Add flag for devices where we can't use bus reset
  • Loading branch information
torvalds committed Jan 23, 2015
2 parents b8de08d + f175aa2 commit 5506959
Show file tree
Hide file tree
Showing 17 changed files with 222 additions and 81 deletions.
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -7274,7 +7274,7 @@ S: Maintained
F: drivers/pci/host/*layerscape*

PCI DRIVER FOR IMX6
M: Richard Zhu <r65037@freescale.com>
M: Richard Zhu <Richard.Zhu@freescale.com>
M: Lucas Stach <[email protected]>
L: [email protected]
L: [email protected] (moderated for non-subscribers)
Expand Down
8 changes: 6 additions & 2 deletions arch/alpha/kernel/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,12 @@ pcibios_claim_one_bus(struct pci_bus *b)
if (r->parent || !r->start || !r->flags)
continue;
if (pci_has_flag(PCI_PROBE_ONLY) ||
(r->flags & IORESOURCE_PCI_FIXED))
pci_claim_resource(dev, i);
(r->flags & IORESOURCE_PCI_FIXED)) {
if (pci_claim_resource(dev, i) == 0)
continue;

pci_claim_bridge_resource(dev, i);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion arch/frv/mb93090-mb00/pci-frv.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
r = &dev->resource[idx];
if (!r->start)
continue;
pci_claim_resource(dev, idx);
pci_claim_bridge_resource(dev, idx);
}
}
pcibios_allocate_bus_resources(&bus->children);
Expand Down
48 changes: 21 additions & 27 deletions arch/ia64/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,45 +487,39 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
return 0;
}

static int is_valid_resource(struct pci_dev *dev, int idx)
void pcibios_fixup_device_resources(struct pci_dev *dev)
{
unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
struct resource *devr = &dev->resource[idx], *busr;
int idx;

if (!dev->bus)
return 0;

pci_bus_for_each_resource(dev->bus, busr, i) {
if (!busr || ((busr->flags ^ devr->flags) & type_mask))
continue;
if ((devr->start) && (devr->start >= busr->start) &&
(devr->end <= busr->end))
return 1;
}
return 0;
}
return;

static void pcibios_fixup_resources(struct pci_dev *dev, int start, int limit)
{
int i;
for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) {
struct resource *r = &dev->resource[idx];

for (i = start; i < limit; i++) {
if (!dev->resource[i].flags)
if (!r->flags || r->parent || !r->start)
continue;
if ((is_valid_resource(dev, i)))
pci_claim_resource(dev, i);
}
}

void pcibios_fixup_device_resources(struct pci_dev *dev)
{
pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES);
pci_claim_resource(dev, idx);
}
}
EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources);

static void pcibios_fixup_bridge_resources(struct pci_dev *dev)
{
pcibios_fixup_resources(dev, PCI_BRIDGE_RESOURCES, PCI_NUM_RESOURCES);
int idx;

if (!dev->bus)
return;

for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
struct resource *r = &dev->resource[idx];

if (!r->flags || r->parent || !r->start)
continue;

pci_claim_bridge_resource(dev, idx);
}
}

/*
Expand Down
13 changes: 12 additions & 1 deletion arch/microblaze/pci/pci-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
pr, (pr && pr->name) ? pr->name : "nil");

if (pr && !(pr->flags & IORESOURCE_UNSET)) {
struct pci_dev *dev = bus->self;

if (request_resource(pr, res) == 0)
continue;
/*
Expand All @@ -1035,6 +1037,12 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
*/
if (reparent_resources(pr, res) == 0)
continue;

if (dev && i < PCI_BRIDGE_RESOURCE_NUM &&
pci_claim_bridge_resource(dev,
i + PCI_BRIDGE_RESOURCES) == 0)
continue;

}
pr_warn("PCI: Cannot allocate resource region ");
pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number);
Expand Down Expand Up @@ -1227,7 +1235,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus)
(unsigned long long)r->end,
(unsigned int)r->flags);

pci_claim_resource(dev, i);
if (pci_claim_resource(dev, i) == 0)
continue;

pci_claim_bridge_resource(dev, i);
}
}

Expand Down
2 changes: 1 addition & 1 deletion arch/mn10300/unit-asb2305/pci-asb2305.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
if (!r->flags)
continue;
if (!r->start ||
pci_claim_resource(dev, idx) < 0) {
pci_claim_bridge_resource(dev, idx) < 0) {
printk(KERN_ERR "PCI:"
" Cannot allocate resource"
" region %d of bridge %s\n",
Expand Down
47 changes: 21 additions & 26 deletions arch/mn10300/unit-asb2305/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,42 +281,37 @@ static int __init pci_check_direct(void)
return -ENODEV;
}

static int is_valid_resource(struct pci_dev *dev, int idx)
static void pcibios_fixup_device_resources(struct pci_dev *dev)
{
unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
struct resource *devr = &dev->resource[idx], *busr;

if (dev->bus) {
pci_bus_for_each_resource(dev->bus, busr, i) {
if (!busr || (busr->flags ^ devr->flags) & type_mask)
continue;

if (devr->start &&
devr->start >= busr->start &&
devr->end <= busr->end)
return 1;
}
}
int idx;

return 0;
if (!dev->bus)
return;

for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) {
struct resource *r = &dev->resource[idx];

if (!r->flags || r->parent || !r->start)
continue;

pci_claim_resource(dev, idx);
}
}

static void pcibios_fixup_device_resources(struct pci_dev *dev)
static void pcibios_fixup_bridge_resources(struct pci_dev *dev)
{
int limit, i;
int idx;

if (dev->bus->number != 0)
if (!dev->bus)
return;

limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ?
PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES;
for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
struct resource *r = &dev->resource[idx];

for (i = 0; i < limit; i++) {
if (!dev->resource[i].flags)
if (!r->flags || r->parent || !r->start)
continue;

if (is_valid_resource(dev, i))
pci_claim_resource(dev, i);
pci_claim_bridge_resource(dev, idx);
}
}

Expand All @@ -330,7 +325,7 @@ void pcibios_fixup_bus(struct pci_bus *bus)

if (bus->self) {
pci_read_bridge_bases(bus);
pcibios_fixup_device_resources(bus->self);
pcibios_fixup_bridge_resources(bus->self);
}

list_for_each_entry(dev, &bus->devices, bus_list)
Expand Down
12 changes: 11 additions & 1 deletion arch/powerpc/kernel/pci-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
pr, (pr && pr->name) ? pr->name : "nil");

if (pr && !(pr->flags & IORESOURCE_UNSET)) {
struct pci_dev *dev = bus->self;

if (request_resource(pr, res) == 0)
continue;
/*
Expand All @@ -1193,6 +1195,11 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
*/
if (reparent_resources(pr, res) == 0)
continue;

if (dev && i < PCI_BRIDGE_RESOURCE_NUM &&
pci_claim_bridge_resource(dev,
i + PCI_BRIDGE_RESOURCES) == 0)
continue;
}
pr_warning("PCI: Cannot allocate resource region "
"%d of PCI bridge %d, will remap\n", i, bus->number);
Expand Down Expand Up @@ -1401,7 +1408,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus)
(unsigned long long)r->end,
(unsigned int)r->flags);

pci_claim_resource(dev, i);
if (pci_claim_resource(dev, i) == 0)
continue;

pci_claim_bridge_resource(dev, i);
}
}

Expand Down
5 changes: 4 additions & 1 deletion arch/sparc/kernel/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,10 @@ static void pci_claim_bus_resources(struct pci_bus *bus)
(unsigned long long)r->end,
(unsigned int)r->flags);

pci_claim_resource(dev, i);
if (pci_claim_resource(dev, i) == 0)
continue;

pci_claim_bridge_resource(dev, i);
}
}

Expand Down
2 changes: 1 addition & 1 deletion arch/x86/pci/i386.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
continue;
if (r->parent) /* Already allocated */
continue;
if (!r->start || pci_claim_resource(dev, idx) < 0) {
if (!r->start || pci_claim_bridge_resource(dev, idx) < 0) {
/*
* Something is wrong with the region.
* Invalidate the resource to prevent
Expand Down
5 changes: 2 additions & 3 deletions drivers/parisc/lba_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -694,9 +694,8 @@ lba_fixup_bus(struct pci_bus *bus)
int i;
/* PCI-PCI Bridge */
pci_read_bridge_bases(bus);
for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
pci_claim_resource(bus->self, i);
}
for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++)
pci_claim_bridge_resource(bus->self, i);
} else {
/* Host-PCI Bridge */
int err;
Expand Down
43 changes: 43 additions & 0 deletions drivers/pci/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,49 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
}
EXPORT_SYMBOL(pci_bus_alloc_resource);

/*
* The @idx resource of @dev should be a PCI-PCI bridge window. If this
* resource fits inside a window of an upstream bridge, do nothing. If it
* overlaps an upstream window but extends outside it, clip the resource so
* it fits completely inside.
*/
bool pci_bus_clip_resource(struct pci_dev *dev, int idx)
{
struct pci_bus *bus = dev->bus;
struct resource *res = &dev->resource[idx];
struct resource orig_res = *res;
struct resource *r;
int i;

pci_bus_for_each_resource(bus, r, i) {
resource_size_t start, end;

if (!r)
continue;

if (resource_type(res) != resource_type(r))
continue;

start = max(r->start, res->start);
end = min(r->end, res->end);

if (start > end)
continue; /* no overlap */

if (res->start == start && res->end == end)
return false; /* no change */

res->start = start;
res->end = end;
dev_printk(KERN_DEBUG, &dev->dev, "%pR clipped to %pR\n",
&orig_res, res);

return true;
}

return false;
}

void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }

/**
Expand Down
Loading

0 comments on commit 5506959

Please sign in to comment.