linux/drivers/misc/xilinx-ai-engine/ai-engine-sysfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Xilinx AI Engine device driver.
   4 *
   5 * Copyright (C) 2021 Xilinx, Inc.
   6 */
   7#include "ai-engine-internal.h"
   8
   9/**
  10 * aie_sysfs_read_handler() - sysfs binary attribute read handler.
  11 * @filp: file pointer.
  12 * @kobj: pointer to the kobject.
  13 * @attr: sysfs binary attribute.
  14 * @buf: buffer to copy the data to.
  15 * @offset: offset into the sysfs file.
  16 * @max_size: maximum length of data that could be copied to buf.
  17 * @return: length of data actually copied to buf.
  18 */
  19ssize_t aie_sysfs_read_handler(struct file *filp, struct kobject *kobj,
  20                               struct bin_attribute *attr, char *buf,
  21                               loff_t offset, size_t max_size)
  22{
  23        ssize_t len = max_size;
  24        struct aie_sysfs_prop *prop;
  25
  26        prop = attr->private;
  27        if (!prop->data)
  28                return 0;
  29
  30        if (!offset)
  31                prop->size = prop->read_callback(kobj, prop->data,
  32                                                 prop->max_size);
  33
  34        if (offset >= prop->size)
  35                return 0;
  36
  37        if (offset + max_size > prop->size)
  38                len = prop->size - offset;
  39
  40        memcpy(buf,  prop->data + offset, len);
  41        return len;
  42}
  43
  44/**
  45 * aie_sysfs_create_dev_attr() - dynamically allocates and initialize a device
  46 *                               attribute
  47 * @dev: device to allocate attribute for.
  48 * @attr: AI engine device attribute.
  49 * @return: pointer to the allocated device attribute.
  50 */
  51static struct device_attribute *
  52aie_sysfs_create_dev_attr(struct device *dev, const struct aie_dev_attr *attr)
  53{
  54        struct device_attribute *node;
  55
  56        node = devm_kzalloc(dev, sizeof(struct device_attribute), GFP_KERNEL);
  57        if (!node)
  58                return ERR_PTR(-ENOMEM);
  59
  60        sysfs_attr_init(node);
  61
  62        node->attr.name = attr->name;
  63        node->attr.mode = attr->mode;
  64        node->show = attr->show;
  65        return node;
  66}
  67
  68/**
  69 * aie_sysfs_create_bin_attr() - dynamically allocates and initialize a binary
  70 *                               attribute
  71 * @dev: device to allocate attribute for.
  72 * @attr: AI engine binary attribute.
  73 * @return: pointer to the allocated binary attribute.
  74 */
  75static struct bin_attribute *
  76aie_sysfs_create_bin_attr(struct device *dev, const struct aie_bin_attr *attr)
  77{
  78        struct bin_attribute *node;
  79        struct aie_sysfs_prop *prop;
  80
  81        node = devm_kzalloc(dev, sizeof(struct bin_attribute), GFP_KERNEL);
  82        if (!node)
  83                return ERR_PTR(-ENOMEM);
  84
  85        sysfs_bin_attr_init(node);
  86
  87        node->attr.name = attr->name;
  88        node->attr.mode = attr->mode;
  89        node->size = attr->size;
  90        node->read = attr->read;
  91
  92        prop = devm_kzalloc(dev, sizeof(struct aie_sysfs_prop), GFP_KERNEL);
  93        if (!prop)
  94                return ERR_PTR(-ENOMEM);
  95
  96        prop->data = devm_kzalloc(dev, node->size, GFP_KERNEL);
  97        if (!prop->data)
  98                return ERR_PTR(-ENOMEM);
  99
 100        prop->max_size = node->size;
 101        prop->read_callback = attr->read_callback;
 102        node->private = prop;
 103        return node;
 104}
 105
 106/**
 107 * aie_tile_sysfs_create() - creates sysfs nodes at the tile level.
 108 * @atile: AI engine tile.
 109 * @return: 0 for success, error code for failure.
 110 */
 111static int aie_tile_sysfs_create(struct aie_tile *atile)
 112{
 113        struct attribute_group *attr_grp;
 114        struct bin_attribute **bin_attrs;
 115        struct attribute **dev_attrs;
 116        const struct aie_sysfs_attr *attr;
 117        int ret = 0;
 118        u32 ttype;
 119        u32 index, i = 0, j = 0;
 120
 121        attr = atile->apart->adev->tile_sysfs_attr;
 122        ttype = atile->apart->adev->ops->get_tile_type(&atile->loc);
 123
 124        if (attr->num_dev_attrs) {
 125                dev_attrs = devm_kzalloc(&atile->dev, sizeof(*dev_attrs) *
 126                                         (attr->num_dev_attrs + 1), GFP_KERNEL);
 127                if (!dev_attrs)
 128                        return -ENOMEM;
 129
 130                for (index = 0; index < attr->num_dev_attrs; index++) {
 131                        struct device_attribute *node;
 132                        const struct aie_dev_attr *dev_attr;
 133
 134                        dev_attr = &attr->dev_attr[index];
 135
 136                        if (!(BIT(ttype) & attr->dev_attr[index].tile_type))
 137                                continue;
 138
 139                        node = aie_sysfs_create_dev_attr(&atile->dev, dev_attr);
 140                        if (IS_ERR_VALUE(node))
 141                                return PTR_ERR(node);
 142
 143                        dev_attrs[i++] = &node->attr;
 144                }
 145        }
 146
 147        if (attr->num_bin_attrs) {
 148                bin_attrs = devm_kzalloc(&atile->dev, sizeof(*bin_attrs) *
 149                                         (attr->num_bin_attrs + 1), GFP_KERNEL);
 150                if (!bin_attrs)
 151                        return -ENOMEM;
 152
 153                for (index = 0; index < attr->num_bin_attrs; index++) {
 154                        struct bin_attribute *node;
 155                        const struct aie_bin_attr *bin_attr;
 156
 157                        bin_attr = &attr->bin_attr[index];
 158
 159                        if (!(BIT(ttype) & attr->bin_attr[index].tile_type))
 160                                continue;
 161
 162                        node = aie_sysfs_create_bin_attr(&atile->dev, bin_attr);
 163                        if (IS_ERR_VALUE(node))
 164                                return PTR_ERR(node);
 165
 166                        bin_attrs[j++] = node;
 167                }
 168        }
 169
 170        if (attr->num_dev_attrs || attr->num_bin_attrs) {
 171                attr_grp = devm_kzalloc(&atile->dev,
 172                                        sizeof(struct attribute_group),
 173                                        GFP_KERNEL);
 174                if (!attr_grp)
 175                        return -ENOMEM;
 176
 177                if (attr->num_dev_attrs)
 178                        attr_grp->attrs = dev_attrs;
 179
 180                if (attr->num_bin_attrs)
 181                        attr_grp->bin_attrs = bin_attrs;
 182
 183                ret = devm_device_add_group(&atile->dev, attr_grp);
 184                if (ret) {
 185                        dev_err(&atile->dev,
 186                                "Failed to add sysfs attributes group\n");
 187                }
 188        }
 189        return ret;
 190}
 191
 192/**
 193 * aie_part_sysfs_create() - creates sysfs nodes at the partition level.
 194 * @apart: AI engine partition.
 195 * @return: 0 for success, error code for failure.
 196 */
 197static int aie_part_sysfs_create(struct aie_partition *apart)
 198{
 199        const struct aie_sysfs_attr *attr;
 200        struct attribute_group *attr_grp;
 201        struct bin_attribute **bin_attrs;
 202        struct attribute **dev_attrs;
 203        int ret = 0;
 204        u32 index;
 205
 206        attr = apart->adev->part_sysfs_attr;
 207
 208        if (attr->num_dev_attrs) {
 209                dev_attrs = devm_kzalloc(&apart->dev, sizeof(*dev_attrs) *
 210                                         (attr->num_dev_attrs + 1), GFP_KERNEL);
 211                if (!dev_attrs)
 212                        return -ENOMEM;
 213
 214                for (index = 0; index < attr->num_dev_attrs; index++) {
 215                        struct device_attribute *node;
 216                        const struct aie_dev_attr *dev_attr;
 217
 218                        dev_attr = &attr->dev_attr[index];
 219
 220                        node = aie_sysfs_create_dev_attr(&apart->dev, dev_attr);
 221                        if (IS_ERR_VALUE(node))
 222                                return PTR_ERR(node);
 223
 224                        dev_attrs[index] = &node->attr;
 225                }
 226        }
 227
 228        if (attr->num_bin_attrs) {
 229                bin_attrs = devm_kzalloc(&apart->dev, sizeof(*bin_attrs) *
 230                                         (attr->num_bin_attrs + 1), GFP_KERNEL);
 231                if (!bin_attrs)
 232                        return -ENOMEM;
 233
 234                for (index = 0; index < attr->num_bin_attrs; index++) {
 235                        struct bin_attribute *node;
 236                        const struct aie_bin_attr *bin_attr;
 237
 238                        bin_attr = &attr->bin_attr[index];
 239
 240                        node = aie_sysfs_create_bin_attr(&apart->dev, bin_attr);
 241                        if (IS_ERR_VALUE(node))
 242                                return PTR_ERR(node);
 243
 244                        bin_attrs[index] = node;
 245                }
 246        }
 247
 248        if (attr->num_dev_attrs || attr->num_bin_attrs) {
 249                attr_grp = devm_kzalloc(&apart->dev,
 250                                        sizeof(struct attribute_group),
 251                                        GFP_KERNEL);
 252                if (!attr_grp)
 253                        return -ENOMEM;
 254
 255                if (attr->num_dev_attrs)
 256                        attr_grp->attrs = dev_attrs;
 257
 258                if (attr->num_bin_attrs)
 259                        attr_grp->bin_attrs = bin_attrs;
 260
 261                ret = devm_device_add_group(&apart->dev, attr_grp);
 262                if (ret) {
 263                        dev_err(&apart->dev,
 264                                "Failed to add sysfs attributes group\n");
 265                }
 266        }
 267        return ret;
 268}
 269
 270/**
 271 * aie_part_sysfs_init() - initializes sysfs interface by creating node at tile
 272 *                         and partition granularity.
 273 * @apart: AI engine partition.
 274 * @return: 0 for success, error code for failure.
 275 */
 276int aie_part_sysfs_init(struct aie_partition *apart)
 277{
 278        struct aie_tile *atile = apart->atiles;
 279        u32 index;
 280        int ret;
 281
 282        ret = aie_part_sysfs_create(apart);
 283        if (ret < 0) {
 284                dev_err(&apart->dev,
 285                        "Failed to create partition level sysfs nodes\n");
 286                return ret;
 287        }
 288
 289        for (index = 0; index < apart->range.size.col * apart->range.size.row;
 290             index++) {
 291                ret = aie_tile_sysfs_create(atile);
 292                if (ret < 0) {
 293                        dev_err(&atile->dev,
 294                                "Failed to create tile level sysfs nodes\n");
 295                        return ret;
 296                }
 297                atile++;
 298        }
 299        return ret;
 300}
 301