1 /* 2 * RapidIO sysfs attributes and support 3 * 4 * Copyright 2005 MontaVista Software, Inc. 5 * Matt Porter <mporter@kernel.crashing.org> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2 of the License, or (at your 10 * option) any later version. 11 */ 12 13 #include <linux/kernel.h> 14 #include <linux/rio.h> 15 #include <linux/rio_drv.h> 16 #include <linux/stat.h> 17 #include <linux/capability.h> 18 19 #include "rio.h" 20 21 /* Sysfs support */ 22 #define rio_config_attr(field, format_string) \ 23 static ssize_t \ 24 field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ 25 { \ 26 struct rio_dev *rdev = to_rio_dev(dev); \ 27 \ 28 return sprintf(buf, format_string, rdev->field); \ 29 } \ 30 31 rio_config_attr(did, "0x%04x\n"); 32 rio_config_attr(vid, "0x%04x\n"); 33 rio_config_attr(device_rev, "0x%08x\n"); 34 rio_config_attr(asm_did, "0x%04x\n"); 35 rio_config_attr(asm_vid, "0x%04x\n"); 36 rio_config_attr(asm_rev, "0x%04x\n"); 37 rio_config_attr(destid, "0x%04x\n"); 38 rio_config_attr(hopcount, "0x%02x\n"); 39 40 static ssize_t routes_show(struct device *dev, struct device_attribute *attr, char *buf) 41 { 42 struct rio_dev *rdev = to_rio_dev(dev); 43 char *str = buf; 44 int i; 45 46 for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); 47 i++) { 48 if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE) 49 continue; 50 str += 51 sprintf(str, "%04x %02x\n", i, 52 rdev->rswitch->route_table[i]); 53 } 54 55 return (str - buf); 56 } 57 58 static ssize_t lprev_show(struct device *dev, 59 struct device_attribute *attr, char *buf) 60 { 61 struct rio_dev *rdev = to_rio_dev(dev); 62 63 return sprintf(buf, "%s\n", 64 (rdev->prev) ? rio_name(rdev->prev) : "root"); 65 } 66 67 static ssize_t lnext_show(struct device *dev, 68 struct device_attribute *attr, char *buf) 69 { 70 struct rio_dev *rdev = to_rio_dev(dev); 71 char *str = buf; 72 int i; 73 74 if (rdev->pef & RIO_PEF_SWITCH) { 75 for (i = 0; i < RIO_GET_TOTAL_PORTS(rdev->swpinfo); i++) { 76 if (rdev->rswitch->nextdev[i]) 77 str += sprintf(str, "%s\n", 78 rio_name(rdev->rswitch->nextdev[i])); 79 else 80 str += sprintf(str, "null\n"); 81 } 82 } 83 84 return str - buf; 85 } 86 87 struct device_attribute rio_dev_attrs[] = { 88 __ATTR_RO(did), 89 __ATTR_RO(vid), 90 __ATTR_RO(device_rev), 91 __ATTR_RO(asm_did), 92 __ATTR_RO(asm_vid), 93 __ATTR_RO(asm_rev), 94 __ATTR_RO(lprev), 95 __ATTR_RO(destid), 96 __ATTR_NULL, 97 }; 98 99 static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL); 100 static DEVICE_ATTR(lnext, S_IRUGO, lnext_show, NULL); 101 static DEVICE_ATTR(hopcount, S_IRUGO, hopcount_show, NULL); 102 103 static ssize_t 104 rio_read_config(struct file *filp, struct kobject *kobj, 105 struct bin_attribute *bin_attr, 106 char *buf, loff_t off, size_t count) 107 { 108 struct rio_dev *dev = 109 to_rio_dev(container_of(kobj, struct device, kobj)); 110 unsigned int size = 0x100; 111 loff_t init_off = off; 112 u8 *data = (u8 *) buf; 113 114 /* Several chips lock up trying to read undefined config space */ 115 if (capable(CAP_SYS_ADMIN)) 116 size = RIO_MAINT_SPACE_SZ; 117 118 if (off >= size) 119 return 0; 120 if (off + count > size) { 121 size -= off; 122 count = size; 123 } else { 124 size = count; 125 } 126 127 if ((off & 1) && size) { 128 u8 val; 129 rio_read_config_8(dev, off, &val); 130 data[off - init_off] = val; 131 off++; 132 size--; 133 } 134 135 if ((off & 3) && size > 2) { 136 u16 val; 137 rio_read_config_16(dev, off, &val); 138 data[off - init_off] = (val >> 8) & 0xff; 139 data[off - init_off + 1] = val & 0xff; 140 off += 2; 141 size -= 2; 142 } 143 144 while (size > 3) { 145 u32 val; 146 rio_read_config_32(dev, off, &val); 147 data[off - init_off] = (val >> 24) & 0xff; 148 data[off - init_off + 1] = (val >> 16) & 0xff; 149 data[off - init_off + 2] = (val >> 8) & 0xff; 150 data[off - init_off + 3] = val & 0xff; 151 off += 4; 152 size -= 4; 153 } 154 155 if (size >= 2) { 156 u16 val; 157 rio_read_config_16(dev, off, &val); 158 data[off - init_off] = (val >> 8) & 0xff; 159 data[off - init_off + 1] = val & 0xff; 160 off += 2; 161 size -= 2; 162 } 163 164 if (size > 0) { 165 u8 val; 166 rio_read_config_8(dev, off, &val); 167 data[off - init_off] = val; 168 off++; 169 --size; 170 } 171 172 return count; 173 } 174 175 static ssize_t 176 rio_write_config(struct file *filp, struct kobject *kobj, 177 struct bin_attribute *bin_attr, 178 char *buf, loff_t off, size_t count) 179 { 180 struct rio_dev *dev = 181 to_rio_dev(container_of(kobj, struct device, kobj)); 182 unsigned int size = count; 183 loff_t init_off = off; 184 u8 *data = (u8 *) buf; 185 186 if (off >= RIO_MAINT_SPACE_SZ) 187 return 0; 188 if (off + count > RIO_MAINT_SPACE_SZ) { 189 size = RIO_MAINT_SPACE_SZ - off; 190 count = size; 191 } 192 193 if ((off & 1) && size) { 194 rio_write_config_8(dev, off, data[off - init_off]); 195 off++; 196 size--; 197 } 198 199 if ((off & 3) && (size > 2)) { 200 u16 val = data[off - init_off + 1]; 201 val |= (u16) data[off - init_off] << 8; 202 rio_write_config_16(dev, off, val); 203 off += 2; 204 size -= 2; 205 } 206 207 while (size > 3) { 208 u32 val = data[off - init_off + 3]; 209 val |= (u32) data[off - init_off + 2] << 8; 210 val |= (u32) data[off - init_off + 1] << 16; 211 val |= (u32) data[off - init_off] << 24; 212 rio_write_config_32(dev, off, val); 213 off += 4; 214 size -= 4; 215 } 216 217 if (size >= 2) { 218 u16 val = data[off - init_off + 1]; 219 val |= (u16) data[off - init_off] << 8; 220 rio_write_config_16(dev, off, val); 221 off += 2; 222 size -= 2; 223 } 224 225 if (size) { 226 rio_write_config_8(dev, off, data[off - init_off]); 227 off++; 228 --size; 229 } 230 231 return count; 232 } 233 234 static struct bin_attribute rio_config_attr = { 235 .attr = { 236 .name = "config", 237 .mode = S_IRUGO | S_IWUSR, 238 }, 239 .size = RIO_MAINT_SPACE_SZ, 240 .read = rio_read_config, 241 .write = rio_write_config, 242 }; 243 244 /** 245 * rio_create_sysfs_dev_files - create RIO specific sysfs files 246 * @rdev: device whose entries should be created 247 * 248 * Create files when @rdev is added to sysfs. 249 */ 250 int rio_create_sysfs_dev_files(struct rio_dev *rdev) 251 { 252 int err = 0; 253 254 err = device_create_bin_file(&rdev->dev, &rio_config_attr); 255 256 if (!err && (rdev->pef & RIO_PEF_SWITCH)) { 257 err |= device_create_file(&rdev->dev, &dev_attr_routes); 258 err |= device_create_file(&rdev->dev, &dev_attr_lnext); 259 err |= device_create_file(&rdev->dev, &dev_attr_hopcount); 260 if (!err && rdev->rswitch->sw_sysfs) 261 err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE); 262 } 263 264 if (err) 265 pr_warning("RIO: Failed to create attribute file(s) for %s\n", 266 rio_name(rdev)); 267 268 return err; 269 } 270 271 /** 272 * rio_remove_sysfs_dev_files - cleanup RIO specific sysfs files 273 * @rdev: device whose entries we should free 274 * 275 * Cleanup when @rdev is removed from sysfs. 276 */ 277 void rio_remove_sysfs_dev_files(struct rio_dev *rdev) 278 { 279 device_remove_bin_file(&rdev->dev, &rio_config_attr); 280 if (rdev->pef & RIO_PEF_SWITCH) { 281 device_remove_file(&rdev->dev, &dev_attr_routes); 282 device_remove_file(&rdev->dev, &dev_attr_lnext); 283 device_remove_file(&rdev->dev, &dev_attr_hopcount); 284 if (rdev->rswitch->sw_sysfs) 285 rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE); 286 } 287 } 288