blob: 29ede8a17a2ca5a7d99e140c0a8e0c8f43848314 [file] [log] [blame]
Scott Feldman01f2e4e2008-09-15 09:17:11 -07001/*
Vasanthy Kolluri29046f92010-06-24 10:52:26 +00002 * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
Scott Feldman01f2e4e2008-09-15 09:17:11 -07003 * Copyright 2007 Nuova Systems, Inc. All rights reserved.
4 *
5 * This program is free software; you may redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
10 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
12 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
13 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
14 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
16 * SOFTWARE.
17 *
18 */
19
20#include <linux/kernel.h>
21#include <linux/errno.h>
22#include <linux/types.h>
23#include <linux/pci.h>
24#include <linux/netdevice.h>
25
26#include "wq_enet_desc.h"
27#include "rq_enet_desc.h"
28#include "cq_enet_desc.h"
29#include "vnic_resource.h"
30#include "vnic_enet.h"
31#include "vnic_dev.h"
32#include "vnic_wq.h"
33#include "vnic_rq.h"
34#include "vnic_cq.h"
35#include "vnic_intr.h"
36#include "vnic_stats.h"
37#include "vnic_nic.h"
38#include "vnic_rss.h"
39#include "enic_res.h"
40#include "enic.h"
41
42int enic_get_vnic_config(struct enic *enic)
43{
44 struct vnic_enet_config *c = &enic->config;
45 int err;
46
47 err = vnic_dev_mac_addr(enic->vdev, enic->mac_addr);
48 if (err) {
Vasanthy Kolluria7a79de2010-06-24 10:50:56 +000049 dev_err(enic_get_dev(enic),
50 "Error getting MAC addr, %d\n", err);
Scott Feldman01f2e4e2008-09-15 09:17:11 -070051 return err;
52 }
53
54#define GET_CONFIG(m) \
55 do { \
56 err = vnic_dev_spec(enic->vdev, \
57 offsetof(struct vnic_enet_config, m), \
58 sizeof(c->m), &c->m); \
59 if (err) { \
Vasanthy Kolluria7a79de2010-06-24 10:50:56 +000060 dev_err(enic_get_dev(enic), \
Scott Feldman01f2e4e2008-09-15 09:17:11 -070061 "Error getting %s, %d\n", #m, err); \
62 return err; \
63 } \
64 } while (0)
65
66 GET_CONFIG(flags);
67 GET_CONFIG(wq_desc_count);
68 GET_CONFIG(rq_desc_count);
69 GET_CONFIG(mtu);
Scott Feldman01f2e4e2008-09-15 09:17:11 -070070 GET_CONFIG(intr_timer_type);
71 GET_CONFIG(intr_mode);
Scott Feldman7c844592009-12-23 13:27:54 +000072 GET_CONFIG(intr_timer_usec);
Vasanthy Kolluri1825aca2010-06-24 10:51:59 +000073 GET_CONFIG(loop_tag);
Scott Feldman01f2e4e2008-09-15 09:17:11 -070074
75 c->wq_desc_count =
76 min_t(u32, ENIC_MAX_WQ_DESCS,
77 max_t(u32, ENIC_MIN_WQ_DESCS,
78 c->wq_desc_count));
Scott Feldmanbd249622009-12-23 13:27:48 +000079 c->wq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
Scott Feldman01f2e4e2008-09-15 09:17:11 -070080
81 c->rq_desc_count =
82 min_t(u32, ENIC_MAX_RQ_DESCS,
83 max_t(u32, ENIC_MIN_RQ_DESCS,
84 c->rq_desc_count));
Scott Feldmanbd249622009-12-23 13:27:48 +000085 c->rq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
Scott Feldman01f2e4e2008-09-15 09:17:11 -070086
87 if (c->mtu == 0)
88 c->mtu = 1500;
89 c->mtu = min_t(u16, ENIC_MAX_MTU,
90 max_t(u16, ENIC_MIN_MTU,
91 c->mtu));
92
Scott Feldman7c844592009-12-23 13:27:54 +000093 c->intr_timer_usec = min_t(u32,
94 INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
95 c->intr_timer_usec);
Scott Feldman01f2e4e2008-09-15 09:17:11 -070096
Vasanthy Kolluria7a79de2010-06-24 10:50:56 +000097 dev_info(enic_get_dev(enic), "vNIC MAC addr %pM wq/rq %d/%d\n",
Johannes Berg7c510e42008-10-27 17:47:26 -070098 enic->mac_addr, c->wq_desc_count, c->rq_desc_count);
Vasanthy Kolluria7a79de2010-06-24 10:50:56 +000099 dev_info(enic_get_dev(enic), "vNIC mtu %d csum tx/rx %d/%d "
100 "tso/lro %d/%d intr timer %d usec\n",
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700101 c->mtu, ENIC_SETTING(enic, TXCSUM),
102 ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
Scott Feldman7c844592009-12-23 13:27:54 +0000103 ENIC_SETTING(enic, LRO), c->intr_timer_usec);
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700104
105 return 0;
106}
107
Vasanthy Kolluri383ab922010-06-24 10:50:12 +0000108int enic_add_vlan(struct enic *enic, u16 vlanid)
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700109{
110 u64 a0 = vlanid, a1 = 0;
111 int wait = 1000;
112 int err;
113
114 err = vnic_dev_cmd(enic->vdev, CMD_VLAN_ADD, &a0, &a1, wait);
115 if (err)
Vasanthy Kolluria7a79de2010-06-24 10:50:56 +0000116 dev_err(enic_get_dev(enic), "Can't add vlan id, %d\n", err);
Vasanthy Kolluri383ab922010-06-24 10:50:12 +0000117
118 return err;
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700119}
120
Vasanthy Kolluri383ab922010-06-24 10:50:12 +0000121int enic_del_vlan(struct enic *enic, u16 vlanid)
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700122{
123 u64 a0 = vlanid, a1 = 0;
124 int wait = 1000;
125 int err;
126
127 err = vnic_dev_cmd(enic->vdev, CMD_VLAN_DEL, &a0, &a1, wait);
128 if (err)
Vasanthy Kolluria7a79de2010-06-24 10:50:56 +0000129 dev_err(enic_get_dev(enic), "Can't delete vlan id, %d\n", err);
Vasanthy Kolluri383ab922010-06-24 10:50:12 +0000130
131 return err;
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700132}
133
134int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
135 u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
136 u8 ig_vlan_strip_en)
137{
138 u64 a0, a1;
139 u32 nic_cfg;
140 int wait = 1000;
141
142 vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
143 rss_hash_type, rss_hash_bits, rss_base_cpu,
144 rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
145
146 a0 = nic_cfg;
147 a1 = 0;
148
149 return vnic_dev_cmd(enic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
150}
151
Scott Feldman6ba9cdc2009-09-03 17:02:24 +0000152int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len)
153{
154 u64 a0 = (u64)key_pa, a1 = len;
155 int wait = 1000;
156
157 return vnic_dev_cmd(enic->vdev, CMD_RSS_KEY, &a0, &a1, wait);
158}
159
160int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len)
161{
162 u64 a0 = (u64)cpu_pa, a1 = len;
163 int wait = 1000;
164
165 return vnic_dev_cmd(enic->vdev, CMD_RSS_CPU, &a0, &a1, wait);
166}
167
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700168void enic_free_vnic_resources(struct enic *enic)
169{
170 unsigned int i;
171
172 for (i = 0; i < enic->wq_count; i++)
173 vnic_wq_free(&enic->wq[i]);
174 for (i = 0; i < enic->rq_count; i++)
175 vnic_rq_free(&enic->rq[i]);
176 for (i = 0; i < enic->cq_count; i++)
177 vnic_cq_free(&enic->cq[i]);
178 for (i = 0; i < enic->intr_count; i++)
179 vnic_intr_free(&enic->intr[i]);
180}
181
182void enic_get_res_counts(struct enic *enic)
183{
Scott Feldman6ba9cdc2009-09-03 17:02:24 +0000184 enic->wq_count = min_t(int,
185 vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ),
186 ENIC_WQ_MAX);
187 enic->rq_count = min_t(int,
188 vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ),
189 ENIC_RQ_MAX);
190 enic->cq_count = min_t(int,
191 vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ),
192 ENIC_CQ_MAX);
193 enic->intr_count = min_t(int,
194 vnic_dev_get_res_count(enic->vdev, RES_TYPE_INTR_CTRL),
195 ENIC_INTR_MAX);
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700196
Vasanthy Kolluria7a79de2010-06-24 10:50:56 +0000197 dev_info(enic_get_dev(enic),
198 "vNIC resources avail: wq %d rq %d cq %d intr %d\n",
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700199 enic->wq_count, enic->rq_count,
200 enic->cq_count, enic->intr_count);
201}
202
203void enic_init_vnic_resources(struct enic *enic)
204{
205 enum vnic_dev_intr_mode intr_mode;
206 unsigned int mask_on_assertion;
207 unsigned int interrupt_offset;
208 unsigned int error_interrupt_enable;
209 unsigned int error_interrupt_offset;
210 unsigned int cq_index;
211 unsigned int i;
212
213 intr_mode = vnic_dev_get_intr_mode(enic->vdev);
214
215 /* Init RQ/WQ resources.
216 *
217 * RQ[0 - n-1] point to CQ[0 - n-1]
218 * WQ[0 - m-1] point to CQ[n - n+m-1]
219 *
220 * Error interrupt is not enabled for MSI.
221 */
222
223 switch (intr_mode) {
224 case VNIC_DEV_INTR_MODE_INTX:
225 case VNIC_DEV_INTR_MODE_MSIX:
226 error_interrupt_enable = 1;
227 error_interrupt_offset = enic->intr_count - 2;
228 break;
229 default:
230 error_interrupt_enable = 0;
231 error_interrupt_offset = 0;
232 break;
233 }
234
235 for (i = 0; i < enic->rq_count; i++) {
236 cq_index = i;
237 vnic_rq_init(&enic->rq[i],
238 cq_index,
239 error_interrupt_enable,
240 error_interrupt_offset);
241 }
242
243 for (i = 0; i < enic->wq_count; i++) {
244 cq_index = enic->rq_count + i;
245 vnic_wq_init(&enic->wq[i],
246 cq_index,
247 error_interrupt_enable,
248 error_interrupt_offset);
249 }
250
251 /* Init CQ resources
252 *
253 * CQ[0 - n+m-1] point to INTR[0] for INTx, MSI
254 * CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X
255 */
256
257 for (i = 0; i < enic->cq_count; i++) {
258
259 switch (intr_mode) {
260 case VNIC_DEV_INTR_MODE_MSIX:
261 interrupt_offset = i;
262 break;
263 default:
264 interrupt_offset = 0;
265 break;
266 }
267
268 vnic_cq_init(&enic->cq[i],
269 0 /* flow_control_enable */,
270 1 /* color_enable */,
271 0 /* cq_head */,
272 0 /* cq_tail */,
273 1 /* cq_tail_color */,
274 1 /* interrupt_enable */,
275 1 /* cq_entry_enable */,
276 0 /* cq_message_enable */,
277 interrupt_offset,
278 0 /* cq_message_addr */);
279 }
280
281 /* Init INTR resources
282 *
283 * mask_on_assertion is not used for INTx due to the level-
284 * triggered nature of INTx
285 */
286
287 switch (intr_mode) {
288 case VNIC_DEV_INTR_MODE_MSI:
289 case VNIC_DEV_INTR_MODE_MSIX:
290 mask_on_assertion = 1;
291 break;
292 default:
293 mask_on_assertion = 0;
294 break;
295 }
296
297 for (i = 0; i < enic->intr_count; i++) {
298 vnic_intr_init(&enic->intr[i],
Scott Feldman7c844592009-12-23 13:27:54 +0000299 INTR_COALESCE_USEC_TO_HW(enic->config.intr_timer_usec),
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700300 enic->config.intr_timer_type,
301 mask_on_assertion);
302 }
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700303}
304
305int enic_alloc_vnic_resources(struct enic *enic)
306{
307 enum vnic_dev_intr_mode intr_mode;
308 unsigned int i;
309 int err;
310
311 intr_mode = vnic_dev_get_intr_mode(enic->vdev);
312
Vasanthy Kolluria7a79de2010-06-24 10:50:56 +0000313 dev_info(enic_get_dev(enic), "vNIC resources used: "
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700314 "wq %d rq %d cq %d intr %d intr mode %s\n",
315 enic->wq_count, enic->rq_count,
316 enic->cq_count, enic->intr_count,
317 intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
318 intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
319 intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" :
Vasanthy Kolluria7a79de2010-06-24 10:50:56 +0000320 "unknown");
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700321
322 /* Allocate queue resources
323 */
324
325 for (i = 0; i < enic->wq_count; i++) {
326 err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i,
327 enic->config.wq_desc_count,
328 sizeof(struct wq_enet_desc));
329 if (err)
330 goto err_out_cleanup;
331 }
332
333 for (i = 0; i < enic->rq_count; i++) {
334 err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i,
335 enic->config.rq_desc_count,
336 sizeof(struct rq_enet_desc));
337 if (err)
338 goto err_out_cleanup;
339 }
340
341 for (i = 0; i < enic->cq_count; i++) {
342 if (i < enic->rq_count)
343 err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
344 enic->config.rq_desc_count,
345 sizeof(struct cq_enet_rq_desc));
346 else
347 err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
348 enic->config.wq_desc_count,
349 sizeof(struct cq_enet_wq_desc));
350 if (err)
351 goto err_out_cleanup;
352 }
353
354 for (i = 0; i < enic->intr_count; i++) {
355 err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
356 if (err)
357 goto err_out_cleanup;
358 }
359
360 /* Hook remaining resource
361 */
362
363 enic->legacy_pba = vnic_dev_get_res(enic->vdev,
364 RES_TYPE_INTR_PBA_LEGACY, 0);
365 if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
Vasanthy Kolluria7a79de2010-06-24 10:50:56 +0000366 dev_err(enic_get_dev(enic),
367 "Failed to hook legacy pba resource\n");
Scott Feldman01f2e4e2008-09-15 09:17:11 -0700368 err = -ENODEV;
369 goto err_out_cleanup;
370 }
371
372 return 0;
373
374err_out_cleanup:
375 enic_free_vnic_resources(enic);
376
377 return err;
378}