18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * configfs to configure the PCI endpoint 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017 Texas Instruments 68c2ecf20Sopenharmony_ci * Author: Kishon Vijay Abraham I <kishon@ti.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/idr.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/pci-epc.h> 148c2ecf20Sopenharmony_ci#include <linux/pci-epf.h> 158c2ecf20Sopenharmony_ci#include <linux/pci-ep-cfs.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic DEFINE_IDR(functions_idr); 188c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(functions_mutex); 198c2ecf20Sopenharmony_cistatic struct config_group *functions_group; 208c2ecf20Sopenharmony_cistatic struct config_group *controllers_group; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct pci_epf_group { 238c2ecf20Sopenharmony_ci struct config_group group; 248c2ecf20Sopenharmony_ci struct pci_epf *epf; 258c2ecf20Sopenharmony_ci int index; 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct pci_epc_group { 298c2ecf20Sopenharmony_ci struct config_group group; 308c2ecf20Sopenharmony_ci struct pci_epc *epc; 318c2ecf20Sopenharmony_ci bool start; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic inline struct pci_epf_group *to_pci_epf_group(struct config_item *item) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci return container_of(to_config_group(item), struct pci_epf_group, group); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic inline struct pci_epc_group *to_pci_epc_group(struct config_item *item) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci return container_of(to_config_group(item), struct pci_epc_group, group); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic ssize_t pci_epc_start_store(struct config_item *item, const char *page, 458c2ecf20Sopenharmony_ci size_t len) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci int ret; 488c2ecf20Sopenharmony_ci bool start; 498c2ecf20Sopenharmony_ci struct pci_epc *epc; 508c2ecf20Sopenharmony_ci struct pci_epc_group *epc_group = to_pci_epc_group(item); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci epc = epc_group->epc; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci ret = kstrtobool(page, &start); 558c2ecf20Sopenharmony_ci if (ret) 568c2ecf20Sopenharmony_ci return ret; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (!start) { 598c2ecf20Sopenharmony_ci pci_epc_stop(epc); 608c2ecf20Sopenharmony_ci epc_group->start = 0; 618c2ecf20Sopenharmony_ci return len; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci ret = pci_epc_start(epc); 658c2ecf20Sopenharmony_ci if (ret) { 668c2ecf20Sopenharmony_ci dev_err(&epc->dev, "failed to start endpoint controller\n"); 678c2ecf20Sopenharmony_ci return -EINVAL; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci epc_group->start = start; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci return len; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic ssize_t pci_epc_start_show(struct config_item *item, char *page) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci return sprintf(page, "%d\n", 788c2ecf20Sopenharmony_ci to_pci_epc_group(item)->start); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epc_, start); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic struct configfs_attribute *pci_epc_attrs[] = { 848c2ecf20Sopenharmony_ci &pci_epc_attr_start, 858c2ecf20Sopenharmony_ci NULL, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int pci_epc_epf_link(struct config_item *epc_item, 898c2ecf20Sopenharmony_ci struct config_item *epf_item) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci int ret; 928c2ecf20Sopenharmony_ci struct pci_epf_group *epf_group = to_pci_epf_group(epf_item); 938c2ecf20Sopenharmony_ci struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); 948c2ecf20Sopenharmony_ci struct pci_epc *epc = epc_group->epc; 958c2ecf20Sopenharmony_ci struct pci_epf *epf = epf_group->epf; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci ret = pci_epc_add_epf(epc, epf); 988c2ecf20Sopenharmony_ci if (ret) 998c2ecf20Sopenharmony_ci return ret; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci ret = pci_epf_bind(epf); 1028c2ecf20Sopenharmony_ci if (ret) { 1038c2ecf20Sopenharmony_ci pci_epc_remove_epf(epc, epf); 1048c2ecf20Sopenharmony_ci return ret; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return 0; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic void pci_epc_epf_unlink(struct config_item *epc_item, 1118c2ecf20Sopenharmony_ci struct config_item *epf_item) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct pci_epc *epc; 1148c2ecf20Sopenharmony_ci struct pci_epf *epf; 1158c2ecf20Sopenharmony_ci struct pci_epf_group *epf_group = to_pci_epf_group(epf_item); 1168c2ecf20Sopenharmony_ci struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci WARN_ON_ONCE(epc_group->start); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci epc = epc_group->epc; 1218c2ecf20Sopenharmony_ci epf = epf_group->epf; 1228c2ecf20Sopenharmony_ci pci_epf_unbind(epf); 1238c2ecf20Sopenharmony_ci pci_epc_remove_epf(epc, epf); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic struct configfs_item_operations pci_epc_item_ops = { 1278c2ecf20Sopenharmony_ci .allow_link = pci_epc_epf_link, 1288c2ecf20Sopenharmony_ci .drop_link = pci_epc_epf_unlink, 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic const struct config_item_type pci_epc_type = { 1328c2ecf20Sopenharmony_ci .ct_item_ops = &pci_epc_item_ops, 1338c2ecf20Sopenharmony_ci .ct_attrs = pci_epc_attrs, 1348c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistruct config_group *pci_ep_cfs_add_epc_group(const char *name) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci int ret; 1408c2ecf20Sopenharmony_ci struct pci_epc *epc; 1418c2ecf20Sopenharmony_ci struct config_group *group; 1428c2ecf20Sopenharmony_ci struct pci_epc_group *epc_group; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci epc_group = kzalloc(sizeof(*epc_group), GFP_KERNEL); 1458c2ecf20Sopenharmony_ci if (!epc_group) { 1468c2ecf20Sopenharmony_ci ret = -ENOMEM; 1478c2ecf20Sopenharmony_ci goto err; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci group = &epc_group->group; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci config_group_init_type_name(group, name, &pci_epc_type); 1538c2ecf20Sopenharmony_ci ret = configfs_register_group(controllers_group, group); 1548c2ecf20Sopenharmony_ci if (ret) { 1558c2ecf20Sopenharmony_ci pr_err("failed to register configfs group for %s\n", name); 1568c2ecf20Sopenharmony_ci goto err_register_group; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci epc = pci_epc_get(name); 1608c2ecf20Sopenharmony_ci if (IS_ERR(epc)) { 1618c2ecf20Sopenharmony_ci ret = PTR_ERR(epc); 1628c2ecf20Sopenharmony_ci goto err_epc_get; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci epc_group->epc = epc; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return group; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cierr_epc_get: 1708c2ecf20Sopenharmony_ci configfs_unregister_group(group); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cierr_register_group: 1738c2ecf20Sopenharmony_ci kfree(epc_group); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cierr: 1768c2ecf20Sopenharmony_ci return ERR_PTR(ret); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_ep_cfs_add_epc_group); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_civoid pci_ep_cfs_remove_epc_group(struct config_group *group) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci struct pci_epc_group *epc_group; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (!group) 1858c2ecf20Sopenharmony_ci return; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci epc_group = container_of(group, struct pci_epc_group, group); 1888c2ecf20Sopenharmony_ci pci_epc_put(epc_group->epc); 1898c2ecf20Sopenharmony_ci configfs_unregister_group(&epc_group->group); 1908c2ecf20Sopenharmony_ci kfree(epc_group); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_ep_cfs_remove_epc_group); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci#define PCI_EPF_HEADER_R(_name) \ 1958c2ecf20Sopenharmony_cistatic ssize_t pci_epf_##_name##_show(struct config_item *item, char *page) \ 1968c2ecf20Sopenharmony_ci{ \ 1978c2ecf20Sopenharmony_ci struct pci_epf *epf = to_pci_epf_group(item)->epf; \ 1988c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!epf->header)) \ 1998c2ecf20Sopenharmony_ci return -EINVAL; \ 2008c2ecf20Sopenharmony_ci return sprintf(page, "0x%04x\n", epf->header->_name); \ 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci#define PCI_EPF_HEADER_W_u32(_name) \ 2048c2ecf20Sopenharmony_cistatic ssize_t pci_epf_##_name##_store(struct config_item *item, \ 2058c2ecf20Sopenharmony_ci const char *page, size_t len) \ 2068c2ecf20Sopenharmony_ci{ \ 2078c2ecf20Sopenharmony_ci u32 val; \ 2088c2ecf20Sopenharmony_ci int ret; \ 2098c2ecf20Sopenharmony_ci struct pci_epf *epf = to_pci_epf_group(item)->epf; \ 2108c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!epf->header)) \ 2118c2ecf20Sopenharmony_ci return -EINVAL; \ 2128c2ecf20Sopenharmony_ci ret = kstrtou32(page, 0, &val); \ 2138c2ecf20Sopenharmony_ci if (ret) \ 2148c2ecf20Sopenharmony_ci return ret; \ 2158c2ecf20Sopenharmony_ci epf->header->_name = val; \ 2168c2ecf20Sopenharmony_ci return len; \ 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci#define PCI_EPF_HEADER_W_u16(_name) \ 2208c2ecf20Sopenharmony_cistatic ssize_t pci_epf_##_name##_store(struct config_item *item, \ 2218c2ecf20Sopenharmony_ci const char *page, size_t len) \ 2228c2ecf20Sopenharmony_ci{ \ 2238c2ecf20Sopenharmony_ci u16 val; \ 2248c2ecf20Sopenharmony_ci int ret; \ 2258c2ecf20Sopenharmony_ci struct pci_epf *epf = to_pci_epf_group(item)->epf; \ 2268c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!epf->header)) \ 2278c2ecf20Sopenharmony_ci return -EINVAL; \ 2288c2ecf20Sopenharmony_ci ret = kstrtou16(page, 0, &val); \ 2298c2ecf20Sopenharmony_ci if (ret) \ 2308c2ecf20Sopenharmony_ci return ret; \ 2318c2ecf20Sopenharmony_ci epf->header->_name = val; \ 2328c2ecf20Sopenharmony_ci return len; \ 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci#define PCI_EPF_HEADER_W_u8(_name) \ 2368c2ecf20Sopenharmony_cistatic ssize_t pci_epf_##_name##_store(struct config_item *item, \ 2378c2ecf20Sopenharmony_ci const char *page, size_t len) \ 2388c2ecf20Sopenharmony_ci{ \ 2398c2ecf20Sopenharmony_ci u8 val; \ 2408c2ecf20Sopenharmony_ci int ret; \ 2418c2ecf20Sopenharmony_ci struct pci_epf *epf = to_pci_epf_group(item)->epf; \ 2428c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!epf->header)) \ 2438c2ecf20Sopenharmony_ci return -EINVAL; \ 2448c2ecf20Sopenharmony_ci ret = kstrtou8(page, 0, &val); \ 2458c2ecf20Sopenharmony_ci if (ret) \ 2468c2ecf20Sopenharmony_ci return ret; \ 2478c2ecf20Sopenharmony_ci epf->header->_name = val; \ 2488c2ecf20Sopenharmony_ci return len; \ 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic ssize_t pci_epf_msi_interrupts_store(struct config_item *item, 2528c2ecf20Sopenharmony_ci const char *page, size_t len) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci u8 val; 2558c2ecf20Sopenharmony_ci int ret; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci ret = kstrtou8(page, 0, &val); 2588c2ecf20Sopenharmony_ci if (ret) 2598c2ecf20Sopenharmony_ci return ret; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci to_pci_epf_group(item)->epf->msi_interrupts = val; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return len; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic ssize_t pci_epf_msi_interrupts_show(struct config_item *item, 2678c2ecf20Sopenharmony_ci char *page) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci return sprintf(page, "%d\n", 2708c2ecf20Sopenharmony_ci to_pci_epf_group(item)->epf->msi_interrupts); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic ssize_t pci_epf_msix_interrupts_store(struct config_item *item, 2748c2ecf20Sopenharmony_ci const char *page, size_t len) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci u16 val; 2778c2ecf20Sopenharmony_ci int ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ret = kstrtou16(page, 0, &val); 2808c2ecf20Sopenharmony_ci if (ret) 2818c2ecf20Sopenharmony_ci return ret; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci to_pci_epf_group(item)->epf->msix_interrupts = val; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return len; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic ssize_t pci_epf_msix_interrupts_show(struct config_item *item, 2898c2ecf20Sopenharmony_ci char *page) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci return sprintf(page, "%d\n", 2928c2ecf20Sopenharmony_ci to_pci_epf_group(item)->epf->msix_interrupts); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ciPCI_EPF_HEADER_R(vendorid) 2968c2ecf20Sopenharmony_ciPCI_EPF_HEADER_W_u16(vendorid) 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ciPCI_EPF_HEADER_R(deviceid) 2998c2ecf20Sopenharmony_ciPCI_EPF_HEADER_W_u16(deviceid) 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ciPCI_EPF_HEADER_R(revid) 3028c2ecf20Sopenharmony_ciPCI_EPF_HEADER_W_u8(revid) 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ciPCI_EPF_HEADER_R(progif_code) 3058c2ecf20Sopenharmony_ciPCI_EPF_HEADER_W_u8(progif_code) 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ciPCI_EPF_HEADER_R(subclass_code) 3088c2ecf20Sopenharmony_ciPCI_EPF_HEADER_W_u8(subclass_code) 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ciPCI_EPF_HEADER_R(baseclass_code) 3118c2ecf20Sopenharmony_ciPCI_EPF_HEADER_W_u8(baseclass_code) 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ciPCI_EPF_HEADER_R(cache_line_size) 3148c2ecf20Sopenharmony_ciPCI_EPF_HEADER_W_u8(cache_line_size) 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ciPCI_EPF_HEADER_R(subsys_vendor_id) 3178c2ecf20Sopenharmony_ciPCI_EPF_HEADER_W_u16(subsys_vendor_id) 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ciPCI_EPF_HEADER_R(subsys_id) 3208c2ecf20Sopenharmony_ciPCI_EPF_HEADER_W_u16(subsys_id) 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ciPCI_EPF_HEADER_R(interrupt_pin) 3238c2ecf20Sopenharmony_ciPCI_EPF_HEADER_W_u8(interrupt_pin) 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, vendorid); 3268c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, deviceid); 3278c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, revid); 3288c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, progif_code); 3298c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, subclass_code); 3308c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, baseclass_code); 3318c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, cache_line_size); 3328c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, subsys_vendor_id); 3338c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, subsys_id); 3348c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, interrupt_pin); 3358c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, msi_interrupts); 3368c2ecf20Sopenharmony_ciCONFIGFS_ATTR(pci_epf_, msix_interrupts); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic struct configfs_attribute *pci_epf_attrs[] = { 3398c2ecf20Sopenharmony_ci &pci_epf_attr_vendorid, 3408c2ecf20Sopenharmony_ci &pci_epf_attr_deviceid, 3418c2ecf20Sopenharmony_ci &pci_epf_attr_revid, 3428c2ecf20Sopenharmony_ci &pci_epf_attr_progif_code, 3438c2ecf20Sopenharmony_ci &pci_epf_attr_subclass_code, 3448c2ecf20Sopenharmony_ci &pci_epf_attr_baseclass_code, 3458c2ecf20Sopenharmony_ci &pci_epf_attr_cache_line_size, 3468c2ecf20Sopenharmony_ci &pci_epf_attr_subsys_vendor_id, 3478c2ecf20Sopenharmony_ci &pci_epf_attr_subsys_id, 3488c2ecf20Sopenharmony_ci &pci_epf_attr_interrupt_pin, 3498c2ecf20Sopenharmony_ci &pci_epf_attr_msi_interrupts, 3508c2ecf20Sopenharmony_ci &pci_epf_attr_msix_interrupts, 3518c2ecf20Sopenharmony_ci NULL, 3528c2ecf20Sopenharmony_ci}; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic void pci_epf_release(struct config_item *item) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct pci_epf_group *epf_group = to_pci_epf_group(item); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci mutex_lock(&functions_mutex); 3598c2ecf20Sopenharmony_ci idr_remove(&functions_idr, epf_group->index); 3608c2ecf20Sopenharmony_ci mutex_unlock(&functions_mutex); 3618c2ecf20Sopenharmony_ci pci_epf_destroy(epf_group->epf); 3628c2ecf20Sopenharmony_ci kfree(epf_group); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic struct configfs_item_operations pci_epf_ops = { 3668c2ecf20Sopenharmony_ci .release = pci_epf_release, 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic const struct config_item_type pci_epf_type = { 3708c2ecf20Sopenharmony_ci .ct_item_ops = &pci_epf_ops, 3718c2ecf20Sopenharmony_ci .ct_attrs = pci_epf_attrs, 3728c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 3738c2ecf20Sopenharmony_ci}; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic struct config_group *pci_epf_make(struct config_group *group, 3768c2ecf20Sopenharmony_ci const char *name) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct pci_epf_group *epf_group; 3798c2ecf20Sopenharmony_ci struct pci_epf *epf; 3808c2ecf20Sopenharmony_ci char *epf_name; 3818c2ecf20Sopenharmony_ci int index, err; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci epf_group = kzalloc(sizeof(*epf_group), GFP_KERNEL); 3848c2ecf20Sopenharmony_ci if (!epf_group) 3858c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci mutex_lock(&functions_mutex); 3888c2ecf20Sopenharmony_ci index = idr_alloc(&functions_idr, epf_group, 0, 0, GFP_KERNEL); 3898c2ecf20Sopenharmony_ci mutex_unlock(&functions_mutex); 3908c2ecf20Sopenharmony_ci if (index < 0) { 3918c2ecf20Sopenharmony_ci err = index; 3928c2ecf20Sopenharmony_ci goto free_group; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci epf_group->index = index; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci config_group_init_type_name(&epf_group->group, name, &pci_epf_type); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci epf_name = kasprintf(GFP_KERNEL, "%s.%d", 4008c2ecf20Sopenharmony_ci group->cg_item.ci_name, epf_group->index); 4018c2ecf20Sopenharmony_ci if (!epf_name) { 4028c2ecf20Sopenharmony_ci err = -ENOMEM; 4038c2ecf20Sopenharmony_ci goto remove_idr; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci epf = pci_epf_create(epf_name); 4078c2ecf20Sopenharmony_ci if (IS_ERR(epf)) { 4088c2ecf20Sopenharmony_ci pr_err("failed to create endpoint function device\n"); 4098c2ecf20Sopenharmony_ci err = -EINVAL; 4108c2ecf20Sopenharmony_ci goto free_name; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci epf_group->epf = epf; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci kfree(epf_name); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci return &epf_group->group; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cifree_name: 4208c2ecf20Sopenharmony_ci kfree(epf_name); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ciremove_idr: 4238c2ecf20Sopenharmony_ci mutex_lock(&functions_mutex); 4248c2ecf20Sopenharmony_ci idr_remove(&functions_idr, epf_group->index); 4258c2ecf20Sopenharmony_ci mutex_unlock(&functions_mutex); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cifree_group: 4288c2ecf20Sopenharmony_ci kfree(epf_group); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return ERR_PTR(err); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic void pci_epf_drop(struct config_group *group, struct config_item *item) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci config_item_put(item); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic struct configfs_group_operations pci_epf_group_ops = { 4398c2ecf20Sopenharmony_ci .make_group = &pci_epf_make, 4408c2ecf20Sopenharmony_ci .drop_item = &pci_epf_drop, 4418c2ecf20Sopenharmony_ci}; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic const struct config_item_type pci_epf_group_type = { 4448c2ecf20Sopenharmony_ci .ct_group_ops = &pci_epf_group_ops, 4458c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 4468c2ecf20Sopenharmony_ci}; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistruct config_group *pci_ep_cfs_add_epf_group(const char *name) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct config_group *group; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci group = configfs_register_default_group(functions_group, name, 4538c2ecf20Sopenharmony_ci &pci_epf_group_type); 4548c2ecf20Sopenharmony_ci if (IS_ERR(group)) 4558c2ecf20Sopenharmony_ci pr_err("failed to register configfs group for %s function\n", 4568c2ecf20Sopenharmony_ci name); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return group; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_ep_cfs_add_epf_group); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_civoid pci_ep_cfs_remove_epf_group(struct config_group *group) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(group)) 4658c2ecf20Sopenharmony_ci return; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci configfs_unregister_default_group(group); 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_ep_cfs_remove_epf_group); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic const struct config_item_type pci_functions_type = { 4728c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 4738c2ecf20Sopenharmony_ci}; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic const struct config_item_type pci_controllers_type = { 4768c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 4778c2ecf20Sopenharmony_ci}; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic const struct config_item_type pci_ep_type = { 4808c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 4818c2ecf20Sopenharmony_ci}; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic struct configfs_subsystem pci_ep_cfs_subsys = { 4848c2ecf20Sopenharmony_ci .su_group = { 4858c2ecf20Sopenharmony_ci .cg_item = { 4868c2ecf20Sopenharmony_ci .ci_namebuf = "pci_ep", 4878c2ecf20Sopenharmony_ci .ci_type = &pci_ep_type, 4888c2ecf20Sopenharmony_ci }, 4898c2ecf20Sopenharmony_ci }, 4908c2ecf20Sopenharmony_ci .su_mutex = __MUTEX_INITIALIZER(pci_ep_cfs_subsys.su_mutex), 4918c2ecf20Sopenharmony_ci}; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic int __init pci_ep_cfs_init(void) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci int ret; 4968c2ecf20Sopenharmony_ci struct config_group *root = &pci_ep_cfs_subsys.su_group; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci config_group_init(root); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci ret = configfs_register_subsystem(&pci_ep_cfs_subsys); 5018c2ecf20Sopenharmony_ci if (ret) { 5028c2ecf20Sopenharmony_ci pr_err("Error %d while registering subsystem %s\n", 5038c2ecf20Sopenharmony_ci ret, root->cg_item.ci_namebuf); 5048c2ecf20Sopenharmony_ci goto err; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci functions_group = configfs_register_default_group(root, "functions", 5088c2ecf20Sopenharmony_ci &pci_functions_type); 5098c2ecf20Sopenharmony_ci if (IS_ERR(functions_group)) { 5108c2ecf20Sopenharmony_ci ret = PTR_ERR(functions_group); 5118c2ecf20Sopenharmony_ci pr_err("Error %d while registering functions group\n", 5128c2ecf20Sopenharmony_ci ret); 5138c2ecf20Sopenharmony_ci goto err_functions_group; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci controllers_group = 5178c2ecf20Sopenharmony_ci configfs_register_default_group(root, "controllers", 5188c2ecf20Sopenharmony_ci &pci_controllers_type); 5198c2ecf20Sopenharmony_ci if (IS_ERR(controllers_group)) { 5208c2ecf20Sopenharmony_ci ret = PTR_ERR(controllers_group); 5218c2ecf20Sopenharmony_ci pr_err("Error %d while registering controllers group\n", 5228c2ecf20Sopenharmony_ci ret); 5238c2ecf20Sopenharmony_ci goto err_controllers_group; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return 0; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cierr_controllers_group: 5298c2ecf20Sopenharmony_ci configfs_unregister_default_group(functions_group); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cierr_functions_group: 5328c2ecf20Sopenharmony_ci configfs_unregister_subsystem(&pci_ep_cfs_subsys); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cierr: 5358c2ecf20Sopenharmony_ci return ret; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_cimodule_init(pci_ep_cfs_init); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic void __exit pci_ep_cfs_exit(void) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci configfs_unregister_default_group(controllers_group); 5428c2ecf20Sopenharmony_ci configfs_unregister_default_group(functions_group); 5438c2ecf20Sopenharmony_ci configfs_unregister_subsystem(&pci_ep_cfs_subsys); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_cimodule_exit(pci_ep_cfs_exit); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCI EP CONFIGFS"); 5488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); 5498c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 550