aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSudarsana Reddy Kalluru <sudarsana.kalluru@qlogic.com>2016-05-17 06:44:26 -0400
committerDavid S. Miller <davem@davemloft.net>2016-05-17 12:29:34 -0400
commit39651abd28146fff2bfac63d68a7a56250a4aead (patch)
tree15716824ac5f57cb1d047efe4df82a9e474e7150
parentccf928249c92b04ec9527e97a7c6b2cd8cd9dc10 (diff)
qed: add support for dcbx.
This patch adds the necessary driver support for Management Firmware to configure the device/firmware with the dcbx results. Management Firmware is responsible for communicating the DCBX and driving the negotiation, but the driver has responsibility of receiving async notification and configuring the results in hw/fw. This patch also adds the dcbx support for future protocols (e.g., FCoE) as preparation to their imminent submission. Signed-off-by: Sudarsana Reddy Kalluru <sudarsana.kalluru@qlogic.com> Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/qlogic/qed/Makefile2
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed.h2
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_cxt.h10
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_dcbx.c562
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_dcbx.h80
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_dev.c105
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_hsi.h21
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_mcp.c13
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_sp.h13
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_sp_commands.c25
-rw-r--r--include/linux/qed/qed_if.h9
11 files changed, 834 insertions, 8 deletions
diff --git a/drivers/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile
index a44874562cfd..d1f157e439cf 100644
--- a/drivers/net/ethernet/qlogic/qed/Makefile
+++ b/drivers/net/ethernet/qlogic/qed/Makefile
@@ -2,5 +2,5 @@ obj-$(CONFIG_QED) := qed.o
2 2
3qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \ 3qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \
4 qed_int.o qed_main.o qed_mcp.o qed_sp_commands.o qed_spq.o qed_l2.o \ 4 qed_int.o qed_main.o qed_mcp.o qed_sp_commands.o qed_spq.o qed_l2.o \
5 qed_selftest.o 5 qed_selftest.o qed_dcbx.o
6qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o 6qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
index 77323fc70927..1042f2af854a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -367,6 +367,8 @@ struct qed_hwfn {
367 struct qed_pf_iov *pf_iov_info; 367 struct qed_pf_iov *pf_iov_info;
368 struct qed_mcp_info *mcp_info; 368 struct qed_mcp_info *mcp_info;
369 369
370 struct qed_dcbx_info *p_dcbx_info;
371
370 struct qed_hw_cid_data *p_tx_cids; 372 struct qed_hw_cid_data *p_tx_cids;
371 struct qed_hw_cid_data *p_rx_cids; 373 struct qed_hw_cid_data *p_rx_cids;
372 374
diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.h b/drivers/net/ethernet/qlogic/qed/qed_cxt.h
index 078ff3fd7920..234c0fa8db2a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.h
@@ -131,6 +131,16 @@ void qed_cxt_hw_init_pf(struct qed_hwfn *p_hwfn);
131void qed_qm_init_pf(struct qed_hwfn *p_hwfn); 131void qed_qm_init_pf(struct qed_hwfn *p_hwfn);
132 132
133/** 133/**
134 * @brief Reconfigures QM pf on the fly
135 *
136 * @param p_hwfn
137 * @param p_ptt
138 *
139 * @return int
140 */
141int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
142
143/**
134 * @brief qed_cxt_release - Release a cid 144 * @brief qed_cxt_release - Release a cid
135 * 145 *
136 * @param p_hwfn 146 * @param p_hwfn
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
new file mode 100644
index 000000000000..cbf58e1f9333
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
@@ -0,0 +1,562 @@
1/* QLogic qed NIC Driver
2 * Copyright (c) 2015 QLogic Corporation
3 *
4 * This software is available under the terms of the GNU General Public License
5 * (GPL) Version 2, available from the file COPYING in the main directory of
6 * this source tree.
7 */
8
9#include <linux/types.h>
10#include <asm/byteorder.h>
11#include <linux/bitops.h>
12#include <linux/errno.h>
13#include <linux/kernel.h>
14#include <linux/slab.h>
15#include <linux/string.h>
16#include "qed.h"
17#include "qed_cxt.h"
18#include "qed_dcbx.h"
19#include "qed_hsi.h"
20#include "qed_sp.h"
21
22#define QED_DCBX_MAX_MIB_READ_TRY (100)
23#define QED_ETH_TYPE_DEFAULT (0)
24#define QED_ETH_TYPE_ROCE (0x8915)
25#define QED_UDP_PORT_TYPE_ROCE_V2 (0x12B7)
26#define QED_ETH_TYPE_FCOE (0x8906)
27#define QED_TCP_PORT_ISCSI (0xCBC)
28
29#define QED_DCBX_INVALID_PRIORITY 0xFF
30
31/* Get Traffic Class from priority traffic class table, 4 bits represent
32 * the traffic class corresponding to the priority.
33 */
34#define QED_DCBX_PRIO2TC(prio_tc_tbl, prio) \
35 ((u32)(prio_tc_tbl >> ((7 - prio) * 4)) & 0x7)
36
37static const struct qed_dcbx_app_metadata qed_dcbx_app_update[] = {
38 {DCBX_PROTOCOL_ISCSI, "ISCSI", QED_PCI_DEFAULT},
39 {DCBX_PROTOCOL_FCOE, "FCOE", QED_PCI_DEFAULT},
40 {DCBX_PROTOCOL_ROCE, "ROCE", QED_PCI_DEFAULT},
41 {DCBX_PROTOCOL_ROCE_V2, "ROCE_V2", QED_PCI_DEFAULT},
42 {DCBX_PROTOCOL_ETH, "ETH", QED_PCI_ETH}
43};
44
45static bool qed_dcbx_app_ethtype(u32 app_info_bitmap)
46{
47 return !!(QED_MFW_GET_FIELD(app_info_bitmap, DCBX_APP_SF) ==
48 DCBX_APP_SF_ETHTYPE);
49}
50
51static bool qed_dcbx_app_port(u32 app_info_bitmap)
52{
53 return !!(QED_MFW_GET_FIELD(app_info_bitmap, DCBX_APP_SF) ==
54 DCBX_APP_SF_PORT);
55}
56
57static bool qed_dcbx_default_tlv(u32 app_info_bitmap, u16 proto_id)
58{
59 return !!(qed_dcbx_app_ethtype(app_info_bitmap) &&
60 proto_id == QED_ETH_TYPE_DEFAULT);
61}
62
63static bool qed_dcbx_iscsi_tlv(u32 app_info_bitmap, u16 proto_id)
64{
65 return !!(qed_dcbx_app_port(app_info_bitmap) &&
66 proto_id == QED_TCP_PORT_ISCSI);
67}
68
69static bool qed_dcbx_fcoe_tlv(u32 app_info_bitmap, u16 proto_id)
70{
71 return !!(qed_dcbx_app_ethtype(app_info_bitmap) &&
72 proto_id == QED_ETH_TYPE_FCOE);
73}
74
75static bool qed_dcbx_roce_tlv(u32 app_info_bitmap, u16 proto_id)
76{
77 return !!(qed_dcbx_app_ethtype(app_info_bitmap) &&
78 proto_id == QED_ETH_TYPE_ROCE);
79}
80
81static bool qed_dcbx_roce_v2_tlv(u32 app_info_bitmap, u16 proto_id)
82{
83 return !!(qed_dcbx_app_port(app_info_bitmap) &&
84 proto_id == QED_UDP_PORT_TYPE_ROCE_V2);
85}
86
87static void
88qed_dcbx_dp_protocol(struct qed_hwfn *p_hwfn, struct qed_dcbx_results *p_data)
89{
90 enum dcbx_protocol_type id;
91 int i;
92
93 DP_VERBOSE(p_hwfn, QED_MSG_DCB, "DCBX negotiated: %d\n",
94 p_data->dcbx_enabled);
95
96 for (i = 0; i < ARRAY_SIZE(qed_dcbx_app_update); i++) {
97 id = qed_dcbx_app_update[i].id;
98
99 DP_VERBOSE(p_hwfn, QED_MSG_DCB,
100 "%s info: update %d, enable %d, prio %d, tc %d, num_tc %d\n",
101 qed_dcbx_app_update[i].name, p_data->arr[id].update,
102 p_data->arr[id].enable, p_data->arr[id].priority,
103 p_data->arr[id].tc, p_hwfn->hw_info.num_tc);
104 }
105}
106
107static void
108qed_dcbx_set_params(struct qed_dcbx_results *p_data,
109 struct qed_hw_info *p_info,
110 bool enable,
111 bool update,
112 u8 prio,
113 u8 tc,
114 enum dcbx_protocol_type type,
115 enum qed_pci_personality personality)
116{
117 /* PF update ramrod data */
118 p_data->arr[type].update = update;
119 p_data->arr[type].enable = enable;
120 p_data->arr[type].priority = prio;
121 p_data->arr[type].tc = tc;
122
123 /* QM reconf data */
124 if (p_info->personality == personality) {
125 if (personality == QED_PCI_ETH)
126 p_info->non_offload_tc = tc;
127 else
128 p_info->offload_tc = tc;
129 }
130}
131
132/* Update app protocol data and hw_info fields with the TLV info */
133static void
134qed_dcbx_update_app_info(struct qed_dcbx_results *p_data,
135 struct qed_hwfn *p_hwfn,
136 bool enable,
137 bool update,
138 u8 prio, u8 tc, enum dcbx_protocol_type type)
139{
140 struct qed_hw_info *p_info = &p_hwfn->hw_info;
141 enum qed_pci_personality personality;
142 enum dcbx_protocol_type id;
143 char *name;
144 int i;
145
146 for (i = 0; i < ARRAY_SIZE(qed_dcbx_app_update); i++) {
147 id = qed_dcbx_app_update[i].id;
148
149 if (type != id)
150 continue;
151
152 personality = qed_dcbx_app_update[i].personality;
153 name = qed_dcbx_app_update[i].name;
154
155 qed_dcbx_set_params(p_data, p_info, enable, update,
156 prio, tc, type, personality);
157 }
158}
159
160static bool
161qed_dcbx_get_app_protocol_type(struct qed_hwfn *p_hwfn,
162 u32 app_prio_bitmap,
163 u16 id, enum dcbx_protocol_type *type)
164{
165 if (qed_dcbx_fcoe_tlv(app_prio_bitmap, id)) {
166 *type = DCBX_PROTOCOL_FCOE;
167 } else if (qed_dcbx_roce_tlv(app_prio_bitmap, id)) {
168 *type = DCBX_PROTOCOL_ROCE;
169 } else if (qed_dcbx_iscsi_tlv(app_prio_bitmap, id)) {
170 *type = DCBX_PROTOCOL_ISCSI;
171 } else if (qed_dcbx_default_tlv(app_prio_bitmap, id)) {
172 *type = DCBX_PROTOCOL_ETH;
173 } else if (qed_dcbx_roce_v2_tlv(app_prio_bitmap, id)) {
174 *type = DCBX_PROTOCOL_ROCE_V2;
175 } else {
176 *type = DCBX_MAX_PROTOCOL_TYPE;
177 DP_ERR(p_hwfn,
178 "No action required, App TLV id = 0x%x app_prio_bitmap = 0x%x\n",
179 id, app_prio_bitmap);
180 return false;
181 }
182
183 return true;
184}
185
186/* Parse app TLV's to update TC information in hw_info structure for
187 * reconfiguring QM. Get protocol specific data for PF update ramrod command.
188 */
189static int
190qed_dcbx_process_tlv(struct qed_hwfn *p_hwfn,
191 struct qed_dcbx_results *p_data,
192 struct dcbx_app_priority_entry *p_tbl,
193 u32 pri_tc_tbl, int count, bool dcbx_enabled)
194{
195 u8 tc, priority, priority_map;
196 enum dcbx_protocol_type type;
197 u16 protocol_id;
198 bool enable;
199 int i;
200
201 DP_VERBOSE(p_hwfn, QED_MSG_DCB, "Num APP entries = %d\n", count);
202
203 /* Parse APP TLV */
204 for (i = 0; i < count; i++) {
205 protocol_id = QED_MFW_GET_FIELD(p_tbl[i].entry,
206 DCBX_APP_PROTOCOL_ID);
207 priority_map = QED_MFW_GET_FIELD(p_tbl[i].entry,
208 DCBX_APP_PRI_MAP);
209 priority = ffs(priority_map) - 1;
210 if (priority < 0) {
211 DP_ERR(p_hwfn, "Invalid priority\n");
212 return -EINVAL;
213 }
214
215 tc = QED_DCBX_PRIO2TC(pri_tc_tbl, priority);
216 if (qed_dcbx_get_app_protocol_type(p_hwfn, p_tbl[i].entry,
217 protocol_id, &type)) {
218 /* ETH always have the enable bit reset, as it gets
219 * vlan information per packet. For other protocols,
220 * should be set according to the dcbx_enabled
221 * indication, but we only got here if there was an
222 * app tlv for the protocol, so dcbx must be enabled.
223 */
224 enable = !!(type == DCBX_PROTOCOL_ETH);
225
226 qed_dcbx_update_app_info(p_data, p_hwfn, enable, true,
227 priority, tc, type);
228 }
229 }
230
231 /* If RoCE-V2 TLV is not detected, driver need to use RoCE app
232 * data for RoCE-v2 not the default app data.
233 */
234 if (!p_data->arr[DCBX_PROTOCOL_ROCE_V2].update &&
235 p_data->arr[DCBX_PROTOCOL_ROCE].update) {
236 tc = p_data->arr[DCBX_PROTOCOL_ROCE].tc;
237 priority = p_data->arr[DCBX_PROTOCOL_ROCE].priority;
238 qed_dcbx_update_app_info(p_data, p_hwfn, true, true,
239 priority, tc, DCBX_PROTOCOL_ROCE_V2);
240 }
241
242 /* Update ramrod protocol data and hw_info fields
243 * with default info when corresponding APP TLV's are not detected.
244 * The enabled field has a different logic for ethernet as only for
245 * ethernet dcb should disabled by default, as the information arrives
246 * from the OS (unless an explicit app tlv was present).
247 */
248 tc = p_data->arr[DCBX_PROTOCOL_ETH].tc;
249 priority = p_data->arr[DCBX_PROTOCOL_ETH].priority;
250 for (type = 0; type < DCBX_MAX_PROTOCOL_TYPE; type++) {
251 if (p_data->arr[type].update)
252 continue;
253
254 enable = (type == DCBX_PROTOCOL_ETH) ? false : dcbx_enabled;
255 qed_dcbx_update_app_info(p_data, p_hwfn, enable, true,
256 priority, tc, type);
257 }
258
259 return 0;
260}
261
262/* Parse app TLV's to update TC information in hw_info structure for
263 * reconfiguring QM. Get protocol specific data for PF update ramrod command.
264 */
265static int qed_dcbx_process_mib_info(struct qed_hwfn *p_hwfn)
266{
267 struct dcbx_app_priority_feature *p_app;
268 struct dcbx_app_priority_entry *p_tbl;
269 struct qed_dcbx_results data = { 0 };
270 struct dcbx_ets_feature *p_ets;
271 struct qed_hw_info *p_info;
272 u32 pri_tc_tbl, flags;
273 bool dcbx_enabled;
274 int num_entries;
275 int rc = 0;
276
277 /* If DCBx version is non zero, then negotiation was
278 * successfuly performed
279 */
280 flags = p_hwfn->p_dcbx_info->operational.flags;
281 dcbx_enabled = !!QED_MFW_GET_FIELD(flags, DCBX_CONFIG_VERSION);
282
283 p_app = &p_hwfn->p_dcbx_info->operational.features.app;
284 p_tbl = p_app->app_pri_tbl;
285
286 p_ets = &p_hwfn->p_dcbx_info->operational.features.ets;
287 pri_tc_tbl = p_ets->pri_tc_tbl[0];
288
289 p_info = &p_hwfn->hw_info;
290 num_entries = QED_MFW_GET_FIELD(p_app->flags, DCBX_APP_NUM_ENTRIES);
291
292 rc = qed_dcbx_process_tlv(p_hwfn, &data, p_tbl, pri_tc_tbl,
293 num_entries, dcbx_enabled);
294 if (rc)
295 return rc;
296
297 p_info->num_tc = QED_MFW_GET_FIELD(p_ets->flags, DCBX_ETS_MAX_TCS);
298 data.pf_id = p_hwfn->rel_pf_id;
299 data.dcbx_enabled = dcbx_enabled;
300
301 qed_dcbx_dp_protocol(p_hwfn, &data);
302
303 memcpy(&p_hwfn->p_dcbx_info->results, &data,
304 sizeof(struct qed_dcbx_results));
305
306 return 0;
307}
308
309static int
310qed_dcbx_copy_mib(struct qed_hwfn *p_hwfn,
311 struct qed_ptt *p_ptt,
312 struct qed_dcbx_mib_meta_data *p_data,
313 enum qed_mib_read_type type)
314{
315 u32 prefix_seq_num, suffix_seq_num;
316 int read_count = 0;
317 int rc = 0;
318
319 /* The data is considered to be valid only if both sequence numbers are
320 * the same.
321 */
322 do {
323 if (type == QED_DCBX_REMOTE_LLDP_MIB) {
324 qed_memcpy_from(p_hwfn, p_ptt, p_data->lldp_remote,
325 p_data->addr, p_data->size);
326 prefix_seq_num = p_data->lldp_remote->prefix_seq_num;
327 suffix_seq_num = p_data->lldp_remote->suffix_seq_num;
328 } else {
329 qed_memcpy_from(p_hwfn, p_ptt, p_data->mib,
330 p_data->addr, p_data->size);
331 prefix_seq_num = p_data->mib->prefix_seq_num;
332 suffix_seq_num = p_data->mib->suffix_seq_num;
333 }
334 read_count++;
335
336 DP_VERBOSE(p_hwfn,
337 QED_MSG_DCB,
338 "mib type = %d, try count = %d prefix seq num = %d suffix seq num = %d\n",
339 type, read_count, prefix_seq_num, suffix_seq_num);
340 } while ((prefix_seq_num != suffix_seq_num) &&
341 (read_count < QED_DCBX_MAX_MIB_READ_TRY));
342
343 if (read_count >= QED_DCBX_MAX_MIB_READ_TRY) {
344 DP_ERR(p_hwfn,
345 "MIB read err, mib type = %d, try count = %d prefix seq num = %d suffix seq num = %d\n",
346 type, read_count, prefix_seq_num, suffix_seq_num);
347 rc = -EIO;
348 }
349
350 return rc;
351}
352
353static int
354qed_dcbx_read_local_lldp_mib(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
355{
356 struct qed_dcbx_mib_meta_data data;
357 int rc = 0;
358
359 memset(&data, 0, sizeof(data));
360 data.addr = p_hwfn->mcp_info->port_addr + offsetof(struct public_port,
361 lldp_config_params);
362 data.lldp_local = p_hwfn->p_dcbx_info->lldp_local;
363 data.size = sizeof(struct lldp_config_params_s);
364 qed_memcpy_from(p_hwfn, p_ptt, data.lldp_local, data.addr, data.size);
365
366 return rc;
367}
368
369static int
370qed_dcbx_read_remote_lldp_mib(struct qed_hwfn *p_hwfn,
371 struct qed_ptt *p_ptt,
372 enum qed_mib_read_type type)
373{
374 struct qed_dcbx_mib_meta_data data;
375 int rc = 0;
376
377 memset(&data, 0, sizeof(data));
378 data.addr = p_hwfn->mcp_info->port_addr + offsetof(struct public_port,
379 lldp_status_params);
380 data.lldp_remote = p_hwfn->p_dcbx_info->lldp_remote;
381 data.size = sizeof(struct lldp_status_params_s);
382 rc = qed_dcbx_copy_mib(p_hwfn, p_ptt, &data, type);
383
384 return rc;
385}
386
387static int
388qed_dcbx_read_operational_mib(struct qed_hwfn *p_hwfn,
389 struct qed_ptt *p_ptt,
390 enum qed_mib_read_type type)
391{
392 struct qed_dcbx_mib_meta_data data;
393 int rc = 0;
394
395 memset(&data, 0, sizeof(data));
396 data.addr = p_hwfn->mcp_info->port_addr +
397 offsetof(struct public_port, operational_dcbx_mib);
398 data.mib = &p_hwfn->p_dcbx_info->operational;
399 data.size = sizeof(struct dcbx_mib);
400 rc = qed_dcbx_copy_mib(p_hwfn, p_ptt, &data, type);
401
402 return rc;
403}
404
405static int
406qed_dcbx_read_remote_mib(struct qed_hwfn *p_hwfn,
407 struct qed_ptt *p_ptt, enum qed_mib_read_type type)
408{
409 struct qed_dcbx_mib_meta_data data;
410 int rc = 0;
411
412 memset(&data, 0, sizeof(data));
413 data.addr = p_hwfn->mcp_info->port_addr +
414 offsetof(struct public_port, remote_dcbx_mib);
415 data.mib = &p_hwfn->p_dcbx_info->remote;
416 data.size = sizeof(struct dcbx_mib);
417 rc = qed_dcbx_copy_mib(p_hwfn, p_ptt, &data, type);
418
419 return rc;
420}
421
422static int
423qed_dcbx_read_local_mib(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
424{
425 struct qed_dcbx_mib_meta_data data;
426 int rc = 0;
427
428 memset(&data, 0, sizeof(data));
429 data.addr = p_hwfn->mcp_info->port_addr +
430 offsetof(struct public_port, local_admin_dcbx_mib);
431 data.local_admin = &p_hwfn->p_dcbx_info->local_admin;
432 data.size = sizeof(struct dcbx_local_params);
433 qed_memcpy_from(p_hwfn, p_ptt, data.local_admin, data.addr, data.size);
434
435 return rc;
436}
437
438static int qed_dcbx_read_mib(struct qed_hwfn *p_hwfn,
439 struct qed_ptt *p_ptt, enum qed_mib_read_type type)
440{
441 int rc = -EINVAL;
442
443 switch (type) {
444 case QED_DCBX_OPERATIONAL_MIB:
445 rc = qed_dcbx_read_operational_mib(p_hwfn, p_ptt, type);
446 break;
447 case QED_DCBX_REMOTE_MIB:
448 rc = qed_dcbx_read_remote_mib(p_hwfn, p_ptt, type);
449 break;
450 case QED_DCBX_LOCAL_MIB:
451 rc = qed_dcbx_read_local_mib(p_hwfn, p_ptt);
452 break;
453 case QED_DCBX_REMOTE_LLDP_MIB:
454 rc = qed_dcbx_read_remote_lldp_mib(p_hwfn, p_ptt, type);
455 break;
456 case QED_DCBX_LOCAL_LLDP_MIB:
457 rc = qed_dcbx_read_local_lldp_mib(p_hwfn, p_ptt);
458 break;
459 default:
460 DP_ERR(p_hwfn, "MIB read err, unknown mib type %d\n", type);
461 }
462
463 return rc;
464}
465
466/* Read updated MIB.
467 * Reconfigure QM and invoke PF update ramrod command if operational MIB
468 * change is detected.
469 */
470int
471qed_dcbx_mib_update_event(struct qed_hwfn *p_hwfn,
472 struct qed_ptt *p_ptt, enum qed_mib_read_type type)
473{
474 int rc = 0;
475
476 rc = qed_dcbx_read_mib(p_hwfn, p_ptt, type);
477 if (rc)
478 return rc;
479
480 if (type == QED_DCBX_OPERATIONAL_MIB) {
481 rc = qed_dcbx_process_mib_info(p_hwfn);
482 if (!rc) {
483 /* reconfigure tcs of QM queues according
484 * to negotiation results
485 */
486 qed_qm_reconf(p_hwfn, p_ptt);
487
488 /* update storm FW with negotiation results */
489 qed_sp_pf_update(p_hwfn);
490 }
491 }
492
493 return rc;
494}
495
496int qed_dcbx_info_alloc(struct qed_hwfn *p_hwfn)
497{
498 int rc = 0;
499
500 p_hwfn->p_dcbx_info = kzalloc(sizeof(*p_hwfn->p_dcbx_info), GFP_KERNEL);
501 if (!p_hwfn->p_dcbx_info) {
502 DP_NOTICE(p_hwfn,
503 "Failed to allocate 'struct qed_dcbx_info'\n");
504 rc = -ENOMEM;
505 }
506
507 return rc;
508}
509
510void qed_dcbx_info_free(struct qed_hwfn *p_hwfn,
511 struct qed_dcbx_info *p_dcbx_info)
512{
513 kfree(p_hwfn->p_dcbx_info);
514}
515
516static void qed_dcbx_update_protocol_data(struct protocol_dcb_data *p_data,
517 struct qed_dcbx_results *p_src,
518 enum dcbx_protocol_type type)
519{
520 p_data->dcb_enable_flag = p_src->arr[type].enable;
521 p_data->dcb_priority = p_src->arr[type].priority;
522 p_data->dcb_tc = p_src->arr[type].tc;
523}
524
525/* Set pf update ramrod command params */
526void qed_dcbx_set_pf_update_params(struct qed_dcbx_results *p_src,
527 struct pf_update_ramrod_data *p_dest)
528{
529 struct protocol_dcb_data *p_dcb_data;
530 bool update_flag = false;
531
532 p_dest->pf_id = p_src->pf_id;
533
534 update_flag = p_src->arr[DCBX_PROTOCOL_FCOE].update;
535 p_dest->update_fcoe_dcb_data_flag = update_flag;
536
537 update_flag = p_src->arr[DCBX_PROTOCOL_ROCE].update;
538 p_dest->update_roce_dcb_data_flag = update_flag;
539 update_flag = p_src->arr[DCBX_PROTOCOL_ROCE_V2].update;
540 p_dest->update_roce_dcb_data_flag = update_flag;
541
542 update_flag = p_src->arr[DCBX_PROTOCOL_ISCSI].update;
543 p_dest->update_iscsi_dcb_data_flag = update_flag;
544 update_flag = p_src->arr[DCBX_PROTOCOL_ETH].update;
545 p_dest->update_eth_dcb_data_flag = update_flag;
546
547 p_dcb_data = &p_dest->fcoe_dcb_data;
548 qed_dcbx_update_protocol_data(p_dcb_data, p_src, DCBX_PROTOCOL_FCOE);
549 p_dcb_data = &p_dest->roce_dcb_data;
550
551 if (p_src->arr[DCBX_PROTOCOL_ROCE].update)
552 qed_dcbx_update_protocol_data(p_dcb_data, p_src,
553 DCBX_PROTOCOL_ROCE);
554 if (p_src->arr[DCBX_PROTOCOL_ROCE_V2].update)
555 qed_dcbx_update_protocol_data(p_dcb_data, p_src,
556 DCBX_PROTOCOL_ROCE_V2);
557
558 p_dcb_data = &p_dest->iscsi_dcb_data;
559 qed_dcbx_update_protocol_data(p_dcb_data, p_src, DCBX_PROTOCOL_ISCSI);
560 p_dcb_data = &p_dest->eth_dcb_data;
561 qed_dcbx_update_protocol_data(p_dcb_data, p_src, DCBX_PROTOCOL_ETH);
562}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.h b/drivers/net/ethernet/qlogic/qed/qed_dcbx.h
new file mode 100644
index 000000000000..e7f834dbda2d
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.h
@@ -0,0 +1,80 @@
1/* QLogic qed NIC Driver
2 * Copyright (c) 2015 QLogic Corporation
3 *
4 * This software is available under the terms of the GNU General Public License
5 * (GPL) Version 2, available from the file COPYING in the main directory of
6 * this source tree.
7 */
8
9#ifndef _QED_DCBX_H
10#define _QED_DCBX_H
11#include <linux/types.h>
12#include <linux/slab.h>
13#include "qed.h"
14#include "qed_hsi.h"
15#include "qed_hw.h"
16#include "qed_mcp.h"
17#include "qed_reg_addr.h"
18
19#define DCBX_CONFIG_MAX_APP_PROTOCOL 4
20
21enum qed_mib_read_type {
22 QED_DCBX_OPERATIONAL_MIB,
23 QED_DCBX_REMOTE_MIB,
24 QED_DCBX_LOCAL_MIB,
25 QED_DCBX_REMOTE_LLDP_MIB,
26 QED_DCBX_LOCAL_LLDP_MIB
27};
28
29struct qed_dcbx_app_data {
30 bool enable; /* DCB enabled */
31 bool update; /* Update indication */
32 u8 priority; /* Priority */
33 u8 tc; /* Traffic Class */
34};
35
36struct qed_dcbx_results {
37 bool dcbx_enabled;
38 u8 pf_id;
39 struct qed_dcbx_app_data arr[DCBX_MAX_PROTOCOL_TYPE];
40};
41
42struct qed_dcbx_app_metadata {
43 enum dcbx_protocol_type id;
44 char *name;
45 enum qed_pci_personality personality;
46};
47
48#define QED_MFW_GET_FIELD(name, field) \
49 (((name) & (field ## _MASK)) >> (field ## _SHIFT))
50
51struct qed_dcbx_info {
52 struct lldp_status_params_s lldp_remote[LLDP_MAX_LLDP_AGENTS];
53 struct lldp_config_params_s lldp_local[LLDP_MAX_LLDP_AGENTS];
54 struct dcbx_local_params local_admin;
55 struct qed_dcbx_results results;
56 struct dcbx_mib operational;
57 struct dcbx_mib remote;
58 u8 dcbx_cap;
59};
60
61struct qed_dcbx_mib_meta_data {
62 struct lldp_config_params_s *lldp_local;
63 struct lldp_status_params_s *lldp_remote;
64 struct dcbx_local_params *local_admin;
65 struct dcbx_mib *mib;
66 size_t size;
67 u32 addr;
68};
69
70/* QED local interface routines */
71int
72qed_dcbx_mib_update_event(struct qed_hwfn *,
73 struct qed_ptt *, enum qed_mib_read_type);
74
75int qed_dcbx_info_alloc(struct qed_hwfn *p_hwfn);
76void qed_dcbx_info_free(struct qed_hwfn *, struct qed_dcbx_info *);
77void qed_dcbx_set_pf_update_params(struct qed_dcbx_results *p_src,
78 struct pf_update_ramrod_data *p_dest);
79
80#endif
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index 6fb6016409c6..089016f46f26 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -22,6 +22,7 @@
22#include <linux/qed/qed_if.h> 22#include <linux/qed/qed_if.h>
23#include "qed.h" 23#include "qed.h"
24#include "qed_cxt.h" 24#include "qed_cxt.h"
25#include "qed_dcbx.h"
25#include "qed_dev_api.h" 26#include "qed_dev_api.h"
26#include "qed_hsi.h" 27#include "qed_hsi.h"
27#include "qed_hw.h" 28#include "qed_hw.h"
@@ -33,6 +34,9 @@
33#include "qed_sriov.h" 34#include "qed_sriov.h"
34#include "qed_vf.h" 35#include "qed_vf.h"
35 36
37static spinlock_t qm_lock;
38static bool qm_lock_init = false;
39
36/* API common to all protocols */ 40/* API common to all protocols */
37enum BAR_ID { 41enum BAR_ID {
38 BAR_ID_0, /* used for GRC */ 42 BAR_ID_0, /* used for GRC */
@@ -147,6 +151,7 @@ void qed_resc_free(struct qed_dev *cdev)
147 qed_int_free(p_hwfn); 151 qed_int_free(p_hwfn);
148 qed_iov_free(p_hwfn); 152 qed_iov_free(p_hwfn);
149 qed_dmae_info_free(p_hwfn); 153 qed_dmae_info_free(p_hwfn);
154 qed_dcbx_info_free(p_hwfn, p_hwfn->p_dcbx_info);
150 } 155 }
151} 156}
152 157
@@ -200,13 +205,19 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn)
200 vport_id = (u8)RESC_START(p_hwfn, QED_VPORT); 205 vport_id = (u8)RESC_START(p_hwfn, QED_VPORT);
201 206
202 /* First init per-TC PQs */ 207 /* First init per-TC PQs */
203 for (i = 0; i < multi_cos_tcs; i++, curr_queue++) { 208 for (i = 0; i < multi_cos_tcs; i++) {
204 struct init_qm_pq_params *params = 209 struct init_qm_pq_params *params =
205 &qm_info->qm_pq_params[curr_queue]; 210 &qm_info->qm_pq_params[curr_queue++];
206 211
207 params->vport_id = vport_id; 212 if (p_hwfn->hw_info.personality == QED_PCI_ETH) {
208 params->tc_id = p_hwfn->hw_info.non_offload_tc; 213 params->vport_id = vport_id;
209 params->wrr_group = 1; 214 params->tc_id = p_hwfn->hw_info.non_offload_tc;
215 params->wrr_group = 1;
216 } else {
217 params->vport_id = vport_id;
218 params->tc_id = p_hwfn->hw_info.offload_tc;
219 params->wrr_group = 1;
220 }
210 } 221 }
211 222
212 /* Then init pure-LB PQ */ 223 /* Then init pure-LB PQ */
@@ -266,6 +277,63 @@ alloc_err:
266 return -ENOMEM; 277 return -ENOMEM;
267} 278}
268 279
280/* This function reconfigures the QM pf on the fly.
281 * For this purpose we:
282 * 1. reconfigure the QM database
283 * 2. set new values to runtime arrat
284 * 3. send an sdm_qm_cmd through the rbc interface to stop the QM
285 * 4. activate init tool in QM_PF stage
286 * 5. send an sdm_qm_cmd through rbc interface to release the QM
287 */
288int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
289{
290 struct qed_qm_info *qm_info = &p_hwfn->qm_info;
291 bool b_rc;
292 int rc;
293
294 /* qm_info is allocated in qed_init_qm_info() which is already called
295 * from qed_resc_alloc() or previous call of qed_qm_reconf().
296 * The allocated size may change each init, so we free it before next
297 * allocation.
298 */
299 qed_qm_info_free(p_hwfn);
300
301 /* initialize qed's qm data structure */
302 rc = qed_init_qm_info(p_hwfn);
303 if (rc)
304 return rc;
305
306 /* stop PF's qm queues */
307 spin_lock_bh(&qm_lock);
308 b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, false, true,
309 qm_info->start_pq, qm_info->num_pqs);
310 spin_unlock_bh(&qm_lock);
311 if (!b_rc)
312 return -EINVAL;
313
314 /* clear the QM_PF runtime phase leftovers from previous init */
315 qed_init_clear_rt_data(p_hwfn);
316
317 /* prepare QM portion of runtime array */
318 qed_qm_init_pf(p_hwfn);
319
320 /* activate init tool on runtime array */
321 rc = qed_init_run(p_hwfn, p_ptt, PHASE_QM_PF, p_hwfn->rel_pf_id,
322 p_hwfn->hw_info.hw_mode);
323 if (rc)
324 return rc;
325
326 /* start PF's qm queues */
327 spin_lock_bh(&qm_lock);
328 b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, true, true,
329 qm_info->start_pq, qm_info->num_pqs);
330 spin_unlock_bh(&qm_lock);
331 if (!b_rc)
332 return -EINVAL;
333
334 return 0;
335}
336
269int qed_resc_alloc(struct qed_dev *cdev) 337int qed_resc_alloc(struct qed_dev *cdev)
270{ 338{
271 struct qed_consq *p_consq; 339 struct qed_consq *p_consq;
@@ -375,6 +443,14 @@ int qed_resc_alloc(struct qed_dev *cdev)
375 "Failed to allocate memory for dmae_info structure\n"); 443 "Failed to allocate memory for dmae_info structure\n");
376 goto alloc_err; 444 goto alloc_err;
377 } 445 }
446
447 /* DCBX initialization */
448 rc = qed_dcbx_info_alloc(p_hwfn);
449 if (rc) {
450 DP_NOTICE(p_hwfn,
451 "Failed to allocate memory for dcbx structure\n");
452 goto alloc_err;
453 }
378 } 454 }
379 455
380 cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL); 456 cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL);
@@ -780,6 +856,11 @@ int qed_hw_init(struct qed_dev *cdev,
780 p_hwfn->first_on_engine = (load_code == 856 p_hwfn->first_on_engine = (load_code ==
781 FW_MSG_CODE_DRV_LOAD_ENGINE); 857 FW_MSG_CODE_DRV_LOAD_ENGINE);
782 858
859 if (!qm_lock_init) {
860 spin_lock_init(&qm_lock);
861 qm_lock_init = true;
862 }
863
783 switch (load_code) { 864 switch (load_code) {
784 case FW_MSG_CODE_DRV_LOAD_ENGINE: 865 case FW_MSG_CODE_DRV_LOAD_ENGINE:
785 rc = qed_hw_init_common(p_hwfn, p_hwfn->p_main_ptt, 866 rc = qed_hw_init_common(p_hwfn, p_hwfn->p_main_ptt,
@@ -821,6 +902,20 @@ int qed_hw_init(struct qed_dev *cdev,
821 return mfw_rc; 902 return mfw_rc;
822 } 903 }
823 904
905 /* send DCBX attention request command */
906 DP_VERBOSE(p_hwfn,
907 QED_MSG_DCB,
908 "sending phony dcbx set command to trigger DCBx attention handling\n");
909 mfw_rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
910 DRV_MSG_CODE_SET_DCBX,
911 1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT,
912 &load_code, &param);
913 if (mfw_rc) {
914 DP_NOTICE(p_hwfn,
915 "Failed to send DCBX attention request\n");
916 return mfw_rc;
917 }
918
824 p_hwfn->hw_init_done = true; 919 p_hwfn->hw_init_done = true;
825 } 920 }
826 921
diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
index 82b7727d090b..9afc15fdbb02 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
@@ -634,6 +634,14 @@ struct pf_start_ramrod_data {
634 u8 reserved0[4]; 634 u8 reserved0[4];
635}; 635};
636 636
637/* Data for port update ramrod */
638struct protocol_dcb_data {
639 u8 dcb_enable_flag;
640 u8 dcb_priority;
641 u8 dcb_tc;
642 u8 reserved;
643};
644
637/* tunnel configuration */ 645/* tunnel configuration */
638struct pf_update_tunnel_config { 646struct pf_update_tunnel_config {
639 u8 update_rx_pf_clss; 647 u8 update_rx_pf_clss;
@@ -656,8 +664,17 @@ struct pf_update_tunnel_config {
656}; 664};
657 665
658struct pf_update_ramrod_data { 666struct pf_update_ramrod_data {
659 u32 reserved[2]; 667 u8 pf_id;
660 u32 reserved_1[6]; 668 u8 update_eth_dcb_data_flag;
669 u8 update_fcoe_dcb_data_flag;
670 u8 update_iscsi_dcb_data_flag;
671 u8 update_roce_dcb_data_flag;
672 u8 update_mf_vlan_flag;
673 __le16 mf_vlan;
674 struct protocol_dcb_data eth_dcb_data;
675 struct protocol_dcb_data fcoe_dcb_data;
676 struct protocol_dcb_data iscsi_dcb_data;
677 struct protocol_dcb_data roce_dcb_data;
661 struct pf_update_tunnel_config tunnel_config; 678 struct pf_update_tunnel_config tunnel_config;
662}; 679};
663 680
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
index 2be943b91916..1182361798b5 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
@@ -15,6 +15,7 @@
15#include <linux/spinlock.h> 15#include <linux/spinlock.h>
16#include <linux/string.h> 16#include <linux/string.h>
17#include "qed.h" 17#include "qed.h"
18#include "qed_dcbx.h"
18#include "qed_hsi.h" 19#include "qed_hsi.h"
19#include "qed_hw.h" 20#include "qed_hw.h"
20#include "qed_mcp.h" 21#include "qed_mcp.h"
@@ -825,6 +826,18 @@ int qed_mcp_handle_events(struct qed_hwfn *p_hwfn,
825 case MFW_DRV_MSG_VF_DISABLED: 826 case MFW_DRV_MSG_VF_DISABLED:
826 qed_mcp_handle_vf_flr(p_hwfn, p_ptt); 827 qed_mcp_handle_vf_flr(p_hwfn, p_ptt);
827 break; 828 break;
829 case MFW_DRV_MSG_LLDP_DATA_UPDATED:
830 qed_dcbx_mib_update_event(p_hwfn, p_ptt,
831 QED_DCBX_REMOTE_LLDP_MIB);
832 break;
833 case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED:
834 qed_dcbx_mib_update_event(p_hwfn, p_ptt,
835 QED_DCBX_REMOTE_MIB);
836 break;
837 case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED:
838 qed_dcbx_mib_update_event(p_hwfn, p_ptt,
839 QED_DCBX_OPERATIONAL_MIB);
840 break;
828 case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: 841 case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE:
829 qed_mcp_handle_transceiver_change(p_hwfn, p_ptt); 842 qed_mcp_handle_transceiver_change(p_hwfn, p_ptt);
830 break; 843 break;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h
index ab5549f4e5ea..ea4e9ce53e0a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h
@@ -354,6 +354,19 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
354 enum qed_mf_mode mode, bool allow_npar_tx_switch); 354 enum qed_mf_mode mode, bool allow_npar_tx_switch);
355 355
356/** 356/**
357 * @brief qed_sp_pf_update - PF Function Update Ramrod
358 *
359 * This ramrod updates function-related parameters. Every parameter can be
360 * updated independently, according to configuration flags.
361 *
362 * @param p_hwfn
363 *
364 * @return int
365 */
366
367int qed_sp_pf_update(struct qed_hwfn *p_hwfn);
368
369/**
357 * @brief qed_sp_pf_stop - PF Function Stop Ramrod 370 * @brief qed_sp_pf_stop - PF Function Stop Ramrod
358 * 371 *
359 * This ramrod is sent to close a Physical Function (PF). It is the last ramrod 372 * This ramrod is sent to close a Physical Function (PF). It is the last ramrod
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
index 8c555ed1f949..67f6ce3c84c8 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
@@ -15,6 +15,7 @@
15#include "qed.h" 15#include "qed.h"
16#include <linux/qed/qed_chain.h> 16#include <linux/qed/qed_chain.h>
17#include "qed_cxt.h" 17#include "qed_cxt.h"
18#include "qed_dcbx.h"
18#include "qed_hsi.h" 19#include "qed_hsi.h"
19#include "qed_hw.h" 20#include "qed_hw.h"
20#include "qed_int.h" 21#include "qed_int.h"
@@ -384,6 +385,30 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
384 return rc; 385 return rc;
385} 386}
386 387
388int qed_sp_pf_update(struct qed_hwfn *p_hwfn)
389{
390 struct qed_spq_entry *p_ent = NULL;
391 struct qed_sp_init_data init_data;
392 int rc = -EINVAL;
393
394 /* Get SPQ entry */
395 memset(&init_data, 0, sizeof(init_data));
396 init_data.cid = qed_spq_get_cid(p_hwfn);
397 init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
398 init_data.comp_mode = QED_SPQ_MODE_CB;
399
400 rc = qed_sp_init_request(p_hwfn, &p_ent,
401 COMMON_RAMROD_PF_UPDATE, PROTOCOLID_COMMON,
402 &init_data);
403 if (rc)
404 return rc;
405
406 qed_dcbx_set_pf_update_params(&p_hwfn->p_dcbx_info->results,
407 &p_ent->ramrod.pf_update);
408
409 return qed_spq_post(p_hwfn, p_ent, NULL);
410}
411
387/* Set pf update ramrod command params */ 412/* Set pf update ramrod command params */
388int qed_sp_pf_update_tunn_cfg(struct qed_hwfn *p_hwfn, 413int qed_sp_pf_update_tunn_cfg(struct qed_hwfn *p_hwfn,
389 struct qed_tunn_update_params *p_tunn, 414 struct qed_tunn_update_params *p_tunn,
diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h
index 0fd8f247e65f..4c29439f54bf 100644
--- a/include/linux/qed/qed_if.h
+++ b/include/linux/qed/qed_if.h
@@ -25,6 +25,15 @@
25#include <linux/qed/common_hsi.h> 25#include <linux/qed/common_hsi.h>
26#include <linux/qed/qed_chain.h> 26#include <linux/qed/qed_chain.h>
27 27
28enum dcbx_protocol_type {
29 DCBX_PROTOCOL_ISCSI,
30 DCBX_PROTOCOL_FCOE,
31 DCBX_PROTOCOL_ROCE,
32 DCBX_PROTOCOL_ROCE_V2,
33 DCBX_PROTOCOL_ETH,
34 DCBX_MAX_PROTOCOL_TYPE
35};
36
28enum qed_led_mode { 37enum qed_led_mode {
29 QED_LED_MODE_OFF, 38 QED_LED_MODE_OFF,
30 QED_LED_MODE_ON, 39 QED_LED_MODE_ON,