Commit | Line | Data |
---|---|---|
577ae39d JK |
1 | /* |
2 | * QLogic qlcnic NIC Driver | |
3 | * Copyright (c) 2009-2013 QLogic Corporation | |
4 | * | |
5 | * See LICENSE.qlcnic for copyright and licensing details. | |
6 | */ | |
7 | ||
ec079a07 | 8 | #include <linux/slab.h> |
ec079a07 SC |
9 | #include <linux/interrupt.h> |
10 | ||
11 | #include "qlcnic.h" | |
319ecf12 | 12 | #include "qlcnic_hw.h" |
ec079a07 SC |
13 | |
14 | #include <linux/swab.h> | |
15 | #include <linux/dma-mapping.h> | |
16 | #include <net/ip.h> | |
17 | #include <linux/ipv6.h> | |
18 | #include <linux/inetdevice.h> | |
19 | #include <linux/sysfs.h> | |
20 | #include <linux/aer.h> | |
21 | #include <linux/log2.h> | |
1f0f467b HP |
22 | #ifdef CONFIG_QLCNIC_HWMON |
23 | #include <linux/hwmon.h> | |
24 | #include <linux/hwmon-sysfs.h> | |
25 | #endif | |
ec079a07 | 26 | |
319ecf12 SC |
27 | #define QLC_STATUS_UNSUPPORTED_CMD -2 |
28 | ||
ec079a07 SC |
29 | int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable) |
30 | { | |
31 | return -EOPNOTSUPP; | |
32 | } | |
33 | ||
34 | int qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) | |
35 | { | |
36 | return -EOPNOTSUPP; | |
37 | } | |
38 | ||
b66e29c9 SC |
39 | static ssize_t qlcnic_store_bridged_mode(struct device *dev, |
40 | struct device_attribute *attr, | |
41 | const char *buf, size_t len) | |
ec079a07 SC |
42 | { |
43 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
44 | unsigned long new; | |
45 | int ret = -EINVAL; | |
46 | ||
79788450 | 47 | if (!(adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG)) |
ec079a07 SC |
48 | goto err_out; |
49 | ||
50 | if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) | |
51 | goto err_out; | |
52 | ||
67d6bfa6 | 53 | if (kstrtoul(buf, 2, &new)) |
ec079a07 SC |
54 | goto err_out; |
55 | ||
319ecf12 | 56 | if (!qlcnic_config_bridged_mode(adapter, !!new)) |
ec079a07 SC |
57 | ret = len; |
58 | ||
59 | err_out: | |
60 | return ret; | |
61 | } | |
62 | ||
b66e29c9 SC |
63 | static ssize_t qlcnic_show_bridged_mode(struct device *dev, |
64 | struct device_attribute *attr, | |
65 | char *buf) | |
ec079a07 SC |
66 | { |
67 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
68 | int bridged_mode = 0; | |
69 | ||
79788450 | 70 | if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG) |
ec079a07 SC |
71 | bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED); |
72 | ||
73 | return sprintf(buf, "%d\n", bridged_mode); | |
74 | } | |
75 | ||
b66e29c9 SC |
76 | static ssize_t qlcnic_store_diag_mode(struct device *dev, |
77 | struct device_attribute *attr, | |
78 | const char *buf, size_t len) | |
ec079a07 SC |
79 | { |
80 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
81 | unsigned long new; | |
82 | ||
67d6bfa6 | 83 | if (kstrtoul(buf, 2, &new)) |
ec079a07 SC |
84 | return -EINVAL; |
85 | ||
86 | if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED)) | |
87 | adapter->flags ^= QLCNIC_DIAG_ENABLED; | |
88 | ||
89 | return len; | |
90 | } | |
91 | ||
b66e29c9 SC |
92 | static ssize_t qlcnic_show_diag_mode(struct device *dev, |
93 | struct device_attribute *attr, char *buf) | |
ec079a07 SC |
94 | { |
95 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
319ecf12 | 96 | return sprintf(buf, "%d\n", !!(adapter->flags & QLCNIC_DIAG_ENABLED)); |
ec079a07 SC |
97 | } |
98 | ||
b66e29c9 SC |
99 | static int qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon, |
100 | u8 *state, u8 *rate) | |
ec079a07 SC |
101 | { |
102 | *rate = LSB(beacon); | |
103 | *state = MSB(beacon); | |
104 | ||
105 | QLCDB(adapter, DRV, "rate %x state %x\n", *rate, *state); | |
106 | ||
107 | if (!*state) { | |
108 | *rate = __QLCNIC_MAX_LED_RATE; | |
109 | return 0; | |
b66e29c9 | 110 | } else if (*state > __QLCNIC_MAX_LED_STATE) { |
ec079a07 | 111 | return -EINVAL; |
b66e29c9 | 112 | } |
ec079a07 SC |
113 | |
114 | if ((!*rate) || (*rate > __QLCNIC_MAX_LED_RATE)) | |
115 | return -EINVAL; | |
116 | ||
117 | return 0; | |
118 | } | |
119 | ||
487042af HM |
120 | static int qlcnic_83xx_store_beacon(struct qlcnic_adapter *adapter, |
121 | const char *buf, size_t len) | |
ec079a07 | 122 | { |
319ecf12 | 123 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
319ecf12 | 124 | unsigned long h_beacon; |
487042af | 125 | int err; |
ec079a07 | 126 | |
487042af HM |
127 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) |
128 | return -EIO; | |
ec079a07 | 129 | |
487042af HM |
130 | if (kstrtoul(buf, 2, &h_beacon)) |
131 | return -EINVAL; | |
319ecf12 | 132 | |
a0431589 HM |
133 | qlcnic_get_beacon_state(adapter); |
134 | ||
487042af | 135 | if (ahw->beacon_state == h_beacon) |
319ecf12 | 136 | return len; |
487042af HM |
137 | |
138 | rtnl_lock(); | |
139 | if (!ahw->beacon_state) { | |
140 | if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) { | |
141 | rtnl_unlock(); | |
142 | return -EBUSY; | |
143 | } | |
319ecf12 SC |
144 | } |
145 | ||
487042af HM |
146 | if (h_beacon) |
147 | err = qlcnic_83xx_config_led(adapter, 1, h_beacon); | |
148 | else | |
149 | err = qlcnic_83xx_config_led(adapter, 0, !h_beacon); | |
150 | if (!err) | |
151 | ahw->beacon_state = h_beacon; | |
152 | ||
153 | if (!ahw->beacon_state) | |
154 | clear_bit(__QLCNIC_LED_ENABLE, &adapter->state); | |
155 | ||
156 | rtnl_unlock(); | |
157 | return len; | |
158 | } | |
159 | ||
160 | static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter, | |
161 | const char *buf, size_t len) | |
162 | { | |
163 | struct qlcnic_hardware_context *ahw = adapter->ahw; | |
34e8c406 | 164 | int err, drv_sds_rings = adapter->drv_sds_rings; |
487042af | 165 | u16 beacon; |
a0431589 | 166 | u8 b_state, b_rate; |
487042af | 167 | |
ec079a07 SC |
168 | if (len != sizeof(u16)) |
169 | return QL_STATUS_INVALID_PARAM; | |
170 | ||
171 | memcpy(&beacon, buf, sizeof(u16)); | |
172 | err = qlcnic_validate_beacon(adapter, beacon, &b_state, &b_rate); | |
173 | if (err) | |
174 | return err; | |
175 | ||
a0431589 | 176 | qlcnic_get_beacon_state(adapter); |
487042af HM |
177 | |
178 | if (ahw->beacon_state == b_state) | |
ec079a07 SC |
179 | return len; |
180 | ||
181 | rtnl_lock(); | |
487042af | 182 | if (!ahw->beacon_state) { |
ec079a07 SC |
183 | if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) { |
184 | rtnl_unlock(); | |
185 | return -EBUSY; | |
186 | } | |
487042af | 187 | } |
ec079a07 SC |
188 | |
189 | if (test_bit(__QLCNIC_RESETTING, &adapter->state)) { | |
190 | err = -EIO; | |
191 | goto out; | |
192 | } | |
193 | ||
194 | if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { | |
195 | err = qlcnic_diag_alloc_res(adapter->netdev, QLCNIC_LED_TEST); | |
196 | if (err) | |
197 | goto out; | |
198 | set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state); | |
199 | } | |
200 | ||
201 | err = qlcnic_config_led(adapter, b_state, b_rate); | |
361cd29c | 202 | if (!err) { |
ec079a07 | 203 | err = len; |
319ecf12 | 204 | ahw->beacon_state = b_state; |
361cd29c | 205 | } |
ec079a07 SC |
206 | |
207 | if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) | |
34e8c406 | 208 | qlcnic_diag_free_res(adapter->netdev, drv_sds_rings); |
ec079a07 | 209 | |
487042af HM |
210 | out: |
211 | if (!ahw->beacon_state) | |
ec079a07 SC |
212 | clear_bit(__QLCNIC_LED_ENABLE, &adapter->state); |
213 | rtnl_unlock(); | |
214 | ||
215 | return err; | |
216 | } | |
217 | ||
487042af HM |
218 | static ssize_t qlcnic_store_beacon(struct device *dev, |
219 | struct device_attribute *attr, | |
220 | const char *buf, size_t len) | |
221 | { | |
222 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
223 | int err = 0; | |
224 | ||
225 | if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) { | |
226 | dev_warn(dev, | |
227 | "LED test not supported in non privileged mode\n"); | |
228 | return -EOPNOTSUPP; | |
229 | } | |
230 | ||
231 | if (qlcnic_82xx_check(adapter)) | |
232 | err = qlcnic_82xx_store_beacon(adapter, buf, len); | |
233 | else if (qlcnic_83xx_check(adapter)) | |
234 | err = qlcnic_83xx_store_beacon(adapter, buf, len); | |
235 | else | |
236 | return -EIO; | |
237 | ||
238 | return err; | |
239 | } | |
240 | ||
b66e29c9 SC |
241 | static ssize_t qlcnic_show_beacon(struct device *dev, |
242 | struct device_attribute *attr, char *buf) | |
ec079a07 SC |
243 | { |
244 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
245 | ||
246 | return sprintf(buf, "%d\n", adapter->ahw->beacon_state); | |
247 | } | |
248 | ||
b66e29c9 SC |
249 | static int qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter, |
250 | loff_t offset, size_t size) | |
ec079a07 SC |
251 | { |
252 | size_t crb_size = 4; | |
253 | ||
254 | if (!(adapter->flags & QLCNIC_DIAG_ENABLED)) | |
255 | return -EIO; | |
256 | ||
257 | if (offset < QLCNIC_PCI_CRBSPACE) { | |
258 | if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, | |
b66e29c9 | 259 | QLCNIC_PCI_CAMQM_END)) |
ec079a07 SC |
260 | crb_size = 8; |
261 | else | |
262 | return -EINVAL; | |
263 | } | |
264 | ||
265 | if ((size != crb_size) || (offset & (crb_size-1))) | |
266 | return -EINVAL; | |
267 | ||
268 | return 0; | |
269 | } | |
270 | ||
b66e29c9 SC |
271 | static ssize_t qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj, |
272 | struct bin_attribute *attr, char *buf, | |
273 | loff_t offset, size_t size) | |
ec079a07 SC |
274 | { |
275 | struct device *dev = container_of(kobj, struct device, kobj); | |
276 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
ec079a07 SC |
277 | int ret; |
278 | ||
279 | ret = qlcnic_sysfs_validate_crb(adapter, offset, size); | |
280 | if (ret != 0) | |
281 | return ret; | |
319ecf12 | 282 | qlcnic_read_crb(adapter, buf, offset, size); |
ec079a07 | 283 | |
ec079a07 SC |
284 | return size; |
285 | } | |
286 | ||
b66e29c9 SC |
287 | static ssize_t qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj, |
288 | struct bin_attribute *attr, char *buf, | |
289 | loff_t offset, size_t size) | |
ec079a07 SC |
290 | { |
291 | struct device *dev = container_of(kobj, struct device, kobj); | |
292 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
ec079a07 SC |
293 | int ret; |
294 | ||
295 | ret = qlcnic_sysfs_validate_crb(adapter, offset, size); | |
296 | if (ret != 0) | |
297 | return ret; | |
298 | ||
319ecf12 | 299 | qlcnic_write_crb(adapter, buf, offset, size); |
ec079a07 SC |
300 | return size; |
301 | } | |
302 | ||
b66e29c9 SC |
303 | static int qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter, |
304 | loff_t offset, size_t size) | |
ec079a07 SC |
305 | { |
306 | if (!(adapter->flags & QLCNIC_DIAG_ENABLED)) | |
307 | return -EIO; | |
308 | ||
309 | if ((size != 8) || (offset & 0x7)) | |
310 | return -EIO; | |
311 | ||
312 | return 0; | |
313 | } | |
314 | ||
b66e29c9 SC |
315 | static ssize_t qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj, |
316 | struct bin_attribute *attr, char *buf, | |
317 | loff_t offset, size_t size) | |
ec079a07 SC |
318 | { |
319 | struct device *dev = container_of(kobj, struct device, kobj); | |
320 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
321 | u64 data; | |
322 | int ret; | |
323 | ||
324 | ret = qlcnic_sysfs_validate_mem(adapter, offset, size); | |
325 | if (ret != 0) | |
326 | return ret; | |
327 | ||
328 | if (qlcnic_pci_mem_read_2M(adapter, offset, &data)) | |
329 | return -EIO; | |
330 | ||
331 | memcpy(buf, &data, size); | |
332 | ||
333 | return size; | |
334 | } | |
335 | ||
b66e29c9 SC |
336 | static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj, |
337 | struct bin_attribute *attr, char *buf, | |
338 | loff_t offset, size_t size) | |
ec079a07 SC |
339 | { |
340 | struct device *dev = container_of(kobj, struct device, kobj); | |
341 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
342 | u64 data; | |
343 | int ret; | |
344 | ||
345 | ret = qlcnic_sysfs_validate_mem(adapter, offset, size); | |
346 | if (ret != 0) | |
347 | return ret; | |
348 | ||
349 | memcpy(&data, buf, size); | |
350 | ||
351 | if (qlcnic_pci_mem_write_2M(adapter, offset, data)) | |
352 | return -EIO; | |
353 | ||
354 | return size; | |
355 | } | |
356 | ||
2f514c52 JK |
357 | int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func) |
358 | { | |
319ecf12 | 359 | int i; |
2f514c52 | 360 | |
4f030227 | 361 | for (i = 0; i < adapter->ahw->total_nic_func; i++) { |
319ecf12 SC |
362 | if (adapter->npars[i].pci_func == pci_func) |
363 | return i; | |
364 | } | |
c65762fc SC |
365 | |
366 | dev_err(&adapter->pdev->dev, "%s: Invalid nic function\n", __func__); | |
d91abf90 | 367 | return -EINVAL; |
319ecf12 SC |
368 | } |
369 | ||
b66e29c9 SC |
370 | static int validate_pm_config(struct qlcnic_adapter *adapter, |
371 | struct qlcnic_pm_func_cfg *pm_cfg, int count) | |
ec079a07 | 372 | { |
319ecf12 SC |
373 | u8 src_pci_func, s_esw_id, d_esw_id; |
374 | u8 dest_pci_func; | |
375 | int i, src_index, dest_index; | |
ec079a07 SC |
376 | |
377 | for (i = 0; i < count; i++) { | |
378 | src_pci_func = pm_cfg[i].pci_func; | |
379 | dest_pci_func = pm_cfg[i].dest_npar; | |
319ecf12 | 380 | src_index = qlcnic_is_valid_nic_func(adapter, src_pci_func); |
319ecf12 | 381 | if (src_index < 0) |
ec079a07 SC |
382 | return QL_STATUS_INVALID_PARAM; |
383 | ||
319ecf12 SC |
384 | dest_index = qlcnic_is_valid_nic_func(adapter, dest_pci_func); |
385 | if (dest_index < 0) | |
ec079a07 SC |
386 | return QL_STATUS_INVALID_PARAM; |
387 | ||
319ecf12 SC |
388 | s_esw_id = adapter->npars[src_index].phy_port; |
389 | d_esw_id = adapter->npars[dest_index].phy_port; | |
ec079a07 SC |
390 | |
391 | if (s_esw_id != d_esw_id) | |
392 | return QL_STATUS_INVALID_PARAM; | |
ec079a07 | 393 | } |
ec079a07 | 394 | |
319ecf12 | 395 | return 0; |
ec079a07 SC |
396 | } |
397 | ||
b66e29c9 SC |
398 | static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp, |
399 | struct kobject *kobj, | |
400 | struct bin_attribute *attr, | |
401 | char *buf, loff_t offset, | |
402 | size_t size) | |
ec079a07 SC |
403 | { |
404 | struct device *dev = container_of(kobj, struct device, kobj); | |
405 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
406 | struct qlcnic_pm_func_cfg *pm_cfg; | |
407 | u32 id, action, pci_func; | |
319ecf12 | 408 | int count, rem, i, ret, index; |
ec079a07 SC |
409 | |
410 | count = size / sizeof(struct qlcnic_pm_func_cfg); | |
411 | rem = size % sizeof(struct qlcnic_pm_func_cfg); | |
412 | if (rem) | |
413 | return QL_STATUS_INVALID_PARAM; | |
414 | ||
b66e29c9 | 415 | pm_cfg = (struct qlcnic_pm_func_cfg *)buf; |
ec079a07 | 416 | ret = validate_pm_config(adapter, pm_cfg, count); |
319ecf12 | 417 | |
ec079a07 SC |
418 | if (ret) |
419 | return ret; | |
420 | for (i = 0; i < count; i++) { | |
421 | pci_func = pm_cfg[i].pci_func; | |
422 | action = !!pm_cfg[i].action; | |
319ecf12 SC |
423 | index = qlcnic_is_valid_nic_func(adapter, pci_func); |
424 | if (index < 0) | |
425 | return QL_STATUS_INVALID_PARAM; | |
426 | ||
427 | id = adapter->npars[index].phy_port; | |
428 | ret = qlcnic_config_port_mirroring(adapter, id, | |
429 | action, pci_func); | |
ec079a07 SC |
430 | if (ret) |
431 | return ret; | |
432 | } | |
433 | ||
434 | for (i = 0; i < count; i++) { | |
435 | pci_func = pm_cfg[i].pci_func; | |
319ecf12 | 436 | index = qlcnic_is_valid_nic_func(adapter, pci_func); |
2f514c52 JK |
437 | if (index < 0) |
438 | return QL_STATUS_INVALID_PARAM; | |
319ecf12 SC |
439 | id = adapter->npars[index].phy_port; |
440 | adapter->npars[index].enable_pm = !!pm_cfg[i].action; | |
441 | adapter->npars[index].dest_npar = id; | |
ec079a07 | 442 | } |
319ecf12 | 443 | |
ec079a07 SC |
444 | return size; |
445 | } | |
446 | ||
b66e29c9 SC |
447 | static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp, |
448 | struct kobject *kobj, | |
449 | struct bin_attribute *attr, | |
450 | char *buf, loff_t offset, | |
451 | size_t size) | |
ec079a07 SC |
452 | { |
453 | struct device *dev = container_of(kobj, struct device, kobj); | |
454 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
2f514c52 | 455 | struct qlcnic_pm_func_cfg *pm_cfg; |
319ecf12 | 456 | u8 pci_func; |
d91abf90 JK |
457 | u32 count; |
458 | int i; | |
ec079a07 | 459 | |
d91abf90 | 460 | memset(buf, 0, size); |
2f514c52 | 461 | pm_cfg = (struct qlcnic_pm_func_cfg *)buf; |
d91abf90 JK |
462 | count = size / sizeof(struct qlcnic_pm_func_cfg); |
463 | for (i = 0; i < adapter->ahw->total_nic_func; i++) { | |
319ecf12 | 464 | pci_func = adapter->npars[i].pci_func; |
d91abf90 JK |
465 | if (pci_func >= count) { |
466 | dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", | |
467 | __func__, adapter->ahw->total_nic_func, count); | |
35dafcb0 | 468 | continue; |
d91abf90 | 469 | } |
35dafcb0 SC |
470 | if (!adapter->npars[i].eswitch_status) |
471 | continue; | |
472 | ||
319ecf12 SC |
473 | pm_cfg[pci_func].action = adapter->npars[i].enable_pm; |
474 | pm_cfg[pci_func].dest_npar = 0; | |
475 | pm_cfg[pci_func].pci_func = i; | |
ec079a07 | 476 | } |
ec079a07 SC |
477 | return size; |
478 | } | |
479 | ||
b66e29c9 SC |
480 | static int validate_esw_config(struct qlcnic_adapter *adapter, |
481 | struct qlcnic_esw_func_cfg *esw_cfg, int count) | |
ec079a07 | 482 | { |
2f514c52 JK |
483 | struct qlcnic_hardware_context *ahw = adapter->ahw; |
484 | int i, ret; | |
ec079a07 SC |
485 | u32 op_mode; |
486 | u8 pci_func; | |
ec079a07 | 487 | |
319ecf12 | 488 | if (qlcnic_82xx_check(adapter)) |
2f514c52 | 489 | op_mode = readl(ahw->pci_base0 + QLCNIC_DRV_OP_MODE); |
319ecf12 | 490 | else |
2f514c52 | 491 | op_mode = QLCRDX(ahw, QLC_83XX_DRV_OP_MODE); |
ec079a07 SC |
492 | |
493 | for (i = 0; i < count; i++) { | |
494 | pci_func = esw_cfg[i].pci_func; | |
d91abf90 | 495 | if (pci_func >= ahw->max_vnic_func) |
ec079a07 SC |
496 | return QL_STATUS_INVALID_PARAM; |
497 | ||
319ecf12 SC |
498 | if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) |
499 | if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0) | |
ec079a07 SC |
500 | return QL_STATUS_INVALID_PARAM; |
501 | ||
502 | switch (esw_cfg[i].op_mode) { | |
503 | case QLCNIC_PORT_DEFAULTS: | |
319ecf12 SC |
504 | if (qlcnic_82xx_check(adapter)) { |
505 | ret = QLC_DEV_GET_DRV(op_mode, pci_func); | |
506 | } else { | |
507 | ret = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode, | |
508 | pci_func); | |
509 | esw_cfg[i].offload_flags = 0; | |
510 | } | |
511 | ||
512 | if (ret != QLCNIC_NON_PRIV_FUNC) { | |
ec079a07 SC |
513 | if (esw_cfg[i].mac_anti_spoof != 0) |
514 | return QL_STATUS_INVALID_PARAM; | |
515 | if (esw_cfg[i].mac_override != 1) | |
516 | return QL_STATUS_INVALID_PARAM; | |
517 | if (esw_cfg[i].promisc_mode != 1) | |
518 | return QL_STATUS_INVALID_PARAM; | |
519 | } | |
520 | break; | |
521 | case QLCNIC_ADD_VLAN: | |
522 | if (!IS_VALID_VLAN(esw_cfg[i].vlan_id)) | |
523 | return QL_STATUS_INVALID_PARAM; | |
524 | if (!esw_cfg[i].op_type) | |
525 | return QL_STATUS_INVALID_PARAM; | |
526 | break; | |
527 | case QLCNIC_DEL_VLAN: | |
528 | if (!esw_cfg[i].op_type) | |
529 | return QL_STATUS_INVALID_PARAM; | |
530 | break; | |
531 | default: | |
532 | return QL_STATUS_INVALID_PARAM; | |
533 | } | |
534 | } | |
319ecf12 | 535 | |
ec079a07 SC |
536 | return 0; |
537 | } | |
538 | ||
b66e29c9 SC |
539 | static ssize_t qlcnic_sysfs_write_esw_config(struct file *file, |
540 | struct kobject *kobj, | |
541 | struct bin_attribute *attr, | |
542 | char *buf, loff_t offset, | |
543 | size_t size) | |
ec079a07 SC |
544 | { |
545 | struct device *dev = container_of(kobj, struct device, kobj); | |
546 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
547 | struct qlcnic_esw_func_cfg *esw_cfg; | |
548 | struct qlcnic_npar_info *npar; | |
549 | int count, rem, i, ret; | |
319ecf12 SC |
550 | int index; |
551 | u8 op_mode = 0, pci_func; | |
ec079a07 SC |
552 | |
553 | count = size / sizeof(struct qlcnic_esw_func_cfg); | |
554 | rem = size % sizeof(struct qlcnic_esw_func_cfg); | |
555 | if (rem) | |
556 | return QL_STATUS_INVALID_PARAM; | |
557 | ||
b66e29c9 | 558 | esw_cfg = (struct qlcnic_esw_func_cfg *)buf; |
ec079a07 SC |
559 | ret = validate_esw_config(adapter, esw_cfg, count); |
560 | if (ret) | |
561 | return ret; | |
562 | ||
563 | for (i = 0; i < count; i++) { | |
319ecf12 | 564 | if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) |
ec079a07 SC |
565 | if (qlcnic_config_switch_port(adapter, &esw_cfg[i])) |
566 | return QL_STATUS_INVALID_PARAM; | |
567 | ||
568 | if (adapter->ahw->pci_func != esw_cfg[i].pci_func) | |
569 | continue; | |
570 | ||
571 | op_mode = esw_cfg[i].op_mode; | |
572 | qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]); | |
573 | esw_cfg[i].op_mode = op_mode; | |
574 | esw_cfg[i].pci_func = adapter->ahw->pci_func; | |
575 | ||
576 | switch (esw_cfg[i].op_mode) { | |
577 | case QLCNIC_PORT_DEFAULTS: | |
578 | qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]); | |
147a9088 SS |
579 | rtnl_lock(); |
580 | qlcnic_set_netdev_features(adapter, &esw_cfg[i]); | |
581 | rtnl_unlock(); | |
ec079a07 SC |
582 | break; |
583 | case QLCNIC_ADD_VLAN: | |
584 | qlcnic_set_vlan_config(adapter, &esw_cfg[i]); | |
585 | break; | |
586 | case QLCNIC_DEL_VLAN: | |
587 | esw_cfg[i].vlan_id = 0; | |
588 | qlcnic_set_vlan_config(adapter, &esw_cfg[i]); | |
589 | break; | |
590 | } | |
591 | } | |
592 | ||
79788450 | 593 | if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) |
ec079a07 SC |
594 | goto out; |
595 | ||
596 | for (i = 0; i < count; i++) { | |
597 | pci_func = esw_cfg[i].pci_func; | |
319ecf12 | 598 | index = qlcnic_is_valid_nic_func(adapter, pci_func); |
2f514c52 JK |
599 | if (index < 0) |
600 | return QL_STATUS_INVALID_PARAM; | |
319ecf12 | 601 | npar = &adapter->npars[index]; |
ec079a07 SC |
602 | switch (esw_cfg[i].op_mode) { |
603 | case QLCNIC_PORT_DEFAULTS: | |
604 | npar->promisc_mode = esw_cfg[i].promisc_mode; | |
605 | npar->mac_override = esw_cfg[i].mac_override; | |
606 | npar->offload_flags = esw_cfg[i].offload_flags; | |
607 | npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof; | |
608 | npar->discard_tagged = esw_cfg[i].discard_tagged; | |
609 | break; | |
610 | case QLCNIC_ADD_VLAN: | |
611 | npar->pvid = esw_cfg[i].vlan_id; | |
612 | break; | |
613 | case QLCNIC_DEL_VLAN: | |
614 | npar->pvid = 0; | |
615 | break; | |
616 | } | |
617 | } | |
618 | out: | |
619 | return size; | |
620 | } | |
621 | ||
b66e29c9 SC |
622 | static ssize_t qlcnic_sysfs_read_esw_config(struct file *file, |
623 | struct kobject *kobj, | |
624 | struct bin_attribute *attr, | |
625 | char *buf, loff_t offset, | |
626 | size_t size) | |
ec079a07 SC |
627 | { |
628 | struct device *dev = container_of(kobj, struct device, kobj); | |
629 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
2f514c52 | 630 | struct qlcnic_esw_func_cfg *esw_cfg; |
d91abf90 JK |
631 | u8 pci_func; |
632 | u32 count; | |
633 | int i; | |
ec079a07 | 634 | |
d91abf90 | 635 | memset(buf, 0, size); |
2f514c52 | 636 | esw_cfg = (struct qlcnic_esw_func_cfg *)buf; |
d91abf90 JK |
637 | count = size / sizeof(struct qlcnic_esw_func_cfg); |
638 | for (i = 0; i < adapter->ahw->total_nic_func; i++) { | |
319ecf12 | 639 | pci_func = adapter->npars[i].pci_func; |
d91abf90 JK |
640 | if (pci_func >= count) { |
641 | dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", | |
642 | __func__, adapter->ahw->total_nic_func, count); | |
35dafcb0 | 643 | continue; |
d91abf90 | 644 | } |
35dafcb0 SC |
645 | if (!adapter->npars[i].eswitch_status) |
646 | continue; | |
647 | ||
319ecf12 SC |
648 | esw_cfg[pci_func].pci_func = pci_func; |
649 | if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func])) | |
ec079a07 SC |
650 | return QL_STATUS_INVALID_PARAM; |
651 | } | |
ec079a07 SC |
652 | return size; |
653 | } | |
654 | ||
b66e29c9 SC |
655 | static int validate_npar_config(struct qlcnic_adapter *adapter, |
656 | struct qlcnic_npar_func_cfg *np_cfg, | |
657 | int count) | |
ec079a07 SC |
658 | { |
659 | u8 pci_func, i; | |
660 | ||
661 | for (i = 0; i < count; i++) { | |
662 | pci_func = np_cfg[i].pci_func; | |
319ecf12 | 663 | if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0) |
ec079a07 SC |
664 | return QL_STATUS_INVALID_PARAM; |
665 | ||
666 | if (!IS_VALID_BW(np_cfg[i].min_bw) || | |
667 | !IS_VALID_BW(np_cfg[i].max_bw)) | |
668 | return QL_STATUS_INVALID_PARAM; | |
669 | } | |
670 | return 0; | |
671 | } | |
672 | ||
b66e29c9 SC |
673 | static ssize_t qlcnic_sysfs_write_npar_config(struct file *file, |
674 | struct kobject *kobj, | |
675 | struct bin_attribute *attr, | |
676 | char *buf, loff_t offset, | |
677 | size_t size) | |
ec079a07 SC |
678 | { |
679 | struct device *dev = container_of(kobj, struct device, kobj); | |
680 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
681 | struct qlcnic_info nic_info; | |
682 | struct qlcnic_npar_func_cfg *np_cfg; | |
319ecf12 | 683 | int i, count, rem, ret, index; |
ec079a07 SC |
684 | u8 pci_func; |
685 | ||
686 | count = size / sizeof(struct qlcnic_npar_func_cfg); | |
687 | rem = size % sizeof(struct qlcnic_npar_func_cfg); | |
688 | if (rem) | |
689 | return QL_STATUS_INVALID_PARAM; | |
690 | ||
b66e29c9 | 691 | np_cfg = (struct qlcnic_npar_func_cfg *)buf; |
ec079a07 SC |
692 | ret = validate_npar_config(adapter, np_cfg, count); |
693 | if (ret) | |
694 | return ret; | |
695 | ||
319ecf12 | 696 | for (i = 0; i < count; i++) { |
ec079a07 | 697 | pci_func = np_cfg[i].pci_func; |
319ecf12 SC |
698 | |
699 | memset(&nic_info, 0, sizeof(struct qlcnic_info)); | |
ec079a07 SC |
700 | ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func); |
701 | if (ret) | |
702 | return ret; | |
703 | nic_info.pci_func = pci_func; | |
704 | nic_info.min_tx_bw = np_cfg[i].min_bw; | |
705 | nic_info.max_tx_bw = np_cfg[i].max_bw; | |
706 | ret = qlcnic_set_nic_info(adapter, &nic_info); | |
707 | if (ret) | |
708 | return ret; | |
319ecf12 | 709 | index = qlcnic_is_valid_nic_func(adapter, pci_func); |
2f514c52 JK |
710 | if (index < 0) |
711 | return QL_STATUS_INVALID_PARAM; | |
319ecf12 SC |
712 | adapter->npars[index].min_bw = nic_info.min_tx_bw; |
713 | adapter->npars[index].max_bw = nic_info.max_tx_bw; | |
ec079a07 SC |
714 | } |
715 | ||
716 | return size; | |
ec079a07 | 717 | } |
b66e29c9 SC |
718 | |
719 | static ssize_t qlcnic_sysfs_read_npar_config(struct file *file, | |
720 | struct kobject *kobj, | |
721 | struct bin_attribute *attr, | |
722 | char *buf, loff_t offset, | |
723 | size_t size) | |
ec079a07 SC |
724 | { |
725 | struct device *dev = container_of(kobj, struct device, kobj); | |
726 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
2f514c52 | 727 | struct qlcnic_npar_func_cfg *np_cfg; |
ec079a07 | 728 | struct qlcnic_info nic_info; |
4f030227 | 729 | u8 pci_func; |
ec079a07 | 730 | int i, ret; |
d91abf90 | 731 | u32 count; |
ec079a07 | 732 | |
319ecf12 | 733 | memset(&nic_info, 0, sizeof(struct qlcnic_info)); |
d91abf90 | 734 | memset(buf, 0, size); |
2f514c52 | 735 | np_cfg = (struct qlcnic_npar_func_cfg *)buf; |
319ecf12 | 736 | |
d91abf90 JK |
737 | count = size / sizeof(struct qlcnic_npar_func_cfg); |
738 | for (i = 0; i < adapter->ahw->total_nic_func; i++) { | |
d91abf90 JK |
739 | if (adapter->npars[i].pci_func >= count) { |
740 | dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", | |
741 | __func__, adapter->ahw->total_nic_func, count); | |
742 | continue; | |
743 | } | |
35dafcb0 SC |
744 | if (!adapter->npars[i].eswitch_status) |
745 | continue; | |
4f030227 JK |
746 | pci_func = adapter->npars[i].pci_func; |
747 | if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0) | |
748 | continue; | |
749 | ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func); | |
750 | if (ret) | |
751 | return ret; | |
752 | ||
753 | np_cfg[pci_func].pci_func = pci_func; | |
754 | np_cfg[pci_func].op_mode = (u8)nic_info.op_mode; | |
755 | np_cfg[pci_func].port_num = nic_info.phys_port; | |
756 | np_cfg[pci_func].fw_capab = nic_info.capabilities; | |
757 | np_cfg[pci_func].min_bw = nic_info.min_tx_bw; | |
758 | np_cfg[pci_func].max_bw = nic_info.max_tx_bw; | |
759 | np_cfg[pci_func].max_tx_queues = nic_info.max_tx_ques; | |
760 | np_cfg[pci_func].max_rx_queues = nic_info.max_rx_ques; | |
ec079a07 | 761 | } |
ec079a07 SC |
762 | return size; |
763 | } | |
764 | ||
b66e29c9 SC |
765 | static ssize_t qlcnic_sysfs_get_port_stats(struct file *file, |
766 | struct kobject *kobj, | |
767 | struct bin_attribute *attr, | |
768 | char *buf, loff_t offset, | |
769 | size_t size) | |
ec079a07 SC |
770 | { |
771 | struct device *dev = container_of(kobj, struct device, kobj); | |
772 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
773 | struct qlcnic_esw_statistics port_stats; | |
774 | int ret; | |
775 | ||
319ecf12 SC |
776 | if (qlcnic_83xx_check(adapter)) |
777 | return QLC_STATUS_UNSUPPORTED_CMD; | |
778 | ||
ec079a07 SC |
779 | if (size != sizeof(struct qlcnic_esw_statistics)) |
780 | return QL_STATUS_INVALID_PARAM; | |
781 | ||
d91abf90 | 782 | if (offset >= adapter->ahw->max_vnic_func) |
ec079a07 SC |
783 | return QL_STATUS_INVALID_PARAM; |
784 | ||
785 | memset(&port_stats, 0, size); | |
786 | ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER, | |
b66e29c9 | 787 | &port_stats.rx); |
ec079a07 SC |
788 | if (ret) |
789 | return ret; | |
790 | ||
791 | ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER, | |
b66e29c9 | 792 | &port_stats.tx); |
ec079a07 SC |
793 | if (ret) |
794 | return ret; | |
795 | ||
796 | memcpy(buf, &port_stats, size); | |
797 | return size; | |
798 | } | |
799 | ||
b66e29c9 SC |
800 | static ssize_t qlcnic_sysfs_get_esw_stats(struct file *file, |
801 | struct kobject *kobj, | |
802 | struct bin_attribute *attr, | |
803 | char *buf, loff_t offset, | |
804 | size_t size) | |
ec079a07 SC |
805 | { |
806 | struct device *dev = container_of(kobj, struct device, kobj); | |
807 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
808 | struct qlcnic_esw_statistics esw_stats; | |
809 | int ret; | |
810 | ||
319ecf12 SC |
811 | if (qlcnic_83xx_check(adapter)) |
812 | return QLC_STATUS_UNSUPPORTED_CMD; | |
813 | ||
ec079a07 SC |
814 | if (size != sizeof(struct qlcnic_esw_statistics)) |
815 | return QL_STATUS_INVALID_PARAM; | |
816 | ||
817 | if (offset >= QLCNIC_NIU_MAX_XG_PORTS) | |
818 | return QL_STATUS_INVALID_PARAM; | |
819 | ||
820 | memset(&esw_stats, 0, size); | |
821 | ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER, | |
b66e29c9 | 822 | &esw_stats.rx); |
ec079a07 SC |
823 | if (ret) |
824 | return ret; | |
825 | ||
826 | ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER, | |
b66e29c9 | 827 | &esw_stats.tx); |
ec079a07 SC |
828 | if (ret) |
829 | return ret; | |
830 | ||
831 | memcpy(buf, &esw_stats, size); | |
832 | return size; | |
833 | } | |
834 | ||
b66e29c9 SC |
835 | static ssize_t qlcnic_sysfs_clear_esw_stats(struct file *file, |
836 | struct kobject *kobj, | |
837 | struct bin_attribute *attr, | |
838 | char *buf, loff_t offset, | |
839 | size_t size) | |
ec079a07 SC |
840 | { |
841 | struct device *dev = container_of(kobj, struct device, kobj); | |
842 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
843 | int ret; | |
844 | ||
319ecf12 SC |
845 | if (qlcnic_83xx_check(adapter)) |
846 | return QLC_STATUS_UNSUPPORTED_CMD; | |
847 | ||
ec079a07 SC |
848 | if (offset >= QLCNIC_NIU_MAX_XG_PORTS) |
849 | return QL_STATUS_INVALID_PARAM; | |
850 | ||
851 | ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset, | |
b66e29c9 | 852 | QLCNIC_QUERY_RX_COUNTER); |
ec079a07 SC |
853 | if (ret) |
854 | return ret; | |
855 | ||
856 | ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset, | |
b66e29c9 | 857 | QLCNIC_QUERY_TX_COUNTER); |
ec079a07 SC |
858 | if (ret) |
859 | return ret; | |
860 | ||
861 | return size; | |
862 | } | |
863 | ||
b66e29c9 SC |
864 | static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file, |
865 | struct kobject *kobj, | |
866 | struct bin_attribute *attr, | |
867 | char *buf, loff_t offset, | |
868 | size_t size) | |
ec079a07 | 869 | { |
319ecf12 | 870 | |
ec079a07 SC |
871 | struct device *dev = container_of(kobj, struct device, kobj); |
872 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
873 | int ret; | |
874 | ||
319ecf12 SC |
875 | if (qlcnic_83xx_check(adapter)) |
876 | return QLC_STATUS_UNSUPPORTED_CMD; | |
877 | ||
d91abf90 | 878 | if (offset >= adapter->ahw->max_vnic_func) |
ec079a07 SC |
879 | return QL_STATUS_INVALID_PARAM; |
880 | ||
881 | ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset, | |
b66e29c9 | 882 | QLCNIC_QUERY_RX_COUNTER); |
ec079a07 SC |
883 | if (ret) |
884 | return ret; | |
885 | ||
886 | ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset, | |
b66e29c9 | 887 | QLCNIC_QUERY_TX_COUNTER); |
ec079a07 SC |
888 | if (ret) |
889 | return ret; | |
890 | ||
891 | return size; | |
892 | } | |
893 | ||
b66e29c9 SC |
894 | static ssize_t qlcnic_sysfs_read_pci_config(struct file *file, |
895 | struct kobject *kobj, | |
896 | struct bin_attribute *attr, | |
897 | char *buf, loff_t offset, | |
898 | size_t size) | |
ec079a07 SC |
899 | { |
900 | struct device *dev = container_of(kobj, struct device, kobj); | |
901 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
2f514c52 | 902 | struct qlcnic_pci_func_cfg *pci_cfg; |
ec079a07 SC |
903 | struct qlcnic_pci_info *pci_info; |
904 | int i, ret; | |
d91abf90 | 905 | u32 count; |
ec079a07 | 906 | |
d91abf90 | 907 | pci_info = kcalloc(size, sizeof(*pci_info), GFP_KERNEL); |
ec079a07 SC |
908 | if (!pci_info) |
909 | return -ENOMEM; | |
910 | ||
911 | ret = qlcnic_get_pci_info(adapter, pci_info); | |
912 | if (ret) { | |
f3c0773f | 913 | kfree(pci_info); |
ec079a07 SC |
914 | return ret; |
915 | } | |
916 | ||
f3c0773f | 917 | pci_cfg = (struct qlcnic_pci_func_cfg *)buf; |
d91abf90 JK |
918 | count = size / sizeof(struct qlcnic_pci_func_cfg); |
919 | for (i = 0; i < count; i++) { | |
ec079a07 SC |
920 | pci_cfg[i].pci_func = pci_info[i].id; |
921 | pci_cfg[i].func_type = pci_info[i].type; | |
f3c0773f | 922 | pci_cfg[i].func_state = 0; |
ec079a07 SC |
923 | pci_cfg[i].port_num = pci_info[i].default_port; |
924 | pci_cfg[i].min_bw = pci_info[i].tx_min_bw; | |
925 | pci_cfg[i].max_bw = pci_info[i].tx_max_bw; | |
926 | memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN); | |
927 | } | |
319ecf12 | 928 | |
f3c0773f | 929 | kfree(pci_info); |
ec079a07 SC |
930 | return size; |
931 | } | |
932 | ||
a520030e HM |
933 | static ssize_t qlcnic_83xx_sysfs_flash_read_handler(struct file *filp, |
934 | struct kobject *kobj, | |
935 | struct bin_attribute *attr, | |
936 | char *buf, loff_t offset, | |
937 | size_t size) | |
938 | { | |
939 | unsigned char *p_read_buf; | |
940 | int ret, count; | |
941 | struct device *dev = container_of(kobj, struct device, kobj); | |
942 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
943 | ||
944 | if (!size) | |
945 | return QL_STATUS_INVALID_PARAM; | |
946 | if (!buf) | |
947 | return QL_STATUS_INVALID_PARAM; | |
948 | ||
949 | count = size / sizeof(u32); | |
950 | ||
951 | if (size % sizeof(u32)) | |
952 | count++; | |
953 | ||
954 | p_read_buf = kcalloc(size, sizeof(unsigned char), GFP_KERNEL); | |
955 | if (!p_read_buf) | |
956 | return -ENOMEM; | |
957 | if (qlcnic_83xx_lock_flash(adapter) != 0) { | |
958 | kfree(p_read_buf); | |
959 | return -EIO; | |
960 | } | |
961 | ||
962 | ret = qlcnic_83xx_lockless_flash_read32(adapter, offset, p_read_buf, | |
963 | count); | |
964 | ||
965 | if (ret) { | |
966 | qlcnic_83xx_unlock_flash(adapter); | |
967 | kfree(p_read_buf); | |
968 | return ret; | |
969 | } | |
970 | ||
971 | qlcnic_83xx_unlock_flash(adapter); | |
972 | memcpy(buf, p_read_buf, size); | |
973 | kfree(p_read_buf); | |
974 | ||
975 | return size; | |
976 | } | |
977 | ||
978 | static int qlcnic_83xx_sysfs_flash_bulk_write(struct qlcnic_adapter *adapter, | |
979 | char *buf, loff_t offset, | |
980 | size_t size) | |
981 | { | |
982 | int i, ret, count; | |
983 | unsigned char *p_cache, *p_src; | |
984 | ||
985 | p_cache = kcalloc(size, sizeof(unsigned char), GFP_KERNEL); | |
986 | if (!p_cache) | |
987 | return -ENOMEM; | |
988 | ||
989 | memcpy(p_cache, buf, size); | |
990 | p_src = p_cache; | |
991 | count = size / sizeof(u32); | |
992 | ||
993 | if (qlcnic_83xx_lock_flash(adapter) != 0) { | |
994 | kfree(p_cache); | |
995 | return -EIO; | |
996 | } | |
997 | ||
998 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | |
999 | ret = qlcnic_83xx_enable_flash_write(adapter); | |
1000 | if (ret) { | |
1001 | kfree(p_cache); | |
1002 | qlcnic_83xx_unlock_flash(adapter); | |
1003 | return -EIO; | |
1004 | } | |
1005 | } | |
1006 | ||
1007 | for (i = 0; i < count / QLC_83XX_FLASH_WRITE_MAX; i++) { | |
1008 | ret = qlcnic_83xx_flash_bulk_write(adapter, offset, | |
1009 | (u32 *)p_src, | |
1010 | QLC_83XX_FLASH_WRITE_MAX); | |
1011 | ||
1012 | if (ret) { | |
1013 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | |
1014 | ret = qlcnic_83xx_disable_flash_write(adapter); | |
1015 | if (ret) { | |
1016 | kfree(p_cache); | |
1017 | qlcnic_83xx_unlock_flash(adapter); | |
1018 | return -EIO; | |
1019 | } | |
1020 | } | |
1021 | ||
1022 | kfree(p_cache); | |
1023 | qlcnic_83xx_unlock_flash(adapter); | |
1024 | return -EIO; | |
1025 | } | |
1026 | ||
1027 | p_src = p_src + sizeof(u32)*QLC_83XX_FLASH_WRITE_MAX; | |
1028 | offset = offset + sizeof(u32)*QLC_83XX_FLASH_WRITE_MAX; | |
1029 | } | |
1030 | ||
1031 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | |
1032 | ret = qlcnic_83xx_disable_flash_write(adapter); | |
1033 | if (ret) { | |
1034 | kfree(p_cache); | |
1035 | qlcnic_83xx_unlock_flash(adapter); | |
1036 | return -EIO; | |
1037 | } | |
1038 | } | |
1039 | ||
1040 | kfree(p_cache); | |
1041 | qlcnic_83xx_unlock_flash(adapter); | |
1042 | ||
1043 | return 0; | |
1044 | } | |
1045 | ||
1046 | static int qlcnic_83xx_sysfs_flash_write(struct qlcnic_adapter *adapter, | |
1047 | char *buf, loff_t offset, size_t size) | |
1048 | { | |
1049 | int i, ret, count; | |
1050 | unsigned char *p_cache, *p_src; | |
1051 | ||
1052 | p_cache = kcalloc(size, sizeof(unsigned char), GFP_KERNEL); | |
1053 | if (!p_cache) | |
1054 | return -ENOMEM; | |
1055 | ||
1056 | memcpy(p_cache, buf, size); | |
1057 | p_src = p_cache; | |
1058 | count = size / sizeof(u32); | |
1059 | ||
1060 | if (qlcnic_83xx_lock_flash(adapter) != 0) { | |
1061 | kfree(p_cache); | |
1062 | return -EIO; | |
1063 | } | |
1064 | ||
1065 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | |
1066 | ret = qlcnic_83xx_enable_flash_write(adapter); | |
1067 | if (ret) { | |
1068 | kfree(p_cache); | |
1069 | qlcnic_83xx_unlock_flash(adapter); | |
1070 | return -EIO; | |
1071 | } | |
1072 | } | |
1073 | ||
1074 | for (i = 0; i < count; i++) { | |
1075 | ret = qlcnic_83xx_flash_write32(adapter, offset, (u32 *)p_src); | |
1076 | if (ret) { | |
1077 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | |
1078 | ret = qlcnic_83xx_disable_flash_write(adapter); | |
1079 | if (ret) { | |
1080 | kfree(p_cache); | |
1081 | qlcnic_83xx_unlock_flash(adapter); | |
1082 | return -EIO; | |
1083 | } | |
1084 | } | |
1085 | kfree(p_cache); | |
1086 | qlcnic_83xx_unlock_flash(adapter); | |
1087 | return -EIO; | |
1088 | } | |
1089 | ||
1090 | p_src = p_src + sizeof(u32); | |
1091 | offset = offset + sizeof(u32); | |
1092 | } | |
1093 | ||
1094 | if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) { | |
1095 | ret = qlcnic_83xx_disable_flash_write(adapter); | |
1096 | if (ret) { | |
1097 | kfree(p_cache); | |
1098 | qlcnic_83xx_unlock_flash(adapter); | |
1099 | return -EIO; | |
1100 | } | |
1101 | } | |
1102 | ||
1103 | kfree(p_cache); | |
1104 | qlcnic_83xx_unlock_flash(adapter); | |
1105 | ||
1106 | return 0; | |
1107 | } | |
1108 | ||
1109 | static ssize_t qlcnic_83xx_sysfs_flash_write_handler(struct file *filp, | |
1110 | struct kobject *kobj, | |
1111 | struct bin_attribute *attr, | |
1112 | char *buf, loff_t offset, | |
1113 | size_t size) | |
1114 | { | |
1115 | int ret; | |
1116 | static int flash_mode; | |
1117 | unsigned long data; | |
1118 | struct device *dev = container_of(kobj, struct device, kobj); | |
1119 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
1120 | ||
1121 | if (!buf) | |
1122 | return QL_STATUS_INVALID_PARAM; | |
1123 | ||
1124 | ret = kstrtoul(buf, 16, &data); | |
1125 | ||
1126 | switch (data) { | |
1127 | case QLC_83XX_FLASH_SECTOR_ERASE_CMD: | |
1128 | flash_mode = QLC_83XX_ERASE_MODE; | |
1129 | ret = qlcnic_83xx_erase_flash_sector(adapter, offset); | |
1130 | if (ret) { | |
1131 | dev_err(&adapter->pdev->dev, | |
1132 | "%s failed at %d\n", __func__, __LINE__); | |
1133 | return -EIO; | |
1134 | } | |
1135 | break; | |
1136 | ||
1137 | case QLC_83XX_FLASH_BULK_WRITE_CMD: | |
1138 | flash_mode = QLC_83XX_BULK_WRITE_MODE; | |
1139 | break; | |
1140 | ||
1141 | case QLC_83XX_FLASH_WRITE_CMD: | |
1142 | flash_mode = QLC_83XX_WRITE_MODE; | |
1143 | break; | |
1144 | default: | |
1145 | if (flash_mode == QLC_83XX_BULK_WRITE_MODE) { | |
1146 | ret = qlcnic_83xx_sysfs_flash_bulk_write(adapter, buf, | |
1147 | offset, size); | |
1148 | if (ret) { | |
1149 | dev_err(&adapter->pdev->dev, | |
1150 | "%s failed at %d\n", | |
1151 | __func__, __LINE__); | |
1152 | return -EIO; | |
1153 | } | |
1154 | } | |
1155 | ||
1156 | if (flash_mode == QLC_83XX_WRITE_MODE) { | |
1157 | ret = qlcnic_83xx_sysfs_flash_write(adapter, buf, | |
1158 | offset, size); | |
1159 | if (ret) { | |
1160 | dev_err(&adapter->pdev->dev, | |
1161 | "%s failed at %d\n", __func__, | |
1162 | __LINE__); | |
1163 | return -EIO; | |
1164 | } | |
1165 | } | |
1166 | } | |
1167 | ||
1168 | return size; | |
1169 | } | |
1170 | ||
ec079a07 SC |
1171 | static struct device_attribute dev_attr_bridged_mode = { |
1172 | .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)}, | |
1173 | .show = qlcnic_show_bridged_mode, | |
1174 | .store = qlcnic_store_bridged_mode, | |
1175 | }; | |
1176 | ||
1177 | static struct device_attribute dev_attr_diag_mode = { | |
1178 | .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)}, | |
1179 | .show = qlcnic_show_diag_mode, | |
1180 | .store = qlcnic_store_diag_mode, | |
1181 | }; | |
1182 | ||
1183 | static struct device_attribute dev_attr_beacon = { | |
1184 | .attr = {.name = "beacon", .mode = (S_IRUGO | S_IWUSR)}, | |
1185 | .show = qlcnic_show_beacon, | |
1186 | .store = qlcnic_store_beacon, | |
1187 | }; | |
1188 | ||
1189 | static struct bin_attribute bin_attr_crb = { | |
1190 | .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)}, | |
1191 | .size = 0, | |
1192 | .read = qlcnic_sysfs_read_crb, | |
1193 | .write = qlcnic_sysfs_write_crb, | |
1194 | }; | |
1195 | ||
1196 | static struct bin_attribute bin_attr_mem = { | |
1197 | .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)}, | |
1198 | .size = 0, | |
1199 | .read = qlcnic_sysfs_read_mem, | |
1200 | .write = qlcnic_sysfs_write_mem, | |
1201 | }; | |
1202 | ||
1203 | static struct bin_attribute bin_attr_npar_config = { | |
1204 | .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)}, | |
1205 | .size = 0, | |
1206 | .read = qlcnic_sysfs_read_npar_config, | |
1207 | .write = qlcnic_sysfs_write_npar_config, | |
1208 | }; | |
1209 | ||
1210 | static struct bin_attribute bin_attr_pci_config = { | |
1211 | .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)}, | |
1212 | .size = 0, | |
1213 | .read = qlcnic_sysfs_read_pci_config, | |
1214 | .write = NULL, | |
1215 | }; | |
1216 | ||
1217 | static struct bin_attribute bin_attr_port_stats = { | |
1218 | .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)}, | |
1219 | .size = 0, | |
1220 | .read = qlcnic_sysfs_get_port_stats, | |
1221 | .write = qlcnic_sysfs_clear_port_stats, | |
1222 | }; | |
1223 | ||
1224 | static struct bin_attribute bin_attr_esw_stats = { | |
1225 | .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)}, | |
1226 | .size = 0, | |
1227 | .read = qlcnic_sysfs_get_esw_stats, | |
1228 | .write = qlcnic_sysfs_clear_esw_stats, | |
1229 | }; | |
1230 | ||
1231 | static struct bin_attribute bin_attr_esw_config = { | |
1232 | .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)}, | |
1233 | .size = 0, | |
1234 | .read = qlcnic_sysfs_read_esw_config, | |
1235 | .write = qlcnic_sysfs_write_esw_config, | |
1236 | }; | |
1237 | ||
1238 | static struct bin_attribute bin_attr_pm_config = { | |
1239 | .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)}, | |
1240 | .size = 0, | |
1241 | .read = qlcnic_sysfs_read_pm_config, | |
1242 | .write = qlcnic_sysfs_write_pm_config, | |
1243 | }; | |
1244 | ||
a520030e HM |
1245 | static struct bin_attribute bin_attr_flash = { |
1246 | .attr = {.name = "flash", .mode = (S_IRUGO | S_IWUSR)}, | |
1247 | .size = 0, | |
1248 | .read = qlcnic_83xx_sysfs_flash_read_handler, | |
1249 | .write = qlcnic_83xx_sysfs_flash_write_handler, | |
1250 | }; | |
1251 | ||
1f0f467b HP |
1252 | #ifdef CONFIG_QLCNIC_HWMON |
1253 | ||
1254 | static ssize_t qlcnic_hwmon_show_temp(struct device *dev, | |
1255 | struct device_attribute *dev_attr, | |
1256 | char *buf) | |
1257 | { | |
1258 | struct qlcnic_adapter *adapter = dev_get_drvdata(dev); | |
1259 | unsigned int temperature = 0, value = 0; | |
1260 | ||
1261 | if (qlcnic_83xx_check(adapter)) | |
1262 | value = QLCRDX(adapter->ahw, QLC_83XX_ASIC_TEMP); | |
1263 | else if (qlcnic_82xx_check(adapter)) | |
1264 | value = QLC_SHARED_REG_RD32(adapter, QLCNIC_ASIC_TEMP); | |
1265 | ||
1266 | temperature = qlcnic_get_temp_val(value); | |
1267 | /* display millidegree celcius */ | |
1268 | temperature *= 1000; | |
1269 | return sprintf(buf, "%u\n", temperature); | |
1270 | } | |
1271 | ||
1272 | /* hwmon-sysfs attributes */ | |
1273 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, | |
1274 | qlcnic_hwmon_show_temp, NULL, 1); | |
1275 | ||
1276 | static struct attribute *qlcnic_hwmon_attrs[] = { | |
1277 | &sensor_dev_attr_temp1_input.dev_attr.attr, | |
1278 | NULL | |
1279 | }; | |
1280 | ||
1281 | ATTRIBUTE_GROUPS(qlcnic_hwmon); | |
1282 | ||
1283 | void qlcnic_register_hwmon_dev(struct qlcnic_adapter *adapter) | |
1284 | { | |
1285 | struct device *dev = &adapter->pdev->dev; | |
1286 | struct device *hwmon_dev; | |
1287 | ||
1288 | /* Skip hwmon registration for a VF device */ | |
1289 | if (qlcnic_sriov_vf_check(adapter)) { | |
1290 | adapter->ahw->hwmon_dev = NULL; | |
1291 | return; | |
1292 | } | |
1293 | hwmon_dev = hwmon_device_register_with_groups(dev, qlcnic_driver_name, | |
1294 | adapter, | |
1295 | qlcnic_hwmon_groups); | |
1296 | if (IS_ERR(hwmon_dev)) { | |
1297 | dev_err(dev, "Cannot register with hwmon, err=%ld\n", | |
1298 | PTR_ERR(hwmon_dev)); | |
1299 | hwmon_dev = NULL; | |
1300 | } | |
1301 | adapter->ahw->hwmon_dev = hwmon_dev; | |
1302 | } | |
1303 | ||
1304 | void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *adapter) | |
1305 | { | |
1306 | struct device *hwmon_dev = adapter->ahw->hwmon_dev; | |
1307 | if (hwmon_dev) { | |
1308 | hwmon_device_unregister(hwmon_dev); | |
1309 | adapter->ahw->hwmon_dev = NULL; | |
1310 | } | |
1311 | } | |
1312 | #endif | |
1313 | ||
ec079a07 SC |
1314 | void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter) |
1315 | { | |
1316 | struct device *dev = &adapter->pdev->dev; | |
1317 | ||
79788450 | 1318 | if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG) |
ec079a07 SC |
1319 | if (device_create_file(dev, &dev_attr_bridged_mode)) |
1320 | dev_warn(dev, | |
b66e29c9 | 1321 | "failed to create bridged_mode sysfs entry\n"); |
ec079a07 SC |
1322 | } |
1323 | ||
1324 | void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter) | |
1325 | { | |
1326 | struct device *dev = &adapter->pdev->dev; | |
1327 | ||
79788450 | 1328 | if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG) |
ec079a07 SC |
1329 | device_remove_file(dev, &dev_attr_bridged_mode); |
1330 | } | |
1331 | ||
21041400 | 1332 | static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) |
ec079a07 SC |
1333 | { |
1334 | struct device *dev = &adapter->pdev->dev; | |
ec079a07 SC |
1335 | |
1336 | if (device_create_bin_file(dev, &bin_attr_port_stats)) | |
1337 | dev_info(dev, "failed to create port stats sysfs entry"); | |
1338 | ||
79788450 | 1339 | if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) |
ec079a07 SC |
1340 | return; |
1341 | if (device_create_file(dev, &dev_attr_diag_mode)) | |
1342 | dev_info(dev, "failed to create diag_mode sysfs entry\n"); | |
1343 | if (device_create_bin_file(dev, &bin_attr_crb)) | |
1344 | dev_info(dev, "failed to create crb sysfs entry\n"); | |
1345 | if (device_create_bin_file(dev, &bin_attr_mem)) | |
1346 | dev_info(dev, "failed to create mem sysfs entry\n"); | |
1347 | ||
78ea2d97 | 1348 | if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) |
66451615 SC |
1349 | return; |
1350 | ||
ec079a07 SC |
1351 | if (device_create_bin_file(dev, &bin_attr_pci_config)) |
1352 | dev_info(dev, "failed to create pci config sysfs entry"); | |
66451615 | 1353 | |
ec079a07 SC |
1354 | if (device_create_file(dev, &dev_attr_beacon)) |
1355 | dev_info(dev, "failed to create beacon sysfs entry"); | |
1356 | ||
1357 | if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) | |
1358 | return; | |
1359 | if (device_create_bin_file(dev, &bin_attr_esw_config)) | |
1360 | dev_info(dev, "failed to create esw config sysfs entry"); | |
79788450 | 1361 | if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) |
ec079a07 SC |
1362 | return; |
1363 | if (device_create_bin_file(dev, &bin_attr_npar_config)) | |
1364 | dev_info(dev, "failed to create npar config sysfs entry"); | |
1365 | if (device_create_bin_file(dev, &bin_attr_pm_config)) | |
1366 | dev_info(dev, "failed to create pm config sysfs entry"); | |
1367 | if (device_create_bin_file(dev, &bin_attr_esw_stats)) | |
1368 | dev_info(dev, "failed to create eswitch stats sysfs entry"); | |
1369 | } | |
1370 | ||
21041400 | 1371 | static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) |
ec079a07 SC |
1372 | { |
1373 | struct device *dev = &adapter->pdev->dev; | |
ec079a07 SC |
1374 | |
1375 | device_remove_bin_file(dev, &bin_attr_port_stats); | |
1376 | ||
79788450 | 1377 | if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) |
ec079a07 SC |
1378 | return; |
1379 | device_remove_file(dev, &dev_attr_diag_mode); | |
1380 | device_remove_bin_file(dev, &bin_attr_crb); | |
1381 | device_remove_bin_file(dev, &bin_attr_mem); | |
66451615 | 1382 | |
78ea2d97 | 1383 | if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) |
66451615 SC |
1384 | return; |
1385 | ||
ec079a07 SC |
1386 | device_remove_bin_file(dev, &bin_attr_pci_config); |
1387 | device_remove_file(dev, &dev_attr_beacon); | |
1388 | if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) | |
1389 | return; | |
1390 | device_remove_bin_file(dev, &bin_attr_esw_config); | |
79788450 | 1391 | if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) |
ec079a07 SC |
1392 | return; |
1393 | device_remove_bin_file(dev, &bin_attr_npar_config); | |
1394 | device_remove_bin_file(dev, &bin_attr_pm_config); | |
1395 | device_remove_bin_file(dev, &bin_attr_esw_stats); | |
1396 | } | |
7e2cf4fe SC |
1397 | |
1398 | void qlcnic_82xx_add_sysfs(struct qlcnic_adapter *adapter) | |
1399 | { | |
1400 | qlcnic_create_diag_entries(adapter); | |
1401 | } | |
1402 | ||
1403 | void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter) | |
1404 | { | |
1405 | qlcnic_remove_diag_entries(adapter); | |
1406 | } | |
319ecf12 SC |
1407 | |
1408 | void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *adapter) | |
1409 | { | |
a520030e HM |
1410 | struct device *dev = &adapter->pdev->dev; |
1411 | ||
319ecf12 | 1412 | qlcnic_create_diag_entries(adapter); |
a520030e HM |
1413 | |
1414 | if (sysfs_create_bin_file(&dev->kobj, &bin_attr_flash)) | |
1415 | dev_info(dev, "failed to create flash sysfs entry\n"); | |
319ecf12 SC |
1416 | } |
1417 | ||
1418 | void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *adapter) | |
1419 | { | |
a520030e HM |
1420 | struct device *dev = &adapter->pdev->dev; |
1421 | ||
319ecf12 | 1422 | qlcnic_remove_diag_entries(adapter); |
a520030e | 1423 | sysfs_remove_bin_file(&dev->kobj, &bin_attr_flash); |
319ecf12 | 1424 | } |