172f3de30SBruce Richardson /* 272f3de30SBruce Richardson * Copyright 2008-2014 Cisco Systems, Inc. All rights reserved. 372f3de30SBruce Richardson * Copyright 2007 Nuova Systems, Inc. All rights reserved. 472f3de30SBruce Richardson * 572f3de30SBruce Richardson * Copyright (c) 2014, Cisco Systems, Inc. 672f3de30SBruce Richardson * All rights reserved. 772f3de30SBruce Richardson * 872f3de30SBruce Richardson * Redistribution and use in source and binary forms, with or without 972f3de30SBruce Richardson * modification, are permitted provided that the following conditions 1072f3de30SBruce Richardson * are met: 1172f3de30SBruce Richardson * 1272f3de30SBruce Richardson * 1. Redistributions of source code must retain the above copyright 1372f3de30SBruce Richardson * notice, this list of conditions and the following disclaimer. 1472f3de30SBruce Richardson * 1572f3de30SBruce Richardson * 2. Redistributions in binary form must reproduce the above copyright 1672f3de30SBruce Richardson * notice, this list of conditions and the following disclaimer in 1772f3de30SBruce Richardson * the documentation and/or other materials provided with the 1872f3de30SBruce Richardson * distribution. 1972f3de30SBruce Richardson * 2072f3de30SBruce Richardson * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2172f3de30SBruce Richardson * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2272f3de30SBruce Richardson * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2372f3de30SBruce Richardson * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 2472f3de30SBruce Richardson * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2572f3de30SBruce Richardson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2672f3de30SBruce Richardson * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2772f3de30SBruce Richardson * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 2872f3de30SBruce Richardson * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2972f3de30SBruce Richardson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 3072f3de30SBruce Richardson * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3172f3de30SBruce Richardson * POSSIBILITY OF SUCH DAMAGE. 3272f3de30SBruce Richardson * 3372f3de30SBruce Richardson */ 3472f3de30SBruce Richardson 3572f3de30SBruce Richardson #include <stdio.h> 3672f3de30SBruce Richardson 3772f3de30SBruce Richardson #include <sys/stat.h> 3872f3de30SBruce Richardson #include <sys/mman.h> 3972f3de30SBruce Richardson #include <fcntl.h> 4072f3de30SBruce Richardson #include <libgen.h> 4172f3de30SBruce Richardson 4272f3de30SBruce Richardson #include <rte_pci.h> 4372f3de30SBruce Richardson #include <rte_memzone.h> 4472f3de30SBruce Richardson #include <rte_malloc.h> 4572f3de30SBruce Richardson #include <rte_mbuf.h> 4672f3de30SBruce Richardson #include <rte_string_fns.h> 4772f3de30SBruce Richardson #include <rte_ethdev.h> 4872f3de30SBruce Richardson 4972f3de30SBruce Richardson #include "enic_compat.h" 5072f3de30SBruce Richardson #include "enic.h" 5172f3de30SBruce Richardson #include "wq_enet_desc.h" 5272f3de30SBruce Richardson #include "rq_enet_desc.h" 5372f3de30SBruce Richardson #include "cq_enet_desc.h" 5472f3de30SBruce Richardson #include "vnic_enet.h" 5572f3de30SBruce Richardson #include "vnic_dev.h" 5672f3de30SBruce Richardson #include "vnic_wq.h" 5772f3de30SBruce Richardson #include "vnic_rq.h" 5872f3de30SBruce Richardson #include "vnic_cq.h" 5972f3de30SBruce Richardson #include "vnic_intr.h" 6072f3de30SBruce Richardson #include "vnic_nic.h" 6172f3de30SBruce Richardson 6272f3de30SBruce Richardson static inline int enic_is_sriov_vf(struct enic *enic) 6372f3de30SBruce Richardson { 6472f3de30SBruce Richardson return enic->pdev->id.device_id == PCI_DEVICE_ID_CISCO_VIC_ENET_VF; 6572f3de30SBruce Richardson } 6672f3de30SBruce Richardson 6772f3de30SBruce Richardson static int is_zero_addr(uint8_t *addr) 6872f3de30SBruce Richardson { 6972f3de30SBruce Richardson return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]); 7072f3de30SBruce Richardson } 7172f3de30SBruce Richardson 7272f3de30SBruce Richardson static int is_mcast_addr(uint8_t *addr) 7372f3de30SBruce Richardson { 7472f3de30SBruce Richardson return addr[0] & 1; 7572f3de30SBruce Richardson } 7672f3de30SBruce Richardson 7772f3de30SBruce Richardson static int is_eth_addr_valid(uint8_t *addr) 7872f3de30SBruce Richardson { 7972f3de30SBruce Richardson return !is_mcast_addr(addr) && !is_zero_addr(addr); 8072f3de30SBruce Richardson } 8172f3de30SBruce Richardson 82947d860cSJohn Daley static void 83a44a1724SNelson Escobar enic_rxmbuf_queue_release(__rte_unused struct enic *enic, struct vnic_rq *rq) 8472f3de30SBruce Richardson { 85947d860cSJohn Daley uint16_t i; 8672f3de30SBruce Richardson 87947d860cSJohn Daley if (!rq || !rq->mbuf_ring) { 88947d860cSJohn Daley dev_debug(enic, "Pointer to rq or mbuf_ring is NULL"); 89947d860cSJohn Daley return; 9072f3de30SBruce Richardson } 9172f3de30SBruce Richardson 92a44a1724SNelson Escobar for (i = 0; i < rq->ring.desc_count; i++) { 93947d860cSJohn Daley if (rq->mbuf_ring[i]) { 94947d860cSJohn Daley rte_pktmbuf_free_seg(rq->mbuf_ring[i]); 95947d860cSJohn Daley rq->mbuf_ring[i] = NULL; 96947d860cSJohn Daley } 97947d860cSJohn Daley } 98947d860cSJohn Daley } 99947d860cSJohn Daley 10072f3de30SBruce Richardson void enic_set_hdr_split_size(struct enic *enic, u16 split_hdr_size) 10172f3de30SBruce Richardson { 10272f3de30SBruce Richardson vnic_set_hdr_split_size(enic->vdev, split_hdr_size); 10372f3de30SBruce Richardson } 10472f3de30SBruce Richardson 1059455b237SJohn Daley static void enic_free_wq_buf(struct vnic_wq_buf *buf) 10672f3de30SBruce Richardson { 107a3b1e955SJohn Daley struct rte_mbuf *mbuf = (struct rte_mbuf *)buf->mb; 10872f3de30SBruce Richardson 109da24f6f6SJohn Daley rte_pktmbuf_free_seg(mbuf); 110a3b1e955SJohn Daley buf->mb = NULL; 11172f3de30SBruce Richardson } 11272f3de30SBruce Richardson 11372f3de30SBruce Richardson static void enic_log_q_error(struct enic *enic) 11472f3de30SBruce Richardson { 11572f3de30SBruce Richardson unsigned int i; 11672f3de30SBruce Richardson u32 error_status; 11772f3de30SBruce Richardson 11872f3de30SBruce Richardson for (i = 0; i < enic->wq_count; i++) { 11972f3de30SBruce Richardson error_status = vnic_wq_error_status(&enic->wq[i]); 12072f3de30SBruce Richardson if (error_status) 12172f3de30SBruce Richardson dev_err(enic, "WQ[%d] error_status %d\n", i, 12272f3de30SBruce Richardson error_status); 12372f3de30SBruce Richardson } 12472f3de30SBruce Richardson 125856d7ba7SNelson Escobar for (i = 0; i < enic_vnic_rq_count(enic); i++) { 126e3725e7fSNelson Escobar if (!enic->rq[i].in_use) 127e3725e7fSNelson Escobar continue; 12872f3de30SBruce Richardson error_status = vnic_rq_error_status(&enic->rq[i]); 12972f3de30SBruce Richardson if (error_status) 13072f3de30SBruce Richardson dev_err(enic, "RQ[%d] error_status %d\n", i, 13172f3de30SBruce Richardson error_status); 13272f3de30SBruce Richardson } 13372f3de30SBruce Richardson } 13472f3de30SBruce Richardson 13565b5434dSJohn Daley static void enic_clear_soft_stats(struct enic *enic) 13665b5434dSJohn Daley { 13765b5434dSJohn Daley struct enic_soft_stats *soft_stats = &enic->soft_stats; 13865b5434dSJohn Daley rte_atomic64_clear(&soft_stats->rx_nombuf); 139c44d9f01SJohn Daley rte_atomic64_clear(&soft_stats->rx_packet_errors); 14065b5434dSJohn Daley } 14165b5434dSJohn Daley 14265b5434dSJohn Daley static void enic_init_soft_stats(struct enic *enic) 14365b5434dSJohn Daley { 14465b5434dSJohn Daley struct enic_soft_stats *soft_stats = &enic->soft_stats; 14565b5434dSJohn Daley rte_atomic64_init(&soft_stats->rx_nombuf); 146c44d9f01SJohn Daley rte_atomic64_init(&soft_stats->rx_packet_errors); 14765b5434dSJohn Daley enic_clear_soft_stats(enic); 14865b5434dSJohn Daley } 14965b5434dSJohn Daley 15072f3de30SBruce Richardson void enic_dev_stats_clear(struct enic *enic) 15172f3de30SBruce Richardson { 15272f3de30SBruce Richardson if (vnic_dev_stats_clear(enic->vdev)) 15372f3de30SBruce Richardson dev_err(enic, "Error in clearing stats\n"); 15465b5434dSJohn Daley enic_clear_soft_stats(enic); 15572f3de30SBruce Richardson } 15672f3de30SBruce Richardson 15772f3de30SBruce Richardson void enic_dev_stats_get(struct enic *enic, struct rte_eth_stats *r_stats) 15872f3de30SBruce Richardson { 15972f3de30SBruce Richardson struct vnic_stats *stats; 160c44d9f01SJohn Daley struct enic_soft_stats *soft_stats = &enic->soft_stats; 161c44d9f01SJohn Daley int64_t rx_truncated; 162c44d9f01SJohn Daley uint64_t rx_packet_errors; 16372f3de30SBruce Richardson 16472f3de30SBruce Richardson if (vnic_dev_stats_dump(enic->vdev, &stats)) { 16572f3de30SBruce Richardson dev_err(enic, "Error in getting stats\n"); 16672f3de30SBruce Richardson return; 16772f3de30SBruce Richardson } 16872f3de30SBruce Richardson 169c44d9f01SJohn Daley /* The number of truncated packets can only be calculated by 170c44d9f01SJohn Daley * subtracting a hardware counter from error packets received by 171c44d9f01SJohn Daley * the driver. Note: this causes transient inaccuracies in the 172c44d9f01SJohn Daley * ipackets count. Also, the length of truncated packets are 173c44d9f01SJohn Daley * counted in ibytes even though truncated packets are dropped 174c44d9f01SJohn Daley * which can make ibytes be slightly higher than it should be. 175c44d9f01SJohn Daley */ 176c44d9f01SJohn Daley rx_packet_errors = rte_atomic64_read(&soft_stats->rx_packet_errors); 177c92efcaeSNelson Escobar rx_truncated = rx_packet_errors - stats->rx.rx_errors; 178c44d9f01SJohn Daley 179c44d9f01SJohn Daley r_stats->ipackets = stats->rx.rx_frames_ok - rx_truncated; 18072f3de30SBruce Richardson r_stats->opackets = stats->tx.tx_frames_ok; 18172f3de30SBruce Richardson 18272f3de30SBruce Richardson r_stats->ibytes = stats->rx.rx_bytes_ok; 18372f3de30SBruce Richardson r_stats->obytes = stats->tx.tx_bytes_ok; 18472f3de30SBruce Richardson 18565b5434dSJohn Daley r_stats->ierrors = stats->rx.rx_errors + stats->rx.rx_drop; 18672f3de30SBruce Richardson r_stats->oerrors = stats->tx.tx_errors; 18772f3de30SBruce Richardson 188c44d9f01SJohn Daley r_stats->imissed = stats->rx.rx_no_bufs + rx_truncated; 1897182d3e7SJohn Daley 19065b5434dSJohn Daley r_stats->rx_nombuf = rte_atomic64_read(&soft_stats->rx_nombuf); 19172f3de30SBruce Richardson } 19272f3de30SBruce Richardson 193*bbab3d97SJohn Daley void enic_del_mac_address(struct enic *enic, int mac_index) 19472f3de30SBruce Richardson { 195*bbab3d97SJohn Daley struct rte_eth_dev *eth_dev = enic->rte_dev; 196*bbab3d97SJohn Daley uint8_t *mac_addr = eth_dev->data->mac_addrs[mac_index].addr_bytes; 197*bbab3d97SJohn Daley 198*bbab3d97SJohn Daley if (vnic_dev_del_addr(enic->vdev, mac_addr)) 19972f3de30SBruce Richardson dev_err(enic, "del mac addr failed\n"); 20072f3de30SBruce Richardson } 20172f3de30SBruce Richardson 20272f3de30SBruce Richardson void enic_set_mac_address(struct enic *enic, uint8_t *mac_addr) 20372f3de30SBruce Richardson { 20472f3de30SBruce Richardson int err; 20572f3de30SBruce Richardson 20672f3de30SBruce Richardson if (!is_eth_addr_valid(mac_addr)) { 20772f3de30SBruce Richardson dev_err(enic, "invalid mac address\n"); 20872f3de30SBruce Richardson return; 20972f3de30SBruce Richardson } 21072f3de30SBruce Richardson 21172f3de30SBruce Richardson err = vnic_dev_add_addr(enic->vdev, mac_addr); 21272f3de30SBruce Richardson if (err) { 21372f3de30SBruce Richardson dev_err(enic, "add mac addr failed\n"); 21472f3de30SBruce Richardson return; 21572f3de30SBruce Richardson } 21672f3de30SBruce Richardson } 21772f3de30SBruce Richardson 21872f3de30SBruce Richardson static void 219947d860cSJohn Daley enic_free_rq_buf(struct rte_mbuf **mbuf) 22072f3de30SBruce Richardson { 221947d860cSJohn Daley if (*mbuf == NULL) 22272f3de30SBruce Richardson return; 22372f3de30SBruce Richardson 224947d860cSJohn Daley rte_pktmbuf_free(*mbuf); 225947d860cSJohn Daley mbuf = NULL; 22672f3de30SBruce Richardson } 22772f3de30SBruce Richardson 22872f3de30SBruce Richardson void enic_init_vnic_resources(struct enic *enic) 22972f3de30SBruce Richardson { 23072f3de30SBruce Richardson unsigned int error_interrupt_enable = 1; 23172f3de30SBruce Richardson unsigned int error_interrupt_offset = 0; 23272f3de30SBruce Richardson unsigned int index = 0; 233fc2c8c06SJohn Daley unsigned int cq_idx; 234856d7ba7SNelson Escobar struct vnic_rq *data_rq; 23572f3de30SBruce Richardson 23672f3de30SBruce Richardson for (index = 0; index < enic->rq_count; index++) { 237aa07bf8fSJohn Daley cq_idx = enic_cq_rq(enic, enic_rte_rq_idx_to_sop_idx(index)); 23816dba071SNelson Escobar 239aa07bf8fSJohn Daley vnic_rq_init(&enic->rq[enic_rte_rq_idx_to_sop_idx(index)], 24016dba071SNelson Escobar cq_idx, 241856d7ba7SNelson Escobar error_interrupt_enable, 242856d7ba7SNelson Escobar error_interrupt_offset); 243856d7ba7SNelson Escobar 244aa07bf8fSJohn Daley data_rq = &enic->rq[enic_rte_rq_idx_to_data_idx(index)]; 245856d7ba7SNelson Escobar if (data_rq->in_use) 246856d7ba7SNelson Escobar vnic_rq_init(data_rq, 24716dba071SNelson Escobar cq_idx, 24872f3de30SBruce Richardson error_interrupt_enable, 24972f3de30SBruce Richardson error_interrupt_offset); 25072f3de30SBruce Richardson 251fc2c8c06SJohn Daley vnic_cq_init(&enic->cq[cq_idx], 25272f3de30SBruce Richardson 0 /* flow_control_enable */, 25372f3de30SBruce Richardson 1 /* color_enable */, 25472f3de30SBruce Richardson 0 /* cq_head */, 25572f3de30SBruce Richardson 0 /* cq_tail */, 25672f3de30SBruce Richardson 1 /* cq_tail_color */, 25772f3de30SBruce Richardson 0 /* interrupt_enable */, 25872f3de30SBruce Richardson 1 /* cq_entry_enable */, 25972f3de30SBruce Richardson 0 /* cq_message_enable */, 26072f3de30SBruce Richardson 0 /* interrupt offset */, 26172f3de30SBruce Richardson 0 /* cq_message_addr */); 26272f3de30SBruce Richardson } 26372f3de30SBruce Richardson 264fc2c8c06SJohn Daley for (index = 0; index < enic->wq_count; index++) { 265fc2c8c06SJohn Daley vnic_wq_init(&enic->wq[index], 266fc2c8c06SJohn Daley enic_cq_wq(enic, index), 267fc2c8c06SJohn Daley error_interrupt_enable, 268fc2c8c06SJohn Daley error_interrupt_offset); 269fc2c8c06SJohn Daley 270fc2c8c06SJohn Daley cq_idx = enic_cq_wq(enic, index); 271fc2c8c06SJohn Daley vnic_cq_init(&enic->cq[cq_idx], 272fc2c8c06SJohn Daley 0 /* flow_control_enable */, 273fc2c8c06SJohn Daley 1 /* color_enable */, 274fc2c8c06SJohn Daley 0 /* cq_head */, 275fc2c8c06SJohn Daley 0 /* cq_tail */, 276fc2c8c06SJohn Daley 1 /* cq_tail_color */, 277fc2c8c06SJohn Daley 0 /* interrupt_enable */, 278fc2c8c06SJohn Daley 0 /* cq_entry_enable */, 279fc2c8c06SJohn Daley 1 /* cq_message_enable */, 280fc2c8c06SJohn Daley 0 /* interrupt offset */, 281fc2c8c06SJohn Daley (u64)enic->wq[index].cqmsg_rz->phys_addr); 282fc2c8c06SJohn Daley } 283fc2c8c06SJohn Daley 28472f3de30SBruce Richardson vnic_intr_init(&enic->intr, 28572f3de30SBruce Richardson enic->config.intr_timer_usec, 28672f3de30SBruce Richardson enic->config.intr_timer_type, 28772f3de30SBruce Richardson /*mask_on_assertion*/1); 28872f3de30SBruce Richardson } 28972f3de30SBruce Richardson 29072f3de30SBruce Richardson 291947d860cSJohn Daley static int 292947d860cSJohn Daley enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq) 29372f3de30SBruce Richardson { 294947d860cSJohn Daley struct rte_mbuf *mb; 295947d860cSJohn Daley struct rq_enet_desc *rqd = rq->ring.descs; 296947d860cSJohn Daley unsigned i; 29772f3de30SBruce Richardson dma_addr_t dma_addr; 29872f3de30SBruce Richardson 299856d7ba7SNelson Escobar if (!rq->in_use) 300856d7ba7SNelson Escobar return 0; 301856d7ba7SNelson Escobar 302bba57df3SNelson Escobar dev_debug(enic, "queue %u, allocating %u rx queue mbufs\n", rq->index, 303947d860cSJohn Daley rq->ring.desc_count); 304947d860cSJohn Daley 305947d860cSJohn Daley for (i = 0; i < rq->ring.desc_count; i++, rqd++) { 306fbfd9955SOlivier Matz mb = rte_mbuf_raw_alloc(rq->mp); 307947d860cSJohn Daley if (mb == NULL) { 308bba57df3SNelson Escobar dev_err(enic, "RX mbuf alloc failed queue_id=%u\n", 309947d860cSJohn Daley (unsigned)rq->index); 310947d860cSJohn Daley return -ENOMEM; 31172f3de30SBruce Richardson } 31272f3de30SBruce Richardson 3131ccc51b0SJohn Daley mb->data_off = RTE_PKTMBUF_HEADROOM; 3144a3259d6SJohn Daley dma_addr = (dma_addr_t)(mb->buf_physaddr 3154a3259d6SJohn Daley + RTE_PKTMBUF_HEADROOM); 316856d7ba7SNelson Escobar rq_enet_desc_enc(rqd, dma_addr, 317856d7ba7SNelson Escobar (rq->is_sop ? RQ_ENET_TYPE_ONLY_SOP 318856d7ba7SNelson Escobar : RQ_ENET_TYPE_NOT_SOP), 3194a3259d6SJohn Daley mb->buf_len - RTE_PKTMBUF_HEADROOM); 320947d860cSJohn Daley rq->mbuf_ring[i] = mb; 32172f3de30SBruce Richardson } 32272f3de30SBruce Richardson 323947d860cSJohn Daley /* make sure all prior writes are complete before doing the PIO write */ 324947d860cSJohn Daley rte_rmb(); 32572f3de30SBruce Richardson 326856d7ba7SNelson Escobar /* Post all but the last buffer to VIC. */ 327856d7ba7SNelson Escobar rq->posted_index = rq->ring.desc_count - 1; 328856d7ba7SNelson Escobar 329947d860cSJohn Daley rq->rx_nb_hold = 0; 33072f3de30SBruce Richardson 331947d860cSJohn Daley dev_debug(enic, "port=%u, qidx=%u, Write %u posted idx, %u sw held\n", 332947d860cSJohn Daley enic->port_id, rq->index, rq->posted_index, rq->rx_nb_hold); 333947d860cSJohn Daley iowrite32(rq->posted_index, &rq->ctrl->posted_index); 33404f97689SJohn Daley iowrite32(0, &rq->ctrl->fetch_index); 335947d860cSJohn Daley rte_rmb(); 33672f3de30SBruce Richardson 33772f3de30SBruce Richardson return 0; 33872f3de30SBruce Richardson 33972f3de30SBruce Richardson } 34072f3de30SBruce Richardson 34172f3de30SBruce Richardson static void * 342da5f560bSNelson Escobar enic_alloc_consistent(void *priv, size_t size, 34372f3de30SBruce Richardson dma_addr_t *dma_handle, u8 *name) 34472f3de30SBruce Richardson { 34572f3de30SBruce Richardson void *vaddr; 34672f3de30SBruce Richardson const struct rte_memzone *rz; 34772f3de30SBruce Richardson *dma_handle = 0; 348da5f560bSNelson Escobar struct enic *enic = (struct enic *)priv; 349da5f560bSNelson Escobar struct enic_memzone_entry *mze; 35072f3de30SBruce Richardson 35172f3de30SBruce Richardson rz = rte_memzone_reserve_aligned((const char *)name, 3527a0b8b7cSDavid Marchand size, SOCKET_ID_ANY, 0, ENIC_ALIGN); 35372f3de30SBruce Richardson if (!rz) { 354bba57df3SNelson Escobar pr_err("%s : Failed to allocate memory requested for %s\n", 35572f3de30SBruce Richardson __func__, name); 35672f3de30SBruce Richardson return NULL; 35772f3de30SBruce Richardson } 35872f3de30SBruce Richardson 35972f3de30SBruce Richardson vaddr = rz->addr; 36072f3de30SBruce Richardson *dma_handle = (dma_addr_t)rz->phys_addr; 36172f3de30SBruce Richardson 362da5f560bSNelson Escobar mze = rte_malloc("enic memzone entry", 363da5f560bSNelson Escobar sizeof(struct enic_memzone_entry), 0); 364da5f560bSNelson Escobar 365da5f560bSNelson Escobar if (!mze) { 366da5f560bSNelson Escobar pr_err("%s : Failed to allocate memory for memzone list\n", 367da5f560bSNelson Escobar __func__); 368da5f560bSNelson Escobar rte_memzone_free(rz); 369da5f560bSNelson Escobar } 370da5f560bSNelson Escobar 371da5f560bSNelson Escobar mze->rz = rz; 372da5f560bSNelson Escobar 373da5f560bSNelson Escobar rte_spinlock_lock(&enic->memzone_list_lock); 374da5f560bSNelson Escobar LIST_INSERT_HEAD(&enic->memzone_list, mze, entries); 375da5f560bSNelson Escobar rte_spinlock_unlock(&enic->memzone_list_lock); 376da5f560bSNelson Escobar 37772f3de30SBruce Richardson return vaddr; 37872f3de30SBruce Richardson } 37972f3de30SBruce Richardson 38072f3de30SBruce Richardson static void 381da5f560bSNelson Escobar enic_free_consistent(void *priv, 38272f3de30SBruce Richardson __rte_unused size_t size, 383da5f560bSNelson Escobar void *vaddr, 384da5f560bSNelson Escobar dma_addr_t dma_handle) 38572f3de30SBruce Richardson { 386da5f560bSNelson Escobar struct enic_memzone_entry *mze; 387da5f560bSNelson Escobar struct enic *enic = (struct enic *)priv; 388da5f560bSNelson Escobar 389da5f560bSNelson Escobar rte_spinlock_lock(&enic->memzone_list_lock); 390da5f560bSNelson Escobar LIST_FOREACH(mze, &enic->memzone_list, entries) { 391da5f560bSNelson Escobar if (mze->rz->addr == vaddr && 392da5f560bSNelson Escobar mze->rz->phys_addr == dma_handle) 393da5f560bSNelson Escobar break; 394da5f560bSNelson Escobar } 395da5f560bSNelson Escobar if (mze == NULL) { 396da5f560bSNelson Escobar rte_spinlock_unlock(&enic->memzone_list_lock); 397da5f560bSNelson Escobar dev_warning(enic, 398da5f560bSNelson Escobar "Tried to free memory, but couldn't find it in the memzone list\n"); 399da5f560bSNelson Escobar return; 400da5f560bSNelson Escobar } 401da5f560bSNelson Escobar LIST_REMOVE(mze, entries); 402da5f560bSNelson Escobar rte_spinlock_unlock(&enic->memzone_list_lock); 403da5f560bSNelson Escobar rte_memzone_free(mze->rz); 404da5f560bSNelson Escobar rte_free(mze); 40572f3de30SBruce Richardson } 40672f3de30SBruce Richardson 407cf8d9826SNelson Escobar int enic_link_update(struct enic *enic) 408cf8d9826SNelson Escobar { 409cf8d9826SNelson Escobar struct rte_eth_dev *eth_dev = enic->rte_dev; 410cf8d9826SNelson Escobar int ret; 411cf8d9826SNelson Escobar int link_status = 0; 412cf8d9826SNelson Escobar 413cf8d9826SNelson Escobar link_status = enic_get_link_status(enic); 414cf8d9826SNelson Escobar ret = (link_status == enic->link_status); 415cf8d9826SNelson Escobar enic->link_status = link_status; 416cf8d9826SNelson Escobar eth_dev->data->dev_link.link_status = link_status; 417cf8d9826SNelson Escobar eth_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX; 418cf8d9826SNelson Escobar eth_dev->data->dev_link.link_speed = vnic_dev_port_speed(enic->vdev); 419cf8d9826SNelson Escobar return ret; 420cf8d9826SNelson Escobar } 421cf8d9826SNelson Escobar 42272f3de30SBruce Richardson static void 42372f3de30SBruce Richardson enic_intr_handler(__rte_unused struct rte_intr_handle *handle, 42472f3de30SBruce Richardson void *arg) 42572f3de30SBruce Richardson { 42653fa8cc0SNelson Escobar struct rte_eth_dev *dev = (struct rte_eth_dev *)arg; 42753fa8cc0SNelson Escobar struct enic *enic = pmd_priv(dev); 42872f3de30SBruce Richardson 42972f3de30SBruce Richardson vnic_intr_return_all_credits(&enic->intr); 43072f3de30SBruce Richardson 43153fa8cc0SNelson Escobar enic_link_update(enic); 432c1ceaf3aSBernard Iremonger _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL); 43372f3de30SBruce Richardson enic_log_q_error(enic); 43472f3de30SBruce Richardson } 43572f3de30SBruce Richardson 43672f3de30SBruce Richardson int enic_enable(struct enic *enic) 43772f3de30SBruce Richardson { 43872f3de30SBruce Richardson unsigned int index; 439947d860cSJohn Daley int err; 44072f3de30SBruce Richardson struct rte_eth_dev *eth_dev = enic->rte_dev; 44172f3de30SBruce Richardson 44272f3de30SBruce Richardson eth_dev->data->dev_link.link_speed = vnic_dev_port_speed(enic->vdev); 44372f3de30SBruce Richardson eth_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX; 44472f3de30SBruce Richardson 44553fa8cc0SNelson Escobar /* vnic notification of link status has already been turned on in 44653fa8cc0SNelson Escobar * enic_dev_init() which is called during probe time. Here we are 44753fa8cc0SNelson Escobar * just turning on interrupt vector 0 if needed. 44853fa8cc0SNelson Escobar */ 44953fa8cc0SNelson Escobar if (eth_dev->data->dev_conf.intr_conf.lsc) 45053fa8cc0SNelson Escobar vnic_dev_notify_set(enic->vdev, 0); 45153fa8cc0SNelson Escobar 45272f3de30SBruce Richardson if (enic_clsf_init(enic)) 45372f3de30SBruce Richardson dev_warning(enic, "Init of hash table for clsf failed."\ 45472f3de30SBruce Richardson "Flow director feature will not work\n"); 45572f3de30SBruce Richardson 45672f3de30SBruce Richardson for (index = 0; index < enic->rq_count; index++) { 457856d7ba7SNelson Escobar err = enic_alloc_rx_queue_mbufs(enic, 458aa07bf8fSJohn Daley &enic->rq[enic_rte_rq_idx_to_sop_idx(index)]); 459947d860cSJohn Daley if (err) { 460856d7ba7SNelson Escobar dev_err(enic, "Failed to alloc sop RX queue mbufs\n"); 461856d7ba7SNelson Escobar return err; 462856d7ba7SNelson Escobar } 463856d7ba7SNelson Escobar err = enic_alloc_rx_queue_mbufs(enic, 464aa07bf8fSJohn Daley &enic->rq[enic_rte_rq_idx_to_data_idx(index)]); 465856d7ba7SNelson Escobar if (err) { 466856d7ba7SNelson Escobar /* release the allocated mbufs for the sop rq*/ 467856d7ba7SNelson Escobar enic_rxmbuf_queue_release(enic, 468aa07bf8fSJohn Daley &enic->rq[enic_rte_rq_idx_to_sop_idx(index)]); 469856d7ba7SNelson Escobar 470856d7ba7SNelson Escobar dev_err(enic, "Failed to alloc data RX queue mbufs\n"); 471947d860cSJohn Daley return err; 47272f3de30SBruce Richardson } 47372f3de30SBruce Richardson } 47472f3de30SBruce Richardson 47572f3de30SBruce Richardson for (index = 0; index < enic->wq_count; index++) 476856d7ba7SNelson Escobar enic_start_wq(enic, index); 47772f3de30SBruce Richardson for (index = 0; index < enic->rq_count; index++) 478856d7ba7SNelson Escobar enic_start_rq(enic, index); 47972f3de30SBruce Richardson 480e5b60cf1SNelson Escobar vnic_dev_add_addr(enic->vdev, enic->mac_addr); 481e5b60cf1SNelson Escobar 48272f3de30SBruce Richardson vnic_dev_enable_wait(enic->vdev); 48372f3de30SBruce Richardson 48472f3de30SBruce Richardson /* Register and enable error interrupt */ 48572f3de30SBruce Richardson rte_intr_callback_register(&(enic->pdev->intr_handle), 48672f3de30SBruce Richardson enic_intr_handler, (void *)enic->rte_dev); 48772f3de30SBruce Richardson 48872f3de30SBruce Richardson rte_intr_enable(&(enic->pdev->intr_handle)); 48972f3de30SBruce Richardson vnic_intr_unmask(&enic->intr); 49072f3de30SBruce Richardson 49172f3de30SBruce Richardson return 0; 49272f3de30SBruce Richardson } 49372f3de30SBruce Richardson 49472f3de30SBruce Richardson int enic_alloc_intr_resources(struct enic *enic) 49572f3de30SBruce Richardson { 49672f3de30SBruce Richardson int err; 49772f3de30SBruce Richardson 49872f3de30SBruce Richardson dev_info(enic, "vNIC resources used: "\ 49972f3de30SBruce Richardson "wq %d rq %d cq %d intr %d\n", 500856d7ba7SNelson Escobar enic->wq_count, enic_vnic_rq_count(enic), 50172f3de30SBruce Richardson enic->cq_count, enic->intr_count); 50272f3de30SBruce Richardson 50372f3de30SBruce Richardson err = vnic_intr_alloc(enic->vdev, &enic->intr, 0); 50472f3de30SBruce Richardson if (err) 50572f3de30SBruce Richardson enic_free_vnic_resources(enic); 50672f3de30SBruce Richardson 50772f3de30SBruce Richardson return err; 50872f3de30SBruce Richardson } 50972f3de30SBruce Richardson 51072f3de30SBruce Richardson void enic_free_rq(void *rxq) 51172f3de30SBruce Richardson { 512856d7ba7SNelson Escobar struct vnic_rq *rq_sop, *rq_data; 51383a9d8b7SJohn Daley struct enic *enic; 51472f3de30SBruce Richardson 51583a9d8b7SJohn Daley if (rxq == NULL) 51683a9d8b7SJohn Daley return; 51783a9d8b7SJohn Daley 518856d7ba7SNelson Escobar rq_sop = (struct vnic_rq *)rxq; 519856d7ba7SNelson Escobar enic = vnic_dev_priv(rq_sop->vdev); 520856d7ba7SNelson Escobar rq_data = &enic->rq[rq_sop->data_queue_idx]; 521856d7ba7SNelson Escobar 522856d7ba7SNelson Escobar enic_rxmbuf_queue_release(enic, rq_sop); 523856d7ba7SNelson Escobar if (rq_data->in_use) 524856d7ba7SNelson Escobar enic_rxmbuf_queue_release(enic, rq_data); 525856d7ba7SNelson Escobar 526856d7ba7SNelson Escobar rte_free(rq_sop->mbuf_ring); 527856d7ba7SNelson Escobar if (rq_data->in_use) 528856d7ba7SNelson Escobar rte_free(rq_data->mbuf_ring); 529856d7ba7SNelson Escobar 530856d7ba7SNelson Escobar rq_sop->mbuf_ring = NULL; 531856d7ba7SNelson Escobar rq_data->mbuf_ring = NULL; 532856d7ba7SNelson Escobar 533856d7ba7SNelson Escobar vnic_rq_free(rq_sop); 534856d7ba7SNelson Escobar if (rq_data->in_use) 535856d7ba7SNelson Escobar vnic_rq_free(rq_data); 536856d7ba7SNelson Escobar 537ceeb00b9SJohn Daley vnic_cq_free(&enic->cq[enic_sop_rq_idx_to_cq_idx(rq_sop->index)]); 538c3e09182SJohn Daley 539c3e09182SJohn Daley rq_sop->in_use = 0; 540c3e09182SJohn Daley rq_data->in_use = 0; 54172f3de30SBruce Richardson } 54272f3de30SBruce Richardson 54372f3de30SBruce Richardson void enic_start_wq(struct enic *enic, uint16_t queue_idx) 54472f3de30SBruce Richardson { 545837e68aeSJohn Daley struct rte_eth_dev *eth_dev = enic->rte_dev; 54672f3de30SBruce Richardson vnic_wq_enable(&enic->wq[queue_idx]); 547837e68aeSJohn Daley eth_dev->data->tx_queue_state[queue_idx] = RTE_ETH_QUEUE_STATE_STARTED; 54872f3de30SBruce Richardson } 54972f3de30SBruce Richardson 55072f3de30SBruce Richardson int enic_stop_wq(struct enic *enic, uint16_t queue_idx) 55172f3de30SBruce Richardson { 552837e68aeSJohn Daley struct rte_eth_dev *eth_dev = enic->rte_dev; 553837e68aeSJohn Daley int ret; 554837e68aeSJohn Daley 555837e68aeSJohn Daley ret = vnic_wq_disable(&enic->wq[queue_idx]); 556837e68aeSJohn Daley if (ret) 557837e68aeSJohn Daley return ret; 558837e68aeSJohn Daley 559837e68aeSJohn Daley eth_dev->data->tx_queue_state[queue_idx] = RTE_ETH_QUEUE_STATE_STOPPED; 560837e68aeSJohn Daley return 0; 56172f3de30SBruce Richardson } 56272f3de30SBruce Richardson 56372f3de30SBruce Richardson void enic_start_rq(struct enic *enic, uint16_t queue_idx) 56472f3de30SBruce Richardson { 565aa07bf8fSJohn Daley struct vnic_rq *rq_sop; 566aa07bf8fSJohn Daley struct vnic_rq *rq_data; 567aa07bf8fSJohn Daley rq_sop = &enic->rq[enic_rte_rq_idx_to_sop_idx(queue_idx)]; 568aa07bf8fSJohn Daley rq_data = &enic->rq[rq_sop->data_queue_idx]; 569837e68aeSJohn Daley struct rte_eth_dev *eth_dev = enic->rte_dev; 570856d7ba7SNelson Escobar 571856d7ba7SNelson Escobar if (rq_data->in_use) 572856d7ba7SNelson Escobar vnic_rq_enable(rq_data); 573856d7ba7SNelson Escobar rte_mb(); 574856d7ba7SNelson Escobar vnic_rq_enable(rq_sop); 575837e68aeSJohn Daley eth_dev->data->rx_queue_state[queue_idx] = RTE_ETH_QUEUE_STATE_STARTED; 57672f3de30SBruce Richardson } 57772f3de30SBruce Richardson 57872f3de30SBruce Richardson int enic_stop_rq(struct enic *enic, uint16_t queue_idx) 57972f3de30SBruce Richardson { 580856d7ba7SNelson Escobar int ret1 = 0, ret2 = 0; 581837e68aeSJohn Daley struct rte_eth_dev *eth_dev = enic->rte_dev; 582aa07bf8fSJohn Daley struct vnic_rq *rq_sop; 583aa07bf8fSJohn Daley struct vnic_rq *rq_data; 584aa07bf8fSJohn Daley rq_sop = &enic->rq[enic_rte_rq_idx_to_sop_idx(queue_idx)]; 585aa07bf8fSJohn Daley rq_data = &enic->rq[rq_sop->data_queue_idx]; 586856d7ba7SNelson Escobar 587856d7ba7SNelson Escobar ret2 = vnic_rq_disable(rq_sop); 588856d7ba7SNelson Escobar rte_mb(); 589856d7ba7SNelson Escobar if (rq_data->in_use) 590856d7ba7SNelson Escobar ret1 = vnic_rq_disable(rq_data); 591856d7ba7SNelson Escobar 592856d7ba7SNelson Escobar if (ret2) 593856d7ba7SNelson Escobar return ret2; 594837e68aeSJohn Daley else if (ret1) 595856d7ba7SNelson Escobar return ret1; 596837e68aeSJohn Daley 597837e68aeSJohn Daley eth_dev->data->rx_queue_state[queue_idx] = RTE_ETH_QUEUE_STATE_STOPPED; 598837e68aeSJohn Daley return 0; 59972f3de30SBruce Richardson } 60072f3de30SBruce Richardson 60172f3de30SBruce Richardson int enic_alloc_rq(struct enic *enic, uint16_t queue_idx, 60272f3de30SBruce Richardson unsigned int socket_id, struct rte_mempool *mp, 603ce16fd70SJohn Daley uint16_t nb_desc, uint16_t free_thresh) 60472f3de30SBruce Richardson { 605947d860cSJohn Daley int rc; 606aa07bf8fSJohn Daley uint16_t sop_queue_idx = enic_rte_rq_idx_to_sop_idx(queue_idx); 607aa07bf8fSJohn Daley uint16_t data_queue_idx = enic_rte_rq_idx_to_data_idx(queue_idx); 608856d7ba7SNelson Escobar struct vnic_rq *rq_sop = &enic->rq[sop_queue_idx]; 609856d7ba7SNelson Escobar struct vnic_rq *rq_data = &enic->rq[data_queue_idx]; 610856d7ba7SNelson Escobar unsigned int mbuf_size, mbufs_per_pkt; 611856d7ba7SNelson Escobar unsigned int nb_sop_desc, nb_data_desc; 612856d7ba7SNelson Escobar uint16_t min_sop, max_sop, min_data, max_data; 613c3e09182SJohn Daley uint16_t mtu = enic->rte_dev->data->mtu; 61472f3de30SBruce Richardson 615856d7ba7SNelson Escobar rq_sop->is_sop = 1; 616856d7ba7SNelson Escobar rq_sop->data_queue_idx = data_queue_idx; 617856d7ba7SNelson Escobar rq_data->is_sop = 0; 618856d7ba7SNelson Escobar rq_data->data_queue_idx = 0; 619856d7ba7SNelson Escobar rq_sop->socket_id = socket_id; 620856d7ba7SNelson Escobar rq_sop->mp = mp; 621856d7ba7SNelson Escobar rq_data->socket_id = socket_id; 622856d7ba7SNelson Escobar rq_data->mp = mp; 623856d7ba7SNelson Escobar rq_sop->in_use = 1; 624ce16fd70SJohn Daley rq_sop->rx_free_thresh = free_thresh; 625ce16fd70SJohn Daley rq_data->rx_free_thresh = free_thresh; 626ce16fd70SJohn Daley dev_debug(enic, "Set queue_id:%u free thresh:%u\n", queue_idx, 627ce16fd70SJohn Daley free_thresh); 62872f3de30SBruce Richardson 629856d7ba7SNelson Escobar mbuf_size = (uint16_t)(rte_pktmbuf_data_room_size(mp) - 630856d7ba7SNelson Escobar RTE_PKTMBUF_HEADROOM); 631856d7ba7SNelson Escobar 632856d7ba7SNelson Escobar if (enic->rte_dev->data->dev_conf.rxmode.enable_scatter) { 633c3e09182SJohn Daley dev_info(enic, "Rq %u Scatter rx mode enabled\n", queue_idx); 634856d7ba7SNelson Escobar /* ceil((mtu + ETHER_HDR_LEN + 4)/mbuf_size) */ 635c3e09182SJohn Daley mbufs_per_pkt = ((mtu + ETHER_HDR_LEN + 4) + 636856d7ba7SNelson Escobar (mbuf_size - 1)) / mbuf_size; 637856d7ba7SNelson Escobar } else { 638856d7ba7SNelson Escobar dev_info(enic, "Scatter rx mode disabled\n"); 639856d7ba7SNelson Escobar mbufs_per_pkt = 1; 640856d7ba7SNelson Escobar } 641856d7ba7SNelson Escobar 642856d7ba7SNelson Escobar if (mbufs_per_pkt > 1) { 643c3e09182SJohn Daley dev_info(enic, "Rq %u Scatter rx mode in use\n", queue_idx); 644e8a71c46SNelson Escobar rq_sop->data_queue_enable = 1; 645856d7ba7SNelson Escobar rq_data->in_use = 1; 646856d7ba7SNelson Escobar } else { 647c3e09182SJohn Daley dev_info(enic, "Rq %u Scatter rx mode not being used\n", 648c3e09182SJohn Daley queue_idx); 649e8a71c46SNelson Escobar rq_sop->data_queue_enable = 0; 650856d7ba7SNelson Escobar rq_data->in_use = 0; 651856d7ba7SNelson Escobar } 652856d7ba7SNelson Escobar 653856d7ba7SNelson Escobar /* number of descriptors have to be a multiple of 32 */ 654856d7ba7SNelson Escobar nb_sop_desc = (nb_desc / mbufs_per_pkt) & ~0x1F; 655856d7ba7SNelson Escobar nb_data_desc = (nb_desc - nb_sop_desc) & ~0x1F; 656856d7ba7SNelson Escobar 657856d7ba7SNelson Escobar rq_sop->max_mbufs_per_pkt = mbufs_per_pkt; 658856d7ba7SNelson Escobar rq_data->max_mbufs_per_pkt = mbufs_per_pkt; 659856d7ba7SNelson Escobar 660856d7ba7SNelson Escobar if (mbufs_per_pkt > 1) { 661856d7ba7SNelson Escobar min_sop = 64; 662856d7ba7SNelson Escobar max_sop = ((enic->config.rq_desc_count / 663856d7ba7SNelson Escobar (mbufs_per_pkt - 1)) & ~0x1F); 664856d7ba7SNelson Escobar min_data = min_sop * (mbufs_per_pkt - 1); 665856d7ba7SNelson Escobar max_data = enic->config.rq_desc_count; 666856d7ba7SNelson Escobar } else { 667856d7ba7SNelson Escobar min_sop = 64; 668856d7ba7SNelson Escobar max_sop = enic->config.rq_desc_count; 669856d7ba7SNelson Escobar min_data = 0; 670856d7ba7SNelson Escobar max_data = 0; 671856d7ba7SNelson Escobar } 672856d7ba7SNelson Escobar 673856d7ba7SNelson Escobar if (nb_desc < (min_sop + min_data)) { 67472f3de30SBruce Richardson dev_warning(enic, 675856d7ba7SNelson Escobar "Number of rx descs too low, adjusting to minimum\n"); 676856d7ba7SNelson Escobar nb_sop_desc = min_sop; 677856d7ba7SNelson Escobar nb_data_desc = min_data; 678856d7ba7SNelson Escobar } else if (nb_desc > (max_sop + max_data)) { 679856d7ba7SNelson Escobar dev_warning(enic, 680856d7ba7SNelson Escobar "Number of rx_descs too high, adjusting to maximum\n"); 681856d7ba7SNelson Escobar nb_sop_desc = max_sop; 682856d7ba7SNelson Escobar nb_data_desc = max_data; 68372f3de30SBruce Richardson } 684856d7ba7SNelson Escobar if (mbufs_per_pkt > 1) { 685856d7ba7SNelson Escobar dev_info(enic, "For mtu %d and mbuf size %d valid rx descriptor range is %d to %d\n", 686c3e09182SJohn Daley mtu, mbuf_size, min_sop + min_data, 687856d7ba7SNelson Escobar max_sop + max_data); 68872f3de30SBruce Richardson } 689856d7ba7SNelson Escobar dev_info(enic, "Using %d rx descriptors (sop %d, data %d)\n", 690856d7ba7SNelson Escobar nb_sop_desc + nb_data_desc, nb_sop_desc, nb_data_desc); 69172f3de30SBruce Richardson 692856d7ba7SNelson Escobar /* Allocate sop queue resources */ 693856d7ba7SNelson Escobar rc = vnic_rq_alloc(enic->vdev, rq_sop, sop_queue_idx, 694856d7ba7SNelson Escobar nb_sop_desc, sizeof(struct rq_enet_desc)); 695947d860cSJohn Daley if (rc) { 696856d7ba7SNelson Escobar dev_err(enic, "error in allocation of sop rq\n"); 697947d860cSJohn Daley goto err_exit; 69872f3de30SBruce Richardson } 699856d7ba7SNelson Escobar nb_sop_desc = rq_sop->ring.desc_count; 70072f3de30SBruce Richardson 701856d7ba7SNelson Escobar if (rq_data->in_use) { 702856d7ba7SNelson Escobar /* Allocate data queue resources */ 703856d7ba7SNelson Escobar rc = vnic_rq_alloc(enic->vdev, rq_data, data_queue_idx, 704856d7ba7SNelson Escobar nb_data_desc, 705856d7ba7SNelson Escobar sizeof(struct rq_enet_desc)); 706856d7ba7SNelson Escobar if (rc) { 707856d7ba7SNelson Escobar dev_err(enic, "error in allocation of data rq\n"); 708856d7ba7SNelson Escobar goto err_free_rq_sop; 709856d7ba7SNelson Escobar } 710856d7ba7SNelson Escobar nb_data_desc = rq_data->ring.desc_count; 711856d7ba7SNelson Escobar } 712947d860cSJohn Daley rc = vnic_cq_alloc(enic->vdev, &enic->cq[queue_idx], queue_idx, 713856d7ba7SNelson Escobar socket_id, nb_sop_desc + nb_data_desc, 71472f3de30SBruce Richardson sizeof(struct cq_enet_rq_desc)); 715947d860cSJohn Daley if (rc) { 71672f3de30SBruce Richardson dev_err(enic, "error in allocation of cq for rq\n"); 717856d7ba7SNelson Escobar goto err_free_rq_data; 71872f3de30SBruce Richardson } 71972f3de30SBruce Richardson 720856d7ba7SNelson Escobar /* Allocate the mbuf rings */ 721856d7ba7SNelson Escobar rq_sop->mbuf_ring = (struct rte_mbuf **) 722856d7ba7SNelson Escobar rte_zmalloc_socket("rq->mbuf_ring", 723856d7ba7SNelson Escobar sizeof(struct rte_mbuf *) * nb_sop_desc, 724856d7ba7SNelson Escobar RTE_CACHE_LINE_SIZE, rq_sop->socket_id); 725856d7ba7SNelson Escobar if (rq_sop->mbuf_ring == NULL) 726856d7ba7SNelson Escobar goto err_free_cq; 727947d860cSJohn Daley 728856d7ba7SNelson Escobar if (rq_data->in_use) { 729856d7ba7SNelson Escobar rq_data->mbuf_ring = (struct rte_mbuf **) 730856d7ba7SNelson Escobar rte_zmalloc_socket("rq->mbuf_ring", 731856d7ba7SNelson Escobar sizeof(struct rte_mbuf *) * nb_data_desc, 732856d7ba7SNelson Escobar RTE_CACHE_LINE_SIZE, rq_sop->socket_id); 733856d7ba7SNelson Escobar if (rq_data->mbuf_ring == NULL) 734856d7ba7SNelson Escobar goto err_free_sop_mbuf; 735856d7ba7SNelson Escobar } 736856d7ba7SNelson Escobar 737c3e09182SJohn Daley rq_sop->tot_nb_desc = nb_desc; /* squirl away for MTU update function */ 738c3e09182SJohn Daley 739947d860cSJohn Daley return 0; 740947d860cSJohn Daley 741856d7ba7SNelson Escobar err_free_sop_mbuf: 742856d7ba7SNelson Escobar rte_free(rq_sop->mbuf_ring); 743856d7ba7SNelson Escobar err_free_cq: 744947d860cSJohn Daley /* cleanup on error */ 745947d860cSJohn Daley vnic_cq_free(&enic->cq[queue_idx]); 746856d7ba7SNelson Escobar err_free_rq_data: 747856d7ba7SNelson Escobar if (rq_data->in_use) 748856d7ba7SNelson Escobar vnic_rq_free(rq_data); 749856d7ba7SNelson Escobar err_free_rq_sop: 750856d7ba7SNelson Escobar vnic_rq_free(rq_sop); 751947d860cSJohn Daley err_exit: 752947d860cSJohn Daley return -ENOMEM; 75372f3de30SBruce Richardson } 75472f3de30SBruce Richardson 75572f3de30SBruce Richardson void enic_free_wq(void *txq) 75672f3de30SBruce Richardson { 75783a9d8b7SJohn Daley struct vnic_wq *wq; 75883a9d8b7SJohn Daley struct enic *enic; 75972f3de30SBruce Richardson 76083a9d8b7SJohn Daley if (txq == NULL) 76183a9d8b7SJohn Daley return; 76283a9d8b7SJohn Daley 76383a9d8b7SJohn Daley wq = (struct vnic_wq *)txq; 76483a9d8b7SJohn Daley enic = vnic_dev_priv(wq->vdev); 765fc2c8c06SJohn Daley rte_memzone_free(wq->cqmsg_rz); 76672f3de30SBruce Richardson vnic_wq_free(wq); 76772f3de30SBruce Richardson vnic_cq_free(&enic->cq[enic->rq_count + wq->index]); 76872f3de30SBruce Richardson } 76972f3de30SBruce Richardson 77072f3de30SBruce Richardson int enic_alloc_wq(struct enic *enic, uint16_t queue_idx, 77172f3de30SBruce Richardson unsigned int socket_id, uint16_t nb_desc) 77272f3de30SBruce Richardson { 77372f3de30SBruce Richardson int err; 77472f3de30SBruce Richardson struct vnic_wq *wq = &enic->wq[queue_idx]; 77572f3de30SBruce Richardson unsigned int cq_index = enic_cq_wq(enic, queue_idx); 776fc2c8c06SJohn Daley char name[NAME_MAX]; 777fc2c8c06SJohn Daley static int instance; 77872f3de30SBruce Richardson 77972f3de30SBruce Richardson wq->socket_id = socket_id; 78072f3de30SBruce Richardson if (nb_desc) { 78172f3de30SBruce Richardson if (nb_desc > enic->config.wq_desc_count) { 78272f3de30SBruce Richardson dev_warning(enic, 78372f3de30SBruce Richardson "WQ %d - number of tx desc in cmd line (%d)"\ 78472f3de30SBruce Richardson "is greater than that in the UCSM/CIMC adapter"\ 78572f3de30SBruce Richardson "policy. Applying the value in the adapter "\ 78672f3de30SBruce Richardson "policy (%d)\n", 78772f3de30SBruce Richardson queue_idx, nb_desc, enic->config.wq_desc_count); 78872f3de30SBruce Richardson } else if (nb_desc != enic->config.wq_desc_count) { 78972f3de30SBruce Richardson enic->config.wq_desc_count = nb_desc; 79072f3de30SBruce Richardson dev_info(enic, 79172f3de30SBruce Richardson "TX Queues - effective number of descs:%d\n", 79272f3de30SBruce Richardson nb_desc); 79372f3de30SBruce Richardson } 79472f3de30SBruce Richardson } 79572f3de30SBruce Richardson 79672f3de30SBruce Richardson /* Allocate queue resources */ 79772f3de30SBruce Richardson err = vnic_wq_alloc(enic->vdev, &enic->wq[queue_idx], queue_idx, 79872f3de30SBruce Richardson enic->config.wq_desc_count, 79972f3de30SBruce Richardson sizeof(struct wq_enet_desc)); 80072f3de30SBruce Richardson if (err) { 80172f3de30SBruce Richardson dev_err(enic, "error in allocation of wq\n"); 80272f3de30SBruce Richardson return err; 80372f3de30SBruce Richardson } 80472f3de30SBruce Richardson 80572f3de30SBruce Richardson err = vnic_cq_alloc(enic->vdev, &enic->cq[cq_index], cq_index, 80672f3de30SBruce Richardson socket_id, enic->config.wq_desc_count, 80772f3de30SBruce Richardson sizeof(struct cq_enet_wq_desc)); 80872f3de30SBruce Richardson if (err) { 80972f3de30SBruce Richardson vnic_wq_free(wq); 81072f3de30SBruce Richardson dev_err(enic, "error in allocation of cq for wq\n"); 81172f3de30SBruce Richardson } 81272f3de30SBruce Richardson 813fc2c8c06SJohn Daley /* setup up CQ message */ 814fc2c8c06SJohn Daley snprintf((char *)name, sizeof(name), 815fc2c8c06SJohn Daley "vnic_cqmsg-%s-%d-%d", enic->bdf_name, queue_idx, 816fc2c8c06SJohn Daley instance++); 817fc2c8c06SJohn Daley 818fc2c8c06SJohn Daley wq->cqmsg_rz = rte_memzone_reserve_aligned((const char *)name, 819fc2c8c06SJohn Daley sizeof(uint32_t), 820fc2c8c06SJohn Daley SOCKET_ID_ANY, 0, 821fc2c8c06SJohn Daley ENIC_ALIGN); 822fc2c8c06SJohn Daley if (!wq->cqmsg_rz) 823fc2c8c06SJohn Daley return -ENOMEM; 824fc2c8c06SJohn Daley 82572f3de30SBruce Richardson return err; 82672f3de30SBruce Richardson } 82772f3de30SBruce Richardson 82872f3de30SBruce Richardson int enic_disable(struct enic *enic) 82972f3de30SBruce Richardson { 83072f3de30SBruce Richardson unsigned int i; 83172f3de30SBruce Richardson int err; 83272f3de30SBruce Richardson 83372f3de30SBruce Richardson vnic_intr_mask(&enic->intr); 83472f3de30SBruce Richardson (void)vnic_intr_masked(&enic->intr); /* flush write */ 835667b8a3bSNelson Escobar rte_intr_disable(&enic->pdev->intr_handle); 836667b8a3bSNelson Escobar rte_intr_callback_unregister(&enic->pdev->intr_handle, 837667b8a3bSNelson Escobar enic_intr_handler, 838667b8a3bSNelson Escobar (void *)enic->rte_dev); 83972f3de30SBruce Richardson 84072f3de30SBruce Richardson vnic_dev_disable(enic->vdev); 84172f3de30SBruce Richardson 84272f3de30SBruce Richardson enic_clsf_destroy(enic); 84372f3de30SBruce Richardson 84472f3de30SBruce Richardson if (!enic_is_sriov_vf(enic)) 84572f3de30SBruce Richardson vnic_dev_del_addr(enic->vdev, enic->mac_addr); 84672f3de30SBruce Richardson 84772f3de30SBruce Richardson for (i = 0; i < enic->wq_count; i++) { 84872f3de30SBruce Richardson err = vnic_wq_disable(&enic->wq[i]); 84972f3de30SBruce Richardson if (err) 85072f3de30SBruce Richardson return err; 85172f3de30SBruce Richardson } 852856d7ba7SNelson Escobar for (i = 0; i < enic_vnic_rq_count(enic); i++) { 853856d7ba7SNelson Escobar if (enic->rq[i].in_use) { 85472f3de30SBruce Richardson err = vnic_rq_disable(&enic->rq[i]); 85572f3de30SBruce Richardson if (err) 85672f3de30SBruce Richardson return err; 85772f3de30SBruce Richardson } 858856d7ba7SNelson Escobar } 85972f3de30SBruce Richardson 86053fa8cc0SNelson Escobar /* If we were using interrupts, set the interrupt vector to -1 86153fa8cc0SNelson Escobar * to disable interrupts. We are not disabling link notifcations, 86253fa8cc0SNelson Escobar * though, as we want the polling of link status to continue working. 86353fa8cc0SNelson Escobar */ 86453fa8cc0SNelson Escobar if (enic->rte_dev->data->dev_conf.intr_conf.lsc) 86553fa8cc0SNelson Escobar vnic_dev_notify_set(enic->vdev, -1); 86653fa8cc0SNelson Escobar 86772f3de30SBruce Richardson vnic_dev_set_reset_flag(enic->vdev, 1); 86872f3de30SBruce Richardson 86972f3de30SBruce Richardson for (i = 0; i < enic->wq_count; i++) 87072f3de30SBruce Richardson vnic_wq_clean(&enic->wq[i], enic_free_wq_buf); 871947d860cSJohn Daley 872856d7ba7SNelson Escobar for (i = 0; i < enic_vnic_rq_count(enic); i++) 873856d7ba7SNelson Escobar if (enic->rq[i].in_use) 87472f3de30SBruce Richardson vnic_rq_clean(&enic->rq[i], enic_free_rq_buf); 87572f3de30SBruce Richardson for (i = 0; i < enic->cq_count; i++) 87672f3de30SBruce Richardson vnic_cq_clean(&enic->cq[i]); 87772f3de30SBruce Richardson vnic_intr_clean(&enic->intr); 87872f3de30SBruce Richardson 87972f3de30SBruce Richardson return 0; 88072f3de30SBruce Richardson } 88172f3de30SBruce Richardson 88272f3de30SBruce Richardson static int enic_dev_wait(struct vnic_dev *vdev, 88372f3de30SBruce Richardson int (*start)(struct vnic_dev *, int), 88472f3de30SBruce Richardson int (*finished)(struct vnic_dev *, int *), 88572f3de30SBruce Richardson int arg) 88672f3de30SBruce Richardson { 88772f3de30SBruce Richardson int done; 88872f3de30SBruce Richardson int err; 88972f3de30SBruce Richardson int i; 89072f3de30SBruce Richardson 89172f3de30SBruce Richardson err = start(vdev, arg); 89272f3de30SBruce Richardson if (err) 89372f3de30SBruce Richardson return err; 89472f3de30SBruce Richardson 89572f3de30SBruce Richardson /* Wait for func to complete...2 seconds max */ 89672f3de30SBruce Richardson for (i = 0; i < 2000; i++) { 89772f3de30SBruce Richardson err = finished(vdev, &done); 89872f3de30SBruce Richardson if (err) 89972f3de30SBruce Richardson return err; 90072f3de30SBruce Richardson if (done) 90172f3de30SBruce Richardson return 0; 90272f3de30SBruce Richardson usleep(1000); 90372f3de30SBruce Richardson } 90472f3de30SBruce Richardson return -ETIMEDOUT; 90572f3de30SBruce Richardson } 90672f3de30SBruce Richardson 90772f3de30SBruce Richardson static int enic_dev_open(struct enic *enic) 90872f3de30SBruce Richardson { 90972f3de30SBruce Richardson int err; 91072f3de30SBruce Richardson 91172f3de30SBruce Richardson err = enic_dev_wait(enic->vdev, vnic_dev_open, 91272f3de30SBruce Richardson vnic_dev_open_done, 0); 91372f3de30SBruce Richardson if (err) 91472f3de30SBruce Richardson dev_err(enic_get_dev(enic), 91572f3de30SBruce Richardson "vNIC device open failed, err %d\n", err); 91672f3de30SBruce Richardson 91772f3de30SBruce Richardson return err; 91872f3de30SBruce Richardson } 91972f3de30SBruce Richardson 92072f3de30SBruce Richardson static int enic_set_rsskey(struct enic *enic) 92172f3de30SBruce Richardson { 92272f3de30SBruce Richardson dma_addr_t rss_key_buf_pa; 92372f3de30SBruce Richardson union vnic_rss_key *rss_key_buf_va = NULL; 92472f3de30SBruce Richardson static union vnic_rss_key rss_key = { 92572f3de30SBruce Richardson .key = { 92672f3de30SBruce Richardson [0] = {.b = {85, 67, 83, 97, 119, 101, 115, 111, 109, 101}}, 92772f3de30SBruce Richardson [1] = {.b = {80, 65, 76, 79, 117, 110, 105, 113, 117, 101}}, 92872f3de30SBruce Richardson [2] = {.b = {76, 73, 78, 85, 88, 114, 111, 99, 107, 115}}, 92972f3de30SBruce Richardson [3] = {.b = {69, 78, 73, 67, 105, 115, 99, 111, 111, 108}}, 93072f3de30SBruce Richardson } 93172f3de30SBruce Richardson }; 93272f3de30SBruce Richardson int err; 93372f3de30SBruce Richardson u8 name[NAME_MAX]; 93472f3de30SBruce Richardson 93572f3de30SBruce Richardson snprintf((char *)name, NAME_MAX, "rss_key-%s", enic->bdf_name); 93672f3de30SBruce Richardson rss_key_buf_va = enic_alloc_consistent(enic, sizeof(union vnic_rss_key), 93772f3de30SBruce Richardson &rss_key_buf_pa, name); 93872f3de30SBruce Richardson if (!rss_key_buf_va) 93972f3de30SBruce Richardson return -ENOMEM; 94072f3de30SBruce Richardson 94172f3de30SBruce Richardson rte_memcpy(rss_key_buf_va, &rss_key, sizeof(union vnic_rss_key)); 94272f3de30SBruce Richardson 94372f3de30SBruce Richardson err = enic_set_rss_key(enic, 94472f3de30SBruce Richardson rss_key_buf_pa, 94572f3de30SBruce Richardson sizeof(union vnic_rss_key)); 94672f3de30SBruce Richardson 947da5f560bSNelson Escobar enic_free_consistent(enic, sizeof(union vnic_rss_key), 94872f3de30SBruce Richardson rss_key_buf_va, rss_key_buf_pa); 94972f3de30SBruce Richardson 95072f3de30SBruce Richardson return err; 95172f3de30SBruce Richardson } 95272f3de30SBruce Richardson 95372f3de30SBruce Richardson static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits) 95472f3de30SBruce Richardson { 95572f3de30SBruce Richardson dma_addr_t rss_cpu_buf_pa; 95672f3de30SBruce Richardson union vnic_rss_cpu *rss_cpu_buf_va = NULL; 95772f3de30SBruce Richardson int i; 95872f3de30SBruce Richardson int err; 95972f3de30SBruce Richardson u8 name[NAME_MAX]; 96072f3de30SBruce Richardson 96172f3de30SBruce Richardson snprintf((char *)name, NAME_MAX, "rss_cpu-%s", enic->bdf_name); 96272f3de30SBruce Richardson rss_cpu_buf_va = enic_alloc_consistent(enic, sizeof(union vnic_rss_cpu), 96372f3de30SBruce Richardson &rss_cpu_buf_pa, name); 96472f3de30SBruce Richardson if (!rss_cpu_buf_va) 96572f3de30SBruce Richardson return -ENOMEM; 96672f3de30SBruce Richardson 96772f3de30SBruce Richardson for (i = 0; i < (1 << rss_hash_bits); i++) 96816dba071SNelson Escobar (*rss_cpu_buf_va).cpu[i / 4].b[i % 4] = 969aa07bf8fSJohn Daley enic_rte_rq_idx_to_sop_idx(i % enic->rq_count); 97072f3de30SBruce Richardson 97172f3de30SBruce Richardson err = enic_set_rss_cpu(enic, 97272f3de30SBruce Richardson rss_cpu_buf_pa, 97372f3de30SBruce Richardson sizeof(union vnic_rss_cpu)); 97472f3de30SBruce Richardson 975da5f560bSNelson Escobar enic_free_consistent(enic, sizeof(union vnic_rss_cpu), 97672f3de30SBruce Richardson rss_cpu_buf_va, rss_cpu_buf_pa); 97772f3de30SBruce Richardson 97872f3de30SBruce Richardson return err; 97972f3de30SBruce Richardson } 98072f3de30SBruce Richardson 98172f3de30SBruce Richardson static int enic_set_niccfg(struct enic *enic, u8 rss_default_cpu, 98272f3de30SBruce Richardson u8 rss_hash_type, u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable) 98372f3de30SBruce Richardson { 98472f3de30SBruce Richardson const u8 tso_ipid_split_en = 0; 98572f3de30SBruce Richardson int err; 98672f3de30SBruce Richardson 98772f3de30SBruce Richardson /* Enable VLAN tag stripping */ 98872f3de30SBruce Richardson 98972f3de30SBruce Richardson err = enic_set_nic_cfg(enic, 99072f3de30SBruce Richardson rss_default_cpu, rss_hash_type, 99172f3de30SBruce Richardson rss_hash_bits, rss_base_cpu, 99272f3de30SBruce Richardson rss_enable, tso_ipid_split_en, 99372f3de30SBruce Richardson enic->ig_vlan_strip_en); 99472f3de30SBruce Richardson 99572f3de30SBruce Richardson return err; 99672f3de30SBruce Richardson } 99772f3de30SBruce Richardson 99872f3de30SBruce Richardson int enic_set_rss_nic_cfg(struct enic *enic) 99972f3de30SBruce Richardson { 100072f3de30SBruce Richardson const u8 rss_default_cpu = 0; 100172f3de30SBruce Richardson const u8 rss_hash_type = NIC_CFG_RSS_HASH_TYPE_IPV4 | 100272f3de30SBruce Richardson NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 | 100372f3de30SBruce Richardson NIC_CFG_RSS_HASH_TYPE_IPV6 | 100472f3de30SBruce Richardson NIC_CFG_RSS_HASH_TYPE_TCP_IPV6; 100572f3de30SBruce Richardson const u8 rss_hash_bits = 7; 100672f3de30SBruce Richardson const u8 rss_base_cpu = 0; 100772f3de30SBruce Richardson u8 rss_enable = ENIC_SETTING(enic, RSS) && (enic->rq_count > 1); 100872f3de30SBruce Richardson 100972f3de30SBruce Richardson if (rss_enable) { 101072f3de30SBruce Richardson if (!enic_set_rsskey(enic)) { 101172f3de30SBruce Richardson if (enic_set_rsscpu(enic, rss_hash_bits)) { 101272f3de30SBruce Richardson rss_enable = 0; 101372f3de30SBruce Richardson dev_warning(enic, "RSS disabled, "\ 101472f3de30SBruce Richardson "Failed to set RSS cpu indirection table."); 101572f3de30SBruce Richardson } 101672f3de30SBruce Richardson } else { 101772f3de30SBruce Richardson rss_enable = 0; 101872f3de30SBruce Richardson dev_warning(enic, 101972f3de30SBruce Richardson "RSS disabled, Failed to set RSS key.\n"); 102072f3de30SBruce Richardson } 102172f3de30SBruce Richardson } 102272f3de30SBruce Richardson 102372f3de30SBruce Richardson return enic_set_niccfg(enic, rss_default_cpu, rss_hash_type, 102472f3de30SBruce Richardson rss_hash_bits, rss_base_cpu, rss_enable); 102572f3de30SBruce Richardson } 102672f3de30SBruce Richardson 102772f3de30SBruce Richardson int enic_setup_finish(struct enic *enic) 102872f3de30SBruce Richardson { 102972f3de30SBruce Richardson int ret; 103072f3de30SBruce Richardson 103165b5434dSJohn Daley enic_init_soft_stats(enic); 103265b5434dSJohn Daley 103372f3de30SBruce Richardson ret = enic_set_rss_nic_cfg(enic); 103472f3de30SBruce Richardson if (ret) { 103572f3de30SBruce Richardson dev_err(enic, "Failed to config nic, aborting.\n"); 103672f3de30SBruce Richardson return -1; 103772f3de30SBruce Richardson } 103872f3de30SBruce Richardson 103972f3de30SBruce Richardson /* Default conf */ 104072f3de30SBruce Richardson vnic_dev_packet_filter(enic->vdev, 104172f3de30SBruce Richardson 1 /* directed */, 104272f3de30SBruce Richardson 1 /* multicast */, 104372f3de30SBruce Richardson 1 /* broadcast */, 104472f3de30SBruce Richardson 0 /* promisc */, 104572f3de30SBruce Richardson 1 /* allmulti */); 104672f3de30SBruce Richardson 104772f3de30SBruce Richardson enic->promisc = 0; 104872f3de30SBruce Richardson enic->allmulti = 1; 104972f3de30SBruce Richardson 105072f3de30SBruce Richardson return 0; 105172f3de30SBruce Richardson } 105272f3de30SBruce Richardson 105372f3de30SBruce Richardson void enic_add_packet_filter(struct enic *enic) 105472f3de30SBruce Richardson { 105572f3de30SBruce Richardson /* Args -> directed, multicast, broadcast, promisc, allmulti */ 105672f3de30SBruce Richardson vnic_dev_packet_filter(enic->vdev, 1, 1, 1, 105772f3de30SBruce Richardson enic->promisc, enic->allmulti); 105872f3de30SBruce Richardson } 105972f3de30SBruce Richardson 106072f3de30SBruce Richardson int enic_get_link_status(struct enic *enic) 106172f3de30SBruce Richardson { 106272f3de30SBruce Richardson return vnic_dev_link_status(enic->vdev); 106372f3de30SBruce Richardson } 106472f3de30SBruce Richardson 106572f3de30SBruce Richardson static void enic_dev_deinit(struct enic *enic) 106672f3de30SBruce Richardson { 106772f3de30SBruce Richardson struct rte_eth_dev *eth_dev = enic->rte_dev; 106872f3de30SBruce Richardson 1069c98779abSNelson Escobar /* stop link status checking */ 1070c98779abSNelson Escobar vnic_dev_notify_unset(enic->vdev); 1071c98779abSNelson Escobar 107272f3de30SBruce Richardson rte_free(eth_dev->data->mac_addrs); 107372f3de30SBruce Richardson } 107472f3de30SBruce Richardson 107572f3de30SBruce Richardson 107672f3de30SBruce Richardson int enic_set_vnic_res(struct enic *enic) 107772f3de30SBruce Richardson { 107872f3de30SBruce Richardson struct rte_eth_dev *eth_dev = enic->rte_dev; 1079b6d5fd2eSJohn Daley int rc = 0; 108072f3de30SBruce Richardson 1081856d7ba7SNelson Escobar /* With Rx scatter support, two RQs are now used per RQ used by 1082856d7ba7SNelson Escobar * the application. 1083856d7ba7SNelson Escobar */ 1084ce93d3c3SNelson Escobar if (enic->conf_rq_count < eth_dev->data->nb_rx_queues) { 1085856d7ba7SNelson Escobar dev_err(dev, "Not enough Receive queues. Requested:%u which uses %d RQs on VIC, Configured:%u\n", 1086856d7ba7SNelson Escobar eth_dev->data->nb_rx_queues, 1087ce93d3c3SNelson Escobar eth_dev->data->nb_rx_queues * 2, enic->conf_rq_count); 1088b6d5fd2eSJohn Daley rc = -EINVAL; 1089b6d5fd2eSJohn Daley } 1090ce93d3c3SNelson Escobar if (enic->conf_wq_count < eth_dev->data->nb_tx_queues) { 1091b6d5fd2eSJohn Daley dev_err(dev, "Not enough Transmit queues. Requested:%u, Configured:%u\n", 1092ce93d3c3SNelson Escobar eth_dev->data->nb_tx_queues, enic->conf_wq_count); 1093b6d5fd2eSJohn Daley rc = -EINVAL; 109472f3de30SBruce Richardson } 109572f3de30SBruce Richardson 1096ce93d3c3SNelson Escobar if (enic->conf_cq_count < (eth_dev->data->nb_rx_queues + 1097ce93d3c3SNelson Escobar eth_dev->data->nb_tx_queues)) { 1098b6d5fd2eSJohn Daley dev_err(dev, "Not enough Completion queues. Required:%u, Configured:%u\n", 1099ce93d3c3SNelson Escobar (eth_dev->data->nb_rx_queues + 1100ce93d3c3SNelson Escobar eth_dev->data->nb_tx_queues), enic->conf_cq_count); 1101b6d5fd2eSJohn Daley rc = -EINVAL; 1102b6d5fd2eSJohn Daley } 1103b6d5fd2eSJohn Daley 1104b6d5fd2eSJohn Daley if (rc == 0) { 110572f3de30SBruce Richardson enic->rq_count = eth_dev->data->nb_rx_queues; 110672f3de30SBruce Richardson enic->wq_count = eth_dev->data->nb_tx_queues; 1107b6d5fd2eSJohn Daley enic->cq_count = enic->rq_count + enic->wq_count; 110872f3de30SBruce Richardson } 110972f3de30SBruce Richardson 1110b6d5fd2eSJohn Daley return rc; 111172f3de30SBruce Richardson } 111272f3de30SBruce Richardson 1113c3e09182SJohn Daley /* Initialize the completion queue for an RQ */ 1114c3e09182SJohn Daley static int 1115c3e09182SJohn Daley enic_reinit_rq(struct enic *enic, unsigned int rq_idx) 1116c3e09182SJohn Daley { 1117c3e09182SJohn Daley struct vnic_rq *sop_rq, *data_rq; 1118c3e09182SJohn Daley unsigned int cq_idx = enic_cq_rq(enic, rq_idx); 1119c3e09182SJohn Daley int rc = 0; 1120c3e09182SJohn Daley 1121aa07bf8fSJohn Daley sop_rq = &enic->rq[enic_rte_rq_idx_to_sop_idx(rq_idx)]; 1122aa07bf8fSJohn Daley data_rq = &enic->rq[enic_rte_rq_idx_to_data_idx(rq_idx)]; 1123c3e09182SJohn Daley 1124c3e09182SJohn Daley vnic_cq_clean(&enic->cq[cq_idx]); 1125c3e09182SJohn Daley vnic_cq_init(&enic->cq[cq_idx], 1126c3e09182SJohn Daley 0 /* flow_control_enable */, 1127c3e09182SJohn Daley 1 /* color_enable */, 1128c3e09182SJohn Daley 0 /* cq_head */, 1129c3e09182SJohn Daley 0 /* cq_tail */, 1130c3e09182SJohn Daley 1 /* cq_tail_color */, 1131c3e09182SJohn Daley 0 /* interrupt_enable */, 1132c3e09182SJohn Daley 1 /* cq_entry_enable */, 1133c3e09182SJohn Daley 0 /* cq_message_enable */, 1134c3e09182SJohn Daley 0 /* interrupt offset */, 1135c3e09182SJohn Daley 0 /* cq_message_addr */); 1136c3e09182SJohn Daley 1137c3e09182SJohn Daley 1138aa07bf8fSJohn Daley vnic_rq_init_start(sop_rq, enic_cq_rq(enic, 1139aa07bf8fSJohn Daley enic_rte_rq_idx_to_sop_idx(rq_idx)), 0, 1140aa07bf8fSJohn Daley sop_rq->ring.desc_count - 1, 1, 0); 1141c3e09182SJohn Daley if (data_rq->in_use) { 1142c3e09182SJohn Daley vnic_rq_init_start(data_rq, 1143aa07bf8fSJohn Daley enic_cq_rq(enic, 1144aa07bf8fSJohn Daley enic_rte_rq_idx_to_data_idx(rq_idx)), 0, 1145aa07bf8fSJohn Daley data_rq->ring.desc_count - 1, 1, 0); 1146c3e09182SJohn Daley } 1147c3e09182SJohn Daley 1148c3e09182SJohn Daley rc = enic_alloc_rx_queue_mbufs(enic, sop_rq); 1149c3e09182SJohn Daley if (rc) 1150c3e09182SJohn Daley return rc; 1151c3e09182SJohn Daley 1152c3e09182SJohn Daley if (data_rq->in_use) { 1153c3e09182SJohn Daley rc = enic_alloc_rx_queue_mbufs(enic, data_rq); 1154c3e09182SJohn Daley if (rc) { 1155c3e09182SJohn Daley enic_rxmbuf_queue_release(enic, sop_rq); 1156c3e09182SJohn Daley return rc; 1157c3e09182SJohn Daley } 1158c3e09182SJohn Daley } 1159c3e09182SJohn Daley 1160c3e09182SJohn Daley return 0; 1161c3e09182SJohn Daley } 1162c3e09182SJohn Daley 1163396a6d71SJohn Daley /* The Cisco NIC can send and receive packets up to a max packet size 1164396a6d71SJohn Daley * determined by the NIC type and firmware. There is also an MTU 1165396a6d71SJohn Daley * configured into the NIC via the CIMC/UCSM management interface 1166396a6d71SJohn Daley * which can be overridden by this function (up to the max packet size). 1167396a6d71SJohn Daley * Depending on the network setup, doing so may cause packet drops 1168396a6d71SJohn Daley * and unexpected behavior. 1169396a6d71SJohn Daley */ 1170396a6d71SJohn Daley int enic_set_mtu(struct enic *enic, uint16_t new_mtu) 1171396a6d71SJohn Daley { 1172c3e09182SJohn Daley unsigned int rq_idx; 1173c3e09182SJohn Daley struct vnic_rq *rq; 1174c3e09182SJohn Daley int rc = 0; 1175396a6d71SJohn Daley uint16_t old_mtu; /* previous setting */ 1176396a6d71SJohn Daley uint16_t config_mtu; /* Value configured into NIC via CIMC/UCSM */ 1177396a6d71SJohn Daley struct rte_eth_dev *eth_dev = enic->rte_dev; 1178396a6d71SJohn Daley 1179396a6d71SJohn Daley old_mtu = eth_dev->data->mtu; 1180396a6d71SJohn Daley config_mtu = enic->config.mtu; 1181396a6d71SJohn Daley 1182396a6d71SJohn Daley if (new_mtu > enic->max_mtu) { 1183396a6d71SJohn Daley dev_err(enic, 1184396a6d71SJohn Daley "MTU not updated: requested (%u) greater than max (%u)\n", 1185396a6d71SJohn Daley new_mtu, enic->max_mtu); 1186396a6d71SJohn Daley return -EINVAL; 1187396a6d71SJohn Daley } 1188396a6d71SJohn Daley if (new_mtu < ENIC_MIN_MTU) { 1189396a6d71SJohn Daley dev_info(enic, 1190396a6d71SJohn Daley "MTU not updated: requested (%u) less than min (%u)\n", 1191396a6d71SJohn Daley new_mtu, ENIC_MIN_MTU); 1192396a6d71SJohn Daley return -EINVAL; 1193396a6d71SJohn Daley } 1194396a6d71SJohn Daley if (new_mtu > config_mtu) 1195396a6d71SJohn Daley dev_warning(enic, 1196396a6d71SJohn Daley "MTU (%u) is greater than value configured in NIC (%u)\n", 1197396a6d71SJohn Daley new_mtu, config_mtu); 1198396a6d71SJohn Daley 1199c3e09182SJohn Daley /* The easy case is when scatter is disabled. However if the MTU 1200c3e09182SJohn Daley * becomes greater than the mbuf data size, packet drops will ensue. 1201c3e09182SJohn Daley */ 1202c3e09182SJohn Daley if (!enic->rte_dev->data->dev_conf.rxmode.enable_scatter) { 1203c3e09182SJohn Daley eth_dev->data->mtu = new_mtu; 1204c3e09182SJohn Daley goto set_mtu_done; 1205c3e09182SJohn Daley } 1206c3e09182SJohn Daley 1207c3e09182SJohn Daley /* Rx scatter is enabled so reconfigure RQ's on the fly. The point is to 1208c3e09182SJohn Daley * change Rx scatter mode if necessary for better performance. I.e. if 1209c3e09182SJohn Daley * MTU was greater than the mbuf size and now it's less, scatter Rx 1210c3e09182SJohn Daley * doesn't have to be used and vice versa. 1211c3e09182SJohn Daley */ 1212c3e09182SJohn Daley rte_spinlock_lock(&enic->mtu_lock); 1213c3e09182SJohn Daley 1214c3e09182SJohn Daley /* Stop traffic on all RQs */ 1215c3e09182SJohn Daley for (rq_idx = 0; rq_idx < enic->rq_count * 2; rq_idx++) { 1216c3e09182SJohn Daley rq = &enic->rq[rq_idx]; 1217c3e09182SJohn Daley if (rq->is_sop && rq->in_use) { 1218aa07bf8fSJohn Daley rc = enic_stop_rq(enic, 1219aa07bf8fSJohn Daley enic_sop_rq_idx_to_rte_idx(rq_idx)); 1220c3e09182SJohn Daley if (rc) { 1221c3e09182SJohn Daley dev_err(enic, "Failed to stop Rq %u\n", rq_idx); 1222c3e09182SJohn Daley goto set_mtu_done; 1223c3e09182SJohn Daley } 1224c3e09182SJohn Daley } 1225c3e09182SJohn Daley } 1226c3e09182SJohn Daley 1227c3e09182SJohn Daley /* replace Rx funciton with a no-op to avoid getting stale pkts */ 1228c3e09182SJohn Daley eth_dev->rx_pkt_burst = enic_dummy_recv_pkts; 1229c3e09182SJohn Daley rte_mb(); 1230c3e09182SJohn Daley 1231c3e09182SJohn Daley /* Allow time for threads to exit the real Rx function. */ 1232c3e09182SJohn Daley usleep(100000); 1233c3e09182SJohn Daley 1234c3e09182SJohn Daley /* now it is safe to reconfigure the RQs */ 1235c3e09182SJohn Daley 1236396a6d71SJohn Daley /* update the mtu */ 1237396a6d71SJohn Daley eth_dev->data->mtu = new_mtu; 1238396a6d71SJohn Daley 1239c3e09182SJohn Daley /* free and reallocate RQs with the new MTU */ 1240c3e09182SJohn Daley for (rq_idx = 0; rq_idx < enic->rq_count; rq_idx++) { 1241aa07bf8fSJohn Daley rq = &enic->rq[enic_rte_rq_idx_to_sop_idx(rq_idx)]; 1242c3e09182SJohn Daley 1243c3e09182SJohn Daley enic_free_rq(rq); 1244c3e09182SJohn Daley rc = enic_alloc_rq(enic, rq_idx, rq->socket_id, rq->mp, 1245ce16fd70SJohn Daley rq->tot_nb_desc, rq->rx_free_thresh); 1246c3e09182SJohn Daley if (rc) { 1247c3e09182SJohn Daley dev_err(enic, 1248c3e09182SJohn Daley "Fatal MTU alloc error- No traffic will pass\n"); 1249c3e09182SJohn Daley goto set_mtu_done; 1250c3e09182SJohn Daley } 1251c3e09182SJohn Daley 1252c3e09182SJohn Daley rc = enic_reinit_rq(enic, rq_idx); 1253c3e09182SJohn Daley if (rc) { 1254c3e09182SJohn Daley dev_err(enic, 1255c3e09182SJohn Daley "Fatal MTU RQ reinit- No traffic will pass\n"); 1256c3e09182SJohn Daley goto set_mtu_done; 1257c3e09182SJohn Daley } 1258c3e09182SJohn Daley } 1259c3e09182SJohn Daley 1260c3e09182SJohn Daley /* put back the real receive function */ 1261c3e09182SJohn Daley rte_mb(); 1262c3e09182SJohn Daley eth_dev->rx_pkt_burst = enic_recv_pkts; 1263c3e09182SJohn Daley rte_mb(); 1264c3e09182SJohn Daley 1265c3e09182SJohn Daley /* restart Rx traffic */ 1266c3e09182SJohn Daley for (rq_idx = 0; rq_idx < enic->rq_count; rq_idx++) { 1267aa07bf8fSJohn Daley rq = &enic->rq[enic_rte_rq_idx_to_sop_idx(rq_idx)]; 1268c3e09182SJohn Daley if (rq->is_sop && rq->in_use) 1269c3e09182SJohn Daley enic_start_rq(enic, rq_idx); 1270c3e09182SJohn Daley } 1271c3e09182SJohn Daley 1272c3e09182SJohn Daley set_mtu_done: 1273396a6d71SJohn Daley dev_info(enic, "MTU changed from %u to %u\n", old_mtu, new_mtu); 1274c3e09182SJohn Daley rte_spinlock_unlock(&enic->mtu_lock); 1275c3e09182SJohn Daley return rc; 1276396a6d71SJohn Daley } 1277396a6d71SJohn Daley 127872f3de30SBruce Richardson static int enic_dev_init(struct enic *enic) 127972f3de30SBruce Richardson { 128072f3de30SBruce Richardson int err; 128172f3de30SBruce Richardson struct rte_eth_dev *eth_dev = enic->rte_dev; 128272f3de30SBruce Richardson 128372f3de30SBruce Richardson vnic_dev_intr_coal_timer_info_default(enic->vdev); 128472f3de30SBruce Richardson 128572f3de30SBruce Richardson /* Get vNIC configuration 128672f3de30SBruce Richardson */ 128772f3de30SBruce Richardson err = enic_get_vnic_config(enic); 128872f3de30SBruce Richardson if (err) { 128972f3de30SBruce Richardson dev_err(dev, "Get vNIC configuration failed, aborting\n"); 129072f3de30SBruce Richardson return err; 129172f3de30SBruce Richardson } 129272f3de30SBruce Richardson 1293b16e60abSNelson Escobar /* Get available resource counts */ 1294b16e60abSNelson Escobar enic_get_res_counts(enic); 1295b16e60abSNelson Escobar if (enic->conf_rq_count == 1) { 1296b16e60abSNelson Escobar dev_err(enic, "Running with only 1 RQ configured in the vNIC is not supported.\n"); 1297b16e60abSNelson Escobar dev_err(enic, "Please configure 2 RQs in the vNIC for each Rx queue used by DPDK.\n"); 1298b16e60abSNelson Escobar dev_err(enic, "See the ENIC PMD guide for more information.\n"); 1299b16e60abSNelson Escobar return -EINVAL; 1300b16e60abSNelson Escobar } 1301b16e60abSNelson Escobar 1302dfbd6a9cSJohn Daley /* Get the supported filters */ 1303dfbd6a9cSJohn Daley enic_fdir_info(enic); 1304dfbd6a9cSJohn Daley 1305*bbab3d97SJohn Daley eth_dev->data->mac_addrs = rte_zmalloc("enic_mac_addr", ETH_ALEN 1306*bbab3d97SJohn Daley * ENIC_MAX_MAC_ADDR, 0); 130772f3de30SBruce Richardson if (!eth_dev->data->mac_addrs) { 130872f3de30SBruce Richardson dev_err(enic, "mac addr storage alloc failed, aborting.\n"); 130972f3de30SBruce Richardson return -1; 131072f3de30SBruce Richardson } 131172f3de30SBruce Richardson ether_addr_copy((struct ether_addr *) enic->mac_addr, 1312*bbab3d97SJohn Daley eth_dev->data->mac_addrs); 131372f3de30SBruce Richardson 131472f3de30SBruce Richardson vnic_dev_set_reset_flag(enic->vdev, 0); 131572f3de30SBruce Richardson 1316c98779abSNelson Escobar /* set up link status checking */ 1317c98779abSNelson Escobar vnic_dev_notify_set(enic->vdev, -1); /* No Intr for notify */ 1318c98779abSNelson Escobar 131972f3de30SBruce Richardson return 0; 132072f3de30SBruce Richardson 132172f3de30SBruce Richardson } 132272f3de30SBruce Richardson 132372f3de30SBruce Richardson int enic_probe(struct enic *enic) 132472f3de30SBruce Richardson { 132572f3de30SBruce Richardson struct rte_pci_device *pdev = enic->pdev; 132672f3de30SBruce Richardson int err = -1; 132772f3de30SBruce Richardson 1328d0c98d9eSJohn Daley dev_debug(enic, " Initializing ENIC PMD\n"); 132972f3de30SBruce Richardson 133072f3de30SBruce Richardson enic->bar0.vaddr = (void *)pdev->mem_resource[0].addr; 133172f3de30SBruce Richardson enic->bar0.len = pdev->mem_resource[0].len; 133272f3de30SBruce Richardson 133372f3de30SBruce Richardson /* Register vNIC device */ 133472f3de30SBruce Richardson enic->vdev = vnic_dev_register(NULL, enic, enic->pdev, &enic->bar0, 1); 133572f3de30SBruce Richardson if (!enic->vdev) { 133672f3de30SBruce Richardson dev_err(enic, "vNIC registration failed, aborting\n"); 133772f3de30SBruce Richardson goto err_out; 133872f3de30SBruce Richardson } 133972f3de30SBruce Richardson 1340da5f560bSNelson Escobar LIST_INIT(&enic->memzone_list); 1341da5f560bSNelson Escobar rte_spinlock_init(&enic->memzone_list_lock); 1342da5f560bSNelson Escobar 134372f3de30SBruce Richardson vnic_register_cbacks(enic->vdev, 134472f3de30SBruce Richardson enic_alloc_consistent, 134572f3de30SBruce Richardson enic_free_consistent); 134672f3de30SBruce Richardson 134772f3de30SBruce Richardson /* Issue device open to get device in known state */ 134872f3de30SBruce Richardson err = enic_dev_open(enic); 134972f3de30SBruce Richardson if (err) { 135072f3de30SBruce Richardson dev_err(enic, "vNIC dev open failed, aborting\n"); 135172f3de30SBruce Richardson goto err_out_unregister; 135272f3de30SBruce Richardson } 135372f3de30SBruce Richardson 135472f3de30SBruce Richardson /* Set ingress vlan rewrite mode before vnic initialization */ 135572f3de30SBruce Richardson err = vnic_dev_set_ig_vlan_rewrite_mode(enic->vdev, 1356947d860cSJohn Daley IG_VLAN_REWRITE_MODE_PASS_THRU); 135772f3de30SBruce Richardson if (err) { 135872f3de30SBruce Richardson dev_err(enic, 135972f3de30SBruce Richardson "Failed to set ingress vlan rewrite mode, aborting.\n"); 136072f3de30SBruce Richardson goto err_out_dev_close; 136172f3de30SBruce Richardson } 136272f3de30SBruce Richardson 136372f3de30SBruce Richardson /* Issue device init to initialize the vnic-to-switch link. 136472f3de30SBruce Richardson * We'll start with carrier off and wait for link UP 136572f3de30SBruce Richardson * notification later to turn on carrier. We don't need 136672f3de30SBruce Richardson * to wait here for the vnic-to-switch link initialization 136772f3de30SBruce Richardson * to complete; link UP notification is the indication that 136872f3de30SBruce Richardson * the process is complete. 136972f3de30SBruce Richardson */ 137072f3de30SBruce Richardson 137172f3de30SBruce Richardson err = vnic_dev_init(enic->vdev, 0); 137272f3de30SBruce Richardson if (err) { 137372f3de30SBruce Richardson dev_err(enic, "vNIC dev init failed, aborting\n"); 137472f3de30SBruce Richardson goto err_out_dev_close; 137572f3de30SBruce Richardson } 137672f3de30SBruce Richardson 137772f3de30SBruce Richardson err = enic_dev_init(enic); 137872f3de30SBruce Richardson if (err) { 137972f3de30SBruce Richardson dev_err(enic, "Device initialization failed, aborting\n"); 138072f3de30SBruce Richardson goto err_out_dev_close; 138172f3de30SBruce Richardson } 138272f3de30SBruce Richardson 138372f3de30SBruce Richardson return 0; 138472f3de30SBruce Richardson 138572f3de30SBruce Richardson err_out_dev_close: 138672f3de30SBruce Richardson vnic_dev_close(enic->vdev); 138772f3de30SBruce Richardson err_out_unregister: 138872f3de30SBruce Richardson vnic_dev_unregister(enic->vdev); 138972f3de30SBruce Richardson err_out: 139072f3de30SBruce Richardson return err; 139172f3de30SBruce Richardson } 139272f3de30SBruce Richardson 139372f3de30SBruce Richardson void enic_remove(struct enic *enic) 139472f3de30SBruce Richardson { 139572f3de30SBruce Richardson enic_dev_deinit(enic); 139672f3de30SBruce Richardson vnic_dev_close(enic->vdev); 139772f3de30SBruce Richardson vnic_dev_unregister(enic->vdev); 139872f3de30SBruce Richardson } 1399