X-Git-Url: http://git.monstr.eu/?a=blobdiff_plain;f=drivers%2Finfiniband%2Fcore%2Fsysfs.c;h=d2a089a6f66639f74ce35f02682ea470167b6a24;hb=a32f433522c97d2f07c060517f1f0f4058aa211b;hp=b8abb30f80df5d0806fe8ca6f8deba3d99ae8a76;hpb=5e6b211136a86e3fa6c9d7d3d0dbc4b7df9923b6;p=linux-2.6-microblaze.git diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index b8abb30f80df..d2a089a6f666 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -60,9 +60,8 @@ struct ib_port { struct attribute_group gid_group; struct attribute_group *pkey_group; const struct attribute_group *pma_table; - struct attribute_group *hw_stats_ag; - struct rdma_hw_stats *hw_stats; - u8 port_num; + struct hw_stats_port_data *hw_stats_data; + u32 port_num; }; struct port_attribute { @@ -85,16 +84,35 @@ struct port_table_attribute { __be16 attr_id; }; -struct hw_stats_attribute { - struct attribute attr; - ssize_t (*show)(struct kobject *kobj, - struct attribute *attr, char *buf); - ssize_t (*store)(struct kobject *kobj, - struct attribute *attr, - const char *buf, - size_t count); - int index; - u8 port_num; +struct hw_stats_device_attribute { + struct device_attribute attr; + ssize_t (*show)(struct ib_device *ibdev, struct rdma_hw_stats *stats, + unsigned int index, unsigned int port_num, char *buf); + ssize_t (*store)(struct ib_device *ibdev, struct rdma_hw_stats *stats, + unsigned int index, unsigned int port_num, + const char *buf, size_t count); +}; + +struct hw_stats_port_attribute { + struct port_attribute attr; + ssize_t (*show)(struct ib_device *ibdev, struct rdma_hw_stats *stats, + unsigned int index, unsigned int port_num, char *buf); + ssize_t (*store)(struct ib_device *ibdev, struct rdma_hw_stats *stats, + unsigned int index, unsigned int port_num, + const char *buf, size_t count); +}; + +struct hw_stats_device_data { + struct attribute_group group; + const struct attribute_group *groups[2]; + struct rdma_hw_stats *stats; + struct hw_stats_device_attribute attrs[]; +}; + +struct hw_stats_port_data { + struct attribute_group group; + struct rdma_hw_stats *stats; + struct hw_stats_port_attribute attrs[]; }; static ssize_t port_attr_show(struct kobject *kobj, @@ -128,6 +146,53 @@ static const struct sysfs_ops port_sysfs_ops = { .store = port_attr_store }; +static ssize_t hw_stat_device_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hw_stats_device_attribute *stat_attr = + container_of(attr, struct hw_stats_device_attribute, attr); + struct ib_device *ibdev = container_of(dev, struct ib_device, dev); + + return stat_attr->show(ibdev, ibdev->hw_stats_data->stats, + stat_attr - ibdev->hw_stats_data->attrs, 0, buf); +} + +static ssize_t hw_stat_device_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hw_stats_device_attribute *stat_attr = + container_of(attr, struct hw_stats_device_attribute, attr); + struct ib_device *ibdev = container_of(dev, struct ib_device, dev); + + return stat_attr->store(ibdev, ibdev->hw_stats_data->stats, + stat_attr - ibdev->hw_stats_data->attrs, 0, buf, + count); +} + +static ssize_t hw_stat_port_show(struct ib_port *port, + struct port_attribute *attr, char *buf) +{ + struct hw_stats_port_attribute *stat_attr = + container_of(attr, struct hw_stats_port_attribute, attr); + + return stat_attr->show(port->ibdev, port->hw_stats_data->stats, + stat_attr - port->hw_stats_data->attrs, + port->port_num, buf); +} + +static ssize_t hw_stat_port_store(struct ib_port *port, + struct port_attribute *attr, const char *buf, + size_t count) +{ + struct hw_stats_port_attribute *stat_attr = + container_of(attr, struct hw_stats_port_attribute, attr); + + return stat_attr->store(port->ibdev, port->hw_stats_data->stats, + stat_attr - port->hw_stats_data->attrs, + port->port_num, buf, count); +} + static ssize_t gid_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -297,7 +362,7 @@ static ssize_t rate_show(struct ib_port *p, struct port_attribute *unused, static const char *phys_state_to_str(enum ib_port_phys_state phys_state) { - static const char * phys_state_str[] = { + static const char *phys_state_str[] = { "", "Sleep", "Polling", @@ -470,14 +535,14 @@ static ssize_t show_port_pkey(struct ib_port *p, struct port_attribute *attr, struct port_table_attribute port_pma_attr_##_name = { \ .attr = __ATTR(_name, S_IRUGO, show_pma_counter, NULL), \ .index = (_offset) | ((_width) << 16) | ((_counter) << 24), \ - .attr_id = IB_PMA_PORT_COUNTERS , \ + .attr_id = IB_PMA_PORT_COUNTERS, \ } #define PORT_PMA_ATTR_EXT(_name, _width, _offset) \ struct port_table_attribute port_pma_attr_ext_##_name = { \ .attr = __ATTR(_name, S_IRUGO, show_pma_counter, NULL), \ .index = (_offset) | ((_width) << 16), \ - .attr_id = IB_PMA_PORT_COUNTERS_EXT , \ + .attr_id = IB_PMA_PORT_COUNTERS_EXT, \ } /* @@ -812,7 +877,7 @@ static const struct attribute_group *get_counter_table(struct ib_device *dev, } static int update_hw_stats(struct ib_device *dev, struct rdma_hw_stats *stats, - u8 port_num, int index) + u32 port_num, int index) { int ret; @@ -835,56 +900,30 @@ static int print_hw_stat(struct ib_device *dev, int port_num, return sysfs_emit(buf, "%llu\n", stats->value[index] + v); } -static ssize_t show_hw_stats(struct kobject *kobj, struct attribute *attr, - char *buf) +static ssize_t show_hw_stats(struct ib_device *ibdev, + struct rdma_hw_stats *stats, unsigned int index, + unsigned int port_num, char *buf) { - struct ib_device *dev; - struct ib_port *port; - struct hw_stats_attribute *hsa; - struct rdma_hw_stats *stats; int ret; - hsa = container_of(attr, struct hw_stats_attribute, attr); - if (!hsa->port_num) { - dev = container_of((struct device *)kobj, - struct ib_device, dev); - stats = dev->hw_stats; - } else { - port = container_of(kobj, struct ib_port, kobj); - dev = port->ibdev; - stats = port->hw_stats; - } mutex_lock(&stats->lock); - ret = update_hw_stats(dev, stats, hsa->port_num, hsa->index); + ret = update_hw_stats(ibdev, stats, port_num, index); if (ret) goto unlock; - ret = print_hw_stat(dev, hsa->port_num, stats, hsa->index, buf); + ret = print_hw_stat(ibdev, port_num, stats, index, buf); unlock: mutex_unlock(&stats->lock); return ret; } -static ssize_t show_stats_lifespan(struct kobject *kobj, - struct attribute *attr, +static ssize_t show_stats_lifespan(struct ib_device *ibdev, + struct rdma_hw_stats *stats, + unsigned int index, unsigned int port_num, char *buf) { - struct hw_stats_attribute *hsa; - struct rdma_hw_stats *stats; int msecs; - hsa = container_of(attr, struct hw_stats_attribute, attr); - if (!hsa->port_num) { - struct ib_device *dev = container_of((struct device *)kobj, - struct ib_device, dev); - - stats = dev->hw_stats; - } else { - struct ib_port *p = container_of(kobj, struct ib_port, kobj); - - stats = p->hw_stats; - } - mutex_lock(&stats->lock); msecs = jiffies_to_msecs(stats->lifespan); mutex_unlock(&stats->lock); @@ -892,12 +931,11 @@ static ssize_t show_stats_lifespan(struct kobject *kobj, return sysfs_emit(buf, "%d\n", msecs); } -static ssize_t set_stats_lifespan(struct kobject *kobj, - struct attribute *attr, - const char *buf, size_t count) +static ssize_t set_stats_lifespan(struct ib_device *ibdev, + struct rdma_hw_stats *stats, + unsigned int index, unsigned int port_num, + const char *buf, size_t count) { - struct hw_stats_attribute *hsa; - struct rdma_hw_stats *stats; int msecs; int jiffies; int ret; @@ -908,17 +946,6 @@ static ssize_t set_stats_lifespan(struct kobject *kobj, if (msecs < 0 || msecs > 10000) return -EINVAL; jiffies = msecs_to_jiffies(msecs); - hsa = container_of(attr, struct hw_stats_attribute, attr); - if (!hsa->port_num) { - struct ib_device *dev = container_of((struct device *)kobj, - struct ib_device, dev); - - stats = dev->hw_stats; - } else { - struct ib_port *p = container_of(kobj, struct ib_port, kobj); - - stats = p->hw_stats; - } mutex_lock(&stats->lock); stats->lifespan = jiffies; @@ -927,65 +954,125 @@ static ssize_t set_stats_lifespan(struct kobject *kobj, return count; } -static void free_hsag(struct kobject *kobj, struct attribute_group *attr_group) +static struct hw_stats_device_data * +alloc_hw_stats_device(struct ib_device *ibdev) { - struct attribute **attr; + struct hw_stats_device_data *data; + struct rdma_hw_stats *stats; + + if (!ibdev->ops.alloc_hw_device_stats) + return ERR_PTR(-EOPNOTSUPP); + stats = ibdev->ops.alloc_hw_device_stats(ibdev); + if (!stats) + return ERR_PTR(-ENOMEM); + if (!stats->names || stats->num_counters <= 0) + goto err_free_stats; + + /* + * Two extra attribue elements here, one for the lifespan entry and + * one to NULL terminate the list for the sysfs core code + */ + data = kzalloc(struct_size(data, attrs, stats->num_counters + 1), + GFP_KERNEL); + if (!data) + goto err_free_stats; + data->group.attrs = kcalloc(stats->num_counters + 2, + sizeof(*data->group.attrs), GFP_KERNEL); + if (!data->group.attrs) + goto err_free_data; - sysfs_remove_group(kobj, attr_group); + mutex_init(&stats->lock); + data->group.name = "hw_counters"; + data->stats = stats; + data->groups[0] = &data->group; + return data; - for (attr = attr_group->attrs; *attr; attr++) - kfree(*attr); - kfree(attr_group); +err_free_data: + kfree(data); +err_free_stats: + kfree(stats); + return ERR_PTR(-ENOMEM); } -static struct attribute *alloc_hsa(int index, u8 port_num, const char *name) +static void free_hw_stats_device(struct hw_stats_device_data *data) { - struct hw_stats_attribute *hsa; + kfree(data->group.attrs); + kfree(data->stats); + kfree(data); +} - hsa = kmalloc(sizeof(*hsa), GFP_KERNEL); - if (!hsa) - return NULL; +static int setup_hw_device_stats(struct ib_device *ibdev) +{ + struct hw_stats_device_attribute *attr; + struct hw_stats_device_data *data; + int i, ret; - hsa->attr.name = (char *)name; - hsa->attr.mode = S_IRUGO; - hsa->show = show_hw_stats; - hsa->store = NULL; - hsa->index = index; - hsa->port_num = port_num; + data = alloc_hw_stats_device(ibdev); + if (IS_ERR(data)) + return PTR_ERR(data); - return &hsa->attr; -} + ret = ibdev->ops.get_hw_stats(ibdev, data->stats, 0, + data->stats->num_counters); + if (ret != data->stats->num_counters) { + if (WARN_ON(ret >= 0)) + ret = -EINVAL; + goto err_free; + } -static struct attribute *alloc_hsa_lifespan(char *name, u8 port_num) -{ - struct hw_stats_attribute *hsa; + data->stats->timestamp = jiffies; - hsa = kmalloc(sizeof(*hsa), GFP_KERNEL); - if (!hsa) - return NULL; + for (i = 0; i < data->stats->num_counters; i++) { + attr = &data->attrs[i]; + sysfs_attr_init(&attr->attr.attr); + attr->attr.attr.name = data->stats->names[i]; + attr->attr.attr.mode = 0444; + attr->attr.show = hw_stat_device_show; + attr->show = show_hw_stats; + data->group.attrs[i] = &attr->attr.attr; + } - hsa->attr.name = name; - hsa->attr.mode = S_IWUSR | S_IRUGO; - hsa->show = show_stats_lifespan; - hsa->store = set_stats_lifespan; - hsa->index = 0; - hsa->port_num = port_num; + attr = &data->attrs[i]; + sysfs_attr_init(&attr->attr.attr); + attr->attr.attr.name = "lifespan"; + attr->attr.attr.mode = 0644; + attr->attr.show = hw_stat_device_show; + attr->show = show_stats_lifespan; + attr->attr.store = hw_stat_device_store; + attr->store = set_stats_lifespan; + data->group.attrs[i] = &attr->attr.attr; + + ibdev->hw_stats_data = data; + ret = device_add_groups(&ibdev->dev, data->groups); + if (ret) + goto err_free; + return 0; - return &hsa->attr; +err_free: + free_hw_stats_device(data); + ibdev->hw_stats_data = NULL; + return ret; } -static void setup_hw_stats(struct ib_device *device, struct ib_port *port, - u8 port_num) +static void destroy_hw_device_stats(struct ib_device *ibdev) { - struct attribute_group *hsag; - struct rdma_hw_stats *stats; - int i, ret; + if (!ibdev->hw_stats_data) + return; + device_remove_groups(&ibdev->dev, ibdev->hw_stats_data->groups); + free_hw_stats_device(ibdev->hw_stats_data); + ibdev->hw_stats_data = NULL; +} - stats = device->ops.alloc_hw_stats(device, port_num); +static struct hw_stats_port_data *alloc_hw_stats_port(struct ib_port *port) +{ + struct ib_device *ibdev = port->ibdev; + struct hw_stats_port_data *data; + struct rdma_hw_stats *stats; + if (!ibdev->ops.alloc_hw_port_stats) + return ERR_PTR(-EOPNOTSUPP); + stats = ibdev->ops.alloc_hw_port_stats(port->ibdev, port->port_num); if (!stats) - return; - + return ERR_PTR(-ENOMEM); if (!stats->names || stats->num_counters <= 0) goto err_free_stats; @@ -993,63 +1080,181 @@ static void setup_hw_stats(struct ib_device *device, struct ib_port *port, * Two extra attribue elements here, one for the lifespan entry and * one to NULL terminate the list for the sysfs core code */ - hsag = kzalloc(sizeof(*hsag) + - sizeof(void *) * (stats->num_counters + 2), + data = kzalloc(struct_size(data, attrs, stats->num_counters + 1), GFP_KERNEL); - if (!hsag) + if (!data) goto err_free_stats; + data->group.attrs = kcalloc(stats->num_counters + 2, + sizeof(*data->group.attrs), GFP_KERNEL); + if (!data->group.attrs) + goto err_free_data; - ret = device->ops.get_hw_stats(device, stats, port_num, - stats->num_counters); - if (ret != stats->num_counters) - goto err_free_hsag; + mutex_init(&stats->lock); + data->group.name = "hw_counters"; + data->stats = stats; + return data; + +err_free_data: + kfree(data); +err_free_stats: + kfree(stats); + return ERR_PTR(-ENOMEM); +} - stats->timestamp = jiffies; +static void free_hw_stats_port(struct hw_stats_port_data *data) +{ + kfree(data->group.attrs); + kfree(data->stats); + kfree(data); +} - hsag->name = "hw_counters"; - hsag->attrs = (void *)hsag + sizeof(*hsag); +static int setup_hw_port_stats(struct ib_port *port) +{ + struct hw_stats_port_attribute *attr; + struct hw_stats_port_data *data; + int i, ret; - for (i = 0; i < stats->num_counters; i++) { - hsag->attrs[i] = alloc_hsa(i, port_num, stats->names[i]); - if (!hsag->attrs[i]) - goto err; - sysfs_attr_init(hsag->attrs[i]); + data = alloc_hw_stats_port(port); + if (IS_ERR(data)) + return PTR_ERR(data); + + ret = port->ibdev->ops.get_hw_stats(port->ibdev, data->stats, + port->port_num, + data->stats->num_counters); + if (ret != data->stats->num_counters) { + if (WARN_ON(ret >= 0)) + ret = -EINVAL; + goto err_free; + } + data->stats->timestamp = jiffies; + + for (i = 0; i < data->stats->num_counters; i++) { + attr = &data->attrs[i]; + sysfs_attr_init(&attr->attr.attr); + attr->attr.attr.name = data->stats->names[i]; + attr->attr.attr.mode = 0444; + attr->attr.show = hw_stat_port_show; + attr->show = show_hw_stats; + data->group.attrs[i] = &attr->attr.attr; } - mutex_init(&stats->lock); - /* treat an error here as non-fatal */ - hsag->attrs[i] = alloc_hsa_lifespan("lifespan", port_num); - if (hsag->attrs[i]) - sysfs_attr_init(hsag->attrs[i]); - - if (port) { - struct kobject *kobj = &port->kobj; - ret = sysfs_create_group(kobj, hsag); - if (ret) - goto err; - port->hw_stats_ag = hsag; - port->hw_stats = stats; - if (device->port_data) - device->port_data[port_num].hw_stats = stats; - } else { - struct kobject *kobj = &device->dev.kobj; - ret = sysfs_create_group(kobj, hsag); - if (ret) - goto err; - device->hw_stats_ag = hsag; - device->hw_stats = stats; + attr = &data->attrs[i]; + sysfs_attr_init(&attr->attr.attr); + attr->attr.attr.name = "lifespan"; + attr->attr.attr.mode = 0644; + attr->attr.show = hw_stat_port_show; + attr->show = show_stats_lifespan; + attr->attr.store = hw_stat_port_store; + attr->store = set_stats_lifespan; + data->group.attrs[i] = &attr->attr.attr; + + port->hw_stats_data = data; + ret = sysfs_create_group(&port->kobj, &data->group); + if (ret) + goto err_free; + return 0; + +err_free: + free_hw_stats_port(data); + port->hw_stats_data = NULL; + return ret; +} + +static void destroy_hw_port_stats(struct ib_port *port) +{ + if (!port->hw_stats_data) + return; + sysfs_remove_group(&port->kobj, &port->hw_stats_data->group); + free_hw_stats_port(port->hw_stats_data); + port->hw_stats_data = NULL; +} + +struct rdma_hw_stats *ib_get_hw_stats_port(struct ib_device *ibdev, + u32 port_num) +{ + if (!ibdev->port_data || !rdma_is_port_valid(ibdev, port_num) || + !ibdev->port_data[port_num].sysfs->hw_stats_data) + return NULL; + return ibdev->port_data[port_num].sysfs->hw_stats_data->stats; +} + +/* + * Create the sysfs: + * ibp0s9/ports/XX/gid_attrs/{ndevs,types}/YYY + * YYY is the gid table index in decimal + */ +static int setup_gid_attrs(struct ib_port *port, + const struct ib_port_attr *attr) +{ + struct gid_attr_group *gid_attr_group; + int ret; + int i; + + gid_attr_group = kzalloc(sizeof(*gid_attr_group), GFP_KERNEL); + if (!gid_attr_group) + return -ENOMEM; + + gid_attr_group->port = port; + ret = kobject_init_and_add(&gid_attr_group->kobj, &gid_attr_type, + &port->kobj, "gid_attrs"); + if (ret) + goto err_put_gid_attrs; + + gid_attr_group->ndev.name = "ndevs"; + gid_attr_group->ndev.attrs = + alloc_group_attrs(show_port_gid_attr_ndev, attr->gid_tbl_len); + if (!gid_attr_group->ndev.attrs) { + ret = -ENOMEM; + goto err_put_gid_attrs; } - return; + ret = sysfs_create_group(&gid_attr_group->kobj, &gid_attr_group->ndev); + if (ret) + goto err_free_gid_ndev; -err: - for (; i >= 0; i--) - kfree(hsag->attrs[i]); -err_free_hsag: - kfree(hsag); -err_free_stats: - kfree(stats); - return; + gid_attr_group->type.name = "types"; + gid_attr_group->type.attrs = alloc_group_attrs( + show_port_gid_attr_gid_type, attr->gid_tbl_len); + if (!gid_attr_group->type.attrs) { + ret = -ENOMEM; + goto err_remove_gid_ndev; + } + + ret = sysfs_create_group(&gid_attr_group->kobj, &gid_attr_group->type); + if (ret) + goto err_free_gid_type; + + port->gid_attr_group = gid_attr_group; + return 0; + +err_free_gid_type: + for (i = 0; i < attr->gid_tbl_len; ++i) + kfree(gid_attr_group->type.attrs[i]); + + kfree(gid_attr_group->type.attrs); + gid_attr_group->type.attrs = NULL; +err_remove_gid_ndev: + sysfs_remove_group(&gid_attr_group->kobj, &gid_attr_group->ndev); +err_free_gid_ndev: + for (i = 0; i < attr->gid_tbl_len; ++i) + kfree(gid_attr_group->ndev.attrs[i]); + + kfree(gid_attr_group->ndev.attrs); + gid_attr_group->ndev.attrs = NULL; +err_put_gid_attrs: + kobject_put(&gid_attr_group->kobj); + return ret; +} + +static void destroy_gid_attrs(struct ib_port *port) +{ + struct gid_attr_group *gid_attr_group = port->gid_attr_group; + + sysfs_remove_group(&gid_attr_group->kobj, + &gid_attr_group->ndev); + sysfs_remove_group(&gid_attr_group->kobj, + &gid_attr_group->type); + kobject_put(&gid_attr_group->kobj); } static int add_port(struct ib_core_device *coredev, int port_num) @@ -1075,28 +1280,14 @@ static int add_port(struct ib_core_device *coredev, int port_num) ret = kobject_init_and_add(&p->kobj, &port_type, coredev->ports_kobj, "%d", port_num); - if (ret) { - goto err_put; - } - - p->gid_attr_group = kzalloc(sizeof(*p->gid_attr_group), GFP_KERNEL); - if (!p->gid_attr_group) { - ret = -ENOMEM; + if (ret) goto err_put; - } - - p->gid_attr_group->port = p; - ret = kobject_init_and_add(&p->gid_attr_group->kobj, &gid_attr_type, - &p->kobj, "gid_attrs"); - if (ret) { - goto err_put_gid_attrs; - } if (device->ops.process_mad && is_full_dev) { p->pma_table = get_counter_table(device, port_num); ret = sysfs_create_group(&p->kobj, p->pma_table); if (ret) - goto err_put_gid_attrs; + goto err_put; } p->gid_group.name = "gids"; @@ -1110,37 +1301,11 @@ static int add_port(struct ib_core_device *coredev, int port_num) if (ret) goto err_free_gid; - p->gid_attr_group->ndev.name = "ndevs"; - p->gid_attr_group->ndev.attrs = alloc_group_attrs(show_port_gid_attr_ndev, - attr.gid_tbl_len); - if (!p->gid_attr_group->ndev.attrs) { - ret = -ENOMEM; - goto err_remove_gid; - } - - ret = sysfs_create_group(&p->gid_attr_group->kobj, - &p->gid_attr_group->ndev); - if (ret) - goto err_free_gid_ndev; - - p->gid_attr_group->type.name = "types"; - p->gid_attr_group->type.attrs = alloc_group_attrs(show_port_gid_attr_gid_type, - attr.gid_tbl_len); - if (!p->gid_attr_group->type.attrs) { - ret = -ENOMEM; - goto err_remove_gid_ndev; - } - - ret = sysfs_create_group(&p->gid_attr_group->kobj, - &p->gid_attr_group->type); - if (ret) - goto err_free_gid_type; - if (attr.pkey_tbl_len) { p->pkey_group = kzalloc(sizeof(*p->pkey_group), GFP_KERNEL); if (!p->pkey_group) { ret = -ENOMEM; - goto err_remove_gid_type; + goto err_remove_gid; } p->pkey_group->name = "pkeys"; @@ -1156,26 +1321,39 @@ static int add_port(struct ib_core_device *coredev, int port_num) goto err_free_pkey; } + /* + * If port == 0, it means hw_counters are per device and not per + * port, so holder should be device. Therefore skip per port + * counter initialization. + */ + if (port_num && is_full_dev) { + ret = setup_hw_port_stats(p); + if (ret && ret != -EOPNOTSUPP) + goto err_remove_pkey; + } + ret = setup_gid_attrs(p, &attr); + if (ret) + goto err_remove_stats; if (device->ops.init_port && is_full_dev) { ret = device->ops.init_port(device, port_num, &p->kobj); if (ret) - goto err_remove_pkey; + goto err_remove_gid_attrs; } - /* - * If port == 0, it means hw_counters are per device and not per - * port, so holder should be device. Therefore skip per port conunter - * initialization. - */ - if (device->ops.alloc_hw_stats && port_num && is_full_dev) - setup_hw_stats(device, p, port_num); - list_add_tail(&p->kobj.entry, &coredev->port_list); + if (device->port_data && is_full_dev) + device->port_data[port_num].sysfs = p; kobject_uevent(&p->kobj, KOBJ_ADD); return 0; +err_remove_gid_attrs: + destroy_gid_attrs(p); + +err_remove_stats: + destroy_hw_port_stats(p); + err_remove_pkey: if (p->pkey_group) sysfs_remove_group(&p->kobj, p->pkey_group); @@ -1192,28 +1370,6 @@ err_free_pkey: err_free_pkey_group: kfree(p->pkey_group); -err_remove_gid_type: - sysfs_remove_group(&p->gid_attr_group->kobj, - &p->gid_attr_group->type); - -err_free_gid_type: - for (i = 0; i < attr.gid_tbl_len; ++i) - kfree(p->gid_attr_group->type.attrs[i]); - - kfree(p->gid_attr_group->type.attrs); - p->gid_attr_group->type.attrs = NULL; - -err_remove_gid_ndev: - sysfs_remove_group(&p->gid_attr_group->kobj, - &p->gid_attr_group->ndev); - -err_free_gid_ndev: - for (i = 0; i < attr.gid_tbl_len; ++i) - kfree(p->gid_attr_group->ndev.attrs[i]); - - kfree(p->gid_attr_group->ndev.attrs); - p->gid_attr_group->ndev.attrs = NULL; - err_remove_gid: sysfs_remove_group(&p->kobj, &p->gid_group); @@ -1228,9 +1384,6 @@ err_remove_pma: if (p->pma_table) sysfs_remove_group(&p->kobj, p->pma_table); -err_put_gid_attrs: - kobject_put(&p->gid_attr_group->kobj); - err_put: kobject_put(&p->kobj); return ret; @@ -1358,22 +1511,16 @@ void ib_free_port_attrs(struct ib_core_device *coredev) struct ib_port *port = container_of(p, struct ib_port, kobj); list_del(&p->entry); - if (port->hw_stats_ag) - free_hsag(&port->kobj, port->hw_stats_ag); - kfree(port->hw_stats); + destroy_hw_port_stats(port); if (device->port_data && is_full_dev) - device->port_data[port->port_num].hw_stats = NULL; + device->port_data[port->port_num].sysfs = NULL; if (port->pma_table) sysfs_remove_group(p, port->pma_table); if (port->pkey_group) sysfs_remove_group(p, port->pkey_group); sysfs_remove_group(p, &port->gid_group); - sysfs_remove_group(&port->gid_attr_group->kobj, - &port->gid_attr_group->ndev); - sysfs_remove_group(&port->gid_attr_group->kobj, - &port->gid_attr_group->type); - kobject_put(&port->gid_attr_group->kobj); + destroy_gid_attrs(port); kobject_put(p); } @@ -1383,7 +1530,7 @@ void ib_free_port_attrs(struct ib_core_device *coredev) int ib_setup_port_attrs(struct ib_core_device *coredev) { struct ib_device *device = rdma_device_to_ibdev(&coredev->dev); - unsigned int port; + u32 port; int ret; coredev->ports_kobj = kobject_create_and_add("ports", @@ -1412,18 +1559,18 @@ int ib_device_register_sysfs(struct ib_device *device) if (ret) return ret; - if (device->ops.alloc_hw_stats) - setup_hw_stats(device, NULL, 0); + ret = setup_hw_device_stats(device); + if (ret && ret != -EOPNOTSUPP) { + ib_free_port_attrs(&device->coredev); + return ret; + } return 0; } void ib_device_unregister_sysfs(struct ib_device *device) { - if (device->hw_stats_ag) - free_hsag(&device->dev.kobj, device->hw_stats_ag); - kfree(device->hw_stats); - + destroy_hw_device_stats(device); ib_free_port_attrs(&device->coredev); } @@ -1437,7 +1584,7 @@ void ib_device_unregister_sysfs(struct ib_device *device) * @ktype: pointer to the ktype for this kobject. * @name: the name of the kobject */ -int ib_port_register_module_stat(struct ib_device *device, u8 port_num, +int ib_port_register_module_stat(struct ib_device *device, u32 port_num, struct kobject *kobj, struct kobj_type *ktype, const char *name) {