15e8cb403SKishon Vijay Abraham I /** 25e8cb403SKishon Vijay Abraham I * PCI Endpoint *Controller* (EPC) library 35e8cb403SKishon Vijay Abraham I * 45e8cb403SKishon Vijay Abraham I * Copyright (C) 2017 Texas Instruments 55e8cb403SKishon Vijay Abraham I * Author: Kishon Vijay Abraham I <kishon@ti.com> 65e8cb403SKishon Vijay Abraham I * 75e8cb403SKishon Vijay Abraham I * This program is free software: you can redistribute it and/or modify 85e8cb403SKishon Vijay Abraham I * it under the terms of the GNU General Public License version 2 of 95e8cb403SKishon Vijay Abraham I * the License as published by the Free Software Foundation. 105e8cb403SKishon Vijay Abraham I * 115e8cb403SKishon Vijay Abraham I * This program is distributed in the hope that it will be useful, 125e8cb403SKishon Vijay Abraham I * but WITHOUT ANY WARRANTY; without even the implied warranty of 135e8cb403SKishon Vijay Abraham I * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 145e8cb403SKishon Vijay Abraham I * GNU General Public License for more details. 155e8cb403SKishon Vijay Abraham I * 165e8cb403SKishon Vijay Abraham I * You should have received a copy of the GNU General Public License 175e8cb403SKishon Vijay Abraham I * along with this program. If not, see <http://www.gnu.org/licenses/>. 185e8cb403SKishon Vijay Abraham I */ 195e8cb403SKishon Vijay Abraham I 205e8cb403SKishon Vijay Abraham I #include <linux/device.h> 215e8cb403SKishon Vijay Abraham I #include <linux/dma-mapping.h> 225e8cb403SKishon Vijay Abraham I #include <linux/slab.h> 235e8cb403SKishon Vijay Abraham I #include <linux/module.h> 2464c1a02aSKishon Vijay Abraham I #include <linux/of_device.h> 255e8cb403SKishon Vijay Abraham I 265e8cb403SKishon Vijay Abraham I #include <linux/pci-epc.h> 275e8cb403SKishon Vijay Abraham I #include <linux/pci-epf.h> 283a401a2cSKishon Vijay Abraham I #include <linux/pci-ep-cfs.h> 295e8cb403SKishon Vijay Abraham I 305e8cb403SKishon Vijay Abraham I static struct class *pci_epc_class; 315e8cb403SKishon Vijay Abraham I 325e8cb403SKishon Vijay Abraham I static void devm_pci_epc_release(struct device *dev, void *res) 335e8cb403SKishon Vijay Abraham I { 345e8cb403SKishon Vijay Abraham I struct pci_epc *epc = *(struct pci_epc **)res; 355e8cb403SKishon Vijay Abraham I 365e8cb403SKishon Vijay Abraham I pci_epc_destroy(epc); 375e8cb403SKishon Vijay Abraham I } 385e8cb403SKishon Vijay Abraham I 395e8cb403SKishon Vijay Abraham I static int devm_pci_epc_match(struct device *dev, void *res, void *match_data) 405e8cb403SKishon Vijay Abraham I { 415e8cb403SKishon Vijay Abraham I struct pci_epc **epc = res; 425e8cb403SKishon Vijay Abraham I 435e8cb403SKishon Vijay Abraham I return *epc == match_data; 445e8cb403SKishon Vijay Abraham I } 455e8cb403SKishon Vijay Abraham I 465e8cb403SKishon Vijay Abraham I /** 475e8cb403SKishon Vijay Abraham I * pci_epc_put() - release the PCI endpoint controller 485e8cb403SKishon Vijay Abraham I * @epc: epc returned by pci_epc_get() 495e8cb403SKishon Vijay Abraham I * 505e8cb403SKishon Vijay Abraham I * release the refcount the caller obtained by invoking pci_epc_get() 515e8cb403SKishon Vijay Abraham I */ 525e8cb403SKishon Vijay Abraham I void pci_epc_put(struct pci_epc *epc) 535e8cb403SKishon Vijay Abraham I { 545e8cb403SKishon Vijay Abraham I if (!epc || IS_ERR(epc)) 555e8cb403SKishon Vijay Abraham I return; 565e8cb403SKishon Vijay Abraham I 575e8cb403SKishon Vijay Abraham I module_put(epc->ops->owner); 585e8cb403SKishon Vijay Abraham I put_device(&epc->dev); 595e8cb403SKishon Vijay Abraham I } 605e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_put); 615e8cb403SKishon Vijay Abraham I 625e8cb403SKishon Vijay Abraham I /** 635e8cb403SKishon Vijay Abraham I * pci_epc_get() - get the PCI endpoint controller 645e8cb403SKishon Vijay Abraham I * @epc_name: device name of the endpoint controller 655e8cb403SKishon Vijay Abraham I * 665e8cb403SKishon Vijay Abraham I * Invoke to get struct pci_epc * corresponding to the device name of the 675e8cb403SKishon Vijay Abraham I * endpoint controller 685e8cb403SKishon Vijay Abraham I */ 695e8cb403SKishon Vijay Abraham I struct pci_epc *pci_epc_get(const char *epc_name) 705e8cb403SKishon Vijay Abraham I { 715e8cb403SKishon Vijay Abraham I int ret = -EINVAL; 725e8cb403SKishon Vijay Abraham I struct pci_epc *epc; 735e8cb403SKishon Vijay Abraham I struct device *dev; 745e8cb403SKishon Vijay Abraham I struct class_dev_iter iter; 755e8cb403SKishon Vijay Abraham I 765e8cb403SKishon Vijay Abraham I class_dev_iter_init(&iter, pci_epc_class, NULL, NULL); 775e8cb403SKishon Vijay Abraham I while ((dev = class_dev_iter_next(&iter))) { 785e8cb403SKishon Vijay Abraham I if (strcmp(epc_name, dev_name(dev))) 795e8cb403SKishon Vijay Abraham I continue; 805e8cb403SKishon Vijay Abraham I 815e8cb403SKishon Vijay Abraham I epc = to_pci_epc(dev); 825e8cb403SKishon Vijay Abraham I if (!try_module_get(epc->ops->owner)) { 835e8cb403SKishon Vijay Abraham I ret = -EINVAL; 845e8cb403SKishon Vijay Abraham I goto err; 855e8cb403SKishon Vijay Abraham I } 865e8cb403SKishon Vijay Abraham I 875e8cb403SKishon Vijay Abraham I class_dev_iter_exit(&iter); 885e8cb403SKishon Vijay Abraham I get_device(&epc->dev); 895e8cb403SKishon Vijay Abraham I return epc; 905e8cb403SKishon Vijay Abraham I } 915e8cb403SKishon Vijay Abraham I 925e8cb403SKishon Vijay Abraham I err: 935e8cb403SKishon Vijay Abraham I class_dev_iter_exit(&iter); 945e8cb403SKishon Vijay Abraham I return ERR_PTR(ret); 955e8cb403SKishon Vijay Abraham I } 965e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_get); 975e8cb403SKishon Vijay Abraham I 985e8cb403SKishon Vijay Abraham I /** 995e8cb403SKishon Vijay Abraham I * pci_epc_stop() - stop the PCI link 1005e8cb403SKishon Vijay Abraham I * @epc: the link of the EPC device that has to be stopped 1015e8cb403SKishon Vijay Abraham I * 1025e8cb403SKishon Vijay Abraham I * Invoke to stop the PCI link 1035e8cb403SKishon Vijay Abraham I */ 1045e8cb403SKishon Vijay Abraham I void pci_epc_stop(struct pci_epc *epc) 1055e8cb403SKishon Vijay Abraham I { 1065e8cb403SKishon Vijay Abraham I unsigned long flags; 1075e8cb403SKishon Vijay Abraham I 1085e8cb403SKishon Vijay Abraham I if (IS_ERR(epc) || !epc->ops->stop) 1095e8cb403SKishon Vijay Abraham I return; 1105e8cb403SKishon Vijay Abraham I 1115e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 1125e8cb403SKishon Vijay Abraham I epc->ops->stop(epc); 1135e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 1145e8cb403SKishon Vijay Abraham I } 1155e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_stop); 1165e8cb403SKishon Vijay Abraham I 1175e8cb403SKishon Vijay Abraham I /** 1185e8cb403SKishon Vijay Abraham I * pci_epc_start() - start the PCI link 1195e8cb403SKishon Vijay Abraham I * @epc: the link of *this* EPC device has to be started 1205e8cb403SKishon Vijay Abraham I * 1215e8cb403SKishon Vijay Abraham I * Invoke to start the PCI link 1225e8cb403SKishon Vijay Abraham I */ 1235e8cb403SKishon Vijay Abraham I int pci_epc_start(struct pci_epc *epc) 1245e8cb403SKishon Vijay Abraham I { 1255e8cb403SKishon Vijay Abraham I int ret; 1265e8cb403SKishon Vijay Abraham I unsigned long flags; 1275e8cb403SKishon Vijay Abraham I 1285e8cb403SKishon Vijay Abraham I if (IS_ERR(epc)) 1295e8cb403SKishon Vijay Abraham I return -EINVAL; 1305e8cb403SKishon Vijay Abraham I 1315e8cb403SKishon Vijay Abraham I if (!epc->ops->start) 1325e8cb403SKishon Vijay Abraham I return 0; 1335e8cb403SKishon Vijay Abraham I 1345e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 1355e8cb403SKishon Vijay Abraham I ret = epc->ops->start(epc); 1365e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 1375e8cb403SKishon Vijay Abraham I 1385e8cb403SKishon Vijay Abraham I return ret; 1395e8cb403SKishon Vijay Abraham I } 1405e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_start); 1415e8cb403SKishon Vijay Abraham I 1425e8cb403SKishon Vijay Abraham I /** 1435e8cb403SKishon Vijay Abraham I * pci_epc_raise_irq() - interrupt the host system 1445e8cb403SKishon Vijay Abraham I * @epc: the EPC device which has to interrupt the host 1454494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 1465e8cb403SKishon Vijay Abraham I * @type: specify the type of interrupt; legacy or MSI 1475e8cb403SKishon Vijay Abraham I * @interrupt_num: the MSI interrupt number 1485e8cb403SKishon Vijay Abraham I * 1495e8cb403SKishon Vijay Abraham I * Invoke to raise an MSI or legacy interrupt 1505e8cb403SKishon Vijay Abraham I */ 1514494738dSCyrille Pitchen int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, 1524494738dSCyrille Pitchen enum pci_epc_irq_type type, u8 interrupt_num) 1535e8cb403SKishon Vijay Abraham I { 1545e8cb403SKishon Vijay Abraham I int ret; 1555e8cb403SKishon Vijay Abraham I unsigned long flags; 1565e8cb403SKishon Vijay Abraham I 1574494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 1585e8cb403SKishon Vijay Abraham I return -EINVAL; 1595e8cb403SKishon Vijay Abraham I 1605e8cb403SKishon Vijay Abraham I if (!epc->ops->raise_irq) 1615e8cb403SKishon Vijay Abraham I return 0; 1625e8cb403SKishon Vijay Abraham I 1635e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 1644494738dSCyrille Pitchen ret = epc->ops->raise_irq(epc, func_no, type, interrupt_num); 1655e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 1665e8cb403SKishon Vijay Abraham I 1675e8cb403SKishon Vijay Abraham I return ret; 1685e8cb403SKishon Vijay Abraham I } 1695e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_raise_irq); 1705e8cb403SKishon Vijay Abraham I 1715e8cb403SKishon Vijay Abraham I /** 1725e8cb403SKishon Vijay Abraham I * pci_epc_get_msi() - get the number of MSI interrupt numbers allocated 1735e8cb403SKishon Vijay Abraham I * @epc: the EPC device to which MSI interrupts was requested 1744494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 1755e8cb403SKishon Vijay Abraham I * 1765e8cb403SKishon Vijay Abraham I * Invoke to get the number of MSI interrupts allocated by the RC 1775e8cb403SKishon Vijay Abraham I */ 1784494738dSCyrille Pitchen int pci_epc_get_msi(struct pci_epc *epc, u8 func_no) 1795e8cb403SKishon Vijay Abraham I { 1805e8cb403SKishon Vijay Abraham I int interrupt; 1815e8cb403SKishon Vijay Abraham I unsigned long flags; 1825e8cb403SKishon Vijay Abraham I 1834494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 1845e8cb403SKishon Vijay Abraham I return 0; 1855e8cb403SKishon Vijay Abraham I 1865e8cb403SKishon Vijay Abraham I if (!epc->ops->get_msi) 1875e8cb403SKishon Vijay Abraham I return 0; 1885e8cb403SKishon Vijay Abraham I 1895e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 1904494738dSCyrille Pitchen interrupt = epc->ops->get_msi(epc, func_no); 1915e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 1925e8cb403SKishon Vijay Abraham I 1935e8cb403SKishon Vijay Abraham I if (interrupt < 0) 1945e8cb403SKishon Vijay Abraham I return 0; 1955e8cb403SKishon Vijay Abraham I 1965e8cb403SKishon Vijay Abraham I interrupt = 1 << interrupt; 1975e8cb403SKishon Vijay Abraham I 1985e8cb403SKishon Vijay Abraham I return interrupt; 1995e8cb403SKishon Vijay Abraham I } 2005e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_get_msi); 2015e8cb403SKishon Vijay Abraham I 2025e8cb403SKishon Vijay Abraham I /** 2035e8cb403SKishon Vijay Abraham I * pci_epc_set_msi() - set the number of MSI interrupt numbers required 2045e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which MSI has to be configured 2054494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 2065e8cb403SKishon Vijay Abraham I * @interrupts: number of MSI interrupts required by the EPF 2075e8cb403SKishon Vijay Abraham I * 2085e8cb403SKishon Vijay Abraham I * Invoke to set the required number of MSI interrupts. 2095e8cb403SKishon Vijay Abraham I */ 2104494738dSCyrille Pitchen int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) 2115e8cb403SKishon Vijay Abraham I { 2125e8cb403SKishon Vijay Abraham I int ret; 2135e8cb403SKishon Vijay Abraham I u8 encode_int; 2145e8cb403SKishon Vijay Abraham I unsigned long flags; 2155e8cb403SKishon Vijay Abraham I 2164494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 2175e8cb403SKishon Vijay Abraham I return -EINVAL; 2185e8cb403SKishon Vijay Abraham I 2195e8cb403SKishon Vijay Abraham I if (!epc->ops->set_msi) 2205e8cb403SKishon Vijay Abraham I return 0; 2215e8cb403SKishon Vijay Abraham I 2225e8cb403SKishon Vijay Abraham I encode_int = order_base_2(interrupts); 2235e8cb403SKishon Vijay Abraham I 2245e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 2254494738dSCyrille Pitchen ret = epc->ops->set_msi(epc, func_no, encode_int); 2265e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 2275e8cb403SKishon Vijay Abraham I 2285e8cb403SKishon Vijay Abraham I return ret; 2295e8cb403SKishon Vijay Abraham I } 2305e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_set_msi); 2315e8cb403SKishon Vijay Abraham I 2325e8cb403SKishon Vijay Abraham I /** 2335e8cb403SKishon Vijay Abraham I * pci_epc_unmap_addr() - unmap CPU address from PCI address 2345e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which address is allocated 2354494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 2365e8cb403SKishon Vijay Abraham I * @phys_addr: physical address of the local system 2375e8cb403SKishon Vijay Abraham I * 2385e8cb403SKishon Vijay Abraham I * Invoke to unmap the CPU address from PCI address. 2395e8cb403SKishon Vijay Abraham I */ 2404494738dSCyrille Pitchen void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, 2414494738dSCyrille Pitchen phys_addr_t phys_addr) 2425e8cb403SKishon Vijay Abraham I { 2435e8cb403SKishon Vijay Abraham I unsigned long flags; 2445e8cb403SKishon Vijay Abraham I 2454494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 2465e8cb403SKishon Vijay Abraham I return; 2475e8cb403SKishon Vijay Abraham I 2485e8cb403SKishon Vijay Abraham I if (!epc->ops->unmap_addr) 2495e8cb403SKishon Vijay Abraham I return; 2505e8cb403SKishon Vijay Abraham I 2515e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 2524494738dSCyrille Pitchen epc->ops->unmap_addr(epc, func_no, phys_addr); 2535e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 2545e8cb403SKishon Vijay Abraham I } 2555e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_unmap_addr); 2565e8cb403SKishon Vijay Abraham I 2575e8cb403SKishon Vijay Abraham I /** 2585e8cb403SKishon Vijay Abraham I * pci_epc_map_addr() - map CPU address to PCI address 2595e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which address is allocated 2604494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 2615e8cb403SKishon Vijay Abraham I * @phys_addr: physical address of the local system 2625e8cb403SKishon Vijay Abraham I * @pci_addr: PCI address to which the physical address should be mapped 2635e8cb403SKishon Vijay Abraham I * @size: the size of the allocation 2645e8cb403SKishon Vijay Abraham I * 2655e8cb403SKishon Vijay Abraham I * Invoke to map CPU address with PCI address. 2665e8cb403SKishon Vijay Abraham I */ 2674494738dSCyrille Pitchen int pci_epc_map_addr(struct pci_epc *epc, u8 func_no, 2684494738dSCyrille Pitchen phys_addr_t phys_addr, u64 pci_addr, size_t size) 2695e8cb403SKishon Vijay Abraham I { 2705e8cb403SKishon Vijay Abraham I int ret; 2715e8cb403SKishon Vijay Abraham I unsigned long flags; 2725e8cb403SKishon Vijay Abraham I 2734494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 2745e8cb403SKishon Vijay Abraham I return -EINVAL; 2755e8cb403SKishon Vijay Abraham I 2765e8cb403SKishon Vijay Abraham I if (!epc->ops->map_addr) 2775e8cb403SKishon Vijay Abraham I return 0; 2785e8cb403SKishon Vijay Abraham I 2795e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 2804494738dSCyrille Pitchen ret = epc->ops->map_addr(epc, func_no, phys_addr, pci_addr, size); 2815e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 2825e8cb403SKishon Vijay Abraham I 2835e8cb403SKishon Vijay Abraham I return ret; 2845e8cb403SKishon Vijay Abraham I } 2855e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_map_addr); 2865e8cb403SKishon Vijay Abraham I 2875e8cb403SKishon Vijay Abraham I /** 2885e8cb403SKishon Vijay Abraham I * pci_epc_clear_bar() - reset the BAR 2895e8cb403SKishon Vijay Abraham I * @epc: the EPC device for which the BAR has to be cleared 2904494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 2915e8cb403SKishon Vijay Abraham I * @bar: the BAR number that has to be reset 2925e8cb403SKishon Vijay Abraham I * 2935e8cb403SKishon Vijay Abraham I * Invoke to reset the BAR of the endpoint device. 2945e8cb403SKishon Vijay Abraham I */ 2954494738dSCyrille Pitchen void pci_epc_clear_bar(struct pci_epc *epc, u8 func_no, int bar) 2965e8cb403SKishon Vijay Abraham I { 2975e8cb403SKishon Vijay Abraham I unsigned long flags; 2985e8cb403SKishon Vijay Abraham I 2994494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 3005e8cb403SKishon Vijay Abraham I return; 3015e8cb403SKishon Vijay Abraham I 3025e8cb403SKishon Vijay Abraham I if (!epc->ops->clear_bar) 3035e8cb403SKishon Vijay Abraham I return; 3045e8cb403SKishon Vijay Abraham I 3055e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 3064494738dSCyrille Pitchen epc->ops->clear_bar(epc, func_no, bar); 3075e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 3085e8cb403SKishon Vijay Abraham I } 3095e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_clear_bar); 3105e8cb403SKishon Vijay Abraham I 3115e8cb403SKishon Vijay Abraham I /** 3125e8cb403SKishon Vijay Abraham I * pci_epc_set_bar() - configure BAR in order for host to assign PCI addr space 3135e8cb403SKishon Vijay Abraham I * @epc: the EPC device on which BAR has to be configured 3144494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 3155e8cb403SKishon Vijay Abraham I * @bar: the BAR number that has to be configured 3165e8cb403SKishon Vijay Abraham I * @size: the size of the addr space 3175e8cb403SKishon Vijay Abraham I * @flags: specify memory allocation/io allocation/32bit address/64 bit address 3185e8cb403SKishon Vijay Abraham I * 3195e8cb403SKishon Vijay Abraham I * Invoke to configure the BAR of the endpoint device. 3205e8cb403SKishon Vijay Abraham I */ 3214494738dSCyrille Pitchen int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, enum pci_barno bar, 3225e8cb403SKishon Vijay Abraham I dma_addr_t bar_phys, size_t size, int flags) 3235e8cb403SKishon Vijay Abraham I { 3245e8cb403SKishon Vijay Abraham I int ret; 3255e8cb403SKishon Vijay Abraham I unsigned long irq_flags; 3265e8cb403SKishon Vijay Abraham I 3274494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 3285e8cb403SKishon Vijay Abraham I return -EINVAL; 3295e8cb403SKishon Vijay Abraham I 3305e8cb403SKishon Vijay Abraham I if (!epc->ops->set_bar) 3315e8cb403SKishon Vijay Abraham I return 0; 3325e8cb403SKishon Vijay Abraham I 3335e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, irq_flags); 3344494738dSCyrille Pitchen ret = epc->ops->set_bar(epc, func_no, bar, bar_phys, size, flags); 3355e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, irq_flags); 3365e8cb403SKishon Vijay Abraham I 3375e8cb403SKishon Vijay Abraham I return ret; 3385e8cb403SKishon Vijay Abraham I } 3395e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_set_bar); 3405e8cb403SKishon Vijay Abraham I 3415e8cb403SKishon Vijay Abraham I /** 3425e8cb403SKishon Vijay Abraham I * pci_epc_write_header() - write standard configuration header 3435e8cb403SKishon Vijay Abraham I * @epc: the EPC device to which the configuration header should be written 3444494738dSCyrille Pitchen * @func_no: the endpoint function number in the EPC device 3455e8cb403SKishon Vijay Abraham I * @header: standard configuration header fields 3465e8cb403SKishon Vijay Abraham I * 3475e8cb403SKishon Vijay Abraham I * Invoke to write the configuration header to the endpoint controller. Every 3485e8cb403SKishon Vijay Abraham I * endpoint controller will have a dedicated location to which the standard 3495e8cb403SKishon Vijay Abraham I * configuration header would be written. The callback function should write 3505e8cb403SKishon Vijay Abraham I * the header fields to this dedicated location. 3515e8cb403SKishon Vijay Abraham I */ 3524494738dSCyrille Pitchen int pci_epc_write_header(struct pci_epc *epc, u8 func_no, 3534494738dSCyrille Pitchen struct pci_epf_header *header) 3545e8cb403SKishon Vijay Abraham I { 3555e8cb403SKishon Vijay Abraham I int ret; 3565e8cb403SKishon Vijay Abraham I unsigned long flags; 3575e8cb403SKishon Vijay Abraham I 3584494738dSCyrille Pitchen if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 3595e8cb403SKishon Vijay Abraham I return -EINVAL; 3605e8cb403SKishon Vijay Abraham I 3615e8cb403SKishon Vijay Abraham I if (!epc->ops->write_header) 3625e8cb403SKishon Vijay Abraham I return 0; 3635e8cb403SKishon Vijay Abraham I 3645e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 3654494738dSCyrille Pitchen ret = epc->ops->write_header(epc, func_no, header); 3665e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 3675e8cb403SKishon Vijay Abraham I 3685e8cb403SKishon Vijay Abraham I return ret; 3695e8cb403SKishon Vijay Abraham I } 3705e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_write_header); 3715e8cb403SKishon Vijay Abraham I 3725e8cb403SKishon Vijay Abraham I /** 3735e8cb403SKishon Vijay Abraham I * pci_epc_add_epf() - bind PCI endpoint function to an endpoint controller 3745e8cb403SKishon Vijay Abraham I * @epc: the EPC device to which the endpoint function should be added 3755e8cb403SKishon Vijay Abraham I * @epf: the endpoint function to be added 3765e8cb403SKishon Vijay Abraham I * 3775e8cb403SKishon Vijay Abraham I * A PCI endpoint device can have one or more functions. In the case of PCIe, 3785e8cb403SKishon Vijay Abraham I * the specification allows up to 8 PCIe endpoint functions. Invoke 3795e8cb403SKishon Vijay Abraham I * pci_epc_add_epf() to add a PCI endpoint function to an endpoint controller. 3805e8cb403SKishon Vijay Abraham I */ 3815e8cb403SKishon Vijay Abraham I int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf) 3825e8cb403SKishon Vijay Abraham I { 3835e8cb403SKishon Vijay Abraham I unsigned long flags; 38464c1a02aSKishon Vijay Abraham I struct device *dev = epc->dev.parent; 3855e8cb403SKishon Vijay Abraham I 3865e8cb403SKishon Vijay Abraham I if (epf->epc) 3875e8cb403SKishon Vijay Abraham I return -EBUSY; 3885e8cb403SKishon Vijay Abraham I 3895e8cb403SKishon Vijay Abraham I if (IS_ERR(epc)) 3905e8cb403SKishon Vijay Abraham I return -EINVAL; 3915e8cb403SKishon Vijay Abraham I 3925e8cb403SKishon Vijay Abraham I if (epf->func_no > epc->max_functions - 1) 3935e8cb403SKishon Vijay Abraham I return -EINVAL; 3945e8cb403SKishon Vijay Abraham I 3955e8cb403SKishon Vijay Abraham I epf->epc = epc; 39664c1a02aSKishon Vijay Abraham I if (dev->of_node) { 39764c1a02aSKishon Vijay Abraham I of_dma_configure(&epf->dev, dev->of_node); 39864c1a02aSKishon Vijay Abraham I } else { 3995e8cb403SKishon Vijay Abraham I dma_set_coherent_mask(&epf->dev, epc->dev.coherent_dma_mask); 4005e8cb403SKishon Vijay Abraham I epf->dev.dma_mask = epc->dev.dma_mask; 40164c1a02aSKishon Vijay Abraham I } 4025e8cb403SKishon Vijay Abraham I 4035e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 4045e8cb403SKishon Vijay Abraham I list_add_tail(&epf->list, &epc->pci_epf); 4055e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 4065e8cb403SKishon Vijay Abraham I 4075e8cb403SKishon Vijay Abraham I return 0; 4085e8cb403SKishon Vijay Abraham I } 4095e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_add_epf); 4105e8cb403SKishon Vijay Abraham I 4115e8cb403SKishon Vijay Abraham I /** 4125e8cb403SKishon Vijay Abraham I * pci_epc_remove_epf() - remove PCI endpoint function from endpoint controller 4135e8cb403SKishon Vijay Abraham I * @epc: the EPC device from which the endpoint function should be removed 4145e8cb403SKishon Vijay Abraham I * @epf: the endpoint function to be removed 4155e8cb403SKishon Vijay Abraham I * 4165e8cb403SKishon Vijay Abraham I * Invoke to remove PCI endpoint function from the endpoint controller. 4175e8cb403SKishon Vijay Abraham I */ 4185e8cb403SKishon Vijay Abraham I void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf) 4195e8cb403SKishon Vijay Abraham I { 4205e8cb403SKishon Vijay Abraham I unsigned long flags; 4215e8cb403SKishon Vijay Abraham I 4225e8cb403SKishon Vijay Abraham I if (!epc || IS_ERR(epc)) 4235e8cb403SKishon Vijay Abraham I return; 4245e8cb403SKishon Vijay Abraham I 4255e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 4265e8cb403SKishon Vijay Abraham I list_del(&epf->list); 4275e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 4285e8cb403SKishon Vijay Abraham I } 4295e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_remove_epf); 4305e8cb403SKishon Vijay Abraham I 4315e8cb403SKishon Vijay Abraham I /** 4325e8cb403SKishon Vijay Abraham I * pci_epc_linkup() - Notify the EPF device that EPC device has established a 4335e8cb403SKishon Vijay Abraham I * connection with the Root Complex. 4345e8cb403SKishon Vijay Abraham I * @epc: the EPC device which has established link with the host 4355e8cb403SKishon Vijay Abraham I * 4365e8cb403SKishon Vijay Abraham I * Invoke to Notify the EPF device that the EPC device has established a 4375e8cb403SKishon Vijay Abraham I * connection with the Root Complex. 4385e8cb403SKishon Vijay Abraham I */ 4395e8cb403SKishon Vijay Abraham I void pci_epc_linkup(struct pci_epc *epc) 4405e8cb403SKishon Vijay Abraham I { 4415e8cb403SKishon Vijay Abraham I unsigned long flags; 4425e8cb403SKishon Vijay Abraham I struct pci_epf *epf; 4435e8cb403SKishon Vijay Abraham I 4445e8cb403SKishon Vijay Abraham I if (!epc || IS_ERR(epc)) 4455e8cb403SKishon Vijay Abraham I return; 4465e8cb403SKishon Vijay Abraham I 4475e8cb403SKishon Vijay Abraham I spin_lock_irqsave(&epc->lock, flags); 4485e8cb403SKishon Vijay Abraham I list_for_each_entry(epf, &epc->pci_epf, list) 4495e8cb403SKishon Vijay Abraham I pci_epf_linkup(epf); 4505e8cb403SKishon Vijay Abraham I spin_unlock_irqrestore(&epc->lock, flags); 4515e8cb403SKishon Vijay Abraham I } 4525e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_linkup); 4535e8cb403SKishon Vijay Abraham I 4545e8cb403SKishon Vijay Abraham I /** 4555e8cb403SKishon Vijay Abraham I * pci_epc_destroy() - destroy the EPC device 4565e8cb403SKishon Vijay Abraham I * @epc: the EPC device that has to be destroyed 4575e8cb403SKishon Vijay Abraham I * 4585e8cb403SKishon Vijay Abraham I * Invoke to destroy the PCI EPC device 4595e8cb403SKishon Vijay Abraham I */ 4605e8cb403SKishon Vijay Abraham I void pci_epc_destroy(struct pci_epc *epc) 4615e8cb403SKishon Vijay Abraham I { 4623a401a2cSKishon Vijay Abraham I pci_ep_cfs_remove_epc_group(epc->group); 4635e8cb403SKishon Vijay Abraham I device_unregister(&epc->dev); 4645e8cb403SKishon Vijay Abraham I kfree(epc); 4655e8cb403SKishon Vijay Abraham I } 4665e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epc_destroy); 4675e8cb403SKishon Vijay Abraham I 4685e8cb403SKishon Vijay Abraham I /** 4695e8cb403SKishon Vijay Abraham I * devm_pci_epc_destroy() - destroy the EPC device 4705e8cb403SKishon Vijay Abraham I * @dev: device that wants to destroy the EPC 4715e8cb403SKishon Vijay Abraham I * @epc: the EPC device that has to be destroyed 4725e8cb403SKishon Vijay Abraham I * 4735e8cb403SKishon Vijay Abraham I * Invoke to destroy the devres associated with this 4745e8cb403SKishon Vijay Abraham I * pci_epc and destroy the EPC device. 4755e8cb403SKishon Vijay Abraham I */ 4765e8cb403SKishon Vijay Abraham I void devm_pci_epc_destroy(struct device *dev, struct pci_epc *epc) 4775e8cb403SKishon Vijay Abraham I { 4785e8cb403SKishon Vijay Abraham I int r; 4795e8cb403SKishon Vijay Abraham I 4805e8cb403SKishon Vijay Abraham I r = devres_destroy(dev, devm_pci_epc_release, devm_pci_epc_match, 4815e8cb403SKishon Vijay Abraham I epc); 4825e8cb403SKishon Vijay Abraham I dev_WARN_ONCE(dev, r, "couldn't find PCI EPC resource\n"); 4835e8cb403SKishon Vijay Abraham I } 4845e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(devm_pci_epc_destroy); 4855e8cb403SKishon Vijay Abraham I 4865e8cb403SKishon Vijay Abraham I /** 4875e8cb403SKishon Vijay Abraham I * __pci_epc_create() - create a new endpoint controller (EPC) device 4885e8cb403SKishon Vijay Abraham I * @dev: device that is creating the new EPC 4895e8cb403SKishon Vijay Abraham I * @ops: function pointers for performing EPC operations 4905e8cb403SKishon Vijay Abraham I * @owner: the owner of the module that creates the EPC device 4915e8cb403SKishon Vijay Abraham I * 4925e8cb403SKishon Vijay Abraham I * Invoke to create a new EPC device and add it to pci_epc class. 4935e8cb403SKishon Vijay Abraham I */ 4945e8cb403SKishon Vijay Abraham I struct pci_epc * 4955e8cb403SKishon Vijay Abraham I __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, 4965e8cb403SKishon Vijay Abraham I struct module *owner) 4975e8cb403SKishon Vijay Abraham I { 4985e8cb403SKishon Vijay Abraham I int ret; 4995e8cb403SKishon Vijay Abraham I struct pci_epc *epc; 5005e8cb403SKishon Vijay Abraham I 5015e8cb403SKishon Vijay Abraham I if (WARN_ON(!dev)) { 5025e8cb403SKishon Vijay Abraham I ret = -EINVAL; 5035e8cb403SKishon Vijay Abraham I goto err_ret; 5045e8cb403SKishon Vijay Abraham I } 5055e8cb403SKishon Vijay Abraham I 5065e8cb403SKishon Vijay Abraham I epc = kzalloc(sizeof(*epc), GFP_KERNEL); 5075e8cb403SKishon Vijay Abraham I if (!epc) { 5085e8cb403SKishon Vijay Abraham I ret = -ENOMEM; 5095e8cb403SKishon Vijay Abraham I goto err_ret; 5105e8cb403SKishon Vijay Abraham I } 5115e8cb403SKishon Vijay Abraham I 5125e8cb403SKishon Vijay Abraham I spin_lock_init(&epc->lock); 5135e8cb403SKishon Vijay Abraham I INIT_LIST_HEAD(&epc->pci_epf); 5145e8cb403SKishon Vijay Abraham I 5155e8cb403SKishon Vijay Abraham I device_initialize(&epc->dev); 5165e8cb403SKishon Vijay Abraham I dma_set_coherent_mask(&epc->dev, dev->coherent_dma_mask); 5175e8cb403SKishon Vijay Abraham I epc->dev.class = pci_epc_class; 5185e8cb403SKishon Vijay Abraham I epc->dev.dma_mask = dev->dma_mask; 51964c1a02aSKishon Vijay Abraham I epc->dev.parent = dev; 5205e8cb403SKishon Vijay Abraham I epc->ops = ops; 5215e8cb403SKishon Vijay Abraham I 5225e8cb403SKishon Vijay Abraham I ret = dev_set_name(&epc->dev, "%s", dev_name(dev)); 5235e8cb403SKishon Vijay Abraham I if (ret) 5245e8cb403SKishon Vijay Abraham I goto put_dev; 5255e8cb403SKishon Vijay Abraham I 5265e8cb403SKishon Vijay Abraham I ret = device_add(&epc->dev); 5275e8cb403SKishon Vijay Abraham I if (ret) 5285e8cb403SKishon Vijay Abraham I goto put_dev; 5295e8cb403SKishon Vijay Abraham I 5303a401a2cSKishon Vijay Abraham I epc->group = pci_ep_cfs_add_epc_group(dev_name(dev)); 5313a401a2cSKishon Vijay Abraham I 5325e8cb403SKishon Vijay Abraham I return epc; 5335e8cb403SKishon Vijay Abraham I 5345e8cb403SKishon Vijay Abraham I put_dev: 5355e8cb403SKishon Vijay Abraham I put_device(&epc->dev); 5365e8cb403SKishon Vijay Abraham I kfree(epc); 5375e8cb403SKishon Vijay Abraham I 5385e8cb403SKishon Vijay Abraham I err_ret: 5395e8cb403SKishon Vijay Abraham I return ERR_PTR(ret); 5405e8cb403SKishon Vijay Abraham I } 5415e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(__pci_epc_create); 5425e8cb403SKishon Vijay Abraham I 5435e8cb403SKishon Vijay Abraham I /** 5445e8cb403SKishon Vijay Abraham I * __devm_pci_epc_create() - create a new endpoint controller (EPC) device 5455e8cb403SKishon Vijay Abraham I * @dev: device that is creating the new EPC 5465e8cb403SKishon Vijay Abraham I * @ops: function pointers for performing EPC operations 5475e8cb403SKishon Vijay Abraham I * @owner: the owner of the module that creates the EPC device 5485e8cb403SKishon Vijay Abraham I * 5495e8cb403SKishon Vijay Abraham I * Invoke to create a new EPC device and add it to pci_epc class. 5505e8cb403SKishon Vijay Abraham I * While at that, it also associates the device with the pci_epc using devres. 5515e8cb403SKishon Vijay Abraham I * On driver detach, release function is invoked on the devres data, 5525e8cb403SKishon Vijay Abraham I * then, devres data is freed. 5535e8cb403SKishon Vijay Abraham I */ 5545e8cb403SKishon Vijay Abraham I struct pci_epc * 5555e8cb403SKishon Vijay Abraham I __devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops, 5565e8cb403SKishon Vijay Abraham I struct module *owner) 5575e8cb403SKishon Vijay Abraham I { 5585e8cb403SKishon Vijay Abraham I struct pci_epc **ptr, *epc; 5595e8cb403SKishon Vijay Abraham I 5605e8cb403SKishon Vijay Abraham I ptr = devres_alloc(devm_pci_epc_release, sizeof(*ptr), GFP_KERNEL); 5615e8cb403SKishon Vijay Abraham I if (!ptr) 5625e8cb403SKishon Vijay Abraham I return ERR_PTR(-ENOMEM); 5635e8cb403SKishon Vijay Abraham I 5645e8cb403SKishon Vijay Abraham I epc = __pci_epc_create(dev, ops, owner); 5655e8cb403SKishon Vijay Abraham I if (!IS_ERR(epc)) { 5665e8cb403SKishon Vijay Abraham I *ptr = epc; 5675e8cb403SKishon Vijay Abraham I devres_add(dev, ptr); 5685e8cb403SKishon Vijay Abraham I } else { 5695e8cb403SKishon Vijay Abraham I devres_free(ptr); 5705e8cb403SKishon Vijay Abraham I } 5715e8cb403SKishon Vijay Abraham I 5725e8cb403SKishon Vijay Abraham I return epc; 5735e8cb403SKishon Vijay Abraham I } 5745e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(__devm_pci_epc_create); 5755e8cb403SKishon Vijay Abraham I 5765e8cb403SKishon Vijay Abraham I static int __init pci_epc_init(void) 5775e8cb403SKishon Vijay Abraham I { 5785e8cb403SKishon Vijay Abraham I pci_epc_class = class_create(THIS_MODULE, "pci_epc"); 5795e8cb403SKishon Vijay Abraham I if (IS_ERR(pci_epc_class)) { 5805e8cb403SKishon Vijay Abraham I pr_err("failed to create pci epc class --> %ld\n", 5815e8cb403SKishon Vijay Abraham I PTR_ERR(pci_epc_class)); 5825e8cb403SKishon Vijay Abraham I return PTR_ERR(pci_epc_class); 5835e8cb403SKishon Vijay Abraham I } 5845e8cb403SKishon Vijay Abraham I 5855e8cb403SKishon Vijay Abraham I return 0; 5865e8cb403SKishon Vijay Abraham I } 5875e8cb403SKishon Vijay Abraham I module_init(pci_epc_init); 5885e8cb403SKishon Vijay Abraham I 5895e8cb403SKishon Vijay Abraham I static void __exit pci_epc_exit(void) 5905e8cb403SKishon Vijay Abraham I { 5915e8cb403SKishon Vijay Abraham I class_destroy(pci_epc_class); 5925e8cb403SKishon Vijay Abraham I } 5935e8cb403SKishon Vijay Abraham I module_exit(pci_epc_exit); 5945e8cb403SKishon Vijay Abraham I 5955e8cb403SKishon Vijay Abraham I MODULE_DESCRIPTION("PCI EPC Library"); 5965e8cb403SKishon Vijay Abraham I MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); 5975e8cb403SKishon Vijay Abraham I MODULE_LICENSE("GPL v2"); 598