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