linux/drivers/rapidio/rio-sysfs.c
<<
>>
Prefs
   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)                                   \
  23static ssize_t                                                          \
  24field##_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}                                                                       \
  30static DEVICE_ATTR_RO(field);
  31
  32rio_config_attr(did, "0x%04x\n");
  33rio_config_attr(vid, "0x%04x\n");
  34rio_config_attr(device_rev, "0x%08x\n");
  35rio_config_attr(asm_did, "0x%04x\n");
  36rio_config_attr(asm_vid, "0x%04x\n");
  37rio_config_attr(asm_rev, "0x%04x\n");
  38rio_config_attr(destid, "0x%04x\n");
  39rio_config_attr(hopcount, "0x%02x\n");
  40
  41static ssize_t routes_show(struct device *dev, struct device_attribute *attr, char *buf)
  42{
  43        struct rio_dev *rdev = to_rio_dev(dev);
  44        char *str = buf;
  45        int i;
  46
  47        for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
  48                        i++) {
  49                if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE)
  50                        continue;
  51                str +=
  52                    sprintf(str, "%04x %02x\n", i,
  53                            rdev->rswitch->route_table[i]);
  54        }
  55
  56        return (str - buf);
  57}
  58static DEVICE_ATTR_RO(routes);
  59
  60static ssize_t lprev_show(struct device *dev,
  61                          struct device_attribute *attr, char *buf)
  62{
  63        struct rio_dev *rdev = to_rio_dev(dev);
  64
  65        return sprintf(buf, "%s\n",
  66                        (rdev->prev) ? rio_name(rdev->prev) : "root");
  67}
  68static DEVICE_ATTR_RO(lprev);
  69
  70static ssize_t lnext_show(struct device *dev,
  71                          struct device_attribute *attr, char *buf)
  72{
  73        struct rio_dev *rdev = to_rio_dev(dev);
  74        char *str = buf;
  75        int i;
  76
  77        if (rdev->pef & RIO_PEF_SWITCH) {
  78                for (i = 0; i < RIO_GET_TOTAL_PORTS(rdev->swpinfo); i++) {
  79                        if (rdev->rswitch->nextdev[i])
  80                                str += sprintf(str, "%s\n",
  81                                        rio_name(rdev->rswitch->nextdev[i]));
  82                        else
  83                                str += sprintf(str, "null\n");
  84                }
  85        }
  86
  87        return str - buf;
  88}
  89static DEVICE_ATTR_RO(lnext);
  90
  91static ssize_t modalias_show(struct device *dev,
  92                             struct device_attribute *attr, char *buf)
  93{
  94        struct rio_dev *rdev = to_rio_dev(dev);
  95
  96        return sprintf(buf, "rapidio:v%04Xd%04Xav%04Xad%04X\n",
  97                       rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did);
  98}
  99static DEVICE_ATTR_RO(modalias);
 100
 101static struct attribute *rio_dev_attrs[] = {
 102        &dev_attr_did.attr,
 103        &dev_attr_vid.attr,
 104        &dev_attr_device_rev.attr,
 105        &dev_attr_asm_did.attr,
 106        &dev_attr_asm_vid.attr,
 107        &dev_attr_asm_rev.attr,
 108        &dev_attr_lprev.attr,
 109        &dev_attr_destid.attr,
 110        &dev_attr_modalias.attr,
 111        NULL,
 112};
 113
 114static const struct attribute_group rio_dev_group = {
 115        .attrs = rio_dev_attrs,
 116};
 117
 118const struct attribute_group *rio_dev_groups[] = {
 119        &rio_dev_group,
 120        NULL,
 121};
 122
 123static ssize_t
 124rio_read_config(struct file *filp, struct kobject *kobj,
 125                struct bin_attribute *bin_attr,
 126                char *buf, loff_t off, size_t count)
 127{
 128        struct rio_dev *dev = to_rio_dev(kobj_to_dev(kobj));
 129        unsigned int size = 0x100;
 130        loff_t init_off = off;
 131        u8 *data = (u8 *) buf;
 132
 133        /* Several chips lock up trying to read undefined config space */
 134        if (capable(CAP_SYS_ADMIN))
 135                size = RIO_MAINT_SPACE_SZ;
 136
 137        if (off >= size)
 138                return 0;
 139        if (off + count > size) {
 140                size -= off;
 141                count = size;
 142        } else {
 143                size = count;
 144        }
 145
 146        if ((off & 1) && size) {
 147                u8 val;
 148                rio_read_config_8(dev, off, &val);
 149                data[off - init_off] = val;
 150                off++;
 151                size--;
 152        }
 153
 154        if ((off & 3) && size > 2) {
 155                u16 val;
 156                rio_read_config_16(dev, off, &val);
 157                data[off - init_off] = (val >> 8) & 0xff;
 158                data[off - init_off + 1] = val & 0xff;
 159                off += 2;
 160                size -= 2;
 161        }
 162
 163        while (size > 3) {
 164                u32 val;
 165                rio_read_config_32(dev, off, &val);
 166                data[off - init_off] = (val >> 24) & 0xff;
 167                data[off - init_off + 1] = (val >> 16) & 0xff;
 168                data[off - init_off + 2] = (val >> 8) & 0xff;
 169                data[off - init_off + 3] = val & 0xff;
 170                off += 4;
 171                size -= 4;
 172        }
 173
 174        if (size >= 2) {
 175                u16 val;
 176                rio_read_config_16(dev, off, &val);
 177                data[off - init_off] = (val >> 8) & 0xff;
 178                data[off - init_off + 1] = val & 0xff;
 179                off += 2;
 180                size -= 2;
 181        }
 182
 183        if (size > 0) {
 184                u8 val;
 185                rio_read_config_8(dev, off, &val);
 186                data[off - init_off] = val;
 187                off++;
 188                --size;
 189        }
 190
 191        return count;
 192}
 193
 194static ssize_t
 195rio_write_config(struct file *filp, struct kobject *kobj,
 196                 struct bin_attribute *bin_attr,
 197                 char *buf, loff_t off, size_t count)
 198{
 199        struct rio_dev *dev = to_rio_dev(kobj_to_dev(kobj));
 200        unsigned int size = count;
 201        loff_t init_off = off;
 202        u8 *data = (u8 *) buf;
 203
 204        if (off >= RIO_MAINT_SPACE_SZ)
 205                return 0;
 206        if (off + count > RIO_MAINT_SPACE_SZ) {
 207                size = RIO_MAINT_SPACE_SZ - off;
 208                count = size;
 209        }
 210
 211        if ((off & 1) && size) {
 212                rio_write_config_8(dev, off, data[off - init_off]);
 213                off++;
 214                size--;
 215        }
 216
 217        if ((off & 3) && (size > 2)) {
 218                u16 val = data[off - init_off + 1];
 219                val |= (u16) data[off - init_off] << 8;
 220                rio_write_config_16(dev, off, val);
 221                off += 2;
 222                size -= 2;
 223        }
 224
 225        while (size > 3) {
 226                u32 val = data[off - init_off + 3];
 227                val |= (u32) data[off - init_off + 2] << 8;
 228                val |= (u32) data[off - init_off + 1] << 16;
 229                val |= (u32) data[off - init_off] << 24;
 230                rio_write_config_32(dev, off, val);
 231                off += 4;
 232                size -= 4;
 233        }
 234
 235        if (size >= 2) {
 236                u16 val = data[off - init_off + 1];
 237                val |= (u16) data[off - init_off] << 8;
 238                rio_write_config_16(dev, off, val);
 239                off += 2;
 240                size -= 2;
 241        }
 242
 243        if (size) {
 244                rio_write_config_8(dev, off, data[off - init_off]);
 245                off++;
 246                --size;
 247        }
 248
 249        return count;
 250}
 251
 252static struct bin_attribute rio_config_attr = {
 253        .attr = {
 254                 .name = "config",
 255                 .mode = S_IRUGO | S_IWUSR,
 256                 },
 257        .size = RIO_MAINT_SPACE_SZ,
 258        .read = rio_read_config,
 259        .write = rio_write_config,
 260};
 261
 262/**
 263 * rio_create_sysfs_dev_files - create RIO specific sysfs files
 264 * @rdev: device whose entries should be created
 265 *
 266 * Create files when @rdev is added to sysfs.
 267 */
 268int rio_create_sysfs_dev_files(struct rio_dev *rdev)
 269{
 270        int err = 0;
 271
 272        err = device_create_bin_file(&rdev->dev, &rio_config_attr);
 273
 274        if (!err && (rdev->pef & RIO_PEF_SWITCH)) {
 275                err |= device_create_file(&rdev->dev, &dev_attr_routes);
 276                err |= device_create_file(&rdev->dev, &dev_attr_lnext);
 277                err |= device_create_file(&rdev->dev, &dev_attr_hopcount);
 278        }
 279
 280        if (err)
 281                pr_warning("RIO: Failed to create attribute file(s) for %s\n",
 282                           rio_name(rdev));
 283
 284        return err;
 285}
 286
 287/**
 288 * rio_remove_sysfs_dev_files - cleanup RIO specific sysfs files
 289 * @rdev: device whose entries we should free
 290 *
 291 * Cleanup when @rdev is removed from sysfs.
 292 */
 293void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
 294{
 295        device_remove_bin_file(&rdev->dev, &rio_config_attr);
 296        if (rdev->pef & RIO_PEF_SWITCH) {
 297                device_remove_file(&rdev->dev, &dev_attr_routes);
 298                device_remove_file(&rdev->dev, &dev_attr_lnext);
 299                device_remove_file(&rdev->dev, &dev_attr_hopcount);
 300        }
 301}
 302
 303static ssize_t bus_scan_store(struct bus_type *bus, const char *buf,
 304                                size_t count)
 305{
 306        long val;
 307        int rc;
 308
 309        if (kstrtol(buf, 0, &val) < 0)
 310                return -EINVAL;
 311
 312        if (val == RIO_MPORT_ANY) {
 313                rc = rio_init_mports();
 314                goto exit;
 315        }
 316
 317        if (val < 0 || val >= RIO_MAX_MPORTS)
 318                return -EINVAL;
 319
 320        rc = rio_mport_scan((int)val);
 321exit:
 322        if (!rc)
 323                rc = count;
 324
 325        return rc;
 326}
 327static BUS_ATTR(scan, (S_IWUSR|S_IWGRP), NULL, bus_scan_store);
 328
 329static struct attribute *rio_bus_attrs[] = {
 330        &bus_attr_scan.attr,
 331        NULL,
 332};
 333
 334static const struct attribute_group rio_bus_group = {
 335        .attrs = rio_bus_attrs,
 336};
 337
 338const struct attribute_group *rio_bus_groups[] = {
 339        &rio_bus_group,
 340        NULL,
 341};
 342
 343static ssize_t
 344port_destid_show(struct device *dev, struct device_attribute *attr,
 345                 char *buf)
 346{
 347        struct rio_mport *mport = to_rio_mport(dev);
 348
 349        if (mport)
 350                return sprintf(buf, "0x%04x\n", mport->host_deviceid);
 351        else
 352                return -ENODEV;
 353}
 354static DEVICE_ATTR_RO(port_destid);
 355
 356static ssize_t sys_size_show(struct device *dev, struct device_attribute *attr,
 357                           char *buf)
 358{
 359        struct rio_mport *mport = to_rio_mport(dev);
 360
 361        if (mport)
 362                return sprintf(buf, "%u\n", mport->sys_size);
 363        else
 364                return -ENODEV;
 365}
 366static DEVICE_ATTR_RO(sys_size);
 367
 368static struct attribute *rio_mport_attrs[] = {
 369        &dev_attr_port_destid.attr,
 370        &dev_attr_sys_size.attr,
 371        NULL,
 372};
 373
 374static const struct attribute_group rio_mport_group = {
 375        .attrs = rio_mport_attrs,
 376};
 377
 378const struct attribute_group *rio_mport_groups[] = {
 379        &rio_mport_group,
 380        NULL,
 381};
 382