qlcnic: dcb: Query adapter DCB capabilities.
[deliverable/linux.git] / drivers / net / ethernet / qlogic / qlcnic / qlcnic_dcb.c
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
8 #include "qlcnic.h"
9
10 #define QLC_DCB_MAX_TC 0x8
11
12 #define QLC_DCB_TSA_SUPPORT(V) (V & 0x1)
13 #define QLC_DCB_ETS_SUPPORT(V) ((V >> 1) & 0x1)
14 #define QLC_DCB_VERSION_SUPPORT(V) ((V >> 2) & 0xf)
15 #define QLC_DCB_MAX_NUM_TC(V) ((V >> 20) & 0xf)
16 #define QLC_DCB_MAX_NUM_ETS_TC(V) ((V >> 24) & 0xf)
17 #define QLC_DCB_MAX_NUM_PFC_TC(V) ((V >> 28) & 0xf)
18
19 static void __qlcnic_dcb_free(struct qlcnic_adapter *);
20 static int __qlcnic_dcb_attach(struct qlcnic_adapter *);
21 static int __qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *, char *);
22 static void __qlcnic_dcb_get_info(struct qlcnic_adapter *);
23
24 static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_adapter *);
25
26 static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_adapter *);
27
28 struct qlcnic_dcb_capability {
29 bool tsa_capability;
30 bool ets_capability;
31 u8 max_num_tc;
32 u8 max_ets_tc;
33 u8 max_pfc_tc;
34 u8 dcb_capability;
35 };
36
37 struct qlcnic_dcb_cfg {
38 struct qlcnic_dcb_capability capability;
39 u32 version;
40 };
41
42 static struct qlcnic_dcb_ops qlcnic_83xx_dcb_ops = {
43 .free = __qlcnic_dcb_free,
44 .attach = __qlcnic_dcb_attach,
45 .query_hw_capability = __qlcnic_dcb_query_hw_capability,
46 .get_info = __qlcnic_dcb_get_info,
47
48 .get_hw_capability = qlcnic_83xx_dcb_get_hw_capability,
49 };
50
51 static struct qlcnic_dcb_ops qlcnic_82xx_dcb_ops = {
52 .free = __qlcnic_dcb_free,
53 .attach = __qlcnic_dcb_attach,
54 .query_hw_capability = __qlcnic_dcb_query_hw_capability,
55 .get_info = __qlcnic_dcb_get_info,
56
57 .get_hw_capability = qlcnic_82xx_dcb_get_hw_capability,
58 };
59
60 void qlcnic_set_dcb_ops(struct qlcnic_adapter *adapter)
61 {
62 if (qlcnic_82xx_check(adapter))
63 adapter->dcb->ops = &qlcnic_82xx_dcb_ops;
64 else if (qlcnic_83xx_check(adapter))
65 adapter->dcb->ops = &qlcnic_83xx_dcb_ops;
66 }
67
68 int __qlcnic_register_dcb(struct qlcnic_adapter *adapter)
69 {
70 struct qlcnic_dcb *dcb;
71
72 dcb = kzalloc(sizeof(struct qlcnic_dcb), GFP_ATOMIC);
73 if (!dcb)
74 return -ENOMEM;
75
76 adapter->dcb = dcb;
77 qlcnic_set_dcb_ops(adapter);
78
79 return 0;
80 }
81
82 static void __qlcnic_dcb_free(struct qlcnic_adapter *adapter)
83 {
84 struct qlcnic_dcb *dcb = adapter->dcb;
85
86 if (!dcb)
87 return;
88
89 kfree(dcb->cfg);
90 dcb->cfg = NULL;
91 kfree(dcb);
92 adapter->dcb = NULL;
93 }
94
95 static void __qlcnic_dcb_get_info(struct qlcnic_adapter *adapter)
96 {
97 qlcnic_dcb_get_hw_capability(adapter);
98 }
99
100 static int __qlcnic_dcb_attach(struct qlcnic_adapter *adapter)
101 {
102 struct qlcnic_dcb *dcb = adapter->dcb;
103
104 dcb->cfg = kzalloc(sizeof(struct qlcnic_dcb_cfg), GFP_ATOMIC);
105 if (!dcb->cfg)
106 return -ENOMEM;
107
108 qlcnic_dcb_get_info(adapter);
109
110 return 0;
111 }
112
113 static int __qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *adapter,
114 char *buf)
115 {
116 struct qlcnic_cmd_args cmd;
117 u32 mbx_out;
118 int err;
119
120 err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DCB_QUERY_CAP);
121 if (err)
122 return err;
123
124 err = qlcnic_issue_cmd(adapter, &cmd);
125 if (err) {
126 dev_err(&adapter->pdev->dev,
127 "Failed to query DCBX capability, err %d\n", err);
128 } else {
129 mbx_out = cmd.rsp.arg[1];
130 if (buf)
131 memcpy(buf, &mbx_out, sizeof(u32));
132 }
133
134 qlcnic_free_mbx_args(&cmd);
135
136 return err;
137 }
138
139 static int __qlcnic_dcb_get_capability(struct qlcnic_adapter *adapter, u32 *val)
140 {
141 struct qlcnic_dcb_capability *cap = &adapter->dcb->cfg->capability;
142 u32 mbx_out;
143 int err;
144
145 memset(cap, 0, sizeof(struct qlcnic_dcb_capability));
146
147 err = qlcnic_dcb_query_hw_capability(adapter, (char *)val);
148 if (err)
149 return err;
150
151 mbx_out = *val;
152 if (QLC_DCB_TSA_SUPPORT(mbx_out))
153 cap->tsa_capability = true;
154
155 if (QLC_DCB_ETS_SUPPORT(mbx_out))
156 cap->ets_capability = true;
157
158 cap->max_num_tc = QLC_DCB_MAX_NUM_TC(mbx_out);
159 cap->max_ets_tc = QLC_DCB_MAX_NUM_ETS_TC(mbx_out);
160 cap->max_pfc_tc = QLC_DCB_MAX_NUM_PFC_TC(mbx_out);
161
162 if (cap->max_num_tc > QLC_DCB_MAX_TC ||
163 cap->max_ets_tc > cap->max_num_tc ||
164 cap->max_pfc_tc > cap->max_num_tc) {
165 dev_err(&adapter->pdev->dev, "Invalid DCB configuration\n");
166 return -EINVAL;
167 }
168
169 return err;
170 }
171
172 static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_adapter *adapter)
173 {
174 struct qlcnic_dcb_cfg *cfg = adapter->dcb->cfg;
175 struct qlcnic_dcb_capability *cap;
176 u32 mbx_out;
177 int err;
178
179 err = __qlcnic_dcb_get_capability(adapter, &mbx_out);
180 if (err)
181 return err;
182
183 cap = &cfg->capability;
184 cap->dcb_capability = DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_LLD_MANAGED;
185
186 if (cap->dcb_capability && cap->tsa_capability && cap->ets_capability)
187 set_bit(__QLCNIC_DCB_STATE, &adapter->state);
188
189 return err;
190 }
191
192 static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_adapter *adapter)
193 {
194 struct qlcnic_dcb_capability *cap = &adapter->dcb->cfg->capability;
195 u32 mbx_out;
196 int err;
197
198 err = __qlcnic_dcb_get_capability(adapter, &mbx_out);
199 if (err)
200 return err;
201
202 if (mbx_out & BIT_2)
203 cap->dcb_capability = DCB_CAP_DCBX_VER_CEE;
204 if (mbx_out & BIT_3)
205 cap->dcb_capability |= DCB_CAP_DCBX_VER_IEEE;
206 if (cap->dcb_capability)
207 cap->dcb_capability |= DCB_CAP_DCBX_LLD_MANAGED;
208
209 if (cap->dcb_capability && cap->tsa_capability && cap->ets_capability)
210 set_bit(__QLCNIC_DCB_STATE, &adapter->state);
211
212 return err;
213 }
This page took 0.040442 seconds and 6 git commands to generate.