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