0001
0002
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
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
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
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);