X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;ds=sidebyside;f=lib%2Flibrte_pmd_e1000%2Figb_ethdev.c;h=044eac39aafaabf48e26a8915fc91e094fe5beed;hb=57f0ba5f8b8588dfa6ffcd001447ef6337afa6cd;hp=f13da4041273f83acd0918f640b684029a84278b;hpb=5caeb1b143da211d545bd9e59e9a93c830fc778f;p=dpdk.git diff --git a/lib/librte_pmd_e1000/igb_ethdev.c b/lib/librte_pmd_e1000/igb_ethdev.c index f13da40412..044eac39aa 100644 --- a/lib/librte_pmd_e1000/igb_ethdev.c +++ b/lib/librte_pmd_e1000/igb_ethdev.c @@ -1,7 +1,7 @@ /*- * BSD LICENSE * - * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,6 +51,7 @@ #include #include #include +#include #include "e1000_logs.h" #include "e1000/e1000_api.h" @@ -319,6 +320,61 @@ igb_identify_hardware(struct rte_eth_dev *dev) /* need to check if it is a vf device below */ } +static int +igb_reset_swfw_lock(struct e1000_hw *hw) +{ + int ret_val; + + /* + * Do mac ops initialization manually here, since we will need + * some function pointers set by this call. + */ + ret_val = e1000_init_mac_params(hw); + if (ret_val) + return ret_val; + + /* + * SMBI lock should not fail in this early stage. If this is the case, + * it is due to an improper exit of the application. + * So force the release of the faulty lock. + */ + if (e1000_get_hw_semaphore_generic(hw) < 0) { + DEBUGOUT("SMBI lock released"); + } + e1000_put_hw_semaphore_generic(hw); + + if (hw->mac.ops.acquire_swfw_sync != NULL) { + uint16_t mask; + + /* + * Phy lock should not fail in this early stage. If this is the case, + * it is due to an improper exit of the application. + * So force the release of the faulty lock. + */ + mask = E1000_SWFW_PHY0_SM << hw->bus.func; + if (hw->bus.func > E1000_FUNC_1) + mask <<= 2; + if (hw->mac.ops.acquire_swfw_sync(hw, mask) < 0) { + DEBUGOUT1("SWFW phy%d lock released", hw->bus.func); + } + hw->mac.ops.release_swfw_sync(hw, mask); + + /* + * This one is more tricky since it is common to all ports; but + * swfw_sync retries last long enough (1s) to be almost sure that if + * lock can not be taken it is due to an improper lock of the + * semaphore. + */ + mask = E1000_SWFW_EEP_SM; + if (hw->mac.ops.acquire_swfw_sync(hw, mask) < 0) { + DEBUGOUT("SWFW common locks released"); + } + hw->mac.ops.release_swfw_sync(hw, mask); + } + + return E1000_SUCCESS; +} + static int eth_igb_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, struct rte_eth_dev *eth_dev) @@ -348,13 +404,25 @@ eth_igb_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, hw->hw_addr= (void *)pci_dev->mem_resource[0].addr; igb_identify_hardware(eth_dev); - if (e1000_setup_init_funcs(hw, TRUE) != E1000_SUCCESS) { + if (e1000_setup_init_funcs(hw, FALSE) != E1000_SUCCESS) { error = -EIO; goto err_late; } e1000_get_bus_info(hw); + /* Reset any pending lock */ + if (igb_reset_swfw_lock(hw) != E1000_SUCCESS) { + error = -EIO; + goto err_late; + } + + /* Finish initialization */ + if (e1000_setup_init_funcs(hw, TRUE) != E1000_SUCCESS) { + error = -EIO; + goto err_late; + } + hw->mac.autoneg = 1; hw->phy.autoneg_wait_to_complete = 0; hw->phy.autoneg_advertised = E1000_ALL_SPEED_DUPLEX; @@ -533,9 +601,7 @@ static struct eth_driver rte_igb_pmd = { { .name = "rte_igb_pmd", .id_table = pci_id_igb_map, -#ifdef RTE_EAL_UNBIND_PORTS .drv_flags = RTE_PCI_DRV_NEED_IGB_UIO, -#endif }, .eth_dev_init = eth_igb_dev_init, .dev_private_size = sizeof(struct e1000_adapter), @@ -548,28 +614,37 @@ static struct eth_driver rte_igbvf_pmd = { { .name = "rte_igbvf_pmd", .id_table = pci_id_igbvf_map, -#ifdef RTE_EAL_UNBIND_PORTS .drv_flags = RTE_PCI_DRV_NEED_IGB_UIO, -#endif }, .eth_dev_init = eth_igbvf_dev_init, .dev_private_size = sizeof(struct e1000_adapter), }; -int -rte_igb_pmd_init(void) +static int +rte_igb_pmd_init(const char *name __rte_unused, const char *params __rte_unused) { rte_eth_driver_register(&rte_igb_pmd); return 0; } +static void +igb_vmdq_vlan_hw_filter_enable(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + /* RCTL: enable VLAN filter since VMDq always use VLAN filter */ + uint32_t rctl = E1000_READ_REG(hw, E1000_RCTL); + rctl |= E1000_RCTL_VFE; + E1000_WRITE_REG(hw, E1000_RCTL, rctl); +} + /* * VF Driver initialization routine. * Invoked one at EAL init time. * Register itself as the [Virtual Poll Mode] Driver of PCI IGB devices. */ -int -rte_igbvf_pmd_init(void) +static int +rte_igbvf_pmd_init(const char *name __rte_unused, const char *params __rte_unused) { DEBUGFUNC("rte_igbvf_pmd_init"); @@ -626,7 +701,7 @@ eth_igb_start(struct rte_eth_dev *dev) return (-EIO); } - E1000_WRITE_REG(hw, E1000_VET, ETHER_TYPE_VLAN); + E1000_WRITE_REG(hw, E1000_VET, ETHER_TYPE_VLAN << 16 | ETHER_TYPE_VLAN); ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); /* Set PF Reset Done bit so PF/VF Mail Ops can work */ @@ -659,6 +734,11 @@ eth_igb_start(struct rte_eth_dev *dev) ETH_VLAN_EXTEND_MASK; eth_igb_vlan_offload_set(dev, mask); + if (dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_VMDQ_ONLY) { + /* Enable VLAN filter since VMDq always use VLAN filter */ + igb_vmdq_vlan_hw_filter_enable(dev); + } + /* * Configure the Interrupt Moderation register (EITR) with the maximum * possible value (0xFFFF) to minimize "System Partial Write" issued by @@ -855,7 +935,7 @@ igb_hardware_init(struct e1000_hw *hw) * frames to be received after sending an XOFF. * - Low water mark works best when it is very near the high water mark. * This allows the receiver to restart by sending XON when it has - * drained a bit. Here we use an arbitary value of 1500 which will + * drained a bit. Here we use an arbitrary value of 1500 which will * restart after one full frame is pulled from the buffer. There * could be several smaller frames in the buffer and if so they will * not trigger the XON until their total number reduces the buffer @@ -883,7 +963,7 @@ igb_hardware_init(struct e1000_hw *hw) if (diag < 0) return (diag); - E1000_WRITE_REG(hw, E1000_VET, ETHER_TYPE_VLAN); + E1000_WRITE_REG(hw, E1000_VET, ETHER_TYPE_VLAN << 16 | ETHER_TYPE_VLAN); e1000_get_phy_info(hw); e1000_check_for_link(hw); @@ -1011,6 +1091,12 @@ eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) /* Tx Errors */ rte_stats->oerrors = stats->ecol + stats->latecol; + /* XON/XOFF pause frames */ + rte_stats->tx_pause_xon = stats->xontxc; + rte_stats->rx_pause_xon = stats->xonrxc; + rte_stats->tx_pause_xoff = stats->xofftxc; + rte_stats->rx_pause_xoff = stats->xoffrxc; + rte_stats->ipackets = stats->gprc; rte_stats->opackets = stats->gptc; rte_stats->ibytes = stats->gorc; @@ -1113,24 +1199,44 @@ eth_igb_infos_get(struct rte_eth_dev *dev, dev_info->min_rx_bufsize = 256; /* See BSIZE field of RCTL register. */ dev_info->max_rx_pktlen = 0x3FFF; /* See RLPML register. */ dev_info->max_mac_addrs = hw->mac.rar_entry_count; + dev_info->rx_offload_capa = + DEV_RX_OFFLOAD_VLAN_STRIP | + DEV_RX_OFFLOAD_IPV4_CKSUM | + DEV_RX_OFFLOAD_UDP_CKSUM | + DEV_RX_OFFLOAD_TCP_CKSUM; + dev_info->tx_offload_capa = + DEV_TX_OFFLOAD_VLAN_INSERT | + DEV_TX_OFFLOAD_IPV4_CKSUM | + DEV_TX_OFFLOAD_UDP_CKSUM | + DEV_TX_OFFLOAD_TCP_CKSUM | + DEV_TX_OFFLOAD_SCTP_CKSUM; switch (hw->mac.type) { case e1000_82575: dev_info->max_rx_queues = 4; dev_info->max_tx_queues = 4; + dev_info->max_vmdq_pools = 0; break; case e1000_82576: dev_info->max_rx_queues = 16; dev_info->max_tx_queues = 16; + dev_info->max_vmdq_pools = ETH_8_POOLS; break; case e1000_82580: dev_info->max_rx_queues = 8; dev_info->max_tx_queues = 8; + dev_info->max_vmdq_pools = ETH_8_POOLS; break; case e1000_i350: + dev_info->max_rx_queues = 8; + dev_info->max_tx_queues = 8; + dev_info->max_vmdq_pools = ETH_8_POOLS; + break; + + case e1000_i354: dev_info->max_rx_queues = 8; dev_info->max_tx_queues = 8; break; @@ -1138,22 +1244,26 @@ eth_igb_infos_get(struct rte_eth_dev *dev, case e1000_i210: dev_info->max_rx_queues = 4; dev_info->max_tx_queues = 4; + dev_info->max_vmdq_pools = 0; break; case e1000_vfadapt: dev_info->max_rx_queues = 2; dev_info->max_tx_queues = 2; + dev_info->max_vmdq_pools = 0; break; case e1000_vfadapt_i350: dev_info->max_rx_queues = 1; dev_info->max_tx_queues = 1; + dev_info->max_vmdq_pools = 0; break; default: /* Should not happen */ dev_info->max_rx_queues = 0; dev_info->max_tx_queues = 0; + dev_info->max_vmdq_pools = 0; } } @@ -1698,6 +1808,7 @@ eth_igb_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) }; uint32_t rx_buf_size; uint32_t max_high_water; + uint32_t rctl; hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); rx_buf_size = igb_get_rx_buffer_size(hw); @@ -1720,6 +1831,21 @@ eth_igb_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) err = e1000_setup_link_generic(hw); if (err == E1000_SUCCESS) { + + /* check if we want to forward MAC frames - driver doesn't have native + * capability to do that, so we'll write the registers ourselves */ + + rctl = E1000_READ_REG(hw, E1000_RCTL); + + /* set or clear MFLCN.PMCF bit depending on configuration */ + if (fc_conf->mac_ctrl_frame_fwd != 0) + rctl |= E1000_RCTL_PMCF; + else + rctl &= ~E1000_RCTL_PMCF; + + E1000_WRITE_REG(hw, E1000_RCTL, rctl); + E1000_WRITE_FLUSH(hw); + return 0; } @@ -2057,3 +2183,16 @@ eth_igb_rss_reta_query(struct rte_eth_dev *dev, return 0; } + +static struct rte_driver pmd_igb_drv = { + .type = PMD_PDEV, + .init = rte_igb_pmd_init, +}; + +static struct rte_driver pmd_igbvf_drv = { + .type = PMD_PDEV, + .init = rte_igbvf_pmd_init, +}; + +PMD_REGISTER_DRIVER(pmd_igb_drv); +PMD_REGISTER_DRIVER(pmd_igbvf_drv);