X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fliquidio%2Flio_ethdev.c;h=84b8a3288d12a7df9813fa5e1c9fbe2da8897b04;hb=92f3ea373e029a70af583d58656dd1b457b93b09;hp=4d0977a8288f14152c55dd296dd38551b935f291;hpb=932aeb387e37fd59def10ffd78c200694ad5eb6a;p=dpdk.git diff --git a/drivers/net/liquidio/lio_ethdev.c b/drivers/net/liquidio/lio_ethdev.c index 4d0977a828..84b8a3288d 100644 --- a/drivers/net/liquidio/lio_ethdev.c +++ b/drivers/net/liquidio/lio_ethdev.c @@ -32,9 +32,11 @@ */ #include +#include #include #include #include +#include #include "lio_logs.h" #include "lio_23xx_vf.h" @@ -309,7 +311,7 @@ lio_dev_xstats_reset(struct rte_eth_dev *eth_dev) } /* Retrieve the device statistics (# packets in/out, # bytes in/out, etc */ -static void +static int lio_dev_stats_get(struct rte_eth_dev *eth_dev, struct rte_eth_stats *stats) { @@ -357,6 +359,8 @@ lio_dev_stats_get(struct rte_eth_dev *eth_dev, stats->ibytes = bytes; stats->ipackets = pkts; stats->ierrors = drop; + + return 0; } static void @@ -393,6 +397,30 @@ lio_dev_info_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *devinfo) { struct lio_device *lio_dev = LIO_DEV(eth_dev); + struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); + + devinfo->pci_dev = pci_dev; + + switch (pci_dev->id.subsystem_device_id) { + /* CN23xx 10G cards */ + case PCI_SUBSYS_DEV_ID_CN2350_210: + case PCI_SUBSYS_DEV_ID_CN2360_210: + case PCI_SUBSYS_DEV_ID_CN2350_210SVPN3: + case PCI_SUBSYS_DEV_ID_CN2360_210SVPN3: + case PCI_SUBSYS_DEV_ID_CN2350_210SVPT: + case PCI_SUBSYS_DEV_ID_CN2360_210SVPT: + devinfo->speed_capa = ETH_LINK_SPEED_10G; + break; + /* CN23xx 25G cards */ + case PCI_SUBSYS_DEV_ID_CN2350_225: + case PCI_SUBSYS_DEV_ID_CN2360_225: + devinfo->speed_capa = ETH_LINK_SPEED_25G; + break; + default: + devinfo->speed_capa = ETH_LINK_SPEED_10G; + lio_dev_err(lio_dev, + "Unknown CN23XX subsystem device id. Setting 10G as default link speed.\n"); + } devinfo->max_rx_queues = lio_dev->max_rx_queues; devinfo->max_tx_queues = lio_dev->max_tx_queues; @@ -404,7 +432,8 @@ lio_dev_info_get(struct rte_eth_dev *eth_dev, devinfo->rx_offload_capa = (DEV_RX_OFFLOAD_IPV4_CKSUM | DEV_RX_OFFLOAD_UDP_CKSUM | - DEV_RX_OFFLOAD_TCP_CKSUM); + DEV_RX_OFFLOAD_TCP_CKSUM | + DEV_RX_OFFLOAD_VLAN_STRIP); devinfo->tx_offload_capa = (DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM | DEV_TX_OFFLOAD_TCP_CKSUM | @@ -424,29 +453,64 @@ lio_dev_info_get(struct rte_eth_dev *eth_dev, } static int -lio_dev_validate_vf_mtu(struct rte_eth_dev *eth_dev, uint16_t new_mtu) +lio_dev_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu) { struct lio_device *lio_dev = LIO_DEV(eth_dev); + uint16_t pf_mtu = lio_dev->linfo.link.s.mtu; + uint32_t frame_len = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + struct lio_dev_ctrl_cmd ctrl_cmd; + struct lio_ctrl_pkt ctrl_pkt; PMD_INIT_FUNC_TRACE(); if (!lio_dev->intf_open) { - lio_dev_err(lio_dev, "Port %d down, can't check MTU\n", + lio_dev_err(lio_dev, "Port %d down, can't set MTU\n", lio_dev->port_id); return -EINVAL; } - /* Limit the MTU to make sure the ethernet packets are between - * ETHER_MIN_MTU bytes and PF's MTU + /* check if VF MTU is within allowed range. + * New value should not exceed PF MTU. */ - if ((new_mtu < ETHER_MIN_MTU) || - (new_mtu > lio_dev->linfo.link.s.mtu)) { - lio_dev_err(lio_dev, "Invalid MTU: %d\n", new_mtu); - lio_dev_err(lio_dev, "Valid range %d and %d\n", - ETHER_MIN_MTU, lio_dev->linfo.link.s.mtu); + if ((mtu < ETHER_MIN_MTU) || (mtu > pf_mtu)) { + lio_dev_err(lio_dev, "VF MTU should be >= %d and <= %d\n", + ETHER_MIN_MTU, pf_mtu); return -EINVAL; } + /* flush added to prevent cmd failure + * incase the queue is full + */ + lio_flush_iq(lio_dev, lio_dev->instr_queue[0]); + + memset(&ctrl_pkt, 0, sizeof(struct lio_ctrl_pkt)); + memset(&ctrl_cmd, 0, sizeof(struct lio_dev_ctrl_cmd)); + + ctrl_cmd.eth_dev = eth_dev; + ctrl_cmd.cond = 0; + + ctrl_pkt.ncmd.s.cmd = LIO_CMD_CHANGE_MTU; + ctrl_pkt.ncmd.s.param1 = mtu; + ctrl_pkt.ctrl_cmd = &ctrl_cmd; + + if (lio_send_ctrl_pkt(lio_dev, &ctrl_pkt)) { + lio_dev_err(lio_dev, "Failed to send command to change MTU\n"); + return -1; + } + + if (lio_wait_for_ctrl_cmd(lio_dev, &ctrl_cmd)) { + lio_dev_err(lio_dev, "Command to change MTU timed out\n"); + return -1; + } + + if (frame_len > ETHER_MAX_LEN) + eth_dev->data->dev_conf.rxmode.jumbo_frame = 1; + else + eth_dev->data->dev_conf.rxmode.jumbo_frame = 0; + + eth_dev->data->dev_conf.rxmode.max_rx_pkt_len = frame_len; + eth_dev->data->mtu = mtu; + return 0; } @@ -825,6 +889,47 @@ lio_dev_udp_tunnel_del(struct rte_eth_dev *eth_dev, return 0; } +static int +lio_dev_vlan_filter_set(struct rte_eth_dev *eth_dev, uint16_t vlan_id, int on) +{ + struct lio_device *lio_dev = LIO_DEV(eth_dev); + struct lio_dev_ctrl_cmd ctrl_cmd; + struct lio_ctrl_pkt ctrl_pkt; + + if (lio_dev->linfo.vlan_is_admin_assigned) + return -EPERM; + + /* flush added to prevent cmd failure + * incase the queue is full + */ + lio_flush_iq(lio_dev, lio_dev->instr_queue[0]); + + memset(&ctrl_pkt, 0, sizeof(struct lio_ctrl_pkt)); + memset(&ctrl_cmd, 0, sizeof(struct lio_dev_ctrl_cmd)); + + ctrl_cmd.eth_dev = eth_dev; + ctrl_cmd.cond = 0; + + ctrl_pkt.ncmd.s.cmd = on ? + LIO_CMD_ADD_VLAN_FILTER : LIO_CMD_DEL_VLAN_FILTER; + ctrl_pkt.ncmd.s.param1 = vlan_id; + ctrl_pkt.ctrl_cmd = &ctrl_cmd; + + if (lio_send_ctrl_pkt(lio_dev, &ctrl_pkt)) { + lio_dev_err(lio_dev, "Failed to %s VLAN port\n", + on ? "add" : "remove"); + return -1; + } + + if (lio_wait_for_ctrl_cmd(lio_dev, &ctrl_cmd)) { + lio_dev_err(lio_dev, "Command to %s VLAN port timed out\n", + on ? "add" : "remove"); + return -1; + } + + return 0; +} + /** * Atomically writes the link status information into global * structure rte_eth_dev. @@ -876,6 +981,7 @@ lio_dev_link_update(struct rte_eth_dev *eth_dev, link.link_status = ETH_LINK_DOWN; link.link_speed = ETH_SPEED_NUM_NONE; link.link_duplex = ETH_LINK_HALF_DUPLEX; + link.link_autoneg = ETH_LINK_AUTONEG; memset(&old, 0, sizeof(old)); /* Return what we found */ @@ -894,6 +1000,9 @@ lio_dev_link_update(struct rte_eth_dev *eth_dev, case LIO_LINK_SPEED_10000: link.link_speed = ETH_SPEED_NUM_10G; break; + case LIO_LINK_SPEED_25000: + link.link_speed = ETH_SPEED_NUM_25G; + break; default: link.link_speed = ETH_SPEED_NUM_NONE; link.link_duplex = ETH_LINK_HALF_DUPLEX; @@ -944,6 +1053,48 @@ lio_change_dev_flag(struct rte_eth_dev *eth_dev) lio_dev_err(lio_dev, "Change dev flag command timed out\n"); } +static void +lio_dev_promiscuous_enable(struct rte_eth_dev *eth_dev) +{ + struct lio_device *lio_dev = LIO_DEV(eth_dev); + + if (strcmp(lio_dev->firmware_version, LIO_VF_TRUST_MIN_VERSION) < 0) { + lio_dev_err(lio_dev, "Require firmware version >= %s\n", + LIO_VF_TRUST_MIN_VERSION); + return; + } + + if (!lio_dev->intf_open) { + lio_dev_err(lio_dev, "Port %d down, can't enable promiscuous\n", + lio_dev->port_id); + return; + } + + lio_dev->ifflags |= LIO_IFFLAG_PROMISC; + lio_change_dev_flag(eth_dev); +} + +static void +lio_dev_promiscuous_disable(struct rte_eth_dev *eth_dev) +{ + struct lio_device *lio_dev = LIO_DEV(eth_dev); + + if (strcmp(lio_dev->firmware_version, LIO_VF_TRUST_MIN_VERSION) < 0) { + lio_dev_err(lio_dev, "Require firmware version >= %s\n", + LIO_VF_TRUST_MIN_VERSION); + return; + } + + if (!lio_dev->intf_open) { + lio_dev_err(lio_dev, "Port %d down, can't disable promiscuous\n", + lio_dev->port_id); + return; + } + + lio_dev->ifflags &= ~LIO_IFFLAG_PROMISC; + lio_change_dev_flag(eth_dev); +} + static void lio_dev_allmulticast_enable(struct rte_eth_dev *eth_dev) { @@ -1109,18 +1260,17 @@ lio_dev_rx_queue_setup(struct rte_eth_dev *eth_dev, uint16_t q_no, * @return * - nothing */ -static void +void lio_dev_rx_queue_release(void *rxq) { struct lio_droq *droq = rxq; - struct lio_device *lio_dev = droq->lio_dev; int oq_no; - /* Run time queue deletion not supported */ - if (lio_dev->port_configured) - return; + if (droq) { + /* Run time queue deletion not supported */ + if (droq->lio_dev->port_configured) + return; - if (droq != NULL) { oq_no = droq->q_no; lio_delete_droq_queue(droq->lio_dev, oq_no); } @@ -1204,18 +1354,18 @@ lio_dev_tx_queue_setup(struct rte_eth_dev *eth_dev, uint16_t q_no, * @return * - nothing */ -static void +void lio_dev_tx_queue_release(void *txq) { struct lio_instr_queue *tq = txq; - struct lio_device *lio_dev = tq->lio_dev; uint32_t fw_mapped_iq_no; - /* Run time queue deletion not supported */ - if (lio_dev->port_configured) - return; - if (tq != NULL) { + if (tq) { + /* Run time queue deletion not supported */ + if (tq->lio_dev->port_configured) + return; + /* Free sg_list */ lio_delete_sglist(tq); @@ -1268,6 +1418,11 @@ lio_dev_get_link_status(struct rte_eth_dev *eth_dev) lio_swap_8B_data((uint64_t *)ls, sizeof(union octeon_link_status) >> 3); if (lio_dev->linfo.link.link_status64 != ls->link_status64) { + if (ls->s.mtu < eth_dev->data->mtu) { + lio_dev_info(lio_dev, "Lowered VF MTU to %d as PF MTU dropped\n", + ls->s.mtu); + eth_dev->data->mtu = ls->s.mtu; + } lio_dev->linfo.link.link_status64 = ls->link_status64; lio_dev_link_update(eth_dev, 0); } @@ -1303,7 +1458,8 @@ lio_sync_link_state_check(void *eth_dev) static int lio_dev_start(struct rte_eth_dev *eth_dev) { - uint16_t mtu = eth_dev->data->dev_conf.rxmode.max_rx_pkt_len; + uint16_t mtu; + uint32_t frame_len = eth_dev->data->dev_conf.rxmode.max_rx_pkt_len; struct lio_device *lio_dev = LIO_DEV(eth_dev); uint16_t timeout = LIO_MAX_CMD_TIMEOUT; int ret = 0; @@ -1338,18 +1494,22 @@ lio_dev_start(struct rte_eth_dev *eth_dev) if (lio_dev->linfo.link.link_status64 == 0) { ret = -1; - goto dev_mtu_check_error; + goto dev_mtu_set_error; } - if (lio_dev->linfo.link.s.mtu != mtu) { - ret = lio_dev_validate_vf_mtu(eth_dev, mtu); + mtu = (uint16_t)(frame_len - ETHER_HDR_LEN - ETHER_CRC_LEN); + if (mtu < ETHER_MIN_MTU) + mtu = ETHER_MIN_MTU; + + if (eth_dev->data->mtu != mtu) { + ret = lio_dev_mtu_set(eth_dev, mtu); if (ret) - goto dev_mtu_check_error; + goto dev_mtu_set_error; } return 0; -dev_mtu_check_error: +dev_mtu_set_error: rte_eal_alarm_cancel(lio_sync_link_state_check, eth_dev); dev_lsc_handle_error: @@ -1359,6 +1519,25 @@ dev_lsc_handle_error: return ret; } +/* Stop device and disable input/output functions */ +static void +lio_dev_stop(struct rte_eth_dev *eth_dev) +{ + struct lio_device *lio_dev = LIO_DEV(eth_dev); + + lio_dev_info(lio_dev, "Stopping port %d\n", eth_dev->data->port_id); + lio_dev->intf_open = 0; + rte_mb(); + + /* Cancel callback if still running. */ + rte_eal_alarm_cancel(lio_sync_link_state_check, eth_dev); + + lio_send_rx_ctrl_cmd(eth_dev, 0); + + /* Clear recorded link status */ + lio_dev->linfo.link.link_status64 = 0; +} + static int lio_dev_set_link_up(struct rte_eth_dev *eth_dev) { @@ -1413,6 +1592,70 @@ lio_dev_set_link_down(struct rte_eth_dev *eth_dev) return 0; } +/** + * Reset and stop the device. This occurs on the first + * call to this routine. Subsequent calls will simply + * return. NB: This will require the NIC to be rebooted. + * + * @param eth_dev + * Pointer to the structure rte_eth_dev + * + * @return + * - nothing + */ +static void +lio_dev_close(struct rte_eth_dev *eth_dev) +{ + struct lio_device *lio_dev = LIO_DEV(eth_dev); + uint32_t i; + + lio_dev_info(lio_dev, "closing port %d\n", eth_dev->data->port_id); + + if (lio_dev->intf_open) + lio_dev_stop(eth_dev); + + lio_wait_for_instr_fetch(lio_dev); + + lio_dev->fn_list.disable_io_queues(lio_dev); + + cn23xx_vf_set_io_queues_off(lio_dev); + + /* Reset iq regs (IQ_DBELL). + * Clear sli_pktx_cnts (OQ_PKTS_SENT). + */ + for (i = 0; i < lio_dev->nb_rx_queues; i++) { + struct lio_droq *droq = lio_dev->droq[i]; + + if (droq == NULL) + break; + + uint32_t pkt_count = rte_read32(droq->pkts_sent_reg); + + lio_dev_dbg(lio_dev, + "pending oq count %u\n", pkt_count); + rte_write32(pkt_count, droq->pkts_sent_reg); + } + + if (lio_dev->pci_dev->kdrv == RTE_KDRV_IGB_UIO) { + cn23xx_vf_ask_pf_to_do_flr(lio_dev); + rte_delay_ms(LIO_PCI_FLR_WAIT); + } + + /* lio_free_mbox */ + lio_dev->fn_list.free_mbox(lio_dev); + + /* Free glist resources */ + rte_free(lio_dev->glist_head); + rte_free(lio_dev->glist_lock); + lio_dev->glist_head = NULL; + lio_dev->glist_lock = NULL; + + lio_dev->port_configured = 0; + + /* Delete all queues */ + lio_dev_clear_queues(eth_dev); +} + /** * Enable tunnel rx checksum verification from firmware. */ @@ -1557,6 +1800,9 @@ static int lio_dev_configure(struct rte_eth_dev *eth_dev) goto nic_config_fail; } + snprintf(lio_dev->firmware_version, LIO_FW_VERSION_LENGTH, "%s", + resp->cfg_info.lio_firmware_version); + lio_swap_8B_data((uint64_t *)(&resp->cfg_info), sizeof(struct octeon_if_cfg_info) >> 3); @@ -1656,8 +1902,12 @@ nic_config_fail: static const struct eth_dev_ops liovf_eth_dev_ops = { .dev_configure = lio_dev_configure, .dev_start = lio_dev_start, + .dev_stop = lio_dev_stop, .dev_set_link_up = lio_dev_set_link_up, .dev_set_link_down = lio_dev_set_link_down, + .dev_close = lio_dev_close, + .promiscuous_enable = lio_dev_promiscuous_enable, + .promiscuous_disable = lio_dev_promiscuous_disable, .allmulticast_enable = lio_dev_allmulticast_enable, .allmulticast_disable = lio_dev_allmulticast_disable, .link_update = lio_dev_link_update, @@ -1667,6 +1917,7 @@ static const struct eth_dev_ops liovf_eth_dev_ops = { .stats_reset = lio_dev_stats_reset, .xstats_reset = lio_dev_xstats_reset, .dev_infos_get = lio_dev_info_get, + .vlan_filter_set = lio_dev_vlan_filter_set, .rx_queue_setup = lio_dev_rx_queue_setup, .rx_queue_release = lio_dev_rx_queue_release, .tx_queue_setup = lio_dev_tx_queue_setup, @@ -1677,6 +1928,7 @@ static const struct eth_dev_ops liovf_eth_dev_ops = { .rss_hash_update = lio_dev_rss_hash_update, .udp_tunnel_port_add = lio_dev_udp_tunnel_add, .udp_tunnel_port_del = lio_dev_udp_tunnel_del, + .mtu_set = lio_dev_mtu_set, }; static void @@ -1762,10 +2014,12 @@ lio_first_time_init(struct lio_device *lio_dev, if (cn23xx_pfvf_handshake(lio_dev)) goto error; - /* Initial reset */ - cn23xx_vf_ask_pf_to_do_flr(lio_dev); - /* Wait for FLR for 100ms per SRIOV specification */ - rte_delay_ms(100); + /* Request and wait for device reset. */ + if (pdev->kdrv == RTE_KDRV_IGB_UIO) { + cn23xx_vf_ask_pf_to_do_flr(lio_dev); + /* FLR wait time doubled as a precaution. */ + rte_delay_ms(LIO_PCI_FLR_WAIT * 2); + } if (cn23xx_vf_set_io_queues_off(lio_dev)) { lio_dev_err(lio_dev, "Setting io queues off failed\n"); @@ -1819,6 +2073,7 @@ lio_eth_dev_uninit(struct rte_eth_dev *eth_dev) rte_free(eth_dev->data->mac_addrs); eth_dev->data->mac_addrs = NULL; + eth_dev->dev_ops = NULL; eth_dev->rx_pkt_burst = NULL; eth_dev->tx_pkt_burst = NULL; @@ -1828,7 +2083,7 @@ lio_eth_dev_uninit(struct rte_eth_dev *eth_dev) static int lio_eth_dev_init(struct rte_eth_dev *eth_dev) { - struct rte_pci_device *pdev = RTE_DEV_TO_PCI(eth_dev->device); + struct rte_pci_device *pdev = RTE_ETH_DEV_TO_PCI(eth_dev); struct lio_device *lio_dev = LIO_DEV(eth_dev); PMD_INIT_FUNC_TRACE(); @@ -1841,7 +2096,6 @@ lio_eth_dev_init(struct rte_eth_dev *eth_dev) return 0; rte_eth_copy_pci_info(eth_dev, pdev); - eth_dev->data->dev_flags |= RTE_ETH_DEV_DETACHABLE; if (pdev->mem_resource[0].addr) { lio_dev->hw_addr = pdev->mem_resource[0].addr; @@ -1884,24 +2138,45 @@ lio_eth_dev_init(struct rte_eth_dev *eth_dev) return 0; } +static int +lio_eth_dev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *pci_dev) +{ + struct rte_eth_dev *eth_dev; + int ret; + + eth_dev = rte_eth_dev_pci_allocate(pci_dev, + sizeof(struct lio_device)); + if (eth_dev == NULL) + return -ENOMEM; + + ret = lio_eth_dev_init(eth_dev); + if (ret) + rte_eth_dev_pci_release(eth_dev); + + return ret; +} + +static int +lio_eth_dev_pci_remove(struct rte_pci_device *pci_dev) +{ + return rte_eth_dev_pci_generic_remove(pci_dev, + lio_eth_dev_uninit); +} + /* Set of PCI devices this driver supports */ static const struct rte_pci_id pci_id_liovf_map[] = { { RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, LIO_CN23XX_VF_VID) }, { .vendor_id = 0, /* sentinel */ } }; -static struct eth_driver rte_liovf_pmd = { - .pci_drv = { - .id_table = pci_id_liovf_map, - .drv_flags = RTE_PCI_DRV_NEED_MAPPING, - .probe = rte_eth_dev_pci_probe, - .remove = rte_eth_dev_pci_remove, - }, - .eth_dev_init = lio_eth_dev_init, - .eth_dev_uninit = lio_eth_dev_uninit, - .dev_private_size = sizeof(struct lio_device), +static struct rte_pci_driver rte_liovf_pmd = { + .id_table = pci_id_liovf_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING, + .probe = lio_eth_dev_pci_probe, + .remove = lio_eth_dev_pci_remove, }; -RTE_PMD_REGISTER_PCI(net_liovf, rte_liovf_pmd.pci_drv); +RTE_PMD_REGISTER_PCI(net_liovf, rte_liovf_pmd); RTE_PMD_REGISTER_PCI_TABLE(net_liovf, pci_id_liovf_map); -RTE_PMD_REGISTER_KMOD_DEP(net_liovf, "* igb_uio | vfio"); +RTE_PMD_REGISTER_KMOD_DEP(net_liovf, "* igb_uio | vfio-pci");