Merge tag 'pci-v4.10-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI updates from Bjorn Helgaas:
"PCI changes:
- add support for PCI on ARM64 boxes with ACPI. We already had this
for theoretical spec-compliant hardware; now we're adding quirks
for the actual hardware (Cavium, HiSilicon, Qualcomm, X-Gene)
- add runtime PM support for hotplug ports
- enable runtime suspend for Intel UHCI that uses platform-specific
wakeup signaling
- add yet another host bridge registration interface. We hope this is
extensible enough to subsume the others
- expose device revision in sysfs for DRM
- to avoid device conflicts, make sure any VF BAR updates are done
before enabling the VF
- avoid unnecessary link retrains for ASPM
- allow INTx masking on Mellanox devices that support it
- allow access to non-standard VPD for Chelsio devices
- update Broadcom iProc support for PAXB v2, PAXC v2, inbound DMA,
etc
- update Rockchip support for max-link-speed
- add NVIDIA Tegra210 support
- add Layerscape LS1046a support
- update R-Car compatibility strings
- add Qualcomm MSM8996 support
- remove some uninformative bootup messages"
* tag 'pci-v4.10-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (115 commits)
PCI: Enable access to non-standard VPD for Chelsio devices (cxgb3)
PCI: Expand "VPD access disabled" quirk message
PCI: pciehp: Remove loading message
PCI: hotplug: Remove hotplug core message
PCI: Remove service driver load/unload messages
PCI/AER: Log AER IRQ when claiming Root Port
PCI/AER: Log errors with PCI device, not PCIe service device
PCI/AER: Remove unused version macros
PCI/PME: Log PME IRQ when claiming Root Port
PCI/PME: Drop unused support for PMEs from Root Complex Event Collectors
PCI: Move config space size macros to pci_regs.h
x86/platform/intel-mid: Constify mid_pci_platform_pm
PCI/ASPM: Don't retrain link if ASPM not possible
PCI: iproc: Skip check for legacy IRQ on PAXC buses
PCI: pciehp: Leave power indicator on when enabling already-enabled slot
PCI: pciehp: Prioritize data-link event over presence detect
PCI: rcar: Add gen3 fallback compatibility string for pcie-rcar
PCI: rcar: Use gen2 fallback compatibility last
PCI: rcar-gen2: Use gen2 fallback compatibility last
PCI: rockchip: Move the deassert of pm/aclk/pclk after phy_init()
..
This commit is contained in:
@@ -227,7 +227,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
|
||||
mask64 = (u32)PCI_BASE_ADDRESS_MEM_MASK;
|
||||
}
|
||||
} else {
|
||||
res->flags |= (l & IORESOURCE_ROM_ENABLE);
|
||||
if (l & PCI_ROM_ADDRESS_ENABLE)
|
||||
res->flags |= IORESOURCE_ROM_ENABLE;
|
||||
l64 = l & PCI_ROM_ADDRESS_MASK;
|
||||
sz64 = sz & PCI_ROM_ADDRESS_MASK;
|
||||
mask64 = (u32)PCI_ROM_ADDRESS_MASK;
|
||||
@@ -521,18 +522,19 @@ static void pci_release_host_bridge_dev(struct device *dev)
|
||||
kfree(bridge);
|
||||
}
|
||||
|
||||
static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
|
||||
struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
|
||||
{
|
||||
struct pci_host_bridge *bridge;
|
||||
|
||||
bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
|
||||
bridge = kzalloc(sizeof(*bridge) + priv, GFP_KERNEL);
|
||||
if (!bridge)
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&bridge->windows);
|
||||
bridge->bus = b;
|
||||
|
||||
return bridge;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_alloc_host_bridge);
|
||||
|
||||
static const unsigned char pcix_bus_speed[] = {
|
||||
PCI_SPEED_UNKNOWN, /* 0 */
|
||||
@@ -717,6 +719,123 @@ static void pci_set_bus_msi_domain(struct pci_bus *bus)
|
||||
dev_set_msi_domain(&bus->dev, d);
|
||||
}
|
||||
|
||||
int pci_register_host_bridge(struct pci_host_bridge *bridge)
|
||||
{
|
||||
struct device *parent = bridge->dev.parent;
|
||||
struct resource_entry *window, *n;
|
||||
struct pci_bus *bus, *b;
|
||||
resource_size_t offset;
|
||||
LIST_HEAD(resources);
|
||||
struct resource *res;
|
||||
char addr[64], *fmt;
|
||||
const char *name;
|
||||
int err;
|
||||
|
||||
bus = pci_alloc_bus(NULL);
|
||||
if (!bus)
|
||||
return -ENOMEM;
|
||||
|
||||
bridge->bus = bus;
|
||||
|
||||
/* temporarily move resources off the list */
|
||||
list_splice_init(&bridge->windows, &resources);
|
||||
bus->sysdata = bridge->sysdata;
|
||||
bus->msi = bridge->msi;
|
||||
bus->ops = bridge->ops;
|
||||
bus->number = bus->busn_res.start = bridge->busnr;
|
||||
#ifdef CONFIG_PCI_DOMAINS_GENERIC
|
||||
bus->domain_nr = pci_bus_find_domain_nr(bus, parent);
|
||||
#endif
|
||||
|
||||
b = pci_find_bus(pci_domain_nr(bus), bridge->busnr);
|
||||
if (b) {
|
||||
/* If we already got to this bus through a different bridge, ignore it */
|
||||
dev_dbg(&b->dev, "bus already known\n");
|
||||
err = -EEXIST;
|
||||
goto free;
|
||||
}
|
||||
|
||||
dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(bus),
|
||||
bridge->busnr);
|
||||
|
||||
err = pcibios_root_bridge_prepare(bridge);
|
||||
if (err)
|
||||
goto free;
|
||||
|
||||
err = device_register(&bridge->dev);
|
||||
if (err)
|
||||
put_device(&bridge->dev);
|
||||
|
||||
bus->bridge = get_device(&bridge->dev);
|
||||
device_enable_async_suspend(bus->bridge);
|
||||
pci_set_bus_of_node(bus);
|
||||
pci_set_bus_msi_domain(bus);
|
||||
|
||||
if (!parent)
|
||||
set_dev_node(bus->bridge, pcibus_to_node(bus));
|
||||
|
||||
bus->dev.class = &pcibus_class;
|
||||
bus->dev.parent = bus->bridge;
|
||||
|
||||
dev_set_name(&bus->dev, "%04x:%02x", pci_domain_nr(bus), bus->number);
|
||||
name = dev_name(&bus->dev);
|
||||
|
||||
err = device_register(&bus->dev);
|
||||
if (err)
|
||||
goto unregister;
|
||||
|
||||
pcibios_add_bus(bus);
|
||||
|
||||
/* Create legacy_io and legacy_mem files for this bus */
|
||||
pci_create_legacy_files(bus);
|
||||
|
||||
if (parent)
|
||||
dev_info(parent, "PCI host bridge to bus %s\n", name);
|
||||
else
|
||||
pr_info("PCI host bridge to bus %s\n", name);
|
||||
|
||||
/* Add initial resources to the bus */
|
||||
resource_list_for_each_entry_safe(window, n, &resources) {
|
||||
list_move_tail(&window->node, &bridge->windows);
|
||||
offset = window->offset;
|
||||
res = window->res;
|
||||
|
||||
if (res->flags & IORESOURCE_BUS)
|
||||
pci_bus_insert_busn_res(bus, bus->number, res->end);
|
||||
else
|
||||
pci_bus_add_resource(bus, res, 0);
|
||||
|
||||
if (offset) {
|
||||
if (resource_type(res) == IORESOURCE_IO)
|
||||
fmt = " (bus address [%#06llx-%#06llx])";
|
||||
else
|
||||
fmt = " (bus address [%#010llx-%#010llx])";
|
||||
|
||||
snprintf(addr, sizeof(addr), fmt,
|
||||
(unsigned long long)(res->start - offset),
|
||||
(unsigned long long)(res->end - offset));
|
||||
} else
|
||||
addr[0] = '\0';
|
||||
|
||||
dev_info(&bus->dev, "root bus resource %pR%s\n", res, addr);
|
||||
}
|
||||
|
||||
down_write(&pci_bus_sem);
|
||||
list_add_tail(&bus->node, &pci_root_buses);
|
||||
up_write(&pci_bus_sem);
|
||||
|
||||
return 0;
|
||||
|
||||
unregister:
|
||||
put_device(&bridge->dev);
|
||||
device_unregister(&bridge->dev);
|
||||
|
||||
free:
|
||||
kfree(bus);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_register_host_bridge);
|
||||
|
||||
static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
|
||||
struct pci_dev *bridge, int busnr)
|
||||
{
|
||||
@@ -2155,113 +2274,43 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
|
||||
{
|
||||
}
|
||||
|
||||
struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
|
||||
struct pci_ops *ops, void *sysdata, struct list_head *resources)
|
||||
static struct pci_bus *pci_create_root_bus_msi(struct device *parent,
|
||||
int bus, struct pci_ops *ops, void *sysdata,
|
||||
struct list_head *resources, struct msi_controller *msi)
|
||||
{
|
||||
int error;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct pci_bus *b, *b2;
|
||||
struct resource_entry *window, *n;
|
||||
struct resource *res;
|
||||
resource_size_t offset;
|
||||
char bus_addr[64];
|
||||
char *fmt;
|
||||
|
||||
b = pci_alloc_bus(NULL);
|
||||
if (!b)
|
||||
return NULL;
|
||||
|
||||
b->sysdata = sysdata;
|
||||
b->ops = ops;
|
||||
b->number = b->busn_res.start = bus;
|
||||
#ifdef CONFIG_PCI_DOMAINS_GENERIC
|
||||
b->domain_nr = pci_bus_find_domain_nr(b, parent);
|
||||
#endif
|
||||
b2 = pci_find_bus(pci_domain_nr(b), bus);
|
||||
if (b2) {
|
||||
/* If we already got to this bus through a different bridge, ignore it */
|
||||
dev_dbg(&b2->dev, "bus already known\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
bridge = pci_alloc_host_bridge(b);
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge)
|
||||
goto err_out;
|
||||
return NULL;
|
||||
|
||||
bridge->dev.parent = parent;
|
||||
bridge->dev.release = pci_release_host_bridge_dev;
|
||||
dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
|
||||
error = pcibios_root_bridge_prepare(bridge);
|
||||
if (error) {
|
||||
kfree(bridge);
|
||||
|
||||
list_splice_init(resources, &bridge->windows);
|
||||
bridge->sysdata = sysdata;
|
||||
bridge->busnr = bus;
|
||||
bridge->ops = ops;
|
||||
bridge->msi = msi;
|
||||
|
||||
error = pci_register_host_bridge(bridge);
|
||||
if (error < 0)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
error = device_register(&bridge->dev);
|
||||
if (error) {
|
||||
put_device(&bridge->dev);
|
||||
goto err_out;
|
||||
}
|
||||
b->bridge = get_device(&bridge->dev);
|
||||
device_enable_async_suspend(b->bridge);
|
||||
pci_set_bus_of_node(b);
|
||||
pci_set_bus_msi_domain(b);
|
||||
return bridge->bus;
|
||||
|
||||
if (!parent)
|
||||
set_dev_node(b->bridge, pcibus_to_node(b));
|
||||
|
||||
b->dev.class = &pcibus_class;
|
||||
b->dev.parent = b->bridge;
|
||||
dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus);
|
||||
error = device_register(&b->dev);
|
||||
if (error)
|
||||
goto class_dev_reg_err;
|
||||
|
||||
pcibios_add_bus(b);
|
||||
|
||||
/* Create legacy_io and legacy_mem files for this bus */
|
||||
pci_create_legacy_files(b);
|
||||
|
||||
if (parent)
|
||||
dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
|
||||
else
|
||||
printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev));
|
||||
|
||||
/* Add initial resources to the bus */
|
||||
resource_list_for_each_entry_safe(window, n, resources) {
|
||||
list_move_tail(&window->node, &bridge->windows);
|
||||
res = window->res;
|
||||
offset = window->offset;
|
||||
if (res->flags & IORESOURCE_BUS)
|
||||
pci_bus_insert_busn_res(b, bus, res->end);
|
||||
else
|
||||
pci_bus_add_resource(b, res, 0);
|
||||
if (offset) {
|
||||
if (resource_type(res) == IORESOURCE_IO)
|
||||
fmt = " (bus address [%#06llx-%#06llx])";
|
||||
else
|
||||
fmt = " (bus address [%#010llx-%#010llx])";
|
||||
snprintf(bus_addr, sizeof(bus_addr), fmt,
|
||||
(unsigned long long) (res->start - offset),
|
||||
(unsigned long long) (res->end - offset));
|
||||
} else
|
||||
bus_addr[0] = '\0';
|
||||
dev_info(&b->dev, "root bus resource %pR%s\n", res, bus_addr);
|
||||
}
|
||||
|
||||
down_write(&pci_bus_sem);
|
||||
list_add_tail(&b->node, &pci_root_buses);
|
||||
up_write(&pci_bus_sem);
|
||||
|
||||
return b;
|
||||
|
||||
class_dev_reg_err:
|
||||
put_device(&bridge->dev);
|
||||
device_unregister(&bridge->dev);
|
||||
err_out:
|
||||
kfree(b);
|
||||
kfree(bridge);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
|
||||
struct pci_ops *ops, void *sysdata, struct list_head *resources)
|
||||
{
|
||||
return pci_create_root_bus_msi(parent, bus, ops, sysdata, resources,
|
||||
NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_create_root_bus);
|
||||
|
||||
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
|
||||
@@ -2342,12 +2391,10 @@ struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus,
|
||||
break;
|
||||
}
|
||||
|
||||
b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
|
||||
b = pci_create_root_bus_msi(parent, bus, ops, sysdata, resources, msi);
|
||||
if (!b)
|
||||
return NULL;
|
||||
|
||||
b->msi = msi;
|
||||
|
||||
if (!found) {
|
||||
dev_info(&b->dev,
|
||||
"No busn resource found for root bus, will use [bus %02x-ff]\n",
|
||||
|
||||
Reference in New Issue
Block a user