]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/net/ethernet/intel/i40e/i40e_configfs.c
i40e: use more portable sign extension
[karo-tx-linux.git] / drivers / net / ethernet / intel / i40e / i40e_configfs.c
1 /*******************************************************************************
2  *
3  * Intel Ethernet Controller XL710 Family Linux Driver
4  * Copyright(c) 2013 - 2015 Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  * The full GNU General Public License is included in this distribution in
19  * the file called "COPYING".
20  *
21  * Contact Information:
22  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
23  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24  *
25  ******************************************************************************/
26
27 #include <linux/configfs.h>
28 #include "i40e.h"
29
30 #if IS_ENABLED(CONFIG_I40E_CONFIGFS_FS)
31
32 /**
33  * configfs structure for i40e
34  *
35  * This file adds code for configfs support for the i40e driver.  This sets
36  * up a filesystem under /sys/kernel/config in which configuration changes
37  * can be made for the driver's netdevs.
38  *
39  * The initialization in this code creates the "i40e" entry in the configfs
40  * system.  After that, the user needs to use mkdir to create configurations
41  * for specific netdev ports; for example "mkdir eth3".  This code will verify
42  * that such a netdev exists and that it is owned by i40e.
43  *
44  **/
45
46 struct i40e_cfgfs_vsi {
47         struct config_item item;
48         struct i40e_vsi *vsi;
49 };
50
51 static inline struct i40e_cfgfs_vsi *to_i40e_cfgfs_vsi(struct config_item *item)
52 {
53         return item ? container_of(item, struct i40e_cfgfs_vsi, item) : NULL;
54 }
55
56 static struct configfs_attribute i40e_cfgfs_vsi_attr_min_bw = {
57         .ca_owner = THIS_MODULE,
58         .ca_name = "min_bw",
59         .ca_mode = S_IRUGO | S_IWUSR,
60 };
61
62 static struct configfs_attribute i40e_cfgfs_vsi_attr_max_bw = {
63         .ca_owner = THIS_MODULE,
64         .ca_name = "max_bw",
65         .ca_mode = S_IRUGO | S_IWUSR,
66 };
67
68 static struct configfs_attribute i40e_cfgfs_vsi_attr_commit = {
69         .ca_owner = THIS_MODULE,
70         .ca_name = "commit",
71         .ca_mode = S_IRUGO | S_IWUSR,
72 };
73
74 static struct configfs_attribute i40e_cfgfs_vsi_attr_port_count = {
75         .ca_owner = THIS_MODULE,
76         .ca_name = "ports",
77         .ca_mode = S_IRUGO | S_IWUSR,
78 };
79
80 static struct configfs_attribute i40e_cfgfs_vsi_attr_part_count = {
81         .ca_owner = THIS_MODULE,
82         .ca_name = "partitions",
83         .ca_mode = S_IRUGO | S_IWUSR,
84 };
85
86 static struct configfs_attribute *i40e_cfgfs_vsi_attrs[] = {
87         &i40e_cfgfs_vsi_attr_min_bw,
88         &i40e_cfgfs_vsi_attr_max_bw,
89         &i40e_cfgfs_vsi_attr_commit,
90         &i40e_cfgfs_vsi_attr_port_count,
91         &i40e_cfgfs_vsi_attr_part_count,
92         NULL,
93 };
94
95 /**
96  * i40e_cfgfs_vsi_attr_show - Show a VSI's NPAR BW partition info
97  * @item: A pointer back to the configfs item created on driver load
98  * @attr: A pointer to this item's configuration attribute
99  * @page: A pointer to the output buffer
100  **/
101 static ssize_t i40e_cfgfs_vsi_attr_show(struct config_item *item,
102                                         struct configfs_attribute *attr,
103                                         char *page)
104 {
105         struct i40e_cfgfs_vsi *i40e_cfgfs_vsi = to_i40e_cfgfs_vsi(item);
106         struct i40e_pf *pf = i40e_cfgfs_vsi->vsi->back;
107         ssize_t count;
108
109         if (i40e_cfgfs_vsi->vsi != pf->vsi[pf->lan_vsi])
110                 return 0;
111
112         if (strncmp(attr->ca_name, "min_bw", 6) == 0)
113                 count = sprintf(page, "%s %s %d%%\n",
114                                 i40e_cfgfs_vsi->vsi->netdev->name,
115                                 (pf->npar_min_bw & I40E_ALT_BW_RELATIVE_MASK) ?
116                                 "Relative Min BW" : "Absolute Min BW",
117                                 pf->npar_min_bw & I40E_ALT_BW_VALUE_MASK);
118         else if (strncmp(attr->ca_name, "max_bw", 6) == 0)
119                 count = sprintf(page, "%s %s %d%%\n",
120                                 i40e_cfgfs_vsi->vsi->netdev->name,
121                                 (pf->npar_max_bw & I40E_ALT_BW_RELATIVE_MASK) ?
122                                 "Relative Max BW" : "Absolute Max BW",
123                                 pf->npar_max_bw & I40E_ALT_BW_VALUE_MASK);
124         else if (strncmp(attr->ca_name, "ports", 5) == 0)
125                 count = sprintf(page, "%d\n",
126                                 pf->hw.num_ports);
127         else if (strncmp(attr->ca_name, "partitions", 10) == 0)
128                 count = sprintf(page, "%d\n",
129                                 pf->hw.num_partitions);
130         else
131                 return 0;
132
133         return count;
134 }
135
136 /**
137  * i40e_cfgfs_vsi_attr_store - Show a VSI's NPAR BW partition info
138  * @item: A pointer back to the configfs item created on driver load
139  * @attr: A pointer to this item's configuration attribute
140  * @page: A pointer to the user input buffer holding the user input values
141  **/
142 static ssize_t i40e_cfgfs_vsi_attr_store(struct config_item *item,
143                                          struct configfs_attribute *attr,
144                                          const char *page, size_t count)
145 {
146         struct i40e_cfgfs_vsi *i40e_cfgfs_vsi = to_i40e_cfgfs_vsi(item);
147         struct i40e_pf *pf = i40e_cfgfs_vsi->vsi->back;
148         char *p = (char *)page;
149         int rc;
150         unsigned long tmp;
151
152         if (i40e_cfgfs_vsi->vsi != pf->vsi[pf->lan_vsi])
153                 return 0;
154
155         if (!p || (*p && (*p == '\n')))
156                 return -EINVAL;
157
158         rc = kstrtoul(p, 10, &tmp);
159         if (rc)
160                 return rc;
161         if (tmp > 100)
162                 return -ERANGE;
163
164         if (strncmp(attr->ca_name, "min_bw", 6) == 0) {
165                 if (tmp > (pf->npar_max_bw & I40E_ALT_BW_VALUE_MASK))
166                         return -ERANGE;
167                 /* Preserve the valid and relative BW bits - the rest is
168                  * don't care.
169                  */
170                 pf->npar_min_bw &= (I40E_ALT_BW_RELATIVE_MASK |
171                                     I40E_ALT_BW_VALID_MASK);
172                 pf->npar_min_bw |= (tmp & I40E_ALT_BW_VALUE_MASK);
173                 i40e_set_npar_bw_setting(pf);
174         } else if (strncmp(attr->ca_name, "max_bw", 6) == 0) {
175                 if (tmp < 1 ||
176                     tmp < (pf->npar_min_bw & I40E_ALT_BW_VALUE_MASK))
177                         return -ERANGE;
178                 /* Preserve the valid and relative BW bits - the rest is
179                  * don't care.
180                  */
181                 pf->npar_max_bw &= (I40E_ALT_BW_RELATIVE_MASK |
182                                     I40E_ALT_BW_VALID_MASK);
183                 pf->npar_max_bw |= (tmp & I40E_ALT_BW_VALUE_MASK);
184                 i40e_set_npar_bw_setting(pf);
185         } else if (strncmp(attr->ca_name, "commit", 6) == 0 && tmp == 1) {
186                 if (i40e_commit_npar_bw_setting(pf))
187                         return -EIO;
188         }
189
190         return count;
191 }
192
193 /**
194  * i40e_cfgfs_vsi_release - Free up the configuration item memory
195  * @item: A pointer back to the configfs item created on driver load
196  **/
197 static void i40e_cfgfs_vsi_release(struct config_item *item)
198 {
199         kfree(to_i40e_cfgfs_vsi(item));
200 }
201
202 static struct configfs_item_operations i40e_cfgfs_vsi_item_ops = {
203         .release                = i40e_cfgfs_vsi_release,
204         .show_attribute         = i40e_cfgfs_vsi_attr_show,
205         .store_attribute        = i40e_cfgfs_vsi_attr_store,
206 };
207
208 static struct config_item_type i40e_cfgfs_vsi_type = {
209         .ct_item_ops    = &i40e_cfgfs_vsi_item_ops,
210         .ct_attrs       = i40e_cfgfs_vsi_attrs,
211         .ct_owner       = THIS_MODULE,
212 };
213
214 struct i40e_cfgfs_group {
215         struct config_group group;
216 };
217
218 /**
219  * to_i40e_cfgfs_group - Get the group pointer from the config item
220  * @item: A pointer back to the configfs item created on driver load
221  **/
222 static inline struct i40e_cfgfs_group *
223 to_i40e_cfgfs_group(struct config_item *item)
224 {
225         return item ? container_of(to_config_group(item),
226                                    struct i40e_cfgfs_group, group) : NULL;
227 }
228
229 /**
230  * i40e_cfgfs_group_make_item - Create the configfs item with group container
231  * @group: A pointer to our configfs group
232  * @name: A pointer to the nume of the device we're looking for
233  **/
234 static struct config_item *
235 i40e_cfgfs_group_make_item(struct config_group *group, const char *name)
236 {
237         struct i40e_cfgfs_vsi *i40e_cfgfs_vsi;
238         struct net_device *netdev;
239         struct i40e_netdev_priv *np;
240
241         read_lock(&dev_base_lock);
242         netdev = first_net_device(&init_net);
243         while (netdev) {
244                 if (strncmp(netdev->name, name, sizeof(netdev->name)) == 0)
245                         break;
246                 netdev = next_net_device(netdev);
247         }
248         read_unlock(&dev_base_lock);
249
250         if (!netdev)
251                 return ERR_PTR(-ENODEV);
252
253         /* is this netdev owned by i40e? */
254         if (netdev->netdev_ops->ndo_open != i40e_open)
255                 return ERR_PTR(-EACCES);
256
257         i40e_cfgfs_vsi = kzalloc(sizeof(*i40e_cfgfs_vsi), GFP_KERNEL);
258         if (!i40e_cfgfs_vsi)
259                 return ERR_PTR(-ENOMEM);
260
261         np = netdev_priv(netdev);
262         i40e_cfgfs_vsi->vsi = np->vsi;
263         config_item_init_type_name(&i40e_cfgfs_vsi->item, name,
264                                    &i40e_cfgfs_vsi_type);
265
266         return &i40e_cfgfs_vsi->item;
267 }
268
269 static struct configfs_attribute i40e_cfgfs_group_attr_description = {
270         .ca_owner = THIS_MODULE,
271         .ca_name = "description",
272         .ca_mode = S_IRUGO,
273 };
274
275 static struct configfs_attribute *i40e_cfgfs_group_attrs[] = {
276         &i40e_cfgfs_group_attr_description,
277         NULL,
278 };
279
280 static ssize_t i40e_cfgfs_group_attr_show(struct config_item *item,
281                                           struct configfs_attribute *attr,
282                                           char *page)
283 {
284         return sprintf(page,
285 "i40e\n"
286 "\n"
287 "This subsystem allows the modification of network port configurations.\n"
288 "To start, use the name of the network port to be configured in a 'mkdir'\n"
289 "command, e.g. 'mkdir eth3'.\n");
290 }
291
292 static void i40e_cfgfs_group_release(struct config_item *item)
293 {
294         kfree(to_i40e_cfgfs_group(item));
295 }
296
297 static struct configfs_item_operations i40e_cfgfs_group_item_ops = {
298         .release        = i40e_cfgfs_group_release,
299         .show_attribute = i40e_cfgfs_group_attr_show,
300 };
301
302 /* Note that, since no extra work is required on ->drop_item(),
303  * no ->drop_item() is provided.
304  */
305 static struct configfs_group_operations i40e_cfgfs_group_ops = {
306         .make_item      = i40e_cfgfs_group_make_item,
307 };
308
309 static struct config_item_type i40e_cfgfs_group_type = {
310         .ct_item_ops    = &i40e_cfgfs_group_item_ops,
311         .ct_group_ops   = &i40e_cfgfs_group_ops,
312         .ct_attrs       = i40e_cfgfs_group_attrs,
313         .ct_owner       = THIS_MODULE,
314 };
315
316 static struct configfs_subsystem i40e_cfgfs_group_subsys = {
317         .su_group = {
318                 .cg_item = {
319                         .ci_namebuf = "i40e",
320                         .ci_type = &i40e_cfgfs_group_type,
321                 },
322         },
323 };
324
325 /**
326  * i40e_configfs_init - Initialize configfs support for our driver
327  **/
328 int i40e_configfs_init(void)
329 {
330         int ret;
331         struct configfs_subsystem *subsys;
332
333         subsys = &i40e_cfgfs_group_subsys;
334
335         config_group_init(&subsys->su_group);
336         mutex_init(&subsys->su_mutex);
337         ret = configfs_register_subsystem(subsys);
338         if (ret) {
339                 pr_err("Error %d while registering configfs subsystem %s\n",
340                        ret, subsys->su_group.cg_item.ci_namebuf);
341                 return ret;
342         }
343
344         return 0;
345 }
346
347 /**
348  * i40e_configfs_init - Bail out - unregister configfs subsystem and release
349  **/
350 void i40e_configfs_exit(void)
351 {
352         configfs_unregister_subsystem(&i40e_cfgfs_group_subsys);
353 }
354 #endif /* IS_ENABLED(CONFIG_I40E_CONFIGFS_FS) */