/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2018-2019 Hisilicon Limited.
+ * Copyright(c) 2018-2021 HiSilicon Limited.
*/
#include <rte_alarm.h>
HNS3_VECTOR0_EVENT_RST,
HNS3_VECTOR0_EVENT_MBX,
HNS3_VECTOR0_EVENT_ERR,
+ HNS3_VECTOR0_EVENT_PTP,
HNS3_VECTOR0_EVENT_OTHER,
};
goto out;
}
+ /* Check for vector0 1588 event source */
+ if (BIT(HNS3_VECTOR0_1588_INT_B) & vector0_int_stats) {
+ val = BIT(HNS3_VECTOR0_1588_INT_B);
+ ret = HNS3_VECTOR0_EVENT_PTP;
+ goto out;
+ }
+
/* check for vector0 msix event source */
if (vector0_int_stats & HNS3_VECTOR0_REG_MSIX_MASK ||
hw_err_src_reg & HNS3_RAS_REG_NFE_MASK) {
return ret;
}
+static bool
+hns3_is_1588_event_type(uint32_t event_type)
+{
+ return (event_type == HNS3_VECTOR0_EVENT_PTP);
+}
+
static void
hns3_clear_event_cause(struct hns3_hw *hw, uint32_t event_type, uint32_t regclr)
{
- if (event_type == HNS3_VECTOR0_EVENT_RST)
+ if (event_type == HNS3_VECTOR0_EVENT_RST ||
+ hns3_is_1588_event_type(event_type))
hns3_write_dev(hw, HNS3_MISC_RESET_STS_REG, regclr);
else if (event_type == HNS3_VECTOR0_EVENT_MBX)
hns3_write_dev(hw, HNS3_VECTOR0_CMDQ_SRC_REG, regclr);
BIT(HNS3_VECTOR0_GLOBALRESET_INT_B) |
BIT(HNS3_VECTOR0_CORERESET_INT_B));
hns3_clear_event_cause(hw, HNS3_VECTOR0_EVENT_MBX, 0);
+ hns3_clear_event_cause(hw, HNS3_VECTOR0_EVENT_PTP,
+ BIT(HNS3_VECTOR0_1588_INT_B));
}
static void
{
struct hns3_hw *hw = &hns->hw;
uint16_t port_base_vlan_state;
- int ret;
+ int ret, err;
if (on == 0 && pvid != hw->port_base_vlan_cfg.pvid) {
if (hw->port_base_vlan_cfg.pvid != HNS3_INVALID_PVID)
if (ret) {
hns3_err(hw, "failed to config rx vlan strip for pvid, "
"ret = %d", ret);
- return ret;
+ goto pvid_vlan_strip_fail;
}
if (pvid == HNS3_INVALID_PVID)
if (ret) {
hns3_err(hw, "failed to update vlan filter entries, ret = %d",
ret);
- return ret;
+ goto vlan_filter_set_fail;
}
out:
hw->port_base_vlan_cfg.state = port_base_vlan_state;
hw->port_base_vlan_cfg.pvid = on ? pvid : HNS3_INVALID_PVID;
return ret;
+
+vlan_filter_set_fail:
+ err = hns3_en_pvid_strip(hns, hw->port_base_vlan_cfg.state ==
+ HNS3_PORT_BASE_VLAN_ENABLE);
+ if (err)
+ hns3_err(hw, "fail to rollback pvid strip, ret = %d", err);
+
+pvid_vlan_strip_fail:
+ err = hns3_vlan_txvlan_cfg(hns, hw->port_base_vlan_cfg.state,
+ hw->port_base_vlan_cfg.pvid);
+ if (err)
+ hns3_err(hw, "fail to rollback txvlan status, ret = %d", err);
+
+ return ret;
}
static int
return 0;
}
+static int
+hns3_refresh_mtu(struct rte_eth_dev *dev, struct rte_eth_conf *conf)
+{
+ struct hns3_adapter *hns = dev->data->dev_private;
+ struct hns3_hw *hw = &hns->hw;
+ uint32_t max_rx_pkt_len;
+ uint16_t mtu;
+ int ret;
+
+ if (!(conf->rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME))
+ return 0;
+
+ /*
+ * If jumbo frames are enabled, MTU needs to be refreshed
+ * according to the maximum RX packet length.
+ */
+ max_rx_pkt_len = conf->rxmode.max_rx_pkt_len;
+ if (max_rx_pkt_len > HNS3_MAX_FRAME_LEN ||
+ max_rx_pkt_len <= HNS3_DEFAULT_FRAME_LEN) {
+ hns3_err(hw, "maximum Rx packet length must be greater than %u "
+ "and no more than %u when jumbo frame enabled.",
+ (uint16_t)HNS3_DEFAULT_FRAME_LEN,
+ (uint16_t)HNS3_MAX_FRAME_LEN);
+ return -EINVAL;
+ }
+
+ mtu = (uint16_t)HNS3_PKTLEN_TO_MTU(max_rx_pkt_len);
+ ret = hns3_dev_mtu_set(dev, mtu);
+ if (ret)
+ return ret;
+ dev->data->mtu = mtu;
+
+ return 0;
+}
+
static int
hns3_dev_configure(struct rte_eth_dev *dev)
{
uint16_t nb_rx_q = dev->data->nb_rx_queues;
uint16_t nb_tx_q = dev->data->nb_tx_queues;
struct rte_eth_rss_conf rss_conf;
- uint32_t max_rx_pkt_len;
- uint16_t mtu;
bool gro_en;
int ret;
goto cfg_err;
}
- /*
- * If jumbo frames are enabled, MTU needs to be refreshed
- * according to the maximum RX packet length.
- */
- if (conf->rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME) {
- max_rx_pkt_len = conf->rxmode.max_rx_pkt_len;
- if (max_rx_pkt_len > HNS3_MAX_FRAME_LEN ||
- max_rx_pkt_len <= HNS3_DEFAULT_FRAME_LEN) {
- hns3_err(hw, "maximum Rx packet length must be greater "
- "than %u and less than %u when jumbo frame enabled.",
- (uint16_t)HNS3_DEFAULT_FRAME_LEN,
- (uint16_t)HNS3_MAX_FRAME_LEN);
- ret = -EINVAL;
- goto cfg_err;
- }
+ ret = hns3_refresh_mtu(dev, conf);
+ if (ret)
+ goto cfg_err;
- mtu = (uint16_t)HNS3_PKTLEN_TO_MTU(max_rx_pkt_len);
- ret = hns3_dev_mtu_set(dev, mtu);
- if (ret)
- goto cfg_err;
- dev->data->mtu = mtu;
- }
+ ret = hns3_mbuf_dyn_rx_timestamp_register(dev, conf);
+ if (ret)
+ goto cfg_err;
ret = hns3_dev_configure_vlan(dev);
if (ret)
info->dev_capa = RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
+ if (hns3_dev_ptp_supported(hw))
+ info->rx_offload_capa |= DEV_RX_OFFLOAD_TIMESTAMP;
+
info->rx_desc_lim = (struct rte_eth_desc_lim) {
.nb_max = HNS3_MAX_RING_DESC,
.nb_min = HNS3_MIN_RING_DESC,
}
static int
-hns3_dev_link_update(struct rte_eth_dev *eth_dev,
- __rte_unused int wait_to_complete)
+hns3_update_port_link_info(struct rte_eth_dev *eth_dev)
{
- struct hns3_adapter *hns = eth_dev->data->dev_private;
- struct hns3_hw *hw = &hns->hw;
- struct hns3_mac *mac = &hw->mac;
- struct rte_eth_link new_link;
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
+ int ret;
- if (!hns3_is_reset_pending(hns)) {
- hns3_update_link_status(hw);
- hns3_update_link_info(eth_dev);
- }
+ (void)hns3_update_link_status(hw);
+
+ ret = hns3_update_link_info(eth_dev);
+ if (ret)
+ hw->mac.link_status = ETH_LINK_DOWN;
+
+ return ret;
+}
+
+static void
+hns3_setup_linkstatus(struct rte_eth_dev *eth_dev,
+ struct rte_eth_link *new_link)
+{
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
+ struct hns3_mac *mac = &hw->mac;
- memset(&new_link, 0, sizeof(new_link));
switch (mac->link_speed) {
case ETH_SPEED_NUM_10M:
case ETH_SPEED_NUM_100M:
case ETH_SPEED_NUM_50G:
case ETH_SPEED_NUM_100G:
case ETH_SPEED_NUM_200G:
- new_link.link_speed = mac->link_speed;
+ new_link->link_speed = mac->link_speed;
break;
default:
- new_link.link_speed = ETH_SPEED_NUM_100M;
+ if (mac->link_status)
+ new_link->link_speed = ETH_SPEED_NUM_UNKNOWN;
+ else
+ new_link->link_speed = ETH_SPEED_NUM_NONE;
break;
}
- new_link.link_duplex = mac->link_duplex;
- new_link.link_status = mac->link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
- new_link.link_autoneg =
+ new_link->link_duplex = mac->link_duplex;
+ new_link->link_status = mac->link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
+ new_link->link_autoneg =
!(eth_dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED);
+}
+
+static int
+hns3_dev_link_update(struct rte_eth_dev *eth_dev, int wait_to_complete)
+{
+#define HNS3_LINK_CHECK_INTERVAL 100 /* 100ms */
+#define HNS3_MAX_LINK_CHECK_TIMES 20 /* 2s (100 * 20ms) in total */
+
+ struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
+ uint32_t retry_cnt = HNS3_MAX_LINK_CHECK_TIMES;
+ struct hns3_mac *mac = &hw->mac;
+ struct rte_eth_link new_link;
+ int ret;
+
+ do {
+ ret = hns3_update_port_link_info(eth_dev);
+ if (ret) {
+ hns3_err(hw, "failed to get port link info, ret = %d.",
+ ret);
+ break;
+ }
+
+ if (!wait_to_complete || mac->link_status == ETH_LINK_UP)
+ break;
+
+ rte_delay_ms(HNS3_LINK_CHECK_INTERVAL);
+ } while (retry_cnt--);
+
+ memset(&new_link, 0, sizeof(new_link));
+ hns3_setup_linkstatus(eth_dev, &new_link);
return rte_eth_linkstatus_set(eth_dev, &new_link);
}
hw->min_tx_pkt_len = HNS3_HIP08_MIN_TX_PKT_LEN;
pf->tqp_config_mode = HNS3_FIXED_MAX_TQP_NUM_MODE;
hw->rss_info.ipv6_sctp_offload_supported = false;
+ hw->udp_cksum_mode = HNS3_SPECIAL_PORT_SW_CKSUM_MODE;
return 0;
}
hw->min_tx_pkt_len = HNS3_HIP09_MIN_TX_PKT_LEN;
pf->tqp_config_mode = HNS3_FLEX_MAX_TQP_NUM_MODE;
hw->rss_info.ipv6_sctp_offload_supported = true;
+ hw->udp_cksum_mode = HNS3_SPECIAL_PORT_HW_CKSUM_MODE;
return 0;
}
}
static void
-hns3_parse_phy_params(struct hns3_cmd_desc *desc, struct hns3_mac *mac)
+hns3_parse_copper_phy_params(struct hns3_cmd_desc *desc, struct hns3_mac *mac)
{
struct hns3_phy_params_bd0_cmd *req;
}
static int
-hns3_get_phy_params(struct hns3_hw *hw, struct hns3_mac *mac)
+hns3_get_copper_phy_params(struct hns3_hw *hw, struct hns3_mac *mac)
{
struct hns3_cmd_desc desc[HNS3_PHY_PARAM_CFG_BD_NUM];
uint16_t i;
return ret;
}
- hns3_parse_phy_params(desc, mac);
+ hns3_parse_copper_phy_params(desc, mac);
return 0;
}
static int
-hns3_update_phy_link_info(struct hns3_hw *hw)
+hns3_update_copper_link_info(struct hns3_hw *hw)
{
struct hns3_mac *mac = &hw->mac;
struct hns3_mac mac_info;
int ret;
memset(&mac_info, 0, sizeof(struct hns3_mac));
- ret = hns3_get_phy_params(hw, &mac_info);
+ ret = hns3_get_copper_phy_params(hw, &mac_info);
if (ret)
return ret;
int ret = 0;
if (hw->mac.media_type == HNS3_MEDIA_TYPE_COPPER)
- ret = hns3_update_phy_link_info(hw);
+ ret = hns3_update_copper_link_info(hw);
else if (hw->mac.media_type == HNS3_MEDIA_TYPE_FIBER)
ret = hns3_update_fiber_link_info(hw);
return false;
}
-/*
- * Current, the PF driver get link status by two ways:
- * 1) Periodic polling in the intr thread context, driver call
- * hns3_update_link_status to update link status.
- * 2) Firmware report async interrupt, driver process the event in the intr
- * thread context, and call hns3_update_link_status to update link status.
- *
- * If detect link status changed, driver need report LSE. One method is add the
- * report LSE logic in hns3_update_link_status.
- *
- * But the PF driver ops(link_update) also call hns3_update_link_status to
- * update link status.
- * If we report LSE in hns3_update_link_status, it may lead to deadlock in the
- * bonding application.
- *
- * So add the one new API which used only in intr thread context.
- */
void
-hns3_update_link_status_and_event(struct hns3_hw *hw)
+hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query)
{
struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
- bool changed = hns3_update_link_status(hw);
- if (changed)
- rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
+ struct rte_eth_link new_link;
+ int ret;
+
+ if (query)
+ hns3_update_port_link_info(dev);
+
+ memset(&new_link, 0, sizeof(new_link));
+ hns3_setup_linkstatus(dev, &new_link);
+
+ ret = rte_eth_linkstatus_set(dev, &new_link);
+ if (ret == 0 && dev->data->dev_conf.intr_conf.lsc != 0)
+ hns3_start_report_lse(dev);
}
static void
struct hns3_adapter *hns = eth_dev->data->dev_private;
struct hns3_hw *hw = &hns->hw;
- if (!hns3_is_reset_pending(hns)) {
- hns3_update_link_status_and_event(hw);
- hns3_update_link_info(eth_dev);
- } else {
+ if (!hns3_is_reset_pending(hns))
+ hns3_update_linkstatus_and_event(hw, true);
+ else
hns3_warn(hw, "Cancel the query when reset is pending");
- }
rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, eth_dev);
}
+static void
+hns3_update_dev_lsc_cap(struct hns3_hw *hw,
+ int fw_compact_cmd_result)
+{
+ struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
+
+ if (hw->adapter_state != HNS3_NIC_UNINITIALIZED)
+ return;
+
+ if (fw_compact_cmd_result != 0) {
+ /*
+ * If fw_compact_cmd_result is not zero, it means firmware don't
+ * support link status change interrupt.
+ * Framework already set RTE_ETH_DEV_INTR_LSC bit because driver
+ * declared RTE_PCI_DRV_INTR_LSC in drv_flags. It need to clear
+ * the RTE_ETH_DEV_INTR_LSC capability when detect firmware
+ * don't support link status change interrupt.
+ */
+ dev->data->dev_flags &= ~RTE_ETH_DEV_INTR_LSC;
+ }
+}
+
static int
hns3_init_hardware(struct hns3_adapter *hns)
{
if (ret)
PMD_INIT_LOG(WARNING, "firmware compatible features not "
"supported, ret = %d.", ret);
+ hns3_update_dev_lsc_cap(hw, ret);
return 0;
goto err_intr_callback_register;
}
+ ret = hns3_ptp_init(hw);
+ if (ret)
+ goto err_get_config;
+
/* Enable interrupt */
rte_intr_enable(&pci_dev->intr_handle);
hns3_pf_enable_irq0(hw);
hns3_rx_scattered_calc(dev);
hns3_set_rxtx_function(dev);
hns3_mp_req_start_rxtx(dev);
- rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, dev);
hns3_restore_filter(dev);
hns3_tm_dev_start_proc(hw);
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
+ hns3_dev_link_update(dev, 0);
+ rte_eal_alarm_set(HNS3_SERVICE_INTERVAL, hns3_service_handler, dev);
+
hns3_info(hw, "hns3 dev start successful!");
return 0;
}
hns3_rx_scattered_reset(dev);
rte_eal_alarm_cancel(hns3_service_handler, dev);
+ hns3_stop_report_lse(dev);
rte_spinlock_unlock(&hw->lock);
return 0;
return -EOPNOTSUPP;
}
+ if (hw->num_tc > 1) {
+ hns3_err(hw, "in multi-TC scenarios, MAC pause is not supported.");
+ return -EOPNOTSUPP;
+ }
+
hns3_get_fc_mode(hw, fc_conf->mode);
if (hw->requested_mode == hw->current_mode &&
pf->pause_time == fc_conf->pause_time)
struct rte_eth_dev *eth_dev;
eth_dev = &rte_eth_devices[hw->data->port_id];
+ hw->mac.link_status = ETH_LINK_DOWN;
if (hw->adapter_state == HNS3_NIC_STARTED) {
rte_eal_alarm_cancel(hns3_service_handler, eth_dev);
- hns3_update_link_status_and_event(hw);
+ hns3_update_linkstatus_and_event(hw, false);
}
- hw->mac.link_status = ETH_LINK_DOWN;
hns3_set_rxtx_function(eth_dev);
rte_wmb();
if (ret)
goto err_promisc;
+ ret = hns3_restore_ptp(hns);
+ if (ret)
+ goto err_promisc;
+
ret = hns3_restore_rx_interrupt(hw);
if (ret)
goto err_promisc;
.rss_hash_conf_get = hns3_dev_rss_hash_conf_get,
.reta_update = hns3_dev_rss_reta_update,
.reta_query = hns3_dev_rss_reta_query,
- .filter_ctrl = hns3_dev_filter_ctrl,
+ .flow_ops_get = hns3_dev_flow_ops_get,
.vlan_filter_set = hns3_vlan_filter_set,
.vlan_tpid_set = hns3_vlan_tpid_set,
.vlan_offload_set = hns3_vlan_offload_set,
.fec_set = hns3_fec_set,
.tm_ops_get = hns3_tm_ops_get,
.tx_done_cleanup = hns3_tx_done_cleanup,
+ .timesync_enable = hns3_timesync_enable,
+ .timesync_disable = hns3_timesync_disable,
+ .timesync_read_rx_timestamp = hns3_timesync_read_rx_timestamp,
+ .timesync_read_tx_timestamp = hns3_timesync_read_tx_timestamp,
+ .timesync_adjust_time = hns3_timesync_adjust_time,
+ .timesync_read_time = hns3_timesync_read_time,
+ .timesync_write_time = hns3_timesync_write_time,
};
static const struct hns3_reset_ops hns3_reset_ops = {
err_mp_init_secondary:
eth_dev->dev_ops = NULL;
eth_dev->rx_pkt_burst = NULL;
+ eth_dev->rx_descriptor_status = NULL;
eth_dev->tx_pkt_burst = NULL;
eth_dev->tx_pkt_prepare = NULL;
eth_dev->tx_descriptor_status = NULL;
static struct rte_pci_driver rte_hns3_pmd = {
.id_table = pci_id_hns3_map,
- .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
.probe = eth_hns3_pci_probe,
.remove = eth_hns3_pci_remove,
};