linux/drivers/pci/endpoint/pci-ep-cfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * configfs to configure the PCI endpoint
   4 *
   5 * Copyright (C) 2017 Texas Instruments
   6 * Author: Kishon Vijay Abraham I <kishon@ti.com>
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/idr.h>
  11#include <linux/slab.h>
  12
  13#include <linux/pci-epc.h>
  14#include <linux/pci-epf.h>
  15#include <linux/pci-ep-cfs.h>
  16
  17static DEFINE_IDR(functions_idr);
  18static DEFINE_MUTEX(functions_mutex);
  19static struct config_group *functions_group;
  20static struct config_group *controllers_group;
  21
  22struct pci_epf_group {
  23        struct config_group group;
  24        struct pci_epf *epf;
  25        int index;
  26};
  27
  28struct pci_epc_group {
  29        struct config_group group;
  30        struct pci_epc *epc;
  31        bool start;
  32};
  33
  34static inline struct pci_epf_group *to_pci_epf_group(struct config_item *item)
  35{
  36        return container_of(to_config_group(item), struct pci_epf_group, group);
  37}
  38
  39static inline struct pci_epc_group *to_pci_epc_group(struct config_item *item)
  40{
  41        return container_of(to_config_group(item), struct pci_epc_group, group);
  42}
  43
  44static ssize_t pci_epc_start_store(struct config_item *item, const char *page,
  45                                   size_t len)
  46{
  47        int ret;
  48        bool start;
  49        struct pci_epc *epc;
  50        struct pci_epc_group *epc_group = to_pci_epc_group(item);
  51
  52        epc = epc_group->epc;
  53
  54        ret = kstrtobool(page, &start);
  55        if (ret)
  56                return ret;
  57
  58        if (!start) {
  59                pci_epc_stop(epc);
  60                epc_group->start = 0;
  61                return len;
  62        }
  63
  64        ret = pci_epc_start(epc);
  65        if (ret) {
  66                dev_err(&epc->dev, "failed to start endpoint controller\n");
  67                return -EINVAL;
  68        }
  69
  70        epc_group->start = start;
  71
  72        return len;
  73}
  74
  75static ssize_t pci_epc_start_show(struct config_item *item, char *page)
  76{
  77        return sprintf(page, "%d\n",
  78                       to_pci_epc_group(item)->start);
  79}
  80
  81CONFIGFS_ATTR(pci_epc_, start);
  82
  83static struct configfs_attribute *pci_epc_attrs[] = {
  84        &pci_epc_attr_start,
  85        NULL,
  86};
  87
  88static int pci_epc_epf_link(struct config_item *epc_item,
  89                            struct config_item *epf_item)
  90{
  91        int ret;
  92        struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);
  93        struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
  94        struct pci_epc *epc = epc_group->epc;
  95        struct pci_epf *epf = epf_group->epf;
  96
  97        ret = pci_epc_add_epf(epc, epf);
  98        if (ret)
  99                return ret;
 100
 101        ret = pci_epf_bind(epf);
 102        if (ret) {
 103                pci_epc_remove_epf(epc, epf);
 104                return ret;
 105        }
 106
 107        return 0;
 108}
 109
 110static void pci_epc_epf_unlink(struct config_item *epc_item,
 111                               struct config_item *epf_item)
 112{
 113        struct pci_epc *epc;
 114        struct pci_epf *epf;
 115        struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);
 116        struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
 117
 118        WARN_ON_ONCE(epc_group->start);
 119
 120        epc = epc_group->epc;
 121        epf = epf_group->epf;
 122        pci_epf_unbind(epf);
 123        pci_epc_remove_epf(epc, epf);
 124}
 125
 126static struct configfs_item_operations pci_epc_item_ops = {
 127        .allow_link     = pci_epc_epf_link,
 128        .drop_link      = pci_epc_epf_unlink,
 129};
 130
 131static const struct config_item_type pci_epc_type = {
 132        .ct_item_ops    = &pci_epc_item_ops,
 133        .ct_attrs       = pci_epc_attrs,
 134        .ct_owner       = THIS_MODULE,
 135};
 136
 137struct config_group *pci_ep_cfs_add_epc_group(const char *name)
 138{
 139        int ret;
 140        struct pci_epc *epc;
 141        struct config_group *group;
 142        struct pci_epc_group *epc_group;
 143
 144        epc_group = kzalloc(sizeof(*epc_group), GFP_KERNEL);
 145        if (!epc_group) {
 146                ret = -ENOMEM;
 147                goto err;
 148        }
 149
 150        group = &epc_group->group;
 151
 152        config_group_init_type_name(group, name, &pci_epc_type);
 153        ret = configfs_register_group(controllers_group, group);
 154        if (ret) {
 155                pr_err("failed to register configfs group for %s\n", name);
 156                goto err_register_group;
 157        }
 158
 159        epc = pci_epc_get(name);
 160        if (IS_ERR(epc)) {
 161                ret = PTR_ERR(epc);
 162                goto err_epc_get;
 163        }
 164
 165        epc_group->epc = epc;
 166
 167        return group;
 168
 169err_epc_get:
 170        configfs_unregister_group(group);
 171
 172err_register_group:
 173        kfree(epc_group);
 174
 175err:
 176        return ERR_PTR(ret);
 177}
 178EXPORT_SYMBOL(pci_ep_cfs_add_epc_group);
 179
 180void pci_ep_cfs_remove_epc_group(struct config_group *group)
 181{
 182        struct pci_epc_group *epc_group;
 183
 184        if (!group)
 185                return;
 186
 187        epc_group = container_of(group, struct pci_epc_group, group);
 188        pci_epc_put(epc_group->epc);
 189        configfs_unregister_group(&epc_group->group);
 190        kfree(epc_group);
 191}
 192EXPORT_SYMBOL(pci_ep_cfs_remove_epc_group);
 193
 194#define PCI_EPF_HEADER_R(_name)                                                \
 195static ssize_t pci_epf_##_name##_show(struct config_item *item, char *page)    \
 196{                                                                              \
 197        struct pci_epf *epf = to_pci_epf_group(item)->epf;                     \
 198        if (WARN_ON_ONCE(!epf->header))                                        \
 199                return -EINVAL;                                                \
 200        return sprintf(page, "0x%04x\n", epf->header->_name);                  \
 201}
 202
 203#define PCI_EPF_HEADER_W_u32(_name)                                            \
 204static ssize_t pci_epf_##_name##_store(struct config_item *item,               \
 205                                       const char *page, size_t len)           \
 206{                                                                              \
 207        u32 val;                                                               \
 208        int ret;                                                               \
 209        struct pci_epf *epf = to_pci_epf_group(item)->epf;                     \
 210        if (WARN_ON_ONCE(!epf->header))                                        \
 211                return -EINVAL;                                                \
 212        ret = kstrtou32(page, 0, &val);                                        \
 213        if (ret)                                                               \
 214                return ret;                                                    \
 215        epf->header->_name = val;                                              \
 216        return len;                                                            \
 217}
 218
 219#define PCI_EPF_HEADER_W_u16(_name)                                            \
 220static ssize_t pci_epf_##_name##_store(struct config_item *item,               \
 221                                       const char *page, size_t len)           \
 222{                                                                              \
 223        u16 val;                                                               \
 224        int ret;                                                               \
 225        struct pci_epf *epf = to_pci_epf_group(item)->epf;                     \
 226        if (WARN_ON_ONCE(!epf->header))                                        \
 227                return -EINVAL;                                                \
 228        ret = kstrtou16(page, 0, &val);                                        \
 229        if (ret)                                                               \
 230                return ret;                                                    \
 231        epf->header->_name = val;                                              \
 232        return len;                                                            \
 233}
 234
 235#define PCI_EPF_HEADER_W_u8(_name)                                             \
 236static ssize_t pci_epf_##_name##_store(struct config_item *item,               \
 237                                       const char *page, size_t len)           \
 238{                                                                              \
 239        u8 val;                                                                \
 240        int ret;                                                               \
 241        struct pci_epf *epf = to_pci_epf_group(item)->epf;                     \
 242        if (WARN_ON_ONCE(!epf->header))                                        \
 243                return -EINVAL;                                                \
 244        ret = kstrtou8(page, 0, &val);                                         \
 245        if (ret)                                                               \
 246                return ret;                                                    \
 247        epf->header->_name = val;                                              \
 248        return len;                                                            \
 249}
 250
 251static ssize_t pci_epf_msi_interrupts_store(struct config_item *item,
 252                                            const char *page, size_t len)
 253{
 254        u8 val;
 255        int ret;
 256
 257        ret = kstrtou8(page, 0, &val);
 258        if (ret)
 259                return ret;
 260
 261        to_pci_epf_group(item)->epf->msi_interrupts = val;
 262
 263        return len;
 264}
 265
 266static ssize_t pci_epf_msi_interrupts_show(struct config_item *item,
 267                                           char *page)
 268{
 269        return sprintf(page, "%d\n",
 270                       to_pci_epf_group(item)->epf->msi_interrupts);
 271}
 272
 273static ssize_t pci_epf_msix_interrupts_store(struct config_item *item,
 274                                             const char *page, size_t len)
 275{
 276        u16 val;
 277        int ret;
 278
 279        ret = kstrtou16(page, 0, &val);
 280        if (ret)
 281                return ret;
 282
 283        to_pci_epf_group(item)->epf->msix_interrupts = val;
 284
 285        return len;
 286}
 287
 288static ssize_t pci_epf_msix_interrupts_show(struct config_item *item,
 289                                            char *page)
 290{
 291        return sprintf(page, "%d\n",
 292                       to_pci_epf_group(item)->epf->msix_interrupts);
 293}
 294
 295PCI_EPF_HEADER_R(vendorid)
 296PCI_EPF_HEADER_W_u16(vendorid)
 297
 298PCI_EPF_HEADER_R(deviceid)
 299PCI_EPF_HEADER_W_u16(deviceid)
 300
 301PCI_EPF_HEADER_R(revid)
 302PCI_EPF_HEADER_W_u8(revid)
 303
 304PCI_EPF_HEADER_R(progif_code)
 305PCI_EPF_HEADER_W_u8(progif_code)
 306
 307PCI_EPF_HEADER_R(subclass_code)
 308PCI_EPF_HEADER_W_u8(subclass_code)
 309
 310PCI_EPF_HEADER_R(baseclass_code)
 311PCI_EPF_HEADER_W_u8(baseclass_code)
 312
 313PCI_EPF_HEADER_R(cache_line_size)
 314PCI_EPF_HEADER_W_u8(cache_line_size)
 315
 316PCI_EPF_HEADER_R(subsys_vendor_id)
 317PCI_EPF_HEADER_W_u16(subsys_vendor_id)
 318
 319PCI_EPF_HEADER_R(subsys_id)
 320PCI_EPF_HEADER_W_u16(subsys_id)
 321
 322PCI_EPF_HEADER_R(interrupt_pin)
 323PCI_EPF_HEADER_W_u8(interrupt_pin)
 324
 325CONFIGFS_ATTR(pci_epf_, vendorid);
 326CONFIGFS_ATTR(pci_epf_, deviceid);
 327CONFIGFS_ATTR(pci_epf_, revid);
 328CONFIGFS_ATTR(pci_epf_, progif_code);
 329CONFIGFS_ATTR(pci_epf_, subclass_code);
 330CONFIGFS_ATTR(pci_epf_, baseclass_code);
 331CONFIGFS_ATTR(pci_epf_, cache_line_size);
 332CONFIGFS_ATTR(pci_epf_, subsys_vendor_id);
 333CONFIGFS_ATTR(pci_epf_, subsys_id);
 334CONFIGFS_ATTR(pci_epf_, interrupt_pin);
 335CONFIGFS_ATTR(pci_epf_, msi_interrupts);
 336CONFIGFS_ATTR(pci_epf_, msix_interrupts);
 337
 338static struct configfs_attribute *pci_epf_attrs[] = {
 339        &pci_epf_attr_vendorid,
 340        &pci_epf_attr_deviceid,
 341        &pci_epf_attr_revid,
 342        &pci_epf_attr_progif_code,
 343        &pci_epf_attr_subclass_code,
 344        &pci_epf_attr_baseclass_code,
 345        &pci_epf_attr_cache_line_size,
 346        &pci_epf_attr_subsys_vendor_id,
 347        &pci_epf_attr_subsys_id,
 348        &pci_epf_attr_interrupt_pin,
 349        &pci_epf_attr_msi_interrupts,
 350        &pci_epf_attr_msix_interrupts,
 351        NULL,
 352};
 353
 354static void pci_epf_release(struct config_item *item)
 355{
 356        struct pci_epf_group *epf_group = to_pci_epf_group(item);
 357
 358        mutex_lock(&functions_mutex);
 359        idr_remove(&functions_idr, epf_group->index);
 360        mutex_unlock(&functions_mutex);
 361        pci_epf_destroy(epf_group->epf);
 362        kfree(epf_group);
 363}
 364
 365static struct configfs_item_operations pci_epf_ops = {
 366        .release                = pci_epf_release,
 367};
 368
 369static const struct config_item_type pci_epf_type = {
 370        .ct_item_ops    = &pci_epf_ops,
 371        .ct_attrs       = pci_epf_attrs,
 372        .ct_owner       = THIS_MODULE,
 373};
 374
 375static struct config_group *pci_epf_make(struct config_group *group,
 376                                         const char *name)
 377{
 378        struct pci_epf_group *epf_group;
 379        struct pci_epf *epf;
 380        char *epf_name;
 381        int index, err;
 382
 383        epf_group = kzalloc(sizeof(*epf_group), GFP_KERNEL);
 384        if (!epf_group)
 385                return ERR_PTR(-ENOMEM);
 386
 387        mutex_lock(&functions_mutex);
 388        index = idr_alloc(&functions_idr, epf_group, 0, 0, GFP_KERNEL);
 389        mutex_unlock(&functions_mutex);
 390        if (index < 0) {
 391                err = index;
 392                goto free_group;
 393        }
 394
 395        epf_group->index = index;
 396
 397        config_group_init_type_name(&epf_group->group, name, &pci_epf_type);
 398
 399        epf_name = kasprintf(GFP_KERNEL, "%s.%d",
 400                             group->cg_item.ci_name, epf_group->index);
 401        if (!epf_name) {
 402                err = -ENOMEM;
 403                goto remove_idr;
 404        }
 405
 406        epf = pci_epf_create(epf_name);
 407        if (IS_ERR(epf)) {
 408                pr_err("failed to create endpoint function device\n");
 409                err = -EINVAL;
 410                goto free_name;
 411        }
 412
 413        epf_group->epf = epf;
 414
 415        kfree(epf_name);
 416
 417        return &epf_group->group;
 418
 419free_name:
 420        kfree(epf_name);
 421
 422remove_idr:
 423        mutex_lock(&functions_mutex);
 424        idr_remove(&functions_idr, epf_group->index);
 425        mutex_unlock(&functions_mutex);
 426
 427free_group:
 428        kfree(epf_group);
 429
 430        return ERR_PTR(err);
 431}
 432
 433static void pci_epf_drop(struct config_group *group, struct config_item *item)
 434{
 435        config_item_put(item);
 436}
 437
 438static struct configfs_group_operations pci_epf_group_ops = {
 439        .make_group     = &pci_epf_make,
 440        .drop_item      = &pci_epf_drop,
 441};
 442
 443static const struct config_item_type pci_epf_group_type = {
 444        .ct_group_ops   = &pci_epf_group_ops,
 445        .ct_owner       = THIS_MODULE,
 446};
 447
 448struct config_group *pci_ep_cfs_add_epf_group(const char *name)
 449{
 450        struct config_group *group;
 451
 452        group = configfs_register_default_group(functions_group, name,
 453                                                &pci_epf_group_type);
 454        if (IS_ERR(group))
 455                pr_err("failed to register configfs group for %s function\n",
 456                       name);
 457
 458        return group;
 459}
 460EXPORT_SYMBOL(pci_ep_cfs_add_epf_group);
 461
 462void pci_ep_cfs_remove_epf_group(struct config_group *group)
 463{
 464        if (IS_ERR_OR_NULL(group))
 465                return;
 466
 467        configfs_unregister_default_group(group);
 468}
 469EXPORT_SYMBOL(pci_ep_cfs_remove_epf_group);
 470
 471static const struct config_item_type pci_functions_type = {
 472        .ct_owner       = THIS_MODULE,
 473};
 474
 475static const struct config_item_type pci_controllers_type = {
 476        .ct_owner       = THIS_MODULE,
 477};
 478
 479static const struct config_item_type pci_ep_type = {
 480        .ct_owner       = THIS_MODULE,
 481};
 482
 483static struct configfs_subsystem pci_ep_cfs_subsys = {
 484        .su_group = {
 485                .cg_item = {
 486                        .ci_namebuf = "pci_ep",
 487                        .ci_type = &pci_ep_type,
 488                },
 489        },
 490        .su_mutex = __MUTEX_INITIALIZER(pci_ep_cfs_subsys.su_mutex),
 491};
 492
 493static int __init pci_ep_cfs_init(void)
 494{
 495        int ret;
 496        struct config_group *root = &pci_ep_cfs_subsys.su_group;
 497
 498        config_group_init(root);
 499
 500        ret = configfs_register_subsystem(&pci_ep_cfs_subsys);
 501        if (ret) {
 502                pr_err("Error %d while registering subsystem %s\n",
 503                       ret, root->cg_item.ci_namebuf);
 504                goto err;
 505        }
 506
 507        functions_group = configfs_register_default_group(root, "functions",
 508                                                          &pci_functions_type);
 509        if (IS_ERR(functions_group)) {
 510                ret = PTR_ERR(functions_group);
 511                pr_err("Error %d while registering functions group\n",
 512                       ret);
 513                goto err_functions_group;
 514        }
 515
 516        controllers_group =
 517                configfs_register_default_group(root, "controllers",
 518                                                &pci_controllers_type);
 519        if (IS_ERR(controllers_group)) {
 520                ret = PTR_ERR(controllers_group);
 521                pr_err("Error %d while registering controllers group\n",
 522                       ret);
 523                goto err_controllers_group;
 524        }
 525
 526        return 0;
 527
 528err_controllers_group:
 529        configfs_unregister_default_group(functions_group);
 530
 531err_functions_group:
 532        configfs_unregister_subsystem(&pci_ep_cfs_subsys);
 533
 534err:
 535        return ret;
 536}
 537module_init(pci_ep_cfs_init);
 538
 539static void __exit pci_ep_cfs_exit(void)
 540{
 541        configfs_unregister_default_group(controllers_group);
 542        configfs_unregister_default_group(functions_group);
 543        configfs_unregister_subsystem(&pci_ep_cfs_subsys);
 544}
 545module_exit(pci_ep_cfs_exit);
 546
 547MODULE_DESCRIPTION("PCI EP CONFIGFS");
 548MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
 549MODULE_LICENSE("GPL v2");
 550