Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Copyright(c) 2022 Intel Corporation. All rights reserved. */
0003 #include <linux/device.h>
0004 #include <linux/module.h>
0005 #include <linux/slab.h>
0006 
0007 #include "cxlmem.h"
0008 #include "cxlpci.h"
0009 
0010 /**
0011  * DOC: cxl port
0012  *
0013  * The port driver enumerates dport via PCI and scans for HDM
0014  * (Host-managed-Device-Memory) decoder resources via the
0015  * @component_reg_phys value passed in by the agent that registered the
0016  * port. All descendant ports of a CXL root port (described by platform
0017  * firmware) are managed in this drivers context. Each driver instance
0018  * is responsible for tearing down the driver context of immediate
0019  * descendant ports. The locking for this is validated by
0020  * CONFIG_PROVE_CXL_LOCKING.
0021  *
0022  * The primary service this driver provides is presenting APIs to other
0023  * drivers to utilize the decoders, and indicating to userspace (via bind
0024  * status) the connectivity of the CXL.mem protocol throughout the
0025  * PCIe topology.
0026  */
0027 
0028 static void schedule_detach(void *cxlmd)
0029 {
0030     schedule_cxl_memdev_detach(cxlmd);
0031 }
0032 
0033 static int cxl_port_probe(struct device *dev)
0034 {
0035     struct cxl_port *port = to_cxl_port(dev);
0036     struct cxl_hdm *cxlhdm;
0037     int rc;
0038 
0039 
0040     if (!is_cxl_endpoint(port)) {
0041         rc = devm_cxl_port_enumerate_dports(port);
0042         if (rc < 0)
0043             return rc;
0044         if (rc == 1)
0045             return devm_cxl_add_passthrough_decoder(port);
0046     }
0047 
0048     cxlhdm = devm_cxl_setup_hdm(port);
0049     if (IS_ERR(cxlhdm))
0050         return PTR_ERR(cxlhdm);
0051 
0052     if (is_cxl_endpoint(port)) {
0053         struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport);
0054         struct cxl_dev_state *cxlds = cxlmd->cxlds;
0055 
0056         /* Cache the data early to ensure is_visible() works */
0057         read_cdat_data(port);
0058 
0059         get_device(&cxlmd->dev);
0060         rc = devm_add_action_or_reset(dev, schedule_detach, cxlmd);
0061         if (rc)
0062             return rc;
0063 
0064         rc = cxl_hdm_decode_init(cxlds, cxlhdm);
0065         if (rc)
0066             return rc;
0067 
0068         rc = cxl_await_media_ready(cxlds);
0069         if (rc) {
0070             dev_err(dev, "Media not active (%d)\n", rc);
0071             return rc;
0072         }
0073     }
0074 
0075     rc = devm_cxl_enumerate_decoders(cxlhdm);
0076     if (rc) {
0077         dev_err(dev, "Couldn't enumerate decoders (%d)\n", rc);
0078         return rc;
0079     }
0080 
0081     return 0;
0082 }
0083 
0084 static ssize_t CDAT_read(struct file *filp, struct kobject *kobj,
0085              struct bin_attribute *bin_attr, char *buf,
0086              loff_t offset, size_t count)
0087 {
0088     struct device *dev = kobj_to_dev(kobj);
0089     struct cxl_port *port = to_cxl_port(dev);
0090 
0091     if (!port->cdat_available)
0092         return -ENXIO;
0093 
0094     if (!port->cdat.table)
0095         return 0;
0096 
0097     return memory_read_from_buffer(buf, count, &offset,
0098                        port->cdat.table,
0099                        port->cdat.length);
0100 }
0101 
0102 static BIN_ATTR_ADMIN_RO(CDAT, 0);
0103 
0104 static umode_t cxl_port_bin_attr_is_visible(struct kobject *kobj,
0105                         struct bin_attribute *attr, int i)
0106 {
0107     struct device *dev = kobj_to_dev(kobj);
0108     struct cxl_port *port = to_cxl_port(dev);
0109 
0110     if ((attr == &bin_attr_CDAT) && port->cdat_available)
0111         return attr->attr.mode;
0112 
0113     return 0;
0114 }
0115 
0116 static struct bin_attribute *cxl_cdat_bin_attributes[] = {
0117     &bin_attr_CDAT,
0118     NULL,
0119 };
0120 
0121 static struct attribute_group cxl_cdat_attribute_group = {
0122     .bin_attrs = cxl_cdat_bin_attributes,
0123     .is_bin_visible = cxl_port_bin_attr_is_visible,
0124 };
0125 
0126 static const struct attribute_group *cxl_port_attribute_groups[] = {
0127     &cxl_cdat_attribute_group,
0128     NULL,
0129 };
0130 
0131 static struct cxl_driver cxl_port_driver = {
0132     .name = "cxl_port",
0133     .probe = cxl_port_probe,
0134     .id = CXL_DEVICE_PORT,
0135     .drv = {
0136         .dev_groups = cxl_port_attribute_groups,
0137     },
0138 };
0139 
0140 module_cxl_driver(cxl_port_driver);
0141 MODULE_LICENSE("GPL v2");
0142 MODULE_IMPORT_NS(CXL);
0143 MODULE_ALIAS_CXL(CXL_DEVICE_PORT);