root/drivers/net/ethernet/cisco/enic/enic_res.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. enic_get_vnic_config
  2. enic_add_vlan
  3. enic_del_vlan
  4. enic_set_nic_cfg
  5. enic_set_rss_key
  6. enic_set_rss_cpu
  7. enic_free_vnic_resources
  8. enic_get_res_counts
  9. enic_init_vnic_resources
  10. enic_alloc_vnic_resources

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

/* [<][>][^][v][top][bottom][index][help] */