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.3-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl

Pull compute express link (cxl) fixes from Dan Williams:
"Several fixes for driver startup regressions that landed during the
merge window as well as some older bugs.

The regressions were due to a lack of testing with what the CXL
specification calls Restricted CXL Host (RCH) topologies compared to
the testing with Virtual Host (VH) CXL topologies. A VH topology is
typical PCIe while RCH topologies map CXL endpoints as Root Complex
Integrated endpoints. The impact is some driver crashes on startup.

This merge window also added compatibility for range registers (the
mechanism that CXL 1.1 defined for mapping memory) to treat them like
HDM decoders (the mechanism that CXL 2.0 defined for mapping
Host-managed Device Memory). That work collided with the new region
enumeration code that was tested with CXL 2.0 setups, and fails with
crashes at startup.

Lastly, the DOE (Data Object Exchange) implementation for retrieving
an ACPI-like data table from CXL devices is being reworked for v6.4.
Several fixes fell out of that work that are suitable for v6.3.

All of this has been in linux-next for a while, and all reported
issues [1] have been addressed.

Summary:

- Fix several issues with region enumeration in RCH topologies that
can trigger crashes on driver startup or shutdown.

- Fix CXL DVSEC range register compatibility versus region
enumeration that leads to startup crashes

- Fix CDAT endiannes handling

- Fix multiple buffer handling boundary conditions

- Fix Data Object Exchange (DOE) workqueue usage vs
CONFIG_DEBUG_OBJECTS warn splats"

Link: http://lore.kernel.org/r/20230405075704.33de8121@canb.auug.org.au [1]

* tag 'cxl-fixes-6.3-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl:
cxl/hdm: Extend DVSEC range register emulation for region enumeration
cxl/hdm: Limit emulation to the number of range registers
cxl/region: Move coherence tracking into cxl_region_attach()
cxl/region: Fix region setup/teardown for RCDs
cxl/port: Fix find_cxl_root() for RCDs and simplify it
cxl/hdm: Skip emulation when driver manages mem_enable
cxl/hdm: Fix double allocation of @cxlhdm
PCI/DOE: Fix memory leak with CONFIG_DEBUG_OBJECTS=y
PCI/DOE: Silence WARN splat with CONFIG_DEBUG_OBJECTS=y
cxl/pci: Handle excessive CDAT length
cxl/pci: Handle truncated CDAT entries
cxl/pci: Handle truncated CDAT header
cxl/pci: Fix CDAT retrieval on big endian

+175 -130
+68 -58
drivers/cxl/core/hdm.c
··· 101 101 BIT(CXL_CM_CAP_CAP_ID_HDM)); 102 102 } 103 103 104 - static struct cxl_hdm *devm_cxl_setup_emulated_hdm(struct cxl_port *port, 105 - struct cxl_endpoint_dvsec_info *info) 104 + static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info) 106 105 { 107 - struct device *dev = &port->dev; 108 106 struct cxl_hdm *cxlhdm; 107 + void __iomem *hdm; 108 + u32 ctrl; 109 + int i; 109 110 111 + if (!info) 112 + return false; 113 + 114 + cxlhdm = dev_get_drvdata(&info->port->dev); 115 + hdm = cxlhdm->regs.hdm_decoder; 116 + 117 + if (!hdm) 118 + return true; 119 + 120 + /* 121 + * If HDM decoders are present and the driver is in control of 122 + * Mem_Enable skip DVSEC based emulation 123 + */ 110 124 if (!info->mem_enabled) 111 - return ERR_PTR(-ENODEV); 125 + return false; 112 126 113 - cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL); 114 - if (!cxlhdm) 115 - return ERR_PTR(-ENOMEM); 127 + /* 128 + * If any decoders are committed already, there should not be any 129 + * emulated DVSEC decoders. 130 + */ 131 + for (i = 0; i < cxlhdm->decoder_count; i++) { 132 + ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i)); 133 + if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl)) 134 + return false; 135 + } 116 136 117 - cxlhdm->port = port; 118 - cxlhdm->decoder_count = info->ranges; 119 - cxlhdm->target_count = info->ranges; 120 - dev_set_drvdata(&port->dev, cxlhdm); 121 - 122 - return cxlhdm; 137 + return true; 123 138 } 124 139 125 140 /** ··· 153 138 cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL); 154 139 if (!cxlhdm) 155 140 return ERR_PTR(-ENOMEM); 156 - 157 141 cxlhdm->port = port; 158 - crb = ioremap(port->component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE); 159 - if (!crb) { 160 - if (info && info->mem_enabled) 161 - return devm_cxl_setup_emulated_hdm(port, info); 142 + dev_set_drvdata(dev, cxlhdm); 162 143 144 + crb = ioremap(port->component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE); 145 + if (!crb && info && info->mem_enabled) { 146 + cxlhdm->decoder_count = info->ranges; 147 + return cxlhdm; 148 + } else if (!crb) { 163 149 dev_err(dev, "No component registers mapped\n"); 164 150 return ERR_PTR(-ENXIO); 165 151 } ··· 176 160 return ERR_PTR(-ENXIO); 177 161 } 178 162 179 - dev_set_drvdata(dev, cxlhdm); 163 + /* 164 + * Now that the hdm capability is parsed, decide if range 165 + * register emulation is needed and fixup cxlhdm accordingly. 166 + */ 167 + if (should_emulate_decoders(info)) { 168 + dev_dbg(dev, "Fallback map %d range register%s\n", info->ranges, 169 + info->ranges > 1 ? "s" : ""); 170 + cxlhdm->decoder_count = info->ranges; 171 + } 180 172 181 173 return cxlhdm; 182 174 } ··· 738 714 return 0; 739 715 } 740 716 741 - static int cxl_setup_hdm_decoder_from_dvsec(struct cxl_port *port, 742 - struct cxl_decoder *cxld, int which, 743 - struct cxl_endpoint_dvsec_info *info) 717 + static int cxl_setup_hdm_decoder_from_dvsec( 718 + struct cxl_port *port, struct cxl_decoder *cxld, u64 *dpa_base, 719 + int which, struct cxl_endpoint_dvsec_info *info) 744 720 { 721 + struct cxl_endpoint_decoder *cxled; 722 + u64 len; 723 + int rc; 724 + 745 725 if (!is_cxl_endpoint(port)) 746 726 return -EOPNOTSUPP; 747 727 748 - if (!range_len(&info->dvsec_range[which])) 728 + cxled = to_cxl_endpoint_decoder(&cxld->dev); 729 + len = range_len(&info->dvsec_range[which]); 730 + if (!len) 749 731 return -ENOENT; 750 732 751 733 cxld->target_type = CXL_DECODER_EXPANDER; ··· 766 736 cxld->flags |= CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK; 767 737 port->commit_end = cxld->id; 768 738 769 - return 0; 770 - } 771 - 772 - static bool should_emulate_decoders(struct cxl_port *port) 773 - { 774 - struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); 775 - void __iomem *hdm = cxlhdm->regs.hdm_decoder; 776 - u32 ctrl; 777 - int i; 778 - 779 - if (!is_cxl_endpoint(cxlhdm->port)) 780 - return false; 781 - 782 - if (!hdm) 783 - return true; 784 - 785 - /* 786 - * If any decoders are committed already, there should not be any 787 - * emulated DVSEC decoders. 788 - */ 789 - for (i = 0; i < cxlhdm->decoder_count; i++) { 790 - ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i)); 791 - if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl)) 792 - return false; 739 + rc = devm_cxl_dpa_reserve(cxled, *dpa_base, len, 0); 740 + if (rc) { 741 + dev_err(&port->dev, 742 + "decoder%d.%d: Failed to reserve DPA range %#llx - %#llx\n (%d)", 743 + port->id, cxld->id, *dpa_base, *dpa_base + len - 1, rc); 744 + return rc; 793 745 } 746 + *dpa_base += len; 747 + cxled->state = CXL_DECODER_STATE_AUTO; 794 748 795 - return true; 749 + return 0; 796 750 } 797 751 798 752 static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, 799 753 int *target_map, void __iomem *hdm, int which, 800 754 u64 *dpa_base, struct cxl_endpoint_dvsec_info *info) 801 755 { 802 - struct cxl_endpoint_decoder *cxled = NULL; 756 + struct cxl_endpoint_decoder *cxled; 803 757 u64 size, base, skip, dpa_size; 804 758 bool committed; 805 759 u32 remainder; ··· 794 780 unsigned char target_id[8]; 795 781 } target_list; 796 782 797 - if (should_emulate_decoders(port)) 798 - return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info); 799 - 800 - if (is_endpoint_decoder(&cxld->dev)) 801 - cxled = to_cxl_endpoint_decoder(&cxld->dev); 783 + if (should_emulate_decoders(info)) 784 + return cxl_setup_hdm_decoder_from_dvsec(port, cxld, dpa_base, 785 + which, info); 802 786 803 787 ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which)); 804 788 base = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which)); ··· 817 805 .start = base, 818 806 .end = base + size - 1, 819 807 }; 820 - 821 - if (cxled && !committed && range_len(&info->dvsec_range[which])) 822 - return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info); 823 808 824 809 /* decoders are enabled if committed */ 825 810 if (committed) { ··· 855 846 if (rc) 856 847 return rc; 857 848 858 - if (!cxled) { 849 + if (!info) { 859 850 target_list.value = 860 851 ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which)); 861 852 for (i = 0; i < cxld->interleave_ways; i++) ··· 875 866 return -ENXIO; 876 867 } 877 868 skip = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SKIP_LOW(which)); 869 + cxled = to_cxl_endpoint_decoder(&cxld->dev); 878 870 rc = devm_cxl_dpa_reserve(cxled, *dpa_base + skip, dpa_size, skip); 879 871 if (rc) { 880 872 dev_err(&port->dev,
+23 -15
drivers/cxl/core/pci.c
··· 462 462 return NULL; 463 463 } 464 464 465 - #define CDAT_DOE_REQ(entry_handle) \ 465 + #define CDAT_DOE_REQ(entry_handle) cpu_to_le32 \ 466 466 (FIELD_PREP(CXL_DOE_TABLE_ACCESS_REQ_CODE, \ 467 467 CXL_DOE_TABLE_ACCESS_REQ_CODE_READ) | \ 468 468 FIELD_PREP(CXL_DOE_TABLE_ACCESS_TABLE_TYPE, \ ··· 475 475 } 476 476 477 477 struct cdat_doe_task { 478 - u32 request_pl; 479 - u32 response_pl[32]; 478 + __le32 request_pl; 479 + __le32 response_pl[32]; 480 480 struct completion c; 481 481 struct pci_doe_task task; 482 482 }; ··· 510 510 return rc; 511 511 } 512 512 wait_for_completion(&t.c); 513 - if (t.task.rv < sizeof(u32)) 513 + if (t.task.rv < 2 * sizeof(__le32)) 514 514 return -EIO; 515 515 516 - *length = t.response_pl[1]; 516 + *length = le32_to_cpu(t.response_pl[1]); 517 517 dev_dbg(dev, "CDAT length %zu\n", *length); 518 518 519 519 return 0; ··· 524 524 struct cxl_cdat *cdat) 525 525 { 526 526 size_t length = cdat->length; 527 - u32 *data = cdat->table; 527 + __le32 *data = cdat->table; 528 528 int entry_handle = 0; 529 529 530 530 do { 531 531 DECLARE_CDAT_DOE_TASK(CDAT_DOE_REQ(entry_handle), t); 532 + struct cdat_entry_header *entry; 532 533 size_t entry_dw; 533 - u32 *entry; 534 534 int rc; 535 535 536 536 rc = pci_doe_submit_task(cdat_doe, &t.task); ··· 539 539 return rc; 540 540 } 541 541 wait_for_completion(&t.c); 542 - /* 1 DW header + 1 DW data min */ 543 - if (t.task.rv < (2 * sizeof(u32))) 542 + 543 + /* 1 DW Table Access Response Header + CDAT entry */ 544 + entry = (struct cdat_entry_header *)(t.response_pl + 1); 545 + if ((entry_handle == 0 && 546 + t.task.rv != sizeof(__le32) + sizeof(struct cdat_header)) || 547 + (entry_handle > 0 && 548 + (t.task.rv < sizeof(__le32) + sizeof(*entry) || 549 + t.task.rv != sizeof(__le32) + le16_to_cpu(entry->length)))) 544 550 return -EIO; 545 551 546 552 /* Get the CXL table access header entry handle */ 547 553 entry_handle = FIELD_GET(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE, 548 - t.response_pl[0]); 549 - entry = t.response_pl + 1; 550 - entry_dw = t.task.rv / sizeof(u32); 554 + le32_to_cpu(t.response_pl[0])); 555 + entry_dw = t.task.rv / sizeof(__le32); 551 556 /* Skip Header */ 552 557 entry_dw -= 1; 553 - entry_dw = min(length / sizeof(u32), entry_dw); 558 + entry_dw = min(length / sizeof(__le32), entry_dw); 554 559 /* Prevent length < 1 DW from causing a buffer overflow */ 555 560 if (entry_dw) { 556 - memcpy(data, entry, entry_dw * sizeof(u32)); 557 - length -= entry_dw * sizeof(u32); 561 + memcpy(data, entry, entry_dw * sizeof(__le32)); 562 + length -= entry_dw * sizeof(__le32); 558 563 data += entry_dw; 559 564 } 560 565 } while (entry_handle != CXL_DOE_TABLE_ACCESS_LAST_ENTRY); 566 + 567 + /* Length in CDAT header may exceed concatenation of CDAT entries */ 568 + cdat->length -= length; 561 569 562 570 return 0; 563 571 }
+3 -3
drivers/cxl/core/pmem.c
··· 62 62 return is_cxl_nvdimm_bridge(dev); 63 63 } 64 64 65 - struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *start) 65 + struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd) 66 66 { 67 - struct cxl_port *port = find_cxl_root(start); 67 + struct cxl_port *port = find_cxl_root(dev_get_drvdata(&cxlmd->dev)); 68 68 struct device *dev; 69 69 70 70 if (!port) ··· 253 253 struct device *dev; 254 254 int rc; 255 255 256 - cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev); 256 + cxl_nvb = cxl_find_nvdimm_bridge(cxlmd); 257 257 if (!cxl_nvb) 258 258 return -ENODEV; 259 259
+7 -31
drivers/cxl/core/port.c
··· 823 823 return false; 824 824 } 825 825 826 - /* Find a 2nd level CXL port that has a dport that is an ancestor of @match */ 827 - static int match_root_child(struct device *dev, const void *match) 826 + struct cxl_port *find_cxl_root(struct cxl_port *port) 828 827 { 829 - const struct device *iter = NULL; 830 - struct cxl_dport *dport; 831 - struct cxl_port *port; 828 + struct cxl_port *iter = port; 832 829 833 - if (!dev_is_cxl_root_child(dev)) 834 - return 0; 830 + while (iter && !is_cxl_root(iter)) 831 + iter = to_cxl_port(iter->dev.parent); 835 832 836 - port = to_cxl_port(dev); 837 - iter = match; 838 - while (iter) { 839 - dport = cxl_find_dport_by_dev(port, iter); 840 - if (dport) 841 - break; 842 - iter = iter->parent; 843 - } 844 - 845 - return !!iter; 846 - } 847 - 848 - struct cxl_port *find_cxl_root(struct device *dev) 849 - { 850 - struct device *port_dev; 851 - struct cxl_port *root; 852 - 853 - port_dev = bus_find_device(&cxl_bus_type, NULL, dev, match_root_child); 854 - if (!port_dev) 833 + if (!iter) 855 834 return NULL; 856 - 857 - root = to_cxl_port(port_dev->parent); 858 - get_device(&root->dev); 859 - put_device(port_dev); 860 - return root; 835 + get_device(&iter->dev); 836 + return iter; 861 837 } 862 838 EXPORT_SYMBOL_NS_GPL(find_cxl_root, CXL); 863 839
+29 -4
drivers/cxl/core/region.c
··· 134 134 struct cxl_endpoint_decoder *cxled = p->targets[i]; 135 135 struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 136 136 struct cxl_port *iter = cxled_to_port(cxled); 137 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 137 138 struct cxl_ep *ep; 138 139 int rc = 0; 140 + 141 + if (cxlds->rcd) 142 + goto endpoint_reset; 139 143 140 144 while (!is_cxl_root(to_cxl_port(iter->dev.parent))) 141 145 iter = to_cxl_port(iter->dev.parent); ··· 157 153 return rc; 158 154 } 159 155 156 + endpoint_reset: 160 157 rc = cxled->cxld.reset(&cxled->cxld); 161 158 if (rc) 162 159 return rc; ··· 1204 1199 { 1205 1200 struct cxl_region_params *p = &cxlr->params; 1206 1201 struct cxl_endpoint_decoder *cxled; 1202 + struct cxl_dev_state *cxlds; 1207 1203 struct cxl_memdev *cxlmd; 1208 1204 struct cxl_port *iter; 1209 1205 struct cxl_ep *ep; ··· 1220 1214 for (i = 0; i < p->nr_targets; i++) { 1221 1215 cxled = p->targets[i]; 1222 1216 cxlmd = cxled_to_memdev(cxled); 1217 + cxlds = cxlmd->cxlds; 1218 + 1219 + if (cxlds->rcd) 1220 + continue; 1223 1221 1224 1222 iter = cxled_to_port(cxled); 1225 1223 while (!is_cxl_root(to_cxl_port(iter->dev.parent))) ··· 1239 1229 { 1240 1230 struct cxl_region_params *p = &cxlr->params; 1241 1231 struct cxl_endpoint_decoder *cxled; 1232 + struct cxl_dev_state *cxlds; 1233 + int i, rc, rch = 0, vh = 0; 1242 1234 struct cxl_memdev *cxlmd; 1243 1235 struct cxl_port *iter; 1244 1236 struct cxl_ep *ep; 1245 - int i, rc; 1246 1237 1247 1238 for (i = 0; i < p->nr_targets; i++) { 1248 1239 cxled = p->targets[i]; 1249 1240 cxlmd = cxled_to_memdev(cxled); 1241 + cxlds = cxlmd->cxlds; 1242 + 1243 + /* validate that all targets agree on topology */ 1244 + if (!cxlds->rcd) { 1245 + vh++; 1246 + } else { 1247 + rch++; 1248 + continue; 1249 + } 1250 1250 1251 1251 iter = cxled_to_port(cxled); 1252 1252 while (!is_cxl_root(to_cxl_port(iter->dev.parent))) ··· 1274 1254 return rc; 1275 1255 } 1276 1256 } 1257 + } 1258 + 1259 + if (rch && vh) { 1260 + dev_err(&cxlr->dev, "mismatched CXL topologies detected\n"); 1261 + cxl_region_teardown_targets(cxlr); 1262 + return -ENXIO; 1277 1263 } 1278 1264 1279 1265 return 0; ··· 1674 1648 if (rc) 1675 1649 goto err_decrement; 1676 1650 p->state = CXL_CONFIG_ACTIVE; 1651 + set_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags); 1677 1652 } 1678 1653 1679 1654 cxled->cxld.interleave_ways = p->interleave_ways; ··· 1776 1749 1777 1750 down_read(&cxl_dpa_rwsem); 1778 1751 rc = cxl_region_attach(cxlr, cxled, pos); 1779 - if (rc == 0) 1780 - set_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags); 1781 1752 up_read(&cxl_dpa_rwsem); 1782 1753 up_write(&cxl_region_rwsem); 1783 1754 return rc; ··· 2276 2251 * bridge for one device is the same for all. 2277 2252 */ 2278 2253 if (i == 0) { 2279 - cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev); 2254 + cxl_nvb = cxl_find_nvdimm_bridge(cxlmd); 2280 2255 if (!cxl_nvb) { 2281 2256 cxlr_pmem = ERR_PTR(-ENODEV); 2282 2257 goto out;
+5 -3
drivers/cxl/cxl.h
··· 658 658 struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport, 659 659 resource_size_t component_reg_phys, 660 660 struct cxl_dport *parent_dport); 661 - struct cxl_port *find_cxl_root(struct device *dev); 661 + struct cxl_port *find_cxl_root(struct cxl_port *port); 662 662 int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd); 663 663 void cxl_bus_rescan(void); 664 664 void cxl_bus_drain(void); ··· 695 695 696 696 /** 697 697 * struct cxl_endpoint_dvsec_info - Cached DVSEC info 698 - * @mem_enabled: cached value of mem_enabled in the DVSEC, PCIE_DEVICE 698 + * @mem_enabled: cached value of mem_enabled in the DVSEC at init time 699 699 * @ranges: Number of active HDM ranges this device uses. 700 + * @port: endpoint port associated with this info instance 700 701 * @dvsec_range: cached attributes of the ranges in the DVSEC, PCIE_DEVICE 701 702 */ 702 703 struct cxl_endpoint_dvsec_info { 703 704 bool mem_enabled; 704 705 int ranges; 706 + struct cxl_port *port; 705 707 struct range dvsec_range[2]; 706 708 }; 707 709 ··· 760 758 bool is_cxl_nvdimm(struct device *dev); 761 759 bool is_cxl_nvdimm_bridge(struct device *dev); 762 760 int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd); 763 - struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev); 761 + struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd); 764 762 765 763 #ifdef CONFIG_CXL_REGION 766 764 bool is_cxl_pmem_region(struct device *dev);
+14
drivers/cxl/cxlpci.h
··· 68 68 CXL_REGLOC_RBI_TYPES 69 69 }; 70 70 71 + struct cdat_header { 72 + __le32 length; 73 + u8 revision; 74 + u8 checksum; 75 + u8 reserved[6]; 76 + __le32 sequence; 77 + } __packed; 78 + 79 + struct cdat_entry_header { 80 + u8 type; 81 + u8 reserved; 82 + __le16 length; 83 + } __packed; 84 + 71 85 int devm_cxl_port_enumerate_dports(struct cxl_port *port); 72 86 struct cxl_dev_state; 73 87 int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
+2 -2
drivers/cxl/port.c
··· 78 78 79 79 static int cxl_endpoint_port_probe(struct cxl_port *port) 80 80 { 81 + struct cxl_endpoint_dvsec_info info = { .port = port }; 81 82 struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport); 82 - struct cxl_endpoint_dvsec_info info = { 0 }; 83 83 struct cxl_dev_state *cxlds = cxlmd->cxlds; 84 84 struct cxl_hdm *cxlhdm; 85 85 struct cxl_port *root; ··· 119 119 * This can't fail in practice as CXL root exit unregisters all 120 120 * descendant ports and that in turn synchronizes with cxl_port_probe() 121 121 */ 122 - root = find_cxl_root(&cxlmd->dev); 122 + root = find_cxl_root(port); 123 123 124 124 /* 125 125 * Now that all endpoint decoders are successfully enumerated, try to
+18 -12
drivers/pci/doe.c
··· 128 128 return -EIO; 129 129 130 130 /* Length is 2 DW of header + length of payload in DW */ 131 - length = 2 + task->request_pl_sz / sizeof(u32); 131 + length = 2 + task->request_pl_sz / sizeof(__le32); 132 132 if (length > PCI_DOE_MAX_LENGTH) 133 133 return -EIO; 134 134 if (length == PCI_DOE_MAX_LENGTH) ··· 141 141 pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, 142 142 FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, 143 143 length)); 144 - for (i = 0; i < task->request_pl_sz / sizeof(u32); i++) 144 + for (i = 0; i < task->request_pl_sz / sizeof(__le32); i++) 145 145 pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, 146 - task->request_pl[i]); 146 + le32_to_cpu(task->request_pl[i])); 147 147 148 148 pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_GO); 149 149 ··· 195 195 196 196 /* First 2 dwords have already been read */ 197 197 length -= 2; 198 - payload_length = min(length, task->response_pl_sz / sizeof(u32)); 198 + payload_length = min(length, task->response_pl_sz / sizeof(__le32)); 199 199 /* Read the rest of the response payload */ 200 200 for (i = 0; i < payload_length; i++) { 201 - pci_read_config_dword(pdev, offset + PCI_DOE_READ, 202 - &task->response_pl[i]); 201 + pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val); 202 + task->response_pl[i] = cpu_to_le32(val); 203 203 /* Prior to the last ack, ensure Data Object Ready */ 204 204 if (i == (payload_length - 1) && !pci_doe_data_obj_ready(doe_mb)) 205 205 return -EIO; ··· 217 217 if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) 218 218 return -EIO; 219 219 220 - return min(length, task->response_pl_sz / sizeof(u32)) * sizeof(u32); 220 + return min(length, task->response_pl_sz / sizeof(__le32)) * sizeof(__le32); 221 221 } 222 222 223 223 static void signal_task_complete(struct pci_doe_task *task, int rv) 224 224 { 225 225 task->rv = rv; 226 226 task->complete(task); 227 + destroy_work_on_stack(&task->work); 227 228 } 228 229 229 230 static void signal_task_abort(struct pci_doe_task *task, int rv) ··· 318 317 { 319 318 u32 request_pl = FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX, 320 319 *index); 320 + __le32 request_pl_le = cpu_to_le32(request_pl); 321 + __le32 response_pl_le; 321 322 u32 response_pl; 322 323 DECLARE_COMPLETION_ONSTACK(c); 323 324 struct pci_doe_task task = { 324 325 .prot.vid = PCI_VENDOR_ID_PCI_SIG, 325 326 .prot.type = PCI_DOE_PROTOCOL_DISCOVERY, 326 - .request_pl = &request_pl, 327 + .request_pl = &request_pl_le, 327 328 .request_pl_sz = sizeof(request_pl), 328 - .response_pl = &response_pl, 329 + .response_pl = &response_pl_le, 329 330 .response_pl_sz = sizeof(response_pl), 330 331 .complete = pci_doe_task_complete, 331 332 .private = &c, ··· 343 340 if (task.rv != sizeof(response_pl)) 344 341 return -EIO; 345 342 343 + response_pl = le32_to_cpu(response_pl_le); 346 344 *vid = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID, response_pl); 347 345 *protocol = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL, 348 346 response_pl); ··· 524 520 * task->complete will be called when the state machine is done processing this 525 521 * task. 526 522 * 523 + * @task must be allocated on the stack. 524 + * 527 525 * Excess data will be discarded. 528 526 * 529 527 * RETURNS: 0 when task has been successfully queued, -ERRNO on error ··· 539 533 * DOE requests must be a whole number of DW and the response needs to 540 534 * be big enough for at least 1 DW 541 535 */ 542 - if (task->request_pl_sz % sizeof(u32) || 543 - task->response_pl_sz < sizeof(u32)) 536 + if (task->request_pl_sz % sizeof(__le32) || 537 + task->response_pl_sz < sizeof(__le32)) 544 538 return -EINVAL; 545 539 546 540 if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags)) 547 541 return -EIO; 548 542 549 543 task->doe_mb = doe_mb; 550 - INIT_WORK(&task->work, doe_statemachine_work); 544 + INIT_WORK_ONSTACK(&task->work, doe_statemachine_work); 551 545 queue_work(doe_mb->work_queue, &task->work); 552 546 return 0; 553 547 }
+6 -2
include/linux/pci-doe.h
··· 34 34 * @work: Used internally by the mailbox 35 35 * @doe_mb: Used internally by the mailbox 36 36 * 37 + * Payloads are treated as opaque byte streams which are transmitted verbatim, 38 + * without byte-swapping. If payloads contain little-endian register values, 39 + * the caller is responsible for conversion with cpu_to_le32() / le32_to_cpu(). 40 + * 37 41 * The payload sizes and rv are specified in bytes with the following 38 42 * restrictions concerning the protocol. 39 43 * ··· 49 45 */ 50 46 struct pci_doe_task { 51 47 struct pci_doe_protocol prot; 52 - u32 *request_pl; 48 + __le32 *request_pl; 53 49 size_t request_pl_sz; 54 - u32 *response_pl; 50 + __le32 *response_pl; 55 51 size_t response_pl_sz; 56 52 int rv; 57 53 void (*complete)(struct pci_doe_task *task);