summaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2020-06-04 12:59:09 -0500
committerBjorn Helgaas <bhelgaas@google.com>2020-06-04 12:59:09 -0500
commit8ab064e93103592bb38f8e77d52e15561df619ec (patch)
tree941fde10a82dabb1b216e03dd0021b0fc2d7cae9 /drivers/pci
parent15d5a0157f31a874c94a0c8142c9bd7d494cb374 (diff)
parent11fdcf05032812bd23cdc42850d1f650376ec09d (diff)
downloadlinux-8ab064e93103592bb38f8e77d52e15561df619ec.tar.bz2
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
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pcie/ptm.c22
-rw-r--r--drivers/pci/probe.c63
-rw-r--r--drivers/pci/remove.c2
-rw-r--r--drivers/pci/setup-bus.c114
4 files changed, 122 insertions, 79 deletions
diff --git a/drivers/pci/pcie/ptm.c b/drivers/pci/pcie/ptm.c
index 9361f3aa26ab..357a454cafa0 100644
--- a/drivers/pci/pcie/ptm.c
+++ b/drivers/pci/pcie/ptm.c
@@ -39,10 +39,6 @@ void pci_ptm_init(struct pci_dev *dev)
if (!pci_is_pcie(dev))
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,
* 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))
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);
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
* furthest upstream Time Source as the PTM Root.
*/
- ups = pci_upstream_bridge(dev);
if (ups && ups->ptm_enabled) {
ctrl = PCI_PTM_CTRL_ENABLE;
if (ups->ptm_granularity == 0)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 77b8a145c39b..27c43ff63cd5 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -565,7 +565,7 @@ static struct pci_bus *pci_alloc_bus(struct pci_bus *parent)
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);
@@ -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->dma_ranges);
-}
-
-static void pci_release_host_bridge_dev(struct device *dev)
-{
- devm_pci_release_host_bridge_dev(dev);
- kfree(to_pci_host_bridge(dev));
+ kfree(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_ltr = 1;
bridge->native_dpc = 1;
+
+ device_initialize(&bridge->dev);
}
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);
+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,
size_t priv)
{
+ int ret;
struct pci_host_bridge *bridge;
- bridge = devm_kzalloc(dev, sizeof(*bridge) + priv, GFP_KERNEL);
+ bridge = pci_alloc_host_bridge(priv);
if (!bridge)
return NULL;
- pci_init_host_bridge(bridge);
- bridge->dev.release = devm_pci_release_host_bridge_dev;
+ ret = devm_add_action_or_reset(dev, devm_pci_alloc_host_bridge_release,
+ bridge);
+ if (ret)
+ return NULL;
return bridge;
}
@@ -634,10 +639,7 @@ EXPORT_SYMBOL(devm_pci_alloc_host_bridge);
void pci_free_host_bridge(struct pci_host_bridge *bridge)
{
- pci_free_resource_list(&bridge->windows);
- pci_free_resource_list(&bridge->dma_ranges);
-
- kfree(bridge);
+ put_device(&bridge->dev);
}
EXPORT_SYMBOL(pci_free_host_bridge);
@@ -908,10 +910,11 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
if (err)
goto free;
- err = device_register(&bridge->dev);
- if (err)
+ err = device_add(&bridge->dev);
+ if (err) {
put_device(&bridge->dev);
-
+ goto free;
+ }
bus->bridge = get_device(&bridge->dev);
device_enable_async_suspend(bus->bridge);
pci_set_bus_of_node(bus);
@@ -977,7 +980,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
unregister:
put_device(&bridge->dev);
- device_unregister(&bridge->dev);
+ device_del(&bridge->dev);
free:
kfree(bus);
@@ -1934,13 +1937,33 @@ static void pci_configure_mps(struct pci_dev *dev)
struct pci_dev *bridge = pci_upstream_bridge(dev);
int mps, mpss, p_mps, rc;
- if (!pci_is_pcie(dev) || !bridge || !pci_is_pcie(bridge))
+ if (!pci_is_pcie(dev))
return;
/* MPS and MRRS fields are of type 'RsvdP' for VFs, short-circuit out */
if (dev->is_virtfn)
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);
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;
err_out:
- kfree(bridge);
+ put_device(&bridge->dev);
return NULL;
}
EXPORT_SYMBOL_GPL(pci_create_root_bus);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index e9c6b120cf45..95dec03d9f2a 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -160,6 +160,6 @@ void pci_remove_root_bus(struct pci_bus *bus)
host_bridge->bus = NULL;
/* remove the host bridge */
- device_unregister(&host_bridge->dev);
+ device_del(&host_bridge->dev);
}
EXPORT_SYMBOL_GPL(pci_remove_root_bus);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index bbcef1a053ab..07cd7a3817dc 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -583,7 +583,7 @@ static void pci_setup_bridge_io(struct pci_dev *bridge)
io_mask = PCI_IO_1K_RANGE_MASK;
/* 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);
if (res->flags & IORESOURCE_IO) {
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;
/* 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);
if (res->flags & IORESOURCE_MEM) {
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 */
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);
if (res->flags & IORESOURCE_PREFETCH) {
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))
return -EINVAL; /* Clipping didn't change anything */
- switch (i - PCI_BRIDGE_RESOURCES) {
- case 0:
+ switch (i) {
+ case PCI_BRIDGE_IO_WINDOW:
pci_setup_bridge_io(bridge);
break;
- case 1:
+ case PCI_BRIDGE_MEM_WINDOW:
pci_setup_bridge_mmio(bridge);
break;
- case 2:
+ case PCI_BRIDGE_PREF_MEM_WINDOW:
pci_setup_bridge_mmio_pref(bridge);
break;
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)
{
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)
- b_res[0].flags |= IORESOURCE_IO;
+ if (bridge->io_window) {
+ b_res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
+ b_res->flags |= IORESOURCE_IO;
+ }
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) {
- b_res[2].flags |= IORESOURCE_MEM_64;
- b_res[2].flags |= PCI_PREF_RANGE_TYPE_64;
+ b_res->flags |= IORESOURCE_MEM_64 |
+ PCI_PREF_RANGE_TYPE_64;
}
}
}
@@ -1105,35 +1109,37 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
struct list_head *realloc_head)
{
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;
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;
/*
* Reserve some resources for CardBus. We reserve a fixed amount
* of bus space for CardBus bridges.
*/
- b_res[0].start = pci_cardbus_io_size;
- b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1;
- b_res[0].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
+ b_res->start = pci_cardbus_io_size;
+ b_res->end = b_res->start + pci_cardbus_io_size - 1;
+ b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
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,
- pci_cardbus_io_size);
+ pci_cardbus_io_size);
}
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;
- b_res[1].start = pci_cardbus_io_size;
- b_res[1].end = b_res[1].start + pci_cardbus_io_size - 1;
- b_res[1].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
+ b_res->start = pci_cardbus_io_size;
+ b_res->end = b_res->start + pci_cardbus_io_size - 1;
+ b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
if (realloc_head) {
- b_res[1].end -= pci_cardbus_io_size;
- add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size,
- pci_cardbus_io_size);
+ b_res->end -= pci_cardbus_io_size;
+ add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size,
+ pci_cardbus_io_size);
}
handle_b_res_2:
@@ -1153,21 +1159,22 @@ handle_b_res_2:
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;
/*
* If we have prefetchable memory support, allocate two regions.
* Otherwise, allocate one region of twice the size.
*/
if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
- b_res[2].start = pci_cardbus_mem_size;
- b_res[2].end = b_res[2].start + pci_cardbus_mem_size - 1;
- b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
- IORESOURCE_STARTALIGN;
+ b_res->start = pci_cardbus_mem_size;
+ b_res->end = b_res->start + pci_cardbus_mem_size - 1;
+ b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
+ IORESOURCE_STARTALIGN;
if (realloc_head) {
- b_res[2].end -= pci_cardbus_mem_size;
- add_to_list(realloc_head, bridge, b_res+2,
- pci_cardbus_mem_size, pci_cardbus_mem_size);
+ b_res->end -= pci_cardbus_mem_size;
+ add_to_list(realloc_head, bridge, b_res,
+ pci_cardbus_mem_size, pci_cardbus_mem_size);
}
/* Reduce that to half */
@@ -1175,15 +1182,16 @@ handle_b_res_2:
}
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;
- b_res[3].start = pci_cardbus_mem_size;
- b_res[3].end = b_res[3].start + b_res_3_size - 1;
- b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
+ b_res->start = pci_cardbus_mem_size;
+ b_res->end = b_res->start + b_res_3_size - 1;
+ b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
if (realloc_head) {
- b_res[3].end -= b_res_3_size;
- add_to_list(realloc_head, bridge, b_res+3, b_res_3_size,
- pci_cardbus_mem_size);
+ b_res->end -= b_res_3_size;
+ add_to_list(realloc_head, bridge, b_res, b_res_3_size,
+ pci_cardbus_mem_size);
}
handle_done:
@@ -1227,7 +1235,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
break;
hdr_type = -1; /* Intentionally invalid - not a PCI device. */
} else {
- pref = &bus->self->resource[PCI_BRIDGE_RESOURCES + 2];
+ pref = &bus->self->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
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;
resource_size_t io_per_hp, mmio_per_hp, mmio_pref_per_hp, align;
- io_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
- mmio_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
- mmio_pref_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
+ io_res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
+ mmio_res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
+ mmio_pref_res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
/*
* 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
* 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 = align ? ALIGN(io.start, align) - io.start : 0;
used_size = align + resource_size(res);
if (!res->parent)
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 = align ? ALIGN(mmio.start, align) - mmio.start : 0;
used_size = align + resource_size(res);
if (!res->parent)
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 = align ? ALIGN(mmio_pref.start, align) -
mmio_pref.start : 0;
@@ -2027,9 +2035,9 @@ static void pci_bridge_distribute_available_resources(struct pci_dev *bridge,
return;
/* Take the initial extra resources from the hotplug port */
- available_io = bridge->resource[PCI_BRIDGE_RESOURCES + 0];
- available_mmio = bridge->resource[PCI_BRIDGE_RESOURCES + 1];
- available_mmio_pref = bridge->resource[PCI_BRIDGE_RESOURCES + 2];
+ available_io = bridge->resource[PCI_BRIDGE_IO_WINDOW];
+ available_mmio = bridge->resource[PCI_BRIDGE_MEM_WINDOW];
+ available_mmio_pref = bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
pci_bus_distribute_available_resources(bridge->subordinate,
add_list, available_io,