@@ -30,17 +30,20 @@ static void unregister_nvdimm(void *nvdimm)
30
30
struct cxl_nvdimm * cxl_nvd = nvdimm_provider_data (nvdimm );
31
31
struct cxl_nvdimm_bridge * cxl_nvb = cxl_nvd -> bridge ;
32
32
struct cxl_pmem_region * cxlr_pmem ;
33
+ unsigned long index ;
33
34
34
35
device_lock (& cxl_nvb -> dev );
35
- cxlr_pmem = cxl_nvd -> region ;
36
36
dev_set_drvdata (& cxl_nvd -> dev , NULL );
37
- cxl_nvd -> region = NULL ;
38
- device_unlock (& cxl_nvb -> dev );
37
+ xa_for_each (& cxl_nvd -> pmem_regions , index , cxlr_pmem ) {
38
+ get_device (& cxlr_pmem -> dev );
39
+ device_unlock (& cxl_nvb -> dev );
39
40
40
- if (cxlr_pmem ) {
41
41
device_release_driver (& cxlr_pmem -> dev );
42
42
put_device (& cxlr_pmem -> dev );
43
+
44
+ device_lock (& cxl_nvb -> dev );
43
45
}
46
+ device_unlock (& cxl_nvb -> dev );
44
47
45
48
nvdimm_delete (nvdimm );
46
49
cxl_nvd -> bridge = NULL ;
@@ -366,25 +369,49 @@ static int match_cxl_nvdimm(struct device *dev, void *data)
366
369
367
370
static void unregister_nvdimm_region (void * nd_region )
368
371
{
369
- struct cxl_nvdimm_bridge * cxl_nvb ;
370
- struct cxl_pmem_region * cxlr_pmem ;
372
+ nvdimm_region_delete (nd_region );
373
+ }
374
+
375
+ static int cxl_nvdimm_add_region (struct cxl_nvdimm * cxl_nvd ,
376
+ struct cxl_pmem_region * cxlr_pmem )
377
+ {
378
+ int rc ;
379
+
380
+ rc = xa_insert (& cxl_nvd -> pmem_regions , (unsigned long )cxlr_pmem ,
381
+ cxlr_pmem , GFP_KERNEL );
382
+ if (rc )
383
+ return rc ;
384
+
385
+ get_device (& cxlr_pmem -> dev );
386
+ return 0 ;
387
+ }
388
+
389
+ static void cxl_nvdimm_del_region (struct cxl_nvdimm * cxl_nvd ,
390
+ struct cxl_pmem_region * cxlr_pmem )
391
+ {
392
+ /*
393
+ * It is possible this is called without a corresponding
394
+ * cxl_nvdimm_add_region for @cxlr_pmem
395
+ */
396
+ cxlr_pmem = xa_erase (& cxl_nvd -> pmem_regions , (unsigned long )cxlr_pmem );
397
+ if (cxlr_pmem )
398
+ put_device (& cxlr_pmem -> dev );
399
+ }
400
+
401
+ static void release_mappings (void * data )
402
+ {
371
403
int i ;
404
+ struct cxl_pmem_region * cxlr_pmem = data ;
405
+ struct cxl_nvdimm_bridge * cxl_nvb = cxlr_pmem -> bridge ;
372
406
373
- cxlr_pmem = nd_region_provider_data (nd_region );
374
- cxl_nvb = cxlr_pmem -> bridge ;
375
407
device_lock (& cxl_nvb -> dev );
376
408
for (i = 0 ; i < cxlr_pmem -> nr_mappings ; i ++ ) {
377
409
struct cxl_pmem_region_mapping * m = & cxlr_pmem -> mapping [i ];
378
410
struct cxl_nvdimm * cxl_nvd = m -> cxl_nvd ;
379
411
380
- if (cxl_nvd -> region ) {
381
- put_device (& cxlr_pmem -> dev );
382
- cxl_nvd -> region = NULL ;
383
- }
412
+ cxl_nvdimm_del_region (cxl_nvd , cxlr_pmem );
384
413
}
385
414
device_unlock (& cxl_nvb -> dev );
386
-
387
- nvdimm_region_delete (nd_region );
388
415
}
389
416
390
417
static void cxlr_pmem_remove_resource (void * res )
@@ -422,7 +449,7 @@ static int cxl_pmem_region_probe(struct device *dev)
422
449
if (!cxl_nvb -> nvdimm_bus ) {
423
450
dev_dbg (dev , "nvdimm bus not found\n" );
424
451
rc = - ENXIO ;
425
- goto err ;
452
+ goto out_nvb ;
426
453
}
427
454
428
455
memset (& mappings , 0 , sizeof (mappings ));
@@ -431,7 +458,7 @@ static int cxl_pmem_region_probe(struct device *dev)
431
458
res = devm_kzalloc (dev , sizeof (* res ), GFP_KERNEL );
432
459
if (!res ) {
433
460
rc = - ENOMEM ;
434
- goto err ;
461
+ goto out_nvb ;
435
462
}
436
463
437
464
res -> name = "Persistent Memory" ;
@@ -442,11 +469,11 @@ static int cxl_pmem_region_probe(struct device *dev)
442
469
443
470
rc = insert_resource (& iomem_resource , res );
444
471
if (rc )
445
- goto err ;
472
+ goto out_nvb ;
446
473
447
474
rc = devm_add_action_or_reset (dev , cxlr_pmem_remove_resource , res );
448
475
if (rc )
449
- goto err ;
476
+ goto out_nvb ;
450
477
451
478
ndr_desc .res = res ;
452
479
ndr_desc .provider_data = cxlr_pmem ;
@@ -462,7 +489,7 @@ static int cxl_pmem_region_probe(struct device *dev)
462
489
nd_set = devm_kzalloc (dev , sizeof (* nd_set ), GFP_KERNEL );
463
490
if (!nd_set ) {
464
491
rc = - ENOMEM ;
465
- goto err ;
492
+ goto out_nvb ;
466
493
}
467
494
468
495
ndr_desc .memregion = cxlr -> id ;
@@ -472,9 +499,13 @@ static int cxl_pmem_region_probe(struct device *dev)
472
499
info = kmalloc_array (cxlr_pmem -> nr_mappings , sizeof (* info ), GFP_KERNEL );
473
500
if (!info ) {
474
501
rc = - ENOMEM ;
475
- goto err ;
502
+ goto out_nvb ;
476
503
}
477
504
505
+ rc = devm_add_action_or_reset (dev , release_mappings , cxlr_pmem );
506
+ if (rc )
507
+ goto out_nvd ;
508
+
478
509
for (i = 0 ; i < cxlr_pmem -> nr_mappings ; i ++ ) {
479
510
struct cxl_pmem_region_mapping * m = & cxlr_pmem -> mapping [i ];
480
511
struct cxl_memdev * cxlmd = m -> cxlmd ;
@@ -486,7 +517,7 @@ static int cxl_pmem_region_probe(struct device *dev)
486
517
dev_dbg (dev , "[%d]: %s: no cxl_nvdimm found\n" , i ,
487
518
dev_name (& cxlmd -> dev ));
488
519
rc = - ENODEV ;
489
- goto err ;
520
+ goto out_nvd ;
490
521
}
491
522
492
523
/* safe to drop ref now with bridge lock held */
@@ -498,10 +529,17 @@ static int cxl_pmem_region_probe(struct device *dev)
498
529
dev_dbg (dev , "[%d]: %s: no nvdimm found\n" , i ,
499
530
dev_name (& cxlmd -> dev ));
500
531
rc = - ENODEV ;
501
- goto err ;
532
+ goto out_nvd ;
502
533
}
503
- cxl_nvd -> region = cxlr_pmem ;
504
- get_device (& cxlr_pmem -> dev );
534
+
535
+ /*
536
+ * Pin the region per nvdimm device as those may be released
537
+ * out-of-order with respect to the region, and a single nvdimm
538
+ * maybe associated with multiple regions
539
+ */
540
+ rc = cxl_nvdimm_add_region (cxl_nvd , cxlr_pmem );
541
+ if (rc )
542
+ goto out_nvd ;
505
543
m -> cxl_nvd = cxl_nvd ;
506
544
mappings [i ] = (struct nd_mapping_desc ) {
507
545
.nvdimm = nvdimm ,
@@ -527,27 +565,18 @@ static int cxl_pmem_region_probe(struct device *dev)
527
565
nvdimm_pmem_region_create (cxl_nvb -> nvdimm_bus , & ndr_desc );
528
566
if (!cxlr_pmem -> nd_region ) {
529
567
rc = - ENOMEM ;
530
- goto err ;
568
+ goto out_nvd ;
531
569
}
532
570
533
571
rc = devm_add_action_or_reset (dev , unregister_nvdimm_region ,
534
572
cxlr_pmem -> nd_region );
535
- out :
573
+ out_nvd :
536
574
kfree (info );
575
+ out_nvb :
537
576
device_unlock (& cxl_nvb -> dev );
538
577
put_device (& cxl_nvb -> dev );
539
578
540
579
return rc ;
541
-
542
- err :
543
- dev_dbg (dev , "failed to create nvdimm region\n" );
544
- for (i -- ; i >= 0 ; i -- ) {
545
- nvdimm = mappings [i ].nvdimm ;
546
- cxl_nvd = nvdimm_provider_data (nvdimm );
547
- put_device (& cxl_nvd -> region -> dev );
548
- cxl_nvd -> region = NULL ;
549
- }
550
- goto out ;
551
580
}
552
581
553
582
static struct cxl_driver cxl_pmem_region_driver = {
0 commit comments