Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
enic_res.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved.
3  * 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 
43 {
44  struct vnic_enet_config *c = &enic->config;
45  int err;
46 
47  err = vnic_dev_get_mac_addr(enic->vdev, enic->mac_addr);
48  if (err) {
49  dev_err(enic_get_dev(enic),
50  "Error getting MAC addr, %d\n", err);
51  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) { \
60  dev_err(enic_get_dev(enic), \
61  "Error getting %s, %d\n", #m, err); \
62  return err; \
63  } \
64  } while (0)
65 
69  GET_CONFIG(mtu);
74 
75  c->wq_desc_count =
78  c->wq_desc_count));
79  c->wq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
80 
81  c->rq_desc_count =
84  c->rq_desc_count));
85  c->rq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
86 
87  if (c->mtu == 0)
88  c->mtu = 1500;
89  c->mtu = min_t(u16, ENIC_MAX_MTU,
91  c->mtu));
92 
95 
96  dev_info(enic_get_dev(enic),
97  "vNIC MAC addr %pM wq/rq %d/%d mtu %d\n",
98  enic->mac_addr, c->wq_desc_count, c->rq_desc_count, c->mtu);
99 
100  dev_info(enic_get_dev(enic), "vNIC csum tx/rx %s/%s "
101  "tso/lro %s/%s rss %s intr mode %s type %s timer %d usec "
102  "loopback tag 0x%04x\n",
103  ENIC_SETTING(enic, TXCSUM) ? "yes" : "no",
104  ENIC_SETTING(enic, RXCSUM) ? "yes" : "no",
105  ENIC_SETTING(enic, TSO) ? "yes" : "no",
106  ENIC_SETTING(enic, LRO) ? "yes" : "no",
107  ENIC_SETTING(enic, RSS) ? "yes" : "no",
108  c->intr_mode == VENET_INTR_MODE_INTX ? "INTx" :
109  c->intr_mode == VENET_INTR_MODE_MSI ? "MSI" :
110  c->intr_mode == VENET_INTR_MODE_ANY ? "any" :
111  "unknown",
112  c->intr_timer_type == VENET_INTR_TYPE_MIN ? "min" :
113  c->intr_timer_type == VENET_INTR_TYPE_IDLE ? "idle" :
114  "unknown",
115  c->intr_timer_usec,
116  c->loop_tag);
117 
118  return 0;
119 }
120 
121 int enic_add_vlan(struct enic *enic, u16 vlanid)
122 {
123  u64 a0 = vlanid, a1 = 0;
124  int wait = 1000;
125  int err;
126 
127  err = vnic_dev_cmd(enic->vdev, CMD_VLAN_ADD, &a0, &a1, wait);
128  if (err)
129  dev_err(enic_get_dev(enic), "Can't add vlan id, %d\n", err);
130 
131  return err;
132 }
133 
134 int enic_del_vlan(struct enic *enic, u16 vlanid)
135 {
136  u64 a0 = vlanid, a1 = 0;
137  int wait = 1000;
138  int err;
139 
140  err = vnic_dev_cmd(enic->vdev, CMD_VLAN_DEL, &a0, &a1, wait);
141  if (err)
142  dev_err(enic_get_dev(enic), "Can't delete vlan id, %d\n", err);
143 
144  return err;
145 }
146 
147 int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
148  u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
149  u8 ig_vlan_strip_en)
150 {
151  u64 a0, a1;
152  u32 nic_cfg;
153  int wait = 1000;
154 
155  vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
156  rss_hash_type, rss_hash_bits, rss_base_cpu,
157  rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
158 
159  a0 = nic_cfg;
160  a1 = 0;
161 
162  return vnic_dev_cmd(enic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
163 }
164 
165 int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len)
166 {
167  u64 a0 = (u64)key_pa, a1 = len;
168  int wait = 1000;
169 
170  return vnic_dev_cmd(enic->vdev, CMD_RSS_KEY, &a0, &a1, wait);
171 }
172 
173 int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len)
174 {
175  u64 a0 = (u64)cpu_pa, a1 = len;
176  int wait = 1000;
177 
178  return vnic_dev_cmd(enic->vdev, CMD_RSS_CPU, &a0, &a1, wait);
179 }
180 
182 {
183  unsigned int i;
184 
185  for (i = 0; i < enic->wq_count; i++)
186  vnic_wq_free(&enic->wq[i]);
187  for (i = 0; i < enic->rq_count; i++)
188  vnic_rq_free(&enic->rq[i]);
189  for (i = 0; i < enic->cq_count; i++)
190  vnic_cq_free(&enic->cq[i]);
191  for (i = 0; i < enic->intr_count; i++)
192  vnic_intr_free(&enic->intr[i]);
193 }
194 
196 {
200  enic->intr_count = vnic_dev_get_res_count(enic->vdev,
202 
203  dev_info(enic_get_dev(enic),
204  "vNIC resources avail: wq %d rq %d cq %d intr %d\n",
205  enic->wq_count, enic->rq_count,
206  enic->cq_count, enic->intr_count);
207 }
208 
210 {
212  unsigned int mask_on_assertion;
213  unsigned int interrupt_offset;
214  unsigned int error_interrupt_enable;
215  unsigned int error_interrupt_offset;
216  unsigned int cq_index;
217  unsigned int i;
218 
219  intr_mode = vnic_dev_get_intr_mode(enic->vdev);
220 
221  /* Init RQ/WQ resources.
222  *
223  * RQ[0 - n-1] point to CQ[0 - n-1]
224  * WQ[0 - m-1] point to CQ[n - n+m-1]
225  *
226  * Error interrupt is not enabled for MSI.
227  */
228 
229  switch (intr_mode) {
232  error_interrupt_enable = 1;
233  error_interrupt_offset = enic->intr_count - 2;
234  break;
235  default:
236  error_interrupt_enable = 0;
237  error_interrupt_offset = 0;
238  break;
239  }
240 
241  for (i = 0; i < enic->rq_count; i++) {
242  cq_index = i;
243  vnic_rq_init(&enic->rq[i],
244  cq_index,
245  error_interrupt_enable,
246  error_interrupt_offset);
247  }
248 
249  for (i = 0; i < enic->wq_count; i++) {
250  cq_index = enic->rq_count + i;
251  vnic_wq_init(&enic->wq[i],
252  cq_index,
253  error_interrupt_enable,
254  error_interrupt_offset);
255  }
256 
257  /* Init CQ resources
258  *
259  * CQ[0 - n+m-1] point to INTR[0] for INTx, MSI
260  * CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X
261  */
262 
263  for (i = 0; i < enic->cq_count; i++) {
264 
265  switch (intr_mode) {
267  interrupt_offset = i;
268  break;
269  default:
270  interrupt_offset = 0;
271  break;
272  }
273 
274  vnic_cq_init(&enic->cq[i],
275  0 /* flow_control_enable */,
276  1 /* color_enable */,
277  0 /* cq_head */,
278  0 /* cq_tail */,
279  1 /* cq_tail_color */,
280  1 /* interrupt_enable */,
281  1 /* cq_entry_enable */,
282  0 /* cq_message_enable */,
283  interrupt_offset,
284  0 /* cq_message_addr */);
285  }
286 
287  /* Init INTR resources
288  *
289  * mask_on_assertion is not used for INTx due to the level-
290  * triggered nature of INTx
291  */
292 
293  switch (intr_mode) {
296  mask_on_assertion = 1;
297  break;
298  default:
299  mask_on_assertion = 0;
300  break;
301  }
302 
303  for (i = 0; i < enic->intr_count; i++) {
304  vnic_intr_init(&enic->intr[i],
305  enic->config.intr_timer_usec,
306  enic->config.intr_timer_type,
307  mask_on_assertion);
308  }
309 }
310 
312 {
314  unsigned int i;
315  int err;
316 
317  intr_mode = vnic_dev_get_intr_mode(enic->vdev);
318 
319  dev_info(enic_get_dev(enic), "vNIC resources used: "
320  "wq %d rq %d cq %d intr %d intr mode %s\n",
321  enic->wq_count, enic->rq_count,
322  enic->cq_count, enic->intr_count,
323  intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
324  intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
325  intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" :
326  "unknown");
327 
328  /* Allocate queue resources
329  */
330 
331  for (i = 0; i < enic->wq_count; i++) {
332  err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i,
333  enic->config.wq_desc_count,
334  sizeof(struct wq_enet_desc));
335  if (err)
336  goto err_out_cleanup;
337  }
338 
339  for (i = 0; i < enic->rq_count; i++) {
340  err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i,
341  enic->config.rq_desc_count,
342  sizeof(struct rq_enet_desc));
343  if (err)
344  goto err_out_cleanup;
345  }
346 
347  for (i = 0; i < enic->cq_count; i++) {
348  if (i < enic->rq_count)
349  err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
350  enic->config.rq_desc_count,
351  sizeof(struct cq_enet_rq_desc));
352  else
353  err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
354  enic->config.wq_desc_count,
355  sizeof(struct cq_enet_wq_desc));
356  if (err)
357  goto err_out_cleanup;
358  }
359 
360  for (i = 0; i < enic->intr_count; i++) {
361  err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
362  if (err)
363  goto err_out_cleanup;
364  }
365 
366  /* Hook remaining resource
367  */
368 
369  enic->legacy_pba = vnic_dev_get_res(enic->vdev,
371  if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
372  dev_err(enic_get_dev(enic),
373  "Failed to hook legacy pba resource\n");
374  err = -ENODEV;
375  goto err_out_cleanup;
376  }
377 
378  return 0;
379 
380 err_out_cleanup:
382 
383  return err;
384 }