18cfab3cfSBjorn Helgaas // SPDX-License-Identifier: GPL-2.0
29b41d19aSKrzysztof Kozlowski /*
35e8cb403SKishon Vijay Abraham I * PCI Endpoint *Function* (EPF) 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/dma-mapping.h>
115e8cb403SKishon Vijay Abraham I #include <linux/slab.h>
125e8cb403SKishon Vijay Abraham I #include <linux/module.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
18ef1433f7SKishon Vijay Abraham I static DEFINE_MUTEX(pci_epf_mutex);
19ef1433f7SKishon Vijay Abraham I
205e8cb403SKishon Vijay Abraham I static struct bus_type pci_epf_bus_type;
2136b85189SBhumika Goyal static const struct device_type pci_epf_type;
225e8cb403SKishon Vijay Abraham I
235e8cb403SKishon Vijay Abraham I /**
245e8cb403SKishon Vijay Abraham I * pci_epf_unbind() - Notify the function driver that the binding between the
255e8cb403SKishon Vijay Abraham I * EPF device and EPC device has been lost
265e8cb403SKishon Vijay Abraham I * @epf: the EPF device which has lost the binding with the EPC device
275e8cb403SKishon Vijay Abraham I *
285e8cb403SKishon Vijay Abraham I * Invoke to notify the function driver that the binding between the EPF device
295e8cb403SKishon Vijay Abraham I * and EPC device has been lost.
305e8cb403SKishon Vijay Abraham I */
pci_epf_unbind(struct pci_epf * epf)315e8cb403SKishon Vijay Abraham I void pci_epf_unbind(struct pci_epf *epf)
325e8cb403SKishon Vijay Abraham I {
331cf362e9SKishon Vijay Abraham I struct pci_epf *epf_vf;
341cf362e9SKishon Vijay Abraham I
355e8cb403SKishon Vijay Abraham I if (!epf->driver) {
365e8cb403SKishon Vijay Abraham I dev_WARN(&epf->dev, "epf device not bound to driver\n");
375e8cb403SKishon Vijay Abraham I return;
385e8cb403SKishon Vijay Abraham I }
395e8cb403SKishon Vijay Abraham I
4007301c98SKishon Vijay Abraham I mutex_lock(&epf->lock);
411cf362e9SKishon Vijay Abraham I list_for_each_entry(epf_vf, &epf->pci_vepf, list) {
421cf362e9SKishon Vijay Abraham I if (epf_vf->is_bound)
431cf362e9SKishon Vijay Abraham I epf_vf->driver->ops->unbind(epf_vf);
441cf362e9SKishon Vijay Abraham I }
451cf362e9SKishon Vijay Abraham I if (epf->is_bound)
465e8cb403SKishon Vijay Abraham I epf->driver->ops->unbind(epf);
4707301c98SKishon Vijay Abraham I mutex_unlock(&epf->lock);
485e8cb403SKishon Vijay Abraham I module_put(epf->driver->owner);
495e8cb403SKishon Vijay Abraham I }
505e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epf_unbind);
515e8cb403SKishon Vijay Abraham I
525e8cb403SKishon Vijay Abraham I /**
535e8cb403SKishon Vijay Abraham I * pci_epf_bind() - Notify the function driver that the EPF device has been
545e8cb403SKishon Vijay Abraham I * bound to a EPC device
555e8cb403SKishon Vijay Abraham I * @epf: the EPF device which has been bound to the EPC device
565e8cb403SKishon Vijay Abraham I *
575e8cb403SKishon Vijay Abraham I * Invoke to notify the function driver that it has been bound to a EPC device
585e8cb403SKishon Vijay Abraham I */
pci_epf_bind(struct pci_epf * epf)595e8cb403SKishon Vijay Abraham I int pci_epf_bind(struct pci_epf *epf)
605e8cb403SKishon Vijay Abraham I {
6153fd3cbeSKishon Vijay Abraham I struct device *dev = &epf->dev;
621cf362e9SKishon Vijay Abraham I struct pci_epf *epf_vf;
6353fd3cbeSKishon Vijay Abraham I u8 func_no, vfunc_no;
6453fd3cbeSKishon Vijay Abraham I struct pci_epc *epc;
6507301c98SKishon Vijay Abraham I int ret;
6607301c98SKishon Vijay Abraham I
675e8cb403SKishon Vijay Abraham I if (!epf->driver) {
6853fd3cbeSKishon Vijay Abraham I dev_WARN(dev, "epf device not bound to driver\n");
695e8cb403SKishon Vijay Abraham I return -EINVAL;
705e8cb403SKishon Vijay Abraham I }
715e8cb403SKishon Vijay Abraham I
725e8cb403SKishon Vijay Abraham I if (!try_module_get(epf->driver->owner))
735e8cb403SKishon Vijay Abraham I return -EAGAIN;
745e8cb403SKishon Vijay Abraham I
7507301c98SKishon Vijay Abraham I mutex_lock(&epf->lock);
761cf362e9SKishon Vijay Abraham I list_for_each_entry(epf_vf, &epf->pci_vepf, list) {
7753fd3cbeSKishon Vijay Abraham I vfunc_no = epf_vf->vfunc_no;
7853fd3cbeSKishon Vijay Abraham I
7953fd3cbeSKishon Vijay Abraham I if (vfunc_no < 1) {
8053fd3cbeSKishon Vijay Abraham I dev_err(dev, "Invalid virtual function number\n");
8153fd3cbeSKishon Vijay Abraham I ret = -EINVAL;
8253fd3cbeSKishon Vijay Abraham I goto ret;
8353fd3cbeSKishon Vijay Abraham I }
8453fd3cbeSKishon Vijay Abraham I
8553fd3cbeSKishon Vijay Abraham I epc = epf->epc;
8653fd3cbeSKishon Vijay Abraham I func_no = epf->func_no;
8753fd3cbeSKishon Vijay Abraham I if (!IS_ERR_OR_NULL(epc)) {
8853fd3cbeSKishon Vijay Abraham I if (!epc->max_vfs) {
8953fd3cbeSKishon Vijay Abraham I dev_err(dev, "No support for virt function\n");
9053fd3cbeSKishon Vijay Abraham I ret = -EINVAL;
9153fd3cbeSKishon Vijay Abraham I goto ret;
9253fd3cbeSKishon Vijay Abraham I }
9353fd3cbeSKishon Vijay Abraham I
9453fd3cbeSKishon Vijay Abraham I if (vfunc_no > epc->max_vfs[func_no]) {
9553fd3cbeSKishon Vijay Abraham I dev_err(dev, "PF%d: Exceeds max vfunc number\n",
9653fd3cbeSKishon Vijay Abraham I func_no);
9753fd3cbeSKishon Vijay Abraham I ret = -EINVAL;
9853fd3cbeSKishon Vijay Abraham I goto ret;
9953fd3cbeSKishon Vijay Abraham I }
10053fd3cbeSKishon Vijay Abraham I }
10153fd3cbeSKishon Vijay Abraham I
10253fd3cbeSKishon Vijay Abraham I epc = epf->sec_epc;
10353fd3cbeSKishon Vijay Abraham I func_no = epf->sec_epc_func_no;
10453fd3cbeSKishon Vijay Abraham I if (!IS_ERR_OR_NULL(epc)) {
10553fd3cbeSKishon Vijay Abraham I if (!epc->max_vfs) {
10653fd3cbeSKishon Vijay Abraham I dev_err(dev, "No support for virt function\n");
10753fd3cbeSKishon Vijay Abraham I ret = -EINVAL;
10853fd3cbeSKishon Vijay Abraham I goto ret;
10953fd3cbeSKishon Vijay Abraham I }
11053fd3cbeSKishon Vijay Abraham I
11153fd3cbeSKishon Vijay Abraham I if (vfunc_no > epc->max_vfs[func_no]) {
11253fd3cbeSKishon Vijay Abraham I dev_err(dev, "PF%d: Exceeds max vfunc number\n",
11353fd3cbeSKishon Vijay Abraham I func_no);
11453fd3cbeSKishon Vijay Abraham I ret = -EINVAL;
11553fd3cbeSKishon Vijay Abraham I goto ret;
11653fd3cbeSKishon Vijay Abraham I }
11753fd3cbeSKishon Vijay Abraham I }
11853fd3cbeSKishon Vijay Abraham I
1191cf362e9SKishon Vijay Abraham I epf_vf->func_no = epf->func_no;
12053fd3cbeSKishon Vijay Abraham I epf_vf->sec_epc_func_no = epf->sec_epc_func_no;
1211cf362e9SKishon Vijay Abraham I epf_vf->epc = epf->epc;
1221cf362e9SKishon Vijay Abraham I epf_vf->sec_epc = epf->sec_epc;
1231cf362e9SKishon Vijay Abraham I ret = epf_vf->driver->ops->bind(epf_vf);
1241cf362e9SKishon Vijay Abraham I if (ret)
1251cf362e9SKishon Vijay Abraham I goto ret;
1261cf362e9SKishon Vijay Abraham I epf_vf->is_bound = true;
1271cf362e9SKishon Vijay Abraham I }
1281cf362e9SKishon Vijay Abraham I
12907301c98SKishon Vijay Abraham I ret = epf->driver->ops->bind(epf);
1301cf362e9SKishon Vijay Abraham I if (ret)
1311cf362e9SKishon Vijay Abraham I goto ret;
1321cf362e9SKishon Vijay Abraham I epf->is_bound = true;
1331cf362e9SKishon Vijay Abraham I
13407301c98SKishon Vijay Abraham I mutex_unlock(&epf->lock);
1351cf362e9SKishon Vijay Abraham I return 0;
1361cf362e9SKishon Vijay Abraham I
1371cf362e9SKishon Vijay Abraham I ret:
1381cf362e9SKishon Vijay Abraham I mutex_unlock(&epf->lock);
1391cf362e9SKishon Vijay Abraham I pci_epf_unbind(epf);
14007301c98SKishon Vijay Abraham I
14107301c98SKishon Vijay Abraham I return ret;
1425e8cb403SKishon Vijay Abraham I }
1435e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epf_bind);
1445e8cb403SKishon Vijay Abraham I
1455e8cb403SKishon Vijay Abraham I /**
1461cf362e9SKishon Vijay Abraham I * pci_epf_add_vepf() - associate virtual EP function to physical EP function
1471cf362e9SKishon Vijay Abraham I * @epf_pf: the physical EP function to which the virtual EP function should be
1481cf362e9SKishon Vijay Abraham I * associated
1491cf362e9SKishon Vijay Abraham I * @epf_vf: the virtual EP function to be added
1501cf362e9SKishon Vijay Abraham I *
1511cf362e9SKishon Vijay Abraham I * A physical endpoint function can be associated with multiple virtual
1521cf362e9SKishon Vijay Abraham I * endpoint functions. Invoke pci_epf_add_epf() to add a virtual PCI endpoint
1531cf362e9SKishon Vijay Abraham I * function to a physical PCI endpoint function.
1541cf362e9SKishon Vijay Abraham I */
pci_epf_add_vepf(struct pci_epf * epf_pf,struct pci_epf * epf_vf)1551cf362e9SKishon Vijay Abraham I int pci_epf_add_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)
1561cf362e9SKishon Vijay Abraham I {
1571cf362e9SKishon Vijay Abraham I u32 vfunc_no;
1581cf362e9SKishon Vijay Abraham I
1591cf362e9SKishon Vijay Abraham I if (IS_ERR_OR_NULL(epf_pf) || IS_ERR_OR_NULL(epf_vf))
1601cf362e9SKishon Vijay Abraham I return -EINVAL;
1611cf362e9SKishon Vijay Abraham I
1621cf362e9SKishon Vijay Abraham I if (epf_pf->epc || epf_vf->epc || epf_vf->epf_pf)
1631cf362e9SKishon Vijay Abraham I return -EBUSY;
1641cf362e9SKishon Vijay Abraham I
1651cf362e9SKishon Vijay Abraham I if (epf_pf->sec_epc || epf_vf->sec_epc)
1661cf362e9SKishon Vijay Abraham I return -EBUSY;
1671cf362e9SKishon Vijay Abraham I
1681cf362e9SKishon Vijay Abraham I mutex_lock(&epf_pf->lock);
1691cf362e9SKishon Vijay Abraham I vfunc_no = find_first_zero_bit(&epf_pf->vfunction_num_map,
1701cf362e9SKishon Vijay Abraham I BITS_PER_LONG);
1711cf362e9SKishon Vijay Abraham I if (vfunc_no >= BITS_PER_LONG) {
1721cf362e9SKishon Vijay Abraham I mutex_unlock(&epf_pf->lock);
1731cf362e9SKishon Vijay Abraham I return -EINVAL;
1741cf362e9SKishon Vijay Abraham I }
1751cf362e9SKishon Vijay Abraham I
1761cf362e9SKishon Vijay Abraham I set_bit(vfunc_no, &epf_pf->vfunction_num_map);
1771cf362e9SKishon Vijay Abraham I epf_vf->vfunc_no = vfunc_no;
1781cf362e9SKishon Vijay Abraham I
1791cf362e9SKishon Vijay Abraham I epf_vf->epf_pf = epf_pf;
1801cf362e9SKishon Vijay Abraham I epf_vf->is_vf = true;
1811cf362e9SKishon Vijay Abraham I
1821cf362e9SKishon Vijay Abraham I list_add_tail(&epf_vf->list, &epf_pf->pci_vepf);
1831cf362e9SKishon Vijay Abraham I mutex_unlock(&epf_pf->lock);
1841cf362e9SKishon Vijay Abraham I
1851cf362e9SKishon Vijay Abraham I return 0;
1861cf362e9SKishon Vijay Abraham I }
1871cf362e9SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epf_add_vepf);
1881cf362e9SKishon Vijay Abraham I
1891cf362e9SKishon Vijay Abraham I /**
1901cf362e9SKishon Vijay Abraham I * pci_epf_remove_vepf() - remove virtual EP function from physical EP function
1911cf362e9SKishon Vijay Abraham I * @epf_pf: the physical EP function from which the virtual EP function should
1921cf362e9SKishon Vijay Abraham I * be removed
1931cf362e9SKishon Vijay Abraham I * @epf_vf: the virtual EP function to be removed
1941cf362e9SKishon Vijay Abraham I *
195b2105b9fSKrzysztof Wilczyński * Invoke to remove a virtual endpoint function from the physical endpoint
1961cf362e9SKishon Vijay Abraham I * function.
1971cf362e9SKishon Vijay Abraham I */
pci_epf_remove_vepf(struct pci_epf * epf_pf,struct pci_epf * epf_vf)1981cf362e9SKishon Vijay Abraham I void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)
1991cf362e9SKishon Vijay Abraham I {
2001cf362e9SKishon Vijay Abraham I if (IS_ERR_OR_NULL(epf_pf) || IS_ERR_OR_NULL(epf_vf))
2011cf362e9SKishon Vijay Abraham I return;
2021cf362e9SKishon Vijay Abraham I
2031cf362e9SKishon Vijay Abraham I mutex_lock(&epf_pf->lock);
2041cf362e9SKishon Vijay Abraham I clear_bit(epf_vf->vfunc_no, &epf_pf->vfunction_num_map);
2051cf362e9SKishon Vijay Abraham I list_del(&epf_vf->list);
2061cf362e9SKishon Vijay Abraham I mutex_unlock(&epf_pf->lock);
2071cf362e9SKishon Vijay Abraham I }
2081cf362e9SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epf_remove_vepf);
2091cf362e9SKishon Vijay Abraham I
2101cf362e9SKishon Vijay Abraham I /**
2115e8cb403SKishon Vijay Abraham I * pci_epf_free_space() - free the allocated PCI EPF register space
2129b41d19aSKrzysztof Kozlowski * @epf: the EPF device from whom to free the memory
2135e8cb403SKishon Vijay Abraham I * @addr: the virtual address of the PCI EPF register space
2145e8cb403SKishon Vijay Abraham I * @bar: the BAR number corresponding to the register space
21563840ff5SKishon Vijay Abraham I * @type: Identifies if the allocated space is for primary EPC or secondary EPC
2165e8cb403SKishon Vijay Abraham I *
2175e8cb403SKishon Vijay Abraham I * Invoke to free the allocated PCI EPF register space.
2185e8cb403SKishon Vijay Abraham I */
pci_epf_free_space(struct pci_epf * epf,void * addr,enum pci_barno bar,enum pci_epc_interface_type type)21963840ff5SKishon Vijay Abraham I void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
22063840ff5SKishon Vijay Abraham I enum pci_epc_interface_type type)
2215e8cb403SKishon Vijay Abraham I {
22280c253bdSColin Ian King struct device *dev;
22363840ff5SKishon Vijay Abraham I struct pci_epf_bar *epf_bar;
22463840ff5SKishon Vijay Abraham I struct pci_epc *epc;
2255e8cb403SKishon Vijay Abraham I
2265e8cb403SKishon Vijay Abraham I if (!addr)
2275e8cb403SKishon Vijay Abraham I return;
2285e8cb403SKishon Vijay Abraham I
22963840ff5SKishon Vijay Abraham I if (type == PRIMARY_INTERFACE) {
23063840ff5SKishon Vijay Abraham I epc = epf->epc;
23163840ff5SKishon Vijay Abraham I epf_bar = epf->bar;
23263840ff5SKishon Vijay Abraham I } else {
23363840ff5SKishon Vijay Abraham I epc = epf->sec_epc;
23463840ff5SKishon Vijay Abraham I epf_bar = epf->sec_epc_bar;
23563840ff5SKishon Vijay Abraham I }
2365e8cb403SKishon Vijay Abraham I
23763840ff5SKishon Vijay Abraham I dev = epc->dev.parent;
23863840ff5SKishon Vijay Abraham I dma_free_coherent(dev, epf_bar[bar].size, addr,
23963840ff5SKishon Vijay Abraham I epf_bar[bar].phys_addr);
24063840ff5SKishon Vijay Abraham I
24163840ff5SKishon Vijay Abraham I epf_bar[bar].phys_addr = 0;
24263840ff5SKishon Vijay Abraham I epf_bar[bar].addr = NULL;
24363840ff5SKishon Vijay Abraham I epf_bar[bar].size = 0;
24463840ff5SKishon Vijay Abraham I epf_bar[bar].barno = 0;
24563840ff5SKishon Vijay Abraham I epf_bar[bar].flags = 0;
2465e8cb403SKishon Vijay Abraham I }
2475e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epf_free_space);
2485e8cb403SKishon Vijay Abraham I
2495e8cb403SKishon Vijay Abraham I /**
2505e8cb403SKishon Vijay Abraham I * pci_epf_alloc_space() - allocate memory for the PCI EPF register space
2519b41d19aSKrzysztof Kozlowski * @epf: the EPF device to whom allocate the memory
2525e8cb403SKishon Vijay Abraham I * @size: the size of the memory that has to be allocated
2535e8cb403SKishon Vijay Abraham I * @bar: the BAR number corresponding to the allocated register space
2542a9a8016SKishon Vijay Abraham I * @align: alignment size for the allocation region
25563840ff5SKishon Vijay Abraham I * @type: Identifies if the allocation is for primary EPC or secondary EPC
2565e8cb403SKishon Vijay Abraham I *
2575e8cb403SKishon Vijay Abraham I * Invoke to allocate memory for the PCI EPF register space.
2585e8cb403SKishon Vijay Abraham I */
pci_epf_alloc_space(struct pci_epf * epf,size_t size,enum pci_barno bar,size_t align,enum pci_epc_interface_type type)2592a9a8016SKishon Vijay Abraham I void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
26063840ff5SKishon Vijay Abraham I size_t align, enum pci_epc_interface_type type)
2615e8cb403SKishon Vijay Abraham I {
26263840ff5SKishon Vijay Abraham I struct pci_epf_bar *epf_bar;
2635e8cb403SKishon Vijay Abraham I dma_addr_t phys_addr;
26463840ff5SKishon Vijay Abraham I struct pci_epc *epc;
26563840ff5SKishon Vijay Abraham I struct device *dev;
26663840ff5SKishon Vijay Abraham I void *space;
2675e8cb403SKishon Vijay Abraham I
2685e8cb403SKishon Vijay Abraham I if (size < 128)
2695e8cb403SKishon Vijay Abraham I size = 128;
2702a9a8016SKishon Vijay Abraham I
2712a9a8016SKishon Vijay Abraham I if (align)
2722a9a8016SKishon Vijay Abraham I size = ALIGN(size, align);
2732a9a8016SKishon Vijay Abraham I else
2745e8cb403SKishon Vijay Abraham I size = roundup_pow_of_two(size);
2755e8cb403SKishon Vijay Abraham I
27663840ff5SKishon Vijay Abraham I if (type == PRIMARY_INTERFACE) {
27763840ff5SKishon Vijay Abraham I epc = epf->epc;
27863840ff5SKishon Vijay Abraham I epf_bar = epf->bar;
27963840ff5SKishon Vijay Abraham I } else {
28063840ff5SKishon Vijay Abraham I epc = epf->sec_epc;
28163840ff5SKishon Vijay Abraham I epf_bar = epf->sec_epc_bar;
28263840ff5SKishon Vijay Abraham I }
28363840ff5SKishon Vijay Abraham I
28463840ff5SKishon Vijay Abraham I dev = epc->dev.parent;
2855e8cb403SKishon Vijay Abraham I space = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL);
2865e8cb403SKishon Vijay Abraham I if (!space) {
2875e8cb403SKishon Vijay Abraham I dev_err(dev, "failed to allocate mem space\n");
2885e8cb403SKishon Vijay Abraham I return NULL;
2895e8cb403SKishon Vijay Abraham I }
2905e8cb403SKishon Vijay Abraham I
29163840ff5SKishon Vijay Abraham I epf_bar[bar].phys_addr = phys_addr;
29263840ff5SKishon Vijay Abraham I epf_bar[bar].addr = space;
29363840ff5SKishon Vijay Abraham I epf_bar[bar].size = size;
29463840ff5SKishon Vijay Abraham I epf_bar[bar].barno = bar;
29563840ff5SKishon Vijay Abraham I epf_bar[bar].flags |= upper_32_bits(size) ?
2965544d67eSKishon Vijay Abraham I PCI_BASE_ADDRESS_MEM_TYPE_64 :
2975544d67eSKishon Vijay Abraham I PCI_BASE_ADDRESS_MEM_TYPE_32;
2985e8cb403SKishon Vijay Abraham I
2995e8cb403SKishon Vijay Abraham I return space;
3005e8cb403SKishon Vijay Abraham I }
3015e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epf_alloc_space);
3025e8cb403SKishon Vijay Abraham I
pci_epf_remove_cfs(struct pci_epf_driver * driver)303a83a2173SKishon Vijay Abraham I static void pci_epf_remove_cfs(struct pci_epf_driver *driver)
304a83a2173SKishon Vijay Abraham I {
305a83a2173SKishon Vijay Abraham I struct config_group *group, *tmp;
306a83a2173SKishon Vijay Abraham I
307a83a2173SKishon Vijay Abraham I if (!IS_ENABLED(CONFIG_PCI_ENDPOINT_CONFIGFS))
308a83a2173SKishon Vijay Abraham I return;
309a83a2173SKishon Vijay Abraham I
310a83a2173SKishon Vijay Abraham I mutex_lock(&pci_epf_mutex);
311a83a2173SKishon Vijay Abraham I list_for_each_entry_safe(group, tmp, &driver->epf_group, group_entry)
312a83a2173SKishon Vijay Abraham I pci_ep_cfs_remove_epf_group(group);
313a83a2173SKishon Vijay Abraham I list_del(&driver->epf_group);
314a83a2173SKishon Vijay Abraham I mutex_unlock(&pci_epf_mutex);
315a83a2173SKishon Vijay Abraham I }
316a83a2173SKishon Vijay Abraham I
3175e8cb403SKishon Vijay Abraham I /**
3185e8cb403SKishon Vijay Abraham I * pci_epf_unregister_driver() - unregister the PCI EPF driver
3195e8cb403SKishon Vijay Abraham I * @driver: the PCI EPF driver that has to be unregistered
3205e8cb403SKishon Vijay Abraham I *
3215e8cb403SKishon Vijay Abraham I * Invoke to unregister the PCI EPF driver.
3225e8cb403SKishon Vijay Abraham I */
pci_epf_unregister_driver(struct pci_epf_driver * driver)3235e8cb403SKishon Vijay Abraham I void pci_epf_unregister_driver(struct pci_epf_driver *driver)
3245e8cb403SKishon Vijay Abraham I {
325a83a2173SKishon Vijay Abraham I pci_epf_remove_cfs(driver);
3265e8cb403SKishon Vijay Abraham I driver_unregister(&driver->driver);
3275e8cb403SKishon Vijay Abraham I }
3285e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epf_unregister_driver);
3295e8cb403SKishon Vijay Abraham I
pci_epf_add_cfs(struct pci_epf_driver * driver)330a83a2173SKishon Vijay Abraham I static int pci_epf_add_cfs(struct pci_epf_driver *driver)
331a83a2173SKishon Vijay Abraham I {
332a83a2173SKishon Vijay Abraham I struct config_group *group;
333a83a2173SKishon Vijay Abraham I const struct pci_epf_device_id *id;
334a83a2173SKishon Vijay Abraham I
335a83a2173SKishon Vijay Abraham I if (!IS_ENABLED(CONFIG_PCI_ENDPOINT_CONFIGFS))
336a83a2173SKishon Vijay Abraham I return 0;
337a83a2173SKishon Vijay Abraham I
338a83a2173SKishon Vijay Abraham I INIT_LIST_HEAD(&driver->epf_group);
339a83a2173SKishon Vijay Abraham I
340a83a2173SKishon Vijay Abraham I id = driver->id_table;
341a83a2173SKishon Vijay Abraham I while (id->name[0]) {
342a83a2173SKishon Vijay Abraham I group = pci_ep_cfs_add_epf_group(id->name);
343a83a2173SKishon Vijay Abraham I if (IS_ERR(group)) {
344a83a2173SKishon Vijay Abraham I pci_epf_remove_cfs(driver);
345a83a2173SKishon Vijay Abraham I return PTR_ERR(group);
346a83a2173SKishon Vijay Abraham I }
347a83a2173SKishon Vijay Abraham I
348a83a2173SKishon Vijay Abraham I mutex_lock(&pci_epf_mutex);
349a83a2173SKishon Vijay Abraham I list_add_tail(&group->group_entry, &driver->epf_group);
350a83a2173SKishon Vijay Abraham I mutex_unlock(&pci_epf_mutex);
351a83a2173SKishon Vijay Abraham I id++;
352a83a2173SKishon Vijay Abraham I }
353a83a2173SKishon Vijay Abraham I
354a83a2173SKishon Vijay Abraham I return 0;
355a83a2173SKishon Vijay Abraham I }
356a83a2173SKishon Vijay Abraham I
3575e8cb403SKishon Vijay Abraham I /**
3585e8cb403SKishon Vijay Abraham I * __pci_epf_register_driver() - register a new PCI EPF driver
3595e8cb403SKishon Vijay Abraham I * @driver: structure representing PCI EPF driver
3605e8cb403SKishon Vijay Abraham I * @owner: the owner of the module that registers the PCI EPF driver
3615e8cb403SKishon Vijay Abraham I *
3625e8cb403SKishon Vijay Abraham I * Invoke to register a new PCI EPF driver.
3635e8cb403SKishon Vijay Abraham I */
__pci_epf_register_driver(struct pci_epf_driver * driver,struct module * owner)3645e8cb403SKishon Vijay Abraham I int __pci_epf_register_driver(struct pci_epf_driver *driver,
3655e8cb403SKishon Vijay Abraham I struct module *owner)
3665e8cb403SKishon Vijay Abraham I {
3675e8cb403SKishon Vijay Abraham I int ret;
3685e8cb403SKishon Vijay Abraham I
3695e8cb403SKishon Vijay Abraham I if (!driver->ops)
3705e8cb403SKishon Vijay Abraham I return -EINVAL;
3715e8cb403SKishon Vijay Abraham I
3725779dd0aSKishon Vijay Abraham I if (!driver->ops->bind || !driver->ops->unbind)
3735e8cb403SKishon Vijay Abraham I return -EINVAL;
3745e8cb403SKishon Vijay Abraham I
3755e8cb403SKishon Vijay Abraham I driver->driver.bus = &pci_epf_bus_type;
3765e8cb403SKishon Vijay Abraham I driver->driver.owner = owner;
3775e8cb403SKishon Vijay Abraham I
3785e8cb403SKishon Vijay Abraham I ret = driver_register(&driver->driver);
3795e8cb403SKishon Vijay Abraham I if (ret)
3805e8cb403SKishon Vijay Abraham I return ret;
3815e8cb403SKishon Vijay Abraham I
382a83a2173SKishon Vijay Abraham I pci_epf_add_cfs(driver);
3833a401a2cSKishon Vijay Abraham I
3845e8cb403SKishon Vijay Abraham I return 0;
3855e8cb403SKishon Vijay Abraham I }
3865e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(__pci_epf_register_driver);
3875e8cb403SKishon Vijay Abraham I
3885e8cb403SKishon Vijay Abraham I /**
3895e8cb403SKishon Vijay Abraham I * pci_epf_destroy() - destroy the created PCI EPF device
3905e8cb403SKishon Vijay Abraham I * @epf: the PCI EPF device that has to be destroyed.
3915e8cb403SKishon Vijay Abraham I *
3925e8cb403SKishon Vijay Abraham I * Invoke to destroy the PCI EPF device created by invoking pci_epf_create().
3935e8cb403SKishon Vijay Abraham I */
pci_epf_destroy(struct pci_epf * epf)3945e8cb403SKishon Vijay Abraham I void pci_epf_destroy(struct pci_epf *epf)
3955e8cb403SKishon Vijay Abraham I {
3965e8cb403SKishon Vijay Abraham I device_unregister(&epf->dev);
3975e8cb403SKishon Vijay Abraham I }
3985e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epf_destroy);
3995e8cb403SKishon Vijay Abraham I
4005e8cb403SKishon Vijay Abraham I /**
4015e8cb403SKishon Vijay Abraham I * pci_epf_create() - create a new PCI EPF device
4025e8cb403SKishon Vijay Abraham I * @name: the name of the PCI EPF device. This name will be used to bind the
403b2105b9fSKrzysztof Wilczyński * EPF device to a EPF driver
4045e8cb403SKishon Vijay Abraham I *
4055e8cb403SKishon Vijay Abraham I * Invoke to create a new PCI EPF device by providing the name of the function
4065e8cb403SKishon Vijay Abraham I * device.
4075e8cb403SKishon Vijay Abraham I */
pci_epf_create(const char * name)4085e8cb403SKishon Vijay Abraham I struct pci_epf *pci_epf_create(const char *name)
4095e8cb403SKishon Vijay Abraham I {
4105e8cb403SKishon Vijay Abraham I int ret;
4115e8cb403SKishon Vijay Abraham I struct pci_epf *epf;
4125e8cb403SKishon Vijay Abraham I struct device *dev;
41336cc14acSRolf Evers-Fischer int len;
4145e8cb403SKishon Vijay Abraham I
4155e8cb403SKishon Vijay Abraham I epf = kzalloc(sizeof(*epf), GFP_KERNEL);
41650ee1061SRolf Evers-Fischer if (!epf)
41750ee1061SRolf Evers-Fischer return ERR_PTR(-ENOMEM);
4185e8cb403SKishon Vijay Abraham I
41936cc14acSRolf Evers-Fischer len = strchrnul(name, '.') - name;
42036cc14acSRolf Evers-Fischer epf->name = kstrndup(name, len, GFP_KERNEL);
4215e8cb403SKishon Vijay Abraham I if (!epf->name) {
42250ee1061SRolf Evers-Fischer kfree(epf);
42350ee1061SRolf Evers-Fischer return ERR_PTR(-ENOMEM);
4245e8cb403SKishon Vijay Abraham I }
4255e8cb403SKishon Vijay Abraham I
4261cf362e9SKishon Vijay Abraham I /* VFs are numbered starting with 1. So set BIT(0) by default */
4271cf362e9SKishon Vijay Abraham I epf->vfunction_num_map = 1;
4281cf362e9SKishon Vijay Abraham I INIT_LIST_HEAD(&epf->pci_vepf);
4291cf362e9SKishon Vijay Abraham I
4305e8cb403SKishon Vijay Abraham I dev = &epf->dev;
4315e8cb403SKishon Vijay Abraham I device_initialize(dev);
4325e8cb403SKishon Vijay Abraham I dev->bus = &pci_epf_bus_type;
4335e8cb403SKishon Vijay Abraham I dev->type = &pci_epf_type;
43407301c98SKishon Vijay Abraham I mutex_init(&epf->lock);
4355e8cb403SKishon Vijay Abraham I
4365e8cb403SKishon Vijay Abraham I ret = dev_set_name(dev, "%s", name);
43750ee1061SRolf Evers-Fischer if (ret) {
4385e8cb403SKishon Vijay Abraham I put_device(dev);
4399eef6a5cSRolf Evers-Fischer return ERR_PTR(ret);
44050ee1061SRolf Evers-Fischer }
4415e8cb403SKishon Vijay Abraham I
44250ee1061SRolf Evers-Fischer ret = device_add(dev);
44350ee1061SRolf Evers-Fischer if (ret) {
44450ee1061SRolf Evers-Fischer put_device(dev);
4455e8cb403SKishon Vijay Abraham I return ERR_PTR(ret);
4465e8cb403SKishon Vijay Abraham I }
44750ee1061SRolf Evers-Fischer
44850ee1061SRolf Evers-Fischer return epf;
44950ee1061SRolf Evers-Fischer }
4505e8cb403SKishon Vijay Abraham I EXPORT_SYMBOL_GPL(pci_epf_create);
4515e8cb403SKishon Vijay Abraham I
pci_epf_dev_release(struct device * dev)4525e8cb403SKishon Vijay Abraham I static void pci_epf_dev_release(struct device *dev)
4535e8cb403SKishon Vijay Abraham I {
4545e8cb403SKishon Vijay Abraham I struct pci_epf *epf = to_pci_epf(dev);
4555e8cb403SKishon Vijay Abraham I
4565e8cb403SKishon Vijay Abraham I kfree(epf->name);
4575e8cb403SKishon Vijay Abraham I kfree(epf);
4585e8cb403SKishon Vijay Abraham I }
4595e8cb403SKishon Vijay Abraham I
46036b85189SBhumika Goyal static const struct device_type pci_epf_type = {
4615e8cb403SKishon Vijay Abraham I .release = pci_epf_dev_release,
4625e8cb403SKishon Vijay Abraham I };
4635e8cb403SKishon Vijay Abraham I
464*081c715dSManivannan Sadhasivam static const struct pci_epf_device_id *
pci_epf_match_id(const struct pci_epf_device_id * id,const struct pci_epf * epf)4655e8cb403SKishon Vijay Abraham I pci_epf_match_id(const struct pci_epf_device_id *id, const struct pci_epf *epf)
4665e8cb403SKishon Vijay Abraham I {
4675e8cb403SKishon Vijay Abraham I while (id->name[0]) {
4685e8cb403SKishon Vijay Abraham I if (strcmp(epf->name, id->name) == 0)
469*081c715dSManivannan Sadhasivam return id;
4705e8cb403SKishon Vijay Abraham I id++;
4715e8cb403SKishon Vijay Abraham I }
4725e8cb403SKishon Vijay Abraham I
473*081c715dSManivannan Sadhasivam return NULL;
4745e8cb403SKishon Vijay Abraham I }
4755e8cb403SKishon Vijay Abraham I
pci_epf_device_match(struct device * dev,struct device_driver * drv)4765e8cb403SKishon Vijay Abraham I static int pci_epf_device_match(struct device *dev, struct device_driver *drv)
4775e8cb403SKishon Vijay Abraham I {
4785e8cb403SKishon Vijay Abraham I struct pci_epf *epf = to_pci_epf(dev);
4795e8cb403SKishon Vijay Abraham I struct pci_epf_driver *driver = to_pci_epf_driver(drv);
4805e8cb403SKishon Vijay Abraham I
4815e8cb403SKishon Vijay Abraham I if (driver->id_table)
482*081c715dSManivannan Sadhasivam return !!pci_epf_match_id(driver->id_table, epf);
4835e8cb403SKishon Vijay Abraham I
4845e8cb403SKishon Vijay Abraham I return !strcmp(epf->name, drv->name);
4855e8cb403SKishon Vijay Abraham I }
4865e8cb403SKishon Vijay Abraham I
pci_epf_device_probe(struct device * dev)4875e8cb403SKishon Vijay Abraham I static int pci_epf_device_probe(struct device *dev)
4885e8cb403SKishon Vijay Abraham I {
4895e8cb403SKishon Vijay Abraham I struct pci_epf *epf = to_pci_epf(dev);
4905e8cb403SKishon Vijay Abraham I struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver);
4915e8cb403SKishon Vijay Abraham I
4925e8cb403SKishon Vijay Abraham I if (!driver->probe)
4935e8cb403SKishon Vijay Abraham I return -ENODEV;
4945e8cb403SKishon Vijay Abraham I
4955e8cb403SKishon Vijay Abraham I epf->driver = driver;
4965e8cb403SKishon Vijay Abraham I
497*081c715dSManivannan Sadhasivam return driver->probe(epf, pci_epf_match_id(driver->id_table, epf));
4985e8cb403SKishon Vijay Abraham I }
4995e8cb403SKishon Vijay Abraham I
pci_epf_device_remove(struct device * dev)500fc7a6209SUwe Kleine-König static void pci_epf_device_remove(struct device *dev)
5015e8cb403SKishon Vijay Abraham I {
5025e8cb403SKishon Vijay Abraham I struct pci_epf *epf = to_pci_epf(dev);
5035e8cb403SKishon Vijay Abraham I struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver);
5045e8cb403SKishon Vijay Abraham I
50528daeff6SKishon Vijay Abraham I if (driver->remove)
506dde0a318SUwe Kleine-König driver->remove(epf);
5075e8cb403SKishon Vijay Abraham I epf->driver = NULL;
5085e8cb403SKishon Vijay Abraham I }
5095e8cb403SKishon Vijay Abraham I
5105e8cb403SKishon Vijay Abraham I static struct bus_type pci_epf_bus_type = {
5115e8cb403SKishon Vijay Abraham I .name = "pci-epf",
5125e8cb403SKishon Vijay Abraham I .match = pci_epf_device_match,
5135e8cb403SKishon Vijay Abraham I .probe = pci_epf_device_probe,
5145e8cb403SKishon Vijay Abraham I .remove = pci_epf_device_remove,
5155e8cb403SKishon Vijay Abraham I };
5165e8cb403SKishon Vijay Abraham I
pci_epf_init(void)5175e8cb403SKishon Vijay Abraham I static int __init pci_epf_init(void)
5185e8cb403SKishon Vijay Abraham I {
5195e8cb403SKishon Vijay Abraham I int ret;
5205e8cb403SKishon Vijay Abraham I
5215e8cb403SKishon Vijay Abraham I ret = bus_register(&pci_epf_bus_type);
5225e8cb403SKishon Vijay Abraham I if (ret) {
5235e8cb403SKishon Vijay Abraham I pr_err("failed to register pci epf bus --> %d\n", ret);
5245e8cb403SKishon Vijay Abraham I return ret;
5255e8cb403SKishon Vijay Abraham I }
5265e8cb403SKishon Vijay Abraham I
5275e8cb403SKishon Vijay Abraham I return 0;
5285e8cb403SKishon Vijay Abraham I }
5295e8cb403SKishon Vijay Abraham I module_init(pci_epf_init);
5305e8cb403SKishon Vijay Abraham I
pci_epf_exit(void)5315e8cb403SKishon Vijay Abraham I static void __exit pci_epf_exit(void)
5325e8cb403SKishon Vijay Abraham I {
5335e8cb403SKishon Vijay Abraham I bus_unregister(&pci_epf_bus_type);
5345e8cb403SKishon Vijay Abraham I }
5355e8cb403SKishon Vijay Abraham I module_exit(pci_epf_exit);
5365e8cb403SKishon Vijay Abraham I
5375e8cb403SKishon Vijay Abraham I MODULE_DESCRIPTION("PCI EPF Library");
5385e8cb403SKishon Vijay Abraham I MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
539