18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PCI Endpoint *Controller* (EPC) library 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/device.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of_device.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/pci-epc.h> 158c2ecf20Sopenharmony_ci#include <linux/pci-epf.h> 168c2ecf20Sopenharmony_ci#include <linux/pci-ep-cfs.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic struct class *pci_epc_class; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic void devm_pci_epc_release(struct device *dev, void *res) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci struct pci_epc *epc = *(struct pci_epc **)res; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci pci_epc_destroy(epc); 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int devm_pci_epc_match(struct device *dev, void *res, void *match_data) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct pci_epc **epc = res; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci return *epc == match_data; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/** 358c2ecf20Sopenharmony_ci * pci_epc_put() - release the PCI endpoint controller 368c2ecf20Sopenharmony_ci * @epc: epc returned by pci_epc_get() 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * release the refcount the caller obtained by invoking pci_epc_get() 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_civoid pci_epc_put(struct pci_epc *epc) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci if (!epc || IS_ERR(epc)) 438c2ecf20Sopenharmony_ci return; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci module_put(epc->ops->owner); 468c2ecf20Sopenharmony_ci put_device(&epc->dev); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_put); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/** 518c2ecf20Sopenharmony_ci * pci_epc_get() - get the PCI endpoint controller 528c2ecf20Sopenharmony_ci * @epc_name: device name of the endpoint controller 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * Invoke to get struct pci_epc * corresponding to the device name of the 558c2ecf20Sopenharmony_ci * endpoint controller 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cistruct pci_epc *pci_epc_get(const char *epc_name) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci int ret = -EINVAL; 608c2ecf20Sopenharmony_ci struct pci_epc *epc; 618c2ecf20Sopenharmony_ci struct device *dev; 628c2ecf20Sopenharmony_ci struct class_dev_iter iter; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci class_dev_iter_init(&iter, pci_epc_class, NULL, NULL); 658c2ecf20Sopenharmony_ci while ((dev = class_dev_iter_next(&iter))) { 668c2ecf20Sopenharmony_ci if (strcmp(epc_name, dev_name(dev))) 678c2ecf20Sopenharmony_ci continue; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci epc = to_pci_epc(dev); 708c2ecf20Sopenharmony_ci if (!try_module_get(epc->ops->owner)) { 718c2ecf20Sopenharmony_ci ret = -EINVAL; 728c2ecf20Sopenharmony_ci goto err; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci class_dev_iter_exit(&iter); 768c2ecf20Sopenharmony_ci get_device(&epc->dev); 778c2ecf20Sopenharmony_ci return epc; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cierr: 818c2ecf20Sopenharmony_ci class_dev_iter_exit(&iter); 828c2ecf20Sopenharmony_ci return ERR_PTR(ret); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_get); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/** 878c2ecf20Sopenharmony_ci * pci_epc_get_first_free_bar() - helper to get first unreserved BAR 888c2ecf20Sopenharmony_ci * @epc_features: pci_epc_features structure that holds the reserved bar bitmap 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * Invoke to get the first unreserved BAR that can be used by the endpoint 918c2ecf20Sopenharmony_ci * function. For any incorrect value in reserved_bar return '0'. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_cienum pci_barno 948c2ecf20Sopenharmony_cipci_epc_get_first_free_bar(const struct pci_epc_features *epc_features) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci return pci_epc_get_next_free_bar(epc_features, BAR_0); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_get_first_free_bar); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/** 1018c2ecf20Sopenharmony_ci * pci_epc_get_next_free_bar() - helper to get unreserved BAR starting from @bar 1028c2ecf20Sopenharmony_ci * @epc_features: pci_epc_features structure that holds the reserved bar bitmap 1038c2ecf20Sopenharmony_ci * @bar: the starting BAR number from where unreserved BAR should be searched 1048c2ecf20Sopenharmony_ci * 1058c2ecf20Sopenharmony_ci * Invoke to get the next unreserved BAR starting from @bar that can be used 1068c2ecf20Sopenharmony_ci * for endpoint function. For any incorrect value in reserved_bar return '0'. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_cienum pci_barno pci_epc_get_next_free_bar(const struct pci_epc_features 1098c2ecf20Sopenharmony_ci *epc_features, enum pci_barno bar) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci unsigned long free_bar; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (!epc_features) 1148c2ecf20Sopenharmony_ci return BAR_0; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* If 'bar - 1' is a 64-bit BAR, move to the next BAR */ 1178c2ecf20Sopenharmony_ci if ((epc_features->bar_fixed_64bit << 1) & 1 << bar) 1188c2ecf20Sopenharmony_ci bar++; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Find if the reserved BAR is also a 64-bit BAR */ 1218c2ecf20Sopenharmony_ci free_bar = epc_features->reserved_bar & epc_features->bar_fixed_64bit; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* Set the adjacent bit if the reserved BAR is also a 64-bit BAR */ 1248c2ecf20Sopenharmony_ci free_bar <<= 1; 1258c2ecf20Sopenharmony_ci free_bar |= epc_features->reserved_bar; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci free_bar = find_next_zero_bit(&free_bar, 6, bar); 1288c2ecf20Sopenharmony_ci if (free_bar > 5) 1298c2ecf20Sopenharmony_ci return NO_BAR; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return free_bar; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_get_next_free_bar); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/** 1368c2ecf20Sopenharmony_ci * pci_epc_get_features() - get the features supported by EPC 1378c2ecf20Sopenharmony_ci * @epc: the features supported by *this* EPC device will be returned 1388c2ecf20Sopenharmony_ci * @func_no: the features supported by the EPC device specific to the 1398c2ecf20Sopenharmony_ci * endpoint function with func_no will be returned 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * Invoke to get the features provided by the EPC which may be 1428c2ecf20Sopenharmony_ci * specific to an endpoint function. Returns pci_epc_features on success 1438c2ecf20Sopenharmony_ci * and NULL for any failures. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ciconst struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc, 1468c2ecf20Sopenharmony_ci u8 func_no) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci const struct pci_epc_features *epc_features; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 1518c2ecf20Sopenharmony_ci return NULL; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (!epc->ops->get_features) 1548c2ecf20Sopenharmony_ci return NULL; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 1578c2ecf20Sopenharmony_ci epc_features = epc->ops->get_features(epc, func_no); 1588c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return epc_features; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_get_features); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/** 1658c2ecf20Sopenharmony_ci * pci_epc_stop() - stop the PCI link 1668c2ecf20Sopenharmony_ci * @epc: the link of the EPC device that has to be stopped 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * Invoke to stop the PCI link 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_civoid pci_epc_stop(struct pci_epc *epc) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci if (IS_ERR(epc) || !epc->ops->stop) 1738c2ecf20Sopenharmony_ci return; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 1768c2ecf20Sopenharmony_ci epc->ops->stop(epc); 1778c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_stop); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/** 1828c2ecf20Sopenharmony_ci * pci_epc_start() - start the PCI link 1838c2ecf20Sopenharmony_ci * @epc: the link of *this* EPC device has to be started 1848c2ecf20Sopenharmony_ci * 1858c2ecf20Sopenharmony_ci * Invoke to start the PCI link 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ciint pci_epc_start(struct pci_epc *epc) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci int ret; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (IS_ERR(epc)) 1928c2ecf20Sopenharmony_ci return -EINVAL; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (!epc->ops->start) 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 1988c2ecf20Sopenharmony_ci ret = epc->ops->start(epc); 1998c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return ret; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_start); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/** 2068c2ecf20Sopenharmony_ci * pci_epc_raise_irq() - interrupt the host system 2078c2ecf20Sopenharmony_ci * @epc: the EPC device which has to interrupt the host 2088c2ecf20Sopenharmony_ci * @func_no: the endpoint function number in the EPC device 2098c2ecf20Sopenharmony_ci * @type: specify the type of interrupt; legacy, MSI or MSI-X 2108c2ecf20Sopenharmony_ci * @interrupt_num: the MSI or MSI-X interrupt number 2118c2ecf20Sopenharmony_ci * 2128c2ecf20Sopenharmony_ci * Invoke to raise an legacy, MSI or MSI-X interrupt 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ciint pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, 2158c2ecf20Sopenharmony_ci enum pci_epc_irq_type type, u16 interrupt_num) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci int ret; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 2208c2ecf20Sopenharmony_ci return -EINVAL; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (!epc->ops->raise_irq) 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 2268c2ecf20Sopenharmony_ci ret = epc->ops->raise_irq(epc, func_no, type, interrupt_num); 2278c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return ret; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_raise_irq); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/** 2348c2ecf20Sopenharmony_ci * pci_epc_get_msi() - get the number of MSI interrupt numbers allocated 2358c2ecf20Sopenharmony_ci * @epc: the EPC device to which MSI interrupts was requested 2368c2ecf20Sopenharmony_ci * @func_no: the endpoint function number in the EPC device 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci * Invoke to get the number of MSI interrupts allocated by the RC 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ciint pci_epc_get_msi(struct pci_epc *epc, u8 func_no) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci int interrupt; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (!epc->ops->get_msi) 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 2518c2ecf20Sopenharmony_ci interrupt = epc->ops->get_msi(epc, func_no); 2528c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (interrupt < 0) 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci interrupt = 1 << interrupt; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return interrupt; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_get_msi); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/** 2648c2ecf20Sopenharmony_ci * pci_epc_set_msi() - set the number of MSI interrupt numbers required 2658c2ecf20Sopenharmony_ci * @epc: the EPC device on which MSI has to be configured 2668c2ecf20Sopenharmony_ci * @func_no: the endpoint function number in the EPC device 2678c2ecf20Sopenharmony_ci * @interrupts: number of MSI interrupts required by the EPF 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * Invoke to set the required number of MSI interrupts. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ciint pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci int ret; 2748c2ecf20Sopenharmony_ci u8 encode_int; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 2778c2ecf20Sopenharmony_ci interrupts > 32) 2788c2ecf20Sopenharmony_ci return -EINVAL; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (!epc->ops->set_msi) 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci encode_int = order_base_2(interrupts); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 2868c2ecf20Sopenharmony_ci ret = epc->ops->set_msi(epc, func_no, encode_int); 2878c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return ret; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_set_msi); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/** 2948c2ecf20Sopenharmony_ci * pci_epc_get_msix() - get the number of MSI-X interrupt numbers allocated 2958c2ecf20Sopenharmony_ci * @epc: the EPC device to which MSI-X interrupts was requested 2968c2ecf20Sopenharmony_ci * @func_no: the endpoint function number in the EPC device 2978c2ecf20Sopenharmony_ci * 2988c2ecf20Sopenharmony_ci * Invoke to get the number of MSI-X interrupts allocated by the RC 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_ciint pci_epc_get_msix(struct pci_epc *epc, u8 func_no) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci int interrupt; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 3058c2ecf20Sopenharmony_ci return 0; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (!epc->ops->get_msix) 3088c2ecf20Sopenharmony_ci return 0; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 3118c2ecf20Sopenharmony_ci interrupt = epc->ops->get_msix(epc, func_no); 3128c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (interrupt < 0) 3158c2ecf20Sopenharmony_ci return 0; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return interrupt + 1; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_get_msix); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/** 3228c2ecf20Sopenharmony_ci * pci_epc_set_msix() - set the number of MSI-X interrupt numbers required 3238c2ecf20Sopenharmony_ci * @epc: the EPC device on which MSI-X has to be configured 3248c2ecf20Sopenharmony_ci * @func_no: the endpoint function number in the EPC device 3258c2ecf20Sopenharmony_ci * @interrupts: number of MSI-X interrupts required by the EPF 3268c2ecf20Sopenharmony_ci * @bir: BAR where the MSI-X table resides 3278c2ecf20Sopenharmony_ci * @offset: Offset pointing to the start of MSI-X table 3288c2ecf20Sopenharmony_ci * 3298c2ecf20Sopenharmony_ci * Invoke to set the required number of MSI-X interrupts. 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_ciint pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts, 3328c2ecf20Sopenharmony_ci enum pci_barno bir, u32 offset) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci int ret; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 3378c2ecf20Sopenharmony_ci interrupts < 1 || interrupts > 2048) 3388c2ecf20Sopenharmony_ci return -EINVAL; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (!epc->ops->set_msix) 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 3448c2ecf20Sopenharmony_ci ret = epc->ops->set_msix(epc, func_no, interrupts - 1, bir, offset); 3458c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return ret; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_set_msix); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/** 3528c2ecf20Sopenharmony_ci * pci_epc_unmap_addr() - unmap CPU address from PCI address 3538c2ecf20Sopenharmony_ci * @epc: the EPC device on which address is allocated 3548c2ecf20Sopenharmony_ci * @func_no: the endpoint function number in the EPC device 3558c2ecf20Sopenharmony_ci * @phys_addr: physical address of the local system 3568c2ecf20Sopenharmony_ci * 3578c2ecf20Sopenharmony_ci * Invoke to unmap the CPU address from PCI address. 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_civoid pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, 3608c2ecf20Sopenharmony_ci phys_addr_t phys_addr) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 3638c2ecf20Sopenharmony_ci return; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (!epc->ops->unmap_addr) 3668c2ecf20Sopenharmony_ci return; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 3698c2ecf20Sopenharmony_ci epc->ops->unmap_addr(epc, func_no, phys_addr); 3708c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_unmap_addr); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci/** 3758c2ecf20Sopenharmony_ci * pci_epc_map_addr() - map CPU address to PCI address 3768c2ecf20Sopenharmony_ci * @epc: the EPC device on which address is allocated 3778c2ecf20Sopenharmony_ci * @func_no: the endpoint function number in the EPC device 3788c2ecf20Sopenharmony_ci * @phys_addr: physical address of the local system 3798c2ecf20Sopenharmony_ci * @pci_addr: PCI address to which the physical address should be mapped 3808c2ecf20Sopenharmony_ci * @size: the size of the allocation 3818c2ecf20Sopenharmony_ci * 3828c2ecf20Sopenharmony_ci * Invoke to map CPU address with PCI address. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ciint pci_epc_map_addr(struct pci_epc *epc, u8 func_no, 3858c2ecf20Sopenharmony_ci phys_addr_t phys_addr, u64 pci_addr, size_t size) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci int ret; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 3908c2ecf20Sopenharmony_ci return -EINVAL; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (!epc->ops->map_addr) 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 3968c2ecf20Sopenharmony_ci ret = epc->ops->map_addr(epc, func_no, phys_addr, pci_addr, size); 3978c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return ret; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_map_addr); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci/** 4048c2ecf20Sopenharmony_ci * pci_epc_clear_bar() - reset the BAR 4058c2ecf20Sopenharmony_ci * @epc: the EPC device for which the BAR has to be cleared 4068c2ecf20Sopenharmony_ci * @func_no: the endpoint function number in the EPC device 4078c2ecf20Sopenharmony_ci * @epf_bar: the struct epf_bar that contains the BAR information 4088c2ecf20Sopenharmony_ci * 4098c2ecf20Sopenharmony_ci * Invoke to reset the BAR of the endpoint device. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_civoid pci_epc_clear_bar(struct pci_epc *epc, u8 func_no, 4128c2ecf20Sopenharmony_ci struct pci_epf_bar *epf_bar) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 4158c2ecf20Sopenharmony_ci (epf_bar->barno == BAR_5 && 4168c2ecf20Sopenharmony_ci epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) 4178c2ecf20Sopenharmony_ci return; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (!epc->ops->clear_bar) 4208c2ecf20Sopenharmony_ci return; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 4238c2ecf20Sopenharmony_ci epc->ops->clear_bar(epc, func_no, epf_bar); 4248c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_clear_bar); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci/** 4298c2ecf20Sopenharmony_ci * pci_epc_set_bar() - configure BAR in order for host to assign PCI addr space 4308c2ecf20Sopenharmony_ci * @epc: the EPC device on which BAR has to be configured 4318c2ecf20Sopenharmony_ci * @func_no: the endpoint function number in the EPC device 4328c2ecf20Sopenharmony_ci * @epf_bar: the struct epf_bar that contains the BAR information 4338c2ecf20Sopenharmony_ci * 4348c2ecf20Sopenharmony_ci * Invoke to configure the BAR of the endpoint device. 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_ciint pci_epc_set_bar(struct pci_epc *epc, u8 func_no, 4378c2ecf20Sopenharmony_ci struct pci_epf_bar *epf_bar) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci int ret; 4408c2ecf20Sopenharmony_ci int flags = epf_bar->flags; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 4438c2ecf20Sopenharmony_ci (epf_bar->barno == BAR_5 && 4448c2ecf20Sopenharmony_ci flags & PCI_BASE_ADDRESS_MEM_TYPE_64) || 4458c2ecf20Sopenharmony_ci (flags & PCI_BASE_ADDRESS_SPACE_IO && 4468c2ecf20Sopenharmony_ci flags & PCI_BASE_ADDRESS_IO_MASK) || 4478c2ecf20Sopenharmony_ci (upper_32_bits(epf_bar->size) && 4488c2ecf20Sopenharmony_ci !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64))) 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!epc->ops->set_bar) 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 4558c2ecf20Sopenharmony_ci ret = epc->ops->set_bar(epc, func_no, epf_bar); 4568c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return ret; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_set_bar); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci/** 4638c2ecf20Sopenharmony_ci * pci_epc_write_header() - write standard configuration header 4648c2ecf20Sopenharmony_ci * @epc: the EPC device to which the configuration header should be written 4658c2ecf20Sopenharmony_ci * @func_no: the endpoint function number in the EPC device 4668c2ecf20Sopenharmony_ci * @header: standard configuration header fields 4678c2ecf20Sopenharmony_ci * 4688c2ecf20Sopenharmony_ci * Invoke to write the configuration header to the endpoint controller. Every 4698c2ecf20Sopenharmony_ci * endpoint controller will have a dedicated location to which the standard 4708c2ecf20Sopenharmony_ci * configuration header would be written. The callback function should write 4718c2ecf20Sopenharmony_ci * the header fields to this dedicated location. 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ciint pci_epc_write_header(struct pci_epc *epc, u8 func_no, 4748c2ecf20Sopenharmony_ci struct pci_epf_header *header) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci int ret; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 4798c2ecf20Sopenharmony_ci return -EINVAL; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (!epc->ops->write_header) 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 4858c2ecf20Sopenharmony_ci ret = epc->ops->write_header(epc, func_no, header); 4868c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci return ret; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_write_header); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci/** 4938c2ecf20Sopenharmony_ci * pci_epc_add_epf() - bind PCI endpoint function to an endpoint controller 4948c2ecf20Sopenharmony_ci * @epc: the EPC device to which the endpoint function should be added 4958c2ecf20Sopenharmony_ci * @epf: the endpoint function to be added 4968c2ecf20Sopenharmony_ci * 4978c2ecf20Sopenharmony_ci * A PCI endpoint device can have one or more functions. In the case of PCIe, 4988c2ecf20Sopenharmony_ci * the specification allows up to 8 PCIe endpoint functions. Invoke 4998c2ecf20Sopenharmony_ci * pci_epc_add_epf() to add a PCI endpoint function to an endpoint controller. 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_ciint pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci u32 func_no; 5048c2ecf20Sopenharmony_ci int ret = 0; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (epf->epc) 5078c2ecf20Sopenharmony_ci return -EBUSY; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (IS_ERR(epc)) 5108c2ecf20Sopenharmony_ci return -EINVAL; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 5138c2ecf20Sopenharmony_ci func_no = find_first_zero_bit(&epc->function_num_map, 5148c2ecf20Sopenharmony_ci BITS_PER_LONG); 5158c2ecf20Sopenharmony_ci if (func_no >= BITS_PER_LONG) { 5168c2ecf20Sopenharmony_ci ret = -EINVAL; 5178c2ecf20Sopenharmony_ci goto ret; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (func_no > epc->max_functions - 1) { 5218c2ecf20Sopenharmony_ci dev_err(&epc->dev, "Exceeding max supported Function Number\n"); 5228c2ecf20Sopenharmony_ci ret = -EINVAL; 5238c2ecf20Sopenharmony_ci goto ret; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci set_bit(func_no, &epc->function_num_map); 5278c2ecf20Sopenharmony_ci epf->func_no = func_no; 5288c2ecf20Sopenharmony_ci epf->epc = epc; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci list_add_tail(&epf->list, &epc->pci_epf); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ciret: 5338c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci return ret; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_add_epf); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci/** 5408c2ecf20Sopenharmony_ci * pci_epc_remove_epf() - remove PCI endpoint function from endpoint controller 5418c2ecf20Sopenharmony_ci * @epc: the EPC device from which the endpoint function should be removed 5428c2ecf20Sopenharmony_ci * @epf: the endpoint function to be removed 5438c2ecf20Sopenharmony_ci * 5448c2ecf20Sopenharmony_ci * Invoke to remove PCI endpoint function from the endpoint controller. 5458c2ecf20Sopenharmony_ci */ 5468c2ecf20Sopenharmony_civoid pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci if (!epc || IS_ERR(epc) || !epf) 5498c2ecf20Sopenharmony_ci return; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci mutex_lock(&epc->lock); 5528c2ecf20Sopenharmony_ci clear_bit(epf->func_no, &epc->function_num_map); 5538c2ecf20Sopenharmony_ci list_del(&epf->list); 5548c2ecf20Sopenharmony_ci epf->epc = NULL; 5558c2ecf20Sopenharmony_ci mutex_unlock(&epc->lock); 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_remove_epf); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/** 5608c2ecf20Sopenharmony_ci * pci_epc_linkup() - Notify the EPF device that EPC device has established a 5618c2ecf20Sopenharmony_ci * connection with the Root Complex. 5628c2ecf20Sopenharmony_ci * @epc: the EPC device which has established link with the host 5638c2ecf20Sopenharmony_ci * 5648c2ecf20Sopenharmony_ci * Invoke to Notify the EPF device that the EPC device has established a 5658c2ecf20Sopenharmony_ci * connection with the Root Complex. 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_civoid pci_epc_linkup(struct pci_epc *epc) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci if (!epc || IS_ERR(epc)) 5708c2ecf20Sopenharmony_ci return; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci atomic_notifier_call_chain(&epc->notifier, LINK_UP, NULL); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_linkup); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci/** 5778c2ecf20Sopenharmony_ci * pci_epc_init_notify() - Notify the EPF device that EPC device's core 5788c2ecf20Sopenharmony_ci * initialization is completed. 5798c2ecf20Sopenharmony_ci * @epc: the EPC device whose core initialization is completeds 5808c2ecf20Sopenharmony_ci * 5818c2ecf20Sopenharmony_ci * Invoke to Notify the EPF device that the EPC device's initialization 5828c2ecf20Sopenharmony_ci * is completed. 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_civoid pci_epc_init_notify(struct pci_epc *epc) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci if (!epc || IS_ERR(epc)) 5878c2ecf20Sopenharmony_ci return; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci atomic_notifier_call_chain(&epc->notifier, CORE_INIT, NULL); 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_init_notify); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/** 5948c2ecf20Sopenharmony_ci * pci_epc_destroy() - destroy the EPC device 5958c2ecf20Sopenharmony_ci * @epc: the EPC device that has to be destroyed 5968c2ecf20Sopenharmony_ci * 5978c2ecf20Sopenharmony_ci * Invoke to destroy the PCI EPC device 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_civoid pci_epc_destroy(struct pci_epc *epc) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci pci_ep_cfs_remove_epc_group(epc->group); 6028c2ecf20Sopenharmony_ci device_unregister(&epc->dev); 6038c2ecf20Sopenharmony_ci kfree(epc); 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_epc_destroy); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci/** 6088c2ecf20Sopenharmony_ci * devm_pci_epc_destroy() - destroy the EPC device 6098c2ecf20Sopenharmony_ci * @dev: device that wants to destroy the EPC 6108c2ecf20Sopenharmony_ci * @epc: the EPC device that has to be destroyed 6118c2ecf20Sopenharmony_ci * 6128c2ecf20Sopenharmony_ci * Invoke to destroy the devres associated with this 6138c2ecf20Sopenharmony_ci * pci_epc and destroy the EPC device. 6148c2ecf20Sopenharmony_ci */ 6158c2ecf20Sopenharmony_civoid devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci int r; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci r = devres_destroy(dev, devm_pci_epc_release, devm_pci_epc_match, 6208c2ecf20Sopenharmony_ci epc); 6218c2ecf20Sopenharmony_ci dev_WARN_ONCE(dev, r, "couldn't find PCI EPC resource\n"); 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_pci_epc_destroy); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci/** 6268c2ecf20Sopenharmony_ci * __pci_epc_create() - create a new endpoint controller (EPC) device 6278c2ecf20Sopenharmony_ci * @dev: device that is creating the new EPC 6288c2ecf20Sopenharmony_ci * @ops: function pointers for performing EPC operations 6298c2ecf20Sopenharmony_ci * @owner: the owner of the module that creates the EPC device 6308c2ecf20Sopenharmony_ci * 6318c2ecf20Sopenharmony_ci * Invoke to create a new EPC device and add it to pci_epc class. 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_cistruct pci_epc * 6348c2ecf20Sopenharmony_ci__pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, 6358c2ecf20Sopenharmony_ci struct module *owner) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci int ret; 6388c2ecf20Sopenharmony_ci struct pci_epc *epc; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (WARN_ON(!dev)) { 6418c2ecf20Sopenharmony_ci ret = -EINVAL; 6428c2ecf20Sopenharmony_ci goto err_ret; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci epc = kzalloc(sizeof(*epc), GFP_KERNEL); 6468c2ecf20Sopenharmony_ci if (!epc) { 6478c2ecf20Sopenharmony_ci ret = -ENOMEM; 6488c2ecf20Sopenharmony_ci goto err_ret; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci mutex_init(&epc->lock); 6528c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&epc->pci_epf); 6538c2ecf20Sopenharmony_ci ATOMIC_INIT_NOTIFIER_HEAD(&epc->notifier); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci device_initialize(&epc->dev); 6568c2ecf20Sopenharmony_ci epc->dev.class = pci_epc_class; 6578c2ecf20Sopenharmony_ci epc->dev.parent = dev; 6588c2ecf20Sopenharmony_ci epc->ops = ops; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci ret = dev_set_name(&epc->dev, "%s", dev_name(dev)); 6618c2ecf20Sopenharmony_ci if (ret) 6628c2ecf20Sopenharmony_ci goto put_dev; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci ret = device_add(&epc->dev); 6658c2ecf20Sopenharmony_ci if (ret) 6668c2ecf20Sopenharmony_ci goto put_dev; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci epc->group = pci_ep_cfs_add_epc_group(dev_name(dev)); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci return epc; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ciput_dev: 6738c2ecf20Sopenharmony_ci put_device(&epc->dev); 6748c2ecf20Sopenharmony_ci kfree(epc); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cierr_ret: 6778c2ecf20Sopenharmony_ci return ERR_PTR(ret); 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__pci_epc_create); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci/** 6828c2ecf20Sopenharmony_ci * __devm_pci_epc_create() - create a new endpoint controller (EPC) device 6838c2ecf20Sopenharmony_ci * @dev: device that is creating the new EPC 6848c2ecf20Sopenharmony_ci * @ops: function pointers for performing EPC operations 6858c2ecf20Sopenharmony_ci * @owner: the owner of the module that creates the EPC device 6868c2ecf20Sopenharmony_ci * 6878c2ecf20Sopenharmony_ci * Invoke to create a new EPC device and add it to pci_epc class. 6888c2ecf20Sopenharmony_ci * While at that, it also associates the device with the pci_epc using devres. 6898c2ecf20Sopenharmony_ci * On driver detach, release function is invoked on the devres data, 6908c2ecf20Sopenharmony_ci * then, devres data is freed. 6918c2ecf20Sopenharmony_ci */ 6928c2ecf20Sopenharmony_cistruct pci_epc * 6938c2ecf20Sopenharmony_ci__devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, 6948c2ecf20Sopenharmony_ci struct module *owner) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci struct pci_epc **ptr, *epc; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci ptr = devres_alloc(devm_pci_epc_release, sizeof(*ptr), GFP_KERNEL); 6998c2ecf20Sopenharmony_ci if (!ptr) 7008c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci epc = __pci_epc_create(dev, ops, owner); 7038c2ecf20Sopenharmony_ci if (!IS_ERR(epc)) { 7048c2ecf20Sopenharmony_ci *ptr = epc; 7058c2ecf20Sopenharmony_ci devres_add(dev, ptr); 7068c2ecf20Sopenharmony_ci } else { 7078c2ecf20Sopenharmony_ci devres_free(ptr); 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci return epc; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__devm_pci_epc_create); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic int __init pci_epc_init(void) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci pci_epc_class = class_create(THIS_MODULE, "pci_epc"); 7178c2ecf20Sopenharmony_ci if (IS_ERR(pci_epc_class)) { 7188c2ecf20Sopenharmony_ci pr_err("failed to create pci epc class --> %ld\n", 7198c2ecf20Sopenharmony_ci PTR_ERR(pci_epc_class)); 7208c2ecf20Sopenharmony_ci return PTR_ERR(pci_epc_class); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci return 0; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_cimodule_init(pci_epc_init); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic void __exit pci_epc_exit(void) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci class_destroy(pci_epc_class); 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_cimodule_exit(pci_epc_exit); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCI EPC Library"); 7348c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); 7358c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 736