linux/drivers/misc/ocxl/core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2// Copyright 2019 IBM Corp.
   3#include <linux/idr.h>
   4#include "ocxl_internal.h"
   5
   6static struct ocxl_fn *ocxl_fn_get(struct ocxl_fn *fn)
   7{
   8        return (get_device(&fn->dev) == NULL) ? NULL : fn;
   9}
  10
  11static void ocxl_fn_put(struct ocxl_fn *fn)
  12{
  13        put_device(&fn->dev);
  14}
  15
  16static struct ocxl_afu *alloc_afu(struct ocxl_fn *fn)
  17{
  18        struct ocxl_afu *afu;
  19
  20        afu = kzalloc(sizeof(struct ocxl_afu), GFP_KERNEL);
  21        if (!afu)
  22                return NULL;
  23
  24        kref_init(&afu->kref);
  25        mutex_init(&afu->contexts_lock);
  26        mutex_init(&afu->afu_control_lock);
  27        idr_init(&afu->contexts_idr);
  28        afu->fn = fn;
  29        ocxl_fn_get(fn);
  30        return afu;
  31}
  32
  33static void free_afu(struct kref *kref)
  34{
  35        struct ocxl_afu *afu = container_of(kref, struct ocxl_afu, kref);
  36
  37        idr_destroy(&afu->contexts_idr);
  38        ocxl_fn_put(afu->fn);
  39        kfree(afu);
  40}
  41
  42void ocxl_afu_get(struct ocxl_afu *afu)
  43{
  44        kref_get(&afu->kref);
  45}
  46EXPORT_SYMBOL_GPL(ocxl_afu_get);
  47
  48void ocxl_afu_put(struct ocxl_afu *afu)
  49{
  50        kref_put(&afu->kref, free_afu);
  51}
  52EXPORT_SYMBOL_GPL(ocxl_afu_put);
  53
  54static int assign_afu_actag(struct ocxl_afu *afu)
  55{
  56        struct ocxl_fn *fn = afu->fn;
  57        int actag_count, actag_offset;
  58        struct pci_dev *pci_dev = to_pci_dev(fn->dev.parent);
  59
  60        /*
  61         * if there were not enough actags for the function, each afu
  62         * reduces its count as well
  63         */
  64        actag_count = afu->config.actag_supported *
  65                fn->actag_enabled / fn->actag_supported;
  66        actag_offset = ocxl_actag_afu_alloc(fn, actag_count);
  67        if (actag_offset < 0) {
  68                dev_err(&pci_dev->dev, "Can't allocate %d actags for AFU: %d\n",
  69                        actag_count, actag_offset);
  70                return actag_offset;
  71        }
  72        afu->actag_base = fn->actag_base + actag_offset;
  73        afu->actag_enabled = actag_count;
  74
  75        ocxl_config_set_afu_actag(pci_dev, afu->config.dvsec_afu_control_pos,
  76                                afu->actag_base, afu->actag_enabled);
  77        dev_dbg(&pci_dev->dev, "actag base=%d enabled=%d\n",
  78                afu->actag_base, afu->actag_enabled);
  79        return 0;
  80}
  81
  82static void reclaim_afu_actag(struct ocxl_afu *afu)
  83{
  84        struct ocxl_fn *fn = afu->fn;
  85        int start_offset, size;
  86
  87        start_offset = afu->actag_base - fn->actag_base;
  88        size = afu->actag_enabled;
  89        ocxl_actag_afu_free(afu->fn, start_offset, size);
  90}
  91
  92static int assign_afu_pasid(struct ocxl_afu *afu)
  93{
  94        struct ocxl_fn *fn = afu->fn;
  95        int pasid_count, pasid_offset;
  96        struct pci_dev *pci_dev = to_pci_dev(fn->dev.parent);
  97
  98        /*
  99         * We only support the case where the function configuration
 100         * requested enough PASIDs to cover all AFUs.
 101         */
 102        pasid_count = 1 << afu->config.pasid_supported_log;
 103        pasid_offset = ocxl_pasid_afu_alloc(fn, pasid_count);
 104        if (pasid_offset < 0) {
 105                dev_err(&pci_dev->dev, "Can't allocate %d PASIDs for AFU: %d\n",
 106                        pasid_count, pasid_offset);
 107                return pasid_offset;
 108        }
 109        afu->pasid_base = fn->pasid_base + pasid_offset;
 110        afu->pasid_count = 0;
 111        afu->pasid_max = pasid_count;
 112
 113        ocxl_config_set_afu_pasid(pci_dev, afu->config.dvsec_afu_control_pos,
 114                                afu->pasid_base,
 115                                afu->config.pasid_supported_log);
 116        dev_dbg(&pci_dev->dev, "PASID base=%d, enabled=%d\n",
 117                afu->pasid_base, pasid_count);
 118        return 0;
 119}
 120
 121static void reclaim_afu_pasid(struct ocxl_afu *afu)
 122{
 123        struct ocxl_fn *fn = afu->fn;
 124        int start_offset, size;
 125
 126        start_offset = afu->pasid_base - fn->pasid_base;
 127        size = 1 << afu->config.pasid_supported_log;
 128        ocxl_pasid_afu_free(afu->fn, start_offset, size);
 129}
 130
 131static int reserve_fn_bar(struct ocxl_fn *fn, int bar)
 132{
 133        struct pci_dev *dev = to_pci_dev(fn->dev.parent);
 134        int rc, idx;
 135
 136        if (bar != 0 && bar != 2 && bar != 4)
 137                return -EINVAL;
 138
 139        idx = bar >> 1;
 140        if (fn->bar_used[idx]++ == 0) {
 141                rc = pci_request_region(dev, bar, "ocxl");
 142                if (rc)
 143                        return rc;
 144        }
 145        return 0;
 146}
 147
 148static void release_fn_bar(struct ocxl_fn *fn, int bar)
 149{
 150        struct pci_dev *dev = to_pci_dev(fn->dev.parent);
 151        int idx;
 152
 153        if (bar != 0 && bar != 2 && bar != 4)
 154                return;
 155
 156        idx = bar >> 1;
 157        if (--fn->bar_used[idx] == 0)
 158                pci_release_region(dev, bar);
 159        WARN_ON(fn->bar_used[idx] < 0);
 160}
 161
 162static int map_mmio_areas(struct ocxl_afu *afu)
 163{
 164        int rc;
 165        struct pci_dev *pci_dev = to_pci_dev(afu->fn->dev.parent);
 166
 167        rc = reserve_fn_bar(afu->fn, afu->config.global_mmio_bar);
 168        if (rc)
 169                return rc;
 170
 171        rc = reserve_fn_bar(afu->fn, afu->config.pp_mmio_bar);
 172        if (rc) {
 173                release_fn_bar(afu->fn, afu->config.global_mmio_bar);
 174                return rc;
 175        }
 176
 177        afu->global_mmio_start =
 178                pci_resource_start(pci_dev, afu->config.global_mmio_bar) +
 179                afu->config.global_mmio_offset;
 180        afu->pp_mmio_start =
 181                pci_resource_start(pci_dev, afu->config.pp_mmio_bar) +
 182                afu->config.pp_mmio_offset;
 183
 184        afu->global_mmio_ptr = ioremap(afu->global_mmio_start,
 185                                afu->config.global_mmio_size);
 186        if (!afu->global_mmio_ptr) {
 187                release_fn_bar(afu->fn, afu->config.pp_mmio_bar);
 188                release_fn_bar(afu->fn, afu->config.global_mmio_bar);
 189                dev_err(&pci_dev->dev, "Error mapping global mmio area\n");
 190                return -ENOMEM;
 191        }
 192
 193        /*
 194         * Leave an empty page between the per-process mmio area and
 195         * the AFU interrupt mappings
 196         */
 197        afu->irq_base_offset = afu->config.pp_mmio_stride + PAGE_SIZE;
 198        return 0;
 199}
 200
 201static void unmap_mmio_areas(struct ocxl_afu *afu)
 202{
 203        if (afu->global_mmio_ptr) {
 204                iounmap(afu->global_mmio_ptr);
 205                afu->global_mmio_ptr = NULL;
 206        }
 207        afu->global_mmio_start = 0;
 208        afu->pp_mmio_start = 0;
 209        release_fn_bar(afu->fn, afu->config.pp_mmio_bar);
 210        release_fn_bar(afu->fn, afu->config.global_mmio_bar);
 211}
 212
 213static int configure_afu(struct ocxl_afu *afu, u8 afu_idx, struct pci_dev *dev)
 214{
 215        int rc;
 216
 217        rc = ocxl_config_read_afu(dev, &afu->fn->config, &afu->config, afu_idx);
 218        if (rc)
 219                return rc;
 220
 221        rc = assign_afu_actag(afu);
 222        if (rc)
 223                return rc;
 224
 225        rc = assign_afu_pasid(afu);
 226        if (rc)
 227                goto err_free_actag;
 228
 229        rc = map_mmio_areas(afu);
 230        if (rc)
 231                goto err_free_pasid;
 232
 233        return 0;
 234
 235err_free_pasid:
 236        reclaim_afu_pasid(afu);
 237err_free_actag:
 238        reclaim_afu_actag(afu);
 239        return rc;
 240}
 241
 242static void deconfigure_afu(struct ocxl_afu *afu)
 243{
 244        unmap_mmio_areas(afu);
 245        reclaim_afu_pasid(afu);
 246        reclaim_afu_actag(afu);
 247}
 248
 249static int activate_afu(struct pci_dev *dev, struct ocxl_afu *afu)
 250{
 251        ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 1);
 252
 253        return 0;
 254}
 255
 256static void deactivate_afu(struct ocxl_afu *afu)
 257{
 258        struct pci_dev *dev = to_pci_dev(afu->fn->dev.parent);
 259
 260        ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 0);
 261}
 262
 263static int init_afu(struct pci_dev *dev, struct ocxl_fn *fn, u8 afu_idx)
 264{
 265        int rc;
 266        struct ocxl_afu *afu;
 267
 268        afu = alloc_afu(fn);
 269        if (!afu)
 270                return -ENOMEM;
 271
 272        rc = configure_afu(afu, afu_idx, dev);
 273        if (rc) {
 274                ocxl_afu_put(afu);
 275                return rc;
 276        }
 277
 278        rc = activate_afu(dev, afu);
 279        if (rc) {
 280                deconfigure_afu(afu);
 281                ocxl_afu_put(afu);
 282                return rc;
 283        }
 284
 285        list_add_tail(&afu->list, &fn->afu_list);
 286
 287        return 0;
 288}
 289
 290static void remove_afu(struct ocxl_afu *afu)
 291{
 292        list_del(&afu->list);
 293        ocxl_context_detach_all(afu);
 294        deactivate_afu(afu);
 295        deconfigure_afu(afu);
 296        ocxl_afu_put(afu); // matches the implicit get in alloc_afu
 297}
 298
 299static struct ocxl_fn *alloc_function(void)
 300{
 301        struct ocxl_fn *fn;
 302
 303        fn = kzalloc(sizeof(struct ocxl_fn), GFP_KERNEL);
 304        if (!fn)
 305                return NULL;
 306
 307        INIT_LIST_HEAD(&fn->afu_list);
 308        INIT_LIST_HEAD(&fn->pasid_list);
 309        INIT_LIST_HEAD(&fn->actag_list);
 310
 311        return fn;
 312}
 313
 314static void free_function(struct ocxl_fn *fn)
 315{
 316        WARN_ON(!list_empty(&fn->afu_list));
 317        WARN_ON(!list_empty(&fn->pasid_list));
 318        kfree(fn);
 319}
 320
 321static void free_function_dev(struct device *dev)
 322{
 323        struct ocxl_fn *fn = container_of(dev, struct ocxl_fn, dev);
 324
 325        free_function(fn);
 326}
 327
 328static int set_function_device(struct ocxl_fn *fn, struct pci_dev *dev)
 329{
 330        fn->dev.parent = &dev->dev;
 331        fn->dev.release = free_function_dev;
 332        return dev_set_name(&fn->dev, "ocxlfn.%s", dev_name(&dev->dev));
 333}
 334
 335static int assign_function_actag(struct ocxl_fn *fn)
 336{
 337        struct pci_dev *dev = to_pci_dev(fn->dev.parent);
 338        u16 base, enabled, supported;
 339        int rc;
 340
 341        rc = ocxl_config_get_actag_info(dev, &base, &enabled, &supported);
 342        if (rc)
 343                return rc;
 344
 345        fn->actag_base = base;
 346        fn->actag_enabled = enabled;
 347        fn->actag_supported = supported;
 348
 349        ocxl_config_set_actag(dev, fn->config.dvsec_function_pos,
 350                        fn->actag_base, fn->actag_enabled);
 351        dev_dbg(&fn->dev, "actag range starting at %d, enabled %d\n",
 352                fn->actag_base, fn->actag_enabled);
 353        return 0;
 354}
 355
 356static int set_function_pasid(struct ocxl_fn *fn)
 357{
 358        struct pci_dev *dev = to_pci_dev(fn->dev.parent);
 359        int rc, desired_count, max_count;
 360
 361        /* A function may not require any PASID */
 362        if (fn->config.max_pasid_log < 0)
 363                return 0;
 364
 365        rc = ocxl_config_get_pasid_info(dev, &max_count);
 366        if (rc)
 367                return rc;
 368
 369        desired_count = 1 << fn->config.max_pasid_log;
 370
 371        if (desired_count > max_count) {
 372                dev_err(&fn->dev,
 373                        "Function requires more PASIDs than is available (%d vs. %d)\n",
 374                        desired_count, max_count);
 375                return -ENOSPC;
 376        }
 377
 378        fn->pasid_base = 0;
 379        return 0;
 380}
 381
 382static int configure_function(struct ocxl_fn *fn, struct pci_dev *dev)
 383{
 384        int rc;
 385
 386        rc = pci_enable_device(dev);
 387        if (rc) {
 388                dev_err(&dev->dev, "pci_enable_device failed: %d\n", rc);
 389                return rc;
 390        }
 391
 392        /*
 393         * Once it has been confirmed to work on our hardware, we
 394         * should reset the function, to force the adapter to restart
 395         * from scratch.
 396         * A function reset would also reset all its AFUs.
 397         *
 398         * Some hints for implementation:
 399         *
 400         * - there's not status bit to know when the reset is done. We
 401         *   should try reading the config space to know when it's
 402         *   done.
 403         * - probably something like:
 404         *      Reset
 405         *      wait 100ms
 406         *      issue config read
 407         *      allow device up to 1 sec to return success on config
 408         *      read before declaring it broken
 409         *
 410         * Some shared logic on the card (CFG, TLX) won't be reset, so
 411         * there's no guarantee that it will be enough.
 412         */
 413        rc = ocxl_config_read_function(dev, &fn->config);
 414        if (rc)
 415                return rc;
 416
 417        rc = set_function_device(fn, dev);
 418        if (rc)
 419                return rc;
 420
 421        rc = assign_function_actag(fn);
 422        if (rc)
 423                return rc;
 424
 425        rc = set_function_pasid(fn);
 426        if (rc)
 427                return rc;
 428
 429        rc = ocxl_link_setup(dev, 0, &fn->link);
 430        if (rc)
 431                return rc;
 432
 433        rc = ocxl_config_set_TL(dev, fn->config.dvsec_tl_pos);
 434        if (rc) {
 435                ocxl_link_release(dev, fn->link);
 436                return rc;
 437        }
 438        return 0;
 439}
 440
 441static void deconfigure_function(struct ocxl_fn *fn)
 442{
 443        struct pci_dev *dev = to_pci_dev(fn->dev.parent);
 444
 445        ocxl_link_release(dev, fn->link);
 446        pci_disable_device(dev);
 447}
 448
 449static struct ocxl_fn *init_function(struct pci_dev *dev)
 450{
 451        struct ocxl_fn *fn;
 452        int rc;
 453
 454        fn = alloc_function();
 455        if (!fn)
 456                return ERR_PTR(-ENOMEM);
 457
 458        rc = configure_function(fn, dev);
 459        if (rc) {
 460                free_function(fn);
 461                return ERR_PTR(rc);
 462        }
 463
 464        rc = device_register(&fn->dev);
 465        if (rc) {
 466                deconfigure_function(fn);
 467                put_device(&fn->dev);
 468                return ERR_PTR(rc);
 469        }
 470        return fn;
 471}
 472
 473// Device detection & initialisation
 474
 475struct ocxl_fn *ocxl_function_open(struct pci_dev *dev)
 476{
 477        int rc, afu_count = 0;
 478        u8 afu;
 479        struct ocxl_fn *fn;
 480
 481        if (!radix_enabled()) {
 482                dev_err(&dev->dev, "Unsupported memory model (hash)\n");
 483                return ERR_PTR(-ENODEV);
 484        }
 485
 486        fn = init_function(dev);
 487        if (IS_ERR(fn)) {
 488                dev_err(&dev->dev, "function init failed: %li\n",
 489                        PTR_ERR(fn));
 490                return fn;
 491        }
 492
 493        for (afu = 0; afu <= fn->config.max_afu_index; afu++) {
 494                rc = ocxl_config_check_afu_index(dev, &fn->config, afu);
 495                if (rc > 0) {
 496                        rc = init_afu(dev, fn, afu);
 497                        if (rc) {
 498                                dev_err(&dev->dev,
 499                                        "Can't initialize AFU index %d\n", afu);
 500                                continue;
 501                        }
 502                        afu_count++;
 503                }
 504        }
 505        dev_info(&dev->dev, "%d AFU(s) configured\n", afu_count);
 506        return fn;
 507}
 508EXPORT_SYMBOL_GPL(ocxl_function_open);
 509
 510struct list_head *ocxl_function_afu_list(struct ocxl_fn *fn)
 511{
 512        return &fn->afu_list;
 513}
 514EXPORT_SYMBOL_GPL(ocxl_function_afu_list);
 515
 516struct ocxl_afu *ocxl_function_fetch_afu(struct ocxl_fn *fn, u8 afu_idx)
 517{
 518        struct ocxl_afu *afu;
 519
 520        list_for_each_entry(afu, &fn->afu_list, list) {
 521                if (afu->config.idx == afu_idx)
 522                        return afu;
 523        }
 524
 525        return NULL;
 526}
 527EXPORT_SYMBOL_GPL(ocxl_function_fetch_afu);
 528
 529const struct ocxl_fn_config *ocxl_function_config(struct ocxl_fn *fn)
 530{
 531        return &fn->config;
 532}
 533EXPORT_SYMBOL_GPL(ocxl_function_config);
 534
 535void ocxl_function_close(struct ocxl_fn *fn)
 536{
 537        struct ocxl_afu *afu, *tmp;
 538
 539        list_for_each_entry_safe(afu, tmp, &fn->afu_list, list) {
 540                remove_afu(afu);
 541        }
 542
 543        deconfigure_function(fn);
 544        device_unregister(&fn->dev);
 545}
 546EXPORT_SYMBOL_GPL(ocxl_function_close);
 547
 548// AFU Metadata
 549
 550struct ocxl_afu_config *ocxl_afu_config(struct ocxl_afu *afu)
 551{
 552        return &afu->config;
 553}
 554EXPORT_SYMBOL_GPL(ocxl_afu_config);
 555
 556void ocxl_afu_set_private(struct ocxl_afu *afu, void *private)
 557{
 558        afu->private = private;
 559}
 560EXPORT_SYMBOL_GPL(ocxl_afu_set_private);
 561
 562void *ocxl_afu_get_private(struct ocxl_afu *afu)
 563{
 564        if (afu)
 565                return afu->private;
 566
 567        return NULL;
 568}
 569EXPORT_SYMBOL_GPL(ocxl_afu_get_private);
 570