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