diff options
Diffstat (limited to 'target/linux/mvebu/patches-4.4/034-net-mvneta-Add-naive-RSS-support.patch')
-rw-r--r-- | target/linux/mvebu/patches-4.4/034-net-mvneta-Add-naive-RSS-support.patch | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/target/linux/mvebu/patches-4.4/034-net-mvneta-Add-naive-RSS-support.patch b/target/linux/mvebu/patches-4.4/034-net-mvneta-Add-naive-RSS-support.patch new file mode 100644 index 0000000000..629c44c8a1 --- /dev/null +++ b/target/linux/mvebu/patches-4.4/034-net-mvneta-Add-naive-RSS-support.patch @@ -0,0 +1,191 @@ +From: Gregory CLEMENT <gregory.clement@free-electrons.com> +Date: Wed, 9 Dec 2015 18:23:50 +0100 +Subject: [PATCH] net: mvneta: Add naive RSS support + +This patch adds the support for the RSS related ethtool +function. Currently it only uses one entry in the indirection table which +allows associating an mvneta interface to a given CPU. + +Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> +Tested-by: Marcin Wojtas <mw@semihalf.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +--- + +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -261,6 +261,11 @@ + + #define MVNETA_TX_MTU_MAX 0x3ffff + ++/* The RSS lookup table actually has 256 entries but we do not use ++ * them yet ++ */ ++#define MVNETA_RSS_LU_TABLE_SIZE 1 ++ + /* TSO header size */ + #define TSO_HEADER_SIZE 128 + +@@ -382,6 +387,8 @@ struct mvneta_port { + unsigned int use_inband_status:1; + + u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)]; ++ ++ u32 indir[MVNETA_RSS_LU_TABLE_SIZE]; + }; + + /* The mvneta_tx_desc and mvneta_rx_desc structures describe the +@@ -1067,7 +1074,7 @@ static void mvneta_defaults_set(struct m + if ((rxq % max_cpu) == cpu) + rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq); + +- if (cpu == rxq_def) ++ if (cpu == pp->rxq_def) + txq_map = MVNETA_CPU_TXQ_ACCESS_ALL_MASK; + + mvreg_write(pp, MVNETA_CPU_MAP(cpu), rxq_map | txq_map); +@@ -2508,6 +2515,18 @@ static void mvneta_percpu_unmask_interru + MVNETA_MISCINTR_INTR_MASK); + } + ++static void mvneta_percpu_mask_interrupt(void *arg) ++{ ++ struct mvneta_port *pp = arg; ++ ++ /* All the queue are masked, but actually only the ones ++ * maped to this CPU will be masked ++ */ ++ mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0); ++ mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0); ++ mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0); ++} ++ + static void mvneta_start_dev(struct mvneta_port *pp) + { + unsigned int cpu; +@@ -3231,6 +3250,106 @@ static int mvneta_ethtool_get_sset_count + return -EOPNOTSUPP; + } + ++static u32 mvneta_ethtool_get_rxfh_indir_size(struct net_device *dev) ++{ ++ return MVNETA_RSS_LU_TABLE_SIZE; ++} ++ ++static int mvneta_ethtool_get_rxnfc(struct net_device *dev, ++ struct ethtool_rxnfc *info, ++ u32 *rules __always_unused) ++{ ++ switch (info->cmd) { ++ case ETHTOOL_GRXRINGS: ++ info->data = rxq_number; ++ return 0; ++ case ETHTOOL_GRXFH: ++ return -EOPNOTSUPP; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int mvneta_config_rss(struct mvneta_port *pp) ++{ ++ int cpu; ++ u32 val; ++ ++ netif_tx_stop_all_queues(pp->dev); ++ ++ for_each_online_cpu(cpu) ++ smp_call_function_single(cpu, mvneta_percpu_mask_interrupt, ++ pp, true); ++ ++ /* We have to synchronise on the napi of each CPU */ ++ for_each_online_cpu(cpu) { ++ struct mvneta_pcpu_port *pcpu_port = ++ per_cpu_ptr(pp->ports, cpu); ++ ++ napi_synchronize(&pcpu_port->napi); ++ napi_disable(&pcpu_port->napi); ++ } ++ ++ pp->rxq_def = pp->indir[0]; ++ ++ /* Update unicast mapping */ ++ mvneta_set_rx_mode(pp->dev); ++ ++ /* Update val of portCfg register accordingly with all RxQueue types */ ++ val = MVNETA_PORT_CONFIG_DEFL_VALUE(pp->rxq_def); ++ mvreg_write(pp, MVNETA_PORT_CONFIG, val); ++ ++ /* Update the elected CPU matching the new rxq_def */ ++ mvneta_percpu_elect(pp); ++ ++ /* We have to synchronise on the napi of each CPU */ ++ for_each_online_cpu(cpu) { ++ struct mvneta_pcpu_port *pcpu_port = ++ per_cpu_ptr(pp->ports, cpu); ++ ++ napi_enable(&pcpu_port->napi); ++ } ++ ++ netif_tx_start_all_queues(pp->dev); ++ ++ return 0; ++} ++ ++static int mvneta_ethtool_set_rxfh(struct net_device *dev, const u32 *indir, ++ const u8 *key, const u8 hfunc) ++{ ++ struct mvneta_port *pp = netdev_priv(dev); ++ /* We require at least one supported parameter to be changed ++ * and no change in any of the unsupported parameters ++ */ ++ if (key || ++ (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) ++ return -EOPNOTSUPP; ++ ++ if (!indir) ++ return 0; ++ ++ memcpy(pp->indir, indir, MVNETA_RSS_LU_TABLE_SIZE); ++ ++ return mvneta_config_rss(pp); ++} ++ ++static int mvneta_ethtool_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, ++ u8 *hfunc) ++{ ++ struct mvneta_port *pp = netdev_priv(dev); ++ ++ if (hfunc) ++ *hfunc = ETH_RSS_HASH_TOP; ++ ++ if (!indir) ++ return 0; ++ ++ memcpy(indir, pp->indir, MVNETA_RSS_LU_TABLE_SIZE); ++ ++ return 0; ++} ++ + static const struct net_device_ops mvneta_netdev_ops = { + .ndo_open = mvneta_open, + .ndo_stop = mvneta_stop, +@@ -3255,6 +3374,10 @@ const struct ethtool_ops mvneta_eth_tool + .get_strings = mvneta_ethtool_get_strings, + .get_ethtool_stats = mvneta_ethtool_get_stats, + .get_sset_count = mvneta_ethtool_get_sset_count, ++ .get_rxfh_indir_size = mvneta_ethtool_get_rxfh_indir_size, ++ .get_rxnfc = mvneta_ethtool_get_rxnfc, ++ .get_rxfh = mvneta_ethtool_get_rxfh, ++ .set_rxfh = mvneta_ethtool_set_rxfh, + }; + + /* Initialize hw */ +@@ -3446,6 +3569,8 @@ static int mvneta_probe(struct platform_ + + pp->rxq_def = rxq_def; + ++ pp->indir[0] = rxq_def; ++ + pp->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pp->clk)) { + err = PTR_ERR(pp->clk); |