Commit 55069592 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pci-v3.19-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/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
parents b8de08da f175aa2c
...@@ -7274,7 +7274,7 @@ S: Maintained ...@@ -7274,7 +7274,7 @@ S: Maintained
F: drivers/pci/host/*layerscape* F: drivers/pci/host/*layerscape*
PCI DRIVER FOR IMX6 PCI DRIVER FOR IMX6
M: Richard Zhu <r65037@freescale.com> M: Richard Zhu <Richard.Zhu@freescale.com>
M: Lucas Stach <l.stach@pengutronix.de> M: Lucas Stach <l.stach@pengutronix.de>
L: linux-pci@vger.kernel.org L: linux-pci@vger.kernel.org
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
......
...@@ -285,8 +285,12 @@ pcibios_claim_one_bus(struct pci_bus *b) ...@@ -285,8 +285,12 @@ pcibios_claim_one_bus(struct pci_bus *b)
if (r->parent || !r->start || !r->flags) if (r->parent || !r->start || !r->flags)
continue; continue;
if (pci_has_flag(PCI_PROBE_ONLY) || if (pci_has_flag(PCI_PROBE_ONLY) ||
(r->flags & IORESOURCE_PCI_FIXED)) (r->flags & IORESOURCE_PCI_FIXED)) {
pci_claim_resource(dev, i); if (pci_claim_resource(dev, i) == 0)
continue;
pci_claim_bridge_resource(dev, i);
}
} }
} }
......
...@@ -94,7 +94,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) ...@@ -94,7 +94,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
r = &dev->resource[idx]; r = &dev->resource[idx];
if (!r->start) if (!r->start)
continue; continue;
pci_claim_resource(dev, idx); pci_claim_bridge_resource(dev, idx);
} }
} }
pcibios_allocate_bus_resources(&bus->children); pcibios_allocate_bus_resources(&bus->children);
......
...@@ -487,45 +487,39 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) ...@@ -487,45 +487,39 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
return 0; 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; int idx;
struct resource *devr = &dev->resource[idx], *busr;
if (!dev->bus) if (!dev->bus)
return 0; return;
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;
}
static void pcibios_fixup_resources(struct pci_dev *dev, int start, int limit) for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) {
{ struct resource *r = &dev->resource[idx];
int i;
for (i = start; i < limit; i++) { if (!r->flags || r->parent || !r->start)
if (!dev->resource[i].flags)
continue; continue;
if ((is_valid_resource(dev, i)))
pci_claim_resource(dev, i);
}
}
void pcibios_fixup_device_resources(struct pci_dev *dev) pci_claim_resource(dev, idx);
{ }
pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES);
} }
EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources); EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources);
static void pcibios_fixup_bridge_resources(struct pci_dev *dev) 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);
}
} }
/* /*
......
...@@ -1026,6 +1026,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) ...@@ -1026,6 +1026,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
pr, (pr && pr->name) ? pr->name : "nil"); pr, (pr && pr->name) ? pr->name : "nil");
if (pr && !(pr->flags & IORESOURCE_UNSET)) { if (pr && !(pr->flags & IORESOURCE_UNSET)) {
struct pci_dev *dev = bus->self;
if (request_resource(pr, res) == 0) if (request_resource(pr, res) == 0)
continue; continue;
/* /*
...@@ -1035,6 +1037,12 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) ...@@ -1035,6 +1037,12 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
*/ */
if (reparent_resources(pr, res) == 0) if (reparent_resources(pr, res) == 0)
continue; 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_warn("PCI: Cannot allocate resource region ");
pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number); pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number);
...@@ -1227,7 +1235,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus) ...@@ -1227,7 +1235,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus)
(unsigned long long)r->end, (unsigned long long)r->end,
(unsigned int)r->flags); (unsigned int)r->flags);
pci_claim_resource(dev, i); if (pci_claim_resource(dev, i) == 0)
continue;
pci_claim_bridge_resource(dev, i);
} }
} }
......
...@@ -106,7 +106,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) ...@@ -106,7 +106,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
if (!r->flags) if (!r->flags)
continue; continue;
if (!r->start || if (!r->start ||
pci_claim_resource(dev, idx) < 0) { pci_claim_bridge_resource(dev, idx) < 0) {
printk(KERN_ERR "PCI:" printk(KERN_ERR "PCI:"
" Cannot allocate resource" " Cannot allocate resource"
" region %d of bridge %s\n", " region %d of bridge %s\n",
......
...@@ -281,42 +281,37 @@ static int __init pci_check_direct(void) ...@@ -281,42 +281,37 @@ static int __init pci_check_direct(void)
return -ENODEV; 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; int idx;
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;
}
}
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; return;
limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ? for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES; struct resource *r = &dev->resource[idx];
for (i = 0; i < limit; i++) { if (!r->flags || r->parent || !r->start)
if (!dev->resource[i].flags)
continue; continue;
if (is_valid_resource(dev, i)) pci_claim_bridge_resource(dev, idx);
pci_claim_resource(dev, i);
} }
} }
...@@ -330,7 +325,7 @@ void pcibios_fixup_bus(struct pci_bus *bus) ...@@ -330,7 +325,7 @@ void pcibios_fixup_bus(struct pci_bus *bus)
if (bus->self) { if (bus->self) {
pci_read_bridge_bases(bus); 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) list_for_each_entry(dev, &bus->devices, bus_list)
......
...@@ -1184,6 +1184,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) ...@@ -1184,6 +1184,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
pr, (pr && pr->name) ? pr->name : "nil"); pr, (pr && pr->name) ? pr->name : "nil");
if (pr && !(pr->flags & IORESOURCE_UNSET)) { if (pr && !(pr->flags & IORESOURCE_UNSET)) {
struct pci_dev *dev = bus->self;
if (request_resource(pr, res) == 0) if (request_resource(pr, res) == 0)
continue; continue;
/* /*
...@@ -1193,6 +1195,11 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) ...@@ -1193,6 +1195,11 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
*/ */
if (reparent_resources(pr, res) == 0) if (reparent_resources(pr, res) == 0)
continue; 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 " pr_warning("PCI: Cannot allocate resource region "
"%d of PCI bridge %d, will remap\n", i, bus->number); "%d of PCI bridge %d, will remap\n", i, bus->number);
...@@ -1401,7 +1408,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus) ...@@ -1401,7 +1408,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus)
(unsigned long long)r->end, (unsigned long long)r->end,
(unsigned int)r->flags); (unsigned int)r->flags);
pci_claim_resource(dev, i); if (pci_claim_resource(dev, i) == 0)
continue;
pci_claim_bridge_resource(dev, i);
} }
} }
......
...@@ -639,7 +639,10 @@ static void pci_claim_bus_resources(struct pci_bus *bus) ...@@ -639,7 +639,10 @@ static void pci_claim_bus_resources(struct pci_bus *bus)
(unsigned long long)r->end, (unsigned long long)r->end,
(unsigned int)r->flags); (unsigned int)r->flags);
pci_claim_resource(dev, i); if (pci_claim_resource(dev, i) == 0)
continue;
pci_claim_bridge_resource(dev, i);
} }
} }
......
...@@ -216,7 +216,7 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev) ...@@ -216,7 +216,7 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
continue; continue;
if (r->parent) /* Already allocated */ if (r->parent) /* Already allocated */
continue; 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. * Something is wrong with the region.
* Invalidate the resource to prevent * Invalidate the resource to prevent
......
...@@ -694,9 +694,8 @@ lba_fixup_bus(struct pci_bus *bus) ...@@ -694,9 +694,8 @@ lba_fixup_bus(struct pci_bus *bus)
int i; int i;
/* PCI-PCI Bridge */ /* PCI-PCI Bridge */
pci_read_bridge_bases(bus); pci_read_bridge_bases(bus);
for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++)
pci_claim_resource(bus->self, i); pci_claim_bridge_resource(bus->self, i);
}
} else { } else {
/* Host-PCI Bridge */ /* Host-PCI Bridge */
int err; int err;
......
...@@ -228,6 +228,49 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, ...@@ -228,6 +228,49 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
} }
EXPORT_SYMBOL(pci_bus_alloc_resource); 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) { } void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }
/** /**
......
...@@ -3271,7 +3271,8 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe) ...@@ -3271,7 +3271,8 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
{ {
struct pci_dev *pdev; struct pci_dev *pdev;
if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self) if (pci_is_root_bus(dev->bus) || dev->subordinate ||
!dev->bus->self || dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
return -ENOTTY; return -ENOTTY;
list_for_each_entry(pdev, &dev->bus->devices, bus_list) list_for_each_entry(pdev, &dev->bus->devices, bus_list)
...@@ -3305,7 +3306,8 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe) ...@@ -3305,7 +3306,8 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
{ {
struct pci_dev *pdev; struct pci_dev *pdev;
if (dev->subordinate || !dev->slot) if (dev->subordinate || !dev->slot ||
dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
return -ENOTTY; return -ENOTTY;
list_for_each_entry(pdev, &dev->bus->devices, bus_list) list_for_each_entry(pdev, &dev->bus->devices, bus_list)
...@@ -3557,6 +3559,20 @@ int pci_try_reset_function(struct pci_dev *dev) ...@@ -3557,6 +3559,20 @@ int pci_try_reset_function(struct pci_dev *dev)
} }
EXPORT_SYMBOL_GPL(pci_try_reset_function); EXPORT_SYMBOL_GPL(pci_try_reset_function);
/* Do any devices on or below this bus prevent a bus reset? */
static bool pci_bus_resetable(struct pci_bus *bus)
{
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) {
if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
(dev->subordinate && !pci_bus_resetable(dev->subordinate)))
return false;
}
return true;
}
/* Lock devices from the top of the tree down */ /* Lock devices from the top of the tree down */
static void pci_bus_lock(struct pci_bus *bus) static void pci_bus_lock(struct pci_bus *bus)
{ {
...@@ -3607,6 +3623,22 @@ static int pci_bus_trylock(struct pci_bus *bus) ...@@ -3607,6 +3623,22 @@ static int pci_bus_trylock(struct pci_bus *bus)
return 0; return 0;
} }
/* Do any devices on or below this slot prevent a bus reset? */
static bool pci_slot_resetable(struct pci_slot *slot)
{
struct pci_dev *dev;
list_for_each_entry(dev, &slot->bus->devices, bus_list) {
if (!dev->slot || dev->slot != slot)
continue;
if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
(dev->subordinate && !pci_bus_resetable(dev->subordinate)))
return false;
}
return true;
}
/* Lock devices from the top of the tree down */ /* Lock devices from the top of the tree down */
static void pci_slot_lock(struct pci_slot *slot) static void pci_slot_lock(struct pci_slot *slot)
{ {
...@@ -3728,7 +3760,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe) ...@@ -3728,7 +3760,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe)
{ {
int rc; int rc;
if (!slot) if (!slot || !pci_slot_resetable(slot))
return -ENOTTY; return -ENOTTY;
if (!probe) if (!probe)
...@@ -3820,7 +3852,7 @@ EXPORT_SYMBOL_GPL(pci_try_reset_slot); ...@@ -3820,7 +3852,7 @@ EXPORT_SYMBOL_GPL(pci_try_reset_slot);
static int pci_bus_reset(struct pci_bus *bus, int probe) static int pci_bus_reset(struct pci_bus *bus, int probe)
{ {
if (!bus->self) if (!bus->self || !pci_bus_resetable(bus))
return -ENOTTY; return -ENOTTY;
if (probe) if (probe)
......
...@@ -208,6 +208,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, ...@@ -208,6 +208,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus,
void __pci_bus_assign_resources(const struct pci_bus *bus, void __pci_bus_assign_resources(const struct pci_bus *bus,
struct list_head *realloc_head, struct list_head *realloc_head,
struct list_head *fail_head); struct list_head *fail_head);
bool pci_bus_clip_resource(struct pci_dev *dev, int idx);
/** /**
* pci_ari_enabled - query ARI forwarding status * pci_ari_enabled - query ARI forwarding status
......
...@@ -3028,6 +3028,20 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169, ...@@ -3028,6 +3028,20 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169,
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID, DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID,
quirk_broken_intx_masking); quirk_broken_intx_masking);
static void quirk_no_bus_reset(struct pci_dev *dev)
{
dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET;
}
/*
* Atheros AR93xx chips do not behave after a bus reset. The device will
* throw a Link Down error on AER-capable systems and regardless of AER,
* config space of the device is never accessible again and typically
* causes the system to hang or reset when access is attempted.
* http://www.spinics.net/lists/linux-pci/msg34797.html
*/
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
/* /*
* Apple: Shutdown Cactus Ridge Thunderbolt controller. * Apple: Shutdown Cactus Ridge Thunderbolt controller.
......
...@@ -530,9 +530,8 @@ EXPORT_SYMBOL(pci_setup_cardbus); ...@@ -530,9 +530,8 @@ EXPORT_SYMBOL(pci_setup_cardbus);
config space writes, so it's quite possible that an I/O window of config space writes, so it's quite possible that an I/O window of
the bridge will have some undesirable address (e.g. 0) after the the bridge will have some undesirable address (e.g. 0) after the
first write. Ditto 64-bit prefetchable MMIO. */ first write. Ditto 64-bit prefetchable MMIO. */
static void pci_setup_bridge_io(struct pci_bus *bus) static void pci_setup_bridge_io(struct pci_dev *bridge)
{ {
struct pci_dev *bridge = bus->self;
struct resource *res; struct resource *res;
struct pci_bus_region region; struct pci_bus_region region;
unsigned long io_mask; unsigned long io_mask;
...@@ -545,7 +544,7 @@ static void pci_setup_bridge_io(struct pci_bus *bus) ...@@ -545,7 +544,7 @@ static void pci_setup_bridge_io(struct pci_bus *bus)
io_mask = PCI_IO_1K_RANGE_MASK; io_mask = PCI_IO_1K_RANGE_MASK;
/* Set up the top and bottom of the PCI I/O segment for this bus. */ /* Set up the top and bottom of the PCI I/O segment for this bus. */
res = bus->resource[0]; res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
pcibios_resource_to_bus(bridge->bus, &region, res); pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
pci_read_config_word(bridge, PCI_IO_BASE, &l); pci_read_config_word(bridge, PCI_IO_BASE, &l);
...@@ -568,15 +567,14 @@ static void pci_setup_bridge_io(struct pci_bus *bus) ...@@ -568,15 +567,14 @@ static void pci_setup_bridge_io(struct pci_bus *bus)
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16); pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
} }
static void pci_setup_bridge_mmio(struct pci_bus *bus) static void pci_setup_bridge_mmio(struct pci_dev *bridge)
{ {
struct pci_dev *bridge = bus->self;
struct resource *res; struct resource *res;
struct pci_bus_region region; struct pci_bus_region region;
u32 l; u32 l;
/* Set up the top and bottom of the PCI Memory segment for this bus. */ /* Set up the top and bottom of the PCI Memory segment for this bus. */
res = bus->resource[1]; res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
pcibios_resource_to_bus(bridge->bus, &region, res); pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_MEM) { if (res->flags & IORESOURCE_MEM) {
l = (region.start >> 16) & 0xfff0; l = (region.start >> 16) & 0xfff0;
...@@ -588,9 +586,8 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus) ...@@ -588,9 +586,8 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus)
pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
} }
static void pci_setup_bridge_mmio_pref(struct pci_bus *bus) static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
{ {
struct pci_dev *bridge = bus->self;
struct resource *res; struct resource *res;
struct pci_bus_region region; struct pci_bus_region region;
u32 l, bu, lu; u32 l, bu, lu;
...@@ -602,7 +599,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus) ...@@ -602,7 +599,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)
/* Set up PREF base/limit. */ /* Set up PREF base/limit. */
bu = lu = 0; bu = lu = 0;
res = bus->resource[2]; res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
pcibios_resource_to_bus(bridge->bus, &region, res); pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_PREFETCH) { if (res->flags & IORESOURCE_PREFETCH) {
l = (region.start >> 16) & 0xfff0; l = (region.start >> 16) & 0xfff0;
...@@ -630,13 +627,13 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) ...@@ -630,13 +627,13 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type)
&bus->busn_res); &bus->busn_res);
if (type & IORESOURCE_IO) if (type & IORESOURCE_IO)
pci_setup_bridge_io(bus); pci_setup_bridge_io(bridge);
if (type & IORESOURCE_MEM) if (type & IORESOURCE_MEM)
pci_setup_bridge_mmio(bus); pci_setup_bridge_mmio(bridge);
if (type & IORESOURCE_PREFETCH) if (type & IORESOURCE_PREFETCH)
pci_setup_bridge_mmio_pref(bus); pci_setup_bridge_mmio_pref(bridge);
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
} }
...@@ -649,6 +646,41 @@ void pci_setup_bridge(struct pci_bus *bus) ...@@ -649,6 +646,41 @@ void pci_setup_bridge(struct pci_bus *bus)
__pci_setup_bridge(bus, type); __pci_setup_bridge(bus, type);
} }
int pci_claim_bridge_resource(struct pci_dev *bridge, int i)
{
if (i < PCI_BRIDGE_RESOURCES || i > PCI_BRIDGE_RESOURCE_END)
return 0;
if (pci_claim_resource(bridge, i) == 0)
return 0; /* claimed the window */
if ((bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
return 0;
if (!pci_bus_clip_resource(bridge, i))
return -EINVAL; /* clipping didn't change anything */
switch (i - PCI_BRIDGE_RESOURCES) {
case 0:
pci_setup_bridge_io(bridge);
break;
case 1:
pci_setup_bridge_mmio(bridge);
break;
case 2:
pci_setup_bridge_mmio_pref(bridge);
break;
default:
return -EINVAL;
}
if (pci_claim_resource(bridge, i) == 0)
return 0; /* claimed a smaller window */
return -EINVAL;
}
/* Check whether the bridge supports optional I/O and /* Check whether the bridge supports optional I/O and
prefetchable memory ranges. If not, the respective prefetchable memory ranges. If not, the respective
base/limit registers must be read-only and read as 0. */ base/limit registers must be read-only and read as 0. */
......
...@@ -175,6 +175,8 @@ enum pci_dev_flags { ...@@ -175,6 +175,8 @@ enum pci_dev_flags {
PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4), PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4),
/* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */
PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5),
/* Do not use bus resets for device */
PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 6),
}; };
enum pci_irq_reroute_variant { enum pci_irq_reroute_variant {
...@@ -1065,6 +1067,7 @@ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx); ...@@ -1065,6 +1067,7 @@ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
void pci_bus_assign_resources(const struct pci_bus *bus); void pci_bus_assign_resources(const struct pci_bus *bus);
void pci_bus_size_bridges(struct pci_bus *bus); void pci_bus_size_bridges(struct pci_bus *bus);
int pci_claim_resource(struct pci_dev *, int); int pci_claim_resource(struct pci_dev *, int);
int pci_claim_bridge_resource(struct pci_dev *bridge, int i);
void pci_assign_unassigned_resources(void); void pci_assign_unassigned_resources(void);
void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge); void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
void pci_assign_unassigned_bus_resources(struct pci_bus *bus); void pci_assign_unassigned_bus_resources(struct pci_bus *bus);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment