776 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * configfs to configure the PCI endpoint4 *5 * Copyright (C) 2017 Texas Instruments6 * 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 config_group primary_epc_group;25 struct config_group secondary_epc_group;26 struct delayed_work cfs_work;27 struct pci_epf *epf;28 int index;29};30 31struct pci_epc_group {32 struct config_group group;33 struct pci_epc *epc;34 bool start;35};36 37static inline struct pci_epf_group *to_pci_epf_group(struct config_item *item)38{39 return container_of(to_config_group(item), struct pci_epf_group, group);40}41 42static inline struct pci_epc_group *to_pci_epc_group(struct config_item *item)43{44 return container_of(to_config_group(item), struct pci_epc_group, group);45}46 47static int pci_secondary_epc_epf_link(struct config_item *epf_item,48 struct config_item *epc_item)49{50 int ret;51 struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);52 struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);53 struct pci_epc *epc = epc_group->epc;54 struct pci_epf *epf = epf_group->epf;55 56 ret = pci_epc_add_epf(epc, epf, SECONDARY_INTERFACE);57 if (ret)58 return ret;59 60 ret = pci_epf_bind(epf);61 if (ret) {62 pci_epc_remove_epf(epc, epf, SECONDARY_INTERFACE);63 return ret;64 }65 66 /* Send any pending EPC initialization complete to the EPF driver */67 pci_epc_notify_pending_init(epc, epf);68 69 return 0;70}71 72static void pci_secondary_epc_epf_unlink(struct config_item *epc_item,73 struct config_item *epf_item)74{75 struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);76 struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);77 struct pci_epc *epc;78 struct pci_epf *epf;79 80 WARN_ON_ONCE(epc_group->start);81 82 epc = epc_group->epc;83 epf = epf_group->epf;84 pci_epf_unbind(epf);85 pci_epc_remove_epf(epc, epf, SECONDARY_INTERFACE);86}87 88static struct configfs_item_operations pci_secondary_epc_item_ops = {89 .allow_link = pci_secondary_epc_epf_link,90 .drop_link = pci_secondary_epc_epf_unlink,91};92 93static const struct config_item_type pci_secondary_epc_type = {94 .ct_item_ops = &pci_secondary_epc_item_ops,95 .ct_owner = THIS_MODULE,96};97 98static struct config_group99*pci_ep_cfs_add_secondary_group(struct pci_epf_group *epf_group)100{101 struct config_group *secondary_epc_group;102 103 secondary_epc_group = &epf_group->secondary_epc_group;104 config_group_init_type_name(secondary_epc_group, "secondary",105 &pci_secondary_epc_type);106 configfs_register_group(&epf_group->group, secondary_epc_group);107 108 return secondary_epc_group;109}110 111static int pci_primary_epc_epf_link(struct config_item *epf_item,112 struct config_item *epc_item)113{114 int ret;115 struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);116 struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);117 struct pci_epc *epc = epc_group->epc;118 struct pci_epf *epf = epf_group->epf;119 120 ret = pci_epc_add_epf(epc, epf, PRIMARY_INTERFACE);121 if (ret)122 return ret;123 124 ret = pci_epf_bind(epf);125 if (ret) {126 pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);127 return ret;128 }129 130 /* Send any pending EPC initialization complete to the EPF driver */131 pci_epc_notify_pending_init(epc, epf);132 133 return 0;134}135 136static void pci_primary_epc_epf_unlink(struct config_item *epc_item,137 struct config_item *epf_item)138{139 struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);140 struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);141 struct pci_epc *epc;142 struct pci_epf *epf;143 144 WARN_ON_ONCE(epc_group->start);145 146 epc = epc_group->epc;147 epf = epf_group->epf;148 pci_epf_unbind(epf);149 pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);150}151 152static struct configfs_item_operations pci_primary_epc_item_ops = {153 .allow_link = pci_primary_epc_epf_link,154 .drop_link = pci_primary_epc_epf_unlink,155};156 157static const struct config_item_type pci_primary_epc_type = {158 .ct_item_ops = &pci_primary_epc_item_ops,159 .ct_owner = THIS_MODULE,160};161 162static struct config_group163*pci_ep_cfs_add_primary_group(struct pci_epf_group *epf_group)164{165 struct config_group *primary_epc_group = &epf_group->primary_epc_group;166 167 config_group_init_type_name(primary_epc_group, "primary",168 &pci_primary_epc_type);169 configfs_register_group(&epf_group->group, primary_epc_group);170 171 return primary_epc_group;172}173 174static ssize_t pci_epc_start_store(struct config_item *item, const char *page,175 size_t len)176{177 int ret;178 bool start;179 struct pci_epc *epc;180 struct pci_epc_group *epc_group = to_pci_epc_group(item);181 182 epc = epc_group->epc;183 184 if (kstrtobool(page, &start) < 0)185 return -EINVAL;186 187 if (start == epc_group->start)188 return -EALREADY;189 190 if (!start) {191 pci_epc_stop(epc);192 epc_group->start = 0;193 return len;194 }195 196 ret = pci_epc_start(epc);197 if (ret) {198 dev_err(&epc->dev, "failed to start endpoint controller\n");199 return -EINVAL;200 }201 202 epc_group->start = start;203 204 return len;205}206 207static ssize_t pci_epc_start_show(struct config_item *item, char *page)208{209 return sysfs_emit(page, "%d\n", to_pci_epc_group(item)->start);210}211 212CONFIGFS_ATTR(pci_epc_, start);213 214static struct configfs_attribute *pci_epc_attrs[] = {215 &pci_epc_attr_start,216 NULL,217};218 219static int pci_epc_epf_link(struct config_item *epc_item,220 struct config_item *epf_item)221{222 int ret;223 struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);224 struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);225 struct pci_epc *epc = epc_group->epc;226 struct pci_epf *epf = epf_group->epf;227 228 ret = pci_epc_add_epf(epc, epf, PRIMARY_INTERFACE);229 if (ret)230 return ret;231 232 ret = pci_epf_bind(epf);233 if (ret) {234 pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);235 return ret;236 }237 238 /* Send any pending EPC initialization complete to the EPF driver */239 pci_epc_notify_pending_init(epc, epf);240 241 return 0;242}243 244static void pci_epc_epf_unlink(struct config_item *epc_item,245 struct config_item *epf_item)246{247 struct pci_epc *epc;248 struct pci_epf *epf;249 struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);250 struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);251 252 WARN_ON_ONCE(epc_group->start);253 254 epc = epc_group->epc;255 epf = epf_group->epf;256 pci_epf_unbind(epf);257 pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);258}259 260static struct configfs_item_operations pci_epc_item_ops = {261 .allow_link = pci_epc_epf_link,262 .drop_link = pci_epc_epf_unlink,263};264 265static const struct config_item_type pci_epc_type = {266 .ct_item_ops = &pci_epc_item_ops,267 .ct_attrs = pci_epc_attrs,268 .ct_owner = THIS_MODULE,269};270 271struct config_group *pci_ep_cfs_add_epc_group(const char *name)272{273 int ret;274 struct pci_epc *epc;275 struct config_group *group;276 struct pci_epc_group *epc_group;277 278 epc_group = kzalloc(sizeof(*epc_group), GFP_KERNEL);279 if (!epc_group) {280 ret = -ENOMEM;281 goto err;282 }283 284 group = &epc_group->group;285 286 config_group_init_type_name(group, name, &pci_epc_type);287 ret = configfs_register_group(controllers_group, group);288 if (ret) {289 pr_err("failed to register configfs group for %s\n", name);290 goto err_register_group;291 }292 293 epc = pci_epc_get(name);294 if (IS_ERR(epc)) {295 ret = PTR_ERR(epc);296 goto err_epc_get;297 }298 299 epc_group->epc = epc;300 301 return group;302 303err_epc_get:304 configfs_unregister_group(group);305 306err_register_group:307 kfree(epc_group);308 309err:310 return ERR_PTR(ret);311}312EXPORT_SYMBOL(pci_ep_cfs_add_epc_group);313 314void pci_ep_cfs_remove_epc_group(struct config_group *group)315{316 struct pci_epc_group *epc_group;317 318 if (!group)319 return;320 321 epc_group = container_of(group, struct pci_epc_group, group);322 pci_epc_put(epc_group->epc);323 configfs_unregister_group(&epc_group->group);324 kfree(epc_group);325}326EXPORT_SYMBOL(pci_ep_cfs_remove_epc_group);327 328#define PCI_EPF_HEADER_R(_name) \329static ssize_t pci_epf_##_name##_show(struct config_item *item, char *page) \330{ \331 struct pci_epf *epf = to_pci_epf_group(item)->epf; \332 if (WARN_ON_ONCE(!epf->header)) \333 return -EINVAL; \334 return sysfs_emit(page, "0x%04x\n", epf->header->_name); \335}336 337#define PCI_EPF_HEADER_W_u32(_name) \338static ssize_t pci_epf_##_name##_store(struct config_item *item, \339 const char *page, size_t len) \340{ \341 u32 val; \342 struct pci_epf *epf = to_pci_epf_group(item)->epf; \343 if (WARN_ON_ONCE(!epf->header)) \344 return -EINVAL; \345 if (kstrtou32(page, 0, &val) < 0) \346 return -EINVAL; \347 epf->header->_name = val; \348 return len; \349}350 351#define PCI_EPF_HEADER_W_u16(_name) \352static ssize_t pci_epf_##_name##_store(struct config_item *item, \353 const char *page, size_t len) \354{ \355 u16 val; \356 struct pci_epf *epf = to_pci_epf_group(item)->epf; \357 if (WARN_ON_ONCE(!epf->header)) \358 return -EINVAL; \359 if (kstrtou16(page, 0, &val) < 0) \360 return -EINVAL; \361 epf->header->_name = val; \362 return len; \363}364 365#define PCI_EPF_HEADER_W_u8(_name) \366static ssize_t pci_epf_##_name##_store(struct config_item *item, \367 const char *page, size_t len) \368{ \369 u8 val; \370 struct pci_epf *epf = to_pci_epf_group(item)->epf; \371 if (WARN_ON_ONCE(!epf->header)) \372 return -EINVAL; \373 if (kstrtou8(page, 0, &val) < 0) \374 return -EINVAL; \375 epf->header->_name = val; \376 return len; \377}378 379static ssize_t pci_epf_msi_interrupts_store(struct config_item *item,380 const char *page, size_t len)381{382 u8 val;383 384 if (kstrtou8(page, 0, &val) < 0)385 return -EINVAL;386 387 to_pci_epf_group(item)->epf->msi_interrupts = val;388 389 return len;390}391 392static ssize_t pci_epf_msi_interrupts_show(struct config_item *item,393 char *page)394{395 return sysfs_emit(page, "%d\n",396 to_pci_epf_group(item)->epf->msi_interrupts);397}398 399static ssize_t pci_epf_msix_interrupts_store(struct config_item *item,400 const char *page, size_t len)401{402 u16 val;403 404 if (kstrtou16(page, 0, &val) < 0)405 return -EINVAL;406 407 to_pci_epf_group(item)->epf->msix_interrupts = val;408 409 return len;410}411 412static ssize_t pci_epf_msix_interrupts_show(struct config_item *item,413 char *page)414{415 return sysfs_emit(page, "%d\n",416 to_pci_epf_group(item)->epf->msix_interrupts);417}418 419PCI_EPF_HEADER_R(vendorid)420PCI_EPF_HEADER_W_u16(vendorid)421 422PCI_EPF_HEADER_R(deviceid)423PCI_EPF_HEADER_W_u16(deviceid)424 425PCI_EPF_HEADER_R(revid)426PCI_EPF_HEADER_W_u8(revid)427 428PCI_EPF_HEADER_R(progif_code)429PCI_EPF_HEADER_W_u8(progif_code)430 431PCI_EPF_HEADER_R(subclass_code)432PCI_EPF_HEADER_W_u8(subclass_code)433 434PCI_EPF_HEADER_R(baseclass_code)435PCI_EPF_HEADER_W_u8(baseclass_code)436 437PCI_EPF_HEADER_R(cache_line_size)438PCI_EPF_HEADER_W_u8(cache_line_size)439 440PCI_EPF_HEADER_R(subsys_vendor_id)441PCI_EPF_HEADER_W_u16(subsys_vendor_id)442 443PCI_EPF_HEADER_R(subsys_id)444PCI_EPF_HEADER_W_u16(subsys_id)445 446PCI_EPF_HEADER_R(interrupt_pin)447PCI_EPF_HEADER_W_u8(interrupt_pin)448 449CONFIGFS_ATTR(pci_epf_, vendorid);450CONFIGFS_ATTR(pci_epf_, deviceid);451CONFIGFS_ATTR(pci_epf_, revid);452CONFIGFS_ATTR(pci_epf_, progif_code);453CONFIGFS_ATTR(pci_epf_, subclass_code);454CONFIGFS_ATTR(pci_epf_, baseclass_code);455CONFIGFS_ATTR(pci_epf_, cache_line_size);456CONFIGFS_ATTR(pci_epf_, subsys_vendor_id);457CONFIGFS_ATTR(pci_epf_, subsys_id);458CONFIGFS_ATTR(pci_epf_, interrupt_pin);459CONFIGFS_ATTR(pci_epf_, msi_interrupts);460CONFIGFS_ATTR(pci_epf_, msix_interrupts);461 462static struct configfs_attribute *pci_epf_attrs[] = {463 &pci_epf_attr_vendorid,464 &pci_epf_attr_deviceid,465 &pci_epf_attr_revid,466 &pci_epf_attr_progif_code,467 &pci_epf_attr_subclass_code,468 &pci_epf_attr_baseclass_code,469 &pci_epf_attr_cache_line_size,470 &pci_epf_attr_subsys_vendor_id,471 &pci_epf_attr_subsys_id,472 &pci_epf_attr_interrupt_pin,473 &pci_epf_attr_msi_interrupts,474 &pci_epf_attr_msix_interrupts,475 NULL,476};477 478static int pci_epf_vepf_link(struct config_item *epf_pf_item,479 struct config_item *epf_vf_item)480{481 struct pci_epf_group *epf_vf_group = to_pci_epf_group(epf_vf_item);482 struct pci_epf_group *epf_pf_group = to_pci_epf_group(epf_pf_item);483 struct pci_epf *epf_pf = epf_pf_group->epf;484 struct pci_epf *epf_vf = epf_vf_group->epf;485 486 return pci_epf_add_vepf(epf_pf, epf_vf);487}488 489static void pci_epf_vepf_unlink(struct config_item *epf_pf_item,490 struct config_item *epf_vf_item)491{492 struct pci_epf_group *epf_vf_group = to_pci_epf_group(epf_vf_item);493 struct pci_epf_group *epf_pf_group = to_pci_epf_group(epf_pf_item);494 struct pci_epf *epf_pf = epf_pf_group->epf;495 struct pci_epf *epf_vf = epf_vf_group->epf;496 497 pci_epf_remove_vepf(epf_pf, epf_vf);498}499 500static void pci_epf_release(struct config_item *item)501{502 struct pci_epf_group *epf_group = to_pci_epf_group(item);503 504 mutex_lock(&functions_mutex);505 idr_remove(&functions_idr, epf_group->index);506 mutex_unlock(&functions_mutex);507 pci_epf_destroy(epf_group->epf);508 kfree(epf_group);509}510 511static struct configfs_item_operations pci_epf_ops = {512 .allow_link = pci_epf_vepf_link,513 .drop_link = pci_epf_vepf_unlink,514 .release = pci_epf_release,515};516 517static const struct config_item_type pci_epf_type = {518 .ct_item_ops = &pci_epf_ops,519 .ct_attrs = pci_epf_attrs,520 .ct_owner = THIS_MODULE,521};522 523/**524 * pci_epf_type_add_cfs() - Help function drivers to expose function specific525 * attributes in configfs526 * @epf: the EPF device that has to be configured using configfs527 * @group: the parent configfs group (corresponding to entries in528 * pci_epf_device_id)529 *530 * Invoke to expose function specific attributes in configfs.531 *532 * Return: A pointer to a config_group structure or NULL if the function driver533 * does not have anything to expose (attributes configured by user) or if534 * the function driver does not implement the add_cfs() method.535 *536 * Returns an error pointer if this function is called for an unbound EPF device537 * or if the EPF driver add_cfs() method fails.538 */539static struct config_group *pci_epf_type_add_cfs(struct pci_epf *epf,540 struct config_group *group)541{542 struct config_group *epf_type_group;543 544 if (!epf->driver) {545 dev_err(&epf->dev, "epf device not bound to driver\n");546 return ERR_PTR(-ENODEV);547 }548 549 if (!epf->driver->ops->add_cfs)550 return NULL;551 552 mutex_lock(&epf->lock);553 epf_type_group = epf->driver->ops->add_cfs(epf, group);554 mutex_unlock(&epf->lock);555 556 return epf_type_group;557}558 559static void pci_ep_cfs_add_type_group(struct pci_epf_group *epf_group)560{561 struct config_group *group;562 563 group = pci_epf_type_add_cfs(epf_group->epf, &epf_group->group);564 if (!group)565 return;566 567 if (IS_ERR(group)) {568 dev_err(&epf_group->epf->dev,569 "failed to create epf type specific attributes\n");570 return;571 }572 573 configfs_register_group(&epf_group->group, group);574}575 576static void pci_epf_cfs_work(struct work_struct *work)577{578 struct pci_epf_group *epf_group;579 struct config_group *group;580 581 epf_group = container_of(work, struct pci_epf_group, cfs_work.work);582 group = pci_ep_cfs_add_primary_group(epf_group);583 if (IS_ERR(group)) {584 pr_err("failed to create 'primary' EPC interface\n");585 return;586 }587 588 group = pci_ep_cfs_add_secondary_group(epf_group);589 if (IS_ERR(group)) {590 pr_err("failed to create 'secondary' EPC interface\n");591 return;592 }593 594 pci_ep_cfs_add_type_group(epf_group);595}596 597static struct config_group *pci_epf_make(struct config_group *group,598 const char *name)599{600 struct pci_epf_group *epf_group;601 struct pci_epf *epf;602 char *epf_name;603 int index, err;604 605 epf_group = kzalloc(sizeof(*epf_group), GFP_KERNEL);606 if (!epf_group)607 return ERR_PTR(-ENOMEM);608 609 mutex_lock(&functions_mutex);610 index = idr_alloc(&functions_idr, epf_group, 0, 0, GFP_KERNEL);611 mutex_unlock(&functions_mutex);612 if (index < 0) {613 err = index;614 goto free_group;615 }616 617 epf_group->index = index;618 619 config_group_init_type_name(&epf_group->group, name, &pci_epf_type);620 621 epf_name = kasprintf(GFP_KERNEL, "%s.%d",622 group->cg_item.ci_name, epf_group->index);623 if (!epf_name) {624 err = -ENOMEM;625 goto remove_idr;626 }627 628 epf = pci_epf_create(epf_name);629 if (IS_ERR(epf)) {630 pr_err("failed to create endpoint function device\n");631 err = -EINVAL;632 goto free_name;633 }634 635 epf->group = &epf_group->group;636 epf_group->epf = epf;637 638 kfree(epf_name);639 640 INIT_DELAYED_WORK(&epf_group->cfs_work, pci_epf_cfs_work);641 queue_delayed_work(system_wq, &epf_group->cfs_work,642 msecs_to_jiffies(1));643 644 return &epf_group->group;645 646free_name:647 kfree(epf_name);648 649remove_idr:650 mutex_lock(&functions_mutex);651 idr_remove(&functions_idr, epf_group->index);652 mutex_unlock(&functions_mutex);653 654free_group:655 kfree(epf_group);656 657 return ERR_PTR(err);658}659 660static void pci_epf_drop(struct config_group *group, struct config_item *item)661{662 config_item_put(item);663}664 665static struct configfs_group_operations pci_epf_group_ops = {666 .make_group = &pci_epf_make,667 .drop_item = &pci_epf_drop,668};669 670static const struct config_item_type pci_epf_group_type = {671 .ct_group_ops = &pci_epf_group_ops,672 .ct_owner = THIS_MODULE,673};674 675struct config_group *pci_ep_cfs_add_epf_group(const char *name)676{677 struct config_group *group;678 679 group = configfs_register_default_group(functions_group, name,680 &pci_epf_group_type);681 if (IS_ERR(group))682 pr_err("failed to register configfs group for %s function\n",683 name);684 685 return group;686}687EXPORT_SYMBOL(pci_ep_cfs_add_epf_group);688 689void pci_ep_cfs_remove_epf_group(struct config_group *group)690{691 if (IS_ERR_OR_NULL(group))692 return;693 694 configfs_unregister_default_group(group);695}696EXPORT_SYMBOL(pci_ep_cfs_remove_epf_group);697 698static const struct config_item_type pci_functions_type = {699 .ct_owner = THIS_MODULE,700};701 702static const struct config_item_type pci_controllers_type = {703 .ct_owner = THIS_MODULE,704};705 706static const struct config_item_type pci_ep_type = {707 .ct_owner = THIS_MODULE,708};709 710static struct configfs_subsystem pci_ep_cfs_subsys = {711 .su_group = {712 .cg_item = {713 .ci_namebuf = "pci_ep",714 .ci_type = &pci_ep_type,715 },716 },717 .su_mutex = __MUTEX_INITIALIZER(pci_ep_cfs_subsys.su_mutex),718};719 720static int __init pci_ep_cfs_init(void)721{722 int ret;723 struct config_group *root = &pci_ep_cfs_subsys.su_group;724 725 config_group_init(root);726 727 ret = configfs_register_subsystem(&pci_ep_cfs_subsys);728 if (ret) {729 pr_err("Error %d while registering subsystem %s\n",730 ret, root->cg_item.ci_namebuf);731 goto err;732 }733 734 functions_group = configfs_register_default_group(root, "functions",735 &pci_functions_type);736 if (IS_ERR(functions_group)) {737 ret = PTR_ERR(functions_group);738 pr_err("Error %d while registering functions group\n",739 ret);740 goto err_functions_group;741 }742 743 controllers_group =744 configfs_register_default_group(root, "controllers",745 &pci_controllers_type);746 if (IS_ERR(controllers_group)) {747 ret = PTR_ERR(controllers_group);748 pr_err("Error %d while registering controllers group\n",749 ret);750 goto err_controllers_group;751 }752 753 return 0;754 755err_controllers_group:756 configfs_unregister_default_group(functions_group);757 758err_functions_group:759 configfs_unregister_subsystem(&pci_ep_cfs_subsys);760 761err:762 return ret;763}764module_init(pci_ep_cfs_init);765 766static void __exit pci_ep_cfs_exit(void)767{768 configfs_unregister_default_group(controllers_group);769 configfs_unregister_default_group(functions_group);770 configfs_unregister_subsystem(&pci_ep_cfs_subsys);771}772module_exit(pci_ep_cfs_exit);773 774MODULE_DESCRIPTION("PCI EP CONFIGFS");775MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");776