aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlastair D'Silva <alastair@d-silva.org>2019-03-27 01:31:32 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2019-05-02 12:55:01 -0400
commit75ca758adbafc81804c39b2c200ecdc819a6c042 (patch)
tree091664d0900e1c6ede2fad272f1561bee354a339
parent2f7d3d1453813cda13e5bace24093eac22cb5e61 (diff)
ocxl: Create a clear delineation between ocxl backend & frontend
The OCXL driver contains both frontend code for interacting with userspace, as well as backend code for interacting with the hardware. This patch separates the backend code from the frontend so that it can be used by other device drivers that communicate via OpenCAPI. Relocate dev, cdev & sysfs files to the frontend code to allow external drivers to maintain their own devices. Reference counting on the device in the backend is replaced with kref counting. Move file & sysfs layer initialisation from core.c (backend) to pci.c (frontend). Create an ocxl_function oriented interface for initing devices & enumerating AFUs. Signed-off-by: Alastair D'Silva <alastair@d-silva.org> Acked-by: Frederic Barrat <fbarrat@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--drivers/misc/ocxl/context.c2
-rw-r--r--drivers/misc/ocxl/core.c201
-rw-r--r--drivers/misc/ocxl/file.c142
-rw-r--r--drivers/misc/ocxl/ocxl_internal.h31
-rw-r--r--drivers/misc/ocxl/pci.c56
-rw-r--r--drivers/misc/ocxl/sysfs.c54
-rw-r--r--include/misc/ocxl.h119
7 files changed, 409 insertions, 196 deletions
diff --git a/drivers/misc/ocxl/context.c b/drivers/misc/ocxl/context.c
index c10a940e3b38..c73a859d2224 100644
--- a/drivers/misc/ocxl/context.c
+++ b/drivers/misc/ocxl/context.c
@@ -238,7 +238,7 @@ int ocxl_context_detach(struct ocxl_context *ctx)
238 } 238 }
239 rc = ocxl_link_remove_pe(ctx->afu->fn->link, ctx->pasid); 239 rc = ocxl_link_remove_pe(ctx->afu->fn->link, ctx->pasid);
240 if (rc) { 240 if (rc) {
241 dev_warn(&ctx->afu->dev, 241 dev_warn(&dev->dev,
242 "Couldn't remove PE entry cleanly: %d\n", rc); 242 "Couldn't remove PE entry cleanly: %d\n", rc);
243 } 243 }
244 return 0; 244 return 0;
diff --git a/drivers/misc/ocxl/core.c b/drivers/misc/ocxl/core.c
index 2f2fe12eac1e..b7a09b21ab36 100644
--- a/drivers/misc/ocxl/core.c
+++ b/drivers/misc/ocxl/core.c
@@ -13,16 +13,6 @@ static void ocxl_fn_put(struct ocxl_fn *fn)
13 put_device(&fn->dev); 13 put_device(&fn->dev);
14} 14}
15 15
16struct ocxl_afu *ocxl_afu_get(struct ocxl_afu *afu)
17{
18 return (get_device(&afu->dev) == NULL) ? NULL : afu;
19}
20
21void ocxl_afu_put(struct ocxl_afu *afu)
22{
23 put_device(&afu->dev);
24}
25
26static struct ocxl_afu *alloc_afu(struct ocxl_fn *fn) 16static struct ocxl_afu *alloc_afu(struct ocxl_fn *fn)
27{ 17{
28 struct ocxl_afu *afu; 18 struct ocxl_afu *afu;
@@ -31,6 +21,7 @@ static struct ocxl_afu *alloc_afu(struct ocxl_fn *fn)
31 if (!afu) 21 if (!afu)
32 return NULL; 22 return NULL;
33 23
24 kref_init(&afu->kref);
34 mutex_init(&afu->contexts_lock); 25 mutex_init(&afu->contexts_lock);
35 mutex_init(&afu->afu_control_lock); 26 mutex_init(&afu->afu_control_lock);
36 idr_init(&afu->contexts_idr); 27 idr_init(&afu->contexts_idr);
@@ -39,32 +30,26 @@ static struct ocxl_afu *alloc_afu(struct ocxl_fn *fn)
39 return afu; 30 return afu;
40} 31}
41 32
42static void free_afu(struct ocxl_afu *afu) 33static void free_afu(struct kref *kref)
43{ 34{
35 struct ocxl_afu *afu = container_of(kref, struct ocxl_afu, kref);
36
44 idr_destroy(&afu->contexts_idr); 37 idr_destroy(&afu->contexts_idr);
45 ocxl_fn_put(afu->fn); 38 ocxl_fn_put(afu->fn);
46 kfree(afu); 39 kfree(afu);
47} 40}
48 41
49static void free_afu_dev(struct device *dev) 42void ocxl_afu_get(struct ocxl_afu *afu)
50{ 43{
51 struct ocxl_afu *afu = to_ocxl_afu(dev); 44 kref_get(&afu->kref);
52
53 ocxl_unregister_afu(afu);
54 free_afu(afu);
55} 45}
46EXPORT_SYMBOL_GPL(ocxl_afu_get);
56 47
57static int set_afu_device(struct ocxl_afu *afu, const char *location) 48void ocxl_afu_put(struct ocxl_afu *afu)
58{ 49{
59 struct ocxl_fn *fn = afu->fn; 50 kref_put(&afu->kref, free_afu);
60 int rc;
61
62 afu->dev.parent = &fn->dev;
63 afu->dev.release = free_afu_dev;
64 rc = dev_set_name(&afu->dev, "%s.%s.%hhu", afu->config.name, location,
65 afu->config.idx);
66 return rc;
67} 51}
52EXPORT_SYMBOL_GPL(ocxl_afu_put);
68 53
69static int assign_afu_actag(struct ocxl_afu *afu) 54static int assign_afu_actag(struct ocxl_afu *afu)
70{ 55{
@@ -233,27 +218,25 @@ static int configure_afu(struct ocxl_afu *afu, u8 afu_idx, struct pci_dev *dev)
233 if (rc) 218 if (rc)
234 return rc; 219 return rc;
235 220
236 rc = set_afu_device(afu, dev_name(&dev->dev));
237 if (rc)
238 return rc;
239
240 rc = assign_afu_actag(afu); 221 rc = assign_afu_actag(afu);
241 if (rc) 222 if (rc)
242 return rc; 223 return rc;
243 224
244 rc = assign_afu_pasid(afu); 225 rc = assign_afu_pasid(afu);
245 if (rc) { 226 if (rc)
246 reclaim_afu_actag(afu); 227 goto err_free_actag;
247 return rc;
248 }
249 228
250 rc = map_mmio_areas(afu); 229 rc = map_mmio_areas(afu);
251 if (rc) { 230 if (rc)
252 reclaim_afu_pasid(afu); 231 goto err_free_pasid;
253 reclaim_afu_actag(afu); 232
254 return rc;
255 }
256 return 0; 233 return 0;
234
235err_free_pasid:
236 reclaim_afu_pasid(afu);
237err_free_actag:
238 reclaim_afu_actag(afu);
239 return rc;
257} 240}
258 241
259static void deconfigure_afu(struct ocxl_afu *afu) 242static void deconfigure_afu(struct ocxl_afu *afu)
@@ -265,16 +248,8 @@ static void deconfigure_afu(struct ocxl_afu *afu)
265 248
266static int activate_afu(struct pci_dev *dev, struct ocxl_afu *afu) 249static int activate_afu(struct pci_dev *dev, struct ocxl_afu *afu)
267{ 250{
268 int rc;
269
270 ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 1); 251 ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 1);
271 /* 252
272 * Char device creation is the last step, as processes can
273 * call our driver immediately, so all our inits must be finished.
274 */
275 rc = ocxl_create_cdev(afu);
276 if (rc)
277 return rc;
278 return 0; 253 return 0;
279} 254}
280 255
@@ -282,11 +257,10 @@ static void deactivate_afu(struct ocxl_afu *afu)
282{ 257{
283 struct pci_dev *dev = to_pci_dev(afu->fn->dev.parent); 258 struct pci_dev *dev = to_pci_dev(afu->fn->dev.parent);
284 259
285 ocxl_destroy_cdev(afu);
286 ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 0); 260 ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 0);
287} 261}
288 262
289int init_afu(struct pci_dev *dev, struct ocxl_fn *fn, u8 afu_idx) 263static int init_afu(struct pci_dev *dev, struct ocxl_fn *fn, u8 afu_idx)
290{ 264{
291 int rc; 265 int rc;
292 struct ocxl_afu *afu; 266 struct ocxl_afu *afu;
@@ -297,41 +271,29 @@ int init_afu(struct pci_dev *dev, struct ocxl_fn *fn, u8 afu_idx)
297 271
298 rc = configure_afu(afu, afu_idx, dev); 272 rc = configure_afu(afu, afu_idx, dev);
299 if (rc) { 273 if (rc) {
300 free_afu(afu); 274 ocxl_afu_put(afu);
301 return rc; 275 return rc;
302 } 276 }
303 277
304 rc = ocxl_register_afu(afu);
305 if (rc)
306 goto err;
307
308 rc = ocxl_sysfs_add_afu(afu);
309 if (rc)
310 goto err;
311
312 rc = activate_afu(dev, afu); 278 rc = activate_afu(dev, afu);
313 if (rc) 279 if (rc) {
314 goto err_sys; 280 deconfigure_afu(afu);
281 ocxl_afu_put(afu);
282 return rc;
283 }
315 284
316 list_add_tail(&afu->list, &fn->afu_list); 285 list_add_tail(&afu->list, &fn->afu_list);
317 return 0;
318 286
319err_sys: 287 return 0;
320 ocxl_sysfs_remove_afu(afu);
321err:
322 deconfigure_afu(afu);
323 device_unregister(&afu->dev);
324 return rc;
325} 288}
326 289
327void remove_afu(struct ocxl_afu *afu) 290static void remove_afu(struct ocxl_afu *afu)
328{ 291{
329 list_del(&afu->list); 292 list_del(&afu->list);
330 ocxl_context_detach_all(afu); 293 ocxl_context_detach_all(afu);
331 deactivate_afu(afu); 294 deactivate_afu(afu);
332 ocxl_sysfs_remove_afu(afu);
333 deconfigure_afu(afu); 295 deconfigure_afu(afu);
334 device_unregister(&afu->dev); 296 ocxl_afu_put(afu); // matches the implicit get in alloc_afu
335} 297}
336 298
337static struct ocxl_fn *alloc_function(void) 299static struct ocxl_fn *alloc_function(void)
@@ -358,7 +320,7 @@ static void free_function(struct ocxl_fn *fn)
358 320
359static void free_function_dev(struct device *dev) 321static void free_function_dev(struct device *dev)
360{ 322{
361 struct ocxl_fn *fn = to_ocxl_function(dev); 323 struct ocxl_fn *fn = container_of(dev, struct ocxl_fn, dev);
362 324
363 free_function(fn); 325 free_function(fn);
364} 326}
@@ -372,7 +334,6 @@ static int set_function_device(struct ocxl_fn *fn, struct pci_dev *dev)
372 rc = dev_set_name(&fn->dev, "ocxlfn.%s", dev_name(&dev->dev)); 334 rc = dev_set_name(&fn->dev, "ocxlfn.%s", dev_name(&dev->dev));
373 if (rc) 335 if (rc)
374 return rc; 336 return rc;
375 pci_set_drvdata(dev, fn);
376 return 0; 337 return 0;
377} 338}
378 339
@@ -490,7 +451,7 @@ static void deconfigure_function(struct ocxl_fn *fn)
490 pci_disable_device(dev); 451 pci_disable_device(dev);
491} 452}
492 453
493struct ocxl_fn *init_function(struct pci_dev *dev) 454static struct ocxl_fn *init_function(struct pci_dev *dev)
494{ 455{
495 struct ocxl_fn *fn; 456 struct ocxl_fn *fn;
496 int rc; 457 int rc;
@@ -514,8 +475,100 @@ struct ocxl_fn *init_function(struct pci_dev *dev)
514 return fn; 475 return fn;
515} 476}
516 477
517void remove_function(struct ocxl_fn *fn) 478// Device detection & initialisation
479
480struct ocxl_fn *ocxl_function_open(struct pci_dev *dev)
481{
482 int rc, afu_count = 0;
483 u8 afu;
484 struct ocxl_fn *fn;
485
486 if (!radix_enabled()) {
487 dev_err(&dev->dev, "Unsupported memory model (hash)\n");
488 return ERR_PTR(-ENODEV);
489 }
490
491 fn = init_function(dev);
492 if (IS_ERR(fn)) {
493 dev_err(&dev->dev, "function init failed: %li\n",
494 PTR_ERR(fn));
495 return fn;
496 }
497
498 for (afu = 0; afu <= fn->config.max_afu_index; afu++) {
499 rc = ocxl_config_check_afu_index(dev, &fn->config, afu);
500 if (rc > 0) {
501 rc = init_afu(dev, fn, afu);
502 if (rc) {
503 dev_err(&dev->dev,
504 "Can't initialize AFU index %d\n", afu);
505 continue;
506 }
507 afu_count++;
508 }
509 }
510 dev_info(&dev->dev, "%d AFU(s) configured\n", afu_count);
511 return fn;
512}
513EXPORT_SYMBOL_GPL(ocxl_function_open);
514
515struct list_head *ocxl_function_afu_list(struct ocxl_fn *fn)
516{
517 return &fn->afu_list;
518}
519EXPORT_SYMBOL_GPL(ocxl_function_afu_list);
520
521struct ocxl_afu *ocxl_function_fetch_afu(struct ocxl_fn *fn, u8 afu_idx)
522{
523 struct ocxl_afu *afu;
524
525 list_for_each_entry(afu, &fn->afu_list, list) {
526 if (afu->config.idx == afu_idx)
527 return afu;
528 }
529
530 return NULL;
531}
532EXPORT_SYMBOL_GPL(ocxl_function_fetch_afu);
533
534const struct ocxl_fn_config *ocxl_function_config(struct ocxl_fn *fn)
518{ 535{
536 return &fn->config;
537}
538EXPORT_SYMBOL_GPL(ocxl_function_config);
539
540void ocxl_function_close(struct ocxl_fn *fn)
541{
542 struct ocxl_afu *afu, *tmp;
543
544 list_for_each_entry_safe(afu, tmp, &fn->afu_list, list) {
545 remove_afu(afu);
546 }
547
519 deconfigure_function(fn); 548 deconfigure_function(fn);
520 device_unregister(&fn->dev); 549 device_unregister(&fn->dev);
521} 550}
551EXPORT_SYMBOL_GPL(ocxl_function_close);
552
553// AFU Metadata
554
555struct ocxl_afu_config *ocxl_afu_config(struct ocxl_afu *afu)
556{
557 return &afu->config;
558}
559EXPORT_SYMBOL_GPL(ocxl_afu_config);
560
561void ocxl_afu_set_private(struct ocxl_afu *afu, void *private)
562{
563 afu->private = private;
564}
565EXPORT_SYMBOL_GPL(ocxl_afu_set_private);
566
567void *ocxl_afu_get_private(struct ocxl_afu *afu)
568{
569 if (afu)
570 return afu->private;
571
572 return NULL;
573}
574EXPORT_SYMBOL_GPL(ocxl_afu_get_private);
diff --git a/drivers/misc/ocxl/file.c b/drivers/misc/ocxl/file.c
index 009e09b7ded5..7a38ea5af9db 100644
--- a/drivers/misc/ocxl/file.c
+++ b/drivers/misc/ocxl/file.c
@@ -17,70 +17,60 @@ static struct class *ocxl_class;
17static struct mutex minors_idr_lock; 17static struct mutex minors_idr_lock;
18static struct idr minors_idr; 18static struct idr minors_idr;
19 19
20static struct ocxl_afu *find_and_get_afu(dev_t devno) 20static struct ocxl_file_info *find_file_info(dev_t devno)
21{ 21{
22 struct ocxl_afu *afu; 22 struct ocxl_file_info *info;
23 int afu_minor;
24 23
25 afu_minor = MINOR(devno);
26 /* 24 /*
27 * We don't declare an RCU critical section here, as our AFU 25 * We don't declare an RCU critical section here, as our AFU
28 * is protected by a reference counter on the device. By the time the 26 * is protected by a reference counter on the device. By the time the
29 * minor number of a device is removed from the idr, the ref count of 27 * info reference is removed from the idr, the ref count of
30 * the device is already at 0, so no user API will access that AFU and 28 * the device is already at 0, so no user API will access that AFU and
31 * this function can't return it. 29 * this function can't return it.
32 */ 30 */
33 afu = idr_find(&minors_idr, afu_minor); 31 info = idr_find(&minors_idr, MINOR(devno));
34 if (afu) 32 return info;
35 ocxl_afu_get(afu);
36 return afu;
37} 33}
38 34
39static int allocate_afu_minor(struct ocxl_afu *afu) 35static int allocate_minor(struct ocxl_file_info *info)
40{ 36{
41 int minor; 37 int minor;
42 38
43 mutex_lock(&minors_idr_lock); 39 mutex_lock(&minors_idr_lock);
44 minor = idr_alloc(&minors_idr, afu, 0, OCXL_NUM_MINORS, GFP_KERNEL); 40 minor = idr_alloc(&minors_idr, info, 0, OCXL_NUM_MINORS, GFP_KERNEL);
45 mutex_unlock(&minors_idr_lock); 41 mutex_unlock(&minors_idr_lock);
46 return minor; 42 return minor;
47} 43}
48 44
49static void free_afu_minor(struct ocxl_afu *afu) 45static void free_minor(struct ocxl_file_info *info)
50{ 46{
51 mutex_lock(&minors_idr_lock); 47 mutex_lock(&minors_idr_lock);
52 idr_remove(&minors_idr, MINOR(afu->dev.devt)); 48 idr_remove(&minors_idr, MINOR(info->dev.devt));
53 mutex_unlock(&minors_idr_lock); 49 mutex_unlock(&minors_idr_lock);
54} 50}
55 51
56static int afu_open(struct inode *inode, struct file *file) 52static int afu_open(struct inode *inode, struct file *file)
57{ 53{
58 struct ocxl_afu *afu; 54 struct ocxl_file_info *info;
59 struct ocxl_context *ctx; 55 struct ocxl_context *ctx;
60 int rc; 56 int rc;
61 57
62 pr_debug("%s for device %x\n", __func__, inode->i_rdev); 58 pr_debug("%s for device %x\n", __func__, inode->i_rdev);
63 59
64 afu = find_and_get_afu(inode->i_rdev); 60 info = find_file_info(inode->i_rdev);
65 if (!afu) 61 if (!info)
66 return -ENODEV; 62 return -ENODEV;
67 63
68 ctx = ocxl_context_alloc(); 64 ctx = ocxl_context_alloc();
69 if (!ctx) { 65 if (!ctx)
70 rc = -ENOMEM; 66 return -ENOMEM;
71 goto put_afu;
72 }
73 67
74 rc = ocxl_context_init(ctx, afu, inode->i_mapping); 68 rc = ocxl_context_init(ctx, info->afu, inode->i_mapping);
75 if (rc) 69 if (rc)
76 goto put_afu; 70 return rc;
71
77 file->private_data = ctx; 72 file->private_data = ctx;
78 ocxl_afu_put(afu);
79 return 0; 73 return 0;
80
81put_afu:
82 ocxl_afu_put(afu);
83 return rc;
84} 74}
85 75
86static long afu_ioctl_attach(struct ocxl_context *ctx, 76static long afu_ioctl_attach(struct ocxl_context *ctx,
@@ -204,11 +194,16 @@ static long afu_ioctl(struct file *file, unsigned int cmd,
204 struct ocxl_ioctl_irq_fd irq_fd; 194 struct ocxl_ioctl_irq_fd irq_fd;
205 u64 irq_offset; 195 u64 irq_offset;
206 long rc; 196 long rc;
197 bool closed;
207 198
208 pr_debug("%s for context %d, command %s\n", __func__, ctx->pasid, 199 pr_debug("%s for context %d, command %s\n", __func__, ctx->pasid,
209 CMD_STR(cmd)); 200 CMD_STR(cmd));
210 201
211 if (ctx->status == CLOSED) 202 mutex_lock(&ctx->status_mutex);
203 closed = (ctx->status == CLOSED);
204 mutex_unlock(&ctx->status_mutex);
205
206 if (closed)
212 return -EIO; 207 return -EIO;
213 208
214 switch (cmd) { 209 switch (cmd) {
@@ -468,39 +463,102 @@ static const struct file_operations ocxl_afu_fops = {
468 .release = afu_release, 463 .release = afu_release,
469}; 464};
470 465
471int ocxl_create_cdev(struct ocxl_afu *afu) 466// Free the info struct
467static void info_release(struct device *dev)
468{
469 struct ocxl_file_info *info = container_of(dev, struct ocxl_file_info, dev);
470
471 free_minor(info);
472 ocxl_afu_put(info->afu);
473 kfree(info);
474}
475
476static int ocxl_file_make_visible(struct ocxl_file_info *info)
472{ 477{
473 int rc; 478 int rc;
474 479
475 cdev_init(&afu->cdev, &ocxl_afu_fops); 480 cdev_init(&info->cdev, &ocxl_afu_fops);
476 rc = cdev_add(&afu->cdev, afu->dev.devt, 1); 481 rc = cdev_add(&info->cdev, info->dev.devt, 1);
477 if (rc) { 482 if (rc) {
478 dev_err(&afu->dev, "Unable to add afu char device: %d\n", rc); 483 dev_err(&info->dev, "Unable to add afu char device: %d\n", rc);
479 return rc; 484 return rc;
480 } 485 }
486
481 return 0; 487 return 0;
482} 488}
483 489
484void ocxl_destroy_cdev(struct ocxl_afu *afu) 490static void ocxl_file_make_invisible(struct ocxl_file_info *info)
485{ 491{
486 cdev_del(&afu->cdev); 492 cdev_del(&info->cdev);
487} 493}
488 494
489int ocxl_register_afu(struct ocxl_afu *afu) 495int ocxl_file_register_afu(struct ocxl_afu *afu)
490{ 496{
491 int minor; 497 int minor;
498 int rc;
499 struct ocxl_file_info *info;
500 struct ocxl_fn *fn = afu->fn;
501 struct pci_dev *pci_dev = to_pci_dev(fn->dev.parent);
502
503 info = kzalloc(sizeof(*info), GFP_KERNEL);
504 if (info == NULL)
505 return -ENOMEM;
492 506
493 minor = allocate_afu_minor(afu); 507 minor = allocate_minor(info);
494 if (minor < 0) 508 if (minor < 0) {
509 kfree(info);
495 return minor; 510 return minor;
496 afu->dev.devt = MKDEV(MAJOR(ocxl_dev), minor); 511 }
497 afu->dev.class = ocxl_class; 512
498 return device_register(&afu->dev); 513 info->dev.parent = &fn->dev;
514 info->dev.devt = MKDEV(MAJOR(ocxl_dev), minor);
515 info->dev.class = ocxl_class;
516 info->dev.release = info_release;
517
518 info->afu = afu;
519 ocxl_afu_get(afu);
520
521 rc = dev_set_name(&info->dev, "%s.%s.%hhu",
522 afu->config.name, dev_name(&pci_dev->dev), afu->config.idx);
523 if (rc)
524 goto err_put;
525
526 rc = device_register(&info->dev);
527 if (rc)
528 goto err_put;
529
530 rc = ocxl_sysfs_register_afu(info);
531 if (rc)
532 goto err_unregister;
533
534 rc = ocxl_file_make_visible(info);
535 if (rc)
536 goto err_unregister;
537
538 ocxl_afu_set_private(afu, info);
539
540 return 0;
541
542err_unregister:
543 ocxl_sysfs_unregister_afu(info); // safe to call even if register failed
544 device_unregister(&info->dev);
545err_put:
546 ocxl_afu_put(afu);
547 free_minor(info);
548 kfree(info);
549 return rc;
499} 550}
500 551
501void ocxl_unregister_afu(struct ocxl_afu *afu) 552void ocxl_file_unregister_afu(struct ocxl_afu *afu)
502{ 553{
503 free_afu_minor(afu); 554 struct ocxl_file_info *info = ocxl_afu_get_private(afu);
555
556 if (!info)
557 return;
558
559 ocxl_file_make_invisible(info);
560 ocxl_sysfs_unregister_afu(info);
561 device_unregister(&info->dev);
504} 562}
505 563
506static char *ocxl_devnode(struct device *dev, umode_t *mode) 564static char *ocxl_devnode(struct device *dev, umode_t *mode)
diff --git a/drivers/misc/ocxl/ocxl_internal.h b/drivers/misc/ocxl/ocxl_internal.h
index 81086534dab5..53b6c64a1bf0 100644
--- a/drivers/misc/ocxl/ocxl_internal.h
+++ b/drivers/misc/ocxl/ocxl_internal.h
@@ -11,9 +11,6 @@
11#define MAX_IRQ_PER_LINK 2000 11#define MAX_IRQ_PER_LINK 2000
12#define MAX_IRQ_PER_CONTEXT MAX_IRQ_PER_LINK 12#define MAX_IRQ_PER_CONTEXT MAX_IRQ_PER_LINK
13 13
14#define to_ocxl_function(d) container_of(d, struct ocxl_fn, dev)
15#define to_ocxl_afu(d) container_of(d, struct ocxl_afu, dev)
16
17extern struct pci_driver ocxl_pci_driver; 14extern struct pci_driver ocxl_pci_driver;
18 15
19struct ocxl_fn { 16struct ocxl_fn {
@@ -30,11 +27,17 @@ struct ocxl_fn {
30 void *link; 27 void *link;
31}; 28};
32 29
30struct ocxl_file_info {
31 struct ocxl_afu *afu;
32 struct device dev;
33 struct cdev cdev;
34 struct bin_attribute attr_global_mmio;
35};
36
33struct ocxl_afu { 37struct ocxl_afu {
38 struct kref kref;
34 struct ocxl_fn *fn; 39 struct ocxl_fn *fn;
35 struct list_head list; 40 struct list_head list;
36 struct device dev;
37 struct cdev cdev;
38 struct ocxl_afu_config config; 41 struct ocxl_afu_config config;
39 int pasid_base; 42 int pasid_base;
40 int pasid_count; /* opened contexts */ 43 int pasid_count; /* opened contexts */
@@ -48,7 +51,7 @@ struct ocxl_afu {
48 u64 irq_base_offset; 51 u64 irq_base_offset;
49 void __iomem *global_mmio_ptr; 52 void __iomem *global_mmio_ptr;
50 u64 pp_mmio_start; 53 u64 pp_mmio_start;
51 struct bin_attribute attr_global_mmio; 54 void *private;
52}; 55};
53 56
54enum ocxl_context_status { 57enum ocxl_context_status {
@@ -91,13 +94,10 @@ struct ocxl_process_element {
91 __be32 software_state; 94 __be32 software_state;
92}; 95};
93 96
94struct ocxl_afu *ocxl_afu_get(struct ocxl_afu *afu);
95void ocxl_afu_put(struct ocxl_afu *afu);
96
97int ocxl_create_cdev(struct ocxl_afu *afu); 97int ocxl_create_cdev(struct ocxl_afu *afu);
98void ocxl_destroy_cdev(struct ocxl_afu *afu); 98void ocxl_destroy_cdev(struct ocxl_afu *afu);
99int ocxl_register_afu(struct ocxl_afu *afu); 99int ocxl_file_register_afu(struct ocxl_afu *afu);
100void ocxl_unregister_afu(struct ocxl_afu *afu); 100void ocxl_file_unregister_afu(struct ocxl_afu *afu);
101 101
102int ocxl_file_init(void); 102int ocxl_file_init(void);
103void ocxl_file_exit(void); 103void ocxl_file_exit(void);
@@ -140,8 +140,8 @@ int ocxl_context_detach(struct ocxl_context *ctx);
140void ocxl_context_detach_all(struct ocxl_afu *afu); 140void ocxl_context_detach_all(struct ocxl_afu *afu);
141void ocxl_context_free(struct ocxl_context *ctx); 141void ocxl_context_free(struct ocxl_context *ctx);
142 142
143int ocxl_sysfs_add_afu(struct ocxl_afu *afu); 143int ocxl_sysfs_register_afu(struct ocxl_file_info *info);
144void ocxl_sysfs_remove_afu(struct ocxl_afu *afu); 144void ocxl_sysfs_unregister_afu(struct ocxl_file_info *info);
145 145
146int ocxl_afu_irq_alloc(struct ocxl_context *ctx, u64 *irq_offset); 146int ocxl_afu_irq_alloc(struct ocxl_context *ctx, u64 *irq_offset);
147int ocxl_afu_irq_free(struct ocxl_context *ctx, u64 irq_offset); 147int ocxl_afu_irq_free(struct ocxl_context *ctx, u64 irq_offset);
@@ -150,9 +150,4 @@ int ocxl_afu_irq_set_fd(struct ocxl_context *ctx, u64 irq_offset,
150 int eventfd); 150 int eventfd);
151u64 ocxl_afu_irq_get_addr(struct ocxl_context *ctx, u64 irq_offset); 151u64 ocxl_afu_irq_get_addr(struct ocxl_context *ctx, u64 irq_offset);
152 152
153struct ocxl_fn *init_function(struct pci_dev *dev);
154void remove_function(struct ocxl_fn *fn);
155int init_afu(struct pci_dev *dev, struct ocxl_fn *fn, u8 afu_idx);
156void remove_afu(struct ocxl_afu *afu);
157
158#endif /* _OCXL_INTERNAL_H_ */ 153#endif /* _OCXL_INTERNAL_H_ */
diff --git a/drivers/misc/ocxl/pci.c b/drivers/misc/ocxl/pci.c
index 4ed7cb1a667f..f2a3ef4b9bdd 100644
--- a/drivers/misc/ocxl/pci.c
+++ b/drivers/misc/ocxl/pci.c
@@ -16,47 +16,45 @@ MODULE_DEVICE_TABLE(pci, ocxl_pci_tbl);
16 16
17static int ocxl_probe(struct pci_dev *dev, const struct pci_device_id *id) 17static int ocxl_probe(struct pci_dev *dev, const struct pci_device_id *id)
18{ 18{
19 int rc, afu_count = 0; 19 int rc;
20 u8 afu; 20 struct ocxl_afu *afu, *tmp;
21 struct ocxl_fn *fn; 21 struct ocxl_fn *fn;
22 struct list_head *afu_list;
22 23
23 if (!radix_enabled()) { 24 fn = ocxl_function_open(dev);
24 dev_err(&dev->dev, "Unsupported memory model (hash)\n"); 25 if (IS_ERR(fn))
25 return -ENODEV;
26 }
27
28 fn = init_function(dev);
29 if (IS_ERR(fn)) {
30 dev_err(&dev->dev, "function init failed: %li\n",
31 PTR_ERR(fn));
32 return PTR_ERR(fn); 26 return PTR_ERR(fn);
33 }
34 27
35 for (afu = 0; afu <= fn->config.max_afu_index; afu++) { 28 pci_set_drvdata(dev, fn);
36 rc = ocxl_config_check_afu_index(dev, &fn->config, afu); 29
37 if (rc > 0) { 30 afu_list = ocxl_function_afu_list(fn);
38 rc = init_afu(dev, fn, afu); 31
39 if (rc) { 32 list_for_each_entry_safe(afu, tmp, afu_list, list) {
40 dev_err(&dev->dev, 33 // Cleanup handled within ocxl_file_register_afu()
41 "Can't initialize AFU index %d\n", afu); 34 rc = ocxl_file_register_afu(afu);
42 continue; 35 if (rc) {
43 } 36 dev_err(&dev->dev, "Failed to register AFU '%s' index %d",
44 afu_count++; 37 afu->config.name, afu->config.idx);
45 } 38 }
46 } 39 }
47 dev_info(&dev->dev, "%d AFU(s) configured\n", afu_count); 40
48 return 0; 41 return 0;
49} 42}
50 43
51static void ocxl_remove(struct pci_dev *dev) 44void ocxl_remove(struct pci_dev *dev)
52{ 45{
53 struct ocxl_afu *afu, *tmp; 46 struct ocxl_fn *fn;
54 struct ocxl_fn *fn = pci_get_drvdata(dev); 47 struct ocxl_afu *afu;
48 struct list_head *afu_list;
55 49
56 list_for_each_entry_safe(afu, tmp, &fn->afu_list, list) { 50 fn = pci_get_drvdata(dev);
57 remove_afu(afu); 51 afu_list = ocxl_function_afu_list(fn);
52
53 list_for_each_entry(afu, afu_list, list) {
54 ocxl_file_unregister_afu(afu);
58 } 55 }
59 remove_function(fn); 56
57 ocxl_function_close(fn);
60} 58}
61 59
62struct pci_driver ocxl_pci_driver = { 60struct pci_driver ocxl_pci_driver = {
diff --git a/drivers/misc/ocxl/sysfs.c b/drivers/misc/ocxl/sysfs.c
index 0ab1fd1b2682..58f1ba264206 100644
--- a/drivers/misc/ocxl/sysfs.c
+++ b/drivers/misc/ocxl/sysfs.c
@@ -3,11 +3,18 @@
3#include <linux/sysfs.h> 3#include <linux/sysfs.h>
4#include "ocxl_internal.h" 4#include "ocxl_internal.h"
5 5
6static inline struct ocxl_afu *to_afu(struct device *device)
7{
8 struct ocxl_file_info *info = container_of(device, struct ocxl_file_info, dev);
9
10 return info->afu;
11}
12
6static ssize_t global_mmio_size_show(struct device *device, 13static ssize_t global_mmio_size_show(struct device *device,
7 struct device_attribute *attr, 14 struct device_attribute *attr,
8 char *buf) 15 char *buf)
9{ 16{
10 struct ocxl_afu *afu = to_ocxl_afu(device); 17 struct ocxl_afu *afu = to_afu(device);
11 18
12 return scnprintf(buf, PAGE_SIZE, "%d\n", 19 return scnprintf(buf, PAGE_SIZE, "%d\n",
13 afu->config.global_mmio_size); 20 afu->config.global_mmio_size);
@@ -17,7 +24,7 @@ static ssize_t pp_mmio_size_show(struct device *device,
17 struct device_attribute *attr, 24 struct device_attribute *attr,
18 char *buf) 25 char *buf)
19{ 26{
20 struct ocxl_afu *afu = to_ocxl_afu(device); 27 struct ocxl_afu *afu = to_afu(device);
21 28
22 return scnprintf(buf, PAGE_SIZE, "%d\n", 29 return scnprintf(buf, PAGE_SIZE, "%d\n",
23 afu->config.pp_mmio_stride); 30 afu->config.pp_mmio_stride);
@@ -27,7 +34,7 @@ static ssize_t afu_version_show(struct device *device,
27 struct device_attribute *attr, 34 struct device_attribute *attr,
28 char *buf) 35 char *buf)
29{ 36{
30 struct ocxl_afu *afu = to_ocxl_afu(device); 37 struct ocxl_afu *afu = to_afu(device);
31 38
32 return scnprintf(buf, PAGE_SIZE, "%hhu:%hhu\n", 39 return scnprintf(buf, PAGE_SIZE, "%hhu:%hhu\n",
33 afu->config.version_major, 40 afu->config.version_major,
@@ -38,7 +45,7 @@ static ssize_t contexts_show(struct device *device,
38 struct device_attribute *attr, 45 struct device_attribute *attr,
39 char *buf) 46 char *buf)
40{ 47{
41 struct ocxl_afu *afu = to_ocxl_afu(device); 48 struct ocxl_afu *afu = to_afu(device);
42 49
43 return scnprintf(buf, PAGE_SIZE, "%d/%d\n", 50 return scnprintf(buf, PAGE_SIZE, "%d/%d\n",
44 afu->pasid_count, afu->pasid_max); 51 afu->pasid_count, afu->pasid_max);
@@ -55,7 +62,7 @@ static ssize_t global_mmio_read(struct file *filp, struct kobject *kobj,
55 struct bin_attribute *bin_attr, char *buf, 62 struct bin_attribute *bin_attr, char *buf,
56 loff_t off, size_t count) 63 loff_t off, size_t count)
57{ 64{
58 struct ocxl_afu *afu = to_ocxl_afu(kobj_to_dev(kobj)); 65 struct ocxl_afu *afu = to_afu(kobj_to_dev(kobj));
59 66
60 if (count == 0 || off < 0 || 67 if (count == 0 || off < 0 ||
61 off >= afu->config.global_mmio_size) 68 off >= afu->config.global_mmio_size)
@@ -86,7 +93,7 @@ static int global_mmio_mmap(struct file *filp, struct kobject *kobj,
86 struct bin_attribute *bin_attr, 93 struct bin_attribute *bin_attr,
87 struct vm_area_struct *vma) 94 struct vm_area_struct *vma)
88{ 95{
89 struct ocxl_afu *afu = to_ocxl_afu(kobj_to_dev(kobj)); 96 struct ocxl_afu *afu = to_afu(kobj_to_dev(kobj));
90 97
91 if ((vma_pages(vma) + vma->vm_pgoff) > 98 if ((vma_pages(vma) + vma->vm_pgoff) >
92 (afu->config.global_mmio_size >> PAGE_SHIFT)) 99 (afu->config.global_mmio_size >> PAGE_SHIFT))
@@ -99,27 +106,25 @@ static int global_mmio_mmap(struct file *filp, struct kobject *kobj,
99 return 0; 106 return 0;
100} 107}
101 108
102int ocxl_sysfs_add_afu(struct ocxl_afu *afu) 109int ocxl_sysfs_register_afu(struct ocxl_file_info *info)
103{ 110{
104 int i, rc; 111 int i, rc;
105 112
106 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 113 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
107 rc = device_create_file(&afu->dev, &afu_attrs[i]); 114 rc = device_create_file(&info->dev, &afu_attrs[i]);
108 if (rc) 115 if (rc)
109 goto err; 116 goto err;
110 } 117 }
111 118
112 sysfs_attr_init(&afu->attr_global_mmio.attr); 119 sysfs_attr_init(&info->attr_global_mmio.attr);
113 afu->attr_global_mmio.attr.name = "global_mmio_area"; 120 info->attr_global_mmio.attr.name = "global_mmio_area";
114 afu->attr_global_mmio.attr.mode = 0600; 121 info->attr_global_mmio.attr.mode = 0600;
115 afu->attr_global_mmio.size = afu->config.global_mmio_size; 122 info->attr_global_mmio.size = info->afu->config.global_mmio_size;
116 afu->attr_global_mmio.read = global_mmio_read; 123 info->attr_global_mmio.read = global_mmio_read;
117 afu->attr_global_mmio.mmap = global_mmio_mmap; 124 info->attr_global_mmio.mmap = global_mmio_mmap;
118 rc = device_create_bin_file(&afu->dev, &afu->attr_global_mmio); 125 rc = device_create_bin_file(&info->dev, &info->attr_global_mmio);
119 if (rc) { 126 if (rc) {
120 dev_err(&afu->dev, 127 dev_err(&info->dev, "Unable to create global mmio attr for afu: %d\n", rc);
121 "Unable to create global mmio attr for afu: %d\n",
122 rc);
123 goto err; 128 goto err;
124 } 129 }
125 130
@@ -127,15 +132,20 @@ int ocxl_sysfs_add_afu(struct ocxl_afu *afu)
127 132
128err: 133err:
129 for (i--; i >= 0; i--) 134 for (i--; i >= 0; i--)
130 device_remove_file(&afu->dev, &afu_attrs[i]); 135 device_remove_file(&info->dev, &afu_attrs[i]);
136
131 return rc; 137 return rc;
132} 138}
133 139
134void ocxl_sysfs_remove_afu(struct ocxl_afu *afu) 140void ocxl_sysfs_unregister_afu(struct ocxl_file_info *info)
135{ 141{
136 int i; 142 int i;
137 143
144 /*
145 * device_remove_bin_file is safe to call if the file is not added as
146 * the files are removed by name, and early exit if not found
147 */
138 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) 148 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++)
139 device_remove_file(&afu->dev, &afu_attrs[i]); 149 device_remove_file(&info->dev, &afu_attrs[i]);
140 device_remove_bin_file(&afu->dev, &afu->attr_global_mmio); 150 device_remove_bin_file(&info->dev, &info->attr_global_mmio);
141} 151}
diff --git a/include/misc/ocxl.h b/include/misc/ocxl.h
index 9530d3be1b30..8bafd748e380 100644
--- a/include/misc/ocxl.h
+++ b/include/misc/ocxl.h
@@ -16,11 +16,7 @@
16 16
17#define OCXL_AFU_NAME_SZ (24+1) /* add 1 for NULL termination */ 17#define OCXL_AFU_NAME_SZ (24+1) /* add 1 for NULL termination */
18 18
19/* 19
20 * The following 2 structures are a fairly generic way of representing
21 * the configuration data for a function and AFU, as read from the
22 * configuration space.
23 */
24struct ocxl_afu_config { 20struct ocxl_afu_config {
25 u8 idx; 21 u8 idx;
26 int dvsec_afu_control_pos; /* offset of AFU control DVSEC */ 22 int dvsec_afu_control_pos; /* offset of AFU control DVSEC */
@@ -49,12 +45,108 @@ struct ocxl_fn_config {
49 s8 max_afu_index; 45 s8 max_afu_index;
50}; 46};
51 47
52/* 48// These are opaque outside the ocxl driver
53 * Read the configuration space of a function and fill in a 49struct ocxl_afu;
54 * ocxl_fn_config structure with all the function details 50struct ocxl_fn;
51
52// Device detection & initialisation
53
54/**
55 * Open an OpenCAPI function on an OpenCAPI device
56 *
57 * @dev: The PCI device that contains the function
58 *
59 * Returns an opaque pointer to the function, or an error pointer (check with IS_ERR)
55 */ 60 */
56int ocxl_config_read_function(struct pci_dev *dev, 61struct ocxl_fn *ocxl_function_open(struct pci_dev *dev);
57 struct ocxl_fn_config *fn); 62
63/**
64 * Get the list of AFUs associated with a PCI function device
65 *
66 * Returns a list of struct ocxl_afu *
67 *
68 * @fn: The OpenCAPI function containing the AFUs
69 */
70struct list_head *ocxl_function_afu_list(struct ocxl_fn *fn);
71
72/**
73 * Fetch an AFU instance from an OpenCAPI function
74 *
75 * @fn: The OpenCAPI function to get the AFU from
76 * @afu_idx: The index of the AFU to get
77 *
78 * If successful, the AFU should be released with ocxl_afu_put()
79 *
80 * Returns a pointer to the AFU, or NULL on error
81 */
82struct ocxl_afu *ocxl_function_fetch_afu(struct ocxl_fn *fn, u8 afu_idx);
83
84/**
85 * Take a reference to an AFU
86 *
87 * @afu: The AFU to increment the reference count on
88 */
89void ocxl_afu_get(struct ocxl_afu *afu);
90
91/**
92 * Release a reference to an AFU
93 *
94 * @afu: The AFU to decrement the reference count on
95 */
96void ocxl_afu_put(struct ocxl_afu *afu);
97
98
99/**
100 * Get the configuration information for an OpenCAPI function
101 *
102 * @fn: The OpenCAPI function to get the config for
103 *
104 * Returns the function config, or NULL on error
105 */
106const struct ocxl_fn_config *ocxl_function_config(struct ocxl_fn *fn);
107
108/**
109 * Close an OpenCAPI function
110 *
111 * This will free any AFUs previously retrieved from the function, and
112 * detach and associated contexts. The contexts must by freed by the caller.
113 *
114 * @fn: The OpenCAPI function to close
115 *
116 */
117void ocxl_function_close(struct ocxl_fn *fn);
118
119// AFU Metadata
120
121/**
122 * Get a pointer to the config for an AFU
123 *
124 * @afu: a pointer to the AFU to get the config for
125 *
126 * Returns a pointer to the AFU config
127 */
128struct ocxl_afu_config *ocxl_afu_config(struct ocxl_afu *afu);
129
130/**
131 * Assign opaque hardware specific information to an OpenCAPI AFU.
132 *
133 * @dev: The PCI device associated with the OpenCAPI device
134 * @private: the opaque hardware specific information to assign to the driver
135 */
136void ocxl_afu_set_private(struct ocxl_afu *afu, void *private);
137
138/**
139 * Fetch the hardware specific information associated with an external OpenCAPI
140 * AFU. This may be consumed by an external OpenCAPI driver.
141 *
142 * @afu: The AFU
143 *
144 * Returns the opaque pointer associated with the device, or NULL if not set
145 */
146void *ocxl_afu_get_private(struct ocxl_afu *dev);
147
148
149// Functions left here are for compatibility with the cxlflash driver
58 150
59/* 151/*
60 * Read the configuration space of a function for the AFU specified by 152 * Read the configuration space of a function for the AFU specified by
@@ -142,6 +234,13 @@ int ocxl_config_terminate_pasid(struct pci_dev *dev,
142 int afu_control_offset, int pasid); 234 int afu_control_offset, int pasid);
143 235
144/* 236/*
237 * Read the configuration space of a function and fill in a
238 * ocxl_fn_config structure with all the function details
239 */
240int ocxl_config_read_function(struct pci_dev *dev,
241 struct ocxl_fn_config *fn);
242
243/*
145 * Set up the opencapi link for the function. 244 * Set up the opencapi link for the function.
146 * 245 *
147 * When called for the first time for a link, it sets up the Shared 246 * When called for the first time for a link, it sets up the Shared