blob: e43866f20bbb2448c64d4830504b9d3860035794 [file] [log] [blame]
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -04001/*
2 * QLogic qlcnic NIC Driver
3 * Copyright (c) 2009-2013 QLogic Corporation
4 *
5 * See LICENSE.qlcnic for copyright and licensing details.
6 */
7
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -04008#include <linux/types.h>
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -04009#include "qlcnic.h"
10
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -040011#define QLC_DCB_NUM_PARAM 3
12
13#define QLC_DCB_FW_VER 0x2
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -040014#define QLC_DCB_MAX_TC 0x8
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -040015#define QLC_DCB_MAX_APP 0x8
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -040016
17#define QLC_DCB_TSA_SUPPORT(V) (V & 0x1)
18#define QLC_DCB_ETS_SUPPORT(V) ((V >> 1) & 0x1)
19#define QLC_DCB_VERSION_SUPPORT(V) ((V >> 2) & 0xf)
20#define QLC_DCB_MAX_NUM_TC(V) ((V >> 20) & 0xf)
21#define QLC_DCB_MAX_NUM_ETS_TC(V) ((V >> 24) & 0xf)
22#define QLC_DCB_MAX_NUM_PFC_TC(V) ((V >> 28) & 0xf)
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -040023#define QLC_DCB_GET_TC_PRIO(X, P) ((X >> (P * 3)) & 0x7)
24#define QLC_DCB_GET_PGID_PRIO(X, P) ((X >> (P * 8)) & 0xff)
25#define QLC_DCB_GET_BWPER_PG(X, P) ((X >> (P * 8)) & 0xff)
26#define QLC_DCB_GET_TSA_PG(X, P) ((X >> (P * 8)) & 0xff)
27#define QLC_DCB_GET_PFC_PRIO(X, P) (((X >> 24) >> P) & 0x1)
28#define QLC_DCB_GET_PROTO_ID_APP(X) ((X >> 8) & 0xffff)
29#define QLC_DCB_GET_SELECTOR_APP(X) (X & 0xff)
30
31#define QLC_DCB_LOCAL_PARAM_FWID 0x3
32#define QLC_DCB_OPER_PARAM_FWID 0x1
33#define QLC_DCB_PEER_PARAM_FWID 0x2
34
35#define QLC_83XX_DCB_GET_NUMAPP(X) ((X >> 2) & 0xf)
36#define QLC_83XX_DCB_TSA_VALID(X) (X & 0x1)
37#define QLC_83XX_DCB_PFC_VALID(X) ((X >> 1) & 0x1)
38#define QLC_83XX_DCB_GET_PRIOMAP_APP(X) (X >> 24)
39
40#define QLC_82XX_DCB_GET_NUMAPP(X) ((X >> 12) & 0xf)
41#define QLC_82XX_DCB_TSA_VALID(X) ((X >> 4) & 0x1)
42#define QLC_82XX_DCB_PFC_VALID(X) ((X >> 5) & 0x1)
43#define QLC_82XX_DCB_GET_PRIOVAL_APP(X) ((X >> 24) & 0x7)
44#define QLC_82XX_DCB_GET_PRIOMAP_APP(X) (1 << X)
45#define QLC_82XX_DCB_PRIO_TC_MAP (0x76543210)
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -040046
47static void __qlcnic_dcb_free(struct qlcnic_adapter *);
48static int __qlcnic_dcb_attach(struct qlcnic_adapter *);
49static int __qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *, char *);
50static void __qlcnic_dcb_get_info(struct qlcnic_adapter *);
51
52static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_adapter *);
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -040053static int qlcnic_82xx_dcb_query_cee_param(struct qlcnic_adapter *, char *, u8);
54static int qlcnic_82xx_dcb_get_cee_cfg(struct qlcnic_adapter *);
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -040055
56static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_adapter *);
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -040057static int qlcnic_83xx_dcb_query_cee_param(struct qlcnic_adapter *, char *, u8);
58static int qlcnic_83xx_dcb_get_cee_cfg(struct qlcnic_adapter *);
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -040059
60struct qlcnic_dcb_capability {
61 bool tsa_capability;
62 bool ets_capability;
63 u8 max_num_tc;
64 u8 max_ets_tc;
65 u8 max_pfc_tc;
66 u8 dcb_capability;
67};
68
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -040069struct qlcnic_dcb_param {
70 u32 hdr_prio_pfc_map[2];
71 u32 prio_pg_map[2];
72 u32 pg_bw_map[2];
73 u32 pg_tsa_map[2];
74 u32 app[QLC_DCB_MAX_APP];
75};
76
77struct qlcnic_dcb_mbx_params {
78 /* 1st local, 2nd operational 3rd remote */
79 struct qlcnic_dcb_param type[3];
80 u32 prio_tc_map;
81};
82
83struct qlcnic_82xx_dcb_param_mbx_le {
84 __le32 hdr_prio_pfc_map[2];
85 __le32 prio_pg_map[2];
86 __le32 pg_bw_map[2];
87 __le32 pg_tsa_map[2];
88 __le32 app[QLC_DCB_MAX_APP];
89};
90
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -040091struct qlcnic_dcb_cfg {
92 struct qlcnic_dcb_capability capability;
93 u32 version;
94};
95
96static struct qlcnic_dcb_ops qlcnic_83xx_dcb_ops = {
97 .free = __qlcnic_dcb_free,
98 .attach = __qlcnic_dcb_attach,
99 .query_hw_capability = __qlcnic_dcb_query_hw_capability,
100 .get_info = __qlcnic_dcb_get_info,
101
102 .get_hw_capability = qlcnic_83xx_dcb_get_hw_capability,
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -0400103 .query_cee_param = qlcnic_83xx_dcb_query_cee_param,
104 .get_cee_cfg = qlcnic_83xx_dcb_get_cee_cfg,
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -0400105};
106
107static struct qlcnic_dcb_ops qlcnic_82xx_dcb_ops = {
108 .free = __qlcnic_dcb_free,
109 .attach = __qlcnic_dcb_attach,
110 .query_hw_capability = __qlcnic_dcb_query_hw_capability,
111 .get_info = __qlcnic_dcb_get_info,
112
113 .get_hw_capability = qlcnic_82xx_dcb_get_hw_capability,
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -0400114 .query_cee_param = qlcnic_82xx_dcb_query_cee_param,
115 .get_cee_cfg = qlcnic_82xx_dcb_get_cee_cfg,
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -0400116};
117
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -0400118static u8 qlcnic_dcb_get_num_app(struct qlcnic_adapter *adapter, u32 val)
119{
120 if (qlcnic_82xx_check(adapter))
121 return QLC_82XX_DCB_GET_NUMAPP(val);
122 else
123 return QLC_83XX_DCB_GET_NUMAPP(val);
124}
125
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -0400126void qlcnic_set_dcb_ops(struct qlcnic_adapter *adapter)
127{
128 if (qlcnic_82xx_check(adapter))
129 adapter->dcb->ops = &qlcnic_82xx_dcb_ops;
130 else if (qlcnic_83xx_check(adapter))
131 adapter->dcb->ops = &qlcnic_83xx_dcb_ops;
132}
133
134int __qlcnic_register_dcb(struct qlcnic_adapter *adapter)
135{
136 struct qlcnic_dcb *dcb;
137
138 dcb = kzalloc(sizeof(struct qlcnic_dcb), GFP_ATOMIC);
139 if (!dcb)
140 return -ENOMEM;
141
142 adapter->dcb = dcb;
143 qlcnic_set_dcb_ops(adapter);
144
145 return 0;
146}
147
148static void __qlcnic_dcb_free(struct qlcnic_adapter *adapter)
149{
150 struct qlcnic_dcb *dcb = adapter->dcb;
151
152 if (!dcb)
153 return;
154
155 kfree(dcb->cfg);
156 dcb->cfg = NULL;
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -0400157 kfree(dcb->param);
158 dcb->param = NULL;
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -0400159 kfree(dcb);
160 adapter->dcb = NULL;
161}
162
163static void __qlcnic_dcb_get_info(struct qlcnic_adapter *adapter)
164{
165 qlcnic_dcb_get_hw_capability(adapter);
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -0400166 qlcnic_dcb_get_cee_cfg(adapter);
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -0400167}
168
169static int __qlcnic_dcb_attach(struct qlcnic_adapter *adapter)
170{
171 struct qlcnic_dcb *dcb = adapter->dcb;
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -0400172 int err = 0;
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -0400173
174 dcb->cfg = kzalloc(sizeof(struct qlcnic_dcb_cfg), GFP_ATOMIC);
175 if (!dcb->cfg)
176 return -ENOMEM;
177
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -0400178 dcb->param = kzalloc(sizeof(struct qlcnic_dcb_mbx_params), GFP_ATOMIC);
179 if (!dcb->param) {
180 err = -ENOMEM;
181 goto out_free_cfg;
182 }
183
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -0400184 qlcnic_dcb_get_info(adapter);
185
186 return 0;
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -0400187out_free_cfg:
188 kfree(dcb->cfg);
189 dcb->cfg = NULL;
190
191 return err;
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -0400192}
193
194static int __qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *adapter,
195 char *buf)
196{
197 struct qlcnic_cmd_args cmd;
198 u32 mbx_out;
199 int err;
200
201 err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DCB_QUERY_CAP);
202 if (err)
203 return err;
204
205 err = qlcnic_issue_cmd(adapter, &cmd);
206 if (err) {
207 dev_err(&adapter->pdev->dev,
208 "Failed to query DCBX capability, err %d\n", err);
209 } else {
210 mbx_out = cmd.rsp.arg[1];
211 if (buf)
212 memcpy(buf, &mbx_out, sizeof(u32));
213 }
214
215 qlcnic_free_mbx_args(&cmd);
216
217 return err;
218}
219
220static int __qlcnic_dcb_get_capability(struct qlcnic_adapter *adapter, u32 *val)
221{
222 struct qlcnic_dcb_capability *cap = &adapter->dcb->cfg->capability;
223 u32 mbx_out;
224 int err;
225
226 memset(cap, 0, sizeof(struct qlcnic_dcb_capability));
227
228 err = qlcnic_dcb_query_hw_capability(adapter, (char *)val);
229 if (err)
230 return err;
231
232 mbx_out = *val;
233 if (QLC_DCB_TSA_SUPPORT(mbx_out))
234 cap->tsa_capability = true;
235
236 if (QLC_DCB_ETS_SUPPORT(mbx_out))
237 cap->ets_capability = true;
238
239 cap->max_num_tc = QLC_DCB_MAX_NUM_TC(mbx_out);
240 cap->max_ets_tc = QLC_DCB_MAX_NUM_ETS_TC(mbx_out);
241 cap->max_pfc_tc = QLC_DCB_MAX_NUM_PFC_TC(mbx_out);
242
243 if (cap->max_num_tc > QLC_DCB_MAX_TC ||
244 cap->max_ets_tc > cap->max_num_tc ||
245 cap->max_pfc_tc > cap->max_num_tc) {
246 dev_err(&adapter->pdev->dev, "Invalid DCB configuration\n");
247 return -EINVAL;
248 }
249
250 return err;
251}
252
253static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_adapter *adapter)
254{
255 struct qlcnic_dcb_cfg *cfg = adapter->dcb->cfg;
256 struct qlcnic_dcb_capability *cap;
257 u32 mbx_out;
258 int err;
259
260 err = __qlcnic_dcb_get_capability(adapter, &mbx_out);
261 if (err)
262 return err;
263
264 cap = &cfg->capability;
265 cap->dcb_capability = DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_LLD_MANAGED;
266
267 if (cap->dcb_capability && cap->tsa_capability && cap->ets_capability)
268 set_bit(__QLCNIC_DCB_STATE, &adapter->state);
269
270 return err;
271}
272
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -0400273static int qlcnic_82xx_dcb_query_cee_param(struct qlcnic_adapter *adapter,
274 char *buf, u8 type)
275{
276 u16 size = sizeof(struct qlcnic_82xx_dcb_param_mbx_le);
277 struct qlcnic_82xx_dcb_param_mbx_le *prsp_le;
278 struct device *dev = &adapter->pdev->dev;
279 dma_addr_t cardrsp_phys_addr;
280 struct qlcnic_dcb_param rsp;
281 struct qlcnic_cmd_args cmd;
282 u64 phys_addr;
283 void *addr;
284 int err, i;
285
286 switch (type) {
287 case QLC_DCB_LOCAL_PARAM_FWID:
288 case QLC_DCB_OPER_PARAM_FWID:
289 case QLC_DCB_PEER_PARAM_FWID:
290 break;
291 default:
292 dev_err(dev, "Invalid parameter type %d\n", type);
293 return -EINVAL;
294 }
295
296 addr = dma_alloc_coherent(&adapter->pdev->dev, size, &cardrsp_phys_addr,
297 GFP_KERNEL);
298 if (addr == NULL)
299 return -ENOMEM;
300
301 prsp_le = addr;
302
303 err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DCB_QUERY_PARAM);
304 if (err)
305 goto out_free_rsp;
306
307 phys_addr = cardrsp_phys_addr;
308 cmd.req.arg[1] = size | (type << 16);
309 cmd.req.arg[2] = MSD(phys_addr);
310 cmd.req.arg[3] = LSD(phys_addr);
311
312 err = qlcnic_issue_cmd(adapter, &cmd);
313 if (err) {
314 dev_err(dev, "Failed to query DCBX parameter, err %d\n", err);
315 goto out;
316 }
317
318 memset(&rsp, 0, sizeof(struct qlcnic_dcb_param));
319 rsp.hdr_prio_pfc_map[0] = le32_to_cpu(prsp_le->hdr_prio_pfc_map[0]);
320 rsp.hdr_prio_pfc_map[1] = le32_to_cpu(prsp_le->hdr_prio_pfc_map[1]);
321 rsp.prio_pg_map[0] = le32_to_cpu(prsp_le->prio_pg_map[0]);
322 rsp.prio_pg_map[1] = le32_to_cpu(prsp_le->prio_pg_map[1]);
323 rsp.pg_bw_map[0] = le32_to_cpu(prsp_le->pg_bw_map[0]);
324 rsp.pg_bw_map[1] = le32_to_cpu(prsp_le->pg_bw_map[1]);
325 rsp.pg_tsa_map[0] = le32_to_cpu(prsp_le->pg_tsa_map[0]);
326 rsp.pg_tsa_map[1] = le32_to_cpu(prsp_le->pg_tsa_map[1]);
327
328 for (i = 0; i < QLC_DCB_MAX_APP; i++)
329 rsp.app[i] = le32_to_cpu(prsp_le->app[i]);
330
331 if (buf)
332 memcpy(buf, &rsp, size);
333out:
334 qlcnic_free_mbx_args(&cmd);
335
336out_free_rsp:
337 dma_free_coherent(&adapter->pdev->dev, size, addr, cardrsp_phys_addr);
338
339 return err;
340}
341
342static int qlcnic_82xx_dcb_get_cee_cfg(struct qlcnic_adapter *adapter)
343{
344 struct qlcnic_dcb_mbx_params *mbx;
345 int err;
346
347 mbx = adapter->dcb->param;
348 if (!mbx)
349 return 0;
350
351 err = qlcnic_dcb_query_cee_param(adapter, (char *)&mbx->type[0],
352 QLC_DCB_LOCAL_PARAM_FWID);
353 if (err)
354 return err;
355
356 err = qlcnic_dcb_query_cee_param(adapter, (char *)&mbx->type[1],
357 QLC_DCB_OPER_PARAM_FWID);
358 if (err)
359 return err;
360
361 err = qlcnic_dcb_query_cee_param(adapter, (char *)&mbx->type[2],
362 QLC_DCB_PEER_PARAM_FWID);
363 if (err)
364 return err;
365
366 mbx->prio_tc_map = QLC_82XX_DCB_PRIO_TC_MAP;
367
368 return err;
369}
370
Sucheta Chakraborty14d385b2013-08-23 13:38:25 -0400371static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_adapter *adapter)
372{
373 struct qlcnic_dcb_capability *cap = &adapter->dcb->cfg->capability;
374 u32 mbx_out;
375 int err;
376
377 err = __qlcnic_dcb_get_capability(adapter, &mbx_out);
378 if (err)
379 return err;
380
381 if (mbx_out & BIT_2)
382 cap->dcb_capability = DCB_CAP_DCBX_VER_CEE;
383 if (mbx_out & BIT_3)
384 cap->dcb_capability |= DCB_CAP_DCBX_VER_IEEE;
385 if (cap->dcb_capability)
386 cap->dcb_capability |= DCB_CAP_DCBX_LLD_MANAGED;
387
388 if (cap->dcb_capability && cap->tsa_capability && cap->ets_capability)
389 set_bit(__QLCNIC_DCB_STATE, &adapter->state);
390
391 return err;
392}
Sucheta Chakrabortyfb859ed2013-08-23 13:38:26 -0400393
394static int qlcnic_83xx_dcb_query_cee_param(struct qlcnic_adapter *adapter,
395 char *buf, u8 idx)
396{
397 struct qlcnic_dcb_mbx_params mbx_out;
398 int err, i, j, k, max_app, size;
399 struct qlcnic_dcb_param *each;
400 struct qlcnic_cmd_args cmd;
401 u32 val;
402 char *p;
403
404 size = 0;
405 memset(&mbx_out, 0, sizeof(struct qlcnic_dcb_mbx_params));
406 memset(buf, 0, sizeof(struct qlcnic_dcb_mbx_params));
407
408 err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DCB_QUERY_PARAM);
409 if (err)
410 return err;
411
412 cmd.req.arg[0] |= QLC_DCB_FW_VER << 29;
413 err = qlcnic_issue_cmd(adapter, &cmd);
414 if (err) {
415 dev_err(&adapter->pdev->dev,
416 "Failed to query DCBX param, err %d\n", err);
417 goto out;
418 }
419
420 mbx_out.prio_tc_map = cmd.rsp.arg[1];
421 p = memcpy(buf, &mbx_out, sizeof(u32));
422 k = 2;
423 p += sizeof(u32);
424
425 for (j = 0; j < QLC_DCB_NUM_PARAM; j++) {
426 each = &mbx_out.type[j];
427
428 each->hdr_prio_pfc_map[0] = cmd.rsp.arg[k++];
429 each->hdr_prio_pfc_map[1] = cmd.rsp.arg[k++];
430 each->prio_pg_map[0] = cmd.rsp.arg[k++];
431 each->prio_pg_map[1] = cmd.rsp.arg[k++];
432 each->pg_bw_map[0] = cmd.rsp.arg[k++];
433 each->pg_bw_map[1] = cmd.rsp.arg[k++];
434 each->pg_tsa_map[0] = cmd.rsp.arg[k++];
435 each->pg_tsa_map[1] = cmd.rsp.arg[k++];
436 val = each->hdr_prio_pfc_map[0];
437
438 max_app = qlcnic_dcb_get_num_app(adapter, val);
439 for (i = 0; i < max_app; i++)
440 each->app[i] = cmd.rsp.arg[i + k];
441
442 size = 16 * sizeof(u32);
443 memcpy(p, &each->hdr_prio_pfc_map[0], size);
444 p += size;
445 if (j == 0)
446 k = 18;
447 else
448 k = 34;
449 }
450out:
451 qlcnic_free_mbx_args(&cmd);
452
453 return err;
454}
455
456static int qlcnic_83xx_dcb_get_cee_cfg(struct qlcnic_adapter *adapter)
457{
458 struct qlcnic_dcb *dcb = adapter->dcb;
459
460 return qlcnic_dcb_query_cee_param(adapter, (char *)dcb->param, 0);
461}