xref: /OK3568_Linux_fs/kernel/drivers/rapidio/rio-sysfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * RapidIO sysfs attributes and support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2005 MontaVista Software, Inc.
6*4882a593Smuzhiyun  * Matt Porter <mporter@kernel.crashing.org>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/rio.h>
11*4882a593Smuzhiyun #include <linux/rio_drv.h>
12*4882a593Smuzhiyun #include <linux/stat.h>
13*4882a593Smuzhiyun #include <linux/capability.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "rio.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun /* Sysfs support */
18*4882a593Smuzhiyun #define rio_config_attr(field, format_string)					\
19*4882a593Smuzhiyun static ssize_t								\
20*4882a593Smuzhiyun field##_show(struct device *dev, struct device_attribute *attr, char *buf)			\
21*4882a593Smuzhiyun {									\
22*4882a593Smuzhiyun 	struct rio_dev *rdev = to_rio_dev(dev);				\
23*4882a593Smuzhiyun 									\
24*4882a593Smuzhiyun 	return sprintf(buf, format_string, rdev->field);		\
25*4882a593Smuzhiyun }									\
26*4882a593Smuzhiyun static DEVICE_ATTR_RO(field);
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun rio_config_attr(did, "0x%04x\n");
29*4882a593Smuzhiyun rio_config_attr(vid, "0x%04x\n");
30*4882a593Smuzhiyun rio_config_attr(device_rev, "0x%08x\n");
31*4882a593Smuzhiyun rio_config_attr(asm_did, "0x%04x\n");
32*4882a593Smuzhiyun rio_config_attr(asm_vid, "0x%04x\n");
33*4882a593Smuzhiyun rio_config_attr(asm_rev, "0x%04x\n");
34*4882a593Smuzhiyun rio_config_attr(destid, "0x%04x\n");
35*4882a593Smuzhiyun rio_config_attr(hopcount, "0x%02x\n");
36*4882a593Smuzhiyun 
routes_show(struct device * dev,struct device_attribute * attr,char * buf)37*4882a593Smuzhiyun static ssize_t routes_show(struct device *dev, struct device_attribute *attr, char *buf)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	struct rio_dev *rdev = to_rio_dev(dev);
40*4882a593Smuzhiyun 	char *str = buf;
41*4882a593Smuzhiyun 	int i;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
44*4882a593Smuzhiyun 			i++) {
45*4882a593Smuzhiyun 		if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE)
46*4882a593Smuzhiyun 			continue;
47*4882a593Smuzhiyun 		str +=
48*4882a593Smuzhiyun 		    sprintf(str, "%04x %02x\n", i,
49*4882a593Smuzhiyun 			    rdev->rswitch->route_table[i]);
50*4882a593Smuzhiyun 	}
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	return (str - buf);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun static DEVICE_ATTR_RO(routes);
55*4882a593Smuzhiyun 
lprev_show(struct device * dev,struct device_attribute * attr,char * buf)56*4882a593Smuzhiyun static ssize_t lprev_show(struct device *dev,
57*4882a593Smuzhiyun 			  struct device_attribute *attr, char *buf)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	struct rio_dev *rdev = to_rio_dev(dev);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	return sprintf(buf, "%s\n",
62*4882a593Smuzhiyun 			(rdev->prev) ? rio_name(rdev->prev) : "root");
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun static DEVICE_ATTR_RO(lprev);
65*4882a593Smuzhiyun 
lnext_show(struct device * dev,struct device_attribute * attr,char * buf)66*4882a593Smuzhiyun static ssize_t lnext_show(struct device *dev,
67*4882a593Smuzhiyun 			  struct device_attribute *attr, char *buf)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	struct rio_dev *rdev = to_rio_dev(dev);
70*4882a593Smuzhiyun 	char *str = buf;
71*4882a593Smuzhiyun 	int i;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	if (rdev->pef & RIO_PEF_SWITCH) {
74*4882a593Smuzhiyun 		for (i = 0; i < RIO_GET_TOTAL_PORTS(rdev->swpinfo); i++) {
75*4882a593Smuzhiyun 			if (rdev->rswitch->nextdev[i])
76*4882a593Smuzhiyun 				str += sprintf(str, "%s\n",
77*4882a593Smuzhiyun 					rio_name(rdev->rswitch->nextdev[i]));
78*4882a593Smuzhiyun 			else
79*4882a593Smuzhiyun 				str += sprintf(str, "null\n");
80*4882a593Smuzhiyun 		}
81*4882a593Smuzhiyun 	}
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	return str - buf;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun static DEVICE_ATTR_RO(lnext);
86*4882a593Smuzhiyun 
modalias_show(struct device * dev,struct device_attribute * attr,char * buf)87*4882a593Smuzhiyun static ssize_t modalias_show(struct device *dev,
88*4882a593Smuzhiyun 			     struct device_attribute *attr, char *buf)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	struct rio_dev *rdev = to_rio_dev(dev);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	return sprintf(buf, "rapidio:v%04Xd%04Xav%04Xad%04X\n",
93*4882a593Smuzhiyun 		       rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun static DEVICE_ATTR_RO(modalias);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun static struct attribute *rio_dev_attrs[] = {
98*4882a593Smuzhiyun 	&dev_attr_did.attr,
99*4882a593Smuzhiyun 	&dev_attr_vid.attr,
100*4882a593Smuzhiyun 	&dev_attr_device_rev.attr,
101*4882a593Smuzhiyun 	&dev_attr_asm_did.attr,
102*4882a593Smuzhiyun 	&dev_attr_asm_vid.attr,
103*4882a593Smuzhiyun 	&dev_attr_asm_rev.attr,
104*4882a593Smuzhiyun 	&dev_attr_lprev.attr,
105*4882a593Smuzhiyun 	&dev_attr_destid.attr,
106*4882a593Smuzhiyun 	&dev_attr_modalias.attr,
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	/* Switch-only attributes */
109*4882a593Smuzhiyun 	&dev_attr_routes.attr,
110*4882a593Smuzhiyun 	&dev_attr_lnext.attr,
111*4882a593Smuzhiyun 	&dev_attr_hopcount.attr,
112*4882a593Smuzhiyun 	NULL,
113*4882a593Smuzhiyun };
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun static ssize_t
rio_read_config(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)116*4882a593Smuzhiyun rio_read_config(struct file *filp, struct kobject *kobj,
117*4882a593Smuzhiyun 		struct bin_attribute *bin_attr,
118*4882a593Smuzhiyun 		char *buf, loff_t off, size_t count)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	struct rio_dev *dev = to_rio_dev(kobj_to_dev(kobj));
121*4882a593Smuzhiyun 	unsigned int size = 0x100;
122*4882a593Smuzhiyun 	loff_t init_off = off;
123*4882a593Smuzhiyun 	u8 *data = (u8 *) buf;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	/* Several chips lock up trying to read undefined config space */
126*4882a593Smuzhiyun 	if (capable(CAP_SYS_ADMIN))
127*4882a593Smuzhiyun 		size = RIO_MAINT_SPACE_SZ;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	if (off >= size)
130*4882a593Smuzhiyun 		return 0;
131*4882a593Smuzhiyun 	if (off + count > size) {
132*4882a593Smuzhiyun 		size -= off;
133*4882a593Smuzhiyun 		count = size;
134*4882a593Smuzhiyun 	} else {
135*4882a593Smuzhiyun 		size = count;
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	if ((off & 1) && size) {
139*4882a593Smuzhiyun 		u8 val;
140*4882a593Smuzhiyun 		rio_read_config_8(dev, off, &val);
141*4882a593Smuzhiyun 		data[off - init_off] = val;
142*4882a593Smuzhiyun 		off++;
143*4882a593Smuzhiyun 		size--;
144*4882a593Smuzhiyun 	}
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	if ((off & 3) && size > 2) {
147*4882a593Smuzhiyun 		u16 val;
148*4882a593Smuzhiyun 		rio_read_config_16(dev, off, &val);
149*4882a593Smuzhiyun 		data[off - init_off] = (val >> 8) & 0xff;
150*4882a593Smuzhiyun 		data[off - init_off + 1] = val & 0xff;
151*4882a593Smuzhiyun 		off += 2;
152*4882a593Smuzhiyun 		size -= 2;
153*4882a593Smuzhiyun 	}
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	while (size > 3) {
156*4882a593Smuzhiyun 		u32 val;
157*4882a593Smuzhiyun 		rio_read_config_32(dev, off, &val);
158*4882a593Smuzhiyun 		data[off - init_off] = (val >> 24) & 0xff;
159*4882a593Smuzhiyun 		data[off - init_off + 1] = (val >> 16) & 0xff;
160*4882a593Smuzhiyun 		data[off - init_off + 2] = (val >> 8) & 0xff;
161*4882a593Smuzhiyun 		data[off - init_off + 3] = val & 0xff;
162*4882a593Smuzhiyun 		off += 4;
163*4882a593Smuzhiyun 		size -= 4;
164*4882a593Smuzhiyun 	}
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	if (size >= 2) {
167*4882a593Smuzhiyun 		u16 val;
168*4882a593Smuzhiyun 		rio_read_config_16(dev, off, &val);
169*4882a593Smuzhiyun 		data[off - init_off] = (val >> 8) & 0xff;
170*4882a593Smuzhiyun 		data[off - init_off + 1] = val & 0xff;
171*4882a593Smuzhiyun 		off += 2;
172*4882a593Smuzhiyun 		size -= 2;
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (size > 0) {
176*4882a593Smuzhiyun 		u8 val;
177*4882a593Smuzhiyun 		rio_read_config_8(dev, off, &val);
178*4882a593Smuzhiyun 		data[off - init_off] = val;
179*4882a593Smuzhiyun 		off++;
180*4882a593Smuzhiyun 		--size;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	return count;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun static ssize_t
rio_write_config(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)187*4882a593Smuzhiyun rio_write_config(struct file *filp, struct kobject *kobj,
188*4882a593Smuzhiyun 		 struct bin_attribute *bin_attr,
189*4882a593Smuzhiyun 		 char *buf, loff_t off, size_t count)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	struct rio_dev *dev = to_rio_dev(kobj_to_dev(kobj));
192*4882a593Smuzhiyun 	unsigned int size = count;
193*4882a593Smuzhiyun 	loff_t init_off = off;
194*4882a593Smuzhiyun 	u8 *data = (u8 *) buf;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (off >= RIO_MAINT_SPACE_SZ)
197*4882a593Smuzhiyun 		return 0;
198*4882a593Smuzhiyun 	if (off + count > RIO_MAINT_SPACE_SZ) {
199*4882a593Smuzhiyun 		size = RIO_MAINT_SPACE_SZ - off;
200*4882a593Smuzhiyun 		count = size;
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if ((off & 1) && size) {
204*4882a593Smuzhiyun 		rio_write_config_8(dev, off, data[off - init_off]);
205*4882a593Smuzhiyun 		off++;
206*4882a593Smuzhiyun 		size--;
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	if ((off & 3) && (size > 2)) {
210*4882a593Smuzhiyun 		u16 val = data[off - init_off + 1];
211*4882a593Smuzhiyun 		val |= (u16) data[off - init_off] << 8;
212*4882a593Smuzhiyun 		rio_write_config_16(dev, off, val);
213*4882a593Smuzhiyun 		off += 2;
214*4882a593Smuzhiyun 		size -= 2;
215*4882a593Smuzhiyun 	}
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	while (size > 3) {
218*4882a593Smuzhiyun 		u32 val = data[off - init_off + 3];
219*4882a593Smuzhiyun 		val |= (u32) data[off - init_off + 2] << 8;
220*4882a593Smuzhiyun 		val |= (u32) data[off - init_off + 1] << 16;
221*4882a593Smuzhiyun 		val |= (u32) data[off - init_off] << 24;
222*4882a593Smuzhiyun 		rio_write_config_32(dev, off, val);
223*4882a593Smuzhiyun 		off += 4;
224*4882a593Smuzhiyun 		size -= 4;
225*4882a593Smuzhiyun 	}
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	if (size >= 2) {
228*4882a593Smuzhiyun 		u16 val = data[off - init_off + 1];
229*4882a593Smuzhiyun 		val |= (u16) data[off - init_off] << 8;
230*4882a593Smuzhiyun 		rio_write_config_16(dev, off, val);
231*4882a593Smuzhiyun 		off += 2;
232*4882a593Smuzhiyun 		size -= 2;
233*4882a593Smuzhiyun 	}
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	if (size) {
236*4882a593Smuzhiyun 		rio_write_config_8(dev, off, data[off - init_off]);
237*4882a593Smuzhiyun 		off++;
238*4882a593Smuzhiyun 		--size;
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	return count;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun static struct bin_attribute rio_config_attr = {
245*4882a593Smuzhiyun 	.attr = {
246*4882a593Smuzhiyun 		 .name = "config",
247*4882a593Smuzhiyun 		 .mode = S_IRUGO | S_IWUSR,
248*4882a593Smuzhiyun 		 },
249*4882a593Smuzhiyun 	.size = RIO_MAINT_SPACE_SZ,
250*4882a593Smuzhiyun 	.read = rio_read_config,
251*4882a593Smuzhiyun 	.write = rio_write_config,
252*4882a593Smuzhiyun };
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun static struct bin_attribute *rio_dev_bin_attrs[] = {
255*4882a593Smuzhiyun 	&rio_config_attr,
256*4882a593Smuzhiyun 	NULL,
257*4882a593Smuzhiyun };
258*4882a593Smuzhiyun 
rio_dev_is_attr_visible(struct kobject * kobj,struct attribute * attr,int n)259*4882a593Smuzhiyun static umode_t rio_dev_is_attr_visible(struct kobject *kobj,
260*4882a593Smuzhiyun 				       struct attribute *attr, int n)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	struct rio_dev *rdev = to_rio_dev(kobj_to_dev(kobj));
263*4882a593Smuzhiyun 	umode_t mode = attr->mode;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	if (!(rdev->pef & RIO_PEF_SWITCH) &&
266*4882a593Smuzhiyun 	    (attr == &dev_attr_routes.attr ||
267*4882a593Smuzhiyun 	     attr == &dev_attr_lnext.attr ||
268*4882a593Smuzhiyun 	     attr == &dev_attr_hopcount.attr)) {
269*4882a593Smuzhiyun 		/*
270*4882a593Smuzhiyun 		 * Hide switch-specific attributes for a non-switch device.
271*4882a593Smuzhiyun 		 */
272*4882a593Smuzhiyun 		mode = 0;
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	return mode;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun static const struct attribute_group rio_dev_group = {
279*4882a593Smuzhiyun 	.attrs		= rio_dev_attrs,
280*4882a593Smuzhiyun 	.is_visible	= rio_dev_is_attr_visible,
281*4882a593Smuzhiyun 	.bin_attrs	= rio_dev_bin_attrs,
282*4882a593Smuzhiyun };
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun const struct attribute_group *rio_dev_groups[] = {
285*4882a593Smuzhiyun 	&rio_dev_group,
286*4882a593Smuzhiyun 	NULL,
287*4882a593Smuzhiyun };
288*4882a593Smuzhiyun 
scan_store(struct bus_type * bus,const char * buf,size_t count)289*4882a593Smuzhiyun static ssize_t scan_store(struct bus_type *bus, const char *buf, size_t count)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	long val;
292*4882a593Smuzhiyun 	int rc;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	if (kstrtol(buf, 0, &val) < 0)
295*4882a593Smuzhiyun 		return -EINVAL;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	if (val == RIO_MPORT_ANY) {
298*4882a593Smuzhiyun 		rc = rio_init_mports();
299*4882a593Smuzhiyun 		goto exit;
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	if (val < 0 || val >= RIO_MAX_MPORTS)
303*4882a593Smuzhiyun 		return -EINVAL;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	rc = rio_mport_scan((int)val);
306*4882a593Smuzhiyun exit:
307*4882a593Smuzhiyun 	if (!rc)
308*4882a593Smuzhiyun 		rc = count;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	return rc;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun static BUS_ATTR_WO(scan);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun static struct attribute *rio_bus_attrs[] = {
315*4882a593Smuzhiyun 	&bus_attr_scan.attr,
316*4882a593Smuzhiyun 	NULL,
317*4882a593Smuzhiyun };
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun static const struct attribute_group rio_bus_group = {
320*4882a593Smuzhiyun 	.attrs = rio_bus_attrs,
321*4882a593Smuzhiyun };
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun const struct attribute_group *rio_bus_groups[] = {
324*4882a593Smuzhiyun 	&rio_bus_group,
325*4882a593Smuzhiyun 	NULL,
326*4882a593Smuzhiyun };
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun static ssize_t
port_destid_show(struct device * dev,struct device_attribute * attr,char * buf)329*4882a593Smuzhiyun port_destid_show(struct device *dev, struct device_attribute *attr,
330*4882a593Smuzhiyun 		 char *buf)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	struct rio_mport *mport = to_rio_mport(dev);
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	if (mport)
335*4882a593Smuzhiyun 		return sprintf(buf, "0x%04x\n", mport->host_deviceid);
336*4882a593Smuzhiyun 	else
337*4882a593Smuzhiyun 		return -ENODEV;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun static DEVICE_ATTR_RO(port_destid);
340*4882a593Smuzhiyun 
sys_size_show(struct device * dev,struct device_attribute * attr,char * buf)341*4882a593Smuzhiyun static ssize_t sys_size_show(struct device *dev, struct device_attribute *attr,
342*4882a593Smuzhiyun 			   char *buf)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	struct rio_mport *mport = to_rio_mport(dev);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	if (mport)
347*4882a593Smuzhiyun 		return sprintf(buf, "%u\n", mport->sys_size);
348*4882a593Smuzhiyun 	else
349*4882a593Smuzhiyun 		return -ENODEV;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun static DEVICE_ATTR_RO(sys_size);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun static struct attribute *rio_mport_attrs[] = {
354*4882a593Smuzhiyun 	&dev_attr_port_destid.attr,
355*4882a593Smuzhiyun 	&dev_attr_sys_size.attr,
356*4882a593Smuzhiyun 	NULL,
357*4882a593Smuzhiyun };
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun static const struct attribute_group rio_mport_group = {
360*4882a593Smuzhiyun 	.attrs = rio_mport_attrs,
361*4882a593Smuzhiyun };
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun const struct attribute_group *rio_mport_groups[] = {
364*4882a593Smuzhiyun 	&rio_mport_group,
365*4882a593Smuzhiyun 	NULL,
366*4882a593Smuzhiyun };
367