octeontx2-pf: ethtool RSS config support

Added support to show or configure RSS hash key, indirection table,
2,4 tuple via ethtool. Also added debug msg_level support
to dump messages when HW reports errors in packet received
or transmitted.

Signed-off-by: Prakash Brahmajyosyula <bprakash@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Sunil Goutham 2020-01-27 18:35:29 +05:30 committed by David S. Miller
parent d45d897984
commit 6e92d71bf8
4 changed files with 269 additions and 4 deletions

View File

@ -220,7 +220,7 @@ int otx2_hw_set_mtu(struct otx2_nic *pfvf, int mtu)
return err;
}
static int otx2_set_flowkey_cfg(struct otx2_nic *pfvf)
int otx2_set_flowkey_cfg(struct otx2_nic *pfvf)
{
struct otx2_rss_info *rss = &pfvf->hw.rss_info;
struct nix_rss_flowkey_cfg *req;
@ -241,7 +241,7 @@ static int otx2_set_flowkey_cfg(struct otx2_nic *pfvf)
return err;
}
static int otx2_set_rss_table(struct otx2_nic *pfvf)
int otx2_set_rss_table(struct otx2_nic *pfvf)
{
struct otx2_rss_info *rss = &pfvf->hw.rss_info;
struct mbox *mbox = &pfvf->mbox;
@ -280,7 +280,7 @@ static int otx2_set_rss_table(struct otx2_nic *pfvf)
return err;
}
static void otx2_set_rss_key(struct otx2_nic *pfvf)
void otx2_set_rss_key(struct otx2_nic *pfvf)
{
struct otx2_rss_info *rss = &pfvf->hw.rss_info;
u64 *key = (u64 *)&rss->key[4];

View File

@ -222,6 +222,9 @@ struct otx2_nic {
struct work_struct reset_task;
struct refill_work *refill_wrk;
/* Ethtool stuff */
u32 msg_enable;
/* Block address of NIX either BLKADDR_NIX0 or BLKADDR_NIX1 */
int nix_blkaddr;
};
@ -580,6 +583,9 @@ void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq);
/* RSS configuration APIs*/
int otx2_rss_init(struct otx2_nic *pfvf);
int otx2_set_flowkey_cfg(struct otx2_nic *pfvf);
void otx2_set_rss_key(struct otx2_nic *pfvf);
int otx2_set_rss_table(struct otx2_nic *pfvf);
/* Mbox handlers */
void mbox_handler_msix_offset(struct otx2_nic *pfvf,

View File

@ -389,7 +389,253 @@ static int otx2_set_coalesce(struct net_device *netdev,
return 0;
}
static int otx2_get_rss_hash_opts(struct otx2_nic *pfvf,
struct ethtool_rxnfc *nfc)
{
struct otx2_rss_info *rss = &pfvf->hw.rss_info;
if (!(rss->flowkey_cfg &
(NIX_FLOW_KEY_TYPE_IPV4 | NIX_FLOW_KEY_TYPE_IPV6)))
return 0;
/* Mimimum is IPv4 and IPv6, SIP/DIP */
nfc->data = RXH_IP_SRC | RXH_IP_DST;
switch (nfc->flow_type) {
case TCP_V4_FLOW:
case TCP_V6_FLOW:
if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_TCP)
nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
break;
case UDP_V4_FLOW:
case UDP_V6_FLOW:
if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_UDP)
nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
break;
case SCTP_V4_FLOW:
case SCTP_V6_FLOW:
if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_SCTP)
nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
break;
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case IPV4_FLOW:
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IPV6_FLOW:
break;
default:
return -EINVAL;
}
return 0;
}
static int otx2_set_rss_hash_opts(struct otx2_nic *pfvf,
struct ethtool_rxnfc *nfc)
{
struct otx2_rss_info *rss = &pfvf->hw.rss_info;
u32 rxh_l4 = RXH_L4_B_0_1 | RXH_L4_B_2_3;
u32 rss_cfg = rss->flowkey_cfg;
if (!rss->enable) {
netdev_err(pfvf->netdev,
"RSS is disabled, cannot change settings\n");
return -EIO;
}
/* Mimimum is IPv4 and IPv6, SIP/DIP */
if (!(nfc->data & RXH_IP_SRC) || !(nfc->data & RXH_IP_DST))
return -EINVAL;
switch (nfc->flow_type) {
case TCP_V4_FLOW:
case TCP_V6_FLOW:
/* Different config for v4 and v6 is not supported.
* Both of them have to be either 4-tuple or 2-tuple.
*/
switch (nfc->data & rxh_l4) {
case 0:
rss_cfg &= ~NIX_FLOW_KEY_TYPE_TCP;
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
rss_cfg |= NIX_FLOW_KEY_TYPE_TCP;
break;
default:
return -EINVAL;
}
break;
case UDP_V4_FLOW:
case UDP_V6_FLOW:
switch (nfc->data & rxh_l4) {
case 0:
rss_cfg &= ~NIX_FLOW_KEY_TYPE_UDP;
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
rss_cfg |= NIX_FLOW_KEY_TYPE_UDP;
break;
default:
return -EINVAL;
}
break;
case SCTP_V4_FLOW:
case SCTP_V6_FLOW:
switch (nfc->data & rxh_l4) {
case 0:
rss_cfg &= ~NIX_FLOW_KEY_TYPE_SCTP;
break;
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
rss_cfg |= NIX_FLOW_KEY_TYPE_SCTP;
break;
default:
return -EINVAL;
}
break;
case IPV4_FLOW:
case IPV6_FLOW:
rss_cfg = NIX_FLOW_KEY_TYPE_IPV4 | NIX_FLOW_KEY_TYPE_IPV6;
break;
default:
return -EINVAL;
}
rss->flowkey_cfg = rss_cfg;
otx2_set_flowkey_cfg(pfvf);
return 0;
}
static int otx2_get_rxnfc(struct net_device *dev,
struct ethtool_rxnfc *nfc, u32 *rules)
{
struct otx2_nic *pfvf = netdev_priv(dev);
int ret = -EOPNOTSUPP;
switch (nfc->cmd) {
case ETHTOOL_GRXRINGS:
nfc->data = pfvf->hw.rx_queues;
ret = 0;
break;
case ETHTOOL_GRXFH:
return otx2_get_rss_hash_opts(pfvf, nfc);
default:
break;
}
return ret;
}
static int otx2_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *nfc)
{
struct otx2_nic *pfvf = netdev_priv(dev);
int ret = -EOPNOTSUPP;
switch (nfc->cmd) {
case ETHTOOL_SRXFH:
ret = otx2_set_rss_hash_opts(pfvf, nfc);
break;
default:
break;
}
return ret;
}
static u32 otx2_get_rxfh_key_size(struct net_device *netdev)
{
struct otx2_nic *pfvf = netdev_priv(netdev);
struct otx2_rss_info *rss;
rss = &pfvf->hw.rss_info;
return sizeof(rss->key);
}
static u32 otx2_get_rxfh_indir_size(struct net_device *dev)
{
struct otx2_nic *pfvf = netdev_priv(dev);
return pfvf->hw.rss_info.rss_size;
}
/* Get RSS configuration */
static int otx2_get_rxfh(struct net_device *dev, u32 *indir,
u8 *hkey, u8 *hfunc)
{
struct otx2_nic *pfvf = netdev_priv(dev);
struct otx2_rss_info *rss;
int idx;
rss = &pfvf->hw.rss_info;
if (indir) {
for (idx = 0; idx < rss->rss_size; idx++)
indir[idx] = rss->ind_tbl[idx];
}
if (hkey)
memcpy(hkey, rss->key, sizeof(rss->key));
if (hfunc)
*hfunc = ETH_RSS_HASH_TOP;
return 0;
}
/* Configure RSS table and hash key */
static int otx2_set_rxfh(struct net_device *dev, const u32 *indir,
const u8 *hkey, const u8 hfunc)
{
struct otx2_nic *pfvf = netdev_priv(dev);
struct otx2_rss_info *rss;
int idx;
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
rss = &pfvf->hw.rss_info;
if (!rss->enable) {
netdev_err(dev, "RSS is disabled, cannot change settings\n");
return -EIO;
}
if (indir) {
for (idx = 0; idx < rss->rss_size; idx++)
rss->ind_tbl[idx] = indir[idx];
}
if (hkey) {
memcpy(rss->key, hkey, sizeof(rss->key));
otx2_set_rss_key(pfvf);
}
otx2_set_rss_table(pfvf);
return 0;
}
static u32 otx2_get_msglevel(struct net_device *netdev)
{
struct otx2_nic *pfvf = netdev_priv(netdev);
return pfvf->msg_enable;
}
static void otx2_set_msglevel(struct net_device *netdev, u32 val)
{
struct otx2_nic *pfvf = netdev_priv(netdev);
pfvf->msg_enable = val;
}
static u32 otx2_get_link(struct net_device *netdev)
{
struct otx2_nic *pfvf = netdev_priv(netdev);
return pfvf->linfo.link_up;
}
static const struct ethtool_ops otx2_ethtool_ops = {
.get_link = otx2_get_link,
.get_drvinfo = otx2_get_drvinfo,
.get_strings = otx2_get_strings,
.get_ethtool_stats = otx2_get_ethtool_stats,
@ -400,6 +646,14 @@ static const struct ethtool_ops otx2_ethtool_ops = {
.set_ringparam = otx2_set_ringparam,
.get_coalesce = otx2_get_coalesce,
.set_coalesce = otx2_set_coalesce,
.get_rxnfc = otx2_get_rxnfc,
.set_rxnfc = otx2_set_rxnfc,
.get_rxfh_key_size = otx2_get_rxfh_key_size,
.get_rxfh_indir_size = otx2_get_rxfh_indir_size,
.get_rxfh = otx2_get_rxfh,
.set_rxfh = otx2_set_rxfh,
.get_msglevel = otx2_get_msglevel,
.set_msglevel = otx2_set_msglevel,
};
void otx2_set_ethtool_ops(struct net_device *netdev)

View File

@ -84,7 +84,7 @@ static void otx2_snd_pkt_handler(struct otx2_nic *pfvf,
struct sk_buff *skb = NULL;
struct sg_list *sg;
if (unlikely(snd_comp->status))
if (unlikely(snd_comp->status) && netif_msg_tx_err(pfvf))
net_err_ratelimited("%s: TX%d: Error in send CQ status:%x\n",
pfvf->netdev->name, cq->cint_idx,
snd_comp->status);
@ -144,6 +144,11 @@ static bool otx2_check_rcv_errors(struct otx2_nic *pfvf,
struct otx2_drv_stats *stats = &pfvf->hw.drv_stats;
struct nix_rx_parse_s *parse = &cqe->parse;
if (netif_msg_rx_err(pfvf))
netdev_err(pfvf->netdev,
"RQ%d: Error pkt with errlev:0x%x errcode:0x%x\n",
qidx, parse->errlev, parse->errcode);
if (parse->errlev == NPC_ERRLVL_RE) {
switch (parse->errcode) {
case ERRCODE_FCS: