PCI updates for v3.19:
Resource management - Clip bridge windows to fit in upstream windows (Yinghai Lu) Virtualization - Mark Atheros AR93xx to avoid using bus reset (Alex Williamson) Miscellaneous - Update Richard Zhu's email address (Lucas Stach) -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUwqpDAAoJEFmIoMA60/r8ykIQAINgkP/iPaFMTPkTSfzTJCMY oQVNGha4FDt6Ic1UWGyS/sYUpywSnALxlYWxVZTm5r+sGQ2yJBo6veuxvCI09YFw lWqf6lfvkFSthWCo7pHLoNaIjKJUNCy4a2han31aAIScMCNX4YF60YorMSjQBST8 smLMG75U3U9VWaXYsV1e5gTvLa5IQh4lgaTgMAOXqd+6WcAR4WwOgD2sR06o2X43 63JF2U+ieuA789Xu2IS92TmMMESD5haEZATqdGPtxpnqyHxmBNu0Y4JkkBWD2S92 HvveOoLBT2TBfICkftvCJscBLHh7PZMIx9nLx58SnijVzX+hzVr4Zfc96MZU50MK DuNbbZn3sO902ukOEpfih7Mg0tDxCxNytleEdAnXmZuqf+odbd/Y4AA0Hg6w7GEY OsVGbQAT/knlTfsSZsivtmUl7l1SXzrozv+q4f4szY95v34S9pm0sWzz0IBn7oKj h7N9Vslr3lyEudOUo1OrFq+0arDw53kwOOkIavMUH0nvTqKs4cmXBcGMfo1EfMa+ 3YhjwbgpvtZ3AXi2NSBk4gIGZEmQslvgRStLhgXVDl+9DieK+sw1Vx4cKe8gu9mD c7zPStEsJBJgd3v+8s8avwo8R0oPZb6MsCKFjjaYojTvpfFmfX0YyWE/TzYoUm6Z +BTyA8t0+3jTArTs/Zid =HRy7 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
550695925d
|
@ -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 <l.stach@pengutronix.de>
|
||||
L: linux-pci@vger.kernel.org
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
|
||||
struct resource *devr = &dev->resource[idx], *busr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void pcibios_fixup_resources(struct pci_dev *dev, int start, int limit)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = start; i < limit; i++) {
|
||||
if (!dev->resource[i].flags)
|
||||
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);
|
||||
int idx;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -281,42 +281,37 @@ static int __init pci_check_direct(void)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int is_valid_resource(struct pci_dev *dev, int idx)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pcibios_fixup_device_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 = 0; idx < PCI_BRIDGE_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_resource(dev, idx);
|
||||
}
|
||||
}
|
||||
|
||||
static void pcibios_fixup_bridge_resources(struct pci_dev *dev)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) { }
|
||||
|
||||
/**
|
||||
|
|
|
@ -3271,7 +3271,8 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
|
|||
{
|
||||
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;
|
||||
|
||||
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)
|
|||
{
|
||||
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;
|
||||
|
||||
list_for_each_entry(pdev, &dev->bus->devices, bus_list)
|
||||
|
@ -3557,6 +3559,20 @@ int pci_try_reset_function(struct pci_dev *dev)
|
|||
}
|
||||
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 */
|
||||
static void pci_bus_lock(struct pci_bus *bus)
|
||||
{
|
||||
|
@ -3607,6 +3623,22 @@ unlock:
|
|||
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 */
|
||||
static void pci_slot_lock(struct pci_slot *slot)
|
||||
{
|
||||
|
@ -3728,7 +3760,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe)
|
|||
{
|
||||
int rc;
|
||||
|
||||
if (!slot)
|
||||
if (!slot || !pci_slot_resetable(slot))
|
||||
return -ENOTTY;
|
||||
|
||||
if (!probe)
|
||||
|
@ -3820,7 +3852,7 @@ EXPORT_SYMBOL_GPL(pci_try_reset_slot);
|
|||
|
||||
static int pci_bus_reset(struct pci_bus *bus, int probe)
|
||||
{
|
||||
if (!bus->self)
|
||||
if (!bus->self || !pci_bus_resetable(bus))
|
||||
return -ENOTTY;
|
||||
|
||||
if (probe)
|
||||
|
|
|
@ -208,6 +208,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus,
|
|||
void __pci_bus_assign_resources(const struct pci_bus *bus,
|
||||
struct list_head *realloc_head,
|
||||
struct list_head *fail_head);
|
||||
bool pci_bus_clip_resource(struct pci_dev *dev, int idx);
|
||||
|
||||
/**
|
||||
* pci_ari_enabled - query ARI forwarding status
|
||||
|
|
|
@ -3028,6 +3028,20 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169,
|
|||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID,
|
||||
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
|
||||
/*
|
||||
* Apple: Shutdown Cactus Ridge Thunderbolt controller.
|
||||
|
|
|
@ -530,9 +530,8 @@ EXPORT_SYMBOL(pci_setup_cardbus);
|
|||
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
|
||||
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 pci_bus_region region;
|
||||
unsigned long io_mask;
|
||||
|
@ -545,7 +544,7 @@ static void pci_setup_bridge_io(struct pci_bus *bus)
|
|||
io_mask = PCI_IO_1K_RANGE_MASK;
|
||||
|
||||
/* 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, ®ion, res);
|
||||
if (res->flags & IORESOURCE_IO) {
|
||||
pci_read_config_word(bridge, PCI_IO_BASE, &l);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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 pci_bus_region region;
|
||||
u32 l;
|
||||
|
||||
/* 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, ®ion, res);
|
||||
if (res->flags & IORESOURCE_MEM) {
|
||||
l = (region.start >> 16) & 0xfff0;
|
||||
|
@ -588,9 +586,8 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus)
|
|||
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 pci_bus_region region;
|
||||
u32 l, bu, lu;
|
||||
|
@ -602,7 +599,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)
|
|||
|
||||
/* Set up PREF base/limit. */
|
||||
bu = lu = 0;
|
||||
res = bus->resource[2];
|
||||
res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
|
||||
pcibios_resource_to_bus(bridge->bus, ®ion, res);
|
||||
if (res->flags & IORESOURCE_PREFETCH) {
|
||||
l = (region.start >> 16) & 0xfff0;
|
||||
|
@ -630,13 +627,13 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type)
|
|||
&bus->busn_res);
|
||||
|
||||
if (type & IORESOURCE_IO)
|
||||
pci_setup_bridge_io(bus);
|
||||
pci_setup_bridge_io(bridge);
|
||||
|
||||
if (type & IORESOURCE_MEM)
|
||||
pci_setup_bridge_mmio(bus);
|
||||
pci_setup_bridge_mmio(bridge);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -649,6 +646,41 @@ void pci_setup_bridge(struct pci_bus *bus)
|
|||
__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
|
||||
prefetchable memory ranges. If not, the respective
|
||||
base/limit registers must be read-only and read as 0. */
|
||||
|
|
|
@ -175,6 +175,8 @@ enum pci_dev_flags {
|
|||
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 */
|
||||
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 {
|
||||
|
@ -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_size_bridges(struct pci_bus *bus);
|
||||
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_bridge_resources(struct pci_dev *bridge);
|
||||
void pci_assign_unassigned_bus_resources(struct pci_bus *bus);
|
||||
|
|
Loading…
Reference in a new issue