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/sched.h> /* for capable() */ 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 38 static ssize_t routes_show(struct device *dev, struct device_attribute *attr, char *buf) 39 { 40 struct rio_dev *rdev = to_rio_dev(dev); 41 char *str = buf; 42 int i; 43 44 if (!rdev->rswitch) 45 goto out; 46 47 for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; 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 out: 56 return (str - buf); 57 } 58 59 struct device_attribute rio_dev_attrs[] = { 60 __ATTR_RO(did), 61 __ATTR_RO(vid), 62 __ATTR_RO(device_rev), 63 __ATTR_RO(asm_did), 64 __ATTR_RO(asm_vid), 65 __ATTR_RO(asm_rev), 66 __ATTR_RO(routes), 67 __ATTR_NULL, 68 }; 69 70 static ssize_t 71 rio_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) 72 { 73 struct rio_dev *dev = 74 to_rio_dev(container_of(kobj, struct device, kobj)); 75 unsigned int size = 0x100; 76 loff_t init_off = off; 77 u8 *data = (u8 *) buf; 78 79 /* Several chips lock up trying to read undefined config space */ 80 if (capable(CAP_SYS_ADMIN)) 81 size = 0x200000; 82 83 if (off > size) 84 return 0; 85 if (off + count > size) { 86 size -= off; 87 count = size; 88 } else { 89 size = count; 90 } 91 92 if ((off & 1) && size) { 93 u8 val; 94 rio_read_config_8(dev, off, &val); 95 data[off - init_off] = val; 96 off++; 97 size--; 98 } 99 100 if ((off & 3) && size > 2) { 101 u16 val; 102 rio_read_config_16(dev, off, &val); 103 data[off - init_off] = (val >> 8) & 0xff; 104 data[off - init_off + 1] = val & 0xff; 105 off += 2; 106 size -= 2; 107 } 108 109 while (size > 3) { 110 u32 val; 111 rio_read_config_32(dev, off, &val); 112 data[off - init_off] = (val >> 24) & 0xff; 113 data[off - init_off + 1] = (val >> 16) & 0xff; 114 data[off - init_off + 2] = (val >> 8) & 0xff; 115 data[off - init_off + 3] = val & 0xff; 116 off += 4; 117 size -= 4; 118 } 119 120 if (size >= 2) { 121 u16 val; 122 rio_read_config_16(dev, off, &val); 123 data[off - init_off] = (val >> 8) & 0xff; 124 data[off - init_off + 1] = val & 0xff; 125 off += 2; 126 size -= 2; 127 } 128 129 if (size > 0) { 130 u8 val; 131 rio_read_config_8(dev, off, &val); 132 data[off - init_off] = val; 133 off++; 134 --size; 135 } 136 137 return count; 138 } 139 140 static ssize_t 141 rio_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) 142 { 143 struct rio_dev *dev = 144 to_rio_dev(container_of(kobj, struct device, kobj)); 145 unsigned int size = count; 146 loff_t init_off = off; 147 u8 *data = (u8 *) buf; 148 149 if (off > 0x200000) 150 return 0; 151 if (off + count > 0x200000) { 152 size = 0x200000 - off; 153 count = size; 154 } 155 156 if ((off & 1) && size) { 157 rio_write_config_8(dev, off, data[off - init_off]); 158 off++; 159 size--; 160 } 161 162 if ((off & 3) && (size > 2)) { 163 u16 val = data[off - init_off + 1]; 164 val |= (u16) data[off - init_off] << 8; 165 rio_write_config_16(dev, off, val); 166 off += 2; 167 size -= 2; 168 } 169 170 while (size > 3) { 171 u32 val = data[off - init_off + 3]; 172 val |= (u32) data[off - init_off + 2] << 8; 173 val |= (u32) data[off - init_off + 1] << 16; 174 val |= (u32) data[off - init_off] << 24; 175 rio_write_config_32(dev, off, val); 176 off += 4; 177 size -= 4; 178 } 179 180 if (size >= 2) { 181 u16 val = data[off - init_off + 1]; 182 val |= (u16) data[off - init_off] << 8; 183 rio_write_config_16(dev, off, val); 184 off += 2; 185 size -= 2; 186 } 187 188 if (size) { 189 rio_write_config_8(dev, off, data[off - init_off]); 190 off++; 191 --size; 192 } 193 194 return count; 195 } 196 197 static struct bin_attribute rio_config_attr = { 198 .attr = { 199 .name = "config", 200 .mode = S_IRUGO | S_IWUSR, 201 .owner = THIS_MODULE, 202 }, 203 .size = 0x200000, 204 .read = rio_read_config, 205 .write = rio_write_config, 206 }; 207 208 /** 209 * rio_create_sysfs_dev_files - create RIO specific sysfs files 210 * @rdev: device whose entries should be created 211 * 212 * Create files when @rdev is added to sysfs. 213 */ 214 int rio_create_sysfs_dev_files(struct rio_dev *rdev) 215 { 216 sysfs_create_bin_file(&rdev->dev.kobj, &rio_config_attr); 217 218 return 0; 219 } 220 221 /** 222 * rio_remove_sysfs_dev_files - cleanup RIO specific sysfs files 223 * @rdev: device whose entries we should free 224 * 225 * Cleanup when @rdev is removed from sysfs. 226 */ 227 void rio_remove_sysfs_dev_files(struct rio_dev *rdev) 228 { 229 sysfs_remove_bin_file(&rdev->dev.kobj, &rio_config_attr); 230 } 231