Commit d75d5f97 authored by David S. Miller's avatar David S. Miller

Merge branch 'hinic-add-rss-support-and-rss-parameters-configuration'

Xue Chaojing says:

====================
hinic: add rss support and rss parameters configuration

This series add rss support for HINIC driver and implement the ethtool
interface related to rss parameter configuration. user can use ethtool
configure rss parameters or show rss parameters.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 760f1dc2 4fdc51bb
......@@ -4,4 +4,4 @@ obj-$(CONFIG_HINIC) += hinic.o
hinic-y := hinic_main.o hinic_tx.o hinic_rx.o hinic_port.o hinic_hw_dev.o \
hinic_hw_io.o hinic_hw_qp.o hinic_hw_cmdq.o hinic_hw_wq.o \
hinic_hw_mgmt.o hinic_hw_api_cmd.o hinic_hw_eqs.o hinic_hw_if.o \
hinic_common.o
hinic_common.o hinic_ethtool.o
......@@ -22,6 +22,7 @@
enum hinic_flags {
HINIC_LINK_UP = BIT(0),
HINIC_INTF_UP = BIT(1),
HINIC_RSS_ENABLE = BIT(2),
};
struct hinic_rx_mode_work {
......@@ -29,6 +30,23 @@ struct hinic_rx_mode_work {
u32 rx_mode;
};
struct hinic_rss_type {
u8 tcp_ipv6_ext;
u8 ipv6_ext;
u8 tcp_ipv6;
u8 ipv6;
u8 tcp_ipv4;
u8 ipv4;
u8 udp_ipv6;
u8 udp_ipv4;
};
enum hinic_rss_hash_type {
HINIC_RSS_HASH_ENGINE_TYPE_XOR,
HINIC_RSS_HASH_ENGINE_TYPE_TOEP,
HINIC_RSS_HASH_ENGINE_TYPE_MAX,
};
struct hinic_dev {
struct net_device *netdev;
struct hinic_hwdev *hwdev;
......@@ -36,6 +54,8 @@ struct hinic_dev {
u32 msg_enable;
unsigned int tx_weight;
unsigned int rx_weight;
u16 num_qps;
u16 max_qps;
unsigned int flags;
......@@ -50,6 +70,14 @@ struct hinic_dev {
struct hinic_txq_stats tx_stats;
struct hinic_rxq_stats rx_stats;
u8 rss_tmpl_idx;
u8 rss_hash_engine;
u16 num_rss;
u16 rss_limit;
struct hinic_rss_type rss_type;
u8 *rss_hkey_user;
s32 *rss_indir_user;
};
#endif
This diff is collapsed.
......@@ -89,9 +89,6 @@ static int get_capability(struct hinic_hwdev *hwdev,
if (nic_cap->num_qps > HINIC_Q_CTXT_MAX)
nic_cap->num_qps = HINIC_Q_CTXT_MAX;
/* num_qps must be power of 2 */
nic_cap->num_qps = BIT(fls(nic_cap->num_qps) - 1);
nic_cap->max_qps = dev_cap->max_sqs + 1;
if (nic_cap->max_qps != (dev_cap->max_rqs + 1))
return -EFAULT;
......@@ -874,6 +871,13 @@ void hinic_free_hwdev(struct hinic_hwdev *hwdev)
hinic_free_hwif(hwdev->hwif);
}
int hinic_hwdev_max_num_qps(struct hinic_hwdev *hwdev)
{
struct hinic_cap *nic_cap = &hwdev->nic_cap;
return nic_cap->max_qps;
}
/**
* hinic_hwdev_num_qps - return the number QPs available for use
* @hwdev: the NIC HW device
......
......@@ -45,8 +45,26 @@ enum hinic_port_cmd {
HINIC_PORT_CMD_SET_RX_CSUM = 26,
HINIC_PORT_CMD_GET_RSS_TEMPLATE_INDIR_TBL = 37,
HINIC_PORT_CMD_SET_PORT_STATE = 41,
HINIC_PORT_CMD_SET_RSS_TEMPLATE_TBL = 43,
HINIC_PORT_CMD_GET_RSS_TEMPLATE_TBL = 44,
HINIC_PORT_CMD_SET_RSS_HASH_ENGINE = 45,
HINIC_PORT_CMD_GET_RSS_HASH_ENGINE = 46,
HINIC_PORT_CMD_GET_RSS_CTX_TBL = 47,
HINIC_PORT_CMD_SET_RSS_CTX_TBL = 48,
HINIC_PORT_CMD_RSS_TEMP_MGR = 49,
HINIC_PORT_CMD_RSS_CFG = 66,
HINIC_PORT_CMD_FWCTXT_INIT = 69,
HINIC_PORT_CMD_SET_FUNC_STATE = 93,
......@@ -62,6 +80,22 @@ enum hinic_port_cmd {
HINIC_PORT_CMD_SET_LRO_TIMER = 244,
};
enum hinic_ucode_cmd {
HINIC_UCODE_CMD_MODIFY_QUEUE_CONTEXT = 0,
HINIC_UCODE_CMD_CLEAN_QUEUE_CONTEXT,
HINIC_UCODE_CMD_ARM_SQ,
HINIC_UCODE_CMD_ARM_RQ,
HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
HINIC_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
HINIC_UCODE_CMD_GET_RSS_INDIR_TABLE,
HINIC_UCODE_CMD_GET_RSS_CONTEXT_TABLE,
HINIC_UCODE_CMD_SET_IQ_ENABLE,
HINIC_UCODE_CMD_SET_RQ_FLUSH = 10
};
#define NIC_RSS_CMD_TEMP_ALLOC 0x01
#define NIC_RSS_CMD_TEMP_FREE 0x02
enum hinic_mgmt_msg_cmd {
HINIC_MGMT_MSG_CMD_BASE = 160,
......@@ -221,6 +255,8 @@ struct hinic_hwdev *hinic_init_hwdev(struct pci_dev *pdev);
void hinic_free_hwdev(struct hinic_hwdev *hwdev);
int hinic_hwdev_max_num_qps(struct hinic_hwdev *hwdev);
int hinic_hwdev_num_qps(struct hinic_hwdev *hwdev);
struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i);
......
......@@ -230,6 +230,22 @@
#define HINIC_GET_RX_PKT_TYPE(offload_type) \
RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_TYPE)
#define HINIC_RSS_TYPE_VALID_SHIFT 23
#define HINIC_RSS_TYPE_TCP_IPV6_EXT_SHIFT 24
#define HINIC_RSS_TYPE_IPV6_EXT_SHIFT 25
#define HINIC_RSS_TYPE_TCP_IPV6_SHIFT 26
#define HINIC_RSS_TYPE_IPV6_SHIFT 27
#define HINIC_RSS_TYPE_TCP_IPV4_SHIFT 28
#define HINIC_RSS_TYPE_IPV4_SHIFT 29
#define HINIC_RSS_TYPE_UDP_IPV6_SHIFT 30
#define HINIC_RSS_TYPE_UDP_IPV4_SHIFT 31
#define HINIC_RSS_TYPE_SET(val, member) \
(((u32)(val) & 0x1) << HINIC_RSS_TYPE_##member##_SHIFT)
#define HINIC_RSS_TYPE_GET(val, member) \
(((u32)(val) >> HINIC_RSS_TYPE_##member##_SHIFT) & 0x1)
enum hinic_l4offload_type {
HINIC_L4_OFF_DISABLE = 0,
HINIC_TCP_OFFLOAD_ENABLE = 1,
......
......@@ -71,138 +71,6 @@ static int set_features(struct hinic_dev *nic_dev,
netdev_features_t pre_features,
netdev_features_t features, bool force_change);
static void set_link_speed(struct ethtool_link_ksettings *link_ksettings,
enum hinic_speed speed)
{
switch (speed) {
case HINIC_SPEED_10MB_LINK:
link_ksettings->base.speed = SPEED_10;
break;
case HINIC_SPEED_100MB_LINK:
link_ksettings->base.speed = SPEED_100;
break;
case HINIC_SPEED_1000MB_LINK:
link_ksettings->base.speed = SPEED_1000;
break;
case HINIC_SPEED_10GB_LINK:
link_ksettings->base.speed = SPEED_10000;
break;
case HINIC_SPEED_25GB_LINK:
link_ksettings->base.speed = SPEED_25000;
break;
case HINIC_SPEED_40GB_LINK:
link_ksettings->base.speed = SPEED_40000;
break;
case HINIC_SPEED_100GB_LINK:
link_ksettings->base.speed = SPEED_100000;
break;
default:
link_ksettings->base.speed = SPEED_UNKNOWN;
break;
}
}
static int hinic_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings
*link_ksettings)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
enum hinic_port_link_state link_state;
struct hinic_port_cap port_cap;
int err;
ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
Autoneg);
link_ksettings->base.speed = SPEED_UNKNOWN;
link_ksettings->base.autoneg = AUTONEG_DISABLE;
link_ksettings->base.duplex = DUPLEX_UNKNOWN;
err = hinic_port_get_cap(nic_dev, &port_cap);
if (err) {
netif_err(nic_dev, drv, netdev,
"Failed to get port capabilities\n");
return err;
}
err = hinic_port_link_state(nic_dev, &link_state);
if (err) {
netif_err(nic_dev, drv, netdev,
"Failed to get port link state\n");
return err;
}
if (link_state != HINIC_LINK_STATE_UP) {
netif_info(nic_dev, drv, netdev, "No link\n");
return err;
}
set_link_speed(link_ksettings, port_cap.speed);
if (!!(port_cap.autoneg_cap & HINIC_AUTONEG_SUPPORTED))
ethtool_link_ksettings_add_link_mode(link_ksettings,
advertising, Autoneg);
if (port_cap.autoneg_state == HINIC_AUTONEG_ACTIVE)
link_ksettings->base.autoneg = AUTONEG_ENABLE;
link_ksettings->base.duplex = (port_cap.duplex == HINIC_DUPLEX_FULL) ?
DUPLEX_FULL : DUPLEX_HALF;
return 0;
}
static void hinic_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
struct hinic_hwdev *hwdev = nic_dev->hwdev;
struct hinic_hwif *hwif = hwdev->hwif;
strlcpy(info->driver, HINIC_DRV_NAME, sizeof(info->driver));
strlcpy(info->bus_info, pci_name(hwif->pdev), sizeof(info->bus_info));
}
static void hinic_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
ring->rx_max_pending = HINIC_RQ_DEPTH;
ring->tx_max_pending = HINIC_SQ_DEPTH;
ring->rx_pending = HINIC_RQ_DEPTH;
ring->tx_pending = HINIC_SQ_DEPTH;
}
static void hinic_get_channels(struct net_device *netdev,
struct ethtool_channels *channels)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
struct hinic_hwdev *hwdev = nic_dev->hwdev;
channels->max_rx = hwdev->nic_cap.max_qps;
channels->max_tx = hwdev->nic_cap.max_qps;
channels->max_other = 0;
channels->max_combined = 0;
channels->rx_count = hinic_hwdev_num_qps(hwdev);
channels->tx_count = hinic_hwdev_num_qps(hwdev);
channels->other_count = 0;
channels->combined_count = 0;
}
static const struct ethtool_ops hinic_ethtool_ops = {
.get_link_ksettings = hinic_get_link_ksettings,
.get_drvinfo = hinic_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = hinic_get_ringparam,
.get_channels = hinic_get_channels,
};
static void update_rx_stats(struct hinic_dev *nic_dev, struct hinic_rxq *rxq)
{
struct hinic_rxq_stats *nic_rx_stats = &nic_dev->rx_stats;
......@@ -382,11 +250,118 @@ static int hinic_configure_max_qnum(struct hinic_dev *nic_dev)
return 0;
}
static int hinic_rss_init(struct hinic_dev *nic_dev)
{
u32 indir_tbl[HINIC_RSS_INDIR_SIZE] = { 0 };
u8 default_rss_key[HINIC_RSS_KEY_SIZE];
u8 tmpl_idx = nic_dev->rss_tmpl_idx;
int err, i;
netdev_rss_key_fill(default_rss_key, sizeof(default_rss_key));
for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++)
indir_tbl[i] = ethtool_rxfh_indir_default(i, nic_dev->num_rss);
err = hinic_rss_set_template_tbl(nic_dev, tmpl_idx, default_rss_key);
if (err)
return err;
err = hinic_rss_set_indir_tbl(nic_dev, tmpl_idx, indir_tbl);
if (err)
return err;
err = hinic_set_rss_type(nic_dev, tmpl_idx, nic_dev->rss_type);
if (err)
return err;
err = hinic_rss_set_hash_engine(nic_dev, tmpl_idx,
nic_dev->rss_hash_engine);
if (err)
return err;
err = hinic_rss_cfg(nic_dev, 1, tmpl_idx);
if (err)
return err;
return 0;
}
static void hinic_rss_deinit(struct hinic_dev *nic_dev)
{
hinic_rss_cfg(nic_dev, 0, nic_dev->rss_tmpl_idx);
}
static void hinic_init_rss_parameters(struct hinic_dev *nic_dev)
{
nic_dev->rss_hash_engine = HINIC_RSS_HASH_ENGINE_TYPE_XOR;
nic_dev->rss_type.tcp_ipv6_ext = 1;
nic_dev->rss_type.ipv6_ext = 1;
nic_dev->rss_type.tcp_ipv6 = 1;
nic_dev->rss_type.ipv6 = 1;
nic_dev->rss_type.tcp_ipv4 = 1;
nic_dev->rss_type.ipv4 = 1;
nic_dev->rss_type.udp_ipv6 = 1;
nic_dev->rss_type.udp_ipv4 = 1;
}
static void hinic_enable_rss(struct hinic_dev *nic_dev)
{
struct net_device *netdev = nic_dev->netdev;
struct hinic_hwdev *hwdev = nic_dev->hwdev;
struct hinic_hwif *hwif = hwdev->hwif;
struct pci_dev *pdev = hwif->pdev;
int i, node, err = 0;
u16 num_cpus = 0;
nic_dev->max_qps = hinic_hwdev_max_num_qps(hwdev);
if (nic_dev->max_qps <= 1) {
nic_dev->flags &= ~HINIC_RSS_ENABLE;
nic_dev->rss_limit = nic_dev->max_qps;
nic_dev->num_qps = nic_dev->max_qps;
nic_dev->num_rss = nic_dev->max_qps;
return;
}
err = hinic_rss_template_alloc(nic_dev, &nic_dev->rss_tmpl_idx);
if (err) {
netif_err(nic_dev, drv, netdev,
"Failed to alloc tmpl_idx for rss, can't enable rss for this function\n");
nic_dev->flags &= ~HINIC_RSS_ENABLE;
nic_dev->max_qps = 1;
nic_dev->rss_limit = nic_dev->max_qps;
nic_dev->num_qps = nic_dev->max_qps;
nic_dev->num_rss = nic_dev->max_qps;
return;
}
nic_dev->flags |= HINIC_RSS_ENABLE;
for (i = 0; i < num_online_cpus(); i++) {
node = cpu_to_node(i);
if (node == dev_to_node(&pdev->dev))
num_cpus++;
}
if (!num_cpus)
num_cpus = num_online_cpus();
nic_dev->num_qps = min_t(u16, nic_dev->max_qps, num_cpus);
nic_dev->rss_limit = nic_dev->num_qps;
nic_dev->num_rss = nic_dev->num_qps;
hinic_init_rss_parameters(nic_dev);
err = hinic_rss_init(nic_dev);
if (err)
netif_err(nic_dev, drv, netdev, "Failed to init rss\n");
}
static int hinic_open(struct net_device *netdev)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
enum hinic_port_link_state link_state;
int err, ret, num_qps;
int err, ret;
if (!(nic_dev->flags & HINIC_INTF_UP)) {
err = hinic_hwdev_ifup(nic_dev->hwdev);
......@@ -411,6 +386,8 @@ static int hinic_open(struct net_device *netdev)
goto err_create_rxqs;
}
hinic_enable_rss(nic_dev);
err = hinic_configure_max_qnum(nic_dev);
if (err) {
netif_err(nic_dev, drv, nic_dev->netdev,
......@@ -418,9 +395,8 @@ static int hinic_open(struct net_device *netdev)
goto err_port_state;
}
num_qps = hinic_hwdev_num_qps(nic_dev->hwdev);
netif_set_real_num_tx_queues(netdev, num_qps);
netif_set_real_num_rx_queues(netdev, num_qps);
netif_set_real_num_tx_queues(netdev, nic_dev->num_qps);
netif_set_real_num_rx_queues(netdev, nic_dev->num_qps);
err = hinic_port_set_state(nic_dev, HINIC_PORT_ENABLE);
if (err) {
......@@ -476,9 +452,12 @@ static int hinic_open(struct net_device *netdev)
if (ret)
netif_warn(nic_dev, drv, netdev,
"Failed to revert port state\n");
err_port_state:
free_rxqs(nic_dev);
if (nic_dev->flags & HINIC_RSS_ENABLE) {
hinic_rss_deinit(nic_dev);
hinic_rss_template_free(nic_dev, nic_dev->rss_tmpl_idx);
}
err_create_rxqs:
free_txqs(nic_dev);
......@@ -522,6 +501,11 @@ static int hinic_close(struct net_device *netdev)
return err;
}
if (nic_dev->flags & HINIC_RSS_ENABLE) {
hinic_rss_deinit(nic_dev);
hinic_rss_template_free(nic_dev, nic_dev->rss_tmpl_idx);
}
free_rxqs(nic_dev);
free_txqs(nic_dev);
......@@ -967,8 +951,8 @@ static int nic_dev_init(struct pci_dev *pdev)
goto err_alloc_etherdev;
}
hinic_set_ethtool_ops(netdev);
netdev->netdev_ops = &hinic_netdev_ops;
netdev->ethtool_ops = &hinic_ethtool_ops;
netdev->max_mtu = ETH_MAX_MTU;
nic_dev = netdev_priv(netdev);
......
......@@ -13,6 +13,9 @@
#include "hinic_dev.h"
#define HINIC_RSS_KEY_SIZE 40
#define HINIC_RSS_INDIR_SIZE 256
enum hinic_rx_mode {
HINIC_RX_MODE_UC = BIT(0),
HINIC_RX_MODE_MC = BIT(1),
......@@ -219,6 +222,100 @@ struct hinic_lro_timer {
u32 timer;
};
struct hinic_rss_template_mgmt {
u8 status;
u8 version;
u8 rsvd0[6];
u16 func_id;
u8 cmd;
u8 template_id;
u8 rsvd1[4];
};
struct hinic_rss_template_key {
u8 status;
u8 version;
u8 rsvd0[6];
u16 func_id;
u8 template_id;
u8 rsvd1;
u8 key[HINIC_RSS_KEY_SIZE];
};
struct hinic_rss_context_tbl {
u32 group_index;
u32 offset;
u32 size;
u32 rsvd;
u32 ctx;
};
struct hinic_rss_context_table {
u8 status;
u8 version;
u8 rsvd0[6];
u16 func_id;
u8 template_id;
u8 rsvd1;
u32 context;
};
struct hinic_rss_indirect_tbl {
u32 group_index;
u32 offset;
u32 size;
u32 rsvd;
u8 entry[HINIC_RSS_INDIR_SIZE];
};
struct hinic_rss_indir_table {
u8 status;
u8 version;
u8 rsvd0[6];
u16 func_id;
u8 template_id;
u8 rsvd1;
u8 indir[HINIC_RSS_INDIR_SIZE];
};
struct hinic_rss_key {
u8 status;
u8 version;
u8 rsvd0[6];
u16 func_id;
u8 template_id;
u8 rsvd1;
u8 key[HINIC_RSS_KEY_SIZE];
};
struct hinic_rss_engine_type {
u8 status;
u8 version;
u8 rsvd0[6];
u16 func_id;
u8 template_id;
u8 hash_engine;
u8 rsvd1[4];
};
struct hinic_rss_config {
u8 status;
u8 version;
u8 rsvd0[6];
u16 func_id;
u8 rss_en;
u8 template_id;
u8 rq_priority_number;
u8 rsvd1[11];
};
int hinic_port_add_mac(struct hinic_dev *nic_dev, const u8 *addr,
u16 vlan_id);
......@@ -255,4 +352,36 @@ int hinic_set_rx_csum_offload(struct hinic_dev *nic_dev, u32 en);
int hinic_set_rx_lro_state(struct hinic_dev *nic_dev, u8 lro_en,
u32 lro_timer, u32 wqe_num);
int hinic_set_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
struct hinic_rss_type rss_type);
int hinic_rss_set_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
const u32 *indir_table);
int hinic_rss_set_template_tbl(struct hinic_dev *nic_dev, u32 template_id,
const u8 *temp);
int hinic_rss_set_hash_engine(struct hinic_dev *nic_dev, u8 template_id,
u8 type);
int hinic_rss_cfg(struct hinic_dev *nic_dev, u8 rss_en, u8 template_id);
int hinic_rss_template_alloc(struct hinic_dev *nic_dev, u8 *tmpl_idx);
int hinic_rss_template_free(struct hinic_dev *nic_dev, u8 tmpl_idx);
void hinic_set_ethtool_ops(struct net_device *netdev);
int hinic_get_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
struct hinic_rss_type *rss_type);
int hinic_rss_get_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
u32 *indir_table);
int hinic_rss_get_template_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
u8 *temp);
int hinic_rss_get_hash_engine(struct hinic_dev *nic_dev, u8 tmpl_idx,
u8 *type);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment