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