Pick up the CXL DVSEC range register emulation for v6.3, and resolve conflicts with the cxl_port_probe() split (from for-6.3/cxl-ram-region) and event handling (from for-6.3/cxl-events).
···101101 BIT(CXL_CM_CAP_CAP_ID_HDM));102102}103103104104+static struct cxl_hdm *devm_cxl_setup_emulated_hdm(struct cxl_port *port,105105+ struct cxl_endpoint_dvsec_info *info)106106+{107107+ struct device *dev = &port->dev;108108+ struct cxl_hdm *cxlhdm;109109+110110+ if (!info->mem_enabled)111111+ return ERR_PTR(-ENODEV);112112+113113+ cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL);114114+ if (!cxlhdm)115115+ return ERR_PTR(-ENOMEM);116116+117117+ cxlhdm->port = port;118118+ cxlhdm->decoder_count = info->ranges;119119+ cxlhdm->target_count = info->ranges;120120+ dev_set_drvdata(&port->dev, cxlhdm);121121+122122+ return cxlhdm;123123+}124124+104125/**105126 * devm_cxl_setup_hdm - map HDM decoder component registers106127 * @port: cxl_port to map128128+ * @info: cached DVSEC range register info107129 */108108-struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port)130130+struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,131131+ struct cxl_endpoint_dvsec_info *info)109132{110133 struct device *dev = &port->dev;111134 struct cxl_hdm *cxlhdm;···142119 cxlhdm->port = port;143120 crb = ioremap(port->component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE);144121 if (!crb) {122122+ if (info && info->mem_enabled)123123+ return devm_cxl_setup_emulated_hdm(port, info);124124+145125 dev_err(dev, "No component registers mapped\n");146126 return ERR_PTR(-ENXIO);147127 }···714688 return 0;715689}716690691691+static int cxl_setup_hdm_decoder_from_dvsec(struct cxl_port *port,692692+ struct cxl_decoder *cxld, int which,693693+ struct cxl_endpoint_dvsec_info *info)694694+{695695+ if (!is_cxl_endpoint(port))696696+ return -EOPNOTSUPP;697697+698698+ if (!range_len(&info->dvsec_range[which]))699699+ return -ENOENT;700700+701701+ cxld->target_type = CXL_DECODER_EXPANDER;702702+ cxld->commit = NULL;703703+ cxld->reset = NULL;704704+ cxld->hpa_range = info->dvsec_range[which];705705+706706+ /*707707+ * Set the emulated decoder as locked pending additional support to708708+ * change the range registers at run time.709709+ */710710+ cxld->flags |= CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK;711711+ port->commit_end = cxld->id;712712+713713+ return 0;714714+}715715+716716+static bool should_emulate_decoders(struct cxl_port *port)717717+{718718+ struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);719719+ void __iomem *hdm = cxlhdm->regs.hdm_decoder;720720+ u32 ctrl;721721+ int i;722722+723723+ if (!is_cxl_endpoint(cxlhdm->port))724724+ return false;725725+726726+ if (!hdm)727727+ return true;728728+729729+ /*730730+ * If any decoders are committed already, there should not be any731731+ * emulated DVSEC decoders.732732+ */733733+ for (i = 0; i < cxlhdm->decoder_count; i++) {734734+ ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i));735735+ if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))736736+ return false;737737+ }738738+739739+ return true;740740+}741741+717742static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,718743 int *target_map, void __iomem *hdm, int which,719719- u64 *dpa_base)744744+ u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)720745{721746 struct cxl_endpoint_decoder *cxled = NULL;722747 u64 size, base, skip, dpa_size;···779702 u64 value;780703 unsigned char target_id[8];781704 } target_list;705705+706706+ if (should_emulate_decoders(port))707707+ return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info);782708783709 if (is_endpoint_decoder(&cxld->dev))784710 cxled = to_cxl_endpoint_decoder(&cxld->dev);···805725 .start = base,806726 .end = base + size - 1,807727 };728728+729729+ if (cxled && !committed && range_len(&info->dvsec_range[which]))730730+ return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info);808731809732 /* decoders are enabled if committed */810733 if (committed) {···881798 return 0;882799}883800884884-/**885885- * devm_cxl_enumerate_decoders - add decoder objects per HDM register set886886- * @cxlhdm: Structure to populate with HDM capabilities887887- */888888-int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)801801+static void cxl_settle_decoders(struct cxl_hdm *cxlhdm)889802{890803 void __iomem *hdm = cxlhdm->regs.hdm_decoder;891891- struct cxl_port *port = cxlhdm->port;892892- int i, committed;893893- u64 dpa_base = 0;804804+ int committed, i;894805 u32 ctrl;806806+807807+ if (!hdm)808808+ return;895809896810 /*897811 * Since the register resource was recently claimed via request_region()···906826 /* ensure that future checks of committed can be trusted */907827 if (committed != cxlhdm->decoder_count)908828 msleep(20);829829+}830830+831831+/**832832+ * devm_cxl_enumerate_decoders - add decoder objects per HDM register set833833+ * @cxlhdm: Structure to populate with HDM capabilities834834+ * @info: cached DVSEC range register info835835+ */836836+int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,837837+ struct cxl_endpoint_dvsec_info *info)838838+{839839+ void __iomem *hdm = cxlhdm->regs.hdm_decoder;840840+ struct cxl_port *port = cxlhdm->port;841841+ int i;842842+ u64 dpa_base = 0;843843+844844+ cxl_settle_decoders(cxlhdm);909845910846 for (i = 0; i < cxlhdm->decoder_count; i++) {911847 int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };···952856 cxld = &cxlsd->cxld;953857 }954858955955- rc = init_hdm_decoder(port, cxld, target_map, hdm, i, &dpa_base);859859+ rc = init_hdm_decoder(port, cxld, target_map, hdm, i,860860+ &dpa_base, info);956861 if (rc) {957862 dev_warn(&port->dev,958863 "Failed to initialize decoder%d.%d\n",
+125-139
drivers/cxl/core/pci.c
···142142}143143EXPORT_SYMBOL_NS_GPL(cxl_await_media_ready, CXL);144144145145-static int wait_for_valid(struct cxl_dev_state *cxlds)145145+static int wait_for_valid(struct pci_dev *pdev, int d)146146{147147- struct pci_dev *pdev = to_pci_dev(cxlds->dev);148148- int d = cxlds->cxl_dvsec, rc;149147 u32 val;148148+ int rc;150149151150 /*152151 * Memory_Info_Valid: When set, indicates that the CXL Range 1 Size high···224225225226 cxld = to_cxl_decoder(dev);226227227227- if (!(cxld->flags & CXL_DECODER_F_LOCK))228228- return 0;229228 if (!(cxld->flags & CXL_DECODER_F_RAM))230229 return 0;231230···253256 return devm_add_action_or_reset(host, disable_hdm, cxlhdm);254257}255258256256-static bool __cxl_hdm_decode_init(struct cxl_dev_state *cxlds,257257- struct cxl_hdm *cxlhdm,258258- struct cxl_endpoint_dvsec_info *info)259259+int cxl_dvsec_rr_decode(struct device *dev, int d,260260+ struct cxl_endpoint_dvsec_info *info)261261+{262262+ struct pci_dev *pdev = to_pci_dev(dev);263263+ int hdm_count, rc, i, ranges = 0;264264+ u16 cap, ctrl;265265+266266+ if (!d) {267267+ dev_dbg(dev, "No DVSEC Capability\n");268268+ return -ENXIO;269269+ }270270+271271+ rc = pci_read_config_word(pdev, d + CXL_DVSEC_CAP_OFFSET, &cap);272272+ if (rc)273273+ return rc;274274+275275+ rc = pci_read_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, &ctrl);276276+ if (rc)277277+ return rc;278278+279279+ if (!(cap & CXL_DVSEC_MEM_CAPABLE)) {280280+ dev_dbg(dev, "Not MEM Capable\n");281281+ return -ENXIO;282282+ }283283+284284+ /*285285+ * It is not allowed by spec for MEM.capable to be set and have 0 legacy286286+ * HDM decoders (values > 2 are also undefined as of CXL 2.0). As this287287+ * driver is for a spec defined class code which must be CXL.mem288288+ * capable, there is no point in continuing to enable CXL.mem.289289+ */290290+ hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap);291291+ if (!hdm_count || hdm_count > 2)292292+ return -EINVAL;293293+294294+ rc = wait_for_valid(pdev, d);295295+ if (rc) {296296+ dev_dbg(dev, "Failure awaiting MEM_INFO_VALID (%d)\n", rc);297297+ return rc;298298+ }299299+300300+ /*301301+ * The current DVSEC values are moot if the memory capability is302302+ * disabled, and they will remain moot after the HDM Decoder303303+ * capability is enabled.304304+ */305305+ info->mem_enabled = FIELD_GET(CXL_DVSEC_MEM_ENABLE, ctrl);306306+ if (!info->mem_enabled)307307+ return 0;308308+309309+ for (i = 0; i < hdm_count; i++) {310310+ u64 base, size;311311+ u32 temp;312312+313313+ rc = pci_read_config_dword(314314+ pdev, d + CXL_DVSEC_RANGE_SIZE_HIGH(i), &temp);315315+ if (rc)316316+ return rc;317317+318318+ size = (u64)temp << 32;319319+320320+ rc = pci_read_config_dword(321321+ pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(i), &temp);322322+ if (rc)323323+ return rc;324324+325325+ size |= temp & CXL_DVSEC_MEM_SIZE_LOW_MASK;326326+ if (!size) {327327+ info->dvsec_range[i] = (struct range) {328328+ .start = 0,329329+ .end = CXL_RESOURCE_NONE,330330+ };331331+ continue;332332+ }333333+334334+ rc = pci_read_config_dword(335335+ pdev, d + CXL_DVSEC_RANGE_BASE_HIGH(i), &temp);336336+ if (rc)337337+ return rc;338338+339339+ base = (u64)temp << 32;340340+341341+ rc = pci_read_config_dword(342342+ pdev, d + CXL_DVSEC_RANGE_BASE_LOW(i), &temp);343343+ if (rc)344344+ return rc;345345+346346+ base |= temp & CXL_DVSEC_MEM_BASE_LOW_MASK;347347+348348+ info->dvsec_range[i] = (struct range) {349349+ .start = base,350350+ .end = base + size - 1351351+ };352352+353353+ ranges++;354354+ }355355+356356+ info->ranges = ranges;357357+358358+ return 0;359359+}360360+EXPORT_SYMBOL_NS_GPL(cxl_dvsec_rr_decode, CXL);361361+362362+/**363363+ * cxl_hdm_decode_init() - Setup HDM decoding for the endpoint364364+ * @cxlds: Device state365365+ * @cxlhdm: Mapped HDM decoder Capability366366+ * @info: Cached DVSEC range registers info367367+ *368368+ * Try to enable the endpoint's HDM Decoder Capability369369+ */370370+int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,371371+ struct cxl_endpoint_dvsec_info *info)259372{260373 void __iomem *hdm = cxlhdm->regs.hdm_decoder;261374 struct cxl_port *port = cxlhdm->port;262375 struct device *dev = cxlds->dev;263376 struct cxl_port *root;264377 int i, rc, allowed;265265- u32 global_ctrl;378378+ u32 global_ctrl = 0;266379267267- global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);380380+ if (hdm)381381+ global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);268382269383 /*270384 * If the HDM Decoder Capability is already enabled then assume271385 * that some other agent like platform firmware set it up.272386 */273273- if (global_ctrl & CXL_HDM_DECODER_ENABLE) {274274- rc = devm_cxl_enable_mem(&port->dev, cxlds);275275- if (rc)276276- return false;277277- return true;278278- }387387+ if (global_ctrl & CXL_HDM_DECODER_ENABLE || (!hdm && info->mem_enabled))388388+ return devm_cxl_enable_mem(&port->dev, cxlds);389389+ else if (!hdm)390390+ return -ENODEV;279391280392 root = to_cxl_port(port->dev.parent);281393 while (!is_cxl_root(root) && is_cxl_port(root->dev.parent))282394 root = to_cxl_port(root->dev.parent);283395 if (!is_cxl_root(root)) {284396 dev_err(dev, "Failed to acquire root port for HDM enable\n");285285- return false;397397+ return -ENODEV;286398 }287399288400 for (i = 0, allowed = 0; info->mem_enabled && i < info->ranges; i++) {···423317 * Decoder Capability Enable.424318 */425319 if (info->mem_enabled)426426- return false;320320+ return 0;427321428322 rc = devm_cxl_enable_hdm(&port->dev, cxlhdm);429323 if (rc)430430- return false;431431-432432- rc = devm_cxl_enable_mem(&port->dev, cxlds);433433- if (rc)434434- return false;435435-436436- return true;437437-}438438-439439-/**440440- * cxl_hdm_decode_init() - Setup HDM decoding for the endpoint441441- * @cxlds: Device state442442- * @cxlhdm: Mapped HDM decoder Capability443443- *444444- * Try to enable the endpoint's HDM Decoder Capability445445- */446446-int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)447447-{448448- struct pci_dev *pdev = to_pci_dev(cxlds->dev);449449- struct cxl_endpoint_dvsec_info info = { 0 };450450- int hdm_count, rc, i, ranges = 0;451451- struct device *dev = &pdev->dev;452452- int d = cxlds->cxl_dvsec;453453- u16 cap, ctrl;454454-455455- if (!d) {456456- dev_dbg(dev, "No DVSEC Capability\n");457457- return -ENXIO;458458- }459459-460460- rc = pci_read_config_word(pdev, d + CXL_DVSEC_CAP_OFFSET, &cap);461461- if (rc)462324 return rc;463325464464- rc = pci_read_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, &ctrl);465465- if (rc)466466- return rc;467467-468468- if (!(cap & CXL_DVSEC_MEM_CAPABLE)) {469469- dev_dbg(dev, "Not MEM Capable\n");470470- return -ENXIO;471471- }472472-473473- /*474474- * It is not allowed by spec for MEM.capable to be set and have 0 legacy475475- * HDM decoders (values > 2 are also undefined as of CXL 2.0). As this476476- * driver is for a spec defined class code which must be CXL.mem477477- * capable, there is no point in continuing to enable CXL.mem.478478- */479479- hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap);480480- if (!hdm_count || hdm_count > 2)481481- return -EINVAL;482482-483483- rc = wait_for_valid(cxlds);484484- if (rc) {485485- dev_dbg(dev, "Failure awaiting MEM_INFO_VALID (%d)\n", rc);486486- return rc;487487- }488488-489489- /*490490- * The current DVSEC values are moot if the memory capability is491491- * disabled, and they will remain moot after the HDM Decoder492492- * capability is enabled.493493- */494494- info.mem_enabled = FIELD_GET(CXL_DVSEC_MEM_ENABLE, ctrl);495495- if (!info.mem_enabled)496496- goto hdm_init;497497-498498- for (i = 0; i < hdm_count; i++) {499499- u64 base, size;500500- u32 temp;501501-502502- rc = pci_read_config_dword(503503- pdev, d + CXL_DVSEC_RANGE_SIZE_HIGH(i), &temp);504504- if (rc)505505- return rc;506506-507507- size = (u64)temp << 32;508508-509509- rc = pci_read_config_dword(510510- pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(i), &temp);511511- if (rc)512512- return rc;513513-514514- size |= temp & CXL_DVSEC_MEM_SIZE_LOW_MASK;515515-516516- rc = pci_read_config_dword(517517- pdev, d + CXL_DVSEC_RANGE_BASE_HIGH(i), &temp);518518- if (rc)519519- return rc;520520-521521- base = (u64)temp << 32;522522-523523- rc = pci_read_config_dword(524524- pdev, d + CXL_DVSEC_RANGE_BASE_LOW(i), &temp);525525- if (rc)526526- return rc;527527-528528- base |= temp & CXL_DVSEC_MEM_BASE_LOW_MASK;529529-530530- info.dvsec_range[i] = (struct range) {531531- .start = base,532532- .end = base + size - 1533533- };534534-535535- if (size)536536- ranges++;537537- }538538-539539- info.ranges = ranges;540540-541541- /*542542- * If DVSEC ranges are being used instead of HDM decoder registers there543543- * is no use in trying to manage those.544544- */545545-hdm_init:546546- if (!__cxl_hdm_decode_init(cxlds, cxlhdm, &info)) {547547- dev_err(dev,548548- "Legacy range registers configuration prevents HDM operation.\n");549549- return -EBUSY;550550- }551551-552552- return 0;326326+ return devm_cxl_enable_mem(&port->dev, cxlds);553327}554328EXPORT_SYMBOL_NS_GPL(cxl_hdm_decode_init, CXL);555329
+18-2
drivers/cxl/cxl.h
···693693int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld);694694int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint);695695696696+/**697697+ * struct cxl_endpoint_dvsec_info - Cached DVSEC info698698+ * @mem_enabled: cached value of mem_enabled in the DVSEC, PCIE_DEVICE699699+ * @ranges: Number of active HDM ranges this device uses.700700+ * @dvsec_range: cached attributes of the ranges in the DVSEC, PCIE_DEVICE701701+ */702702+struct cxl_endpoint_dvsec_info {703703+ bool mem_enabled;704704+ int ranges;705705+ struct range dvsec_range[2];706706+};707707+696708struct cxl_hdm;697697-struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port);698698-int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm);709709+struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,710710+ struct cxl_endpoint_dvsec_info *info);711711+int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,712712+ struct cxl_endpoint_dvsec_info *info);699713int devm_cxl_add_passthrough_decoder(struct cxl_port *port);714714+int cxl_dvsec_rr_decode(struct device *dev, int dvsec,715715+ struct cxl_endpoint_dvsec_info *info);700716701717bool is_cxl_region(struct device *dev);702718
-12
drivers/cxl/cxlmem.h
···188188#define CXL_CAPACITY_MULTIPLIER SZ_256M189189190190/**191191- * struct cxl_endpoint_dvsec_info - Cached DVSEC info192192- * @mem_enabled: cached value of mem_enabled in the DVSEC, PCIE_DEVICE193193- * @ranges: Number of active HDM ranges this device uses.194194- * @dvsec_range: cached attributes of the ranges in the DVSEC, PCIE_DEVICE195195- */196196-struct cxl_endpoint_dvsec_info {197197- bool mem_enabled;198198- int ranges;199199- struct range dvsec_range[2];200200-};201201-202202-/**203191 * Event Interrupt Policy204192 *205193 * CXL rev 3.0 section 8.2.9.2.4; Table 8-52