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