diff options
Diffstat (limited to 'drivers/net/ethernet/cavium/liquidio')
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/lio_core.c | 145 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/lio_ethtool.c | 24 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/lio_main.c | 440 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/lio_vf_main.c | 278 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/liquidio_common.h | 30 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/octeon_device.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/octeon_droq.c | 83 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/octeon_droq.h | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/octeon_network.h | 73 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/request_manager.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/response_manager.c | 6 |
12 files changed, 503 insertions, 602 deletions
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 32ae63b6f20e..2a94eee943b2 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -164,15 +164,6 @@ void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr) } break; - case OCTNET_CMD_CHANGE_MTU: - /* If command is successful, change the MTU. */ - netif_info(lio, probe, lio->netdev, "MTU Changed from %d to %d\n", - netdev->mtu, nctrl->ncmd.s.param1); - netdev->mtu = nctrl->ncmd.s.param1; - queue_delayed_work(lio->link_status_wq.wq, - &lio->link_status_wq.wk.work, 0); - break; - case OCTNET_CMD_GPIO_ACCESS: netif_info(lio, probe, lio->netdev, "LED Flashing visual identification\n"); @@ -386,20 +377,12 @@ static void lio_update_txq_status(struct octeon_device *oct, int iq_num) return; lio = GET_LIO(netdev); - if (netif_is_multiqueue(netdev)) { - if (__netif_subqueue_stopped(netdev, iq->q_index) && - lio->linfo.link.s.link_up && - (!octnet_iq_is_full(oct, iq_num))) { - netif_wake_subqueue(netdev, iq->q_index); - INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, iq_num, - tx_restart, 1); - } - } else if (netif_queue_stopped(netdev) && - lio->linfo.link.s.link_up && - (!octnet_iq_is_full(oct, lio->txq))) { - INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, lio->txq, + if (__netif_subqueue_stopped(netdev, iq->q_index) && + lio->linfo.link.s.link_up && + (!octnet_iq_is_full(oct, iq_num))) { + netif_wake_subqueue(netdev, iq->q_index); + INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, iq_num, tx_restart, 1); - netif_wake_queue(netdev); } } @@ -571,7 +554,8 @@ liquidio_push_packet(u32 octeon_id __attribute__((unused)), napi_gro_receive(napi, skb); - droq->stats.rx_bytes_received += len; + droq->stats.rx_bytes_received += len - + rh->r_dh.len * BYTES_PER_DHLEN_UNIT; droq->stats.rx_pkts_received++; } else { recv_buffer_free(skb); @@ -635,9 +619,7 @@ static int liquidio_napi_poll(struct napi_struct *napi, int budget) iq_no = droq->q_no; /* Handle Droq descriptors */ - work_done = octeon_process_droq_poll_cmd(oct, droq->q_no, - POLL_EVENT_PROCESS_PKTS, - budget); + work_done = octeon_droq_process_poll_pkts(oct, droq, budget); /* Flush the instruction queue */ iq = oct->instr_queue[iq_no]; @@ -668,8 +650,7 @@ static int liquidio_napi_poll(struct napi_struct *napi, int budget) tx_done = 1; napi_complete_done(napi, work_done); - octeon_process_droq_poll_cmd(droq->oct_dev, droq->q_no, - POLL_EVENT_ENABLE_INTR, 0); + octeon_enable_irq(droq->oct_dev, droq->q_no); return 0; } @@ -1080,3 +1061,111 @@ int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs) } return 0; } + +static void liquidio_change_mtu_completion(struct octeon_device *oct, + u32 status, void *buf) +{ + struct octeon_soft_command *sc = (struct octeon_soft_command *)buf; + struct liquidio_if_cfg_context *ctx; + + ctx = (struct liquidio_if_cfg_context *)sc->ctxptr; + + if (status) { + dev_err(&oct->pci_dev->dev, "MTU change failed. Status: %llx\n", + CVM_CAST64(status)); + WRITE_ONCE(ctx->cond, LIO_CHANGE_MTU_FAIL); + } else { + WRITE_ONCE(ctx->cond, LIO_CHANGE_MTU_SUCCESS); + } + + /* This barrier is required to be sure that the response has been + * written fully before waking up the handler + */ + wmb(); + + wake_up_interruptible(&ctx->wc); +} + +/** + * \brief Net device change_mtu + * @param netdev network device + */ +int liquidio_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct lio *lio = GET_LIO(netdev); + struct octeon_device *oct = lio->oct_dev; + struct liquidio_if_cfg_context *ctx; + struct octeon_soft_command *sc; + union octnet_cmd *ncmd; + int ctx_size; + int ret = 0; + + ctx_size = sizeof(struct liquidio_if_cfg_context); + sc = (struct octeon_soft_command *) + octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, 16, ctx_size); + + ncmd = (union octnet_cmd *)sc->virtdptr; + ctx = (struct liquidio_if_cfg_context *)sc->ctxptr; + + WRITE_ONCE(ctx->cond, 0); + ctx->octeon_id = lio_get_device_id(oct); + init_waitqueue_head(&ctx->wc); + + ncmd->u64 = 0; + ncmd->s.cmd = OCTNET_CMD_CHANGE_MTU; + ncmd->s.param1 = new_mtu; + + octeon_swap_8B_data((u64 *)ncmd, (OCTNET_CMD_SIZE >> 3)); + + sc->iq_no = lio->linfo.txpciq[0].s.q_no; + + octeon_prepare_soft_command(oct, sc, OPCODE_NIC, + OPCODE_NIC_CMD, 0, 0, 0); + + sc->callback = liquidio_change_mtu_completion; + sc->callback_arg = sc; + sc->wait_time = 100; + + ret = octeon_send_soft_command(oct, sc); + if (ret == IQ_SEND_FAILED) { + netif_info(lio, rx_err, lio->netdev, "Failed to change MTU\n"); + return -EINVAL; + } + /* Sleep on a wait queue till the cond flag indicates that the + * response arrived or timed-out. + */ + if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR || + ctx->cond == LIO_CHANGE_MTU_FAIL) { + octeon_free_soft_command(oct, sc); + return -EINVAL; + } + + netdev->mtu = new_mtu; + lio->mtu = new_mtu; + + octeon_free_soft_command(oct, sc); + return 0; +} + +int lio_wait_for_clean_oq(struct octeon_device *oct) +{ + int retry = 100, pending_pkts = 0; + int idx; + + do { + pending_pkts = 0; + + for (idx = 0; idx < MAX_OCTEON_OUTPUT_QUEUES(oct); idx++) { + if (!(oct->io_qmask.oq & BIT_ULL(idx))) + continue; + pending_pkts += + atomic_read(&oct->droq[idx]->pkts_pending); + } + + if (pending_pkts > 0) + schedule_timeout_uninterruptible(1); + + } while (retry-- && pending_pkts); + + return pending_pkts; +} diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index a63ddf07f168..550ac29682a5 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -232,10 +232,16 @@ static int lio_get_link_ksettings(struct net_device *netdev, linfo = &lio->linfo; - if (linfo->link.s.if_mode == INTERFACE_MODE_XAUI || - linfo->link.s.if_mode == INTERFACE_MODE_RXAUI || - linfo->link.s.if_mode == INTERFACE_MODE_XLAUI || - linfo->link.s.if_mode == INTERFACE_MODE_XFI) { + switch (linfo->link.s.phy_type) { + case LIO_PHY_PORT_TP: + ecmd->base.port = PORT_TP; + supported = (SUPPORTED_10000baseT_Full | + SUPPORTED_TP | SUPPORTED_Pause); + advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_Pause); + ecmd->base.autoneg = AUTONEG_DISABLE; + break; + + case LIO_PHY_PORT_FIBRE: ecmd->base.port = PORT_FIBRE; if (linfo->link.s.speed == SPEED_10000) { @@ -245,12 +251,18 @@ static int lio_get_link_ksettings(struct net_device *netdev, supported |= SUPPORTED_FIBRE | SUPPORTED_Pause; advertising |= ADVERTISED_Pause; + ecmd->base.autoneg = AUTONEG_DISABLE; + break; + } + + if (linfo->link.s.if_mode == INTERFACE_MODE_XAUI || + linfo->link.s.if_mode == INTERFACE_MODE_RXAUI || + linfo->link.s.if_mode == INTERFACE_MODE_XLAUI || + linfo->link.s.if_mode == INTERFACE_MODE_XFI) { ethtool_convert_legacy_u32_to_link_mode( ecmd->link_modes.supported, supported); ethtool_convert_legacy_u32_to_link_mode( ecmd->link_modes.advertising, advertising); - ecmd->base.autoneg = AUTONEG_DISABLE; - } else { dev_err(&oct->pci_dev->dev, "Unknown link interface reported %d\n", linfo->link.s.if_mode); diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index a5eecd895a82..603a144d3d9c 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -91,18 +91,9 @@ static int octeon_console_debug_enabled(u32 console) */ #define LIO_SYNC_OCTEON_TIME_INTERVAL_MS 60000 -struct liquidio_if_cfg_context { - int octeon_id; - - wait_queue_head_t wc; - - int cond; -}; - -struct liquidio_if_cfg_resp { - u64 rh; - struct liquidio_if_cfg_info cfg_info; - u64 status; +struct lio_trusted_vf_ctx { + struct completion complete; + int status; }; struct liquidio_rx_ctl_context { @@ -523,148 +514,30 @@ static void liquidio_deinit_pci(void) } /** - * \brief Stop Tx queues - * @param netdev network device - */ -static inline void txqs_stop(struct net_device *netdev) -{ - if (netif_is_multiqueue(netdev)) { - int i; - - for (i = 0; i < netdev->num_tx_queues; i++) - netif_stop_subqueue(netdev, i); - } else { - netif_stop_queue(netdev); - } -} - -/** - * \brief Start Tx queues - * @param netdev network device - */ -static inline void txqs_start(struct net_device *netdev) -{ - if (netif_is_multiqueue(netdev)) { - int i; - - for (i = 0; i < netdev->num_tx_queues; i++) - netif_start_subqueue(netdev, i); - } else { - netif_start_queue(netdev); - } -} - -/** - * \brief Wake Tx queues - * @param netdev network device - */ -static inline void txqs_wake(struct net_device *netdev) -{ - struct lio *lio = GET_LIO(netdev); - - if (netif_is_multiqueue(netdev)) { - int i; - - for (i = 0; i < netdev->num_tx_queues; i++) { - int qno = lio->linfo.txpciq[i % - lio->oct_dev->num_iqs].s.q_no; - - if (__netif_subqueue_stopped(netdev, i)) { - INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, qno, - tx_restart, 1); - netif_wake_subqueue(netdev, i); - } - } - } else { - INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, lio->txq, - tx_restart, 1); - netif_wake_queue(netdev); - } -} - -/** - * \brief Stop Tx queue - * @param netdev network device - */ -static void stop_txq(struct net_device *netdev) -{ - txqs_stop(netdev); -} - -/** - * \brief Start Tx queue - * @param netdev network device - */ -static void start_txq(struct net_device *netdev) -{ - struct lio *lio = GET_LIO(netdev); - - if (lio->linfo.link.s.link_up) { - txqs_start(netdev); - return; - } -} - -/** - * \brief Wake a queue - * @param netdev network device - * @param q which queue to wake - */ -static inline void wake_q(struct net_device *netdev, int q) -{ - if (netif_is_multiqueue(netdev)) - netif_wake_subqueue(netdev, q); - else - netif_wake_queue(netdev); -} - -/** - * \brief Stop a queue - * @param netdev network device - * @param q which queue to stop - */ -static inline void stop_q(struct net_device *netdev, int q) -{ - if (netif_is_multiqueue(netdev)) - netif_stop_subqueue(netdev, q); - else - netif_stop_queue(netdev); -} - -/** * \brief Check Tx queue status, and take appropriate action * @param lio per-network private data * @returns 0 if full, number of queues woken up otherwise */ static inline int check_txq_status(struct lio *lio) { + int numqs = lio->netdev->num_tx_queues; int ret_val = 0; + int q, iq; - if (netif_is_multiqueue(lio->netdev)) { - int numqs = lio->netdev->num_tx_queues; - int q, iq = 0; - - /* check each sub-queue state */ - for (q = 0; q < numqs; q++) { - iq = lio->linfo.txpciq[q % - lio->oct_dev->num_iqs].s.q_no; - if (octnet_iq_is_full(lio->oct_dev, iq)) - continue; - if (__netif_subqueue_stopped(lio->netdev, q)) { - wake_q(lio->netdev, q); - INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, iq, - tx_restart, 1); - ret_val++; - } + /* check each sub-queue state */ + for (q = 0; q < numqs; q++) { + iq = lio->linfo.txpciq[q % + lio->oct_dev->num_iqs].s.q_no; + if (octnet_iq_is_full(lio->oct_dev, iq)) + continue; + if (__netif_subqueue_stopped(lio->netdev, q)) { + netif_wake_subqueue(lio->netdev, q); + INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, iq, + tx_restart, 1); + ret_val++; } - } else { - if (octnet_iq_is_full(lio->oct_dev, lio->txq)) - return 0; - wake_q(lio->netdev, lio->txq); - INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, lio->txq, - tx_restart, 1); - ret_val = 1; } + return ret_val; } @@ -841,8 +714,12 @@ static void octnet_link_status_change(struct work_struct *work) struct cavium_wk *wk = (struct cavium_wk *)work; struct lio *lio = (struct lio *)wk->ctxptr; + /* lio->linfo.link.s.mtu always contains max MTU of the lio interface. + * this API is invoked only when new max-MTU of the interface is + * less than current MTU. + */ rtnl_lock(); - call_netdevice_notifiers(NETDEV_CHANGEMTU, lio->netdev); + dev_set_mtu(lio->netdev, lio->linfo.link.s.mtu); rtnl_unlock(); } @@ -891,7 +768,11 @@ static inline void update_link_status(struct net_device *netdev, { struct lio *lio = GET_LIO(netdev); int changed = (lio->linfo.link.u64 != ls->u64); + int current_max_mtu = lio->linfo.link.s.mtu; + struct octeon_device *oct = lio->oct_dev; + dev_dbg(&oct->pci_dev->dev, "%s: lio->linfo.link.u64=%llx, ls->u64=%llx\n", + __func__, lio->linfo.link.u64, ls->u64); lio->linfo.link.u64 = ls->u64; if ((lio->intf_open) && (changed)) { @@ -899,11 +780,25 @@ static inline void update_link_status(struct net_device *netdev, lio->link_changes++; if (lio->linfo.link.s.link_up) { + dev_dbg(&oct->pci_dev->dev, "%s: link_up", __func__); netif_carrier_on(netdev); - txqs_wake(netdev); + wake_txqs(netdev); } else { + dev_dbg(&oct->pci_dev->dev, "%s: link_off", __func__); netif_carrier_off(netdev); - stop_txq(netdev); + stop_txqs(netdev); + } + if (lio->linfo.link.s.mtu != current_max_mtu) { + netif_info(lio, probe, lio->netdev, "Max MTU changed from %d to %d\n", + current_max_mtu, lio->linfo.link.s.mtu); + netdev->max_mtu = lio->linfo.link.s.mtu; + } + if (lio->linfo.link.s.mtu < netdev->mtu) { + dev_warn(&oct->pci_dev->dev, + "Current MTU is higher than new max MTU; Reducing the current mtu from %d to %d\n", + netdev->mtu, lio->linfo.link.s.mtu); + queue_delayed_work(lio->link_status_wq.wq, + &lio->link_status_wq.wk.work, 0); } } } @@ -1739,43 +1634,6 @@ static int octeon_pci_os_setup(struct octeon_device *oct) return 0; } -static inline int skb_iq(struct lio *lio, struct sk_buff *skb) -{ - int q = 0; - - if (netif_is_multiqueue(lio->netdev)) - q = skb->queue_mapping % lio->linfo.num_txpciq; - - return q; -} - -/** - * \brief Check Tx queue state for a given network buffer - * @param lio per-network private data - * @param skb network buffer - */ -static inline int check_txq_state(struct lio *lio, struct sk_buff *skb) -{ - int q = 0, iq = 0; - - if (netif_is_multiqueue(lio->netdev)) { - q = skb->queue_mapping; - iq = lio->linfo.txpciq[(q % lio->oct_dev->num_iqs)].s.q_no; - } else { - iq = lio->txq; - q = iq; - } - - if (octnet_iq_is_full(lio->oct_dev, iq)) - return 0; - - if (__netif_subqueue_stopped(lio->netdev, q)) { - INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, iq, tx_restart, 1); - wake_q(lio->netdev, q); - } - return 1; -} - /** * \brief Unmap and free network buffer * @param buf buffer @@ -1793,8 +1651,6 @@ static void free_netbuf(void *buf) dma_unmap_single(&lio->oct_dev->pci_dev->dev, finfo->dptr, skb->len, DMA_TO_DEVICE); - check_txq_state(lio, skb); - tx_buffer_free(skb); } @@ -1835,8 +1691,6 @@ static void free_netsgbuf(void *buf) list_add_tail(&g->list, &lio->glist[iq]); spin_unlock(&lio->glist_lock[iq]); - check_txq_state(lio, skb); /* mq support: sub-queue state check */ - tx_buffer_free(skb); } @@ -1882,8 +1736,6 @@ static void free_netsgbuf_with_resp(void *buf) spin_unlock(&lio->glist_lock[iq]); /* Don't free the skb yet */ - - check_txq_state(lio, skb); } /** @@ -2211,7 +2063,7 @@ static int liquidio_open(struct net_device *netdev) return -1; } - start_txq(netdev); + start_txqs(netdev); /* tell Octeon to start forwarding packets to host */ send_rx_ctrl_cmd(lio, 1); @@ -2232,16 +2084,6 @@ static int liquidio_stop(struct net_device *netdev) struct octeon_device *oct = lio->oct_dev; struct napi_struct *napi, *n; - if (oct->props[lio->ifidx].napi_enabled) { - list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) - napi_disable(napi); - - oct->props[lio->ifidx].napi_enabled = 0; - - if (OCTEON_CN23XX_PF(oct)) - oct->droq[0]->ops.poll_mode = 0; - } - ifstate_reset(lio, LIO_IFSTATE_RUNNING); netif_tx_disable(netdev); @@ -2267,6 +2109,21 @@ static int liquidio_stop(struct net_device *netdev) lio->ptp_clock = NULL; } + /* Wait for any pending Rx descriptors */ + if (lio_wait_for_clean_oq(oct)) + netif_info(lio, rx_err, lio->netdev, + "Proceeding with stop interface after partial RX desc processing\n"); + + if (oct->props[lio->ifidx].napi_enabled == 1) { + list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) + napi_disable(napi); + + oct->props[lio->ifidx].napi_enabled = 0; + + if (OCTEON_CN23XX_PF(oct)) + oct->droq[0]->ops.poll_mode = 0; + } + dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name); return 0; @@ -2449,38 +2306,6 @@ static struct net_device_stats *liquidio_get_stats(struct net_device *netdev) } /** - * \brief Net device change_mtu - * @param netdev network device - */ -static int liquidio_change_mtu(struct net_device *netdev, int new_mtu) -{ - struct lio *lio = GET_LIO(netdev); - struct octeon_device *oct = lio->oct_dev; - struct octnic_ctrl_pkt nctrl; - int ret = 0; - - memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); - - nctrl.ncmd.u64 = 0; - nctrl.ncmd.s.cmd = OCTNET_CMD_CHANGE_MTU; - nctrl.ncmd.s.param1 = new_mtu; - nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = 100; - nctrl.netpndev = (u64)netdev; - nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; - - ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { - dev_err(&oct->pci_dev->dev, "Failed to set MTU\n"); - return -1; - } - - lio->mtu = new_mtu; - - return 0; -} - -/** * \brief Handler for SIOCSHWTSTAMP ioctl * @param netdev network device * @param ifr interface request @@ -2685,14 +2510,9 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) lio = GET_LIO(netdev); oct = lio->oct_dev; - if (netif_is_multiqueue(netdev)) { - q_idx = skb->queue_mapping; - q_idx = (q_idx % (lio->linfo.num_txpciq)); - tag = q_idx; - iq_no = lio->linfo.txpciq[q_idx].s.q_no; - } else { - iq_no = lio->txq; - } + q_idx = skb_iq(lio, skb); + tag = q_idx; + iq_no = lio->linfo.txpciq[q_idx].s.q_no; stats = &oct->instr_queue[iq_no]->stats; @@ -2723,23 +2543,14 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) ndata.q_no = iq_no; - if (netif_is_multiqueue(netdev)) { - if (octnet_iq_is_full(oct, ndata.q_no)) { - /* defer sending if queue is full */ - netif_info(lio, tx_err, lio->netdev, "Transmit failed iq:%d full\n", - ndata.q_no); - stats->tx_iq_busy++; - return NETDEV_TX_BUSY; - } - } else { - if (octnet_iq_is_full(oct, lio->txq)) { - /* defer sending if queue is full */ - stats->tx_iq_busy++; - netif_info(lio, tx_err, lio->netdev, "Transmit failed iq:%d full\n", - lio->txq); - return NETDEV_TX_BUSY; - } + if (octnet_iq_is_full(oct, ndata.q_no)) { + /* defer sending if queue is full */ + netif_info(lio, tx_err, lio->netdev, "Transmit failed iq:%d full\n", + ndata.q_no); + stats->tx_iq_busy++; + return NETDEV_TX_BUSY; } + /* pr_info(" XMIT - valid Qs: %d, 1st Q no: %d, cpu: %d, q_no:%d\n", * lio->linfo.num_txpciq, lio->txq, cpu, ndata.q_no); */ @@ -2895,7 +2706,7 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) netif_info(lio, tx_queued, lio->netdev, "Transmit queued successfully\n"); if (status == IQ_SEND_STOP) - stop_q(netdev, q_idx); + netif_stop_subqueue(netdev, q_idx); netif_trans_update(netdev); @@ -2934,7 +2745,7 @@ static void liquidio_tx_timeout(struct net_device *netdev) "Transmit timeout tx_dropped:%ld, waking up queues now!!\n", netdev->stats.tx_dropped); netif_trans_update(netdev); - txqs_wake(netdev); + wake_txqs(netdev); } static int liquidio_vlan_rx_add_vid(struct net_device *netdev, @@ -3289,10 +3100,120 @@ static int liquidio_get_vf_config(struct net_device *netdev, int vfidx, ether_addr_copy(&ivi->mac[0], macaddr); ivi->vlan = oct->sriov_info.vf_vlantci[vfidx] & VLAN_VID_MASK; ivi->qos = oct->sriov_info.vf_vlantci[vfidx] >> VLAN_PRIO_SHIFT; + if (oct->sriov_info.trusted_vf.active && + oct->sriov_info.trusted_vf.id == vfidx) + ivi->trusted = true; + else + ivi->trusted = false; ivi->linkstate = oct->sriov_info.vf_linkstate[vfidx]; return 0; } +static void trusted_vf_callback(struct octeon_device *oct_dev, + u32 status, void *ptr) +{ + struct octeon_soft_command *sc = (struct octeon_soft_command *)ptr; + struct lio_trusted_vf_ctx *ctx; + + ctx = (struct lio_trusted_vf_ctx *)sc->ctxptr; + ctx->status = status; + + complete(&ctx->complete); +} + +static int liquidio_send_vf_trust_cmd(struct lio *lio, int vfidx, bool trusted) +{ + struct octeon_device *oct = lio->oct_dev; + struct lio_trusted_vf_ctx *ctx; + struct octeon_soft_command *sc; + int ctx_size, retval; + + ctx_size = sizeof(struct lio_trusted_vf_ctx); + sc = octeon_alloc_soft_command(oct, 0, 0, ctx_size); + + ctx = (struct lio_trusted_vf_ctx *)sc->ctxptr; + init_completion(&ctx->complete); + + sc->iq_no = lio->linfo.txpciq[0].s.q_no; + + /* vfidx is 0 based, but vf_num (param1) is 1 based */ + octeon_prepare_soft_command(oct, sc, OPCODE_NIC, + OPCODE_NIC_SET_TRUSTED_VF, 0, vfidx + 1, + trusted); + + sc->callback = trusted_vf_callback; + sc->callback_arg = sc; + sc->wait_time = 1000; + + retval = octeon_send_soft_command(oct, sc); + if (retval == IQ_SEND_FAILED) { + retval = -1; + } else { + /* Wait for response or timeout */ + if (wait_for_completion_timeout(&ctx->complete, + msecs_to_jiffies(2000))) + retval = ctx->status; + else + retval = -1; + } + + octeon_free_soft_command(oct, sc); + + return retval; +} + +static int liquidio_set_vf_trust(struct net_device *netdev, int vfidx, + bool setting) +{ + struct lio *lio = GET_LIO(netdev); + struct octeon_device *oct = lio->oct_dev; + + if (strcmp(oct->fw_info.liquidio_firmware_version, "1.7.1") < 0) { + /* trusted vf is not supported by firmware older than 1.7.1 */ + return -EOPNOTSUPP; + } + + if (vfidx < 0 || vfidx >= oct->sriov_info.num_vfs_alloced) { + netif_info(lio, drv, lio->netdev, "Invalid vfidx %d\n", vfidx); + return -EINVAL; + } + + if (setting) { + /* Set */ + + if (oct->sriov_info.trusted_vf.active && + oct->sriov_info.trusted_vf.id == vfidx) + return 0; + + if (oct->sriov_info.trusted_vf.active) { + netif_info(lio, drv, lio->netdev, "More than one trusted VF is not allowed\n"); + return -EPERM; + } + } else { + /* Clear */ + + if (!oct->sriov_info.trusted_vf.active) + return 0; + } + + if (!liquidio_send_vf_trust_cmd(lio, vfidx, setting)) { + if (setting) { + oct->sriov_info.trusted_vf.id = vfidx; + oct->sriov_info.trusted_vf.active = true; + } else { + oct->sriov_info.trusted_vf.active = false; + } + + netif_info(lio, drv, lio->netdev, "VF %u is %strusted\n", vfidx, + setting ? "" : "not "); + } else { + netif_info(lio, drv, lio->netdev, "Failed to set VF trusted\n"); + return -1; + } + + return 0; +} + static int liquidio_set_vf_link_state(struct net_device *netdev, int vfidx, int linkstate) { @@ -3423,6 +3344,7 @@ static const struct net_device_ops lionetdevops = { .ndo_set_vf_mac = liquidio_set_vf_mac, .ndo_set_vf_vlan = liquidio_set_vf_vlan, .ndo_get_vf_config = liquidio_get_vf_config, + .ndo_set_vf_trust = liquidio_set_vf_trust, .ndo_set_vf_link_state = liquidio_set_vf_link_state, }; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index fd70a4844e2d..f92dfa411de6 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -40,20 +40,6 @@ MODULE_PARM_DESC(debug, "NETIF_MSG debug bits"); #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) -struct liquidio_if_cfg_context { - int octeon_id; - - wait_queue_head_t wc; - - int cond; -}; - -struct liquidio_if_cfg_resp { - u64 rh; - struct liquidio_if_cfg_info cfg_info; - u64 status; -}; - struct liquidio_rx_ctl_context { int octeon_id; @@ -299,105 +285,6 @@ static struct pci_driver liquidio_vf_pci_driver = { }; /** - * \brief Stop Tx queues - * @param netdev network device - */ -static void txqs_stop(struct net_device *netdev) -{ - if (netif_is_multiqueue(netdev)) { - int i; - - for (i = 0; i < netdev->num_tx_queues; i++) - netif_stop_subqueue(netdev, i); - } else { - netif_stop_queue(netdev); - } -} - -/** - * \brief Start Tx queues - * @param netdev network device - */ -static void txqs_start(struct net_device *netdev) -{ - if (netif_is_multiqueue(netdev)) { - int i; - - for (i = 0; i < netdev->num_tx_queues; i++) - netif_start_subqueue(netdev, i); - } else { - netif_start_queue(netdev); - } -} - -/** - * \brief Wake Tx queues - * @param netdev network device - */ -static void txqs_wake(struct net_device *netdev) -{ - struct lio *lio = GET_LIO(netdev); - - if (netif_is_multiqueue(netdev)) { - int i; - - for (i = 0; i < netdev->num_tx_queues; i++) { - int qno = lio->linfo.txpciq[i % lio->oct_dev->num_iqs] - .s.q_no; - if (__netif_subqueue_stopped(netdev, i)) { - INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, qno, - tx_restart, 1); - netif_wake_subqueue(netdev, i); - } - } - } else { - INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, lio->txq, - tx_restart, 1); - netif_wake_queue(netdev); - } -} - -/** - * \brief Start Tx queue - * @param netdev network device - */ -static void start_txq(struct net_device *netdev) -{ - struct lio *lio = GET_LIO(netdev); - - if (lio->linfo.link.s.link_up) { - txqs_start(netdev); - return; - } -} - -/** - * \brief Wake a queue - * @param netdev network device - * @param q which queue to wake - */ -static void wake_q(struct net_device *netdev, int q) -{ - if (netif_is_multiqueue(netdev)) - netif_wake_subqueue(netdev, q); - else - netif_wake_queue(netdev); -} - -/** - * \brief Stop a queue - * @param netdev network device - * @param q which queue to stop - */ -static void stop_q(struct net_device *netdev, int q) -{ - if (netif_is_multiqueue(netdev)) - netif_stop_subqueue(netdev, q); - else - netif_stop_queue(netdev); -} - -/** * Remove the node at the head of the list. The list would be empty at * the end of this call if there are no more nodes in the list. */ @@ -564,8 +451,12 @@ static void octnet_link_status_change(struct work_struct *work) struct cavium_wk *wk = (struct cavium_wk *)work; struct lio *lio = (struct lio *)wk->ctxptr; + /* lio->linfo.link.s.mtu always contains max MTU of the lio interface. + * this API is invoked only when new max-MTU of the interface is + * less than current MTU. + */ rtnl_lock(); - call_netdevice_notifiers(NETDEV_CHANGEMTU, lio->netdev); + dev_set_mtu(lio->netdev, lio->linfo.link.s.mtu); rtnl_unlock(); } @@ -613,6 +504,7 @@ static void update_link_status(struct net_device *netdev, union oct_link_status *ls) { struct lio *lio = GET_LIO(netdev); + int current_max_mtu = lio->linfo.link.s.mtu; struct octeon_device *oct = lio->oct_dev; if ((lio->intf_open) && (lio->linfo.link.u64 != ls->u64)) { @@ -623,24 +515,23 @@ static void update_link_status(struct net_device *netdev, if (lio->linfo.link.s.link_up) { netif_carrier_on(netdev); - txqs_wake(netdev); + wake_txqs(netdev); } else { netif_carrier_off(netdev); - txqs_stop(netdev); + stop_txqs(netdev); } - if (lio->linfo.link.s.mtu != netdev->max_mtu) { - dev_info(&oct->pci_dev->dev, "Max MTU Changed from %d to %d\n", - netdev->max_mtu, lio->linfo.link.s.mtu); + if (lio->linfo.link.s.mtu != current_max_mtu) { + dev_info(&oct->pci_dev->dev, + "Max MTU Changed from %d to %d\n", + current_max_mtu, lio->linfo.link.s.mtu); netdev->max_mtu = lio->linfo.link.s.mtu; } if (lio->linfo.link.s.mtu < netdev->mtu) { dev_warn(&oct->pci_dev->dev, - "PF has changed the MTU for gmx port. Reducing the mtu from %d to %d\n", + "Current MTU is higher than new max MTU; Reducing the current mtu from %d to %d\n", netdev->mtu, lio->linfo.link.s.mtu); - lio->mtu = lio->linfo.link.s.mtu; - netdev->mtu = lio->linfo.link.s.mtu; queue_delayed_work(lio->link_status_wq.wq, &lio->link_status_wq.wk.work, 0); } @@ -1062,44 +953,6 @@ static int octeon_pci_os_setup(struct octeon_device *oct) return 0; } -static int skb_iq(struct lio *lio, struct sk_buff *skb) -{ - int q = 0; - - if (netif_is_multiqueue(lio->netdev)) - q = skb->queue_mapping % lio->linfo.num_txpciq; - - return q; -} - -/** - * \brief Check Tx queue state for a given network buffer - * @param lio per-network private data - * @param skb network buffer - */ -static int check_txq_state(struct lio *lio, struct sk_buff *skb) -{ - int q = 0, iq = 0; - - if (netif_is_multiqueue(lio->netdev)) { - q = skb->queue_mapping; - iq = lio->linfo.txpciq[q % lio->oct_dev->num_iqs].s.q_no; - } else { - iq = lio->txq; - q = iq; - } - - if (octnet_iq_is_full(lio->oct_dev, iq)) - return 0; - - if (__netif_subqueue_stopped(lio->netdev, q)) { - INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, iq, tx_restart, 1); - wake_q(lio->netdev, q); - } - - return 1; -} - /** * \brief Unmap and free network buffer * @param buf buffer @@ -1117,8 +970,6 @@ static void free_netbuf(void *buf) dma_unmap_single(&lio->oct_dev->pci_dev->dev, finfo->dptr, skb->len, DMA_TO_DEVICE); - check_txq_state(lio, skb); - tx_buffer_free(skb); } @@ -1160,8 +1011,6 @@ static void free_netsgbuf(void *buf) list_add_tail(&g->list, &lio->glist[iq]); spin_unlock(&lio->glist_lock[iq]); - check_txq_state(lio, skb); /* mq support: sub-queue state check */ - tx_buffer_free(skb); } @@ -1207,8 +1056,6 @@ static void free_netsgbuf_with_resp(void *buf) spin_unlock(&lio->glist_lock[iq]); /* Don't free the skb yet */ - - check_txq_state(lio, skb); } /** @@ -1268,7 +1115,7 @@ static int liquidio_open(struct net_device *netdev) lio->intf_open = 1; netif_info(lio, ifup, lio->netdev, "Interface Open, ready for traffic\n"); - start_txq(netdev); + start_txqs(netdev); /* tell Octeon to start forwarding packets to host */ send_rx_ctrl_cmd(lio, 1); @@ -1291,15 +1138,6 @@ static int liquidio_stop(struct net_device *netdev) /* tell Octeon to stop forwarding packets to host */ send_rx_ctrl_cmd(lio, 0); - if (oct->props[lio->ifidx].napi_enabled) { - list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) - napi_disable(napi); - - oct->props[lio->ifidx].napi_enabled = 0; - - oct->droq[0]->ops.poll_mode = 0; - } - netif_info(lio, ifdown, lio->netdev, "Stopping interface!\n"); /* Inform that netif carrier is down */ lio->intf_open = 0; @@ -1310,7 +1148,21 @@ static int liquidio_stop(struct net_device *netdev) ifstate_reset(lio, LIO_IFSTATE_RUNNING); - txqs_stop(netdev); + stop_txqs(netdev); + + /* Wait for any pending Rx descriptors */ + if (lio_wait_for_clean_oq(oct)) + netif_info(lio, rx_err, lio->netdev, + "Proceeding with stop interface after partial RX desc processing\n"); + + if (oct->props[lio->ifidx].napi_enabled == 1) { + list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) + napi_disable(napi); + + oct->props[lio->ifidx].napi_enabled = 0; + + oct->droq[0]->ops.poll_mode = 0; + } dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name); @@ -1538,41 +1390,6 @@ static struct net_device_stats *liquidio_get_stats(struct net_device *netdev) } /** - * \brief Net device change_mtu - * @param netdev network device - */ -static int liquidio_change_mtu(struct net_device *netdev, int new_mtu) -{ - struct octnic_ctrl_pkt nctrl; - struct octeon_device *oct; - struct lio *lio; - int ret = 0; - - lio = GET_LIO(netdev); - oct = lio->oct_dev; - - memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); - - nctrl.ncmd.u64 = 0; - nctrl.ncmd.s.cmd = OCTNET_CMD_CHANGE_MTU; - nctrl.ncmd.s.param1 = new_mtu; - nctrl.iq_no = lio->linfo.txpciq[0].s.q_no; - nctrl.wait_time = LIO_CMD_WAIT_TM; - nctrl.netpndev = (u64)netdev; - nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; - - ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); - if (ret < 0) { - dev_err(&oct->pci_dev->dev, "Failed to set MTU\n"); - return -EIO; - } - - lio->mtu = new_mtu; - - return 0; -} - -/** * \brief Handler for SIOCSHWTSTAMP ioctl * @param netdev network device * @param ifr interface request @@ -1763,14 +1580,9 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) lio = GET_LIO(netdev); oct = lio->oct_dev; - if (netif_is_multiqueue(netdev)) { - q_idx = skb->queue_mapping; - q_idx = (q_idx % (lio->linfo.num_txpciq)); - tag = q_idx; - iq_no = lio->linfo.txpciq[q_idx].s.q_no; - } else { - iq_no = lio->txq; - } + q_idx = skb_iq(lio, skb); + tag = q_idx; + iq_no = lio->linfo.txpciq[q_idx].s.q_no; stats = &oct->instr_queue[iq_no]->stats; @@ -1799,22 +1611,12 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) ndata.q_no = iq_no; - if (netif_is_multiqueue(netdev)) { - if (octnet_iq_is_full(oct, ndata.q_no)) { - /* defer sending if queue is full */ - netif_info(lio, tx_err, lio->netdev, "Transmit failed iq:%d full\n", - ndata.q_no); - stats->tx_iq_busy++; - return NETDEV_TX_BUSY; - } - } else { - if (octnet_iq_is_full(oct, lio->txq)) { - /* defer sending if queue is full */ - stats->tx_iq_busy++; - netif_info(lio, tx_err, lio->netdev, "Transmit failed iq:%d full\n", - ndata.q_no); - return NETDEV_TX_BUSY; - } + if (octnet_iq_is_full(oct, ndata.q_no)) { + /* defer sending if queue is full */ + netif_info(lio, tx_err, lio->netdev, "Transmit failed iq:%d full\n", + ndata.q_no); + stats->tx_iq_busy++; + return NETDEV_TX_BUSY; } ndata.datasize = skb->len; @@ -1956,7 +1758,7 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) if (status == IQ_SEND_STOP) { dev_err(&oct->pci_dev->dev, "Rcvd IQ_SEND_STOP signal; stopping IQ-%d\n", iq_no); - stop_q(netdev, q_idx); + netif_stop_subqueue(netdev, q_idx); } netif_trans_update(netdev); @@ -1996,7 +1798,7 @@ static void liquidio_tx_timeout(struct net_device *netdev) "Transmit timeout tx_dropped:%ld, waking up queues now!!\n", netdev->stats.tx_dropped); netif_trans_update(netdev); - txqs_wake(netdev); + wake_txqs(netdev); } static int diff --git a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h index 522dcc4dcff7..75eea83c7cc6 100644 --- a/drivers/net/ethernet/cavium/liquidio/liquidio_common.h +++ b/drivers/net/ethernet/cavium/liquidio/liquidio_common.h @@ -84,6 +84,7 @@ enum octeon_tag_type { #define OPCODE_NIC_IF_CFG 0x09 #define OPCODE_NIC_VF_DRV_NOTICE 0x0A #define OPCODE_NIC_INTRMOD_PARAMS 0x0B +#define OPCODE_NIC_SET_TRUSTED_VF 0x13 #define OPCODE_NIC_SYNC_OCTEON_TIME 0x14 #define VF_DRV_LOADED 1 #define VF_DRV_REMOVED -1 @@ -192,7 +193,8 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry, #define OCTNET_MAX_FRM_SIZE (16000 + OCTNET_FRM_HEADER_SIZE) -#define OCTNET_DEFAULT_FRM_SIZE (1500 + OCTNET_FRM_HEADER_SIZE) +#define OCTNET_DEFAULT_MTU (1500) +#define OCTNET_DEFAULT_FRM_SIZE (OCTNET_DEFAULT_MTU + OCTNET_FRM_HEADER_SIZE) /** NIC Commands are sent using this Octeon Input Queue */ #define OCTNET_CMD_Q 0 @@ -675,9 +677,11 @@ union oct_link_status { u64 if_mode:5; u64 pause:1; u64 flashing:1; - u64 reserved:15; + u64 phy_type:5; + u64 reserved:10; #else - u64 reserved:15; + u64 reserved:10; + u64 phy_type:5; u64 flashing:1; u64 pause:1; u64 if_mode:5; @@ -690,6 +694,12 @@ union oct_link_status { } s; }; +enum lio_phy_type { + LIO_PHY_PORT_TP = 0x0, + LIO_PHY_PORT_FIBRE = 0x1, + LIO_PHY_PORT_UNKNOWN, +}; + /** The txpciq info passed to host from the firmware */ union oct_txpciq { @@ -702,9 +712,13 @@ union oct_txpciq { u64 pkind:6; u64 use_qpg:1; u64 qpg:11; - u64 reserved:30; + u64 reserved0:10; + u64 ctrl_qpg:11; + u64 reserved:9; #else - u64 reserved:30; + u64 reserved:9; + u64 ctrl_qpg:11; + u64 reserved0:10; u64 qpg:11; u64 use_qpg:1; u64 pkind:6; @@ -909,6 +923,12 @@ union oct_nic_if_cfg { } s; }; +struct lio_trusted_vf { + uint64_t active: 1; + uint64_t id : 8; + uint64_t reserved: 55; +}; + struct lio_time { s64 sec; /* seconds */ s64 nsec; /* nanoseconds */ diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h index 63b0c758a0a6..91937cc5c1d7 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h @@ -370,6 +370,8 @@ struct octeon_sriov_info { u32 sriov_enabled; + struct lio_trusted_vf trusted_vf; + /*lookup table that maps DPI ring number to VF pci_dev struct pointer*/ struct pci_dev *dpiring_to_vfpcidev_lut[MAX_POSSIBLE_VFS]; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c index 3461d65ff4eb..f044718cea52 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c @@ -788,7 +788,7 @@ octeon_droq_process_packets(struct octeon_device *oct, * called before calling this routine. */ -static int +int octeon_droq_process_poll_pkts(struct octeon_device *oct, struct octeon_droq *droq, u32 budget) { @@ -835,71 +835,46 @@ octeon_droq_process_poll_pkts(struct octeon_device *oct, return total_pkts_processed; } +/* Enable Pkt Interrupt */ int -octeon_process_droq_poll_cmd(struct octeon_device *oct, u32 q_no, int cmd, - u32 arg) +octeon_enable_irq(struct octeon_device *oct, u32 q_no) { - struct octeon_droq *droq; - - droq = oct->droq[q_no]; + switch (oct->chip_id) { + case OCTEON_CN66XX: + case OCTEON_CN68XX: { + struct octeon_cn6xxx *cn6xxx = + (struct octeon_cn6xxx *)oct->chip; + unsigned long flags; + u32 value; - if (cmd == POLL_EVENT_PROCESS_PKTS) - return octeon_droq_process_poll_pkts(oct, droq, arg); + spin_lock_irqsave + (&cn6xxx->lock_for_droq_int_enb_reg, flags); + value = octeon_read_csr(oct, CN6XXX_SLI_PKT_TIME_INT_ENB); + value |= (1 << q_no); + octeon_write_csr(oct, CN6XXX_SLI_PKT_TIME_INT_ENB, value); + value = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT_ENB); + value |= (1 << q_no); + octeon_write_csr(oct, CN6XXX_SLI_PKT_CNT_INT_ENB, value); - if (cmd == POLL_EVENT_PENDING_PKTS) { - u32 pkt_cnt = atomic_read(&droq->pkts_pending); + /* don't bother flushing the enables */ - return octeon_droq_process_packets(oct, droq, pkt_cnt); + spin_unlock_irqrestore + (&cn6xxx->lock_for_droq_int_enb_reg, flags); } - - if (cmd == POLL_EVENT_ENABLE_INTR) { - u32 value; - unsigned long flags; - - /* Enable Pkt Interrupt */ - switch (oct->chip_id) { - case OCTEON_CN66XX: - case OCTEON_CN68XX: { - struct octeon_cn6xxx *cn6xxx = - (struct octeon_cn6xxx *)oct->chip; - spin_lock_irqsave - (&cn6xxx->lock_for_droq_int_enb_reg, flags); - value = - octeon_read_csr(oct, - CN6XXX_SLI_PKT_TIME_INT_ENB); - value |= (1 << q_no); - octeon_write_csr(oct, - CN6XXX_SLI_PKT_TIME_INT_ENB, - value); - value = - octeon_read_csr(oct, - CN6XXX_SLI_PKT_CNT_INT_ENB); - value |= (1 << q_no); - octeon_write_csr(oct, - CN6XXX_SLI_PKT_CNT_INT_ENB, - value); - - /* don't bother flushing the enables */ - - spin_unlock_irqrestore - (&cn6xxx->lock_for_droq_int_enb_reg, flags); - return 0; - } break; - case OCTEON_CN23XX_PF_VID: { - lio_enable_irq(oct->droq[q_no], oct->instr_queue[q_no]); - } + case OCTEON_CN23XX_PF_VID: + lio_enable_irq(oct->droq[q_no], oct->instr_queue[q_no]); break; - case OCTEON_CN23XX_VF_VID: - lio_enable_irq(oct->droq[q_no], oct->instr_queue[q_no]); + case OCTEON_CN23XX_VF_VID: + lio_enable_irq(oct->droq[q_no], oct->instr_queue[q_no]); break; - } - return 0; + default: + dev_err(&oct->pci_dev->dev, "%s Unknown Chip\n", __func__); + return 1; } - dev_err(&oct->pci_dev->dev, "%s Unknown command: %d\n", __func__, cmd); - return -EINVAL; + return 0; } int octeon_register_droq_ops(struct octeon_device *oct, u32 q_no, diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.h b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h index 815a9f56fd59..f28f262d4ab6 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.h @@ -123,11 +123,6 @@ struct oct_droq_stats { }; -#define POLL_EVENT_INTR_ARRIVED 1 -#define POLL_EVENT_PROCESS_PKTS 2 -#define POLL_EVENT_PENDING_PKTS 3 -#define POLL_EVENT_ENABLE_INTR 4 - /* The maximum number of buffers that can be dispatched from the * output/dma queue. Set to 64 assuming 1K buffers in DROQ and the fact that * max packet size from DROQ is 64K. @@ -414,8 +409,10 @@ int octeon_droq_process_packets(struct octeon_device *oct, struct octeon_droq *droq, u32 budget); -int octeon_process_droq_poll_cmd(struct octeon_device *oct, u32 q_no, - int cmd, u32 arg); +int octeon_droq_process_poll_pkts(struct octeon_device *oct, + struct octeon_droq *droq, u32 budget); + +int octeon_enable_irq(struct octeon_device *oct, u32 q_no); void octeon_droq_check_oom(struct octeon_droq *droq); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c index 57af7df74ced..28e74ee23ff8 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c @@ -87,7 +87,7 @@ int octeon_mbox_read(struct octeon_mbox *mbox) } if (mbox->state & OCTEON_MBOX_STATE_REQUEST_RECEIVING) { - if (mbox->mbox_req.recv_len < msg.s.len) { + if (mbox->mbox_req.recv_len < mbox->mbox_req.msg.s.len) { ret = 0; } else { mbox->state &= ~OCTEON_MBOX_STATE_REQUEST_RECEIVING; @@ -96,7 +96,8 @@ int octeon_mbox_read(struct octeon_mbox *mbox) } } else { if (mbox->state & OCTEON_MBOX_STATE_RESPONSE_RECEIVING) { - if (mbox->mbox_resp.recv_len < msg.s.len) { + if (mbox->mbox_resp.recv_len < + mbox->mbox_resp.msg.s.len) { ret = 0; } else { mbox->state &= diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_network.h b/drivers/net/ethernet/cavium/liquidio/octeon_network.h index f2d1a076a038..4069710796a8 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_network.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_network.h @@ -35,6 +35,18 @@ #define LIO_IFSTATE_RX_TIMESTAMP_ENABLED 0x08 #define LIO_IFSTATE_RESETTING 0x10 +struct liquidio_if_cfg_context { + u32 octeon_id; + wait_queue_head_t wc; + int cond; +}; + +struct liquidio_if_cfg_resp { + u64 rh; + struct liquidio_if_cfg_info cfg_info; + u64 status; +}; + struct oct_nic_stats_resp { u64 rh; struct oct_link_stats stats; @@ -178,12 +190,21 @@ irqreturn_t liquidio_msix_intr_handler(int irq __attribute__((unused)), int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs); +int lio_wait_for_clean_oq(struct octeon_device *oct); /** * \brief Register ethtool operations * @param netdev pointer to network device */ void liquidio_set_ethtool_ops(struct net_device *netdev); +/** + * \brief Net device change_mtu + * @param netdev network device + */ +int liquidio_change_mtu(struct net_device *netdev, int new_mtu); +#define LIO_CHANGE_MTU_SUCCESS 1 +#define LIO_CHANGE_MTU_FAIL 2 + #define SKB_ADJ_MASK 0x3F #define SKB_ADJ (SKB_ADJ_MASK + 1) @@ -486,4 +507,56 @@ static inline int wait_for_pending_requests(struct octeon_device *oct) return 0; } +/** + * \brief Stop Tx queues + * @param netdev network device + */ +static inline void stop_txqs(struct net_device *netdev) +{ + int i; + + for (i = 0; i < netdev->num_tx_queues; i++) + netif_stop_subqueue(netdev, i); +} + +/** + * \brief Wake Tx queues + * @param netdev network device + */ +static inline void wake_txqs(struct net_device *netdev) +{ + struct lio *lio = GET_LIO(netdev); + int i, qno; + + for (i = 0; i < netdev->num_tx_queues; i++) { + qno = lio->linfo.txpciq[i % lio->oct_dev->num_iqs].s.q_no; + + if (__netif_subqueue_stopped(netdev, i)) { + INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, qno, + tx_restart, 1); + netif_wake_subqueue(netdev, i); + } + } +} + +/** + * \brief Start Tx queues + * @param netdev network device + */ +static inline void start_txqs(struct net_device *netdev) +{ + struct lio *lio = GET_LIO(netdev); + int i; + + if (lio->linfo.link.s.link_up) { + for (i = 0; i < netdev->num_tx_queues; i++) + netif_start_subqueue(netdev, i); + } +} + +static inline int skb_iq(struct lio *lio, struct sk_buff *skb) +{ + return skb->queue_mapping % lio->linfo.num_txpciq; +} + #endif diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c index e07d2093b971..b1270355b0b1 100644 --- a/drivers/net/ethernet/cavium/liquidio/request_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c @@ -366,6 +366,7 @@ int lio_process_iq_request_list(struct octeon_device *oct, struct octeon_instr_queue *iq, u32 napi_budget) { + struct cavium_wq *cwq = &oct->dma_comp_wq; int reqtype; void *buf; u32 old = iq->flush_index; @@ -450,6 +451,10 @@ lio_process_iq_request_list(struct octeon_device *oct, bytes_compl); iq->flush_index = old; + if (atomic_read(&oct->response_list + [OCTEON_ORDERED_SC_LIST].pending_req_count)) + queue_delayed_work(cwq->wq, &cwq->wk.work, msecs_to_jiffies(1)); + return inst_count; } @@ -623,7 +628,8 @@ octeon_prepare_soft_command(struct octeon_device *oct, pki_ih3->tag = LIO_CONTROL; pki_ih3->tagtype = ATOMIC_TAG; pki_ih3->qpg = - oct->instr_queue[sc->iq_no]->txpciq.s.qpg; + oct->instr_queue[sc->iq_no]->txpciq.s.ctrl_qpg; + pki_ih3->pm = 0x7; pki_ih3->sl = 8; diff --git a/drivers/net/ethernet/cavium/liquidio/response_manager.c b/drivers/net/ethernet/cavium/liquidio/response_manager.c index 3d691c69f74d..fe5b53700576 100644 --- a/drivers/net/ethernet/cavium/liquidio/response_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/response_manager.c @@ -49,7 +49,6 @@ int octeon_setup_response_list(struct octeon_device *oct) INIT_DELAYED_WORK(&cwq->wk.work, oct_poll_req_completion); cwq->wk.ctxptr = oct; oct->cmd_resp_state = OCT_DRV_ONLINE; - queue_delayed_work(cwq->wq, &cwq->wk.work, msecs_to_jiffies(50)); return ret; } @@ -164,5 +163,8 @@ static void oct_poll_req_completion(struct work_struct *work) struct cavium_wq *cwq = &oct->dma_comp_wq; lio_process_ordered_list(oct, 0); - queue_delayed_work(cwq->wq, &cwq->wk.work, msecs_to_jiffies(50)); + + if (atomic_read(&oct->response_list + [OCTEON_ORDERED_SC_LIST].pending_req_count)) + queue_delayed_work(cwq->wq, &cwq->wk.work, msecs_to_jiffies(1)); } |