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 static ssize_t modalias_show(struct device *dev, 88 struct device_attribute *attr, char *buf) 89 { 90 struct rio_dev *rdev = to_rio_dev(dev); 91 92 return sprintf(buf, "rapidio:v%04Xd%04Xav%04Xad%04X\n", 93 rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did); 94 } 95 96 struct device_attribute rio_dev_attrs[] = { 97 __ATTR_RO(did), 98 __ATTR_RO(vid), 99 __ATTR_RO(device_rev), 100 __ATTR_RO(asm_did), 101 __ATTR_RO(asm_vid), 102 __ATTR_RO(asm_rev), 103 __ATTR_RO(lprev), 104 __ATTR_RO(destid), 105 __ATTR_RO(modalias), 106 __ATTR_NULL, 107 }; 108 109 static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL); 110 static DEVICE_ATTR(lnext, S_IRUGO, lnext_show, NULL); 111 static DEVICE_ATTR(hopcount, S_IRUGO, hopcount_show, NULL); 112 113 static ssize_t 114 rio_read_config(struct file *filp, struct kobject *kobj, 115 struct bin_attribute *bin_attr, 116 char *buf, loff_t off, size_t count) 117 { 118 struct rio_dev *dev = 119 to_rio_dev(container_of(kobj, struct device, kobj)); 120 unsigned int size = 0x100; 121 loff_t init_off = off; 122 u8 *data = (u8 *) buf; 123 124 /* Several chips lock up trying to read undefined config space */ 125 if (capable(CAP_SYS_ADMIN)) 126 size = RIO_MAINT_SPACE_SZ; 127 128 if (off >= size) 129 return 0; 130 if (off + count > size) { 131 size -= off; 132 count = size; 133 } else { 134 size = count; 135 } 136 137 if ((off & 1) && size) { 138 u8 val; 139 rio_read_config_8(dev, off, &val); 140 data[off - init_off] = val; 141 off++; 142 size--; 143 } 144 145 if ((off & 3) && size > 2) { 146 u16 val; 147 rio_read_config_16(dev, off, &val); 148 data[off - init_off] = (val >> 8) & 0xff; 149 data[off - init_off + 1] = val & 0xff; 150 off += 2; 151 size -= 2; 152 } 153 154 while (size > 3) { 155 u32 val; 156 rio_read_config_32(dev, off, &val); 157 data[off - init_off] = (val >> 24) & 0xff; 158 data[off - init_off + 1] = (val >> 16) & 0xff; 159 data[off - init_off + 2] = (val >> 8) & 0xff; 160 data[off - init_off + 3] = val & 0xff; 161 off += 4; 162 size -= 4; 163 } 164 165 if (size >= 2) { 166 u16 val; 167 rio_read_config_16(dev, off, &val); 168 data[off - init_off] = (val >> 8) & 0xff; 169 data[off - init_off + 1] = val & 0xff; 170 off += 2; 171 size -= 2; 172 } 173 174 if (size > 0) { 175 u8 val; 176 rio_read_config_8(dev, off, &val); 177 data[off - init_off] = val; 178 off++; 179 --size; 180 } 181 182 return count; 183 } 184 185 static ssize_t 186 rio_write_config(struct file *filp, struct kobject *kobj, 187 struct bin_attribute *bin_attr, 188 char *buf, loff_t off, size_t count) 189 { 190 struct rio_dev *dev = 191 to_rio_dev(container_of(kobj, struct device, kobj)); 192 unsigned int size = count; 193 loff_t init_off = off; 194 u8 *data = (u8 *) buf; 195 196 if (off >= RIO_MAINT_SPACE_SZ) 197 return 0; 198 if (off + count > RIO_MAINT_SPACE_SZ) { 199 size = RIO_MAINT_SPACE_SZ - off; 200 count = size; 201 } 202 203 if ((off & 1) && size) { 204 rio_write_config_8(dev, off, data[off - init_off]); 205 off++; 206 size--; 207 } 208 209 if ((off & 3) && (size > 2)) { 210 u16 val = data[off - init_off + 1]; 211 val |= (u16) data[off - init_off] << 8; 212 rio_write_config_16(dev, off, val); 213 off += 2; 214 size -= 2; 215 } 216 217 while (size > 3) { 218 u32 val = data[off - init_off + 3]; 219 val |= (u32) data[off - init_off + 2] << 8; 220 val |= (u32) data[off - init_off + 1] << 16; 221 val |= (u32) data[off - init_off] << 24; 222 rio_write_config_32(dev, off, val); 223 off += 4; 224 size -= 4; 225 } 226 227 if (size >= 2) { 228 u16 val = data[off - init_off + 1]; 229 val |= (u16) data[off - init_off] << 8; 230 rio_write_config_16(dev, off, val); 231 off += 2; 232 size -= 2; 233 } 234 235 if (size) { 236 rio_write_config_8(dev, off, data[off - init_off]); 237 off++; 238 --size; 239 } 240 241 return count; 242 } 243 244 static struct bin_attribute rio_config_attr = { 245 .attr = { 246 .name = "config", 247 .mode = S_IRUGO | S_IWUSR, 248 }, 249 .size = RIO_MAINT_SPACE_SZ, 250 .read = rio_read_config, 251 .write = rio_write_config, 252 }; 253 254 /** 255 * rio_create_sysfs_dev_files - create RIO specific sysfs files 256 * @rdev: device whose entries should be created 257 * 258 * Create files when @rdev is added to sysfs. 259 */ 260 int rio_create_sysfs_dev_files(struct rio_dev *rdev) 261 { 262 int err = 0; 263 264 err = device_create_bin_file(&rdev->dev, &rio_config_attr); 265 266 if (!err && (rdev->pef & RIO_PEF_SWITCH)) { 267 err |= device_create_file(&rdev->dev, &dev_attr_routes); 268 err |= device_create_file(&rdev->dev, &dev_attr_lnext); 269 err |= device_create_file(&rdev->dev, &dev_attr_hopcount); 270 } 271 272 if (err) 273 pr_warning("RIO: Failed to create attribute file(s) for %s\n", 274 rio_name(rdev)); 275 276 return err; 277 } 278 279 /** 280 * rio_remove_sysfs_dev_files - cleanup RIO specific sysfs files 281 * @rdev: device whose entries we should free 282 * 283 * Cleanup when @rdev is removed from sysfs. 284 */ 285 void rio_remove_sysfs_dev_files(struct rio_dev *rdev) 286 { 287 device_remove_bin_file(&rdev->dev, &rio_config_attr); 288 if (rdev->pef & RIO_PEF_SWITCH) { 289 device_remove_file(&rdev->dev, &dev_attr_routes); 290 device_remove_file(&rdev->dev, &dev_attr_lnext); 291 device_remove_file(&rdev->dev, &dev_attr_hopcount); 292 } 293 } 294 295 static ssize_t bus_scan_store(struct bus_type *bus, const char *buf, 296 size_t count) 297 { 298 long val; 299 int rc; 300 301 if (kstrtol(buf, 0, &val) < 0) 302 return -EINVAL; 303 304 if (val == RIO_MPORT_ANY) { 305 rc = rio_init_mports(); 306 goto exit; 307 } 308 309 if (val < 0 || val >= RIO_MAX_MPORTS) 310 return -EINVAL; 311 312 rc = rio_mport_scan((int)val); 313 exit: 314 if (!rc) 315 rc = count; 316 317 return rc; 318 } 319 320 struct bus_attribute rio_bus_attrs[] = { 321 __ATTR(scan, (S_IWUSR|S_IWGRP), NULL, bus_scan_store), 322 __ATTR_NULL 323 }; 324