xref: /openbmc/linux/drivers/pci/endpoint/pci-ep-cfs.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
18cfab3cfSBjorn Helgaas // SPDX-License-Identifier: GPL-2.0
29b41d19aSKrzysztof Kozlowski /*
3d7467991SKishon Vijay Abraham I  * configfs to configure the PCI endpoint
4d7467991SKishon Vijay Abraham I  *
5d7467991SKishon Vijay Abraham I  * Copyright (C) 2017 Texas Instruments
6d7467991SKishon Vijay Abraham I  * Author: Kishon Vijay Abraham I <kishon@ti.com>
7d7467991SKishon Vijay Abraham I  */
8d7467991SKishon Vijay Abraham I 
9d7467991SKishon Vijay Abraham I #include <linux/module.h>
10fc41df28SCyrille Pitchen #include <linux/idr.h>
11d7467991SKishon Vijay Abraham I #include <linux/slab.h>
12d7467991SKishon Vijay Abraham I 
13d7467991SKishon Vijay Abraham I #include <linux/pci-epc.h>
14d7467991SKishon Vijay Abraham I #include <linux/pci-epf.h>
15d7467991SKishon Vijay Abraham I #include <linux/pci-ep-cfs.h>
16d7467991SKishon Vijay Abraham I 
17fc41df28SCyrille Pitchen static DEFINE_IDR(functions_idr);
18fc41df28SCyrille Pitchen static DEFINE_MUTEX(functions_mutex);
19d7467991SKishon Vijay Abraham I static struct config_group *functions_group;
20d7467991SKishon Vijay Abraham I static struct config_group *controllers_group;
21d7467991SKishon Vijay Abraham I 
22d7467991SKishon Vijay Abraham I struct pci_epf_group {
23d7467991SKishon Vijay Abraham I 	struct config_group group;
24e85a2d78SKishon Vijay Abraham I 	struct config_group primary_epc_group;
25e85a2d78SKishon Vijay Abraham I 	struct config_group secondary_epc_group;
2670b3740fSDamien Le Moal 	struct config_group *type_group;
27e85a2d78SKishon Vijay Abraham I 	struct delayed_work cfs_work;
28d7467991SKishon Vijay Abraham I 	struct pci_epf *epf;
29fc41df28SCyrille Pitchen 	int index;
30d7467991SKishon Vijay Abraham I };
31d7467991SKishon Vijay Abraham I 
32d7467991SKishon Vijay Abraham I struct pci_epc_group {
33d7467991SKishon Vijay Abraham I 	struct config_group group;
34d7467991SKishon Vijay Abraham I 	struct pci_epc *epc;
35d7467991SKishon Vijay Abraham I 	bool start;
36d7467991SKishon Vijay Abraham I };
37d7467991SKishon Vijay Abraham I 
to_pci_epf_group(struct config_item * item)38d7467991SKishon Vijay Abraham I static inline struct pci_epf_group *to_pci_epf_group(struct config_item *item)
39d7467991SKishon Vijay Abraham I {
40d7467991SKishon Vijay Abraham I 	return container_of(to_config_group(item), struct pci_epf_group, group);
41d7467991SKishon Vijay Abraham I }
42d7467991SKishon Vijay Abraham I 
to_pci_epc_group(struct config_item * item)43d7467991SKishon Vijay Abraham I static inline struct pci_epc_group *to_pci_epc_group(struct config_item *item)
44d7467991SKishon Vijay Abraham I {
45d7467991SKishon Vijay Abraham I 	return container_of(to_config_group(item), struct pci_epc_group, group);
46d7467991SKishon Vijay Abraham I }
47d7467991SKishon Vijay Abraham I 
pci_secondary_epc_epf_link(struct config_item * epf_item,struct config_item * epc_item)48e85a2d78SKishon Vijay Abraham I static int pci_secondary_epc_epf_link(struct config_item *epf_item,
49e85a2d78SKishon Vijay Abraham I 				      struct config_item *epc_item)
50e85a2d78SKishon Vijay Abraham I {
51e85a2d78SKishon Vijay Abraham I 	int ret;
52e85a2d78SKishon Vijay Abraham I 	struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);
53e85a2d78SKishon Vijay Abraham I 	struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
54e85a2d78SKishon Vijay Abraham I 	struct pci_epc *epc = epc_group->epc;
55e85a2d78SKishon Vijay Abraham I 	struct pci_epf *epf = epf_group->epf;
56e85a2d78SKishon Vijay Abraham I 
57e85a2d78SKishon Vijay Abraham I 	ret = pci_epc_add_epf(epc, epf, SECONDARY_INTERFACE);
58e85a2d78SKishon Vijay Abraham I 	if (ret)
59e85a2d78SKishon Vijay Abraham I 		return ret;
60e85a2d78SKishon Vijay Abraham I 
61e85a2d78SKishon Vijay Abraham I 	ret = pci_epf_bind(epf);
62e85a2d78SKishon Vijay Abraham I 	if (ret) {
63e85a2d78SKishon Vijay Abraham I 		pci_epc_remove_epf(epc, epf, SECONDARY_INTERFACE);
64e85a2d78SKishon Vijay Abraham I 		return ret;
65e85a2d78SKishon Vijay Abraham I 	}
66e85a2d78SKishon Vijay Abraham I 
67e85a2d78SKishon Vijay Abraham I 	return 0;
68e85a2d78SKishon Vijay Abraham I }
69e85a2d78SKishon Vijay Abraham I 
pci_secondary_epc_epf_unlink(struct config_item * epc_item,struct config_item * epf_item)70e85a2d78SKishon Vijay Abraham I static void pci_secondary_epc_epf_unlink(struct config_item *epc_item,
71e85a2d78SKishon Vijay Abraham I 					 struct config_item *epf_item)
72e85a2d78SKishon Vijay Abraham I {
73e85a2d78SKishon Vijay Abraham I 	struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);
74e85a2d78SKishon Vijay Abraham I 	struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
75e85a2d78SKishon Vijay Abraham I 	struct pci_epc *epc;
76e85a2d78SKishon Vijay Abraham I 	struct pci_epf *epf;
77e85a2d78SKishon Vijay Abraham I 
78e85a2d78SKishon Vijay Abraham I 	WARN_ON_ONCE(epc_group->start);
79e85a2d78SKishon Vijay Abraham I 
80e85a2d78SKishon Vijay Abraham I 	epc = epc_group->epc;
81e85a2d78SKishon Vijay Abraham I 	epf = epf_group->epf;
82e85a2d78SKishon Vijay Abraham I 	pci_epf_unbind(epf);
83e85a2d78SKishon Vijay Abraham I 	pci_epc_remove_epf(epc, epf, SECONDARY_INTERFACE);
84e85a2d78SKishon Vijay Abraham I }
85e85a2d78SKishon Vijay Abraham I 
86e85a2d78SKishon Vijay Abraham I static struct configfs_item_operations pci_secondary_epc_item_ops = {
87e85a2d78SKishon Vijay Abraham I 	.allow_link	= pci_secondary_epc_epf_link,
88e85a2d78SKishon Vijay Abraham I 	.drop_link	= pci_secondary_epc_epf_unlink,
89e85a2d78SKishon Vijay Abraham I };
90e85a2d78SKishon Vijay Abraham I 
91e85a2d78SKishon Vijay Abraham I static const struct config_item_type pci_secondary_epc_type = {
92e85a2d78SKishon Vijay Abraham I 	.ct_item_ops	= &pci_secondary_epc_item_ops,
93e85a2d78SKishon Vijay Abraham I 	.ct_owner	= THIS_MODULE,
94e85a2d78SKishon Vijay Abraham I };
95e85a2d78SKishon Vijay Abraham I 
96e85a2d78SKishon Vijay Abraham I static struct config_group
pci_ep_cfs_add_secondary_group(struct pci_epf_group * epf_group)97e85a2d78SKishon Vijay Abraham I *pci_ep_cfs_add_secondary_group(struct pci_epf_group *epf_group)
98e85a2d78SKishon Vijay Abraham I {
99e85a2d78SKishon Vijay Abraham I 	struct config_group *secondary_epc_group;
100e85a2d78SKishon Vijay Abraham I 
101e85a2d78SKishon Vijay Abraham I 	secondary_epc_group = &epf_group->secondary_epc_group;
102e85a2d78SKishon Vijay Abraham I 	config_group_init_type_name(secondary_epc_group, "secondary",
103e85a2d78SKishon Vijay Abraham I 				    &pci_secondary_epc_type);
104e85a2d78SKishon Vijay Abraham I 	configfs_register_group(&epf_group->group, secondary_epc_group);
105e85a2d78SKishon Vijay Abraham I 
106e85a2d78SKishon Vijay Abraham I 	return secondary_epc_group;
107e85a2d78SKishon Vijay Abraham I }
108e85a2d78SKishon Vijay Abraham I 
pci_primary_epc_epf_link(struct config_item * epf_item,struct config_item * epc_item)109e85a2d78SKishon Vijay Abraham I static int pci_primary_epc_epf_link(struct config_item *epf_item,
110e85a2d78SKishon Vijay Abraham I 				    struct config_item *epc_item)
111e85a2d78SKishon Vijay Abraham I {
112e85a2d78SKishon Vijay Abraham I 	int ret;
113e85a2d78SKishon Vijay Abraham I 	struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);
114e85a2d78SKishon Vijay Abraham I 	struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
115e85a2d78SKishon Vijay Abraham I 	struct pci_epc *epc = epc_group->epc;
116e85a2d78SKishon Vijay Abraham I 	struct pci_epf *epf = epf_group->epf;
117e85a2d78SKishon Vijay Abraham I 
118e85a2d78SKishon Vijay Abraham I 	ret = pci_epc_add_epf(epc, epf, PRIMARY_INTERFACE);
119e85a2d78SKishon Vijay Abraham I 	if (ret)
120e85a2d78SKishon Vijay Abraham I 		return ret;
121e85a2d78SKishon Vijay Abraham I 
122e85a2d78SKishon Vijay Abraham I 	ret = pci_epf_bind(epf);
123e85a2d78SKishon Vijay Abraham I 	if (ret) {
124e85a2d78SKishon Vijay Abraham I 		pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);
125e85a2d78SKishon Vijay Abraham I 		return ret;
126e85a2d78SKishon Vijay Abraham I 	}
127e85a2d78SKishon Vijay Abraham I 
128e85a2d78SKishon Vijay Abraham I 	return 0;
129e85a2d78SKishon Vijay Abraham I }
130e85a2d78SKishon Vijay Abraham I 
pci_primary_epc_epf_unlink(struct config_item * epc_item,struct config_item * epf_item)131e85a2d78SKishon Vijay Abraham I static void pci_primary_epc_epf_unlink(struct config_item *epc_item,
132e85a2d78SKishon Vijay Abraham I 				       struct config_item *epf_item)
133e85a2d78SKishon Vijay Abraham I {
134e85a2d78SKishon Vijay Abraham I 	struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);
135e85a2d78SKishon Vijay Abraham I 	struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
136e85a2d78SKishon Vijay Abraham I 	struct pci_epc *epc;
137e85a2d78SKishon Vijay Abraham I 	struct pci_epf *epf;
138e85a2d78SKishon Vijay Abraham I 
139e85a2d78SKishon Vijay Abraham I 	WARN_ON_ONCE(epc_group->start);
140e85a2d78SKishon Vijay Abraham I 
141e85a2d78SKishon Vijay Abraham I 	epc = epc_group->epc;
142e85a2d78SKishon Vijay Abraham I 	epf = epf_group->epf;
143e85a2d78SKishon Vijay Abraham I 	pci_epf_unbind(epf);
144e85a2d78SKishon Vijay Abraham I 	pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);
145e85a2d78SKishon Vijay Abraham I }
146e85a2d78SKishon Vijay Abraham I 
147e85a2d78SKishon Vijay Abraham I static struct configfs_item_operations pci_primary_epc_item_ops = {
148e85a2d78SKishon Vijay Abraham I 	.allow_link	= pci_primary_epc_epf_link,
149e85a2d78SKishon Vijay Abraham I 	.drop_link	= pci_primary_epc_epf_unlink,
150e85a2d78SKishon Vijay Abraham I };
151e85a2d78SKishon Vijay Abraham I 
152e85a2d78SKishon Vijay Abraham I static const struct config_item_type pci_primary_epc_type = {
153e85a2d78SKishon Vijay Abraham I 	.ct_item_ops	= &pci_primary_epc_item_ops,
154e85a2d78SKishon Vijay Abraham I 	.ct_owner	= THIS_MODULE,
155e85a2d78SKishon Vijay Abraham I };
156e85a2d78SKishon Vijay Abraham I 
157e85a2d78SKishon Vijay Abraham I static struct config_group
pci_ep_cfs_add_primary_group(struct pci_epf_group * epf_group)158e85a2d78SKishon Vijay Abraham I *pci_ep_cfs_add_primary_group(struct pci_epf_group *epf_group)
159e85a2d78SKishon Vijay Abraham I {
160e85a2d78SKishon Vijay Abraham I 	struct config_group *primary_epc_group = &epf_group->primary_epc_group;
161e85a2d78SKishon Vijay Abraham I 
162e85a2d78SKishon Vijay Abraham I 	config_group_init_type_name(primary_epc_group, "primary",
163e85a2d78SKishon Vijay Abraham I 				    &pci_primary_epc_type);
164e85a2d78SKishon Vijay Abraham I 	configfs_register_group(&epf_group->group, primary_epc_group);
165e85a2d78SKishon Vijay Abraham I 
166e85a2d78SKishon Vijay Abraham I 	return primary_epc_group;
167e85a2d78SKishon Vijay Abraham I }
168e85a2d78SKishon Vijay Abraham I 
pci_epc_start_store(struct config_item * item,const char * page,size_t len)169d7467991SKishon Vijay Abraham I static ssize_t pci_epc_start_store(struct config_item *item, const char *page,
170d7467991SKishon Vijay Abraham I 				   size_t len)
171d7467991SKishon Vijay Abraham I {
172d7467991SKishon Vijay Abraham I 	int ret;
173d7467991SKishon Vijay Abraham I 	bool start;
174d7467991SKishon Vijay Abraham I 	struct pci_epc *epc;
175d7467991SKishon Vijay Abraham I 	struct pci_epc_group *epc_group = to_pci_epc_group(item);
176d7467991SKishon Vijay Abraham I 
177d7467991SKishon Vijay Abraham I 	epc = epc_group->epc;
178d7467991SKishon Vijay Abraham I 
17936f354ecSKrzysztof Wilczyński 	if (kstrtobool(page, &start) < 0)
18036f354ecSKrzysztof Wilczyński 		return -EINVAL;
181d7467991SKishon Vijay Abraham I 
182*a504c965SManivannan Sadhasivam 	if (start == epc_group->start)
183*a504c965SManivannan Sadhasivam 		return -EALREADY;
184*a504c965SManivannan Sadhasivam 
185d7467991SKishon Vijay Abraham I 	if (!start) {
186d7467991SKishon Vijay Abraham I 		pci_epc_stop(epc);
187f58d5f53SKunihiko Hayashi 		epc_group->start = 0;
188d7467991SKishon Vijay Abraham I 		return len;
189d7467991SKishon Vijay Abraham I 	}
190d7467991SKishon Vijay Abraham I 
191d7467991SKishon Vijay Abraham I 	ret = pci_epc_start(epc);
192d7467991SKishon Vijay Abraham I 	if (ret) {
193d7467991SKishon Vijay Abraham I 		dev_err(&epc->dev, "failed to start endpoint controller\n");
194d7467991SKishon Vijay Abraham I 		return -EINVAL;
195d7467991SKishon Vijay Abraham I 	}
196d7467991SKishon Vijay Abraham I 
197d7467991SKishon Vijay Abraham I 	epc_group->start = start;
198d7467991SKishon Vijay Abraham I 
199d7467991SKishon Vijay Abraham I 	return len;
200d7467991SKishon Vijay Abraham I }
201d7467991SKishon Vijay Abraham I 
pci_epc_start_show(struct config_item * item,char * page)202d7467991SKishon Vijay Abraham I static ssize_t pci_epc_start_show(struct config_item *item, char *page)
203d7467991SKishon Vijay Abraham I {
204a2258831SKunihiko Hayashi 	return sysfs_emit(page, "%d\n", to_pci_epc_group(item)->start);
205d7467991SKishon Vijay Abraham I }
206d7467991SKishon Vijay Abraham I 
207d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epc_, start);
208d7467991SKishon Vijay Abraham I 
209d7467991SKishon Vijay Abraham I static struct configfs_attribute *pci_epc_attrs[] = {
210d7467991SKishon Vijay Abraham I 	&pci_epc_attr_start,
211d7467991SKishon Vijay Abraham I 	NULL,
212d7467991SKishon Vijay Abraham I };
213d7467991SKishon Vijay Abraham I 
pci_epc_epf_link(struct config_item * epc_item,struct config_item * epf_item)214d7467991SKishon Vijay Abraham I static int pci_epc_epf_link(struct config_item *epc_item,
215d7467991SKishon Vijay Abraham I 			    struct config_item *epf_item)
216d7467991SKishon Vijay Abraham I {
217d7467991SKishon Vijay Abraham I 	int ret;
218d7467991SKishon Vijay Abraham I 	struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);
219d7467991SKishon Vijay Abraham I 	struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
2200c47cd7aSNiklas Cassel 	struct pci_epc *epc = epc_group->epc;
2210c47cd7aSNiklas Cassel 	struct pci_epf *epf = epf_group->epf;
222d7467991SKishon Vijay Abraham I 
22363840ff5SKishon Vijay Abraham I 	ret = pci_epc_add_epf(epc, epf, PRIMARY_INTERFACE);
224d7467991SKishon Vijay Abraham I 	if (ret)
2252499ee84SKishon Vijay Abraham I 		return ret;
226d7467991SKishon Vijay Abraham I 
227d7467991SKishon Vijay Abraham I 	ret = pci_epf_bind(epf);
2282499ee84SKishon Vijay Abraham I 	if (ret) {
22963840ff5SKishon Vijay Abraham I 		pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);
2302499ee84SKishon Vijay Abraham I 		return ret;
2312499ee84SKishon Vijay Abraham I 	}
232d7467991SKishon Vijay Abraham I 
233d7467991SKishon Vijay Abraham I 	return 0;
234d7467991SKishon Vijay Abraham I }
235d7467991SKishon Vijay Abraham I 
pci_epc_epf_unlink(struct config_item * epc_item,struct config_item * epf_item)236d7467991SKishon Vijay Abraham I static void pci_epc_epf_unlink(struct config_item *epc_item,
237d7467991SKishon Vijay Abraham I 			       struct config_item *epf_item)
238d7467991SKishon Vijay Abraham I {
239d7467991SKishon Vijay Abraham I 	struct pci_epc *epc;
240d7467991SKishon Vijay Abraham I 	struct pci_epf *epf;
241d7467991SKishon Vijay Abraham I 	struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);
242d7467991SKishon Vijay Abraham I 	struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
243d7467991SKishon Vijay Abraham I 
244d7467991SKishon Vijay Abraham I 	WARN_ON_ONCE(epc_group->start);
245d7467991SKishon Vijay Abraham I 
246d7467991SKishon Vijay Abraham I 	epc = epc_group->epc;
247d7467991SKishon Vijay Abraham I 	epf = epf_group->epf;
248d7467991SKishon Vijay Abraham I 	pci_epf_unbind(epf);
24963840ff5SKishon Vijay Abraham I 	pci_epc_remove_epf(epc, epf, PRIMARY_INTERFACE);
250d7467991SKishon Vijay Abraham I }
251d7467991SKishon Vijay Abraham I 
252d7467991SKishon Vijay Abraham I static struct configfs_item_operations pci_epc_item_ops = {
253d7467991SKishon Vijay Abraham I 	.allow_link	= pci_epc_epf_link,
254d7467991SKishon Vijay Abraham I 	.drop_link	= pci_epc_epf_unlink,
255d7467991SKishon Vijay Abraham I };
256d7467991SKishon Vijay Abraham I 
2575c4e2476SBhumika Goyal static const struct config_item_type pci_epc_type = {
258d7467991SKishon Vijay Abraham I 	.ct_item_ops	= &pci_epc_item_ops,
259d7467991SKishon Vijay Abraham I 	.ct_attrs	= pci_epc_attrs,
260d7467991SKishon Vijay Abraham I 	.ct_owner	= THIS_MODULE,
261d7467991SKishon Vijay Abraham I };
262d7467991SKishon Vijay Abraham I 
pci_ep_cfs_add_epc_group(const char * name)263d7467991SKishon Vijay Abraham I struct config_group *pci_ep_cfs_add_epc_group(const char *name)
264d7467991SKishon Vijay Abraham I {
265d7467991SKishon Vijay Abraham I 	int ret;
266d7467991SKishon Vijay Abraham I 	struct pci_epc *epc;
267d7467991SKishon Vijay Abraham I 	struct config_group *group;
268d7467991SKishon Vijay Abraham I 	struct pci_epc_group *epc_group;
269d7467991SKishon Vijay Abraham I 
270d7467991SKishon Vijay Abraham I 	epc_group = kzalloc(sizeof(*epc_group), GFP_KERNEL);
271d7467991SKishon Vijay Abraham I 	if (!epc_group) {
272d7467991SKishon Vijay Abraham I 		ret = -ENOMEM;
273d7467991SKishon Vijay Abraham I 		goto err;
274d7467991SKishon Vijay Abraham I 	}
275d7467991SKishon Vijay Abraham I 
276d7467991SKishon Vijay Abraham I 	group = &epc_group->group;
277d7467991SKishon Vijay Abraham I 
278d7467991SKishon Vijay Abraham I 	config_group_init_type_name(group, name, &pci_epc_type);
279d7467991SKishon Vijay Abraham I 	ret = configfs_register_group(controllers_group, group);
280d7467991SKishon Vijay Abraham I 	if (ret) {
281d7467991SKishon Vijay Abraham I 		pr_err("failed to register configfs group for %s\n", name);
282d7467991SKishon Vijay Abraham I 		goto err_register_group;
283d7467991SKishon Vijay Abraham I 	}
284d7467991SKishon Vijay Abraham I 
285d7467991SKishon Vijay Abraham I 	epc = pci_epc_get(name);
286d7467991SKishon Vijay Abraham I 	if (IS_ERR(epc)) {
287d7467991SKishon Vijay Abraham I 		ret = PTR_ERR(epc);
288d7467991SKishon Vijay Abraham I 		goto err_epc_get;
289d7467991SKishon Vijay Abraham I 	}
290d7467991SKishon Vijay Abraham I 
291d7467991SKishon Vijay Abraham I 	epc_group->epc = epc;
292d7467991SKishon Vijay Abraham I 
293d7467991SKishon Vijay Abraham I 	return group;
294d7467991SKishon Vijay Abraham I 
295d7467991SKishon Vijay Abraham I err_epc_get:
296d7467991SKishon Vijay Abraham I 	configfs_unregister_group(group);
297d7467991SKishon Vijay Abraham I 
298d7467991SKishon Vijay Abraham I err_register_group:
299d7467991SKishon Vijay Abraham I 	kfree(epc_group);
300d7467991SKishon Vijay Abraham I 
301d7467991SKishon Vijay Abraham I err:
302d7467991SKishon Vijay Abraham I 	return ERR_PTR(ret);
303d7467991SKishon Vijay Abraham I }
304d7467991SKishon Vijay Abraham I EXPORT_SYMBOL(pci_ep_cfs_add_epc_group);
305d7467991SKishon Vijay Abraham I 
pci_ep_cfs_remove_epc_group(struct config_group * group)306d7467991SKishon Vijay Abraham I void pci_ep_cfs_remove_epc_group(struct config_group *group)
307d7467991SKishon Vijay Abraham I {
308d7467991SKishon Vijay Abraham I 	struct pci_epc_group *epc_group;
309d7467991SKishon Vijay Abraham I 
310d7467991SKishon Vijay Abraham I 	if (!group)
311d7467991SKishon Vijay Abraham I 		return;
312d7467991SKishon Vijay Abraham I 
313d7467991SKishon Vijay Abraham I 	epc_group = container_of(group, struct pci_epc_group, group);
314d7467991SKishon Vijay Abraham I 	pci_epc_put(epc_group->epc);
315d7467991SKishon Vijay Abraham I 	configfs_unregister_group(&epc_group->group);
316d7467991SKishon Vijay Abraham I 	kfree(epc_group);
317d7467991SKishon Vijay Abraham I }
318d7467991SKishon Vijay Abraham I EXPORT_SYMBOL(pci_ep_cfs_remove_epc_group);
319d7467991SKishon Vijay Abraham I 
320d7467991SKishon Vijay Abraham I #define PCI_EPF_HEADER_R(_name)						       \
321d7467991SKishon Vijay Abraham I static ssize_t pci_epf_##_name##_show(struct config_item *item,	char *page)    \
322d7467991SKishon Vijay Abraham I {									       \
323d7467991SKishon Vijay Abraham I 	struct pci_epf *epf = to_pci_epf_group(item)->epf;		       \
324d7467991SKishon Vijay Abraham I 	if (WARN_ON_ONCE(!epf->header))					       \
325d7467991SKishon Vijay Abraham I 		return -EINVAL;						       \
326a2258831SKunihiko Hayashi 	return sysfs_emit(page, "0x%04x\n", epf->header->_name);	       \
327d7467991SKishon Vijay Abraham I }
328d7467991SKishon Vijay Abraham I 
329d7467991SKishon Vijay Abraham I #define PCI_EPF_HEADER_W_u32(_name)					       \
330d7467991SKishon Vijay Abraham I static ssize_t pci_epf_##_name##_store(struct config_item *item,	       \
331d7467991SKishon Vijay Abraham I 				       const char *page, size_t len)	       \
332d7467991SKishon Vijay Abraham I {									       \
333d7467991SKishon Vijay Abraham I 	u32 val;							       \
334d7467991SKishon Vijay Abraham I 	struct pci_epf *epf = to_pci_epf_group(item)->epf;		       \
335d7467991SKishon Vijay Abraham I 	if (WARN_ON_ONCE(!epf->header))					       \
336d7467991SKishon Vijay Abraham I 		return -EINVAL;						       \
33736f354ecSKrzysztof Wilczyński 	if (kstrtou32(page, 0, &val) < 0)				       \
33836f354ecSKrzysztof Wilczyński 		return -EINVAL;						       \
339d7467991SKishon Vijay Abraham I 	epf->header->_name = val;					       \
340d7467991SKishon Vijay Abraham I 	return len;							       \
341d7467991SKishon Vijay Abraham I }
342d7467991SKishon Vijay Abraham I 
343d7467991SKishon Vijay Abraham I #define PCI_EPF_HEADER_W_u16(_name)					       \
344d7467991SKishon Vijay Abraham I static ssize_t pci_epf_##_name##_store(struct config_item *item,	       \
345d7467991SKishon Vijay Abraham I 				       const char *page, size_t len)	       \
346d7467991SKishon Vijay Abraham I {									       \
347d7467991SKishon Vijay Abraham I 	u16 val;							       \
348d7467991SKishon Vijay Abraham I 	struct pci_epf *epf = to_pci_epf_group(item)->epf;		       \
349d7467991SKishon Vijay Abraham I 	if (WARN_ON_ONCE(!epf->header))					       \
350d7467991SKishon Vijay Abraham I 		return -EINVAL;						       \
35136f354ecSKrzysztof Wilczyński 	if (kstrtou16(page, 0, &val) < 0)				       \
35236f354ecSKrzysztof Wilczyński 		return -EINVAL;						       \
353d7467991SKishon Vijay Abraham I 	epf->header->_name = val;					       \
354d7467991SKishon Vijay Abraham I 	return len;							       \
355d7467991SKishon Vijay Abraham I }
356d7467991SKishon Vijay Abraham I 
357d7467991SKishon Vijay Abraham I #define PCI_EPF_HEADER_W_u8(_name)					       \
358d7467991SKishon Vijay Abraham I static ssize_t pci_epf_##_name##_store(struct config_item *item,	       \
359d7467991SKishon Vijay Abraham I 				       const char *page, size_t len)	       \
360d7467991SKishon Vijay Abraham I {									       \
361d7467991SKishon Vijay Abraham I 	u8 val;								       \
362d7467991SKishon Vijay Abraham I 	struct pci_epf *epf = to_pci_epf_group(item)->epf;		       \
363d7467991SKishon Vijay Abraham I 	if (WARN_ON_ONCE(!epf->header))					       \
364d7467991SKishon Vijay Abraham I 		return -EINVAL;						       \
36536f354ecSKrzysztof Wilczyński 	if (kstrtou8(page, 0, &val) < 0)				       \
36636f354ecSKrzysztof Wilczyński 		return -EINVAL;						       \
367d7467991SKishon Vijay Abraham I 	epf->header->_name = val;					       \
368d7467991SKishon Vijay Abraham I 	return len;							       \
369d7467991SKishon Vijay Abraham I }
370d7467991SKishon Vijay Abraham I 
pci_epf_msi_interrupts_store(struct config_item * item,const char * page,size_t len)371d7467991SKishon Vijay Abraham I static ssize_t pci_epf_msi_interrupts_store(struct config_item *item,
372d7467991SKishon Vijay Abraham I 					    const char *page, size_t len)
373d7467991SKishon Vijay Abraham I {
374d7467991SKishon Vijay Abraham I 	u8 val;
375d7467991SKishon Vijay Abraham I 
37636f354ecSKrzysztof Wilczyński 	if (kstrtou8(page, 0, &val) < 0)
37736f354ecSKrzysztof Wilczyński 		return -EINVAL;
378d7467991SKishon Vijay Abraham I 
379d7467991SKishon Vijay Abraham I 	to_pci_epf_group(item)->epf->msi_interrupts = val;
380d7467991SKishon Vijay Abraham I 
381d7467991SKishon Vijay Abraham I 	return len;
382d7467991SKishon Vijay Abraham I }
383d7467991SKishon Vijay Abraham I 
pci_epf_msi_interrupts_show(struct config_item * item,char * page)384d7467991SKishon Vijay Abraham I static ssize_t pci_epf_msi_interrupts_show(struct config_item *item,
385d7467991SKishon Vijay Abraham I 					   char *page)
386d7467991SKishon Vijay Abraham I {
387a2258831SKunihiko Hayashi 	return sysfs_emit(page, "%d\n",
388d7467991SKishon Vijay Abraham I 			  to_pci_epf_group(item)->epf->msi_interrupts);
389d7467991SKishon Vijay Abraham I }
390d7467991SKishon Vijay Abraham I 
pci_epf_msix_interrupts_store(struct config_item * item,const char * page,size_t len)3918963106eSGustavo Pimentel static ssize_t pci_epf_msix_interrupts_store(struct config_item *item,
3928963106eSGustavo Pimentel 					     const char *page, size_t len)
3938963106eSGustavo Pimentel {
3948963106eSGustavo Pimentel 	u16 val;
3958963106eSGustavo Pimentel 
39636f354ecSKrzysztof Wilczyński 	if (kstrtou16(page, 0, &val) < 0)
39736f354ecSKrzysztof Wilczyński 		return -EINVAL;
3988963106eSGustavo Pimentel 
3998963106eSGustavo Pimentel 	to_pci_epf_group(item)->epf->msix_interrupts = val;
4008963106eSGustavo Pimentel 
4018963106eSGustavo Pimentel 	return len;
4028963106eSGustavo Pimentel }
4038963106eSGustavo Pimentel 
pci_epf_msix_interrupts_show(struct config_item * item,char * page)4048963106eSGustavo Pimentel static ssize_t pci_epf_msix_interrupts_show(struct config_item *item,
4058963106eSGustavo Pimentel 					    char *page)
4068963106eSGustavo Pimentel {
407a2258831SKunihiko Hayashi 	return sysfs_emit(page, "%d\n",
4088963106eSGustavo Pimentel 			  to_pci_epf_group(item)->epf->msix_interrupts);
4098963106eSGustavo Pimentel }
4108963106eSGustavo Pimentel 
411d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_R(vendorid)
412d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_W_u16(vendorid)
413d7467991SKishon Vijay Abraham I 
414d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_R(deviceid)
415d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_W_u16(deviceid)
416d7467991SKishon Vijay Abraham I 
417d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_R(revid)
418d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_W_u8(revid)
419d7467991SKishon Vijay Abraham I 
420d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_R(progif_code)
421d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_W_u8(progif_code)
422d7467991SKishon Vijay Abraham I 
423d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_R(subclass_code)
424d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_W_u8(subclass_code)
425d7467991SKishon Vijay Abraham I 
426d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_R(baseclass_code)
427d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_W_u8(baseclass_code)
428d7467991SKishon Vijay Abraham I 
429d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_R(cache_line_size)
430d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_W_u8(cache_line_size)
431d7467991SKishon Vijay Abraham I 
432d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_R(subsys_vendor_id)
433d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_W_u16(subsys_vendor_id)
434d7467991SKishon Vijay Abraham I 
435d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_R(subsys_id)
436d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_W_u16(subsys_id)
437d7467991SKishon Vijay Abraham I 
438d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_R(interrupt_pin)
439d7467991SKishon Vijay Abraham I PCI_EPF_HEADER_W_u8(interrupt_pin)
440d7467991SKishon Vijay Abraham I 
441d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epf_, vendorid);
442d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epf_, deviceid);
443d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epf_, revid);
444d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epf_, progif_code);
445d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epf_, subclass_code);
446d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epf_, baseclass_code);
447d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epf_, cache_line_size);
448d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epf_, subsys_vendor_id);
449d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epf_, subsys_id);
450d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epf_, interrupt_pin);
451d7467991SKishon Vijay Abraham I CONFIGFS_ATTR(pci_epf_, msi_interrupts);
4528963106eSGustavo Pimentel CONFIGFS_ATTR(pci_epf_, msix_interrupts);
453d7467991SKishon Vijay Abraham I 
454d7467991SKishon Vijay Abraham I static struct configfs_attribute *pci_epf_attrs[] = {
455d7467991SKishon Vijay Abraham I 	&pci_epf_attr_vendorid,
456d7467991SKishon Vijay Abraham I 	&pci_epf_attr_deviceid,
457d7467991SKishon Vijay Abraham I 	&pci_epf_attr_revid,
458d7467991SKishon Vijay Abraham I 	&pci_epf_attr_progif_code,
459d7467991SKishon Vijay Abraham I 	&pci_epf_attr_subclass_code,
460d7467991SKishon Vijay Abraham I 	&pci_epf_attr_baseclass_code,
461d7467991SKishon Vijay Abraham I 	&pci_epf_attr_cache_line_size,
462d7467991SKishon Vijay Abraham I 	&pci_epf_attr_subsys_vendor_id,
463d7467991SKishon Vijay Abraham I 	&pci_epf_attr_subsys_id,
464d7467991SKishon Vijay Abraham I 	&pci_epf_attr_interrupt_pin,
465d7467991SKishon Vijay Abraham I 	&pci_epf_attr_msi_interrupts,
4668963106eSGustavo Pimentel 	&pci_epf_attr_msix_interrupts,
467d7467991SKishon Vijay Abraham I 	NULL,
468d7467991SKishon Vijay Abraham I };
469d7467991SKishon Vijay Abraham I 
pci_epf_vepf_link(struct config_item * epf_pf_item,struct config_item * epf_vf_item)470101600e7SKishon Vijay Abraham I static int pci_epf_vepf_link(struct config_item *epf_pf_item,
471101600e7SKishon Vijay Abraham I 			     struct config_item *epf_vf_item)
472101600e7SKishon Vijay Abraham I {
473101600e7SKishon Vijay Abraham I 	struct pci_epf_group *epf_vf_group = to_pci_epf_group(epf_vf_item);
474101600e7SKishon Vijay Abraham I 	struct pci_epf_group *epf_pf_group = to_pci_epf_group(epf_pf_item);
475101600e7SKishon Vijay Abraham I 	struct pci_epf *epf_pf = epf_pf_group->epf;
476101600e7SKishon Vijay Abraham I 	struct pci_epf *epf_vf = epf_vf_group->epf;
477101600e7SKishon Vijay Abraham I 
478101600e7SKishon Vijay Abraham I 	return pci_epf_add_vepf(epf_pf, epf_vf);
479101600e7SKishon Vijay Abraham I }
480101600e7SKishon Vijay Abraham I 
pci_epf_vepf_unlink(struct config_item * epf_pf_item,struct config_item * epf_vf_item)481101600e7SKishon Vijay Abraham I static void pci_epf_vepf_unlink(struct config_item *epf_pf_item,
482101600e7SKishon Vijay Abraham I 				struct config_item *epf_vf_item)
483101600e7SKishon Vijay Abraham I {
484101600e7SKishon Vijay Abraham I 	struct pci_epf_group *epf_vf_group = to_pci_epf_group(epf_vf_item);
485101600e7SKishon Vijay Abraham I 	struct pci_epf_group *epf_pf_group = to_pci_epf_group(epf_pf_item);
486101600e7SKishon Vijay Abraham I 	struct pci_epf *epf_pf = epf_pf_group->epf;
487101600e7SKishon Vijay Abraham I 	struct pci_epf *epf_vf = epf_vf_group->epf;
488101600e7SKishon Vijay Abraham I 
489101600e7SKishon Vijay Abraham I 	pci_epf_remove_vepf(epf_pf, epf_vf);
490101600e7SKishon Vijay Abraham I }
491101600e7SKishon Vijay Abraham I 
pci_epf_release(struct config_item * item)492d7467991SKishon Vijay Abraham I static void pci_epf_release(struct config_item *item)
493d7467991SKishon Vijay Abraham I {
494d7467991SKishon Vijay Abraham I 	struct pci_epf_group *epf_group = to_pci_epf_group(item);
495d7467991SKishon Vijay Abraham I 
496fc41df28SCyrille Pitchen 	mutex_lock(&functions_mutex);
497fc41df28SCyrille Pitchen 	idr_remove(&functions_idr, epf_group->index);
498fc41df28SCyrille Pitchen 	mutex_unlock(&functions_mutex);
499d7467991SKishon Vijay Abraham I 	pci_epf_destroy(epf_group->epf);
500d7467991SKishon Vijay Abraham I 	kfree(epf_group);
501d7467991SKishon Vijay Abraham I }
502d7467991SKishon Vijay Abraham I 
503d7467991SKishon Vijay Abraham I static struct configfs_item_operations pci_epf_ops = {
504101600e7SKishon Vijay Abraham I 	.allow_link		= pci_epf_vepf_link,
505101600e7SKishon Vijay Abraham I 	.drop_link		= pci_epf_vepf_unlink,
506d7467991SKishon Vijay Abraham I 	.release		= pci_epf_release,
507d7467991SKishon Vijay Abraham I };
508d7467991SKishon Vijay Abraham I 
5095c4e2476SBhumika Goyal static const struct config_item_type pci_epf_type = {
510d7467991SKishon Vijay Abraham I 	.ct_item_ops	= &pci_epf_ops,
511d7467991SKishon Vijay Abraham I 	.ct_attrs	= pci_epf_attrs,
512d7467991SKishon Vijay Abraham I 	.ct_owner	= THIS_MODULE,
513d7467991SKishon Vijay Abraham I };
514d7467991SKishon Vijay Abraham I 
515f6ec3397SDamien Le Moal /**
516f6ec3397SDamien Le Moal  * pci_epf_type_add_cfs() - Help function drivers to expose function specific
517f6ec3397SDamien Le Moal  *                          attributes in configfs
518f6ec3397SDamien Le Moal  * @epf: the EPF device that has to be configured using configfs
519f6ec3397SDamien Le Moal  * @group: the parent configfs group (corresponding to entries in
520f6ec3397SDamien Le Moal  *         pci_epf_device_id)
521f6ec3397SDamien Le Moal  *
522f6ec3397SDamien Le Moal  * Invoke to expose function specific attributes in configfs.
523f6ec3397SDamien Le Moal  *
524f6ec3397SDamien Le Moal  * Return: A pointer to a config_group structure or NULL if the function driver
525f6ec3397SDamien Le Moal  * does not have anything to expose (attributes configured by user) or if
526f6ec3397SDamien Le Moal  * the function driver does not implement the add_cfs() method.
527f6ec3397SDamien Le Moal  *
528f6ec3397SDamien Le Moal  * Returns an error pointer if this function is called for an unbound EPF device
529f6ec3397SDamien Le Moal  * or if the EPF driver add_cfs() method fails.
530f6ec3397SDamien Le Moal  */
pci_epf_type_add_cfs(struct pci_epf * epf,struct config_group * group)531f6ec3397SDamien Le Moal static struct config_group *pci_epf_type_add_cfs(struct pci_epf *epf,
532f6ec3397SDamien Le Moal 						 struct config_group *group)
533f6ec3397SDamien Le Moal {
534f6ec3397SDamien Le Moal 	struct config_group *epf_type_group;
535f6ec3397SDamien Le Moal 
536f6ec3397SDamien Le Moal 	if (!epf->driver) {
537f6ec3397SDamien Le Moal 		dev_err(&epf->dev, "epf device not bound to driver\n");
538b6a6e033SDamien Le Moal 		return ERR_PTR(-ENODEV);
539f6ec3397SDamien Le Moal 	}
540f6ec3397SDamien Le Moal 
541f6ec3397SDamien Le Moal 	if (!epf->driver->ops->add_cfs)
542f6ec3397SDamien Le Moal 		return NULL;
543f6ec3397SDamien Le Moal 
544f6ec3397SDamien Le Moal 	mutex_lock(&epf->lock);
545f6ec3397SDamien Le Moal 	epf_type_group = epf->driver->ops->add_cfs(epf, group);
546f6ec3397SDamien Le Moal 	mutex_unlock(&epf->lock);
547f6ec3397SDamien Le Moal 
548f6ec3397SDamien Le Moal 	return epf_type_group;
549f6ec3397SDamien Le Moal }
550f6ec3397SDamien Le Moal 
pci_ep_cfs_add_type_group(struct pci_epf_group * epf_group)55170b3740fSDamien Le Moal static void pci_ep_cfs_add_type_group(struct pci_epf_group *epf_group)
55270b3740fSDamien Le Moal {
55370b3740fSDamien Le Moal 	struct config_group *group;
55470b3740fSDamien Le Moal 
55570b3740fSDamien Le Moal 	group = pci_epf_type_add_cfs(epf_group->epf, &epf_group->group);
55670b3740fSDamien Le Moal 	if (!group)
55770b3740fSDamien Le Moal 		return;
55870b3740fSDamien Le Moal 
55970b3740fSDamien Le Moal 	if (IS_ERR(group)) {
56070b3740fSDamien Le Moal 		dev_err(&epf_group->epf->dev,
56170b3740fSDamien Le Moal 			"failed to create epf type specific attributes\n");
56270b3740fSDamien Le Moal 		return;
56370b3740fSDamien Le Moal 	}
56470b3740fSDamien Le Moal 
56570b3740fSDamien Le Moal 	configfs_register_group(&epf_group->group, group);
56670b3740fSDamien Le Moal }
56770b3740fSDamien Le Moal 
pci_epf_cfs_work(struct work_struct * work)568e85a2d78SKishon Vijay Abraham I static void pci_epf_cfs_work(struct work_struct *work)
569e85a2d78SKishon Vijay Abraham I {
570e85a2d78SKishon Vijay Abraham I 	struct pci_epf_group *epf_group;
571e85a2d78SKishon Vijay Abraham I 	struct config_group *group;
572e85a2d78SKishon Vijay Abraham I 
573e85a2d78SKishon Vijay Abraham I 	epf_group = container_of(work, struct pci_epf_group, cfs_work.work);
574e85a2d78SKishon Vijay Abraham I 	group = pci_ep_cfs_add_primary_group(epf_group);
575e85a2d78SKishon Vijay Abraham I 	if (IS_ERR(group)) {
576e85a2d78SKishon Vijay Abraham I 		pr_err("failed to create 'primary' EPC interface\n");
577e85a2d78SKishon Vijay Abraham I 		return;
578e85a2d78SKishon Vijay Abraham I 	}
579e85a2d78SKishon Vijay Abraham I 
580e85a2d78SKishon Vijay Abraham I 	group = pci_ep_cfs_add_secondary_group(epf_group);
581e85a2d78SKishon Vijay Abraham I 	if (IS_ERR(group)) {
582e85a2d78SKishon Vijay Abraham I 		pr_err("failed to create 'secondary' EPC interface\n");
583e85a2d78SKishon Vijay Abraham I 		return;
584e85a2d78SKishon Vijay Abraham I 	}
58570b3740fSDamien Le Moal 
58670b3740fSDamien Le Moal 	pci_ep_cfs_add_type_group(epf_group);
587e85a2d78SKishon Vijay Abraham I }
588e85a2d78SKishon Vijay Abraham I 
pci_epf_make(struct config_group * group,const char * name)589d7467991SKishon Vijay Abraham I static struct config_group *pci_epf_make(struct config_group *group,
590d7467991SKishon Vijay Abraham I 					 const char *name)
591d7467991SKishon Vijay Abraham I {
592d7467991SKishon Vijay Abraham I 	struct pci_epf_group *epf_group;
593d7467991SKishon Vijay Abraham I 	struct pci_epf *epf;
594fc41df28SCyrille Pitchen 	char *epf_name;
595fc41df28SCyrille Pitchen 	int index, err;
596d7467991SKishon Vijay Abraham I 
597d7467991SKishon Vijay Abraham I 	epf_group = kzalloc(sizeof(*epf_group), GFP_KERNEL);
598d7467991SKishon Vijay Abraham I 	if (!epf_group)
599d7467991SKishon Vijay Abraham I 		return ERR_PTR(-ENOMEM);
600d7467991SKishon Vijay Abraham I 
601fc41df28SCyrille Pitchen 	mutex_lock(&functions_mutex);
602fc41df28SCyrille Pitchen 	index = idr_alloc(&functions_idr, epf_group, 0, 0, GFP_KERNEL);
603fc41df28SCyrille Pitchen 	mutex_unlock(&functions_mutex);
604fc41df28SCyrille Pitchen 	if (index < 0) {
605fc41df28SCyrille Pitchen 		err = index;
606fc41df28SCyrille Pitchen 		goto free_group;
607fc41df28SCyrille Pitchen 	}
608fc41df28SCyrille Pitchen 
609fc41df28SCyrille Pitchen 	epf_group->index = index;
610fc41df28SCyrille Pitchen 
611d7467991SKishon Vijay Abraham I 	config_group_init_type_name(&epf_group->group, name, &pci_epf_type);
612d7467991SKishon Vijay Abraham I 
613fc41df28SCyrille Pitchen 	epf_name = kasprintf(GFP_KERNEL, "%s.%d",
614fc41df28SCyrille Pitchen 			     group->cg_item.ci_name, epf_group->index);
615fc41df28SCyrille Pitchen 	if (!epf_name) {
616fc41df28SCyrille Pitchen 		err = -ENOMEM;
617fc41df28SCyrille Pitchen 		goto remove_idr;
618fc41df28SCyrille Pitchen 	}
619fc41df28SCyrille Pitchen 
620fc41df28SCyrille Pitchen 	epf = pci_epf_create(epf_name);
621d7467991SKishon Vijay Abraham I 	if (IS_ERR(epf)) {
622d7467991SKishon Vijay Abraham I 		pr_err("failed to create endpoint function device\n");
623fc41df28SCyrille Pitchen 		err = -EINVAL;
624fc41df28SCyrille Pitchen 		goto free_name;
625d7467991SKishon Vijay Abraham I 	}
626d7467991SKishon Vijay Abraham I 
62738ad827eSKishon Vijay Abraham I 	epf->group = &epf_group->group;
628d7467991SKishon Vijay Abraham I 	epf_group->epf = epf;
629d7467991SKishon Vijay Abraham I 
630fc41df28SCyrille Pitchen 	kfree(epf_name);
631fc41df28SCyrille Pitchen 
632e85a2d78SKishon Vijay Abraham I 	INIT_DELAYED_WORK(&epf_group->cfs_work, pci_epf_cfs_work);
633e85a2d78SKishon Vijay Abraham I 	queue_delayed_work(system_wq, &epf_group->cfs_work,
634e85a2d78SKishon Vijay Abraham I 			   msecs_to_jiffies(1));
635e85a2d78SKishon Vijay Abraham I 
636d7467991SKishon Vijay Abraham I 	return &epf_group->group;
637fc41df28SCyrille Pitchen 
638fc41df28SCyrille Pitchen free_name:
639fc41df28SCyrille Pitchen 	kfree(epf_name);
640fc41df28SCyrille Pitchen 
641fc41df28SCyrille Pitchen remove_idr:
642fc41df28SCyrille Pitchen 	mutex_lock(&functions_mutex);
643fc41df28SCyrille Pitchen 	idr_remove(&functions_idr, epf_group->index);
644fc41df28SCyrille Pitchen 	mutex_unlock(&functions_mutex);
645fc41df28SCyrille Pitchen 
646fc41df28SCyrille Pitchen free_group:
647fc41df28SCyrille Pitchen 	kfree(epf_group);
648fc41df28SCyrille Pitchen 
649fc41df28SCyrille Pitchen 	return ERR_PTR(err);
650d7467991SKishon Vijay Abraham I }
651d7467991SKishon Vijay Abraham I 
pci_epf_drop(struct config_group * group,struct config_item * item)652d7467991SKishon Vijay Abraham I static void pci_epf_drop(struct config_group *group, struct config_item *item)
653d7467991SKishon Vijay Abraham I {
654d7467991SKishon Vijay Abraham I 	config_item_put(item);
655d7467991SKishon Vijay Abraham I }
656d7467991SKishon Vijay Abraham I 
657d7467991SKishon Vijay Abraham I static struct configfs_group_operations pci_epf_group_ops = {
658d7467991SKishon Vijay Abraham I 	.make_group     = &pci_epf_make,
659d7467991SKishon Vijay Abraham I 	.drop_item      = &pci_epf_drop,
660d7467991SKishon Vijay Abraham I };
661d7467991SKishon Vijay Abraham I 
6625c4e2476SBhumika Goyal static const struct config_item_type pci_epf_group_type = {
663d7467991SKishon Vijay Abraham I 	.ct_group_ops	= &pci_epf_group_ops,
664d7467991SKishon Vijay Abraham I 	.ct_owner	= THIS_MODULE,
665d7467991SKishon Vijay Abraham I };
666d7467991SKishon Vijay Abraham I 
pci_ep_cfs_add_epf_group(const char * name)667d7467991SKishon Vijay Abraham I struct config_group *pci_ep_cfs_add_epf_group(const char *name)
668d7467991SKishon Vijay Abraham I {
669d7467991SKishon Vijay Abraham I 	struct config_group *group;
670d7467991SKishon Vijay Abraham I 
671d7467991SKishon Vijay Abraham I 	group = configfs_register_default_group(functions_group, name,
672d7467991SKishon Vijay Abraham I 						&pci_epf_group_type);
673d7467991SKishon Vijay Abraham I 	if (IS_ERR(group))
674d7467991SKishon Vijay Abraham I 		pr_err("failed to register configfs group for %s function\n",
675d7467991SKishon Vijay Abraham I 		       name);
676d7467991SKishon Vijay Abraham I 
677d7467991SKishon Vijay Abraham I 	return group;
678d7467991SKishon Vijay Abraham I }
679d7467991SKishon Vijay Abraham I EXPORT_SYMBOL(pci_ep_cfs_add_epf_group);
680d7467991SKishon Vijay Abraham I 
pci_ep_cfs_remove_epf_group(struct config_group * group)681d7467991SKishon Vijay Abraham I void pci_ep_cfs_remove_epf_group(struct config_group *group)
682d7467991SKishon Vijay Abraham I {
683d7467991SKishon Vijay Abraham I 	if (IS_ERR_OR_NULL(group))
684d7467991SKishon Vijay Abraham I 		return;
685d7467991SKishon Vijay Abraham I 
686d7467991SKishon Vijay Abraham I 	configfs_unregister_default_group(group);
687d7467991SKishon Vijay Abraham I }
688d7467991SKishon Vijay Abraham I EXPORT_SYMBOL(pci_ep_cfs_remove_epf_group);
689d7467991SKishon Vijay Abraham I 
6905c4e2476SBhumika Goyal static const struct config_item_type pci_functions_type = {
691d7467991SKishon Vijay Abraham I 	.ct_owner	= THIS_MODULE,
692d7467991SKishon Vijay Abraham I };
693d7467991SKishon Vijay Abraham I 
6945c4e2476SBhumika Goyal static const struct config_item_type pci_controllers_type = {
695d7467991SKishon Vijay Abraham I 	.ct_owner	= THIS_MODULE,
696d7467991SKishon Vijay Abraham I };
697d7467991SKishon Vijay Abraham I 
6985c4e2476SBhumika Goyal static const struct config_item_type pci_ep_type = {
699d7467991SKishon Vijay Abraham I 	.ct_owner	= THIS_MODULE,
700d7467991SKishon Vijay Abraham I };
701d7467991SKishon Vijay Abraham I 
702d7467991SKishon Vijay Abraham I static struct configfs_subsystem pci_ep_cfs_subsys = {
703d7467991SKishon Vijay Abraham I 	.su_group = {
704d7467991SKishon Vijay Abraham I 		.cg_item = {
705d7467991SKishon Vijay Abraham I 			.ci_namebuf = "pci_ep",
706d7467991SKishon Vijay Abraham I 			.ci_type = &pci_ep_type,
707d7467991SKishon Vijay Abraham I 		},
708d7467991SKishon Vijay Abraham I 	},
709d7467991SKishon Vijay Abraham I 	.su_mutex = __MUTEX_INITIALIZER(pci_ep_cfs_subsys.su_mutex),
710d7467991SKishon Vijay Abraham I };
711d7467991SKishon Vijay Abraham I 
pci_ep_cfs_init(void)712d7467991SKishon Vijay Abraham I static int __init pci_ep_cfs_init(void)
713d7467991SKishon Vijay Abraham I {
714d7467991SKishon Vijay Abraham I 	int ret;
715d7467991SKishon Vijay Abraham I 	struct config_group *root = &pci_ep_cfs_subsys.su_group;
716d7467991SKishon Vijay Abraham I 
717d7467991SKishon Vijay Abraham I 	config_group_init(root);
718d7467991SKishon Vijay Abraham I 
719d7467991SKishon Vijay Abraham I 	ret = configfs_register_subsystem(&pci_ep_cfs_subsys);
720d7467991SKishon Vijay Abraham I 	if (ret) {
721d7467991SKishon Vijay Abraham I 		pr_err("Error %d while registering subsystem %s\n",
722d7467991SKishon Vijay Abraham I 		       ret, root->cg_item.ci_namebuf);
723d7467991SKishon Vijay Abraham I 		goto err;
724d7467991SKishon Vijay Abraham I 	}
725d7467991SKishon Vijay Abraham I 
726d7467991SKishon Vijay Abraham I 	functions_group = configfs_register_default_group(root, "functions",
727d7467991SKishon Vijay Abraham I 							  &pci_functions_type);
728d7467991SKishon Vijay Abraham I 	if (IS_ERR(functions_group)) {
729d7467991SKishon Vijay Abraham I 		ret = PTR_ERR(functions_group);
730d7467991SKishon Vijay Abraham I 		pr_err("Error %d while registering functions group\n",
731d7467991SKishon Vijay Abraham I 		       ret);
732d7467991SKishon Vijay Abraham I 		goto err_functions_group;
733d7467991SKishon Vijay Abraham I 	}
734d7467991SKishon Vijay Abraham I 
735d7467991SKishon Vijay Abraham I 	controllers_group =
736d7467991SKishon Vijay Abraham I 		configfs_register_default_group(root, "controllers",
737d7467991SKishon Vijay Abraham I 						&pci_controllers_type);
738d7467991SKishon Vijay Abraham I 	if (IS_ERR(controllers_group)) {
739d7467991SKishon Vijay Abraham I 		ret = PTR_ERR(controllers_group);
740d7467991SKishon Vijay Abraham I 		pr_err("Error %d while registering controllers group\n",
741d7467991SKishon Vijay Abraham I 		       ret);
742d7467991SKishon Vijay Abraham I 		goto err_controllers_group;
743d7467991SKishon Vijay Abraham I 	}
744d7467991SKishon Vijay Abraham I 
745d7467991SKishon Vijay Abraham I 	return 0;
746d7467991SKishon Vijay Abraham I 
747d7467991SKishon Vijay Abraham I err_controllers_group:
748d7467991SKishon Vijay Abraham I 	configfs_unregister_default_group(functions_group);
749d7467991SKishon Vijay Abraham I 
750d7467991SKishon Vijay Abraham I err_functions_group:
751d7467991SKishon Vijay Abraham I 	configfs_unregister_subsystem(&pci_ep_cfs_subsys);
752d7467991SKishon Vijay Abraham I 
753d7467991SKishon Vijay Abraham I err:
754d7467991SKishon Vijay Abraham I 	return ret;
755d7467991SKishon Vijay Abraham I }
756d7467991SKishon Vijay Abraham I module_init(pci_ep_cfs_init);
757d7467991SKishon Vijay Abraham I 
pci_ep_cfs_exit(void)758d7467991SKishon Vijay Abraham I static void __exit pci_ep_cfs_exit(void)
759d7467991SKishon Vijay Abraham I {
760d7467991SKishon Vijay Abraham I 	configfs_unregister_default_group(controllers_group);
761d7467991SKishon Vijay Abraham I 	configfs_unregister_default_group(functions_group);
762d7467991SKishon Vijay Abraham I 	configfs_unregister_subsystem(&pci_ep_cfs_subsys);
763d7467991SKishon Vijay Abraham I }
764d7467991SKishon Vijay Abraham I module_exit(pci_ep_cfs_exit);
765d7467991SKishon Vijay Abraham I 
766d7467991SKishon Vijay Abraham I MODULE_DESCRIPTION("PCI EP CONFIGFS");
767d7467991SKishon Vijay Abraham I MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
768