cxl/port: Introduce cxl_port_to_pci_bus()
authorDan Williams <dan.j.williams@intel.com>
Mon, 31 Jan 2022 16:44:52 +0000 (08:44 -0800)
committerDan Williams <dan.j.williams@intel.com>
Wed, 9 Feb 2022 06:57:29 +0000 (22:57 -0800)
Add a helper for converting a PCI enumerated cxl_port into the pci_bus
that hosts its dports. For switch ports this is trivial, but for root
ports there is no generic way to go from a platform defined host bridge
device, like ACPI0016 to its corresponding pci_bus. Rather than spill
ACPI goop outside of the cxl_acpi driver, just arrange for it to
register an xarray translation from the uport device to the
corresponding pci_bus.

This is in preparation for centralizing dport enumeration in the core.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Ben Widawsky <ben.widawsky@intel.com>
Link: https://lore.kernel.org/r/164364745633.85488.9744017377155103992.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/cxl/acpi.c
drivers/cxl/core/port.c
drivers/cxl/cxl.h

index 93d1dc5..ab2b765 100644 (file)
@@ -225,17 +225,21 @@ static int add_host_bridge_uport(struct device *match, void *arg)
                return 0;
        }
 
+       /*
+        * Note that this lookup already succeeded in
+        * to_cxl_host_bridge(), so no need to check for failure here
+        */
+       pci_root = acpi_pci_find_root(bridge->handle);
+       rc = devm_cxl_register_pci_bus(host, match, pci_root->bus);
+       if (rc)
+               return rc;
+
        port = devm_cxl_add_port(host, match, dport->component_reg_phys,
                                 root_port);
        if (IS_ERR(port))
                return PTR_ERR(port);
        dev_dbg(host, "%s: add: %s\n", dev_name(match), dev_name(&port->dev));
 
-       /*
-        * Note that this lookup already succeeded in
-        * to_cxl_host_bridge(), so no need to check for failure here
-        */
-       pci_root = acpi_pci_find_root(bridge->handle);
        ctx = (struct cxl_walk_context){
                .dev = host,
                .root = pci_root->bus,
index fc5d862..2a4230d 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 static DEFINE_IDA(cxl_port_ida);
+static DEFINE_XARRAY(cxl_root_buses);
 
 static ssize_t devtype_show(struct device *dev, struct device_attribute *attr,
                            char *buf)
@@ -418,6 +419,42 @@ err:
 }
 EXPORT_SYMBOL_NS_GPL(devm_cxl_add_port, CXL);
 
+struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port)
+{
+       /* There is no pci_bus associated with a CXL platform-root port */
+       if (is_cxl_root(port))
+               return NULL;
+
+       if (dev_is_pci(port->uport)) {
+               struct pci_dev *pdev = to_pci_dev(port->uport);
+
+               return pdev->subordinate;
+       }
+
+       return xa_load(&cxl_root_buses, (unsigned long)port->uport);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_port_to_pci_bus, CXL);
+
+static void unregister_pci_bus(void *uport)
+{
+       xa_erase(&cxl_root_buses, (unsigned long)uport);
+}
+
+int devm_cxl_register_pci_bus(struct device *host, struct device *uport,
+                             struct pci_bus *bus)
+{
+       int rc;
+
+       if (dev_is_pci(uport))
+               return -EINVAL;
+
+       rc = xa_insert(&cxl_root_buses, (unsigned long)uport, bus, GFP_KERNEL);
+       if (rc)
+               return rc;
+       return devm_add_action_or_reset(host, unregister_pci_bus, uport);
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_register_pci_bus, CXL);
+
 static struct cxl_dport *find_dport(struct cxl_port *port, int id)
 {
        struct cxl_dport *dport;
index e791629..4d4cc82 100644 (file)
@@ -295,6 +295,9 @@ static inline bool is_cxl_root(struct cxl_port *port)
 
 bool is_cxl_port(struct device *dev);
 struct cxl_port *to_cxl_port(struct device *dev);
+int devm_cxl_register_pci_bus(struct device *host, struct device *uport,
+                             struct pci_bus *bus);
+struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port);
 struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
                                   resource_size_t component_reg_phys,
                                   struct cxl_port *parent_port);