X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fe1000%2Fem_ethdev.c;h=9b5e1afa0c31b3a7408fcc69fad4fd48a9afe07c;hb=e64a0edb01812bb688c32ddda18eede344ffe163;hp=dfabb158ca6fac303d7826482adc050697234d0e;hpb=b9eee2cb8c291d9063297c8a36d042eb59190ae9;p=dpdk.git diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c index dfabb158ca..9b5e1afa0c 100644 --- a/drivers/net/e1000/em_ethdev.c +++ b/drivers/net/e1000/em_ethdev.c @@ -81,6 +81,7 @@ static int eth_em_flow_ctrl_get(struct rte_eth_dev *dev, static int eth_em_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf); static int eth_em_interrupt_setup(struct rte_eth_dev *dev); +static int eth_em_rxq_interrupt_setup(struct rte_eth_dev *dev); static int eth_em_interrupt_get_status(struct rte_eth_dev *dev); static int eth_em_interrupt_action(struct rte_eth_dev *dev); static void eth_em_interrupt_handler(struct rte_intr_handle *handle, @@ -107,10 +108,16 @@ static void em_vlan_hw_strip_disable(struct rte_eth_dev *dev); static void eth_em_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on); */ + +static int eth_em_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id); +static int eth_em_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id); +static void em_lsc_intr_disable(struct e1000_hw *hw); +static void em_rxq_intr_enable(struct e1000_hw *hw); +static void em_rxq_intr_disable(struct e1000_hw *hw); + static int eth_em_led_on(struct rte_eth_dev *dev); static int eth_em_led_off(struct rte_eth_dev *dev); -static void em_intr_disable(struct e1000_hw *hw); static int em_get_rx_buffer_size(struct e1000_hw *hw); static void eth_em_rar_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr, uint32_t index, uint32_t pool); @@ -159,6 +166,8 @@ static const struct eth_dev_ops eth_em_ops = { .rx_descriptor_done = eth_em_rx_descriptor_done, .tx_queue_setup = eth_em_tx_queue_setup, .tx_queue_release = eth_em_tx_queue_release, + .rx_queue_intr_enable = eth_em_rx_queue_intr_enable, + .rx_queue_intr_disable = eth_em_rx_queue_intr_disable, .dev_led_on = eth_em_led_on, .dev_led_off = eth_em_led_off, .flow_ctrl_get = eth_em_flow_ctrl_get, @@ -166,6 +175,8 @@ static const struct eth_dev_ops eth_em_ops = { .mac_addr_add = eth_em_rar_set, .mac_addr_remove = eth_em_rar_clear, .set_mc_addr_list = eth_em_set_mc_addr_list, + .rxq_info_get = em_rxq_info_get, + .txq_info_get = em_txq_info_get, }; /** @@ -220,6 +231,32 @@ rte_em_dev_atomic_write_link_status(struct rte_eth_dev *dev, return 0; } +/** + * eth_em_dev_is_ich8 - Check for ICH8 device + * @hw: pointer to the HW structure + * + * return TRUE for ICH8, otherwise FALSE + **/ +static bool +eth_em_dev_is_ich8(struct e1000_hw *hw) +{ + DEBUGFUNC("eth_em_dev_is_ich8"); + + switch (hw->device_id) { + case E1000_DEV_ID_PCH_LPT_I217_LM: + case E1000_DEV_ID_PCH_LPT_I217_V: + case E1000_DEV_ID_PCH_LPTLP_I218_LM: + case E1000_DEV_ID_PCH_LPTLP_I218_V: + case E1000_DEV_ID_PCH_I218_V2: + case E1000_DEV_ID_PCH_I218_LM2: + case E1000_DEV_ID_PCH_I218_V3: + case E1000_DEV_ID_PCH_I218_LM3: + return 1; + default: + return 0; + } +} + static int eth_em_dev_init(struct rte_eth_dev *eth_dev) { @@ -232,6 +269,7 @@ eth_em_dev_init(struct rte_eth_dev *eth_dev) E1000_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private); pci_dev = eth_dev->pci_dev; + eth_dev->dev_ops = ð_em_ops; eth_dev->rx_pkt_burst = (eth_rx_burst_t)ð_em_recv_pkts; eth_dev->tx_pkt_burst = (eth_tx_burst_t)ð_em_xmit_pkts; @@ -246,11 +284,15 @@ eth_em_dev_init(struct rte_eth_dev *eth_dev) return 0; } + rte_eth_copy_pci_info(eth_dev, pci_dev); + hw->hw_addr = (void *)pci_dev->mem_resource[0].addr; hw->device_id = pci_dev->id.device_id; adapter->stopped = 0; /* For ICH8 support we'll need to map the flash memory BAR */ + if (eth_em_dev_is_ich8(hw)) + hw->flash_address = (void *)pci_dev->mem_resource[1].addr; if (e1000_setup_init_funcs(hw, TRUE) != E1000_SUCCESS || em_hw_init(hw) != 0) { @@ -258,7 +300,7 @@ eth_em_dev_init(struct rte_eth_dev *eth_dev) "failed to init HW", eth_dev->data->port_id, pci_dev->id.vendor_id, pci_dev->id.device_id); - return -(ENODEV); + return -ENODEV; } /* Allocate memory for storing MAC addresses */ @@ -268,7 +310,7 @@ eth_em_dev_init(struct rte_eth_dev *eth_dev) PMD_INIT_LOG(ERR, "Failed to allocate %d bytes needed to " "store MAC addresses", ETHER_ADDR_LEN * hw->mac.rar_entry_count); - return -(ENOMEM); + return -ENOMEM; } /* Copy the permanent MAC address */ @@ -278,14 +320,14 @@ eth_em_dev_init(struct rte_eth_dev *eth_dev) /* initialize the vfta */ memset(shadow_vfta, 0, sizeof(*shadow_vfta)); - PMD_INIT_LOG(INFO, "port_id %d vendorID=0x%x deviceID=0x%x", + PMD_INIT_LOG(DEBUG, "port_id %d vendorID=0x%x deviceID=0x%x", eth_dev->data->port_id, pci_dev->id.vendor_id, pci_dev->id.device_id); rte_intr_callback_register(&(pci_dev->intr_handle), eth_em_interrupt_handler, (void *)eth_dev); - return (0); + return 0; } static int @@ -417,11 +459,11 @@ em_hw_init(struct e1000_hw *hw) PMD_INIT_LOG(ERR, "PHY reset is blocked due to " "SOL/IDER session"); } - return (0); + return 0; error: em_hw_control_release(hw); - return (diag); + return diag; } static int @@ -434,7 +476,7 @@ eth_em_configure(struct rte_eth_dev *dev) intr->flags |= E1000_FLAG_NEED_LINK_UPDATE; PMD_INIT_FUNC_TRACE(); - return (0); + return 0; } static void @@ -476,6 +518,7 @@ em_set_pba(struct e1000_hw *hw) break; case e1000_pchlan: case e1000_pch2lan: + case e1000_pch_lpt: pba = E1000_PBA_26K; break; default: @@ -492,7 +535,9 @@ eth_em_start(struct rte_eth_dev *dev) E1000_DEV_PRIVATE(dev->data->dev_private); struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle; int ret, mask; + uint32_t intr_vector = 0; PMD_INIT_FUNC_TRACE(); @@ -520,7 +565,7 @@ eth_em_start(struct rte_eth_dev *dev) /* Initialize the hardware */ if (em_hardware_init(hw)) { PMD_INIT_LOG(ERR, "Unable to initialize the hardware"); - return (-EIO); + return -EIO; } E1000_WRITE_REG(hw, E1000_VET, ETHER_TYPE_VLAN); @@ -528,6 +573,26 @@ eth_em_start(struct rte_eth_dev *dev) /* Configure for OS presence */ em_init_manageability(hw); + if (dev->data->dev_conf.intr_conf.rxq != 0) { + intr_vector = dev->data->nb_rx_queues; + if (rte_intr_efd_enable(intr_handle, intr_vector)) + return -1; + } + + if (rte_intr_dp_is_en(intr_handle)) { + intr_handle->intr_vec = + rte_zmalloc("intr_vec", + dev->data->nb_rx_queues * sizeof(int), 0); + if (intr_handle->intr_vec == NULL) { + PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues" + " intr_vec\n", dev->data->nb_rx_queues); + return -ENOMEM; + } + + /* enable rx interrupt */ + em_rxq_intr_enable(hw); + } + eth_em_tx_init(dev); ret = eth_em_rx_init(dev); @@ -599,28 +664,42 @@ eth_em_start(struct rte_eth_dev *dev) } e1000_setup_link(hw); - /* check if lsc interrupt feature is enabled */ - if (dev->data->dev_conf.intr_conf.lsc != 0) { - ret = eth_em_interrupt_setup(dev); - if (ret) { - PMD_INIT_LOG(ERR, "Unable to setup interrupts"); - em_dev_clear_queues(dev); - return ret; + if (rte_intr_allow_others(intr_handle)) { + /* check if lsc interrupt is enabled */ + if (dev->data->dev_conf.intr_conf.lsc != 0) { + ret = eth_em_interrupt_setup(dev); + if (ret) { + PMD_INIT_LOG(ERR, "Unable to setup interrupts"); + em_dev_clear_queues(dev); + return ret; + } } + } else { + rte_intr_callback_unregister(intr_handle, + eth_em_interrupt_handler, + (void *)dev); + if (dev->data->dev_conf.intr_conf.lsc != 0) + PMD_INIT_LOG(INFO, "lsc won't enable because of" + " no intr multiplex\n"); } + /* check if rxq interrupt is enabled */ + if (dev->data->dev_conf.intr_conf.rxq != 0) + eth_em_rxq_interrupt_setup(dev); + + rte_intr_enable(intr_handle); adapter->stopped = 0; PMD_INIT_LOG(DEBUG, "<<"); - return (0); + return 0; error_invalid_config: PMD_INIT_LOG(ERR, "Invalid link_speed/link_duplex (%u/%u) for port %u", dev->data->dev_conf.link_speed, dev->data->dev_conf.link_duplex, dev->data->port_id); em_dev_clear_queues(dev); - return (-EINVAL); + return -EINVAL; } /********************************************************************* @@ -634,8 +713,11 @@ eth_em_stop(struct rte_eth_dev *dev) { struct rte_eth_link link; struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle; + + em_rxq_intr_disable(hw); + em_lsc_intr_disable(hw); - em_intr_disable(hw); e1000_reset_hw(hw); if (hw->mac.type >= e1000_82544) E1000_WRITE_REG(hw, E1000_WUC, 0); @@ -648,6 +730,19 @@ eth_em_stop(struct rte_eth_dev *dev) /* clear the recorded link status */ memset(&link, 0, sizeof(link)); rte_em_dev_atomic_write_link_status(dev, &link); + + if (!rte_intr_allow_others(intr_handle)) + /* resume to the default handler */ + rte_intr_callback_register(intr_handle, + eth_em_interrupt_handler, + (void *)dev); + + /* Clean datapath event and queue/vec mapping */ + rte_intr_efd_disable(intr_handle); + if (intr_handle->intr_vec != NULL) { + rte_free(intr_handle->intr_vec); + intr_handle->intr_vec = NULL; + } } static void @@ -659,6 +754,7 @@ eth_em_close(struct rte_eth_dev *dev) eth_em_stop(dev); adapter->stopped = 1; + em_dev_free_queues(dev); e1000_phy_hw_reset(hw); em_release_manageability(hw); em_hw_control_release(hw); @@ -732,13 +828,15 @@ em_hardware_init(struct e1000_hw *hw) hw->fc.low_water = 0x5048; hw->fc.pause_time = 0x0650; hw->fc.refresh_time = 0x0400; + } else if (hw->mac.type == e1000_pch_lpt) { + hw->fc.requested_mode = e1000_fc_full; } diag = e1000_init_hw(hw); if (diag < 0) - return (diag); + return diag; e1000_check_for_link(hw); - return (0); + return 0; } /* This function is based on em_update_stats_counters() in e1000/if_em.c */ @@ -845,12 +943,9 @@ eth_em_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) return; /* Rx Errors */ - rte_stats->ibadcrc = stats->crcerrs; - rte_stats->ibadlen = stats->rlec + stats->ruc + stats->roc; rte_stats->imissed = stats->mpc; - rte_stats->ierrors = rte_stats->ibadcrc + - rte_stats->ibadlen + - rte_stats->imissed + + rte_stats->ierrors = stats->crcerrs + + stats->rlec + stats->ruc + stats->roc + stats->rxerrc + stats->algnerrc + stats->cexterr; /* Tx Errors */ @@ -860,12 +955,6 @@ eth_em_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) rte_stats->opackets = stats->gptc; rte_stats->ibytes = stats->gorc; rte_stats->obytes = stats->gotc; - - /* XON/XOFF pause frames stats registers */ - 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; } static void @@ -881,6 +970,27 @@ eth_em_stats_reset(struct rte_eth_dev *dev) memset(hw_stats, 0, sizeof(*hw_stats)); } +static int +eth_em_rx_queue_intr_enable(struct rte_eth_dev *dev, __rte_unused uint16_t queue_id) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + em_rxq_intr_enable(hw); + rte_intr_enable(&dev->pci_dev->intr_handle); + + return 0; +} + +static int +eth_em_rx_queue_intr_disable(struct rte_eth_dev *dev, __rte_unused uint16_t queue_id) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + em_rxq_intr_disable(hw); + + return 0; +} + static uint32_t em_get_max_pktlen(const struct e1000_hw *hw) { @@ -890,17 +1000,18 @@ em_get_max_pktlen(const struct e1000_hw *hw) case e1000_ich9lan: case e1000_ich10lan: case e1000_pch2lan: + case e1000_pch_lpt: case e1000_82574: case e1000_80003es2lan: /* 9K Jumbo Frame size */ - return (0x2412); + case e1000_82583: + return 0x2412; case e1000_pchlan: - return (0x1000); + return 0x1000; /* Adapters that do not support jumbo frames */ - case e1000_82583: case e1000_ich8lan: - return (ETHER_MAX_LEN); + return ETHER_MAX_LEN; default: - return (MAX_JUMBO_FRAME_SIZE); + return MAX_JUMBO_FRAME_SIZE; } } @@ -932,6 +1043,18 @@ eth_em_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) dev_info->max_rx_queues = 1; dev_info->max_tx_queues = 1; + + dev_info->rx_desc_lim = (struct rte_eth_desc_lim) { + .nb_max = E1000_MAX_RING_DESC, + .nb_min = E1000_MIN_RING_DESC, + .nb_align = EM_RXD_ALIGN, + }; + + dev_info->tx_desc_lim = (struct rte_eth_desc_lim) { + .nb_max = E1000_MAX_RING_DESC, + .nb_min = E1000_MIN_RING_DESC, + .nb_align = EM_TXD_ALIGN, + }; } /* return 0 means link status changed, -1 means not changed */ @@ -1248,13 +1371,7 @@ eth_em_vlan_offload_set(struct rte_eth_dev *dev, int mask) } } -static void -em_intr_disable(struct e1000_hw *hw) -{ - E1000_WRITE_REG(hw, E1000_IMC, ~0); -} - -/** +/* * It enables the interrupt mask and then enable the interrupt. * * @param dev @@ -1267,12 +1384,80 @@ em_intr_disable(struct e1000_hw *hw) static int eth_em_interrupt_setup(struct rte_eth_dev *dev) { + uint32_t regval; struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - E1000_WRITE_REG(hw, E1000_IMS, E1000_ICR_LSC); - rte_intr_enable(&(dev->pci_dev->intr_handle)); - return (0); + /* clear interrupt */ + E1000_READ_REG(hw, E1000_ICR); + regval = E1000_READ_REG(hw, E1000_IMS); + E1000_WRITE_REG(hw, E1000_IMS, regval | E1000_ICR_LSC); + return 0; +} + +/* + * It clears the interrupt causes and enables the interrupt. + * It will be called once only during nic initialized. + * + * @param dev + * Pointer to struct rte_eth_dev. + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int +eth_em_rxq_interrupt_setup(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + E1000_READ_REG(hw, E1000_ICR); + em_rxq_intr_enable(hw); + return 0; +} + +/* + * It enable receive packet interrupt. + * @param hw + * Pointer to struct e1000_hw + * + * @return + */ +static void +em_rxq_intr_enable(struct e1000_hw *hw) +{ + E1000_WRITE_REG(hw, E1000_IMS, E1000_IMS_RXT0); + E1000_WRITE_FLUSH(hw); +} + +/* + * It disabled lsc interrupt. + * @param hw + * Pointer to struct e1000_hw + * + * @return + */ +static void +em_lsc_intr_disable(struct e1000_hw *hw) +{ + E1000_WRITE_REG(hw, E1000_IMC, E1000_IMS_LSC); + E1000_WRITE_FLUSH(hw); +} + +/* + * It disabled receive packet interrupt. + * @param hw + * Pointer to struct e1000_hw + * + * @return + */ +static void +em_rxq_intr_disable(struct e1000_hw *hw) +{ + E1000_READ_REG(hw, E1000_ICR); + E1000_WRITE_REG(hw, E1000_IMC, E1000_IMS_RXT0); + E1000_WRITE_FLUSH(hw); } /* @@ -1349,9 +1534,10 @@ eth_em_interrupt_action(struct rte_eth_dev *dev) } else { PMD_INIT_LOG(INFO, " Port %d: Link Down", dev->data->port_id); } - PMD_INIT_LOG(INFO, "PCI Address: %04d:%02d:%02d:%d", + PMD_INIT_LOG(DEBUG, "PCI Address: %04d:%02d:%02d:%d", dev->pci_dev->addr.domain, dev->pci_dev->addr.bus, dev->pci_dev->addr.devid, dev->pci_dev->addr.function); + tctl = E1000_READ_REG(hw, E1000_TCTL); rctl = E1000_READ_REG(hw, E1000_RCTL); if (link.link_status) { @@ -1398,7 +1584,7 @@ eth_em_led_on(struct rte_eth_dev *dev) struct e1000_hw *hw; hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - return (e1000_led_on(hw) == E1000_SUCCESS ? 0 : -ENOTSUP); + return e1000_led_on(hw) == E1000_SUCCESS ? 0 : -ENOTSUP; } static int @@ -1407,7 +1593,7 @@ eth_em_led_off(struct rte_eth_dev *dev) struct e1000_hw *hw; hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - return (e1000_led_off(hw) == E1000_SUCCESS ? 0 : -ENOTSUP); + return e1000_led_off(hw) == E1000_SUCCESS ? 0 : -ENOTSUP; } static int @@ -1479,7 +1665,7 @@ eth_em_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) (fc_conf->high_water < fc_conf->low_water)) { PMD_INIT_LOG(ERR, "e1000 incorrect high/low water value"); PMD_INIT_LOG(ERR, "high water must <= 0x%x", max_high_water); - return (-EINVAL); + return -EINVAL; } hw->fc.requested_mode = rte_fcmode_2_e1000_fcmode[fc_conf->mode]; @@ -1509,7 +1695,7 @@ eth_em_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) } PMD_INIT_LOG(ERR, "e1000_setup_link_generic = 0x%x", err); - return (-EIO); + return -EIO; } static void