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