xref: /OK3568_Linux_fs/kernel/drivers/pci/endpoint/pci-ep-cfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * configfs to configure the PCI endpoint
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2017 Texas Instruments
6*4882a593Smuzhiyun  * Author: Kishon Vijay Abraham I <kishon@ti.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/idr.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/pci-epc.h>
14*4882a593Smuzhiyun #include <linux/pci-epf.h>
15*4882a593Smuzhiyun #include <linux/pci-ep-cfs.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun static DEFINE_IDR(functions_idr);
18*4882a593Smuzhiyun static DEFINE_MUTEX(functions_mutex);
19*4882a593Smuzhiyun static struct config_group *functions_group;
20*4882a593Smuzhiyun static struct config_group *controllers_group;
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun struct pci_epf_group {
23*4882a593Smuzhiyun 	struct config_group group;
24*4882a593Smuzhiyun 	struct pci_epf *epf;
25*4882a593Smuzhiyun 	int index;
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun struct pci_epc_group {
29*4882a593Smuzhiyun 	struct config_group group;
30*4882a593Smuzhiyun 	struct pci_epc *epc;
31*4882a593Smuzhiyun 	bool start;
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun 
to_pci_epf_group(struct config_item * item)34*4882a593Smuzhiyun static inline struct pci_epf_group *to_pci_epf_group(struct config_item *item)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	return container_of(to_config_group(item), struct pci_epf_group, group);
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun 
to_pci_epc_group(struct config_item * item)39*4882a593Smuzhiyun static inline struct pci_epc_group *to_pci_epc_group(struct config_item *item)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	return container_of(to_config_group(item), struct pci_epc_group, group);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
pci_epc_start_store(struct config_item * item,const char * page,size_t len)44*4882a593Smuzhiyun static ssize_t pci_epc_start_store(struct config_item *item, const char *page,
45*4882a593Smuzhiyun 				   size_t len)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	int ret;
48*4882a593Smuzhiyun 	bool start;
49*4882a593Smuzhiyun 	struct pci_epc *epc;
50*4882a593Smuzhiyun 	struct pci_epc_group *epc_group = to_pci_epc_group(item);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	epc = epc_group->epc;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	ret = kstrtobool(page, &start);
55*4882a593Smuzhiyun 	if (ret)
56*4882a593Smuzhiyun 		return ret;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	if (!start) {
59*4882a593Smuzhiyun 		pci_epc_stop(epc);
60*4882a593Smuzhiyun 		epc_group->start = 0;
61*4882a593Smuzhiyun 		return len;
62*4882a593Smuzhiyun 	}
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	ret = pci_epc_start(epc);
65*4882a593Smuzhiyun 	if (ret) {
66*4882a593Smuzhiyun 		dev_err(&epc->dev, "failed to start endpoint controller\n");
67*4882a593Smuzhiyun 		return -EINVAL;
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	epc_group->start = start;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	return len;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
pci_epc_start_show(struct config_item * item,char * page)75*4882a593Smuzhiyun static ssize_t pci_epc_start_show(struct config_item *item, char *page)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	return sprintf(page, "%d\n",
78*4882a593Smuzhiyun 		       to_pci_epc_group(item)->start);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epc_, start);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun static struct configfs_attribute *pci_epc_attrs[] = {
84*4882a593Smuzhiyun 	&pci_epc_attr_start,
85*4882a593Smuzhiyun 	NULL,
86*4882a593Smuzhiyun };
87*4882a593Smuzhiyun 
pci_epc_epf_link(struct config_item * epc_item,struct config_item * epf_item)88*4882a593Smuzhiyun static int pci_epc_epf_link(struct config_item *epc_item,
89*4882a593Smuzhiyun 			    struct config_item *epf_item)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	int ret;
92*4882a593Smuzhiyun 	struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);
93*4882a593Smuzhiyun 	struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
94*4882a593Smuzhiyun 	struct pci_epc *epc = epc_group->epc;
95*4882a593Smuzhiyun 	struct pci_epf *epf = epf_group->epf;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	ret = pci_epc_add_epf(epc, epf);
98*4882a593Smuzhiyun 	if (ret)
99*4882a593Smuzhiyun 		return ret;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	ret = pci_epf_bind(epf);
102*4882a593Smuzhiyun 	if (ret) {
103*4882a593Smuzhiyun 		pci_epc_remove_epf(epc, epf);
104*4882a593Smuzhiyun 		return ret;
105*4882a593Smuzhiyun 	}
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	return 0;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
pci_epc_epf_unlink(struct config_item * epc_item,struct config_item * epf_item)110*4882a593Smuzhiyun static void pci_epc_epf_unlink(struct config_item *epc_item,
111*4882a593Smuzhiyun 			       struct config_item *epf_item)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	struct pci_epc *epc;
114*4882a593Smuzhiyun 	struct pci_epf *epf;
115*4882a593Smuzhiyun 	struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);
116*4882a593Smuzhiyun 	struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	WARN_ON_ONCE(epc_group->start);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	epc = epc_group->epc;
121*4882a593Smuzhiyun 	epf = epf_group->epf;
122*4882a593Smuzhiyun 	pci_epf_unbind(epf);
123*4882a593Smuzhiyun 	pci_epc_remove_epf(epc, epf);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun static struct configfs_item_operations pci_epc_item_ops = {
127*4882a593Smuzhiyun 	.allow_link	= pci_epc_epf_link,
128*4882a593Smuzhiyun 	.drop_link	= pci_epc_epf_unlink,
129*4882a593Smuzhiyun };
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun static const struct config_item_type pci_epc_type = {
132*4882a593Smuzhiyun 	.ct_item_ops	= &pci_epc_item_ops,
133*4882a593Smuzhiyun 	.ct_attrs	= pci_epc_attrs,
134*4882a593Smuzhiyun 	.ct_owner	= THIS_MODULE,
135*4882a593Smuzhiyun };
136*4882a593Smuzhiyun 
pci_ep_cfs_add_epc_group(const char * name)137*4882a593Smuzhiyun struct config_group *pci_ep_cfs_add_epc_group(const char *name)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	int ret;
140*4882a593Smuzhiyun 	struct pci_epc *epc;
141*4882a593Smuzhiyun 	struct config_group *group;
142*4882a593Smuzhiyun 	struct pci_epc_group *epc_group;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	epc_group = kzalloc(sizeof(*epc_group), GFP_KERNEL);
145*4882a593Smuzhiyun 	if (!epc_group) {
146*4882a593Smuzhiyun 		ret = -ENOMEM;
147*4882a593Smuzhiyun 		goto err;
148*4882a593Smuzhiyun 	}
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	group = &epc_group->group;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	config_group_init_type_name(group, name, &pci_epc_type);
153*4882a593Smuzhiyun 	ret = configfs_register_group(controllers_group, group);
154*4882a593Smuzhiyun 	if (ret) {
155*4882a593Smuzhiyun 		pr_err("failed to register configfs group for %s\n", name);
156*4882a593Smuzhiyun 		goto err_register_group;
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	epc = pci_epc_get(name);
160*4882a593Smuzhiyun 	if (IS_ERR(epc)) {
161*4882a593Smuzhiyun 		ret = PTR_ERR(epc);
162*4882a593Smuzhiyun 		goto err_epc_get;
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	epc_group->epc = epc;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	return group;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun err_epc_get:
170*4882a593Smuzhiyun 	configfs_unregister_group(group);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun err_register_group:
173*4882a593Smuzhiyun 	kfree(epc_group);
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun err:
176*4882a593Smuzhiyun 	return ERR_PTR(ret);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun EXPORT_SYMBOL(pci_ep_cfs_add_epc_group);
179*4882a593Smuzhiyun 
pci_ep_cfs_remove_epc_group(struct config_group * group)180*4882a593Smuzhiyun void pci_ep_cfs_remove_epc_group(struct config_group *group)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	struct pci_epc_group *epc_group;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	if (!group)
185*4882a593Smuzhiyun 		return;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	epc_group = container_of(group, struct pci_epc_group, group);
188*4882a593Smuzhiyun 	pci_epc_put(epc_group->epc);
189*4882a593Smuzhiyun 	configfs_unregister_group(&epc_group->group);
190*4882a593Smuzhiyun 	kfree(epc_group);
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun EXPORT_SYMBOL(pci_ep_cfs_remove_epc_group);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun #define PCI_EPF_HEADER_R(_name)						       \
195*4882a593Smuzhiyun static ssize_t pci_epf_##_name##_show(struct config_item *item,	char *page)    \
196*4882a593Smuzhiyun {									       \
197*4882a593Smuzhiyun 	struct pci_epf *epf = to_pci_epf_group(item)->epf;		       \
198*4882a593Smuzhiyun 	if (WARN_ON_ONCE(!epf->header))					       \
199*4882a593Smuzhiyun 		return -EINVAL;						       \
200*4882a593Smuzhiyun 	return sprintf(page, "0x%04x\n", epf->header->_name);		       \
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun #define PCI_EPF_HEADER_W_u32(_name)					       \
204*4882a593Smuzhiyun static ssize_t pci_epf_##_name##_store(struct config_item *item,	       \
205*4882a593Smuzhiyun 				       const char *page, size_t len)	       \
206*4882a593Smuzhiyun {									       \
207*4882a593Smuzhiyun 	u32 val;							       \
208*4882a593Smuzhiyun 	int ret;							       \
209*4882a593Smuzhiyun 	struct pci_epf *epf = to_pci_epf_group(item)->epf;		       \
210*4882a593Smuzhiyun 	if (WARN_ON_ONCE(!epf->header))					       \
211*4882a593Smuzhiyun 		return -EINVAL;						       \
212*4882a593Smuzhiyun 	ret = kstrtou32(page, 0, &val);					       \
213*4882a593Smuzhiyun 	if (ret)							       \
214*4882a593Smuzhiyun 		return ret;						       \
215*4882a593Smuzhiyun 	epf->header->_name = val;					       \
216*4882a593Smuzhiyun 	return len;							       \
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun #define PCI_EPF_HEADER_W_u16(_name)					       \
220*4882a593Smuzhiyun static ssize_t pci_epf_##_name##_store(struct config_item *item,	       \
221*4882a593Smuzhiyun 				       const char *page, size_t len)	       \
222*4882a593Smuzhiyun {									       \
223*4882a593Smuzhiyun 	u16 val;							       \
224*4882a593Smuzhiyun 	int ret;							       \
225*4882a593Smuzhiyun 	struct pci_epf *epf = to_pci_epf_group(item)->epf;		       \
226*4882a593Smuzhiyun 	if (WARN_ON_ONCE(!epf->header))					       \
227*4882a593Smuzhiyun 		return -EINVAL;						       \
228*4882a593Smuzhiyun 	ret = kstrtou16(page, 0, &val);					       \
229*4882a593Smuzhiyun 	if (ret)							       \
230*4882a593Smuzhiyun 		return ret;						       \
231*4882a593Smuzhiyun 	epf->header->_name = val;					       \
232*4882a593Smuzhiyun 	return len;							       \
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun #define PCI_EPF_HEADER_W_u8(_name)					       \
236*4882a593Smuzhiyun static ssize_t pci_epf_##_name##_store(struct config_item *item,	       \
237*4882a593Smuzhiyun 				       const char *page, size_t len)	       \
238*4882a593Smuzhiyun {									       \
239*4882a593Smuzhiyun 	u8 val;								       \
240*4882a593Smuzhiyun 	int ret;							       \
241*4882a593Smuzhiyun 	struct pci_epf *epf = to_pci_epf_group(item)->epf;		       \
242*4882a593Smuzhiyun 	if (WARN_ON_ONCE(!epf->header))					       \
243*4882a593Smuzhiyun 		return -EINVAL;						       \
244*4882a593Smuzhiyun 	ret = kstrtou8(page, 0, &val);					       \
245*4882a593Smuzhiyun 	if (ret)							       \
246*4882a593Smuzhiyun 		return ret;						       \
247*4882a593Smuzhiyun 	epf->header->_name = val;					       \
248*4882a593Smuzhiyun 	return len;							       \
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
pci_epf_msi_interrupts_store(struct config_item * item,const char * page,size_t len)251*4882a593Smuzhiyun static ssize_t pci_epf_msi_interrupts_store(struct config_item *item,
252*4882a593Smuzhiyun 					    const char *page, size_t len)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	u8 val;
255*4882a593Smuzhiyun 	int ret;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	ret = kstrtou8(page, 0, &val);
258*4882a593Smuzhiyun 	if (ret)
259*4882a593Smuzhiyun 		return ret;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	to_pci_epf_group(item)->epf->msi_interrupts = val;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	return len;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
pci_epf_msi_interrupts_show(struct config_item * item,char * page)266*4882a593Smuzhiyun static ssize_t pci_epf_msi_interrupts_show(struct config_item *item,
267*4882a593Smuzhiyun 					   char *page)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	return sprintf(page, "%d\n",
270*4882a593Smuzhiyun 		       to_pci_epf_group(item)->epf->msi_interrupts);
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun 
pci_epf_msix_interrupts_store(struct config_item * item,const char * page,size_t len)273*4882a593Smuzhiyun static ssize_t pci_epf_msix_interrupts_store(struct config_item *item,
274*4882a593Smuzhiyun 					     const char *page, size_t len)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun 	u16 val;
277*4882a593Smuzhiyun 	int ret;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	ret = kstrtou16(page, 0, &val);
280*4882a593Smuzhiyun 	if (ret)
281*4882a593Smuzhiyun 		return ret;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	to_pci_epf_group(item)->epf->msix_interrupts = val;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	return len;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun 
pci_epf_msix_interrupts_show(struct config_item * item,char * page)288*4882a593Smuzhiyun static ssize_t pci_epf_msix_interrupts_show(struct config_item *item,
289*4882a593Smuzhiyun 					    char *page)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	return sprintf(page, "%d\n",
292*4882a593Smuzhiyun 		       to_pci_epf_group(item)->epf->msix_interrupts);
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun PCI_EPF_HEADER_R(vendorid)
296*4882a593Smuzhiyun PCI_EPF_HEADER_W_u16(vendorid)
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun PCI_EPF_HEADER_R(deviceid)
299*4882a593Smuzhiyun PCI_EPF_HEADER_W_u16(deviceid)
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun PCI_EPF_HEADER_R(revid)
302*4882a593Smuzhiyun PCI_EPF_HEADER_W_u8(revid)
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun PCI_EPF_HEADER_R(progif_code)
305*4882a593Smuzhiyun PCI_EPF_HEADER_W_u8(progif_code)
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun PCI_EPF_HEADER_R(subclass_code)
308*4882a593Smuzhiyun PCI_EPF_HEADER_W_u8(subclass_code)
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun PCI_EPF_HEADER_R(baseclass_code)
311*4882a593Smuzhiyun PCI_EPF_HEADER_W_u8(baseclass_code)
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun PCI_EPF_HEADER_R(cache_line_size)
314*4882a593Smuzhiyun PCI_EPF_HEADER_W_u8(cache_line_size)
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun PCI_EPF_HEADER_R(subsys_vendor_id)
317*4882a593Smuzhiyun PCI_EPF_HEADER_W_u16(subsys_vendor_id)
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun PCI_EPF_HEADER_R(subsys_id)
320*4882a593Smuzhiyun PCI_EPF_HEADER_W_u16(subsys_id)
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun PCI_EPF_HEADER_R(interrupt_pin)
323*4882a593Smuzhiyun PCI_EPF_HEADER_W_u8(interrupt_pin)
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, vendorid);
326*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, deviceid);
327*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, revid);
328*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, progif_code);
329*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, subclass_code);
330*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, baseclass_code);
331*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, cache_line_size);
332*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, subsys_vendor_id);
333*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, subsys_id);
334*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, interrupt_pin);
335*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, msi_interrupts);
336*4882a593Smuzhiyun CONFIGFS_ATTR(pci_epf_, msix_interrupts);
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun static struct configfs_attribute *pci_epf_attrs[] = {
339*4882a593Smuzhiyun 	&pci_epf_attr_vendorid,
340*4882a593Smuzhiyun 	&pci_epf_attr_deviceid,
341*4882a593Smuzhiyun 	&pci_epf_attr_revid,
342*4882a593Smuzhiyun 	&pci_epf_attr_progif_code,
343*4882a593Smuzhiyun 	&pci_epf_attr_subclass_code,
344*4882a593Smuzhiyun 	&pci_epf_attr_baseclass_code,
345*4882a593Smuzhiyun 	&pci_epf_attr_cache_line_size,
346*4882a593Smuzhiyun 	&pci_epf_attr_subsys_vendor_id,
347*4882a593Smuzhiyun 	&pci_epf_attr_subsys_id,
348*4882a593Smuzhiyun 	&pci_epf_attr_interrupt_pin,
349*4882a593Smuzhiyun 	&pci_epf_attr_msi_interrupts,
350*4882a593Smuzhiyun 	&pci_epf_attr_msix_interrupts,
351*4882a593Smuzhiyun 	NULL,
352*4882a593Smuzhiyun };
353*4882a593Smuzhiyun 
pci_epf_release(struct config_item * item)354*4882a593Smuzhiyun static void pci_epf_release(struct config_item *item)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun 	struct pci_epf_group *epf_group = to_pci_epf_group(item);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	mutex_lock(&functions_mutex);
359*4882a593Smuzhiyun 	idr_remove(&functions_idr, epf_group->index);
360*4882a593Smuzhiyun 	mutex_unlock(&functions_mutex);
361*4882a593Smuzhiyun 	pci_epf_destroy(epf_group->epf);
362*4882a593Smuzhiyun 	kfree(epf_group);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun static struct configfs_item_operations pci_epf_ops = {
366*4882a593Smuzhiyun 	.release		= pci_epf_release,
367*4882a593Smuzhiyun };
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun static const struct config_item_type pci_epf_type = {
370*4882a593Smuzhiyun 	.ct_item_ops	= &pci_epf_ops,
371*4882a593Smuzhiyun 	.ct_attrs	= pci_epf_attrs,
372*4882a593Smuzhiyun 	.ct_owner	= THIS_MODULE,
373*4882a593Smuzhiyun };
374*4882a593Smuzhiyun 
pci_epf_make(struct config_group * group,const char * name)375*4882a593Smuzhiyun static struct config_group *pci_epf_make(struct config_group *group,
376*4882a593Smuzhiyun 					 const char *name)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	struct pci_epf_group *epf_group;
379*4882a593Smuzhiyun 	struct pci_epf *epf;
380*4882a593Smuzhiyun 	char *epf_name;
381*4882a593Smuzhiyun 	int index, err;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	epf_group = kzalloc(sizeof(*epf_group), GFP_KERNEL);
384*4882a593Smuzhiyun 	if (!epf_group)
385*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	mutex_lock(&functions_mutex);
388*4882a593Smuzhiyun 	index = idr_alloc(&functions_idr, epf_group, 0, 0, GFP_KERNEL);
389*4882a593Smuzhiyun 	mutex_unlock(&functions_mutex);
390*4882a593Smuzhiyun 	if (index < 0) {
391*4882a593Smuzhiyun 		err = index;
392*4882a593Smuzhiyun 		goto free_group;
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	epf_group->index = index;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	config_group_init_type_name(&epf_group->group, name, &pci_epf_type);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	epf_name = kasprintf(GFP_KERNEL, "%s.%d",
400*4882a593Smuzhiyun 			     group->cg_item.ci_name, epf_group->index);
401*4882a593Smuzhiyun 	if (!epf_name) {
402*4882a593Smuzhiyun 		err = -ENOMEM;
403*4882a593Smuzhiyun 		goto remove_idr;
404*4882a593Smuzhiyun 	}
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	epf = pci_epf_create(epf_name);
407*4882a593Smuzhiyun 	if (IS_ERR(epf)) {
408*4882a593Smuzhiyun 		pr_err("failed to create endpoint function device\n");
409*4882a593Smuzhiyun 		err = -EINVAL;
410*4882a593Smuzhiyun 		goto free_name;
411*4882a593Smuzhiyun 	}
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	epf_group->epf = epf;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	kfree(epf_name);
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	return &epf_group->group;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun free_name:
420*4882a593Smuzhiyun 	kfree(epf_name);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun remove_idr:
423*4882a593Smuzhiyun 	mutex_lock(&functions_mutex);
424*4882a593Smuzhiyun 	idr_remove(&functions_idr, epf_group->index);
425*4882a593Smuzhiyun 	mutex_unlock(&functions_mutex);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun free_group:
428*4882a593Smuzhiyun 	kfree(epf_group);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	return ERR_PTR(err);
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun 
pci_epf_drop(struct config_group * group,struct config_item * item)433*4882a593Smuzhiyun static void pci_epf_drop(struct config_group *group, struct config_item *item)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	config_item_put(item);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun static struct configfs_group_operations pci_epf_group_ops = {
439*4882a593Smuzhiyun 	.make_group     = &pci_epf_make,
440*4882a593Smuzhiyun 	.drop_item      = &pci_epf_drop,
441*4882a593Smuzhiyun };
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun static const struct config_item_type pci_epf_group_type = {
444*4882a593Smuzhiyun 	.ct_group_ops	= &pci_epf_group_ops,
445*4882a593Smuzhiyun 	.ct_owner	= THIS_MODULE,
446*4882a593Smuzhiyun };
447*4882a593Smuzhiyun 
pci_ep_cfs_add_epf_group(const char * name)448*4882a593Smuzhiyun struct config_group *pci_ep_cfs_add_epf_group(const char *name)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	struct config_group *group;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	group = configfs_register_default_group(functions_group, name,
453*4882a593Smuzhiyun 						&pci_epf_group_type);
454*4882a593Smuzhiyun 	if (IS_ERR(group))
455*4882a593Smuzhiyun 		pr_err("failed to register configfs group for %s function\n",
456*4882a593Smuzhiyun 		       name);
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	return group;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun EXPORT_SYMBOL(pci_ep_cfs_add_epf_group);
461*4882a593Smuzhiyun 
pci_ep_cfs_remove_epf_group(struct config_group * group)462*4882a593Smuzhiyun void pci_ep_cfs_remove_epf_group(struct config_group *group)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun 	if (IS_ERR_OR_NULL(group))
465*4882a593Smuzhiyun 		return;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	configfs_unregister_default_group(group);
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun EXPORT_SYMBOL(pci_ep_cfs_remove_epf_group);
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun static const struct config_item_type pci_functions_type = {
472*4882a593Smuzhiyun 	.ct_owner	= THIS_MODULE,
473*4882a593Smuzhiyun };
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun static const struct config_item_type pci_controllers_type = {
476*4882a593Smuzhiyun 	.ct_owner	= THIS_MODULE,
477*4882a593Smuzhiyun };
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun static const struct config_item_type pci_ep_type = {
480*4882a593Smuzhiyun 	.ct_owner	= THIS_MODULE,
481*4882a593Smuzhiyun };
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun static struct configfs_subsystem pci_ep_cfs_subsys = {
484*4882a593Smuzhiyun 	.su_group = {
485*4882a593Smuzhiyun 		.cg_item = {
486*4882a593Smuzhiyun 			.ci_namebuf = "pci_ep",
487*4882a593Smuzhiyun 			.ci_type = &pci_ep_type,
488*4882a593Smuzhiyun 		},
489*4882a593Smuzhiyun 	},
490*4882a593Smuzhiyun 	.su_mutex = __MUTEX_INITIALIZER(pci_ep_cfs_subsys.su_mutex),
491*4882a593Smuzhiyun };
492*4882a593Smuzhiyun 
pci_ep_cfs_init(void)493*4882a593Smuzhiyun static int __init pci_ep_cfs_init(void)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun 	int ret;
496*4882a593Smuzhiyun 	struct config_group *root = &pci_ep_cfs_subsys.su_group;
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	config_group_init(root);
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	ret = configfs_register_subsystem(&pci_ep_cfs_subsys);
501*4882a593Smuzhiyun 	if (ret) {
502*4882a593Smuzhiyun 		pr_err("Error %d while registering subsystem %s\n",
503*4882a593Smuzhiyun 		       ret, root->cg_item.ci_namebuf);
504*4882a593Smuzhiyun 		goto err;
505*4882a593Smuzhiyun 	}
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	functions_group = configfs_register_default_group(root, "functions",
508*4882a593Smuzhiyun 							  &pci_functions_type);
509*4882a593Smuzhiyun 	if (IS_ERR(functions_group)) {
510*4882a593Smuzhiyun 		ret = PTR_ERR(functions_group);
511*4882a593Smuzhiyun 		pr_err("Error %d while registering functions group\n",
512*4882a593Smuzhiyun 		       ret);
513*4882a593Smuzhiyun 		goto err_functions_group;
514*4882a593Smuzhiyun 	}
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	controllers_group =
517*4882a593Smuzhiyun 		configfs_register_default_group(root, "controllers",
518*4882a593Smuzhiyun 						&pci_controllers_type);
519*4882a593Smuzhiyun 	if (IS_ERR(controllers_group)) {
520*4882a593Smuzhiyun 		ret = PTR_ERR(controllers_group);
521*4882a593Smuzhiyun 		pr_err("Error %d while registering controllers group\n",
522*4882a593Smuzhiyun 		       ret);
523*4882a593Smuzhiyun 		goto err_controllers_group;
524*4882a593Smuzhiyun 	}
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	return 0;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun err_controllers_group:
529*4882a593Smuzhiyun 	configfs_unregister_default_group(functions_group);
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun err_functions_group:
532*4882a593Smuzhiyun 	configfs_unregister_subsystem(&pci_ep_cfs_subsys);
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun err:
535*4882a593Smuzhiyun 	return ret;
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun module_init(pci_ep_cfs_init);
538*4882a593Smuzhiyun 
pci_ep_cfs_exit(void)539*4882a593Smuzhiyun static void __exit pci_ep_cfs_exit(void)
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun 	configfs_unregister_default_group(controllers_group);
542*4882a593Smuzhiyun 	configfs_unregister_default_group(functions_group);
543*4882a593Smuzhiyun 	configfs_unregister_subsystem(&pci_ep_cfs_subsys);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun module_exit(pci_ep_cfs_exit);
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun MODULE_DESCRIPTION("PCI EP CONFIGFS");
548*4882a593Smuzhiyun MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
549*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
550