18cfab3cfSBjorn Helgaas // SPDX-License-Identifier: GPL-2.0 29b41d19aSKrzysztof Kozlowski /* 35e8cb403SKishon Vijay Abraham I * PCI Endpoint *Controller* (EPC) library 45e8cb403SKishon Vijay Abraham I * 55e8cb403SKishon Vijay Abraham I * Copyright (C) 2017 Texas Instruments 65e8cb403SKishon Vijay Abraham I * Author: Kishon Vijay Abraham I <kishon@ti.com> 75e8cb403SKishon Vijay Abraham I */ 85e8cb403SKishon Vijay Abraham I 95e8cb403SKishon Vijay Abraham I #include <linux/device.h> 105e8cb403SKishon Vijay Abraham I #include <linux/slab.h> 115e8cb403SKishon Vijay Abraham I #include <linux/module.h> 1264c1a02aSKishon Vijay Abraham I #include <linux/of_device.h> 135e8cb403SKishon Vijay Abraham I 145e8cb403SKishon Vijay Abraham I #include <linux/pci-epc.h> 155e8cb403SKishon Vijay Abraham I #include <linux/pci-epf.h> 163a401a2cSKishon Vijay Abraham I #include <linux/pci-ep-cfs.h> 175e8cb403SKishon Vijay Abraham I 185e8cb403SKishon Vijay Abraham I static struct class *pci_epc_class; 195e8cb403SKishon Vijay Abraham I 205e8cb403SKishon Vijay Abraham I static void devm_pci_epc_release(struct device *dev, void *res) 215e8cb403SKishon Vijay Abraham I { 225e8cb403SKishon Vijay Abraham I struct pci_epc *epc = *(struct pci_epc **)res; 235e8cb403SKishon Vijay Abraham I 245e8cb403SKishon Vijay Abraham I pci_epc_destroy(epc); 255e8cb403SKishon Vijay Abraham I } 265e8cb403SKishon Vijay Abraham I 275e8cb403SKishon Vijay Abraham I static int devm_pci_epc_match(struct device *dev, void *res, void *match_data) 285e8cb403SKishon Vijay Abraham I { 295e8cb403SKishon Vijay Abraham I struct pci_epc **epc = res; 305e8cb403SKishon Vijay Abraham I 315e8cb403SKishon Vijay Abraham I return *epc == match_data; 325e8cb403SKishon Vijay Abraham I } 335e8cb403SKishon Vijay Abraham I 345e8cb403SKishon Vijay Abraham I /** 355e8cb403SKishon Vijay Abraham I * pci_epc_put() - release the PCI endpoint controller 365e8cb403SKishon Vijay Abraham I * @epc: epc returned by pci_epc_get() 375e8cb403SKishon Vijay Abraham I * 385e8cb403SKishon Vijay Abraham I * release the refcount the caller obtained by invoking pci_epc_get() 395e8cb403SKishon Vijay Abraham I */ 405e8cb403SKishon Vijay Abraham I void pci_epc_put(struct pci_epc *epc) 415e8cb403SKishon Vijay Abraham I { 425e8cb403SKishon Vijay Abraham I if (!epc || IS_ERR(epc)) 435e8cb403SKishon Vijay Abraham I return; 445e8cb403SKishon Vijay Abraham I 455e8cb403SKishon Vijay Abraham I module_put(epc->ops->owner); 465e8cb403SKishon Vijay Abraham I put_device(&epc->dev); 475e8cb403SKishon Vijay Abraham I } 485e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_put); 495e8cb403SKishon Vijay Abraham I 505e8cb403SKishon Vijay Abraham I /** 515e8cb403SKishon Vijay Abraham I * pci_epc_get() - get the PCI endpoint controller 525e8cb403SKishon Vijay Abraham I * @epc_name: device name of the endpoint controller 535e8cb403SKishon Vijay Abraham I * 545e8cb403SKishon Vijay Abraham I * Invoke to get struct pci_epc * corresponding to the device name of the 555e8cb403SKishon Vijay Abraham I * endpoint controller 565e8cb403SKishon Vijay Abraham I */ 575e8cb403SKishon Vijay Abraham I struct pci_epc *pci_epc_get(const char *epc_name) 585e8cb403SKishon Vijay Abraham I { 595e8cb403SKishon Vijay Abraham I int ret = -EINVAL; 605e8cb403SKishon Vijay Abraham I struct pci_epc *epc; 615e8cb403SKishon Vijay Abraham I struct device *dev; 625e8cb403SKishon Vijay Abraham I struct class_dev_iter iter; 635e8cb403SKishon Vijay Abraham I 645e8cb403SKishon Vijay Abraham I class_dev_iter_init(&iter, pci_epc_class, NULL, NULL); 655e8cb403SKishon Vijay Abraham I while ((dev = class_dev_iter_next(&iter))) { 665e8cb403SKishon Vijay Abraham I if (strcmp(epc_name, dev_name(dev))) 675e8cb403SKishon Vijay Abraham I continue; 685e8cb403SKishon Vijay Abraham I 695e8cb403SKishon Vijay Abraham I epc = to_pci_epc(dev); 705e8cb403SKishon Vijay Abraham I if (!try_module_get(epc->ops->owner)) { 715e8cb403SKishon Vijay Abraham I ret = -EINVAL; 725e8cb403SKishon Vijay Abraham I goto err; 735e8cb403SKishon Vijay Abraham I } 745e8cb403SKishon Vijay Abraham I 755e8cb403SKishon Vijay Abraham I class_dev_iter_exit(&iter); 765e8cb403SKishon Vijay Abraham I get_device(&epc->dev); 775e8cb403SKishon Vijay Abraham I return epc; 785e8cb403SKishon Vijay Abraham I } 795e8cb403SKishon Vijay Abraham I 805e8cb403SKishon Vijay Abraham I err: 815e8cb403SKishon Vijay Abraham I class_dev_iter_exit(&iter); 825e8cb403SKishon Vijay Abraham I return ERR_PTR(ret); 835e8cb403SKishon Vijay Abraham I } 845e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_get); 855e8cb403SKishon Vijay Abraham I 865e8cb403SKishon Vijay Abraham I /** 871e9efe6cSKishon Vijay Abraham I * pci_epc_get_first_free_bar() - helper to get first unreserved BAR 881e9efe6cSKishon Vijay Abraham I * @epc_features: pci_epc_features structure that holds the reserved bar bitmap 891e9efe6cSKishon Vijay Abraham I * 90fa8fef0eSKishon Vijay Abraham I * Invoke to get the first unreserved BAR that can be used by the endpoint 911e9efe6cSKishon Vijay Abraham I * function. For any incorrect value in reserved_bar return '0'. 921e9efe6cSKishon Vijay Abraham I */ 930e27aeccSKishon Vijay Abraham I enum pci_barno 940e27aeccSKishon Vijay Abraham I pci_epc_get_first_free_bar(const struct pci_epc_features *epc_features) 951e9efe6cSKishon Vijay Abraham I { 96fa8fef0eSKishon Vijay Abraham I return pci_epc_get_next_free_bar(epc_features, BAR_0); 97fa8fef0eSKishon Vijay Abraham I } 98fa8fef0eSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_get_first_free_bar); 99fa8fef0eSKishon Vijay Abraham I 100fa8fef0eSKishon Vijay Abraham I /** 101fa8fef0eSKishon Vijay Abraham I * pci_epc_get_next_free_bar() - helper to get unreserved BAR starting from @bar 102fa8fef0eSKishon Vijay Abraham I * @epc_features: pci_epc_features structure that holds the reserved bar bitmap 103fa8fef0eSKishon Vijay Abraham I * @bar: the starting BAR number from where unreserved BAR should be searched 104fa8fef0eSKishon Vijay Abraham I * 105fa8fef0eSKishon Vijay Abraham I * Invoke to get the next unreserved BAR starting from @bar that can be used 106fa8fef0eSKishon Vijay Abraham I * for endpoint function. For any incorrect value in reserved_bar return '0'. 107fa8fef0eSKishon Vijay Abraham I */ 1080e27aeccSKishon Vijay Abraham I enum pci_barno pci_epc_get_next_free_bar(const struct pci_epc_features 109fa8fef0eSKishon Vijay Abraham I *epc_features, enum pci_barno bar) 110fa8fef0eSKishon Vijay Abraham I { 111959a48d0SKishon Vijay Abraham I unsigned long free_bar; 1121e9efe6cSKishon Vijay Abraham I 1131e9efe6cSKishon Vijay Abraham I if (!epc_features) 1140e27aeccSKishon Vijay Abraham I return BAR_0; 1151e9efe6cSKishon Vijay Abraham I 116fa8fef0eSKishon Vijay Abraham I /* If 'bar - 1' is a 64-bit BAR, move to the next BAR */ 117fa8fef0eSKishon Vijay Abraham I if ((epc_features->bar_fixed_64bit << 1) & 1 << bar) 118fa8fef0eSKishon Vijay Abraham I bar++; 119fa8fef0eSKishon Vijay Abraham I 120959a48d0SKishon Vijay Abraham I /* Find if the reserved BAR is also a 64-bit BAR */ 121959a48d0SKishon Vijay Abraham I free_bar = epc_features->reserved_bar & epc_features->bar_fixed_64bit; 122959a48d0SKishon Vijay Abraham I 123959a48d0SKishon Vijay Abraham I /* Set the adjacent bit if the reserved BAR is also a 64-bit BAR */ 124959a48d0SKishon Vijay Abraham I free_bar <<= 1; 125959a48d0SKishon Vijay Abraham I free_bar |= epc_features->reserved_bar; 126959a48d0SKishon Vijay Abraham I 127fa8fef0eSKishon Vijay Abraham I free_bar = find_next_zero_bit(&free_bar, 6, bar); 1281e9efe6cSKishon Vijay Abraham I if (free_bar > 5) 1290e27aeccSKishon Vijay Abraham I return NO_BAR; 1301e9efe6cSKishon Vijay Abraham I 1311e9efe6cSKishon Vijay Abraham I return free_bar; 1321e9efe6cSKishon Vijay Abraham I } 133fa8fef0eSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_get_next_free_bar); 1341e9efe6cSKishon Vijay Abraham I 1351e9efe6cSKishon Vijay Abraham I /** 13641cb8d18SKishon Vijay Abraham I * pci_epc_get_features() - get the features supported by EPC 13741cb8d18SKishon Vijay Abraham I * @epc: the features supported by *this* EPC device will be returned 13841cb8d18SKishon Vijay Abraham I * @func_no: the features supported by the EPC device specific to the 13941cb8d18SKishon Vijay Abraham I * endpoint function with func_no will be returned 14053fd3cbeSKishon Vijay Abraham I * @vfunc_no: the features supported by the EPC device specific to the 14153fd3cbeSKishon Vijay Abraham I * virtual endpoint function with vfunc_no will be returned 14241cb8d18SKishon Vijay Abraham I * 14341cb8d18SKishon Vijay Abraham I * Invoke to get the features provided by the EPC which may be 14441cb8d18SKishon Vijay Abraham I * specific to an endpoint function. Returns pci_epc_features on success 14541cb8d18SKishon Vijay Abraham I * and NULL for any failures. 14641cb8d18SKishon Vijay Abraham I */ 14741cb8d18SKishon Vijay Abraham I const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc, 14853fd3cbeSKishon Vijay Abraham I u8 func_no, u8 vfunc_no) 14941cb8d18SKishon Vijay Abraham I { 15041cb8d18SKishon Vijay Abraham I const struct pci_epc_features *epc_features; 15141cb8d18SKishon Vijay Abraham I 15241cb8d18SKishon Vijay Abraham I if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 15341cb8d18SKishon Vijay Abraham I return NULL; 15441cb8d18SKishon Vijay Abraham I 15553fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 15653fd3cbeSKishon Vijay Abraham I return NULL; 15753fd3cbeSKishon Vijay Abraham I 15841cb8d18SKishon Vijay Abraham I if (!epc->ops->get_features) 15941cb8d18SKishon Vijay Abraham I return NULL; 16041cb8d18SKishon Vijay Abraham I 1613d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 16253fd3cbeSKishon Vijay Abraham I epc_features = epc->ops->get_features(epc, func_no, vfunc_no); 1633d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 16441cb8d18SKishon Vijay Abraham I 16541cb8d18SKishon Vijay Abraham I return epc_features; 16641cb8d18SKishon Vijay Abraham I } 16741cb8d18SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_get_features); 16841cb8d18SKishon Vijay Abraham I 16941cb8d18SKishon Vijay Abraham I /** 1705e8cb403SKishon Vijay Abraham I * pci_epc_stop() - stop the PCI link 1715e8cb403SKishon Vijay Abraham I * @epc: the link of the EPC device that has to be stopped 1725e8cb403SKishon Vijay Abraham I * 1735e8cb403SKishon Vijay Abraham I * Invoke to stop the PCI link 1745e8cb403SKishon Vijay Abraham I */ 1755e8cb403SKishon Vijay Abraham I void pci_epc_stop(struct pci_epc *epc) 1765e8cb403SKishon Vijay Abraham I { 1775e8cb403SKishon Vijay Abraham I if (IS_ERR(epc) || !epc->ops->stop) 1785e8cb403SKishon Vijay Abraham I return; 1795e8cb403SKishon Vijay Abraham I 1803d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 1815e8cb403SKishon Vijay Abraham I epc->ops->stop(epc); 1823d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 1835e8cb403SKishon Vijay Abraham I } 1845e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_stop); 1855e8cb403SKishon Vijay Abraham I 1865e8cb403SKishon Vijay Abraham I /** 1875e8cb403SKishon Vijay Abraham I * pci_epc_start() - start the PCI link 1885e8cb403SKishon Vijay Abraham I * @epc: the link of *this* EPC device has to be started 1895e8cb403SKishon Vijay Abraham I * 1905e8cb403SKishon Vijay Abraham I * Invoke to start the PCI link 1915e8cb403SKishon Vijay Abraham I */ 1925e8cb403SKishon Vijay Abraham I int pci_epc_start(struct pci_epc *epc) 1935e8cb403SKishon Vijay Abraham I { 1945e8cb403SKishon Vijay Abraham I int ret; 1955e8cb403SKishon Vijay Abraham I 1965e8cb403SKishon Vijay Abraham I if (IS_ERR(epc)) 1975e8cb403SKishon Vijay Abraham I return -EINVAL; 1985e8cb403SKishon Vijay Abraham I 1995e8cb403SKishon Vijay Abraham I if (!epc->ops->start) 2005e8cb403SKishon Vijay Abraham I return 0; 2015e8cb403SKishon Vijay Abraham I 2023d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 2035e8cb403SKishon Vijay Abraham I ret = epc->ops->start(epc); 2043d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 2055e8cb403SKishon Vijay Abraham I 2065e8cb403SKishon Vijay Abraham I return ret; 2075e8cb403SKishon Vijay Abraham I } 2085e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_start); 2095e8cb403SKishon Vijay Abraham I 2105e8cb403SKishon Vijay Abraham I /** 2115e8cb403SKishon Vijay Abraham I * pci_epc_raise_irq() - interrupt the host system 2125e8cb403SKishon Vijay Abraham I * @epc: the EPC device which has to interrupt the host 21353fd3cbeSKishon Vijay Abraham I * @func_no: the physical endpoint function number in the EPC device 21453fd3cbeSKishon Vijay Abraham I * @vfunc_no: the virtual endpoint function number in the physical function 215d3c70a98SGustavo Pimentel * @type: specify the type of interrupt; legacy, MSI or MSI-X 216d3c70a98SGustavo Pimentel * @interrupt_num: the MSI or MSI-X interrupt number 2175e8cb403SKishon Vijay Abraham I * 218d3c70a98SGustavo Pimentel * Invoke to raise an legacy, MSI or MSI-X interrupt 2195e8cb403SKishon Vijay Abraham I */ 22053fd3cbeSKishon Vijay Abraham I int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 221d3c70a98SGustavo Pimentel enum pci_epc_irq_type type, u16 interrupt_num) 2225e8cb403SKishon Vijay Abraham I { 2235e8cb403SKishon Vijay Abraham I int ret; 2245e8cb403SKishon Vijay Abraham I 2254494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 2265e8cb403SKishon Vijay Abraham I return -EINVAL; 2275e8cb403SKishon Vijay Abraham I 22853fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 22953fd3cbeSKishon Vijay Abraham I return -EINVAL; 23053fd3cbeSKishon Vijay Abraham I 2315e8cb403SKishon Vijay Abraham I if (!epc->ops->raise_irq) 2325e8cb403SKishon Vijay Abraham I return 0; 2335e8cb403SKishon Vijay Abraham I 2343d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 23553fd3cbeSKishon Vijay Abraham I ret = epc->ops->raise_irq(epc, func_no, vfunc_no, type, interrupt_num); 2363d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 2375e8cb403SKishon Vijay Abraham I 2385e8cb403SKishon Vijay Abraham I return ret; 2395e8cb403SKishon Vijay Abraham I } 2405e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_raise_irq); 2415e8cb403SKishon Vijay Abraham I 2425e8cb403SKishon Vijay Abraham I /** 24387d5972eSKishon Vijay Abraham I * pci_epc_map_msi_irq() - Map physical address to MSI address and return 24487d5972eSKishon Vijay Abraham I * MSI data 24587d5972eSKishon Vijay Abraham I * @epc: the EPC device which has the MSI capability 24687d5972eSKishon Vijay Abraham I * @func_no: the physical endpoint function number in the EPC device 24753fd3cbeSKishon Vijay Abraham I * @vfunc_no: the virtual endpoint function number in the physical function 24887d5972eSKishon Vijay Abraham I * @phys_addr: the physical address of the outbound region 24987d5972eSKishon Vijay Abraham I * @interrupt_num: the MSI interrupt number 25087d5972eSKishon Vijay Abraham I * @entry_size: Size of Outbound address region for each interrupt 25187d5972eSKishon Vijay Abraham I * @msi_data: the data that should be written in order to raise MSI interrupt 25287d5972eSKishon Vijay Abraham I * with interrupt number as 'interrupt num' 25387d5972eSKishon Vijay Abraham I * @msi_addr_offset: Offset of MSI address from the aligned outbound address 25487d5972eSKishon Vijay Abraham I * to which the MSI address is mapped 25587d5972eSKishon Vijay Abraham I * 25687d5972eSKishon Vijay Abraham I * Invoke to map physical address to MSI address and return MSI data. The 25787d5972eSKishon Vijay Abraham I * physical address should be an address in the outbound region. This is 25887d5972eSKishon Vijay Abraham I * required to implement doorbell functionality of NTB wherein EPC on either 25987d5972eSKishon Vijay Abraham I * side of the interface (primary and secondary) can directly write to the 26087d5972eSKishon Vijay Abraham I * physical address (in outbound region) of the other interface to ring 26187d5972eSKishon Vijay Abraham I * doorbell. 26287d5972eSKishon Vijay Abraham I */ 26353fd3cbeSKishon Vijay Abraham I int pci_epc_map_msi_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 26453fd3cbeSKishon Vijay Abraham I phys_addr_t phys_addr, u8 interrupt_num, u32 entry_size, 26553fd3cbeSKishon Vijay Abraham I u32 *msi_data, u32 *msi_addr_offset) 26687d5972eSKishon Vijay Abraham I { 26787d5972eSKishon Vijay Abraham I int ret; 26887d5972eSKishon Vijay Abraham I 26987d5972eSKishon Vijay Abraham I if (IS_ERR_OR_NULL(epc)) 27087d5972eSKishon Vijay Abraham I return -EINVAL; 27187d5972eSKishon Vijay Abraham I 27253fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 27353fd3cbeSKishon Vijay Abraham I return -EINVAL; 27453fd3cbeSKishon Vijay Abraham I 27587d5972eSKishon Vijay Abraham I if (!epc->ops->map_msi_irq) 27687d5972eSKishon Vijay Abraham I return -EINVAL; 27787d5972eSKishon Vijay Abraham I 27887d5972eSKishon Vijay Abraham I mutex_lock(&epc->lock); 27953fd3cbeSKishon Vijay Abraham I ret = epc->ops->map_msi_irq(epc, func_no, vfunc_no, phys_addr, 28053fd3cbeSKishon Vijay Abraham I interrupt_num, entry_size, msi_data, 28153fd3cbeSKishon Vijay Abraham I msi_addr_offset); 28287d5972eSKishon Vijay Abraham I mutex_unlock(&epc->lock); 28387d5972eSKishon Vijay Abraham I 28487d5972eSKishon Vijay Abraham I return ret; 28587d5972eSKishon Vijay Abraham I } 28687d5972eSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_map_msi_irq); 28787d5972eSKishon Vijay Abraham I 28887d5972eSKishon Vijay Abraham I /** 2895e8cb403SKishon Vijay Abraham I * pci_epc_get_msi() - get the number of MSI interrupt numbers allocated 2905e8cb403SKishon Vijay Abraham I * @epc: the EPC device to which MSI interrupts was requested 29153fd3cbeSKishon Vijay Abraham I * @func_no: the physical endpoint function number in the EPC device 29253fd3cbeSKishon Vijay Abraham I * @vfunc_no: the virtual endpoint function number in the physical function 2935e8cb403SKishon Vijay Abraham I * 2945e8cb403SKishon Vijay Abraham I * Invoke to get the number of MSI interrupts allocated by the RC 2955e8cb403SKishon Vijay Abraham I */ 29653fd3cbeSKishon Vijay Abraham I int pci_epc_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no) 2975e8cb403SKishon Vijay Abraham I { 2985e8cb403SKishon Vijay Abraham I int interrupt; 2995e8cb403SKishon Vijay Abraham I 3004494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 3015e8cb403SKishon Vijay Abraham I return 0; 3025e8cb403SKishon Vijay Abraham I 30353fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 30453fd3cbeSKishon Vijay Abraham I return 0; 30553fd3cbeSKishon Vijay Abraham I 3065e8cb403SKishon Vijay Abraham I if (!epc->ops->get_msi) 3075e8cb403SKishon Vijay Abraham I return 0; 3085e8cb403SKishon Vijay Abraham I 3093d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 31053fd3cbeSKishon Vijay Abraham I interrupt = epc->ops->get_msi(epc, func_no, vfunc_no); 3113d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 3125e8cb403SKishon Vijay Abraham I 3135e8cb403SKishon Vijay Abraham I if (interrupt < 0) 3145e8cb403SKishon Vijay Abraham I return 0; 3155e8cb403SKishon Vijay Abraham I 3165e8cb403SKishon Vijay Abraham I interrupt = 1 << interrupt; 3175e8cb403SKishon Vijay Abraham I 3185e8cb403SKishon Vijay Abraham I return interrupt; 3195e8cb403SKishon Vijay Abraham I } 3205e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_get_msi); 3215e8cb403SKishon Vijay Abraham I 3225e8cb403SKishon Vijay Abraham I /** 3235e8cb403SKishon Vijay Abraham I * pci_epc_set_msi() - set the number of MSI interrupt numbers required 3245e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which MSI has to be configured 32553fd3cbeSKishon Vijay Abraham I * @func_no: the physical endpoint function number in the EPC device 32653fd3cbeSKishon Vijay Abraham I * @vfunc_no: the virtual endpoint function number in the physical function 3275e8cb403SKishon Vijay Abraham I * @interrupts: number of MSI interrupts required by the EPF 3285e8cb403SKishon Vijay Abraham I * 3295e8cb403SKishon Vijay Abraham I * Invoke to set the required number of MSI interrupts. 3305e8cb403SKishon Vijay Abraham I */ 33153fd3cbeSKishon Vijay Abraham I int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u8 interrupts) 3325e8cb403SKishon Vijay Abraham I { 3335e8cb403SKishon Vijay Abraham I int ret; 3345e8cb403SKishon Vijay Abraham I u8 encode_int; 3355e8cb403SKishon Vijay Abraham I 33615c972dfSGustavo Pimentel if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 33750b62030SLi Chen interrupts < 1 || interrupts > 32) 3385e8cb403SKishon Vijay Abraham I return -EINVAL; 3395e8cb403SKishon Vijay Abraham I 34053fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 34153fd3cbeSKishon Vijay Abraham I return -EINVAL; 34253fd3cbeSKishon Vijay Abraham I 3435e8cb403SKishon Vijay Abraham I if (!epc->ops->set_msi) 3445e8cb403SKishon Vijay Abraham I return 0; 3455e8cb403SKishon Vijay Abraham I 3465e8cb403SKishon Vijay Abraham I encode_int = order_base_2(interrupts); 3475e8cb403SKishon Vijay Abraham I 3483d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 34953fd3cbeSKishon Vijay Abraham I ret = epc->ops->set_msi(epc, func_no, vfunc_no, encode_int); 3503d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 3515e8cb403SKishon Vijay Abraham I 3525e8cb403SKishon Vijay Abraham I return ret; 3535e8cb403SKishon Vijay Abraham I } 3545e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_set_msi); 3555e8cb403SKishon Vijay Abraham I 3565e8cb403SKishon Vijay Abraham I /** 3578963106eSGustavo Pimentel * pci_epc_get_msix() - get the number of MSI-X interrupt numbers allocated 3588963106eSGustavo Pimentel * @epc: the EPC device to which MSI-X interrupts was requested 35953fd3cbeSKishon Vijay Abraham I * @func_no: the physical endpoint function number in the EPC device 36053fd3cbeSKishon Vijay Abraham I * @vfunc_no: the virtual endpoint function number in the physical function 3618963106eSGustavo Pimentel * 3628963106eSGustavo Pimentel * Invoke to get the number of MSI-X interrupts allocated by the RC 3638963106eSGustavo Pimentel */ 36453fd3cbeSKishon Vijay Abraham I int pci_epc_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) 3658963106eSGustavo Pimentel { 3668963106eSGustavo Pimentel int interrupt; 3678963106eSGustavo Pimentel 3688963106eSGustavo Pimentel if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 3698963106eSGustavo Pimentel return 0; 3708963106eSGustavo Pimentel 37153fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 37253fd3cbeSKishon Vijay Abraham I return 0; 37353fd3cbeSKishon Vijay Abraham I 3748963106eSGustavo Pimentel if (!epc->ops->get_msix) 3758963106eSGustavo Pimentel return 0; 3768963106eSGustavo Pimentel 3773d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 37853fd3cbeSKishon Vijay Abraham I interrupt = epc->ops->get_msix(epc, func_no, vfunc_no); 3793d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 3808963106eSGustavo Pimentel 3818963106eSGustavo Pimentel if (interrupt < 0) 3828963106eSGustavo Pimentel return 0; 3838963106eSGustavo Pimentel 3848963106eSGustavo Pimentel return interrupt + 1; 3858963106eSGustavo Pimentel } 3868963106eSGustavo Pimentel EXPORT_SYMBOL_GPL(pci_epc_get_msix); 3878963106eSGustavo Pimentel 3888963106eSGustavo Pimentel /** 3898963106eSGustavo Pimentel * pci_epc_set_msix() - set the number of MSI-X interrupt numbers required 3908963106eSGustavo Pimentel * @epc: the EPC device on which MSI-X has to be configured 39153fd3cbeSKishon Vijay Abraham I * @func_no: the physical endpoint function number in the EPC device 39253fd3cbeSKishon Vijay Abraham I * @vfunc_no: the virtual endpoint function number in the physical function 3938963106eSGustavo Pimentel * @interrupts: number of MSI-X interrupts required by the EPF 39483153d9fSKishon Vijay Abraham I * @bir: BAR where the MSI-X table resides 39583153d9fSKishon Vijay Abraham I * @offset: Offset pointing to the start of MSI-X table 3968963106eSGustavo Pimentel * 3978963106eSGustavo Pimentel * Invoke to set the required number of MSI-X interrupts. 3988963106eSGustavo Pimentel */ 39953fd3cbeSKishon Vijay Abraham I int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 40053fd3cbeSKishon Vijay Abraham I u16 interrupts, enum pci_barno bir, u32 offset) 4018963106eSGustavo Pimentel { 4028963106eSGustavo Pimentel int ret; 4038963106eSGustavo Pimentel 4048963106eSGustavo Pimentel if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 4058963106eSGustavo Pimentel interrupts < 1 || interrupts > 2048) 4068963106eSGustavo Pimentel return -EINVAL; 4078963106eSGustavo Pimentel 40853fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 40953fd3cbeSKishon Vijay Abraham I return -EINVAL; 41053fd3cbeSKishon Vijay Abraham I 4118963106eSGustavo Pimentel if (!epc->ops->set_msix) 4128963106eSGustavo Pimentel return 0; 4138963106eSGustavo Pimentel 4143d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 41553fd3cbeSKishon Vijay Abraham I ret = epc->ops->set_msix(epc, func_no, vfunc_no, interrupts - 1, bir, 41653fd3cbeSKishon Vijay Abraham I offset); 4173d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 4188963106eSGustavo Pimentel 4198963106eSGustavo Pimentel return ret; 4208963106eSGustavo Pimentel } 4218963106eSGustavo Pimentel EXPORT_SYMBOL_GPL(pci_epc_set_msix); 4228963106eSGustavo Pimentel 4238963106eSGustavo Pimentel /** 4245e8cb403SKishon Vijay Abraham I * pci_epc_unmap_addr() - unmap CPU address from PCI address 4255e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which address is allocated 42653fd3cbeSKishon Vijay Abraham I * @func_no: the physical endpoint function number in the EPC device 42753fd3cbeSKishon Vijay Abraham I * @vfunc_no: the virtual endpoint function number in the physical function 4285e8cb403SKishon Vijay Abraham I * @phys_addr: physical address of the local system 4295e8cb403SKishon Vijay Abraham I * 4305e8cb403SKishon Vijay Abraham I * Invoke to unmap the CPU address from PCI address. 4315e8cb403SKishon Vijay Abraham I */ 43253fd3cbeSKishon Vijay Abraham I void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 4334494738dSCyrille Pitchen phys_addr_t phys_addr) 4345e8cb403SKishon Vijay Abraham I { 4354494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 4365e8cb403SKishon Vijay Abraham I return; 4375e8cb403SKishon Vijay Abraham I 43853fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 43953fd3cbeSKishon Vijay Abraham I return; 44053fd3cbeSKishon Vijay Abraham I 4415e8cb403SKishon Vijay Abraham I if (!epc->ops->unmap_addr) 4425e8cb403SKishon Vijay Abraham I return; 4435e8cb403SKishon Vijay Abraham I 4443d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 44553fd3cbeSKishon Vijay Abraham I epc->ops->unmap_addr(epc, func_no, vfunc_no, phys_addr); 4463d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 4475e8cb403SKishon Vijay Abraham I } 4485e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_unmap_addr); 4495e8cb403SKishon Vijay Abraham I 4505e8cb403SKishon Vijay Abraham I /** 4515e8cb403SKishon Vijay Abraham I * pci_epc_map_addr() - map CPU address to PCI address 4525e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which address is allocated 45353fd3cbeSKishon Vijay Abraham I * @func_no: the physical endpoint function number in the EPC device 45453fd3cbeSKishon Vijay Abraham I * @vfunc_no: the virtual endpoint function number in the physical function 4555e8cb403SKishon Vijay Abraham I * @phys_addr: physical address of the local system 4565e8cb403SKishon Vijay Abraham I * @pci_addr: PCI address to which the physical address should be mapped 4575e8cb403SKishon Vijay Abraham I * @size: the size of the allocation 4585e8cb403SKishon Vijay Abraham I * 4595e8cb403SKishon Vijay Abraham I * Invoke to map CPU address with PCI address. 4605e8cb403SKishon Vijay Abraham I */ 46153fd3cbeSKishon Vijay Abraham I int pci_epc_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 4624494738dSCyrille Pitchen phys_addr_t phys_addr, u64 pci_addr, size_t size) 4635e8cb403SKishon Vijay Abraham I { 4645e8cb403SKishon Vijay Abraham I int ret; 4655e8cb403SKishon Vijay Abraham I 4664494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 4675e8cb403SKishon Vijay Abraham I return -EINVAL; 4685e8cb403SKishon Vijay Abraham I 46953fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 47053fd3cbeSKishon Vijay Abraham I return -EINVAL; 47153fd3cbeSKishon Vijay Abraham I 4725e8cb403SKishon Vijay Abraham I if (!epc->ops->map_addr) 4735e8cb403SKishon Vijay Abraham I return 0; 4745e8cb403SKishon Vijay Abraham I 4753d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 47653fd3cbeSKishon Vijay Abraham I ret = epc->ops->map_addr(epc, func_no, vfunc_no, phys_addr, pci_addr, 47753fd3cbeSKishon Vijay Abraham I size); 4783d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 4795e8cb403SKishon Vijay Abraham I 4805e8cb403SKishon Vijay Abraham I return ret; 4815e8cb403SKishon Vijay Abraham I } 4825e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_map_addr); 4835e8cb403SKishon Vijay Abraham I 4845e8cb403SKishon Vijay Abraham I /** 4855e8cb403SKishon Vijay Abraham I * pci_epc_clear_bar() - reset the BAR 4865e8cb403SKishon Vijay Abraham I * @epc: the EPC device for which the BAR has to be cleared 48753fd3cbeSKishon Vijay Abraham I * @func_no: the physical endpoint function number in the EPC device 48853fd3cbeSKishon Vijay Abraham I * @vfunc_no: the virtual endpoint function number in the physical function 48977d08dbdSNiklas Cassel * @epf_bar: the struct epf_bar that contains the BAR information 4905e8cb403SKishon Vijay Abraham I * 4915e8cb403SKishon Vijay Abraham I * Invoke to reset the BAR of the endpoint device. 4925e8cb403SKishon Vijay Abraham I */ 49353fd3cbeSKishon Vijay Abraham I void pci_epc_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 49477d08dbdSNiklas Cassel struct pci_epf_bar *epf_bar) 4955e8cb403SKishon Vijay Abraham I { 4966474a4e5SNiklas Cassel if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 4976474a4e5SNiklas Cassel (epf_bar->barno == BAR_5 && 4986474a4e5SNiklas Cassel epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) 4995e8cb403SKishon Vijay Abraham I return; 5005e8cb403SKishon Vijay Abraham I 50153fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 50253fd3cbeSKishon Vijay Abraham I return; 50353fd3cbeSKishon Vijay Abraham I 5045e8cb403SKishon Vijay Abraham I if (!epc->ops->clear_bar) 5055e8cb403SKishon Vijay Abraham I return; 5065e8cb403SKishon Vijay Abraham I 5073d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 50853fd3cbeSKishon Vijay Abraham I epc->ops->clear_bar(epc, func_no, vfunc_no, epf_bar); 5093d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 5105e8cb403SKishon Vijay Abraham I } 5115e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_clear_bar); 5125e8cb403SKishon Vijay Abraham I 5135e8cb403SKishon Vijay Abraham I /** 5145e8cb403SKishon Vijay Abraham I * pci_epc_set_bar() - configure BAR in order for host to assign PCI addr space 5155e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which BAR has to be configured 51653fd3cbeSKishon Vijay Abraham I * @func_no: the physical endpoint function number in the EPC device 51753fd3cbeSKishon Vijay Abraham I * @vfunc_no: the virtual endpoint function number in the physical function 518bc4a4897SNiklas Cassel * @epf_bar: the struct epf_bar that contains the BAR information 5195e8cb403SKishon Vijay Abraham I * 5205e8cb403SKishon Vijay Abraham I * Invoke to configure the BAR of the endpoint device. 5215e8cb403SKishon Vijay Abraham I */ 52253fd3cbeSKishon Vijay Abraham I int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 523bc4a4897SNiklas Cassel struct pci_epf_bar *epf_bar) 5245e8cb403SKishon Vijay Abraham I { 5255e8cb403SKishon Vijay Abraham I int ret; 5263567a4edSNiklas Cassel int flags = epf_bar->flags; 5275e8cb403SKishon Vijay Abraham I 528f16b1f6fSNiklas Cassel if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 529f16b1f6fSNiklas Cassel (epf_bar->barno == BAR_5 && 5303567a4edSNiklas Cassel flags & PCI_BASE_ADDRESS_MEM_TYPE_64) || 5313567a4edSNiklas Cassel (flags & PCI_BASE_ADDRESS_SPACE_IO && 532f25b5faeSNiklas Cassel flags & PCI_BASE_ADDRESS_IO_MASK) || 533f25b5faeSNiklas Cassel (upper_32_bits(epf_bar->size) && 534f25b5faeSNiklas Cassel !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64))) 5355e8cb403SKishon Vijay Abraham I return -EINVAL; 5365e8cb403SKishon Vijay Abraham I 53753fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 53853fd3cbeSKishon Vijay Abraham I return -EINVAL; 53953fd3cbeSKishon Vijay Abraham I 5405e8cb403SKishon Vijay Abraham I if (!epc->ops->set_bar) 5415e8cb403SKishon Vijay Abraham I return 0; 5425e8cb403SKishon Vijay Abraham I 5433d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 54453fd3cbeSKishon Vijay Abraham I ret = epc->ops->set_bar(epc, func_no, vfunc_no, epf_bar); 5453d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 5465e8cb403SKishon Vijay Abraham I 5475e8cb403SKishon Vijay Abraham I return ret; 5485e8cb403SKishon Vijay Abraham I } 5495e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_set_bar); 5505e8cb403SKishon Vijay Abraham I 5515e8cb403SKishon Vijay Abraham I /** 5525e8cb403SKishon Vijay Abraham I * pci_epc_write_header() - write standard configuration header 5535e8cb403SKishon Vijay Abraham I * @epc: the EPC device to which the configuration header should be written 55453fd3cbeSKishon Vijay Abraham I * @func_no: the physical endpoint function number in the EPC device 55553fd3cbeSKishon Vijay Abraham I * @vfunc_no: the virtual endpoint function number in the physical function 5565e8cb403SKishon Vijay Abraham I * @header: standard configuration header fields 5575e8cb403SKishon Vijay Abraham I * 5585e8cb403SKishon Vijay Abraham I * Invoke to write the configuration header to the endpoint controller. Every 5595e8cb403SKishon Vijay Abraham I * endpoint controller will have a dedicated location to which the standard 5605e8cb403SKishon Vijay Abraham I * configuration header would be written. The callback function should write 5615e8cb403SKishon Vijay Abraham I * the header fields to this dedicated location. 5625e8cb403SKishon Vijay Abraham I */ 56353fd3cbeSKishon Vijay Abraham I int pci_epc_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no, 5644494738dSCyrille Pitchen struct pci_epf_header *header) 5655e8cb403SKishon Vijay Abraham I { 5665e8cb403SKishon Vijay Abraham I int ret; 5675e8cb403SKishon Vijay Abraham I 5684494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 5695e8cb403SKishon Vijay Abraham I return -EINVAL; 5705e8cb403SKishon Vijay Abraham I 57153fd3cbeSKishon Vijay Abraham I if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) 57253fd3cbeSKishon Vijay Abraham I return -EINVAL; 57353fd3cbeSKishon Vijay Abraham I 57453fd3cbeSKishon Vijay Abraham I /* Only Virtual Function #1 has deviceID */ 57553fd3cbeSKishon Vijay Abraham I if (vfunc_no > 1) 57653fd3cbeSKishon Vijay Abraham I return -EINVAL; 57753fd3cbeSKishon Vijay Abraham I 5785e8cb403SKishon Vijay Abraham I if (!epc->ops->write_header) 5795e8cb403SKishon Vijay Abraham I return 0; 5805e8cb403SKishon Vijay Abraham I 5813d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 58253fd3cbeSKishon Vijay Abraham I ret = epc->ops->write_header(epc, func_no, vfunc_no, header); 5833d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 5845e8cb403SKishon Vijay Abraham I 5855e8cb403SKishon Vijay Abraham I return ret; 5865e8cb403SKishon Vijay Abraham I } 5875e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_write_header); 5885e8cb403SKishon Vijay Abraham I 5895e8cb403SKishon Vijay Abraham I /** 5905e8cb403SKishon Vijay Abraham I * pci_epc_add_epf() - bind PCI endpoint function to an endpoint controller 5915e8cb403SKishon Vijay Abraham I * @epc: the EPC device to which the endpoint function should be added 5925e8cb403SKishon Vijay Abraham I * @epf: the endpoint function to be added 59363840ff5SKishon Vijay Abraham I * @type: Identifies if the EPC is connected to the primary or secondary 59463840ff5SKishon Vijay Abraham I * interface of EPF 5955e8cb403SKishon Vijay Abraham I * 5965e8cb403SKishon Vijay Abraham I * A PCI endpoint device can have one or more functions. In the case of PCIe, 5975e8cb403SKishon Vijay Abraham I * the specification allows up to 8 PCIe endpoint functions. Invoke 5985e8cb403SKishon Vijay Abraham I * pci_epc_add_epf() to add a PCI endpoint function to an endpoint controller. 5995e8cb403SKishon Vijay Abraham I */ 60063840ff5SKishon Vijay Abraham I int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf, 60163840ff5SKishon Vijay Abraham I enum pci_epc_interface_type type) 6025e8cb403SKishon Vijay Abraham I { 60363840ff5SKishon Vijay Abraham I struct list_head *list; 6042499ee84SKishon Vijay Abraham I u32 func_no; 6052499ee84SKishon Vijay Abraham I int ret = 0; 6062499ee84SKishon Vijay Abraham I 6071cf362e9SKishon Vijay Abraham I if (IS_ERR_OR_NULL(epc) || epf->is_vf) 60863840ff5SKishon Vijay Abraham I return -EINVAL; 60963840ff5SKishon Vijay Abraham I 61063840ff5SKishon Vijay Abraham I if (type == PRIMARY_INTERFACE && epf->epc) 6115e8cb403SKishon Vijay Abraham I return -EBUSY; 6125e8cb403SKishon Vijay Abraham I 61363840ff5SKishon Vijay Abraham I if (type == SECONDARY_INTERFACE && epf->sec_epc) 61463840ff5SKishon Vijay Abraham I return -EBUSY; 6155e8cb403SKishon Vijay Abraham I 616*d6dd5bafSManivannan Sadhasivam mutex_lock(&epc->list_lock); 6172499ee84SKishon Vijay Abraham I func_no = find_first_zero_bit(&epc->function_num_map, 6182499ee84SKishon Vijay Abraham I BITS_PER_LONG); 6192499ee84SKishon Vijay Abraham I if (func_no >= BITS_PER_LONG) { 6202499ee84SKishon Vijay Abraham I ret = -EINVAL; 6212499ee84SKishon Vijay Abraham I goto ret; 6222499ee84SKishon Vijay Abraham I } 6235e8cb403SKishon Vijay Abraham I 6242499ee84SKishon Vijay Abraham I if (func_no > epc->max_functions - 1) { 6252499ee84SKishon Vijay Abraham I dev_err(&epc->dev, "Exceeding max supported Function Number\n"); 6262499ee84SKishon Vijay Abraham I ret = -EINVAL; 6272499ee84SKishon Vijay Abraham I goto ret; 6282499ee84SKishon Vijay Abraham I } 6292499ee84SKishon Vijay Abraham I 6302499ee84SKishon Vijay Abraham I set_bit(func_no, &epc->function_num_map); 63163840ff5SKishon Vijay Abraham I if (type == PRIMARY_INTERFACE) { 6322499ee84SKishon Vijay Abraham I epf->func_no = func_no; 6335e8cb403SKishon Vijay Abraham I epf->epc = epc; 63463840ff5SKishon Vijay Abraham I list = &epf->list; 63563840ff5SKishon Vijay Abraham I } else { 63663840ff5SKishon Vijay Abraham I epf->sec_epc_func_no = func_no; 63763840ff5SKishon Vijay Abraham I epf->sec_epc = epc; 63863840ff5SKishon Vijay Abraham I list = &epf->sec_epc_list; 63963840ff5SKishon Vijay Abraham I } 6405e8cb403SKishon Vijay Abraham I 64163840ff5SKishon Vijay Abraham I list_add_tail(list, &epc->pci_epf); 6422499ee84SKishon Vijay Abraham I ret: 643*d6dd5bafSManivannan Sadhasivam mutex_unlock(&epc->list_lock); 6445e8cb403SKishon Vijay Abraham I 6452499ee84SKishon Vijay Abraham I return ret; 6465e8cb403SKishon Vijay Abraham I } 6475e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_add_epf); 6485e8cb403SKishon Vijay Abraham I 6495e8cb403SKishon Vijay Abraham I /** 6505e8cb403SKishon Vijay Abraham I * pci_epc_remove_epf() - remove PCI endpoint function from endpoint controller 6515e8cb403SKishon Vijay Abraham I * @epc: the EPC device from which the endpoint function should be removed 6525e8cb403SKishon Vijay Abraham I * @epf: the endpoint function to be removed 65343395d9eSKrzysztof Wilczyński * @type: identifies if the EPC is connected to the primary or secondary 65443395d9eSKrzysztof Wilczyński * interface of EPF 6555e8cb403SKishon Vijay Abraham I * 6565e8cb403SKishon Vijay Abraham I * Invoke to remove PCI endpoint function from the endpoint controller. 6575e8cb403SKishon Vijay Abraham I */ 65863840ff5SKishon Vijay Abraham I void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf, 65963840ff5SKishon Vijay Abraham I enum pci_epc_interface_type type) 6605e8cb403SKishon Vijay Abraham I { 66163840ff5SKishon Vijay Abraham I struct list_head *list; 66263840ff5SKishon Vijay Abraham I u32 func_no = 0; 66363840ff5SKishon Vijay Abraham I 664db7a6248SAlan Mikhak if (!epc || IS_ERR(epc) || !epf) 6655e8cb403SKishon Vijay Abraham I return; 6665e8cb403SKishon Vijay Abraham I 66763840ff5SKishon Vijay Abraham I if (type == PRIMARY_INTERFACE) { 66863840ff5SKishon Vijay Abraham I func_no = epf->func_no; 66963840ff5SKishon Vijay Abraham I list = &epf->list; 67063840ff5SKishon Vijay Abraham I } else { 67163840ff5SKishon Vijay Abraham I func_no = epf->sec_epc_func_no; 67263840ff5SKishon Vijay Abraham I list = &epf->sec_epc_list; 67363840ff5SKishon Vijay Abraham I } 67463840ff5SKishon Vijay Abraham I 675*d6dd5bafSManivannan Sadhasivam mutex_lock(&epc->list_lock); 67663840ff5SKishon Vijay Abraham I clear_bit(func_no, &epc->function_num_map); 67763840ff5SKishon Vijay Abraham I list_del(list); 678db7a6248SAlan Mikhak epf->epc = NULL; 679*d6dd5bafSManivannan Sadhasivam mutex_unlock(&epc->list_lock); 6805e8cb403SKishon Vijay Abraham I } 6815e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_remove_epf); 6825e8cb403SKishon Vijay Abraham I 6835e8cb403SKishon Vijay Abraham I /** 6845e8cb403SKishon Vijay Abraham I * pci_epc_linkup() - Notify the EPF device that EPC device has established a 6855e8cb403SKishon Vijay Abraham I * connection with the Root Complex. 6865e8cb403SKishon Vijay Abraham I * @epc: the EPC device which has established link with the host 6875e8cb403SKishon Vijay Abraham I * 6885e8cb403SKishon Vijay Abraham I * Invoke to Notify the EPF device that the EPC device has established a 6895e8cb403SKishon Vijay Abraham I * connection with the Root Complex. 6905e8cb403SKishon Vijay Abraham I */ 6915e8cb403SKishon Vijay Abraham I void pci_epc_linkup(struct pci_epc *epc) 6925e8cb403SKishon Vijay Abraham I { 6935e8cb403SKishon Vijay Abraham I if (!epc || IS_ERR(epc)) 6945e8cb403SKishon Vijay Abraham I return; 6955e8cb403SKishon Vijay Abraham I 6960ef22dcfSVidya Sagar atomic_notifier_call_chain(&epc->notifier, LINK_UP, NULL); 6975e8cb403SKishon Vijay Abraham I } 6985e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_linkup); 6995e8cb403SKishon Vijay Abraham I 7005e8cb403SKishon Vijay Abraham I /** 7010ef22dcfSVidya Sagar * pci_epc_init_notify() - Notify the EPF device that EPC device's core 7020ef22dcfSVidya Sagar * initialization is completed. 703b2105b9fSKrzysztof Wilczyński * @epc: the EPC device whose core initialization is completed 7040ef22dcfSVidya Sagar * 7050ef22dcfSVidya Sagar * Invoke to Notify the EPF device that the EPC device's initialization 7060ef22dcfSVidya Sagar * is completed. 7070ef22dcfSVidya Sagar */ 7080ef22dcfSVidya Sagar void pci_epc_init_notify(struct pci_epc *epc) 7090ef22dcfSVidya Sagar { 7100ef22dcfSVidya Sagar if (!epc || IS_ERR(epc)) 7110ef22dcfSVidya Sagar return; 7120ef22dcfSVidya Sagar 7130ef22dcfSVidya Sagar atomic_notifier_call_chain(&epc->notifier, CORE_INIT, NULL); 7140ef22dcfSVidya Sagar } 7150ef22dcfSVidya Sagar EXPORT_SYMBOL_GPL(pci_epc_init_notify); 7160ef22dcfSVidya Sagar 7170ef22dcfSVidya Sagar /** 7185e8cb403SKishon Vijay Abraham I * pci_epc_destroy() - destroy the EPC device 7195e8cb403SKishon Vijay Abraham I * @epc: the EPC device that has to be destroyed 7205e8cb403SKishon Vijay Abraham I * 7215e8cb403SKishon Vijay Abraham I * Invoke to destroy the PCI EPC device 7225e8cb403SKishon Vijay Abraham I */ 7235e8cb403SKishon Vijay Abraham I void pci_epc_destroy(struct pci_epc *epc) 7245e8cb403SKishon Vijay Abraham I { 7253a401a2cSKishon Vijay Abraham I pci_ep_cfs_remove_epc_group(epc->group); 7265e8cb403SKishon Vijay Abraham I device_unregister(&epc->dev); 7275e8cb403SKishon Vijay Abraham I } 7285e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_destroy); 7295e8cb403SKishon Vijay Abraham I 7305e8cb403SKishon Vijay Abraham I /** 7315e8cb403SKishon Vijay Abraham I * devm_pci_epc_destroy() - destroy the EPC device 7325e8cb403SKishon Vijay Abraham I * @dev: device that wants to destroy the EPC 7335e8cb403SKishon Vijay Abraham I * @epc: the EPC device that has to be destroyed 7345e8cb403SKishon Vijay Abraham I * 7355e8cb403SKishon Vijay Abraham I * Invoke to destroy the devres associated with this 7365e8cb403SKishon Vijay Abraham I * pci_epc and destroy the EPC device. 7375e8cb403SKishon Vijay Abraham I */ 7385e8cb403SKishon Vijay Abraham I void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc) 7395e8cb403SKishon Vijay Abraham I { 7405e8cb403SKishon Vijay Abraham I int r; 7415e8cb403SKishon Vijay Abraham I 7425e8cb403SKishon Vijay Abraham I r = devres_destroy(dev, devm_pci_epc_release, devm_pci_epc_match, 7435e8cb403SKishon Vijay Abraham I epc); 7445e8cb403SKishon Vijay Abraham I dev_WARN_ONCE(dev, r, "couldn't find PCI EPC resource\n"); 7455e8cb403SKishon Vijay Abraham I } 7465e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(devm_pci_epc_destroy); 7475e8cb403SKishon Vijay Abraham I 7487711cbb4SYoshihiro Shimoda static void pci_epc_release(struct device *dev) 7497711cbb4SYoshihiro Shimoda { 7507711cbb4SYoshihiro Shimoda kfree(to_pci_epc(dev)); 7517711cbb4SYoshihiro Shimoda } 7527711cbb4SYoshihiro Shimoda 7535e8cb403SKishon Vijay Abraham I /** 7545e8cb403SKishon Vijay Abraham I * __pci_epc_create() - create a new endpoint controller (EPC) device 7555e8cb403SKishon Vijay Abraham I * @dev: device that is creating the new EPC 7565e8cb403SKishon Vijay Abraham I * @ops: function pointers for performing EPC operations 7575e8cb403SKishon Vijay Abraham I * @owner: the owner of the module that creates the EPC device 7585e8cb403SKishon Vijay Abraham I * 7595e8cb403SKishon Vijay Abraham I * Invoke to create a new EPC device and add it to pci_epc class. 7605e8cb403SKishon Vijay Abraham I */ 7615e8cb403SKishon Vijay Abraham I struct pci_epc * 7625e8cb403SKishon Vijay Abraham I __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, 7635e8cb403SKishon Vijay Abraham I struct module *owner) 7645e8cb403SKishon Vijay Abraham I { 7655e8cb403SKishon Vijay Abraham I int ret; 7665e8cb403SKishon Vijay Abraham I struct pci_epc *epc; 7675e8cb403SKishon Vijay Abraham I 7685e8cb403SKishon Vijay Abraham I if (WARN_ON(!dev)) { 7695e8cb403SKishon Vijay Abraham I ret = -EINVAL; 7705e8cb403SKishon Vijay Abraham I goto err_ret; 7715e8cb403SKishon Vijay Abraham I } 7725e8cb403SKishon Vijay Abraham I 7735e8cb403SKishon Vijay Abraham I epc = kzalloc(sizeof(*epc), GFP_KERNEL); 7745e8cb403SKishon Vijay Abraham I if (!epc) { 7755e8cb403SKishon Vijay Abraham I ret = -ENOMEM; 7765e8cb403SKishon Vijay Abraham I goto err_ret; 7775e8cb403SKishon Vijay Abraham I } 7785e8cb403SKishon Vijay Abraham I 7793d3248dbSKishon Vijay Abraham I mutex_init(&epc->lock); 780*d6dd5bafSManivannan Sadhasivam mutex_init(&epc->list_lock); 7815e8cb403SKishon Vijay Abraham I INIT_LIST_HEAD(&epc->pci_epf); 7825779dd0aSKishon Vijay Abraham I ATOMIC_INIT_NOTIFIER_HEAD(&epc->notifier); 7835e8cb403SKishon Vijay Abraham I 7845e8cb403SKishon Vijay Abraham I device_initialize(&epc->dev); 7855e8cb403SKishon Vijay Abraham I epc->dev.class = pci_epc_class; 78664c1a02aSKishon Vijay Abraham I epc->dev.parent = dev; 7877711cbb4SYoshihiro Shimoda epc->dev.release = pci_epc_release; 7885e8cb403SKishon Vijay Abraham I epc->ops = ops; 7895e8cb403SKishon Vijay Abraham I 7905e8cb403SKishon Vijay Abraham I ret = dev_set_name(&epc->dev, "%s", dev_name(dev)); 7915e8cb403SKishon Vijay Abraham I if (ret) 7925e8cb403SKishon Vijay Abraham I goto put_dev; 7935e8cb403SKishon Vijay Abraham I 7945e8cb403SKishon Vijay Abraham I ret = device_add(&epc->dev); 7955e8cb403SKishon Vijay Abraham I if (ret) 7965e8cb403SKishon Vijay Abraham I goto put_dev; 7975e8cb403SKishon Vijay Abraham I 7983a401a2cSKishon Vijay Abraham I epc->group = pci_ep_cfs_add_epc_group(dev_name(dev)); 7993a401a2cSKishon Vijay Abraham I 8005e8cb403SKishon Vijay Abraham I return epc; 8015e8cb403SKishon Vijay Abraham I 8025e8cb403SKishon Vijay Abraham I put_dev: 8035e8cb403SKishon Vijay Abraham I put_device(&epc->dev); 8045e8cb403SKishon Vijay Abraham I kfree(epc); 8055e8cb403SKishon Vijay Abraham I 8065e8cb403SKishon Vijay Abraham I err_ret: 8075e8cb403SKishon Vijay Abraham I return ERR_PTR(ret); 8085e8cb403SKishon Vijay Abraham I } 8095e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(__pci_epc_create); 8105e8cb403SKishon Vijay Abraham I 8115e8cb403SKishon Vijay Abraham I /** 8125e8cb403SKishon Vijay Abraham I * __devm_pci_epc_create() - create a new endpoint controller (EPC) device 8135e8cb403SKishon Vijay Abraham I * @dev: device that is creating the new EPC 8145e8cb403SKishon Vijay Abraham I * @ops: function pointers for performing EPC operations 8155e8cb403SKishon Vijay Abraham I * @owner: the owner of the module that creates the EPC device 8165e8cb403SKishon Vijay Abraham I * 8175e8cb403SKishon Vijay Abraham I * Invoke to create a new EPC device and add it to pci_epc class. 8185e8cb403SKishon Vijay Abraham I * While at that, it also associates the device with the pci_epc using devres. 8195e8cb403SKishon Vijay Abraham I * On driver detach, release function is invoked on the devres data, 8205e8cb403SKishon Vijay Abraham I * then, devres data is freed. 8215e8cb403SKishon Vijay Abraham I */ 8225e8cb403SKishon Vijay Abraham I struct pci_epc * 8235e8cb403SKishon Vijay Abraham I __devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, 8245e8cb403SKishon Vijay Abraham I struct module *owner) 8255e8cb403SKishon Vijay Abraham I { 8265e8cb403SKishon Vijay Abraham I struct pci_epc **ptr, *epc; 8275e8cb403SKishon Vijay Abraham I 8285e8cb403SKishon Vijay Abraham I ptr = devres_alloc(devm_pci_epc_release, sizeof(*ptr), GFP_KERNEL); 8295e8cb403SKishon Vijay Abraham I if (!ptr) 8305e8cb403SKishon Vijay Abraham I return ERR_PTR(-ENOMEM); 8315e8cb403SKishon Vijay Abraham I 8325e8cb403SKishon Vijay Abraham I epc = __pci_epc_create(dev, ops, owner); 8335e8cb403SKishon Vijay Abraham I if (!IS_ERR(epc)) { 8345e8cb403SKishon Vijay Abraham I *ptr = epc; 8355e8cb403SKishon Vijay Abraham I devres_add(dev, ptr); 8365e8cb403SKishon Vijay Abraham I } else { 8375e8cb403SKishon Vijay Abraham I devres_free(ptr); 8385e8cb403SKishon Vijay Abraham I } 8395e8cb403SKishon Vijay Abraham I 8405e8cb403SKishon Vijay Abraham I return epc; 8415e8cb403SKishon Vijay Abraham I } 8425e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(__devm_pci_epc_create); 8435e8cb403SKishon Vijay Abraham I 8445e8cb403SKishon Vijay Abraham I static int __init pci_epc_init(void) 8455e8cb403SKishon Vijay Abraham I { 8465e8cb403SKishon Vijay Abraham I pci_epc_class = class_create(THIS_MODULE, "pci_epc"); 8475e8cb403SKishon Vijay Abraham I if (IS_ERR(pci_epc_class)) { 8485e8cb403SKishon Vijay Abraham I pr_err("failed to create pci epc class --> %ld\n", 8495e8cb403SKishon Vijay Abraham I PTR_ERR(pci_epc_class)); 8505e8cb403SKishon Vijay Abraham I return PTR_ERR(pci_epc_class); 8515e8cb403SKishon Vijay Abraham I } 8525e8cb403SKishon Vijay Abraham I 8535e8cb403SKishon Vijay Abraham I return 0; 8545e8cb403SKishon Vijay Abraham I } 8555e8cb403SKishon Vijay Abraham I module_init(pci_epc_init); 8565e8cb403SKishon Vijay Abraham I 8575e8cb403SKishon Vijay Abraham I static void __exit pci_epc_exit(void) 8585e8cb403SKishon Vijay Abraham I { 8595e8cb403SKishon Vijay Abraham I class_destroy(pci_epc_class); 8605e8cb403SKishon Vijay Abraham I } 8615e8cb403SKishon Vijay Abraham I module_exit(pci_epc_exit); 8625e8cb403SKishon Vijay Abraham I 8635e8cb403SKishon Vijay Abraham I MODULE_DESCRIPTION("PCI EPC Library"); 8645e8cb403SKishon Vijay Abraham I MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); 8655e8cb403SKishon Vijay Abraham I MODULE_LICENSE("GPL v2"); 866