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 * 901e9efe6cSKishon Vijay Abraham I * Invoke to get the first unreserved BAR that can be used for endpoint 911e9efe6cSKishon Vijay Abraham I * function. For any incorrect value in reserved_bar return '0'. 921e9efe6cSKishon Vijay Abraham I */ 931e9efe6cSKishon Vijay Abraham I unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features 941e9efe6cSKishon Vijay Abraham I *epc_features) 951e9efe6cSKishon Vijay Abraham I { 96*959a48d0SKishon Vijay Abraham I unsigned long free_bar; 971e9efe6cSKishon Vijay Abraham I 981e9efe6cSKishon Vijay Abraham I if (!epc_features) 991e9efe6cSKishon Vijay Abraham I return 0; 1001e9efe6cSKishon Vijay Abraham I 101*959a48d0SKishon Vijay Abraham I /* Find if the reserved BAR is also a 64-bit BAR */ 102*959a48d0SKishon Vijay Abraham I free_bar = epc_features->reserved_bar & epc_features->bar_fixed_64bit; 103*959a48d0SKishon Vijay Abraham I 104*959a48d0SKishon Vijay Abraham I /* Set the adjacent bit if the reserved BAR is also a 64-bit BAR */ 105*959a48d0SKishon Vijay Abraham I free_bar <<= 1; 106*959a48d0SKishon Vijay Abraham I free_bar |= epc_features->reserved_bar; 107*959a48d0SKishon Vijay Abraham I 108*959a48d0SKishon Vijay Abraham I /* Now find the free BAR */ 109*959a48d0SKishon Vijay Abraham I free_bar = ffz(free_bar); 1101e9efe6cSKishon Vijay Abraham I if (free_bar > 5) 1111e9efe6cSKishon Vijay Abraham I return 0; 1121e9efe6cSKishon Vijay Abraham I 1131e9efe6cSKishon Vijay Abraham I return free_bar; 1141e9efe6cSKishon Vijay Abraham I } 1151e9efe6cSKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_get_first_free_bar); 1161e9efe6cSKishon Vijay Abraham I 1171e9efe6cSKishon Vijay Abraham I /** 11841cb8d18SKishon Vijay Abraham I * pci_epc_get_features() - get the features supported by EPC 11941cb8d18SKishon Vijay Abraham I * @epc: the features supported by *this* EPC device will be returned 12041cb8d18SKishon Vijay Abraham I * @func_no: the features supported by the EPC device specific to the 12141cb8d18SKishon Vijay Abraham I * endpoint function with func_no will be returned 12241cb8d18SKishon Vijay Abraham I * 12341cb8d18SKishon Vijay Abraham I * Invoke to get the features provided by the EPC which may be 12441cb8d18SKishon Vijay Abraham I * specific to an endpoint function. Returns pci_epc_features on success 12541cb8d18SKishon Vijay Abraham I * and NULL for any failures. 12641cb8d18SKishon Vijay Abraham I */ 12741cb8d18SKishon Vijay Abraham I const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc, 12841cb8d18SKishon Vijay Abraham I u8 func_no) 12941cb8d18SKishon Vijay Abraham I { 13041cb8d18SKishon Vijay Abraham I const struct pci_epc_features *epc_features; 13141cb8d18SKishon Vijay Abraham I 13241cb8d18SKishon Vijay Abraham I if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 13341cb8d18SKishon Vijay Abraham I return NULL; 13441cb8d18SKishon Vijay Abraham I 13541cb8d18SKishon Vijay Abraham I if (!epc->ops->get_features) 13641cb8d18SKishon Vijay Abraham I return NULL; 13741cb8d18SKishon Vijay Abraham I 1383d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 13941cb8d18SKishon Vijay Abraham I epc_features = epc->ops->get_features(epc, func_no); 1403d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 14141cb8d18SKishon Vijay Abraham I 14241cb8d18SKishon Vijay Abraham I return epc_features; 14341cb8d18SKishon Vijay Abraham I } 14441cb8d18SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_get_features); 14541cb8d18SKishon Vijay Abraham I 14641cb8d18SKishon Vijay Abraham I /** 1475e8cb403SKishon Vijay Abraham I * pci_epc_stop() - stop the PCI link 1485e8cb403SKishon Vijay Abraham I * @epc: the link of the EPC device that has to be stopped 1495e8cb403SKishon Vijay Abraham I * 1505e8cb403SKishon Vijay Abraham I * Invoke to stop the PCI link 1515e8cb403SKishon Vijay Abraham I */ 1525e8cb403SKishon Vijay Abraham I void pci_epc_stop(struct pci_epc *epc) 1535e8cb403SKishon Vijay Abraham I { 1545e8cb403SKishon Vijay Abraham I if (IS_ERR(epc) || !epc->ops->stop) 1555e8cb403SKishon Vijay Abraham I return; 1565e8cb403SKishon Vijay Abraham I 1573d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 1585e8cb403SKishon Vijay Abraham I epc->ops->stop(epc); 1593d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 1605e8cb403SKishon Vijay Abraham I } 1615e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_stop); 1625e8cb403SKishon Vijay Abraham I 1635e8cb403SKishon Vijay Abraham I /** 1645e8cb403SKishon Vijay Abraham I * pci_epc_start() - start the PCI link 1655e8cb403SKishon Vijay Abraham I * @epc: the link of *this* EPC device has to be started 1665e8cb403SKishon Vijay Abraham I * 1675e8cb403SKishon Vijay Abraham I * Invoke to start the PCI link 1685e8cb403SKishon Vijay Abraham I */ 1695e8cb403SKishon Vijay Abraham I int pci_epc_start(struct pci_epc *epc) 1705e8cb403SKishon Vijay Abraham I { 1715e8cb403SKishon Vijay Abraham I int ret; 1725e8cb403SKishon Vijay Abraham I 1735e8cb403SKishon Vijay Abraham I if (IS_ERR(epc)) 1745e8cb403SKishon Vijay Abraham I return -EINVAL; 1755e8cb403SKishon Vijay Abraham I 1765e8cb403SKishon Vijay Abraham I if (!epc->ops->start) 1775e8cb403SKishon Vijay Abraham I return 0; 1785e8cb403SKishon Vijay Abraham I 1793d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 1805e8cb403SKishon Vijay Abraham I ret = epc->ops->start(epc); 1813d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 1825e8cb403SKishon Vijay Abraham I 1835e8cb403SKishon Vijay Abraham I return ret; 1845e8cb403SKishon Vijay Abraham I } 1855e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_start); 1865e8cb403SKishon Vijay Abraham I 1875e8cb403SKishon Vijay Abraham I /** 1885e8cb403SKishon Vijay Abraham I * pci_epc_raise_irq() - interrupt the host system 1895e8cb403SKishon Vijay Abraham I * @epc: the EPC device which has to interrupt the host 1904494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 191d3c70a98SGustavo Pimentel * @type: specify the type of interrupt; legacy, MSI or MSI-X 192d3c70a98SGustavo Pimentel * @interrupt_num: the MSI or MSI-X interrupt number 1935e8cb403SKishon Vijay Abraham I * 194d3c70a98SGustavo Pimentel * Invoke to raise an legacy, MSI or MSI-X interrupt 1955e8cb403SKishon Vijay Abraham I */ 1964494738dSCyrille Pitchen int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, 197d3c70a98SGustavo Pimentel enum pci_epc_irq_type type, u16 interrupt_num) 1985e8cb403SKishon Vijay Abraham I { 1995e8cb403SKishon Vijay Abraham I int ret; 2005e8cb403SKishon Vijay Abraham I 2014494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 2025e8cb403SKishon Vijay Abraham I return -EINVAL; 2035e8cb403SKishon Vijay Abraham I 2045e8cb403SKishon Vijay Abraham I if (!epc->ops->raise_irq) 2055e8cb403SKishon Vijay Abraham I return 0; 2065e8cb403SKishon Vijay Abraham I 2073d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 2084494738dSCyrille Pitchen ret = epc->ops->raise_irq(epc, func_no, type, interrupt_num); 2093d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 2105e8cb403SKishon Vijay Abraham I 2115e8cb403SKishon Vijay Abraham I return ret; 2125e8cb403SKishon Vijay Abraham I } 2135e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_raise_irq); 2145e8cb403SKishon Vijay Abraham I 2155e8cb403SKishon Vijay Abraham I /** 2165e8cb403SKishon Vijay Abraham I * pci_epc_get_msi() - get the number of MSI interrupt numbers allocated 2175e8cb403SKishon Vijay Abraham I * @epc: the EPC device to which MSI interrupts was requested 2184494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 2195e8cb403SKishon Vijay Abraham I * 2205e8cb403SKishon Vijay Abraham I * Invoke to get the number of MSI interrupts allocated by the RC 2215e8cb403SKishon Vijay Abraham I */ 2224494738dSCyrille Pitchen int pci_epc_get_msi(struct pci_epc *epc, u8 func_no) 2235e8cb403SKishon Vijay Abraham I { 2245e8cb403SKishon Vijay Abraham I int interrupt; 2255e8cb403SKishon Vijay Abraham I 2264494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 2275e8cb403SKishon Vijay Abraham I return 0; 2285e8cb403SKishon Vijay Abraham I 2295e8cb403SKishon Vijay Abraham I if (!epc->ops->get_msi) 2305e8cb403SKishon Vijay Abraham I return 0; 2315e8cb403SKishon Vijay Abraham I 2323d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 2334494738dSCyrille Pitchen interrupt = epc->ops->get_msi(epc, func_no); 2343d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 2355e8cb403SKishon Vijay Abraham I 2365e8cb403SKishon Vijay Abraham I if (interrupt < 0) 2375e8cb403SKishon Vijay Abraham I return 0; 2385e8cb403SKishon Vijay Abraham I 2395e8cb403SKishon Vijay Abraham I interrupt = 1 << interrupt; 2405e8cb403SKishon Vijay Abraham I 2415e8cb403SKishon Vijay Abraham I return interrupt; 2425e8cb403SKishon Vijay Abraham I } 2435e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_get_msi); 2445e8cb403SKishon Vijay Abraham I 2455e8cb403SKishon Vijay Abraham I /** 2465e8cb403SKishon Vijay Abraham I * pci_epc_set_msi() - set the number of MSI interrupt numbers required 2475e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which MSI has to be configured 2484494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 2495e8cb403SKishon Vijay Abraham I * @interrupts: number of MSI interrupts required by the EPF 2505e8cb403SKishon Vijay Abraham I * 2515e8cb403SKishon Vijay Abraham I * Invoke to set the required number of MSI interrupts. 2525e8cb403SKishon Vijay Abraham I */ 2534494738dSCyrille Pitchen int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) 2545e8cb403SKishon Vijay Abraham I { 2555e8cb403SKishon Vijay Abraham I int ret; 2565e8cb403SKishon Vijay Abraham I u8 encode_int; 2575e8cb403SKishon Vijay Abraham I 25815c972dfSGustavo Pimentel if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 25915c972dfSGustavo Pimentel interrupts > 32) 2605e8cb403SKishon Vijay Abraham I return -EINVAL; 2615e8cb403SKishon Vijay Abraham I 2625e8cb403SKishon Vijay Abraham I if (!epc->ops->set_msi) 2635e8cb403SKishon Vijay Abraham I return 0; 2645e8cb403SKishon Vijay Abraham I 2655e8cb403SKishon Vijay Abraham I encode_int = order_base_2(interrupts); 2665e8cb403SKishon Vijay Abraham I 2673d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 2684494738dSCyrille Pitchen ret = epc->ops->set_msi(epc, func_no, encode_int); 2693d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 2705e8cb403SKishon Vijay Abraham I 2715e8cb403SKishon Vijay Abraham I return ret; 2725e8cb403SKishon Vijay Abraham I } 2735e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_set_msi); 2745e8cb403SKishon Vijay Abraham I 2755e8cb403SKishon Vijay Abraham I /** 2768963106eSGustavo Pimentel * pci_epc_get_msix() - get the number of MSI-X interrupt numbers allocated 2778963106eSGustavo Pimentel * @epc: the EPC device to which MSI-X interrupts was requested 2788963106eSGustavo Pimentel * @func_no: the endpoint function number in the EPC device 2798963106eSGustavo Pimentel * 2808963106eSGustavo Pimentel * Invoke to get the number of MSI-X interrupts allocated by the RC 2818963106eSGustavo Pimentel */ 2828963106eSGustavo Pimentel int pci_epc_get_msix(struct pci_epc *epc, u8 func_no) 2838963106eSGustavo Pimentel { 2848963106eSGustavo Pimentel int interrupt; 2858963106eSGustavo Pimentel 2868963106eSGustavo Pimentel if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 2878963106eSGustavo Pimentel return 0; 2888963106eSGustavo Pimentel 2898963106eSGustavo Pimentel if (!epc->ops->get_msix) 2908963106eSGustavo Pimentel return 0; 2918963106eSGustavo Pimentel 2923d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 2938963106eSGustavo Pimentel interrupt = epc->ops->get_msix(epc, func_no); 2943d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 2958963106eSGustavo Pimentel 2968963106eSGustavo Pimentel if (interrupt < 0) 2978963106eSGustavo Pimentel return 0; 2988963106eSGustavo Pimentel 2998963106eSGustavo Pimentel return interrupt + 1; 3008963106eSGustavo Pimentel } 3018963106eSGustavo Pimentel EXPORT_SYMBOL_GPL(pci_epc_get_msix); 3028963106eSGustavo Pimentel 3038963106eSGustavo Pimentel /** 3048963106eSGustavo Pimentel * pci_epc_set_msix() - set the number of MSI-X interrupt numbers required 3058963106eSGustavo Pimentel * @epc: the EPC device on which MSI-X has to be configured 3068963106eSGustavo Pimentel * @func_no: the endpoint function number in the EPC device 3078963106eSGustavo Pimentel * @interrupts: number of MSI-X interrupts required by the EPF 30883153d9fSKishon Vijay Abraham I * @bir: BAR where the MSI-X table resides 30983153d9fSKishon Vijay Abraham I * @offset: Offset pointing to the start of MSI-X table 3108963106eSGustavo Pimentel * 3118963106eSGustavo Pimentel * Invoke to set the required number of MSI-X interrupts. 3128963106eSGustavo Pimentel */ 31383153d9fSKishon Vijay Abraham I int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts, 31483153d9fSKishon Vijay Abraham I enum pci_barno bir, u32 offset) 3158963106eSGustavo Pimentel { 3168963106eSGustavo Pimentel int ret; 3178963106eSGustavo Pimentel 3188963106eSGustavo Pimentel if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 3198963106eSGustavo Pimentel interrupts < 1 || interrupts > 2048) 3208963106eSGustavo Pimentel return -EINVAL; 3218963106eSGustavo Pimentel 3228963106eSGustavo Pimentel if (!epc->ops->set_msix) 3238963106eSGustavo Pimentel return 0; 3248963106eSGustavo Pimentel 3253d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 32683153d9fSKishon Vijay Abraham I ret = epc->ops->set_msix(epc, func_no, interrupts - 1, bir, offset); 3273d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 3288963106eSGustavo Pimentel 3298963106eSGustavo Pimentel return ret; 3308963106eSGustavo Pimentel } 3318963106eSGustavo Pimentel EXPORT_SYMBOL_GPL(pci_epc_set_msix); 3328963106eSGustavo Pimentel 3338963106eSGustavo Pimentel /** 3345e8cb403SKishon Vijay Abraham I * pci_epc_unmap_addr() - unmap CPU address from PCI address 3355e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which address is allocated 3364494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 3375e8cb403SKishon Vijay Abraham I * @phys_addr: physical address of the local system 3385e8cb403SKishon Vijay Abraham I * 3395e8cb403SKishon Vijay Abraham I * Invoke to unmap the CPU address from PCI address. 3405e8cb403SKishon Vijay Abraham I */ 3414494738dSCyrille Pitchen void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, 3424494738dSCyrille Pitchen phys_addr_t phys_addr) 3435e8cb403SKishon Vijay Abraham I { 3444494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 3455e8cb403SKishon Vijay Abraham I return; 3465e8cb403SKishon Vijay Abraham I 3475e8cb403SKishon Vijay Abraham I if (!epc->ops->unmap_addr) 3485e8cb403SKishon Vijay Abraham I return; 3495e8cb403SKishon Vijay Abraham I 3503d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 3514494738dSCyrille Pitchen epc->ops->unmap_addr(epc, func_no, phys_addr); 3523d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 3535e8cb403SKishon Vijay Abraham I } 3545e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_unmap_addr); 3555e8cb403SKishon Vijay Abraham I 3565e8cb403SKishon Vijay Abraham I /** 3575e8cb403SKishon Vijay Abraham I * pci_epc_map_addr() - map CPU address to PCI address 3585e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which address is allocated 3594494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 3605e8cb403SKishon Vijay Abraham I * @phys_addr: physical address of the local system 3615e8cb403SKishon Vijay Abraham I * @pci_addr: PCI address to which the physical address should be mapped 3625e8cb403SKishon Vijay Abraham I * @size: the size of the allocation 3635e8cb403SKishon Vijay Abraham I * 3645e8cb403SKishon Vijay Abraham I * Invoke to map CPU address with PCI address. 3655e8cb403SKishon Vijay Abraham I */ 3664494738dSCyrille Pitchen int pci_epc_map_addr(struct pci_epc *epc, u8 func_no, 3674494738dSCyrille Pitchen phys_addr_t phys_addr, u64 pci_addr, size_t size) 3685e8cb403SKishon Vijay Abraham I { 3695e8cb403SKishon Vijay Abraham I int ret; 3705e8cb403SKishon Vijay Abraham I 3714494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 3725e8cb403SKishon Vijay Abraham I return -EINVAL; 3735e8cb403SKishon Vijay Abraham I 3745e8cb403SKishon Vijay Abraham I if (!epc->ops->map_addr) 3755e8cb403SKishon Vijay Abraham I return 0; 3765e8cb403SKishon Vijay Abraham I 3773d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 3784494738dSCyrille Pitchen ret = epc->ops->map_addr(epc, func_no, phys_addr, pci_addr, size); 3793d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 3805e8cb403SKishon Vijay Abraham I 3815e8cb403SKishon Vijay Abraham I return ret; 3825e8cb403SKishon Vijay Abraham I } 3835e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_map_addr); 3845e8cb403SKishon Vijay Abraham I 3855e8cb403SKishon Vijay Abraham I /** 3865e8cb403SKishon Vijay Abraham I * pci_epc_clear_bar() - reset the BAR 3875e8cb403SKishon Vijay Abraham I * @epc: the EPC device for which the BAR has to be cleared 3884494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 38977d08dbdSNiklas Cassel * @epf_bar: the struct epf_bar that contains the BAR information 3905e8cb403SKishon Vijay Abraham I * 3915e8cb403SKishon Vijay Abraham I * Invoke to reset the BAR of the endpoint device. 3925e8cb403SKishon Vijay Abraham I */ 39377d08dbdSNiklas Cassel void pci_epc_clear_bar(struct pci_epc *epc, u8 func_no, 39477d08dbdSNiklas Cassel struct pci_epf_bar *epf_bar) 3955e8cb403SKishon Vijay Abraham I { 3966474a4e5SNiklas Cassel if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 3976474a4e5SNiklas Cassel (epf_bar->barno == BAR_5 && 3986474a4e5SNiklas Cassel epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) 3995e8cb403SKishon Vijay Abraham I return; 4005e8cb403SKishon Vijay Abraham I 4015e8cb403SKishon Vijay Abraham I if (!epc->ops->clear_bar) 4025e8cb403SKishon Vijay Abraham I return; 4035e8cb403SKishon Vijay Abraham I 4043d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 40577d08dbdSNiklas Cassel epc->ops->clear_bar(epc, func_no, epf_bar); 4063d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 4075e8cb403SKishon Vijay Abraham I } 4085e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_clear_bar); 4095e8cb403SKishon Vijay Abraham I 4105e8cb403SKishon Vijay Abraham I /** 4115e8cb403SKishon Vijay Abraham I * pci_epc_set_bar() - configure BAR in order for host to assign PCI addr space 4125e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which BAR has to be configured 4134494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 414bc4a4897SNiklas Cassel * @epf_bar: the struct epf_bar that contains the BAR information 4155e8cb403SKishon Vijay Abraham I * 4165e8cb403SKishon Vijay Abraham I * Invoke to configure the BAR of the endpoint device. 4175e8cb403SKishon Vijay Abraham I */ 418bc4a4897SNiklas Cassel int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, 419bc4a4897SNiklas Cassel struct pci_epf_bar *epf_bar) 4205e8cb403SKishon Vijay Abraham I { 4215e8cb403SKishon Vijay Abraham I int ret; 4223567a4edSNiklas Cassel int flags = epf_bar->flags; 4235e8cb403SKishon Vijay Abraham I 424f16b1f6fSNiklas Cassel if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 425f16b1f6fSNiklas Cassel (epf_bar->barno == BAR_5 && 4263567a4edSNiklas Cassel flags & PCI_BASE_ADDRESS_MEM_TYPE_64) || 4273567a4edSNiklas Cassel (flags & PCI_BASE_ADDRESS_SPACE_IO && 428f25b5faeSNiklas Cassel flags & PCI_BASE_ADDRESS_IO_MASK) || 429f25b5faeSNiklas Cassel (upper_32_bits(epf_bar->size) && 430f25b5faeSNiklas Cassel !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64))) 4315e8cb403SKishon Vijay Abraham I return -EINVAL; 4325e8cb403SKishon Vijay Abraham I 4335e8cb403SKishon Vijay Abraham I if (!epc->ops->set_bar) 4345e8cb403SKishon Vijay Abraham I return 0; 4355e8cb403SKishon Vijay Abraham I 4363d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 437bc4a4897SNiklas Cassel ret = epc->ops->set_bar(epc, func_no, epf_bar); 4383d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 4395e8cb403SKishon Vijay Abraham I 4405e8cb403SKishon Vijay Abraham I return ret; 4415e8cb403SKishon Vijay Abraham I } 4425e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_set_bar); 4435e8cb403SKishon Vijay Abraham I 4445e8cb403SKishon Vijay Abraham I /** 4455e8cb403SKishon Vijay Abraham I * pci_epc_write_header() - write standard configuration header 4465e8cb403SKishon Vijay Abraham I * @epc: the EPC device to which the configuration header should be written 4474494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 4485e8cb403SKishon Vijay Abraham I * @header: standard configuration header fields 4495e8cb403SKishon Vijay Abraham I * 4505e8cb403SKishon Vijay Abraham I * Invoke to write the configuration header to the endpoint controller. Every 4515e8cb403SKishon Vijay Abraham I * endpoint controller will have a dedicated location to which the standard 4525e8cb403SKishon Vijay Abraham I * configuration header would be written. The callback function should write 4535e8cb403SKishon Vijay Abraham I * the header fields to this dedicated location. 4545e8cb403SKishon Vijay Abraham I */ 4554494738dSCyrille Pitchen int pci_epc_write_header(struct pci_epc *epc, u8 func_no, 4564494738dSCyrille Pitchen struct pci_epf_header *header) 4575e8cb403SKishon Vijay Abraham I { 4585e8cb403SKishon Vijay Abraham I int ret; 4595e8cb403SKishon Vijay Abraham I 4604494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 4615e8cb403SKishon Vijay Abraham I return -EINVAL; 4625e8cb403SKishon Vijay Abraham I 4635e8cb403SKishon Vijay Abraham I if (!epc->ops->write_header) 4645e8cb403SKishon Vijay Abraham I return 0; 4655e8cb403SKishon Vijay Abraham I 4663d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 4674494738dSCyrille Pitchen ret = epc->ops->write_header(epc, func_no, header); 4683d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 4695e8cb403SKishon Vijay Abraham I 4705e8cb403SKishon Vijay Abraham I return ret; 4715e8cb403SKishon Vijay Abraham I } 4725e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_write_header); 4735e8cb403SKishon Vijay Abraham I 4745e8cb403SKishon Vijay Abraham I /** 4755e8cb403SKishon Vijay Abraham I * pci_epc_add_epf() - bind PCI endpoint function to an endpoint controller 4765e8cb403SKishon Vijay Abraham I * @epc: the EPC device to which the endpoint function should be added 4775e8cb403SKishon Vijay Abraham I * @epf: the endpoint function to be added 4785e8cb403SKishon Vijay Abraham I * 4795e8cb403SKishon Vijay Abraham I * A PCI endpoint device can have one or more functions. In the case of PCIe, 4805e8cb403SKishon Vijay Abraham I * the specification allows up to 8 PCIe endpoint functions. Invoke 4815e8cb403SKishon Vijay Abraham I * pci_epc_add_epf() to add a PCI endpoint function to an endpoint controller. 4825e8cb403SKishon Vijay Abraham I */ 4835e8cb403SKishon Vijay Abraham I int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf) 4845e8cb403SKishon Vijay Abraham I { 4852499ee84SKishon Vijay Abraham I u32 func_no; 4862499ee84SKishon Vijay Abraham I int ret = 0; 4872499ee84SKishon Vijay Abraham I 4885e8cb403SKishon Vijay Abraham I if (epf->epc) 4895e8cb403SKishon Vijay Abraham I return -EBUSY; 4905e8cb403SKishon Vijay Abraham I 4915e8cb403SKishon Vijay Abraham I if (IS_ERR(epc)) 4925e8cb403SKishon Vijay Abraham I return -EINVAL; 4935e8cb403SKishon Vijay Abraham I 4942499ee84SKishon Vijay Abraham I mutex_lock(&epc->lock); 4952499ee84SKishon Vijay Abraham I func_no = find_first_zero_bit(&epc->function_num_map, 4962499ee84SKishon Vijay Abraham I BITS_PER_LONG); 4972499ee84SKishon Vijay Abraham I if (func_no >= BITS_PER_LONG) { 4982499ee84SKishon Vijay Abraham I ret = -EINVAL; 4992499ee84SKishon Vijay Abraham I goto ret; 5002499ee84SKishon Vijay Abraham I } 5015e8cb403SKishon Vijay Abraham I 5022499ee84SKishon Vijay Abraham I if (func_no > epc->max_functions - 1) { 5032499ee84SKishon Vijay Abraham I dev_err(&epc->dev, "Exceeding max supported Function Number\n"); 5042499ee84SKishon Vijay Abraham I ret = -EINVAL; 5052499ee84SKishon Vijay Abraham I goto ret; 5062499ee84SKishon Vijay Abraham I } 5072499ee84SKishon Vijay Abraham I 5082499ee84SKishon Vijay Abraham I set_bit(func_no, &epc->function_num_map); 5092499ee84SKishon Vijay Abraham I epf->func_no = func_no; 5105e8cb403SKishon Vijay Abraham I epf->epc = epc; 5115e8cb403SKishon Vijay Abraham I 5125e8cb403SKishon Vijay Abraham I list_add_tail(&epf->list, &epc->pci_epf); 5132499ee84SKishon Vijay Abraham I 5142499ee84SKishon Vijay Abraham I ret: 5153d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 5165e8cb403SKishon Vijay Abraham I 5172499ee84SKishon Vijay Abraham I return ret; 5185e8cb403SKishon Vijay Abraham I } 5195e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_add_epf); 5205e8cb403SKishon Vijay Abraham I 5215e8cb403SKishon Vijay Abraham I /** 5225e8cb403SKishon Vijay Abraham I * pci_epc_remove_epf() - remove PCI endpoint function from endpoint controller 5235e8cb403SKishon Vijay Abraham I * @epc: the EPC device from which the endpoint function should be removed 5245e8cb403SKishon Vijay Abraham I * @epf: the endpoint function to be removed 5255e8cb403SKishon Vijay Abraham I * 5265e8cb403SKishon Vijay Abraham I * Invoke to remove PCI endpoint function from the endpoint controller. 5275e8cb403SKishon Vijay Abraham I */ 5285e8cb403SKishon Vijay Abraham I void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf) 5295e8cb403SKishon Vijay Abraham I { 530db7a6248SAlan Mikhak if (!epc || IS_ERR(epc) || !epf) 5315e8cb403SKishon Vijay Abraham I return; 5325e8cb403SKishon Vijay Abraham I 5333d3248dbSKishon Vijay Abraham I mutex_lock(&epc->lock); 5342499ee84SKishon Vijay Abraham I clear_bit(epf->func_no, &epc->function_num_map); 5355e8cb403SKishon Vijay Abraham I list_del(&epf->list); 536db7a6248SAlan Mikhak epf->epc = NULL; 5373d3248dbSKishon Vijay Abraham I mutex_unlock(&epc->lock); 5385e8cb403SKishon Vijay Abraham I } 5395e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_remove_epf); 5405e8cb403SKishon Vijay Abraham I 5415e8cb403SKishon Vijay Abraham I /** 5425e8cb403SKishon Vijay Abraham I * pci_epc_linkup() - Notify the EPF device that EPC device has established a 5435e8cb403SKishon Vijay Abraham I * connection with the Root Complex. 5445e8cb403SKishon Vijay Abraham I * @epc: the EPC device which has established link with the host 5455e8cb403SKishon Vijay Abraham I * 5465e8cb403SKishon Vijay Abraham I * Invoke to Notify the EPF device that the EPC device has established a 5475e8cb403SKishon Vijay Abraham I * connection with the Root Complex. 5485e8cb403SKishon Vijay Abraham I */ 5495e8cb403SKishon Vijay Abraham I void pci_epc_linkup(struct pci_epc *epc) 5505e8cb403SKishon Vijay Abraham I { 5515e8cb403SKishon Vijay Abraham I if (!epc || IS_ERR(epc)) 5525e8cb403SKishon Vijay Abraham I return; 5535e8cb403SKishon Vijay Abraham I 5540ef22dcfSVidya Sagar atomic_notifier_call_chain(&epc->notifier, LINK_UP, NULL); 5555e8cb403SKishon Vijay Abraham I } 5565e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_linkup); 5575e8cb403SKishon Vijay Abraham I 5585e8cb403SKishon Vijay Abraham I /** 5590ef22dcfSVidya Sagar * pci_epc_init_notify() - Notify the EPF device that EPC device's core 5600ef22dcfSVidya Sagar * initialization is completed. 5610ef22dcfSVidya Sagar * @epc: the EPC device whose core initialization is completeds 5620ef22dcfSVidya Sagar * 5630ef22dcfSVidya Sagar * Invoke to Notify the EPF device that the EPC device's initialization 5640ef22dcfSVidya Sagar * is completed. 5650ef22dcfSVidya Sagar */ 5660ef22dcfSVidya Sagar void pci_epc_init_notify(struct pci_epc *epc) 5670ef22dcfSVidya Sagar { 5680ef22dcfSVidya Sagar if (!epc || IS_ERR(epc)) 5690ef22dcfSVidya Sagar return; 5700ef22dcfSVidya Sagar 5710ef22dcfSVidya Sagar atomic_notifier_call_chain(&epc->notifier, CORE_INIT, NULL); 5720ef22dcfSVidya Sagar } 5730ef22dcfSVidya Sagar EXPORT_SYMBOL_GPL(pci_epc_init_notify); 5740ef22dcfSVidya Sagar 5750ef22dcfSVidya Sagar /** 5765e8cb403SKishon Vijay Abraham I * pci_epc_destroy() - destroy the EPC device 5775e8cb403SKishon Vijay Abraham I * @epc: the EPC device that has to be destroyed 5785e8cb403SKishon Vijay Abraham I * 5795e8cb403SKishon Vijay Abraham I * Invoke to destroy the PCI EPC device 5805e8cb403SKishon Vijay Abraham I */ 5815e8cb403SKishon Vijay Abraham I void pci_epc_destroy(struct pci_epc *epc) 5825e8cb403SKishon Vijay Abraham I { 5833a401a2cSKishon Vijay Abraham I pci_ep_cfs_remove_epc_group(epc->group); 5845e8cb403SKishon Vijay Abraham I device_unregister(&epc->dev); 5855e8cb403SKishon Vijay Abraham I kfree(epc); 5865e8cb403SKishon Vijay Abraham I } 5875e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_destroy); 5885e8cb403SKishon Vijay Abraham I 5895e8cb403SKishon Vijay Abraham I /** 5905e8cb403SKishon Vijay Abraham I * devm_pci_epc_destroy() - destroy the EPC device 5915e8cb403SKishon Vijay Abraham I * @dev: device that wants to destroy the EPC 5925e8cb403SKishon Vijay Abraham I * @epc: the EPC device that has to be destroyed 5935e8cb403SKishon Vijay Abraham I * 5945e8cb403SKishon Vijay Abraham I * Invoke to destroy the devres associated with this 5955e8cb403SKishon Vijay Abraham I * pci_epc and destroy the EPC device. 5965e8cb403SKishon Vijay Abraham I */ 5975e8cb403SKishon Vijay Abraham I void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc) 5985e8cb403SKishon Vijay Abraham I { 5995e8cb403SKishon Vijay Abraham I int r; 6005e8cb403SKishon Vijay Abraham I 6015e8cb403SKishon Vijay Abraham I r = devres_destroy(dev, devm_pci_epc_release, devm_pci_epc_match, 6025e8cb403SKishon Vijay Abraham I epc); 6035e8cb403SKishon Vijay Abraham I dev_WARN_ONCE(dev, r, "couldn't find PCI EPC resource\n"); 6045e8cb403SKishon Vijay Abraham I } 6055e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(devm_pci_epc_destroy); 6065e8cb403SKishon Vijay Abraham I 6075e8cb403SKishon Vijay Abraham I /** 6085e8cb403SKishon Vijay Abraham I * __pci_epc_create() - create a new endpoint controller (EPC) device 6095e8cb403SKishon Vijay Abraham I * @dev: device that is creating the new EPC 6105e8cb403SKishon Vijay Abraham I * @ops: function pointers for performing EPC operations 6115e8cb403SKishon Vijay Abraham I * @owner: the owner of the module that creates the EPC device 6125e8cb403SKishon Vijay Abraham I * 6135e8cb403SKishon Vijay Abraham I * Invoke to create a new EPC device and add it to pci_epc class. 6145e8cb403SKishon Vijay Abraham I */ 6155e8cb403SKishon Vijay Abraham I struct pci_epc * 6165e8cb403SKishon Vijay Abraham I __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, 6175e8cb403SKishon Vijay Abraham I struct module *owner) 6185e8cb403SKishon Vijay Abraham I { 6195e8cb403SKishon Vijay Abraham I int ret; 6205e8cb403SKishon Vijay Abraham I struct pci_epc *epc; 6215e8cb403SKishon Vijay Abraham I 6225e8cb403SKishon Vijay Abraham I if (WARN_ON(!dev)) { 6235e8cb403SKishon Vijay Abraham I ret = -EINVAL; 6245e8cb403SKishon Vijay Abraham I goto err_ret; 6255e8cb403SKishon Vijay Abraham I } 6265e8cb403SKishon Vijay Abraham I 6275e8cb403SKishon Vijay Abraham I epc = kzalloc(sizeof(*epc), GFP_KERNEL); 6285e8cb403SKishon Vijay Abraham I if (!epc) { 6295e8cb403SKishon Vijay Abraham I ret = -ENOMEM; 6305e8cb403SKishon Vijay Abraham I goto err_ret; 6315e8cb403SKishon Vijay Abraham I } 6325e8cb403SKishon Vijay Abraham I 6333d3248dbSKishon Vijay Abraham I mutex_init(&epc->lock); 6345e8cb403SKishon Vijay Abraham I INIT_LIST_HEAD(&epc->pci_epf); 6355779dd0aSKishon Vijay Abraham I ATOMIC_INIT_NOTIFIER_HEAD(&epc->notifier); 6365e8cb403SKishon Vijay Abraham I 6375e8cb403SKishon Vijay Abraham I device_initialize(&epc->dev); 6385e8cb403SKishon Vijay Abraham I epc->dev.class = pci_epc_class; 63964c1a02aSKishon Vijay Abraham I epc->dev.parent = dev; 6405e8cb403SKishon Vijay Abraham I epc->ops = ops; 6415e8cb403SKishon Vijay Abraham I 6425e8cb403SKishon Vijay Abraham I ret = dev_set_name(&epc->dev, "%s", dev_name(dev)); 6435e8cb403SKishon Vijay Abraham I if (ret) 6445e8cb403SKishon Vijay Abraham I goto put_dev; 6455e8cb403SKishon Vijay Abraham I 6465e8cb403SKishon Vijay Abraham I ret = device_add(&epc->dev); 6475e8cb403SKishon Vijay Abraham I if (ret) 6485e8cb403SKishon Vijay Abraham I goto put_dev; 6495e8cb403SKishon Vijay Abraham I 6503a401a2cSKishon Vijay Abraham I epc->group = pci_ep_cfs_add_epc_group(dev_name(dev)); 6513a401a2cSKishon Vijay Abraham I 6525e8cb403SKishon Vijay Abraham I return epc; 6535e8cb403SKishon Vijay Abraham I 6545e8cb403SKishon Vijay Abraham I put_dev: 6555e8cb403SKishon Vijay Abraham I put_device(&epc->dev); 6565e8cb403SKishon Vijay Abraham I kfree(epc); 6575e8cb403SKishon Vijay Abraham I 6585e8cb403SKishon Vijay Abraham I err_ret: 6595e8cb403SKishon Vijay Abraham I return ERR_PTR(ret); 6605e8cb403SKishon Vijay Abraham I } 6615e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(__pci_epc_create); 6625e8cb403SKishon Vijay Abraham I 6635e8cb403SKishon Vijay Abraham I /** 6645e8cb403SKishon Vijay Abraham I * __devm_pci_epc_create() - create a new endpoint controller (EPC) device 6655e8cb403SKishon Vijay Abraham I * @dev: device that is creating the new EPC 6665e8cb403SKishon Vijay Abraham I * @ops: function pointers for performing EPC operations 6675e8cb403SKishon Vijay Abraham I * @owner: the owner of the module that creates the EPC device 6685e8cb403SKishon Vijay Abraham I * 6695e8cb403SKishon Vijay Abraham I * Invoke to create a new EPC device and add it to pci_epc class. 6705e8cb403SKishon Vijay Abraham I * While at that, it also associates the device with the pci_epc using devres. 6715e8cb403SKishon Vijay Abraham I * On driver detach, release function is invoked on the devres data, 6725e8cb403SKishon Vijay Abraham I * then, devres data is freed. 6735e8cb403SKishon Vijay Abraham I */ 6745e8cb403SKishon Vijay Abraham I struct pci_epc * 6755e8cb403SKishon Vijay Abraham I __devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, 6765e8cb403SKishon Vijay Abraham I struct module *owner) 6775e8cb403SKishon Vijay Abraham I { 6785e8cb403SKishon Vijay Abraham I struct pci_epc **ptr, *epc; 6795e8cb403SKishon Vijay Abraham I 6805e8cb403SKishon Vijay Abraham I ptr = devres_alloc(devm_pci_epc_release, sizeof(*ptr), GFP_KERNEL); 6815e8cb403SKishon Vijay Abraham I if (!ptr) 6825e8cb403SKishon Vijay Abraham I return ERR_PTR(-ENOMEM); 6835e8cb403SKishon Vijay Abraham I 6845e8cb403SKishon Vijay Abraham I epc = __pci_epc_create(dev, ops, owner); 6855e8cb403SKishon Vijay Abraham I if (!IS_ERR(epc)) { 6865e8cb403SKishon Vijay Abraham I *ptr = epc; 6875e8cb403SKishon Vijay Abraham I devres_add(dev, ptr); 6885e8cb403SKishon Vijay Abraham I } else { 6895e8cb403SKishon Vijay Abraham I devres_free(ptr); 6905e8cb403SKishon Vijay Abraham I } 6915e8cb403SKishon Vijay Abraham I 6925e8cb403SKishon Vijay Abraham I return epc; 6935e8cb403SKishon Vijay Abraham I } 6945e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(__devm_pci_epc_create); 6955e8cb403SKishon Vijay Abraham I 6965e8cb403SKishon Vijay Abraham I static int __init pci_epc_init(void) 6975e8cb403SKishon Vijay Abraham I { 6985e8cb403SKishon Vijay Abraham I pci_epc_class = class_create(THIS_MODULE, "pci_epc"); 6995e8cb403SKishon Vijay Abraham I if (IS_ERR(pci_epc_class)) { 7005e8cb403SKishon Vijay Abraham I pr_err("failed to create pci epc class --> %ld\n", 7015e8cb403SKishon Vijay Abraham I PTR_ERR(pci_epc_class)); 7025e8cb403SKishon Vijay Abraham I return PTR_ERR(pci_epc_class); 7035e8cb403SKishon Vijay Abraham I } 7045e8cb403SKishon Vijay Abraham I 7055e8cb403SKishon Vijay Abraham I return 0; 7065e8cb403SKishon Vijay Abraham I } 7075e8cb403SKishon Vijay Abraham I module_init(pci_epc_init); 7085e8cb403SKishon Vijay Abraham I 7095e8cb403SKishon Vijay Abraham I static void __exit pci_epc_exit(void) 7105e8cb403SKishon Vijay Abraham I { 7115e8cb403SKishon Vijay Abraham I class_destroy(pci_epc_class); 7125e8cb403SKishon Vijay Abraham I } 7135e8cb403SKishon Vijay Abraham I module_exit(pci_epc_exit); 7145e8cb403SKishon Vijay Abraham I 7155e8cb403SKishon Vijay Abraham I MODULE_DESCRIPTION("PCI EPC Library"); 7165e8cb403SKishon Vijay Abraham I MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); 7175e8cb403SKishon Vijay Abraham I MODULE_LICENSE("GPL v2"); 718