Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'cxl-fixes-6.4-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl

Pull compute express link fixes from Dan Williams:
"The 'media ready' series prevents the driver from acting on bad
capacity information, and it moves some checks earlier in the init
sequence which impacts topics in the queue for 6.5.

Additional hotplug testing uncovered a missing enable for memory
decode. A debug crash fix is also included.

Summary:

- Stop trusting capacity data before the "media ready" indication

- Add missing HDM decoder capability enable for the cold-plug case

- Fix a debug message induced crash"

* tag 'cxl-fixes-6.4-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl:
cxl: Explicitly initialize resources when media is not ready
cxl/port: Fix NULL pointer access in devm_cxl_add_port()
cxl: Move cxl_await_media_ready() to before capacity info retrieval
cxl: Wait Memory_Info_Valid before access memory related info
cxl/port: Enable the HDM decoder capability for switch ports

+153 -29
+11 -1
drivers/cxl/core/mbox.c
··· 1028 1028 * cxl_dev_state_identify() - Send the IDENTIFY command to the device. 1029 1029 * @cxlds: The device data for the operation 1030 1030 * 1031 - * Return: 0 if identify was executed successfully. 1031 + * Return: 0 if identify was executed successfully or media not ready. 1032 1032 * 1033 1033 * This will dispatch the identify command to the device and on success populate 1034 1034 * structures to be exported to sysfs. ··· 1040 1040 struct cxl_mbox_cmd mbox_cmd; 1041 1041 u32 val; 1042 1042 int rc; 1043 + 1044 + if (!cxlds->media_ready) 1045 + return 0; 1043 1046 1044 1047 mbox_cmd = (struct cxl_mbox_cmd) { 1045 1048 .opcode = CXL_MBOX_OP_IDENTIFY, ··· 1104 1101 { 1105 1102 struct device *dev = cxlds->dev; 1106 1103 int rc; 1104 + 1105 + if (!cxlds->media_ready) { 1106 + cxlds->dpa_res = DEFINE_RES_MEM(0, 0); 1107 + cxlds->ram_res = DEFINE_RES_MEM(0, 0); 1108 + cxlds->pmem_res = DEFINE_RES_MEM(0, 0); 1109 + return 0; 1110 + } 1107 1111 1108 1112 cxlds->dpa_res = 1109 1113 (struct resource)DEFINE_RES_MEM(0, cxlds->total_bytes);
+99 -13
drivers/cxl/core/pci.c
··· 101 101 } 102 102 EXPORT_SYMBOL_NS_GPL(devm_cxl_port_enumerate_dports, CXL); 103 103 104 - /* 105 - * Wait up to @media_ready_timeout for the device to report memory 106 - * active. 107 - */ 108 - int cxl_await_media_ready(struct cxl_dev_state *cxlds) 104 + static int cxl_dvsec_mem_range_valid(struct cxl_dev_state *cxlds, int id) 105 + { 106 + struct pci_dev *pdev = to_pci_dev(cxlds->dev); 107 + int d = cxlds->cxl_dvsec; 108 + bool valid = false; 109 + int rc, i; 110 + u32 temp; 111 + 112 + if (id > CXL_DVSEC_RANGE_MAX) 113 + return -EINVAL; 114 + 115 + /* Check MEM INFO VALID bit first, give up after 1s */ 116 + i = 1; 117 + do { 118 + rc = pci_read_config_dword(pdev, 119 + d + CXL_DVSEC_RANGE_SIZE_LOW(id), 120 + &temp); 121 + if (rc) 122 + return rc; 123 + 124 + valid = FIELD_GET(CXL_DVSEC_MEM_INFO_VALID, temp); 125 + if (valid) 126 + break; 127 + msleep(1000); 128 + } while (i--); 129 + 130 + if (!valid) { 131 + dev_err(&pdev->dev, 132 + "Timeout awaiting memory range %d valid after 1s.\n", 133 + id); 134 + return -ETIMEDOUT; 135 + } 136 + 137 + return 0; 138 + } 139 + 140 + static int cxl_dvsec_mem_range_active(struct cxl_dev_state *cxlds, int id) 109 141 { 110 142 struct pci_dev *pdev = to_pci_dev(cxlds->dev); 111 143 int d = cxlds->cxl_dvsec; 112 144 bool active = false; 113 - u64 md_status; 114 145 int rc, i; 146 + u32 temp; 115 147 148 + if (id > CXL_DVSEC_RANGE_MAX) 149 + return -EINVAL; 150 + 151 + /* Check MEM ACTIVE bit, up to 60s timeout by default */ 116 152 for (i = media_ready_timeout; i; i--) { 117 - u32 temp; 118 - 119 153 rc = pci_read_config_dword( 120 - pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(0), &temp); 154 + pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(id), &temp); 121 155 if (rc) 122 156 return rc; 123 157 ··· 166 132 "timeout awaiting memory active after %d seconds\n", 167 133 media_ready_timeout); 168 134 return -ETIMEDOUT; 135 + } 136 + 137 + return 0; 138 + } 139 + 140 + /* 141 + * Wait up to @media_ready_timeout for the device to report memory 142 + * active. 143 + */ 144 + int cxl_await_media_ready(struct cxl_dev_state *cxlds) 145 + { 146 + struct pci_dev *pdev = to_pci_dev(cxlds->dev); 147 + int d = cxlds->cxl_dvsec; 148 + int rc, i, hdm_count; 149 + u64 md_status; 150 + u16 cap; 151 + 152 + rc = pci_read_config_word(pdev, 153 + d + CXL_DVSEC_CAP_OFFSET, &cap); 154 + if (rc) 155 + return rc; 156 + 157 + hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap); 158 + for (i = 0; i < hdm_count; i++) { 159 + rc = cxl_dvsec_mem_range_valid(cxlds, i); 160 + if (rc) 161 + return rc; 162 + } 163 + 164 + for (i = 0; i < hdm_count; i++) { 165 + rc = cxl_dvsec_mem_range_active(cxlds, i); 166 + if (rc) 167 + return rc; 169 168 } 170 169 171 170 md_status = readq(cxlds->regs.memdev + CXLMDEV_STATUS_OFFSET); ··· 308 241 hdm + CXL_HDM_DECODER_CTRL_OFFSET); 309 242 } 310 243 311 - static int devm_cxl_enable_hdm(struct device *host, struct cxl_hdm *cxlhdm) 244 + int devm_cxl_enable_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm) 312 245 { 313 - void __iomem *hdm = cxlhdm->regs.hdm_decoder; 246 + void __iomem *hdm; 314 247 u32 global_ctrl; 315 248 249 + /* 250 + * If the hdm capability was not mapped there is nothing to enable and 251 + * the caller is responsible for what happens next. For example, 252 + * emulate a passthrough decoder. 253 + */ 254 + if (IS_ERR(cxlhdm)) 255 + return 0; 256 + 257 + hdm = cxlhdm->regs.hdm_decoder; 316 258 global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET); 259 + 260 + /* 261 + * If the HDM decoder capability was enabled on entry, skip 262 + * registering disable_hdm() since this decode capability may be 263 + * owned by platform firmware. 264 + */ 265 + if (global_ctrl & CXL_HDM_DECODER_ENABLE) 266 + return 0; 267 + 317 268 writel(global_ctrl | CXL_HDM_DECODER_ENABLE, 318 269 hdm + CXL_HDM_DECODER_CTRL_OFFSET); 319 270 320 - return devm_add_action_or_reset(host, disable_hdm, cxlhdm); 271 + return devm_add_action_or_reset(&port->dev, disable_hdm, cxlhdm); 321 272 } 273 + EXPORT_SYMBOL_NS_GPL(devm_cxl_enable_hdm, CXL); 322 274 323 275 int cxl_dvsec_rr_decode(struct device *dev, int d, 324 276 struct cxl_endpoint_dvsec_info *info) ··· 511 425 if (info->mem_enabled) 512 426 return 0; 513 427 514 - rc = devm_cxl_enable_hdm(&port->dev, cxlhdm); 428 + rc = devm_cxl_enable_hdm(port, cxlhdm); 515 429 if (rc) 516 430 return rc; 517 431
+3 -4
drivers/cxl/core/port.c
··· 750 750 751 751 parent_port = parent_dport ? parent_dport->port : NULL; 752 752 if (IS_ERR(port)) { 753 - dev_dbg(uport, "Failed to add %s%s%s%s: %ld\n", 754 - dev_name(&port->dev), 755 - parent_port ? " to " : "", 753 + dev_dbg(uport, "Failed to add%s%s%s: %ld\n", 754 + parent_port ? " port to " : "", 756 755 parent_port ? dev_name(&parent_port->dev) : "", 757 - parent_port ? "" : " (root port)", 756 + parent_port ? "" : " root port", 758 757 PTR_ERR(port)); 759 758 } else { 760 759 dev_dbg(uport, "%s added%s%s%s\n",
+1
drivers/cxl/cxl.h
··· 710 710 struct cxl_hdm; 711 711 struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, 712 712 struct cxl_endpoint_dvsec_info *info); 713 + int devm_cxl_enable_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm); 713 714 int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, 714 715 struct cxl_endpoint_dvsec_info *info); 715 716 int devm_cxl_add_passthrough_decoder(struct cxl_port *port);
+2
drivers/cxl/cxlmem.h
··· 266 266 * @regs: Parsed register blocks 267 267 * @cxl_dvsec: Offset to the PCIe device DVSEC 268 268 * @rcd: operating in RCD mode (CXL 3.0 9.11.8 CXL Devices Attached to an RCH) 269 + * @media_ready: Indicate whether the device media is usable 269 270 * @payload_size: Size of space for payload 270 271 * (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register) 271 272 * @lsa_size: Size of Label Storage Area ··· 304 303 int cxl_dvsec; 305 304 306 305 bool rcd; 306 + bool media_ready; 307 307 size_t payload_size; 308 308 size_t lsa_size; 309 309 struct mutex mbox_mutex; /* Protects device mailbox and firmware */
+2
drivers/cxl/cxlpci.h
··· 31 31 #define CXL_DVSEC_RANGE_BASE_LOW(i) (0x24 + (i * 0x10)) 32 32 #define CXL_DVSEC_MEM_BASE_LOW_MASK GENMASK(31, 28) 33 33 34 + #define CXL_DVSEC_RANGE_MAX 2 35 + 34 36 /* CXL 2.0 8.1.4: Non-CXL Function Map DVSEC */ 35 37 #define CXL_DVSEC_FUNCTION_MAP 2 36 38
+3
drivers/cxl/mem.c
··· 124 124 struct dentry *dentry; 125 125 int rc; 126 126 127 + if (!cxlds->media_ready) 128 + return -EBUSY; 129 + 127 130 /* 128 131 * Someone is trying to reattach this device after it lost its port 129 132 * connection (an endpoint port previously registered by this memdev was
+6
drivers/cxl/pci.c
··· 708 708 if (rc) 709 709 dev_dbg(&pdev->dev, "Failed to map RAS capability.\n"); 710 710 711 + rc = cxl_await_media_ready(cxlds); 712 + if (rc == 0) 713 + cxlds->media_ready = true; 714 + else 715 + dev_warn(&pdev->dev, "Media not active (%d)\n", rc); 716 + 711 717 rc = cxl_pci_setup_mailbox(cxlds); 712 718 if (rc) 713 719 return rc;
+9 -11
drivers/cxl/port.c
··· 60 60 static int cxl_switch_port_probe(struct cxl_port *port) 61 61 { 62 62 struct cxl_hdm *cxlhdm; 63 - int rc; 63 + int rc, nr_dports; 64 64 65 - rc = devm_cxl_port_enumerate_dports(port); 66 - if (rc < 0) 67 - return rc; 65 + nr_dports = devm_cxl_port_enumerate_dports(port); 66 + if (nr_dports < 0) 67 + return nr_dports; 68 68 69 69 cxlhdm = devm_cxl_setup_hdm(port, NULL); 70 + rc = devm_cxl_enable_hdm(port, cxlhdm); 71 + if (rc) 72 + return rc; 73 + 70 74 if (!IS_ERR(cxlhdm)) 71 75 return devm_cxl_enumerate_decoders(cxlhdm, NULL); 72 76 ··· 79 75 return PTR_ERR(cxlhdm); 80 76 } 81 77 82 - if (rc == 1) { 78 + if (nr_dports == 1) { 83 79 dev_dbg(&port->dev, "Fallback to passthrough decoder\n"); 84 80 return devm_cxl_add_passthrough_decoder(port); 85 81 } ··· 116 112 rc = cxl_hdm_decode_init(cxlds, cxlhdm, &info); 117 113 if (rc) 118 114 return rc; 119 - 120 - rc = cxl_await_media_ready(cxlds); 121 - if (rc) { 122 - dev_err(&port->dev, "Media not active (%d)\n", rc); 123 - return rc; 124 - } 125 115 126 116 rc = devm_cxl_enumerate_decoders(cxlhdm, &info); 127 117 if (rc)
+1
tools/testing/cxl/Kbuild
··· 6 6 ldflags-y += --wrap=nvdimm_bus_register 7 7 ldflags-y += --wrap=devm_cxl_port_enumerate_dports 8 8 ldflags-y += --wrap=devm_cxl_setup_hdm 9 + ldflags-y += --wrap=devm_cxl_enable_hdm 9 10 ldflags-y += --wrap=devm_cxl_add_passthrough_decoder 10 11 ldflags-y += --wrap=devm_cxl_enumerate_decoders 11 12 ldflags-y += --wrap=cxl_await_media_ready
+1
tools/testing/cxl/test/mem.c
··· 1256 1256 if (rc) 1257 1257 return rc; 1258 1258 1259 + cxlds->media_ready = true; 1259 1260 rc = cxl_dev_state_identify(cxlds); 1260 1261 if (rc) 1261 1262 return rc;
+15
tools/testing/cxl/test/mock.c
··· 149 149 } 150 150 EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_setup_hdm, CXL); 151 151 152 + int __wrap_devm_cxl_enable_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm) 153 + { 154 + int index, rc; 155 + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 156 + 157 + if (ops && ops->is_mock_port(port->uport)) 158 + rc = 0; 159 + else 160 + rc = devm_cxl_enable_hdm(port, cxlhdm); 161 + put_cxl_mock_ops(index); 162 + 163 + return rc; 164 + } 165 + EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_enable_hdm, CXL); 166 + 152 167 int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port) 153 168 { 154 169 int rc, index;