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