From 56ea46a997b7cdc1bc2134f406d467c47e463bb3 Mon Sep 17 00:00:00 2001 From: Zijie Pan Date: Tue, 17 Jun 2014 20:09:26 +0200 Subject: [PATCH] ethdev: retrieve flow control configuration This patch adds a new function in ethdev api to retrieve current flow control configuration. This operation has been implemented for rte_em_pmd, rte_igb_pmd and rte_ixgbe_pmd. Signed-off-by: Zijie Pan Signed-off-by: David Marchand Acked-by: Konstantin Ananyev --- lib/librte_ether/rte_ethdev.c | 16 +++++++++ lib/librte_ether/rte_ethdev.h | 24 +++++++++++-- lib/librte_pmd_e1000/em_ethdev.c | 44 +++++++++++++++++++++++ lib/librte_pmd_e1000/igb_ethdev.c | 44 +++++++++++++++++++++++ lib/librte_pmd_ixgbe/ixgbe_ethdev.c | 55 +++++++++++++++++++++++++++-- 5 files changed, 179 insertions(+), 4 deletions(-) diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index 66eb2660ed..9b9d5f66c5 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -1636,6 +1636,22 @@ rte_eth_dev_fdir_set_masks(uint8_t port_id, struct rte_fdir_masks *fdir_mask) return (*dev->dev_ops->fdir_set_masks)(dev, fdir_mask); } +int +rte_eth_dev_flow_ctrl_get(uint8_t port_id, struct rte_eth_fc_conf *fc_conf) +{ + struct rte_eth_dev *dev; + + if (port_id >= nb_ports) { + PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); + return (-ENODEV); + } + + dev = &rte_eth_devices[port_id]; + FUNC_PTR_OR_ERR_RET(*dev->dev_ops->flow_ctrl_get, -ENOTSUP); + memset(fc_conf, 0, sizeof(*fc_conf)); + return (*dev->dev_ops->flow_ctrl_get)(dev, fc_conf); +} + int rte_eth_dev_flow_ctrl_set(uint8_t port_id, struct rte_eth_fc_conf *fc_conf) { diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h index 1dd1d39251..1e0564d3e0 100644 --- a/lib/librte_ether/rte_ethdev.h +++ b/lib/librte_ether/rte_ethdev.h @@ -1140,8 +1140,12 @@ typedef int (*fdir_set_masks_t)(struct rte_eth_dev *dev, struct rte_fdir_masks *fdir_masks); /**< @internal Setup flow director masks on an Ethernet device */ +typedef int (*flow_ctrl_get_t)(struct rte_eth_dev *dev, + struct rte_eth_fc_conf *fc_conf); +/**< @internal Get current flow control parameter on an Ethernet device */ + typedef int (*flow_ctrl_set_t)(struct rte_eth_dev *dev, - struct rte_eth_fc_conf *fc_conf); + struct rte_eth_fc_conf *fc_conf); /**< @internal Setup flow control parameter on an Ethernet device */ typedef int (*priority_flow_ctrl_set_t)(struct rte_eth_dev *dev, @@ -1389,6 +1393,7 @@ struct eth_dev_ops { eth_queue_release_t tx_queue_release;/**< Release TX queue.*/ eth_dev_led_on_t dev_led_on; /**< Turn on LED. */ eth_dev_led_off_t dev_led_off; /**< Turn off LED. */ + flow_ctrl_get_t flow_ctrl_get; /**< Get flow control. */ flow_ctrl_set_t flow_ctrl_set; /**< Setup flow control. */ priority_flow_ctrl_set_t priority_flow_ctrl_set; /**< Setup priority flow control.*/ eth_mac_addr_remove_t mac_addr_remove; /**< Remove MAC address */ @@ -2700,6 +2705,21 @@ int rte_eth_led_on(uint8_t port_id); */ int rte_eth_led_off(uint8_t port_id); +/** + * Get current status of the Ethernet link flow control for Ethernet device + * + * @param port_id + * The port identifier of the Ethernet device. + * @param fc_conf + * The pointer to the structure where to store the flow control parameters. + * @return + * - (0) if successful. + * - (-ENOTSUP) if hardware doesn't support flow control. + * - (-ENODEV) if *port_id* invalid. + */ +int rte_eth_dev_flow_ctrl_get(uint8_t port_id, + struct rte_eth_fc_conf *fc_conf); + /** * Configure the Ethernet link flow control for Ethernet device * @@ -2715,7 +2735,7 @@ int rte_eth_led_off(uint8_t port_id); * - (-EIO) if flow control setup failure */ int rte_eth_dev_flow_ctrl_set(uint8_t port_id, - struct rte_eth_fc_conf *fc_conf); + struct rte_eth_fc_conf *fc_conf); /** * Configure the Ethernet priority flow control under DCB environment diff --git a/lib/librte_pmd_e1000/em_ethdev.c b/lib/librte_pmd_e1000/em_ethdev.c index dc0082f3cd..58efcdf7e0 100644 --- a/lib/librte_pmd_e1000/em_ethdev.c +++ b/lib/librte_pmd_e1000/em_ethdev.c @@ -77,6 +77,8 @@ static void eth_em_stats_get(struct rte_eth_dev *dev, static void eth_em_stats_reset(struct rte_eth_dev *dev); static void eth_em_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info); +static int eth_em_flow_ctrl_get(struct rte_eth_dev *dev, + struct rte_eth_fc_conf *fc_conf); 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); @@ -153,6 +155,7 @@ static struct eth_dev_ops eth_em_ops = { .tx_queue_release = eth_em_tx_queue_release, .dev_led_on = eth_em_led_on, .dev_led_off = eth_em_led_off, + .flow_ctrl_get = eth_em_flow_ctrl_get, .flow_ctrl_set = eth_em_flow_ctrl_set, .mac_addr_add = eth_em_rar_set, .mac_addr_remove = eth_em_rar_clear, @@ -1362,6 +1365,47 @@ eth_em_led_off(struct rte_eth_dev *dev) return (e1000_led_off(hw) == E1000_SUCCESS ? 0 : -ENOTSUP); } +static int +eth_em_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + struct e1000_hw *hw; + uint32_t ctrl; + int tx_pause; + int rx_pause; + + hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + fc_conf->pause_time = hw->fc.pause_time; + fc_conf->high_water = hw->fc.high_water; + fc_conf->low_water = hw->fc.low_water; + fc_conf->send_xon = hw->fc.send_xon; + + /* + * Return rx_pause and tx_pause status according to actual setting of + * the TFCE and RFCE bits in the CTRL register. + */ + ctrl = E1000_READ_REG(hw, E1000_CTRL); + if (ctrl & E1000_CTRL_TFCE) + tx_pause = 1; + else + tx_pause = 0; + + if (ctrl & E1000_CTRL_RFCE) + rx_pause = 1; + else + rx_pause = 0; + + if (rx_pause && tx_pause) + fc_conf->mode = RTE_FC_FULL; + else if (rx_pause) + fc_conf->mode = RTE_FC_RX_PAUSE; + else if (tx_pause) + fc_conf->mode = RTE_FC_TX_PAUSE; + else + fc_conf->mode = RTE_FC_NONE; + + return 0; +} + static int eth_em_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) { diff --git a/lib/librte_pmd_e1000/igb_ethdev.c b/lib/librte_pmd_e1000/igb_ethdev.c index ae7e03b9e5..92ac4a83c7 100644 --- a/lib/librte_pmd_e1000/igb_ethdev.c +++ b/lib/librte_pmd_e1000/igb_ethdev.c @@ -72,6 +72,8 @@ static void eth_igb_stats_get(struct rte_eth_dev *dev, static void eth_igb_stats_reset(struct rte_eth_dev *dev); static void eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info); +static int eth_igb_flow_ctrl_get(struct rte_eth_dev *dev, + struct rte_eth_fc_conf *fc_conf); static int eth_igb_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf); static int eth_igb_lsc_interrupt_setup(struct rte_eth_dev *dev); @@ -227,6 +229,7 @@ static struct eth_dev_ops eth_igb_ops = { .tx_queue_release = eth_igb_tx_queue_release, .dev_led_on = eth_igb_led_on, .dev_led_off = eth_igb_led_off, + .flow_ctrl_get = eth_igb_flow_ctrl_get, .flow_ctrl_set = eth_igb_flow_ctrl_set, .mac_addr_add = eth_igb_rar_set, .mac_addr_remove = eth_igb_rar_clear, @@ -1855,6 +1858,47 @@ eth_igb_led_off(struct rte_eth_dev *dev) return (e1000_led_off(hw) == E1000_SUCCESS ? 0 : -ENOTSUP); } +static int +eth_igb_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + struct e1000_hw *hw; + uint32_t ctrl; + int tx_pause; + int rx_pause; + + hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + fc_conf->pause_time = hw->fc.pause_time; + fc_conf->high_water = hw->fc.high_water; + fc_conf->low_water = hw->fc.low_water; + fc_conf->send_xon = hw->fc.send_xon; + + /* + * Return rx_pause and tx_pause status according to actual setting of + * the TFCE and RFCE bits in the CTRL register. + */ + ctrl = E1000_READ_REG(hw, E1000_CTRL); + if (ctrl & E1000_CTRL_TFCE) + tx_pause = 1; + else + tx_pause = 0; + + if (ctrl & E1000_CTRL_RFCE) + rx_pause = 1; + else + rx_pause = 0; + + if (rx_pause && tx_pause) + fc_conf->mode = RTE_FC_FULL; + else if (rx_pause) + fc_conf->mode = RTE_FC_RX_PAUSE; + else if (tx_pause) + fc_conf->mode = RTE_FC_TX_PAUSE; + else + fc_conf->mode = RTE_FC_NONE; + + return 0; +} + static int eth_igb_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) { diff --git a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c index fbeb1f4bba..f130080600 100644 --- a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c +++ b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c @@ -134,8 +134,10 @@ static void ixgbe_vlan_hw_extend_disable(struct rte_eth_dev *dev); static int ixgbe_dev_led_on(struct rte_eth_dev *dev); static int ixgbe_dev_led_off(struct rte_eth_dev *dev); -static int ixgbe_flow_ctrl_set(struct rte_eth_dev *dev, - struct rte_eth_fc_conf *fc_conf); +static int ixgbe_flow_ctrl_get(struct rte_eth_dev *dev, + struct rte_eth_fc_conf *fc_conf); +static int ixgbe_flow_ctrl_set(struct rte_eth_dev *dev, + struct rte_eth_fc_conf *fc_conf); static int ixgbe_priority_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_pfc_conf *pfc_conf); static int ixgbe_dev_rss_reta_update(struct rte_eth_dev *dev, @@ -307,6 +309,7 @@ static struct eth_dev_ops ixgbe_eth_dev_ops = { .tx_queue_release = ixgbe_dev_tx_queue_release, .dev_led_on = ixgbe_dev_led_on, .dev_led_off = ixgbe_dev_led_off, + .flow_ctrl_get = ixgbe_flow_ctrl_get, .flow_ctrl_set = ixgbe_flow_ctrl_set, .priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set, .mac_addr_add = ixgbe_add_rar, @@ -2291,6 +2294,54 @@ ixgbe_dev_led_off(struct rte_eth_dev *dev) return (ixgbe_led_off(hw, 0) == IXGBE_SUCCESS ? 0 : -ENOTSUP); } +static int +ixgbe_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + struct ixgbe_hw *hw; + uint32_t mflcn_reg; + uint32_t fccfg_reg; + int rx_pause; + int tx_pause; + + hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + fc_conf->pause_time = hw->fc.pause_time; + fc_conf->high_water = hw->fc.high_water[0]; + fc_conf->low_water = hw->fc.low_water[0]; + fc_conf->send_xon = hw->fc.send_xon; + + /* + * Return rx_pause status according to actual setting of + * MFLCN register. + */ + mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); + if (mflcn_reg & (IXGBE_MFLCN_RPFCE | IXGBE_MFLCN_RFCE)) + rx_pause = 1; + else + rx_pause = 0; + + /* + * Return tx_pause status according to actual setting of + * FCCFG register. + */ + fccfg_reg = IXGBE_READ_REG(hw, IXGBE_FCCFG); + if (fccfg_reg & (IXGBE_FCCFG_TFCE_802_3X | IXGBE_FCCFG_TFCE_PRIORITY)) + tx_pause = 1; + else + tx_pause = 0; + + if (rx_pause && tx_pause) + fc_conf->mode = RTE_FC_FULL; + else if (rx_pause) + fc_conf->mode = RTE_FC_RX_PAUSE; + else if (tx_pause) + fc_conf->mode = RTE_FC_TX_PAUSE; + else + fc_conf->mode = RTE_FC_NONE; + + return 0; +} + static int ixgbe_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) { -- 2.20.1