Merge branch 'pci/enumeration'

- Fix pci_register_host_bridge() device_register() error handling (Rob
    Herring)

  - Fix pci_host_bridge struct device release/free handling (Rob Herring)

  - Program MPS for RCiEP devices (Ashok Raj)

  - Inherit PTM settings from Switch Upstream Port so we can enable PTM on
    Endpoints (Bjorn Helgaas)

  - Add #defines for bridge windows (PCI_BRIDGE_IO_WINDOW,
    PCI_BRIDGE_MEM_WINDOW, etc) (Krzysztof Wilczynski)

* pci/enumeration:
  pcmcia: Use CardBus window names (PCI_CB_BRIDGE_IO_0_WINDOW etc) when freeing
  PCI: Use bridge window names (PCI_BRIDGE_IO_WINDOW etc)
  PCI/PTM: Inherit Switch Downstream Port PTM settings from Upstream Port
  PCI: Program MPS for RCiEP devices
  PCI: Fix pci_host_bridge struct device release/free handling
  PCI: Fix pci_register_host_bridge() device_register() error handling
This commit is contained in:
Bjorn Helgaas 2020-06-04 12:59:09 -05:00
commit 8ab064e931
6 changed files with 161 additions and 94 deletions

View File

@ -39,10 +39,6 @@ void pci_ptm_init(struct pci_dev *dev)
if (!pci_is_pcie(dev)) if (!pci_is_pcie(dev))
return; return;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
if (!pos)
return;
/* /*
* Enable PTM only on interior devices (root ports, switch ports, * Enable PTM only on interior devices (root ports, switch ports,
* etc.) on the assumption that it causes no link traffic until an * etc.) on the assumption that it causes no link traffic until an
@ -52,6 +48,23 @@ void pci_ptm_init(struct pci_dev *dev)
pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)) pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END))
return; return;
/*
* Switch Downstream Ports are not permitted to have a PTM
* capability; their PTM behavior is controlled by the Upstream
* Port (PCIe r5.0, sec 7.9.16).
*/
ups = pci_upstream_bridge(dev);
if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM &&
ups && ups->ptm_enabled) {
dev->ptm_granularity = ups->ptm_granularity;
dev->ptm_enabled = 1;
return;
}
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
if (!pos)
return;
pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap); pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
local_clock = (cap & PCI_PTM_GRANULARITY_MASK) >> 8; local_clock = (cap & PCI_PTM_GRANULARITY_MASK) >> 8;
@ -61,7 +74,6 @@ void pci_ptm_init(struct pci_dev *dev)
* the spec recommendation (PCIe r3.1, sec 7.32.3), select the * the spec recommendation (PCIe r3.1, sec 7.32.3), select the
* furthest upstream Time Source as the PTM Root. * furthest upstream Time Source as the PTM Root.
*/ */
ups = pci_upstream_bridge(dev);
if (ups && ups->ptm_enabled) { if (ups && ups->ptm_enabled) {
ctrl = PCI_PTM_CTRL_ENABLE; ctrl = PCI_PTM_CTRL_ENABLE;
if (ups->ptm_granularity == 0) if (ups->ptm_granularity == 0)

View File

@ -565,7 +565,7 @@ static struct pci_bus *pci_alloc_bus(struct pci_bus *parent)
return b; return b;
} }
static void devm_pci_release_host_bridge_dev(struct device *dev) static void pci_release_host_bridge_dev(struct device *dev)
{ {
struct pci_host_bridge *bridge = to_pci_host_bridge(dev); struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
@ -574,12 +574,7 @@ static void devm_pci_release_host_bridge_dev(struct device *dev)
pci_free_resource_list(&bridge->windows); pci_free_resource_list(&bridge->windows);
pci_free_resource_list(&bridge->dma_ranges); pci_free_resource_list(&bridge->dma_ranges);
} kfree(bridge);
static void pci_release_host_bridge_dev(struct device *dev)
{
devm_pci_release_host_bridge_dev(dev);
kfree(to_pci_host_bridge(dev));
} }
static void pci_init_host_bridge(struct pci_host_bridge *bridge) static void pci_init_host_bridge(struct pci_host_bridge *bridge)
@ -599,6 +594,8 @@ static void pci_init_host_bridge(struct pci_host_bridge *bridge)
bridge->native_pme = 1; bridge->native_pme = 1;
bridge->native_ltr = 1; bridge->native_ltr = 1;
bridge->native_dpc = 1; bridge->native_dpc = 1;
device_initialize(&bridge->dev);
} }
struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
@ -616,17 +613,25 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
} }
EXPORT_SYMBOL(pci_alloc_host_bridge); EXPORT_SYMBOL(pci_alloc_host_bridge);
static void devm_pci_alloc_host_bridge_release(void *data)
{
pci_free_host_bridge(data);
}
struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev, struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev,
size_t priv) size_t priv)
{ {
int ret;
struct pci_host_bridge *bridge; struct pci_host_bridge *bridge;
bridge = devm_kzalloc(dev, sizeof(*bridge) + priv, GFP_KERNEL); bridge = pci_alloc_host_bridge(priv);
if (!bridge) if (!bridge)
return NULL; return NULL;
pci_init_host_bridge(bridge); ret = devm_add_action_or_reset(dev, devm_pci_alloc_host_bridge_release,
bridge->dev.release = devm_pci_release_host_bridge_dev; bridge);
if (ret)
return NULL;
return bridge; return bridge;
} }
@ -634,10 +639,7 @@ EXPORT_SYMBOL(devm_pci_alloc_host_bridge);
void pci_free_host_bridge(struct pci_host_bridge *bridge) void pci_free_host_bridge(struct pci_host_bridge *bridge)
{ {
pci_free_resource_list(&bridge->windows); put_device(&bridge->dev);
pci_free_resource_list(&bridge->dma_ranges);
kfree(bridge);
} }
EXPORT_SYMBOL(pci_free_host_bridge); EXPORT_SYMBOL(pci_free_host_bridge);
@ -908,10 +910,11 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
if (err) if (err)
goto free; goto free;
err = device_register(&bridge->dev); err = device_add(&bridge->dev);
if (err) if (err) {
put_device(&bridge->dev); put_device(&bridge->dev);
goto free;
}
bus->bridge = get_device(&bridge->dev); bus->bridge = get_device(&bridge->dev);
device_enable_async_suspend(bus->bridge); device_enable_async_suspend(bus->bridge);
pci_set_bus_of_node(bus); pci_set_bus_of_node(bus);
@ -977,7 +980,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
unregister: unregister:
put_device(&bridge->dev); put_device(&bridge->dev);
device_unregister(&bridge->dev); device_del(&bridge->dev);
free: free:
kfree(bus); kfree(bus);
@ -1934,13 +1937,33 @@ static void pci_configure_mps(struct pci_dev *dev)
struct pci_dev *bridge = pci_upstream_bridge(dev); struct pci_dev *bridge = pci_upstream_bridge(dev);
int mps, mpss, p_mps, rc; int mps, mpss, p_mps, rc;
if (!pci_is_pcie(dev) || !bridge || !pci_is_pcie(bridge)) if (!pci_is_pcie(dev))
return; return;
/* MPS and MRRS fields are of type 'RsvdP' for VFs, short-circuit out */ /* MPS and MRRS fields are of type 'RsvdP' for VFs, short-circuit out */
if (dev->is_virtfn) if (dev->is_virtfn)
return; return;
/*
* For Root Complex Integrated Endpoints, program the maximum
* supported value unless limited by the PCIE_BUS_PEER2PEER case.
*/
if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) {
if (pcie_bus_config == PCIE_BUS_PEER2PEER)
mps = 128;
else
mps = 128 << dev->pcie_mpss;
rc = pcie_set_mps(dev, mps);
if (rc) {
pci_warn(dev, "can't set Max Payload Size to %d; if necessary, use \"pci=pcie_bus_safe\" and report a bug\n",
mps);
}
return;
}
if (!bridge || !pci_is_pcie(bridge))
return;
mps = pcie_get_mps(dev); mps = pcie_get_mps(dev);
p_mps = pcie_get_mps(bridge); p_mps = pcie_get_mps(bridge);
@ -2952,7 +2975,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
return bridge->bus; return bridge->bus;
err_out: err_out:
kfree(bridge); put_device(&bridge->dev);
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(pci_create_root_bus); EXPORT_SYMBOL_GPL(pci_create_root_bus);

View File

@ -160,6 +160,6 @@ void pci_remove_root_bus(struct pci_bus *bus)
host_bridge->bus = NULL; host_bridge->bus = NULL;
/* remove the host bridge */ /* remove the host bridge */
device_unregister(&host_bridge->dev); device_del(&host_bridge->dev);
} }
EXPORT_SYMBOL_GPL(pci_remove_root_bus); EXPORT_SYMBOL_GPL(pci_remove_root_bus);

View File

@ -583,7 +583,7 @@ static void pci_setup_bridge_io(struct pci_dev *bridge)
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 = &bridge->resource[PCI_BRIDGE_RESOURCES + 0]; res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
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);
@ -613,7 +613,7 @@ static void pci_setup_bridge_mmio(struct pci_dev *bridge)
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 = &bridge->resource[PCI_BRIDGE_RESOURCES + 1]; res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
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;
@ -640,7 +640,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
/* Set up PREF base/limit */ /* Set up PREF base/limit */
bu = lu = 0; bu = lu = 0;
res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2]; res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
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;
@ -707,14 +707,14 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i)
if (!pci_bus_clip_resource(bridge, i)) if (!pci_bus_clip_resource(bridge, i))
return -EINVAL; /* Clipping didn't change anything */ return -EINVAL; /* Clipping didn't change anything */
switch (i - PCI_BRIDGE_RESOURCES) { switch (i) {
case 0: case PCI_BRIDGE_IO_WINDOW:
pci_setup_bridge_io(bridge); pci_setup_bridge_io(bridge);
break; break;
case 1: case PCI_BRIDGE_MEM_WINDOW:
pci_setup_bridge_mmio(bridge); pci_setup_bridge_mmio(bridge);
break; break;
case 2: case PCI_BRIDGE_PREF_MEM_WINDOW:
pci_setup_bridge_mmio_pref(bridge); pci_setup_bridge_mmio_pref(bridge);
break; break;
default: default:
@ -735,18 +735,22 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i)
static void pci_bridge_check_ranges(struct pci_bus *bus) static void pci_bridge_check_ranges(struct pci_bus *bus)
{ {
struct pci_dev *bridge = bus->self; struct pci_dev *bridge = bus->self;
struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; struct resource *b_res;
b_res[1].flags |= IORESOURCE_MEM; b_res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
b_res->flags |= IORESOURCE_MEM;
if (bridge->io_window) if (bridge->io_window) {
b_res[0].flags |= IORESOURCE_IO; b_res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
b_res->flags |= IORESOURCE_IO;
}
if (bridge->pref_window) { if (bridge->pref_window) {
b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; b_res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
if (bridge->pref_64_window) { if (bridge->pref_64_window) {
b_res[2].flags |= IORESOURCE_MEM_64; b_res->flags |= IORESOURCE_MEM_64 |
b_res[2].flags |= PCI_PREF_RANGE_TYPE_64; PCI_PREF_RANGE_TYPE_64;
} }
} }
} }
@ -1105,34 +1109,36 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
struct list_head *realloc_head) struct list_head *realloc_head)
{ {
struct pci_dev *bridge = bus->self; struct pci_dev *bridge = bus->self;
struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; struct resource *b_res;
resource_size_t b_res_3_size = pci_cardbus_mem_size * 2; resource_size_t b_res_3_size = pci_cardbus_mem_size * 2;
u16 ctrl; u16 ctrl;
if (b_res[0].parent) b_res = &bridge->resource[PCI_CB_BRIDGE_IO_0_WINDOW];
if (b_res->parent)
goto handle_b_res_1; goto handle_b_res_1;
/* /*
* Reserve some resources for CardBus. We reserve a fixed amount * Reserve some resources for CardBus. We reserve a fixed amount
* of bus space for CardBus bridges. * of bus space for CardBus bridges.
*/ */
b_res[0].start = pci_cardbus_io_size; b_res->start = pci_cardbus_io_size;
b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1; b_res->end = b_res->start + pci_cardbus_io_size - 1;
b_res[0].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN; b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
if (realloc_head) { if (realloc_head) {
b_res[0].end -= pci_cardbus_io_size; b_res->end -= pci_cardbus_io_size;
add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size,
pci_cardbus_io_size); pci_cardbus_io_size);
} }
handle_b_res_1: handle_b_res_1:
if (b_res[1].parent) b_res = &bridge->resource[PCI_CB_BRIDGE_IO_1_WINDOW];
if (b_res->parent)
goto handle_b_res_2; goto handle_b_res_2;
b_res[1].start = pci_cardbus_io_size; b_res->start = pci_cardbus_io_size;
b_res[1].end = b_res[1].start + pci_cardbus_io_size - 1; b_res->end = b_res->start + pci_cardbus_io_size - 1;
b_res[1].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN; b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
if (realloc_head) { if (realloc_head) {
b_res[1].end -= pci_cardbus_io_size; b_res->end -= pci_cardbus_io_size;
add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size, add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size,
pci_cardbus_io_size); pci_cardbus_io_size);
} }
@ -1153,20 +1159,21 @@ handle_b_res_2:
pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl); pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
} }
if (b_res[2].parent) b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_0_WINDOW];
if (b_res->parent)
goto handle_b_res_3; goto handle_b_res_3;
/* /*
* If we have prefetchable memory support, allocate two regions. * If we have prefetchable memory support, allocate two regions.
* Otherwise, allocate one region of twice the size. * Otherwise, allocate one region of twice the size.
*/ */
if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) { if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
b_res[2].start = pci_cardbus_mem_size; b_res->start = pci_cardbus_mem_size;
b_res[2].end = b_res[2].start + pci_cardbus_mem_size - 1; b_res->end = b_res->start + pci_cardbus_mem_size - 1;
b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
IORESOURCE_STARTALIGN; IORESOURCE_STARTALIGN;
if (realloc_head) { if (realloc_head) {
b_res[2].end -= pci_cardbus_mem_size; b_res->end -= pci_cardbus_mem_size;
add_to_list(realloc_head, bridge, b_res+2, add_to_list(realloc_head, bridge, b_res,
pci_cardbus_mem_size, pci_cardbus_mem_size); pci_cardbus_mem_size, pci_cardbus_mem_size);
} }
@ -1175,14 +1182,15 @@ handle_b_res_2:
} }
handle_b_res_3: handle_b_res_3:
if (b_res[3].parent) b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_1_WINDOW];
if (b_res->parent)
goto handle_done; goto handle_done;
b_res[3].start = pci_cardbus_mem_size; b_res->start = pci_cardbus_mem_size;
b_res[3].end = b_res[3].start + b_res_3_size - 1; b_res->end = b_res->start + b_res_3_size - 1;
b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN; b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
if (realloc_head) { if (realloc_head) {
b_res[3].end -= b_res_3_size; b_res->end -= b_res_3_size;
add_to_list(realloc_head, bridge, b_res+3, b_res_3_size, add_to_list(realloc_head, bridge, b_res, b_res_3_size,
pci_cardbus_mem_size); pci_cardbus_mem_size);
} }
@ -1227,7 +1235,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
break; break;
hdr_type = -1; /* Intentionally invalid - not a PCI device. */ hdr_type = -1; /* Intentionally invalid - not a PCI device. */
} else { } else {
pref = &bus->self->resource[PCI_BRIDGE_RESOURCES + 2]; pref = &bus->self->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
hdr_type = bus->self->hdr_type; hdr_type = bus->self->hdr_type;
} }
@ -1885,9 +1893,9 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
struct pci_dev *dev, *bridge = bus->self; struct pci_dev *dev, *bridge = bus->self;
resource_size_t io_per_hp, mmio_per_hp, mmio_pref_per_hp, align; resource_size_t io_per_hp, mmio_per_hp, mmio_pref_per_hp, align;
io_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0]; io_res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
mmio_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1]; mmio_res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
mmio_pref_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2]; mmio_pref_res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
/* /*
* The alignment of this bridge is yet to be considered, hence it must * The alignment of this bridge is yet to be considered, hence it must
@ -1960,21 +1968,21 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
* Reduce the available resource space by what the * Reduce the available resource space by what the
* bridge and devices below it occupy. * bridge and devices below it occupy.
*/ */
res = &dev->resource[PCI_BRIDGE_RESOURCES + 0]; res = &dev->resource[PCI_BRIDGE_IO_WINDOW];
align = pci_resource_alignment(dev, res); align = pci_resource_alignment(dev, res);
align = align ? ALIGN(io.start, align) - io.start : 0; align = align ? ALIGN(io.start, align) - io.start : 0;
used_size = align + resource_size(res); used_size = align + resource_size(res);
if (!res->parent) if (!res->parent)
io.start = min(io.start + used_size, io.end + 1); io.start = min(io.start + used_size, io.end + 1);
res = &dev->resource[PCI_BRIDGE_RESOURCES + 1]; res = &dev->resource[PCI_BRIDGE_MEM_WINDOW];
align = pci_resource_alignment(dev, res); align = pci_resource_alignment(dev, res);
align = align ? ALIGN(mmio.start, align) - mmio.start : 0; align = align ? ALIGN(mmio.start, align) - mmio.start : 0;
used_size = align + resource_size(res); used_size = align + resource_size(res);
if (!res->parent) if (!res->parent)
mmio.start = min(mmio.start + used_size, mmio.end + 1); mmio.start = min(mmio.start + used_size, mmio.end + 1);
res = &dev->resource[PCI_BRIDGE_RESOURCES + 2]; res = &dev->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
align = pci_resource_alignment(dev, res); align = pci_resource_alignment(dev, res);
align = align ? ALIGN(mmio_pref.start, align) - align = align ? ALIGN(mmio_pref.start, align) -
mmio_pref.start : 0; mmio_pref.start : 0;
@ -2027,9 +2035,9 @@ static void pci_bridge_distribute_available_resources(struct pci_dev *bridge,
return; return;
/* Take the initial extra resources from the hotplug port */ /* Take the initial extra resources from the hotplug port */
available_io = bridge->resource[PCI_BRIDGE_RESOURCES + 0]; available_io = bridge->resource[PCI_BRIDGE_IO_WINDOW];
available_mmio = bridge->resource[PCI_BRIDGE_RESOURCES + 1]; available_mmio = bridge->resource[PCI_BRIDGE_MEM_WINDOW];
available_mmio_pref = bridge->resource[PCI_BRIDGE_RESOURCES + 2]; available_mmio_pref = bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
pci_bus_distribute_available_resources(bridge->subordinate, pci_bus_distribute_available_resources(bridge->subordinate,
add_list, available_io, add_list, available_io,

View File

@ -694,7 +694,7 @@ static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type
struct pci_bus_region region; struct pci_bus_region region;
unsigned mask; unsigned mask;
res = dev->resource + PCI_BRIDGE_RESOURCES + nr; res = &dev->resource[nr];
/* Already allocated? */ /* Already allocated? */
if (res->parent) if (res->parent)
return 0; return 0;
@ -711,7 +711,7 @@ static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type
region.end = config_readl(socket, addr_end) | ~mask; region.end = config_readl(socket, addr_end) | ~mask;
if (region.start && region.end > region.start && !override_bios) { if (region.start && region.end > region.start && !override_bios) {
pcibios_bus_to_resource(dev->bus, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
if (pci_claim_resource(dev, PCI_BRIDGE_RESOURCES + nr) == 0) if (pci_claim_resource(dev, nr) == 0)
return 0; return 0;
dev_info(&dev->dev, dev_info(&dev->dev,
"Preassigned resource %d busy or not available, reconfiguring...\n", "Preassigned resource %d busy or not available, reconfiguring...\n",
@ -745,19 +745,35 @@ static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type
return 0; return 0;
} }
static void yenta_free_res(struct yenta_socket *socket, int nr)
{
struct pci_dev *dev = socket->dev;
struct resource *res;
res = &dev->resource[nr];
if (res->start != 0 && res->end != 0)
release_resource(res);
res->start = res->end = res->flags = 0;
}
/* /*
* Allocate the bridge mappings for the device.. * Allocate the bridge mappings for the device..
*/ */
static void yenta_allocate_resources(struct yenta_socket *socket) static void yenta_allocate_resources(struct yenta_socket *socket)
{ {
int program = 0; int program = 0;
program += yenta_allocate_res(socket, 0, IORESOURCE_IO, program += yenta_allocate_res(socket, PCI_CB_BRIDGE_IO_0_WINDOW,
IORESOURCE_IO,
PCI_CB_IO_BASE_0, PCI_CB_IO_LIMIT_0); PCI_CB_IO_BASE_0, PCI_CB_IO_LIMIT_0);
program += yenta_allocate_res(socket, 1, IORESOURCE_IO, program += yenta_allocate_res(socket, PCI_CB_BRIDGE_IO_1_WINDOW,
IORESOURCE_IO,
PCI_CB_IO_BASE_1, PCI_CB_IO_LIMIT_1); PCI_CB_IO_BASE_1, PCI_CB_IO_LIMIT_1);
program += yenta_allocate_res(socket, 2, IORESOURCE_MEM|IORESOURCE_PREFETCH, program += yenta_allocate_res(socket, PCI_CB_BRIDGE_MEM_0_WINDOW,
IORESOURCE_MEM | IORESOURCE_PREFETCH,
PCI_CB_MEMORY_BASE_0, PCI_CB_MEMORY_LIMIT_0); PCI_CB_MEMORY_BASE_0, PCI_CB_MEMORY_LIMIT_0);
program += yenta_allocate_res(socket, 3, IORESOURCE_MEM, program += yenta_allocate_res(socket, PCI_CB_BRIDGE_MEM_1_WINDOW,
IORESOURCE_MEM,
PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1); PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1);
if (program) if (program)
pci_setup_cardbus(socket->dev->subordinate); pci_setup_cardbus(socket->dev->subordinate);
@ -769,14 +785,10 @@ static void yenta_allocate_resources(struct yenta_socket *socket)
*/ */
static void yenta_free_resources(struct yenta_socket *socket) static void yenta_free_resources(struct yenta_socket *socket)
{ {
int i; yenta_free_res(socket, PCI_CB_BRIDGE_IO_0_WINDOW);
for (i = 0; i < 4; i++) { yenta_free_res(socket, PCI_CB_BRIDGE_IO_1_WINDOW);
struct resource *res; yenta_free_res(socket, PCI_CB_BRIDGE_MEM_0_WINDOW);
res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i; yenta_free_res(socket, PCI_CB_BRIDGE_MEM_1_WINDOW);
if (res->start != 0 && res->end != 0)
release_resource(res);
res->start = res->end = res->flags = 0;
}
} }

View File

@ -100,9 +100,21 @@ enum {
PCI_IOV_RESOURCE_END = PCI_IOV_RESOURCES + PCI_SRIOV_NUM_BARS - 1, PCI_IOV_RESOURCE_END = PCI_IOV_RESOURCES + PCI_SRIOV_NUM_BARS - 1,
#endif #endif
/* Resources assigned to buses behind the bridge */ /* PCI-to-PCI (P2P) bridge windows */
#define PCI_BRIDGE_IO_WINDOW (PCI_BRIDGE_RESOURCES + 0)
#define PCI_BRIDGE_MEM_WINDOW (PCI_BRIDGE_RESOURCES + 1)
#define PCI_BRIDGE_PREF_MEM_WINDOW (PCI_BRIDGE_RESOURCES + 2)
/* CardBus bridge windows */
#define PCI_CB_BRIDGE_IO_0_WINDOW (PCI_BRIDGE_RESOURCES + 0)
#define PCI_CB_BRIDGE_IO_1_WINDOW (PCI_BRIDGE_RESOURCES + 1)
#define PCI_CB_BRIDGE_MEM_0_WINDOW (PCI_BRIDGE_RESOURCES + 2)
#define PCI_CB_BRIDGE_MEM_1_WINDOW (PCI_BRIDGE_RESOURCES + 3)
/* Total number of bridge resources for P2P and CardBus */
#define PCI_BRIDGE_RESOURCE_NUM 4 #define PCI_BRIDGE_RESOURCE_NUM 4
/* Resources assigned to buses behind the bridge */
PCI_BRIDGE_RESOURCES, PCI_BRIDGE_RESOURCES,
PCI_BRIDGE_RESOURCE_END = PCI_BRIDGE_RESOURCES + PCI_BRIDGE_RESOURCE_END = PCI_BRIDGE_RESOURCES +
PCI_BRIDGE_RESOURCE_NUM - 1, PCI_BRIDGE_RESOURCE_NUM - 1,