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

Merge branch 'for-6.5/cxl-region-fixes' into for-6.5/cxl

Pick up the recent fixes to how CPU caches are managed relative to
region setup / teardown, and make sure that all decoders transition
successfully before updating the region state from COMMIT => ACTIVE.

+72 -46
+63 -39
drivers/cxl/core/region.c
··· 125 125 return xa_load(&port->regions, (unsigned long)cxlr); 126 126 } 127 127 128 + static int cxl_region_invalidate_memregion(struct cxl_region *cxlr) 129 + { 130 + if (!cpu_cache_has_invalidate_memregion()) { 131 + if (IS_ENABLED(CONFIG_CXL_REGION_INVALIDATION_TEST)) { 132 + dev_warn_once( 133 + &cxlr->dev, 134 + "Bypassing cpu_cache_invalidate_memregion() for testing!\n"); 135 + return 0; 136 + } else { 137 + dev_err(&cxlr->dev, 138 + "Failed to synchronize CPU cache state\n"); 139 + return -ENXIO; 140 + } 141 + } 142 + 143 + cpu_cache_invalidate_memregion(IORES_DESC_CXL); 144 + return 0; 145 + } 146 + 128 147 static int cxl_region_decode_reset(struct cxl_region *cxlr, int count) 129 148 { 130 149 struct cxl_region_params *p = &cxlr->params; 131 - int i; 150 + int i, rc = 0; 151 + 152 + /* 153 + * Before region teardown attempt to flush, and if the flush 154 + * fails cancel the region teardown for data consistency 155 + * concerns 156 + */ 157 + rc = cxl_region_invalidate_memregion(cxlr); 158 + if (rc) 159 + return rc; 132 160 133 161 for (i = count - 1; i >= 0; i--) { 134 162 struct cxl_endpoint_decoder *cxled = p->targets[i]; ··· 164 136 struct cxl_port *iter = cxled_to_port(cxled); 165 137 struct cxl_dev_state *cxlds = cxlmd->cxlds; 166 138 struct cxl_ep *ep; 167 - int rc = 0; 168 139 169 140 if (cxlds->rcd) 170 141 goto endpoint_reset; ··· 182 155 rc = cxld->reset(cxld); 183 156 if (rc) 184 157 return rc; 158 + set_bit(CXL_REGION_F_NEEDS_RESET, &cxlr->flags); 185 159 } 186 160 187 161 endpoint_reset: 188 162 rc = cxled->cxld.reset(&cxled->cxld); 189 163 if (rc) 190 164 return rc; 165 + set_bit(CXL_REGION_F_NEEDS_RESET, &cxlr->flags); 191 166 } 167 + 168 + /* all decoders associated with this region have been torn down */ 169 + clear_bit(CXL_REGION_F_NEEDS_RESET, &cxlr->flags); 192 170 193 171 return 0; 194 172 } ··· 288 256 goto out; 289 257 } 290 258 291 - if (commit) 259 + /* 260 + * Invalidate caches before region setup to drop any speculative 261 + * consumption of this address space 262 + */ 263 + rc = cxl_region_invalidate_memregion(cxlr); 264 + if (rc) 265 + return rc; 266 + 267 + if (commit) { 292 268 rc = cxl_region_decode_commit(cxlr); 293 - else { 269 + if (rc == 0) 270 + p->state = CXL_CONFIG_COMMIT; 271 + } else { 294 272 p->state = CXL_CONFIG_RESET_PENDING; 295 273 up_write(&cxl_region_rwsem); 296 274 device_release_driver(&cxlr->dev); ··· 310 268 * The lock was dropped, so need to revalidate that the reset is 311 269 * still pending. 312 270 */ 313 - if (p->state == CXL_CONFIG_RESET_PENDING) 271 + if (p->state == CXL_CONFIG_RESET_PENDING) { 314 272 rc = cxl_region_decode_reset(cxlr, p->interleave_ways); 273 + /* 274 + * Revert to committed since there may still be active 275 + * decoders associated with this region, or move forward 276 + * to active to mark the reset successful 277 + */ 278 + if (rc) 279 + p->state = CXL_CONFIG_COMMIT; 280 + else 281 + p->state = CXL_CONFIG_ACTIVE; 282 + } 315 283 } 316 - 317 - if (rc) 318 - goto out; 319 - 320 - if (commit) 321 - p->state = CXL_CONFIG_COMMIT; 322 - else if (p->state == CXL_CONFIG_RESET_PENDING) 323 - p->state = CXL_CONFIG_ACTIVE; 324 284 325 285 out: 326 286 up_write(&cxl_region_rwsem); ··· 1730 1686 if (rc) 1731 1687 goto err_decrement; 1732 1688 p->state = CXL_CONFIG_ACTIVE; 1733 - set_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags); 1734 1689 } 1735 1690 1736 1691 cxled->cxld.interleave_ways = p->interleave_ways; ··· 2858 2815 } 2859 2816 EXPORT_SYMBOL_NS_GPL(cxl_add_to_region, CXL); 2860 2817 2861 - static int cxl_region_invalidate_memregion(struct cxl_region *cxlr) 2862 - { 2863 - if (!test_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags)) 2864 - return 0; 2865 - 2866 - if (!cpu_cache_has_invalidate_memregion()) { 2867 - if (IS_ENABLED(CONFIG_CXL_REGION_INVALIDATION_TEST)) { 2868 - dev_warn_once( 2869 - &cxlr->dev, 2870 - "Bypassing cpu_cache_invalidate_memregion() for testing!\n"); 2871 - clear_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags); 2872 - return 0; 2873 - } else { 2874 - dev_err(&cxlr->dev, 2875 - "Failed to synchronize CPU cache state\n"); 2876 - return -ENXIO; 2877 - } 2878 - } 2879 - 2880 - cpu_cache_invalidate_memregion(IORES_DESC_CXL); 2881 - clear_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags); 2882 - return 0; 2883 - } 2884 - 2885 2818 static int is_system_ram(struct resource *res, void *arg) 2886 2819 { 2887 2820 struct cxl_region *cxlr = arg; ··· 2885 2866 goto out; 2886 2867 } 2887 2868 2888 - rc = cxl_region_invalidate_memregion(cxlr); 2869 + if (test_bit(CXL_REGION_F_NEEDS_RESET, &cxlr->flags)) { 2870 + dev_err(&cxlr->dev, 2871 + "failed to activate, re-commit region and retry\n"); 2872 + rc = -ENXIO; 2873 + goto out; 2874 + } 2889 2875 2890 2876 /* 2891 2877 * From this point on any path that changes the region's state away from
+9 -7
drivers/cxl/cxl.h
··· 471 471 }; 472 472 473 473 /* 474 - * Flag whether this region needs to have its HPA span synchronized with 475 - * CPU cache state at region activation time. 476 - */ 477 - #define CXL_REGION_F_INCOHERENT 0 478 - 479 - /* 480 474 * Indicate whether this region has been assembled by autodetection or 481 475 * userspace assembly. Prevent endpoint decoders outside of automatic 482 476 * detection from being added to the region. 483 477 */ 484 - #define CXL_REGION_F_AUTO 1 478 + #define CXL_REGION_F_AUTO 0 479 + 480 + /* 481 + * Require that a committed region successfully complete a teardown once 482 + * any of its associated decoders have been torn down. This maintains 483 + * the commit state for the region since there are committed decoders, 484 + * but blocks cxl_region_probe(). 485 + */ 486 + #define CXL_REGION_F_NEEDS_RESET 1 485 487 486 488 /** 487 489 * struct cxl_region - CXL region