@@ -25,8 +25,83 @@ enum {
25
25
NUM_DCR = 4 ,
26
26
};
27
27
28
+ #define NDTEST_SCM_DIMM_CMD_MASK \
29
+ ((1ul << ND_CMD_GET_CONFIG_SIZE) | \
30
+ (1ul << ND_CMD_GET_CONFIG_DATA) | \
31
+ (1ul << ND_CMD_SET_CONFIG_DATA) | \
32
+ (1ul << ND_CMD_CALL))
33
+
34
+ #define NFIT_DIMM_HANDLE (node , socket , imc , chan , dimm ) \
35
+ (((node & 0xfff) << 16) | ((socket & 0xf) << 12) \
36
+ | ((imc & 0xf) << 8) | ((chan & 0xf) << 4) | (dimm & 0xf))
37
+
38
+ static DEFINE_SPINLOCK (ndtest_lock );
28
39
static struct ndtest_priv * instances [NUM_INSTANCES ];
29
40
static struct class * ndtest_dimm_class ;
41
+ static struct gen_pool * ndtest_pool ;
42
+
43
+ static struct ndtest_dimm dimm_group1 [] = {
44
+ {
45
+ .size = DIMM_SIZE ,
46
+ .handle = NFIT_DIMM_HANDLE (0 , 0 , 0 , 0 , 0 ),
47
+ .uuid_str = "1e5c75d2-b618-11ea-9aa3-507b9ddc0f72" ,
48
+ .physical_id = 0 ,
49
+ .num_formats = 2 ,
50
+ },
51
+ {
52
+ .size = DIMM_SIZE ,
53
+ .handle = NFIT_DIMM_HANDLE (0 , 0 , 0 , 0 , 1 ),
54
+ .uuid_str = "1c4d43ac-b618-11ea-be80-507b9ddc0f72" ,
55
+ .physical_id = 1 ,
56
+ .num_formats = 2 ,
57
+ },
58
+ {
59
+ .size = DIMM_SIZE ,
60
+ .handle = NFIT_DIMM_HANDLE (0 , 0 , 1 , 0 , 0 ),
61
+ .uuid_str = "a9f17ffc-b618-11ea-b36d-507b9ddc0f72" ,
62
+ .physical_id = 2 ,
63
+ .num_formats = 2 ,
64
+ },
65
+ {
66
+ .size = DIMM_SIZE ,
67
+ .handle = NFIT_DIMM_HANDLE (0 , 0 , 1 , 0 , 1 ),
68
+ .uuid_str = "b6b83b22-b618-11ea-8aae-507b9ddc0f72" ,
69
+ .physical_id = 3 ,
70
+ .num_formats = 2 ,
71
+ },
72
+ {
73
+ .size = DIMM_SIZE ,
74
+ .handle = NFIT_DIMM_HANDLE (0 , 1 , 0 , 0 , 0 ),
75
+ .uuid_str = "bf9baaee-b618-11ea-b181-507b9ddc0f72" ,
76
+ .physical_id = 4 ,
77
+ .num_formats = 2 ,
78
+ },
79
+ };
80
+
81
+ static struct ndtest_dimm dimm_group2 [] = {
82
+ {
83
+ .size = DIMM_SIZE ,
84
+ .handle = NFIT_DIMM_HANDLE (1 , 0 , 0 , 0 , 0 ),
85
+ .uuid_str = "ca0817e2-b618-11ea-9db3-507b9ddc0f72" ,
86
+ .physical_id = 0 ,
87
+ .num_formats = 1 ,
88
+ },
89
+ };
90
+
91
+ static struct ndtest_config bus_configs [NUM_INSTANCES ] = {
92
+ /* bus 1 */
93
+ {
94
+ .dimm_start = 0 ,
95
+ .dimm_count = ARRAY_SIZE (dimm_group1 ),
96
+ .dimms = dimm_group1 ,
97
+ },
98
+ /* bus 2 */
99
+ {
100
+ .dimm_start = ARRAY_SIZE (dimm_group1 ),
101
+ .dimm_count = ARRAY_SIZE (dimm_group2 ),
102
+ .dimms = dimm_group2 ,
103
+ },
104
+ };
30
105
31
106
static inline struct ndtest_priv * to_ndtest_priv (struct device * dev )
32
107
{
@@ -65,6 +140,152 @@ static int ndtest_ctl(struct nvdimm_bus_descriptor *nd_desc,
65
140
return 0 ;
66
141
}
67
142
143
+ static void ndtest_release_resource (void * data )
144
+ {
145
+ struct nfit_test_resource * res = data ;
146
+
147
+ spin_lock (& ndtest_lock );
148
+ list_del (& res -> list );
149
+ spin_unlock (& ndtest_lock );
150
+
151
+ if (resource_size (& res -> res ) >= DIMM_SIZE )
152
+ gen_pool_free (ndtest_pool , res -> res .start ,
153
+ resource_size (& res -> res ));
154
+ vfree (res -> buf );
155
+ kfree (res );
156
+ }
157
+
158
+ static void * ndtest_alloc_resource (struct ndtest_priv * p , size_t size ,
159
+ dma_addr_t * dma )
160
+ {
161
+ dma_addr_t __dma ;
162
+ void * buf ;
163
+ struct nfit_test_resource * res ;
164
+ struct genpool_data_align data = {
165
+ .align = SZ_128M ,
166
+ };
167
+
168
+ res = kzalloc (sizeof (* res ), GFP_KERNEL );
169
+ if (!res )
170
+ return NULL ;
171
+
172
+ buf = vmalloc (size );
173
+ if (size >= DIMM_SIZE )
174
+ __dma = gen_pool_alloc_algo (ndtest_pool , size ,
175
+ gen_pool_first_fit_align , & data );
176
+ else
177
+ __dma = (unsigned long ) buf ;
178
+
179
+ if (!__dma )
180
+ goto buf_err ;
181
+
182
+ INIT_LIST_HEAD (& res -> list );
183
+ res -> dev = & p -> pdev .dev ;
184
+ res -> buf = buf ;
185
+ res -> res .start = __dma ;
186
+ res -> res .end = __dma + size - 1 ;
187
+ res -> res .name = "NFIT" ;
188
+ spin_lock_init (& res -> lock );
189
+ INIT_LIST_HEAD (& res -> requests );
190
+ spin_lock (& ndtest_lock );
191
+ list_add (& res -> list , & p -> resources );
192
+ spin_unlock (& ndtest_lock );
193
+
194
+ if (dma )
195
+ * dma = __dma ;
196
+
197
+ if (!devm_add_action (& p -> pdev .dev , ndtest_release_resource , res ))
198
+ return res -> buf ;
199
+
200
+ buf_err :
201
+ if (__dma && size >= DIMM_SIZE )
202
+ gen_pool_free (ndtest_pool , __dma , size );
203
+ if (buf )
204
+ vfree (buf );
205
+ kfree (res );
206
+
207
+ return NULL ;
208
+ }
209
+
210
+ static void put_dimms (void * data )
211
+ {
212
+ struct ndtest_priv * p = data ;
213
+ int i ;
214
+
215
+ for (i = 0 ; i < p -> config -> dimm_count ; i ++ )
216
+ if (p -> config -> dimms [i ].dev ) {
217
+ device_unregister (p -> config -> dimms [i ].dev );
218
+ p -> config -> dimms [i ].dev = NULL ;
219
+ }
220
+ }
221
+
222
+ static int ndtest_dimm_register (struct ndtest_priv * priv ,
223
+ struct ndtest_dimm * dimm , int id )
224
+ {
225
+ struct device * dev = & priv -> pdev .dev ;
226
+ unsigned long dimm_flags = dimm -> flags ;
227
+
228
+ if (dimm -> num_formats > 1 ) {
229
+ set_bit (NDD_ALIASING , & dimm_flags );
230
+ set_bit (NDD_LABELING , & dimm_flags );
231
+ }
232
+
233
+ dimm -> nvdimm = nvdimm_create (priv -> bus , dimm , NULL , dimm_flags ,
234
+ NDTEST_SCM_DIMM_CMD_MASK , 0 , NULL );
235
+ if (!dimm -> nvdimm ) {
236
+ dev_err (dev , "Error creating DIMM object for %pOF\n" , priv -> dn );
237
+ return - ENXIO ;
238
+ }
239
+
240
+ dimm -> dev = device_create_with_groups (ndtest_dimm_class ,
241
+ & priv -> pdev .dev ,
242
+ 0 , dimm , NULL ,
243
+ "test_dimm%d" , id );
244
+ if (!dimm -> dev ) {
245
+ pr_err ("Could not create dimm device attributes\n" );
246
+ return - ENOMEM ;
247
+ }
248
+
249
+ return 0 ;
250
+ }
251
+
252
+ static int ndtest_nvdimm_init (struct ndtest_priv * p )
253
+ {
254
+ struct ndtest_dimm * d ;
255
+ void * res ;
256
+ int i , id ;
257
+
258
+ for (i = 0 ; i < p -> config -> dimm_count ; i ++ ) {
259
+ d = & p -> config -> dimms [i ];
260
+ d -> id = id = p -> config -> dimm_start + i ;
261
+ res = ndtest_alloc_resource (p , LABEL_SIZE , NULL );
262
+ if (!res )
263
+ return - ENOMEM ;
264
+
265
+ d -> label_area = res ;
266
+ sprintf (d -> label_area , "label%d" , id );
267
+ d -> config_size = LABEL_SIZE ;
268
+
269
+ if (!ndtest_alloc_resource (p , d -> size ,
270
+ & p -> dimm_dma [id ]))
271
+ return - ENOMEM ;
272
+
273
+ if (!ndtest_alloc_resource (p , LABEL_SIZE ,
274
+ & p -> label_dma [id ]))
275
+ return - ENOMEM ;
276
+
277
+ if (!ndtest_alloc_resource (p , LABEL_SIZE ,
278
+ & p -> dcr_dma [id ]))
279
+ return - ENOMEM ;
280
+
281
+ d -> address = p -> dimm_dma [id ];
282
+
283
+ ndtest_dimm_register (p , d , id );
284
+ }
285
+
286
+ return 0 ;
287
+ }
288
+
68
289
static ssize_t compatible_show (struct device * dev ,
69
290
struct device_attribute * attr , char * buf )
70
291
{
@@ -89,6 +310,8 @@ static const struct attribute_group *ndtest_attribute_groups[] = {
89
310
90
311
static int ndtest_bus_register (struct ndtest_priv * p )
91
312
{
313
+ p -> config = & bus_configs [p -> pdev .id ];
314
+
92
315
p -> bus_desc .ndctl = ndtest_ctl ;
93
316
p -> bus_desc .module = THIS_MODULE ;
94
317
p -> bus_desc .provider_name = NULL ;
@@ -114,14 +337,34 @@ static int ndtest_remove(struct platform_device *pdev)
114
337
static int ndtest_probe (struct platform_device * pdev )
115
338
{
116
339
struct ndtest_priv * p ;
340
+ int rc ;
117
341
118
342
p = to_ndtest_priv (& pdev -> dev );
119
343
if (ndtest_bus_register (p ))
120
344
return - ENOMEM ;
121
345
346
+ p -> dcr_dma = devm_kcalloc (& p -> pdev .dev , NUM_DCR ,
347
+ sizeof (dma_addr_t ), GFP_KERNEL );
348
+ p -> label_dma = devm_kcalloc (& p -> pdev .dev , NUM_DCR ,
349
+ sizeof (dma_addr_t ), GFP_KERNEL );
350
+ p -> dimm_dma = devm_kcalloc (& p -> pdev .dev , NUM_DCR ,
351
+ sizeof (dma_addr_t ), GFP_KERNEL );
352
+
353
+ rc = ndtest_nvdimm_init (p );
354
+ if (rc )
355
+ goto err ;
356
+
357
+ rc = devm_add_action_or_reset (& pdev -> dev , put_dimms , p );
358
+ if (rc )
359
+ goto err ;
360
+
122
361
platform_set_drvdata (pdev , p );
123
362
124
363
return 0 ;
364
+
365
+ err :
366
+ pr_err ("%s:%d Failed nvdimm init\n" , __func__ , __LINE__ );
367
+ return rc ;
125
368
}
126
369
127
370
static const struct platform_device_id ndtest_id [] = {
@@ -155,6 +398,10 @@ static void cleanup_devices(void)
155
398
156
399
nfit_test_teardown ();
157
400
401
+ if (ndtest_pool )
402
+ gen_pool_destroy (ndtest_pool );
403
+
404
+
158
405
if (ndtest_dimm_class )
159
406
class_destroy (ndtest_dimm_class );
160
407
}
@@ -178,6 +425,17 @@ static __init int ndtest_init(void)
178
425
goto err_register ;
179
426
}
180
427
428
+ ndtest_pool = gen_pool_create (ilog2 (SZ_4M ), NUMA_NO_NODE );
429
+ if (!ndtest_pool ) {
430
+ rc = - ENOMEM ;
431
+ goto err_register ;
432
+ }
433
+
434
+ if (gen_pool_add (ndtest_pool , SZ_4G , SZ_4G , NUMA_NO_NODE )) {
435
+ rc = - ENOMEM ;
436
+ goto err_register ;
437
+ }
438
+
181
439
/* Each instance can be taken as a bus, which can have multiple dimms */
182
440
for (i = 0 ; i < NUM_INSTANCES ; i ++ ) {
183
441
struct ndtest_priv * priv ;
0 commit comments