X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fatlantic%2Fatl_ethdev.c;h=8327863cd9b6c53b2d70ed6e61cfd5a9dd58cf25;hb=6723c0fc7207ca4416822b170b1485a78aa47c7c;hp=2f365844752cdfad1260e1add3848884cef2c5b0;hpb=3af0d308541a5c32fb03a97d60c872264554a103;p=dpdk.git diff --git a/drivers/net/atlantic/atl_ethdev.c b/drivers/net/atlantic/atl_ethdev.c index 2f36584475..8327863cd9 100644 --- a/drivers/net/atlantic/atl_ethdev.c +++ b/drivers/net/atlantic/atl_ethdev.c @@ -2,6 +2,7 @@ * Copyright(c) 2018 Aquantia Corporation */ +#include #include #include "atl_ethdev.h" @@ -48,6 +49,37 @@ static void atl_dev_info_get(struct rte_eth_dev *dev, static const uint32_t *atl_dev_supported_ptypes_get(struct rte_eth_dev *dev); +static int atl_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu); + +/* VLAN stuff */ +static int atl_vlan_filter_set(struct rte_eth_dev *dev, + uint16_t vlan_id, int on); + +static int atl_vlan_offload_set(struct rte_eth_dev *dev, int mask); + +static void atl_vlan_strip_queue_set(struct rte_eth_dev *dev, + uint16_t queue_id, int on); + +static int atl_vlan_tpid_set(struct rte_eth_dev *dev, + enum rte_vlan_type vlan_type, uint16_t tpid); + +/* EEPROM */ +static int atl_dev_get_eeprom_length(struct rte_eth_dev *dev); +static int atl_dev_get_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *eeprom); +static int atl_dev_set_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *eeprom); + +/* Regs */ +static int atl_dev_get_regs(struct rte_eth_dev *dev, + struct rte_dev_reg_info *regs); + +/* Flow control */ +static int atl_flow_ctrl_get(struct rte_eth_dev *dev, + struct rte_eth_fc_conf *fc_conf); +static int atl_flow_ctrl_set(struct rte_eth_dev *dev, + struct rte_eth_fc_conf *fc_conf); + static void atl_dev_link_status_print(struct rte_eth_dev *dev); /* Interrupts */ @@ -58,6 +90,18 @@ static int atl_dev_interrupt_action(struct rte_eth_dev *dev, struct rte_intr_handle *handle); static void atl_dev_interrupt_handler(void *param); + +static int atl_add_mac_addr(struct rte_eth_dev *dev, + struct ether_addr *mac_addr, + uint32_t index, uint32_t pool); +static void atl_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index); +static int atl_set_default_mac_addr(struct rte_eth_dev *dev, + struct ether_addr *mac_addr); + +static int atl_dev_set_mc_addr_list(struct rte_eth_dev *dev, + struct ether_addr *mc_addr_set, + uint32_t nb_mc_addr); + /* RSS */ static int atl_reta_update(struct rte_eth_dev *dev, struct rte_eth_rss_reta_entry64 *reta_conf, @@ -122,7 +166,8 @@ static struct rte_pci_driver rte_atl_pmd = { | DEV_RX_OFFLOAD_IPV4_CKSUM \ | DEV_RX_OFFLOAD_UDP_CKSUM \ | DEV_RX_OFFLOAD_TCP_CKSUM \ - | DEV_RX_OFFLOAD_JUMBO_FRAME) + | DEV_RX_OFFLOAD_JUMBO_FRAME \ + | DEV_RX_OFFLOAD_VLAN_FILTER) #define ATL_TX_OFFLOADS (DEV_TX_OFFLOAD_VLAN_INSERT \ | DEV_TX_OFFLOAD_IPV4_CKSUM \ @@ -190,6 +235,8 @@ static const struct eth_dev_ops atl_eth_dev_ops = { /* Link */ .link_update = atl_dev_link_update, + .get_reg = atl_dev_get_regs, + /* Stats */ .stats_get = atl_dev_stats_get, .xstats_get = atl_dev_xstats_get, @@ -201,6 +248,14 @@ static const struct eth_dev_ops atl_eth_dev_ops = { .dev_infos_get = atl_dev_info_get, .dev_supported_ptypes_get = atl_dev_supported_ptypes_get, + .mtu_set = atl_dev_mtu_set, + + /* VLAN */ + .vlan_filter_set = atl_vlan_filter_set, + .vlan_offload_set = atl_vlan_offload_set, + .vlan_tpid_set = atl_vlan_tpid_set, + .vlan_strip_queue_set = atl_vlan_strip_queue_set, + /* Queue Control */ .rx_queue_start = atl_rx_queue_start, .rx_queue_stop = atl_rx_queue_stop, @@ -219,6 +274,20 @@ static const struct eth_dev_ops atl_eth_dev_ops = { .rx_descriptor_status = atl_dev_rx_descriptor_status, .tx_descriptor_status = atl_dev_tx_descriptor_status, + /* EEPROM */ + .get_eeprom_length = atl_dev_get_eeprom_length, + .get_eeprom = atl_dev_get_eeprom, + .set_eeprom = atl_dev_set_eeprom, + + /* Flow Control */ + .flow_ctrl_get = atl_flow_ctrl_get, + .flow_ctrl_set = atl_flow_ctrl_set, + + /* MAC */ + .mac_addr_add = atl_add_mac_addr, + .mac_addr_remove = atl_remove_mac_addr, + .mac_addr_set = atl_set_default_mac_addr, + .set_mc_addr_list = atl_dev_set_mc_addr_list, .rxq_info_get = atl_rxq_info_get, .txq_info_get = atl_txq_info_get, @@ -287,6 +356,7 @@ eth_atl_dev_init(struct rte_eth_dev *eth_dev) AQ_NIC_RATE_1G | AQ_NIC_RATE_100M; + adapter->hw_cfg.flow_control = (AQ_NIC_FC_RX | AQ_NIC_FC_TX); adapter->hw_cfg.aq_rss.indirection_table_size = HW_ATL_B0_RSS_REDIRECTION_MAX; @@ -397,8 +467,6 @@ atl_dev_start(struct rte_eth_dev *dev) struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); struct rte_intr_handle *intr_handle = &pci_dev->intr_handle; uint32_t intr_vector = 0; - uint32_t *link_speeds; - uint32_t speed = 0; int status; int err; @@ -475,6 +543,8 @@ atl_dev_start(struct rte_eth_dev *dev) goto error; } + err = atl_dev_set_link_up(dev); + err = hw->aq_fw_ops->update_link_status(hw); if (err) @@ -482,26 +552,6 @@ atl_dev_start(struct rte_eth_dev *dev) dev->data->dev_link.link_status = hw->aq_link_status.mbps != 0; - link_speeds = &dev->data->dev_conf.link_speeds; - - speed = 0x0; - - if (*link_speeds == ETH_LINK_SPEED_AUTONEG) { - speed = hw->aq_nic_cfg->link_speed_msk; - } else { - if (*link_speeds & ETH_LINK_SPEED_10G) - speed |= AQ_NIC_RATE_10G; - if (*link_speeds & ETH_LINK_SPEED_5G) - speed |= AQ_NIC_RATE_5G; - if (*link_speeds & ETH_LINK_SPEED_1G) - speed |= AQ_NIC_RATE_1G; - if (*link_speeds & ETH_LINK_SPEED_2_5G) - speed |= AQ_NIC_RATE_2G5; - if (*link_speeds & ETH_LINK_SPEED_100M) - speed |= AQ_NIC_RATE_100M; - } - - err = hw->aq_fw_ops->set_link_speed(hw, speed); if (err) goto error; @@ -589,9 +639,25 @@ static int atl_dev_set_link_up(struct rte_eth_dev *dev) { struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t link_speeds = dev->data->dev_conf.link_speeds; + uint32_t speed_mask = 0; + + if (link_speeds == ETH_LINK_SPEED_AUTONEG) { + speed_mask = hw->aq_nic_cfg->link_speed_msk; + } else { + if (link_speeds & ETH_LINK_SPEED_10G) + speed_mask |= AQ_NIC_RATE_10G; + if (link_speeds & ETH_LINK_SPEED_5G) + speed_mask |= AQ_NIC_RATE_5G; + if (link_speeds & ETH_LINK_SPEED_1G) + speed_mask |= AQ_NIC_RATE_1G; + if (link_speeds & ETH_LINK_SPEED_2_5G) + speed_mask |= AQ_NIC_RATE_2G5; + if (link_speeds & ETH_LINK_SPEED_100M) + speed_mask |= AQ_NIC_RATE_100M; + } - return hw->aq_fw_ops->set_link_speed(hw, - hw->aq_nic_cfg->link_speed_msk); + return hw->aq_fw_ops->set_link_speed(hw, speed_mask); } /* @@ -690,10 +756,10 @@ atl_dev_xstats_get_names(struct rte_eth_dev *dev __rte_unused, return RTE_DIM(atl_xstats_tbl); for (i = 0; i < size && i < RTE_DIM(atl_xstats_tbl); i++) - snprintf(xstats_names[i].name, RTE_ETH_XSTATS_NAME_SIZE, "%s", - atl_xstats_tbl[i].name); + strlcpy(xstats_names[i].name, atl_xstats_tbl[i].name, + RTE_ETH_XSTATS_NAME_SIZE); - return size; + return i; } static int @@ -713,7 +779,7 @@ atl_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *stats, atl_xstats_tbl[i].offset); } - return n; + return i; } static int @@ -1026,6 +1092,367 @@ atl_dev_interrupt_handler(void *param) atl_dev_interrupt_action(dev, dev->intr_handle); } +#define SFP_EEPROM_SIZE 0xff + +static int +atl_dev_get_eeprom_length(struct rte_eth_dev *dev __rte_unused) +{ + return SFP_EEPROM_SIZE; +} + +int atl_dev_get_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *eeprom) +{ + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t dev_addr = SMBUS_DEVICE_ID; + + if (hw->aq_fw_ops->get_eeprom == NULL) + return -ENOTSUP; + + if (eeprom->length + eeprom->offset > SFP_EEPROM_SIZE || + eeprom->data == NULL) + return -EINVAL; + + if (eeprom->magic) + dev_addr = eeprom->magic; + + return hw->aq_fw_ops->get_eeprom(hw, dev_addr, eeprom->data, + eeprom->length, eeprom->offset); +} + +int atl_dev_set_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *eeprom) +{ + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t dev_addr = SMBUS_DEVICE_ID; + + if (hw->aq_fw_ops->set_eeprom == NULL) + return -ENOTSUP; + + if (eeprom->length != SFP_EEPROM_SIZE || eeprom->data == NULL) + return -EINVAL; + + if (eeprom->magic) + dev_addr = eeprom->magic; + + return hw->aq_fw_ops->set_eeprom(hw, dev_addr, + eeprom->data, eeprom->length); +} + +static int +atl_dev_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs) +{ + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + u32 mif_id; + int err; + + if (regs->data == NULL) { + regs->length = hw_atl_utils_hw_get_reg_length(); + regs->width = sizeof(u32); + return 0; + } + + /* Only full register dump is supported */ + if (regs->length && regs->length != hw_atl_utils_hw_get_reg_length()) + return -ENOTSUP; + + err = hw_atl_utils_hw_get_regs(hw, regs->data); + + /* Device version */ + mif_id = hw_atl_reg_glb_mif_id_get(hw); + regs->version = mif_id & 0xFFU; + + return err; +} + +static int +atl_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + if (hw->aq_nic_cfg->flow_control == AQ_NIC_FC_OFF) + fc_conf->mode = RTE_FC_NONE; + else if (hw->aq_nic_cfg->flow_control & (AQ_NIC_FC_RX | AQ_NIC_FC_TX)) + fc_conf->mode = RTE_FC_FULL; + else if (hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX) + fc_conf->mode = RTE_FC_RX_PAUSE; + else if (hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX) + fc_conf->mode = RTE_FC_TX_PAUSE; + + return 0; +} + +static int +atl_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t old_flow_control = hw->aq_nic_cfg->flow_control; + + + if (hw->aq_fw_ops->set_flow_control == NULL) + return -ENOTSUP; + + if (fc_conf->mode == RTE_FC_NONE) + hw->aq_nic_cfg->flow_control = AQ_NIC_FC_OFF; + else if (fc_conf->mode == RTE_FC_RX_PAUSE) + hw->aq_nic_cfg->flow_control = AQ_NIC_FC_RX; + else if (fc_conf->mode == RTE_FC_TX_PAUSE) + hw->aq_nic_cfg->flow_control = AQ_NIC_FC_TX; + else if (fc_conf->mode == RTE_FC_FULL) + hw->aq_nic_cfg->flow_control = (AQ_NIC_FC_RX | AQ_NIC_FC_TX); + + if (old_flow_control != hw->aq_nic_cfg->flow_control) + return hw->aq_fw_ops->set_flow_control(hw); + + return 0; +} + +static int +atl_update_mac_addr(struct rte_eth_dev *dev, uint32_t index, + u8 *mac_addr, bool enable) +{ + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + unsigned int h = 0U; + unsigned int l = 0U; + int err; + + if (mac_addr) { + h = (mac_addr[0] << 8) | (mac_addr[1]); + l = (mac_addr[2] << 24) | (mac_addr[3] << 16) | + (mac_addr[4] << 8) | mac_addr[5]; + } + + hw_atl_rpfl2_uc_flr_en_set(hw, 0U, index); + hw_atl_rpfl2unicast_dest_addresslsw_set(hw, l, index); + hw_atl_rpfl2unicast_dest_addressmsw_set(hw, h, index); + + if (enable) + hw_atl_rpfl2_uc_flr_en_set(hw, 1U, index); + + err = aq_hw_err_from_flags(hw); + + return err; +} + +static int +atl_add_mac_addr(struct rte_eth_dev *dev, struct ether_addr *mac_addr, + uint32_t index __rte_unused, uint32_t pool __rte_unused) +{ + if (is_zero_ether_addr(mac_addr)) { + PMD_DRV_LOG(ERR, "Invalid Ethernet Address"); + return -EINVAL; + } + + return atl_update_mac_addr(dev, index, (u8 *)mac_addr, true); +} + +static void +atl_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index) +{ + atl_update_mac_addr(dev, index, NULL, false); +} + +static int +atl_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr) +{ + atl_remove_mac_addr(dev, 0); + atl_add_mac_addr(dev, addr, 0, 0); + return 0; +} + +static int +atl_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) +{ + struct rte_eth_dev_info dev_info; + uint32_t frame_size = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + + atl_dev_info_get(dev, &dev_info); + + if ((mtu < ETHER_MIN_MTU) || (frame_size > dev_info.max_rx_pktlen)) + return -EINVAL; + + /* update max frame size */ + dev->data->dev_conf.rxmode.max_rx_pkt_len = frame_size; + + return 0; +} + +static int +atl_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) +{ + struct aq_hw_cfg_s *cfg = + ATL_DEV_PRIVATE_TO_CFG(dev->data->dev_private); + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int err = 0; + int i = 0; + + PMD_INIT_FUNC_TRACE(); + + for (i = 0; i < HW_ATL_B0_MAX_VLAN_IDS; i++) { + if (cfg->vlan_filter[i] == vlan_id) { + if (!on) { + /* Disable VLAN filter. */ + hw_atl_rpf_vlan_flr_en_set(hw, 0U, i); + + /* Clear VLAN filter entry */ + cfg->vlan_filter[i] = 0; + } + break; + } + } + + /* VLAN_ID was not found. So, nothing to delete. */ + if (i == HW_ATL_B0_MAX_VLAN_IDS && !on) + goto exit; + + /* VLAN_ID already exist, or already removed above. Nothing to do. */ + if (i != HW_ATL_B0_MAX_VLAN_IDS) + goto exit; + + /* Try to found free VLAN filter to add new VLAN_ID */ + for (i = 0; i < HW_ATL_B0_MAX_VLAN_IDS; i++) { + if (cfg->vlan_filter[i] == 0) + break; + } + + if (i == HW_ATL_B0_MAX_VLAN_IDS) { + /* We have no free VLAN filter to add new VLAN_ID*/ + err = -ENOMEM; + goto exit; + } + + cfg->vlan_filter[i] = vlan_id; + hw_atl_rpf_vlan_flr_act_set(hw, 1U, i); + hw_atl_rpf_vlan_id_flr_set(hw, vlan_id, i); + hw_atl_rpf_vlan_flr_en_set(hw, 1U, i); + +exit: + /* Enable VLAN promisc mode if vlan_filter empty */ + for (i = 0; i < HW_ATL_B0_MAX_VLAN_IDS; i++) { + if (cfg->vlan_filter[i] != 0) + break; + } + + hw_atl_rpf_vlan_prom_mode_en_set(hw, i == HW_ATL_B0_MAX_VLAN_IDS); + + return err; +} + +static int +atl_enable_vlan_filter(struct rte_eth_dev *dev, int en) +{ + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct aq_hw_cfg_s *cfg = + ATL_DEV_PRIVATE_TO_CFG(dev->data->dev_private); + int i; + + PMD_INIT_FUNC_TRACE(); + + for (i = 0; i < HW_ATL_B0_MAX_VLAN_IDS; i++) { + if (cfg->vlan_filter[i]) + hw_atl_rpf_vlan_flr_en_set(hw, en, i); + } + return 0; +} + +static int +atl_vlan_offload_set(struct rte_eth_dev *dev, int mask) +{ + struct aq_hw_cfg_s *cfg = + ATL_DEV_PRIVATE_TO_CFG(dev->data->dev_private); + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int ret = 0; + int i; + + PMD_INIT_FUNC_TRACE(); + + ret = atl_enable_vlan_filter(dev, mask & ETH_VLAN_FILTER_MASK); + + cfg->vlan_strip = !!(mask & ETH_VLAN_STRIP_MASK); + + for (i = 0; i < dev->data->nb_rx_queues; i++) + hw_atl_rpo_rx_desc_vlan_stripping_set(hw, cfg->vlan_strip, i); + + if (mask & ETH_VLAN_EXTEND_MASK) + ret = -ENOTSUP; + + return ret; +} + +static int +atl_vlan_tpid_set(struct rte_eth_dev *dev, enum rte_vlan_type vlan_type, + uint16_t tpid) +{ + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int err = 0; + + PMD_INIT_FUNC_TRACE(); + + switch (vlan_type) { + case ETH_VLAN_TYPE_INNER: + hw_atl_rpf_vlan_inner_etht_set(hw, tpid); + break; + case ETH_VLAN_TYPE_OUTER: + hw_atl_rpf_vlan_outer_etht_set(hw, tpid); + break; + default: + PMD_DRV_LOG(ERR, "Unsupported VLAN type"); + err = -ENOTSUP; + } + + return err; +} + +static void +atl_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue_id, int on) +{ + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + + if (queue_id > dev->data->nb_rx_queues) { + PMD_DRV_LOG(ERR, "Invalid queue id"); + return; + } + + hw_atl_rpo_rx_desc_vlan_stripping_set(hw, on, queue_id); +} + +static int +atl_dev_set_mc_addr_list(struct rte_eth_dev *dev, + struct ether_addr *mc_addr_set, + uint32_t nb_mc_addr) +{ + struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private); + u32 i; + + if (nb_mc_addr > AQ_HW_MULTICAST_ADDRESS_MAX - HW_ATL_B0_MAC_MIN) + return -EINVAL; + + /* Update whole uc filters table */ + for (i = 0; i < AQ_HW_MULTICAST_ADDRESS_MAX - HW_ATL_B0_MAC_MIN; i++) { + u8 *mac_addr = NULL; + u32 l = 0, h = 0; + + if (i < nb_mc_addr) { + mac_addr = mc_addr_set[i].addr_bytes; + l = (mac_addr[2] << 24) | (mac_addr[3] << 16) | + (mac_addr[4] << 8) | mac_addr[5]; + h = (mac_addr[0] << 8) | mac_addr[1]; + } + + hw_atl_rpfl2_uc_flr_en_set(hw, 0U, HW_ATL_B0_MAC_MIN + i); + hw_atl_rpfl2unicast_dest_addresslsw_set(hw, l, + HW_ATL_B0_MAC_MIN + i); + hw_atl_rpfl2unicast_dest_addressmsw_set(hw, h, + HW_ATL_B0_MAC_MIN + i); + hw_atl_rpfl2_uc_flr_en_set(hw, !!mac_addr, + HW_ATL_B0_MAC_MIN + i); + } + + return 0; +} + static int atl_reta_update(struct rte_eth_dev *dev, struct rte_eth_rss_reta_entry64 *reta_conf,