Skip to content

Commit d3a8a9e

Browse files
Ronak Doshidavem330
authored andcommitted
vmxnet3: add support to get/set rx flow hash
With vmxnet3 version 4, the emulation supports multiqueue(RSS) for UDP and ESP traffic. A guest can enable/disable RSS for UDP/ESP over IPv4/IPv6 by issuing commands introduced in this patch. ESP ipv6 is not yet supported in this patch. This patch implements get_rss_hash_opts and set_rss_hash_opts methods to allow querying and configuring different Rx flow hash configurations. Signed-off-by: Ronak Doshi <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 123db31 commit d3a8a9e

File tree

4 files changed

+272
-2
lines changed

4 files changed

+272
-2
lines changed

drivers/net/vmxnet3/vmxnet3_defs.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ enum {
8282
VMXNET3_CMD_RESERVED3,
8383
VMXNET3_CMD_SET_COALESCE,
8484
VMXNET3_CMD_REGISTER_MEMREGS,
85+
VMXNET3_CMD_SET_RSS_FIELDS,
8586

8687
VMXNET3_CMD_FIRST_GET = 0xF00D0000,
8788
VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET,
@@ -96,6 +97,7 @@ enum {
9697
VMXNET3_CMD_GET_RESERVED1,
9798
VMXNET3_CMD_GET_TXDATA_DESC_SIZE,
9899
VMXNET3_CMD_GET_COALESCE,
100+
VMXNET3_CMD_GET_RSS_FIELDS,
99101
};
100102

101103
/*
@@ -685,12 +687,22 @@ struct Vmxnet3_MemRegs {
685687
struct Vmxnet3_MemoryRegion memRegs[1];
686688
};
687689

690+
enum Vmxnet3_RSSField {
691+
VMXNET3_RSS_FIELDS_TCPIP4 = 0x0001,
692+
VMXNET3_RSS_FIELDS_TCPIP6 = 0x0002,
693+
VMXNET3_RSS_FIELDS_UDPIP4 = 0x0004,
694+
VMXNET3_RSS_FIELDS_UDPIP6 = 0x0008,
695+
VMXNET3_RSS_FIELDS_ESPIP4 = 0x0010,
696+
VMXNET3_RSS_FIELDS_ESPIP6 = 0x0020,
697+
};
698+
688699
/* If the command data <= 16 bytes, use the shared memory directly.
689700
* otherwise, use variable length configuration descriptor.
690701
*/
691702
union Vmxnet3_CmdInfo {
692703
struct Vmxnet3_VariableLenConfDesc varConf;
693704
struct Vmxnet3_SetPolling setPolling;
705+
enum Vmxnet3_RSSField setRssFields;
694706
__le64 data[2];
695707
};
696708

drivers/net/vmxnet3/vmxnet3_drv.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2554,6 +2554,39 @@ vmxnet3_init_coalesce(struct vmxnet3_adapter *adapter)
25542554
spin_unlock_irqrestore(&adapter->cmd_lock, flags);
25552555
}
25562556

2557+
static void
2558+
vmxnet3_init_rssfields(struct vmxnet3_adapter *adapter)
2559+
{
2560+
struct Vmxnet3_DriverShared *shared = adapter->shared;
2561+
union Vmxnet3_CmdInfo *cmdInfo = &shared->cu.cmdInfo;
2562+
unsigned long flags;
2563+
2564+
if (!VMXNET3_VERSION_GE_4(adapter))
2565+
return;
2566+
2567+
spin_lock_irqsave(&adapter->cmd_lock, flags);
2568+
2569+
if (adapter->default_rss_fields) {
2570+
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
2571+
VMXNET3_CMD_GET_RSS_FIELDS);
2572+
adapter->rss_fields =
2573+
VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
2574+
} else {
2575+
cmdInfo->setRssFields = adapter->rss_fields;
2576+
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
2577+
VMXNET3_CMD_SET_RSS_FIELDS);
2578+
/* Not all requested RSS may get applied, so get and
2579+
* cache what was actually applied.
2580+
*/
2581+
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
2582+
VMXNET3_CMD_GET_RSS_FIELDS);
2583+
adapter->rss_fields =
2584+
VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
2585+
}
2586+
2587+
spin_unlock_irqrestore(&adapter->cmd_lock, flags);
2588+
}
2589+
25572590
int
25582591
vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
25592592
{
@@ -2603,6 +2636,7 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
26032636
}
26042637

26052638
vmxnet3_init_coalesce(adapter);
2639+
vmxnet3_init_rssfields(adapter);
26062640

26072641
for (i = 0; i < adapter->num_rx_queues; i++) {
26082642
VMXNET3_WRITE_BAR0_REG(adapter,
@@ -3430,6 +3464,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
34303464
adapter->default_coal_mode = true;
34313465
}
34323466

3467+
if (VMXNET3_VERSION_GE_4(adapter)) {
3468+
adapter->default_rss_fields = true;
3469+
adapter->rss_fields = VMXNET3_RSS_FIELDS_DEFAULT;
3470+
}
3471+
34333472
SET_NETDEV_DEV(netdev, &pdev->dev);
34343473
vmxnet3_declare_features(adapter, dma64);
34353474

drivers/net/vmxnet3/vmxnet3_ethtool.c

Lines changed: 217 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -665,18 +665,232 @@ vmxnet3_set_ringparam(struct net_device *netdev,
665665
return err;
666666
}
667667

668+
static int
669+
vmxnet3_get_rss_hash_opts(struct vmxnet3_adapter *adapter,
670+
struct ethtool_rxnfc *info)
671+
{
672+
enum Vmxnet3_RSSField rss_fields;
673+
674+
if (netif_running(adapter->netdev)) {
675+
unsigned long flags;
676+
677+
spin_lock_irqsave(&adapter->cmd_lock, flags);
678+
679+
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
680+
VMXNET3_CMD_GET_RSS_FIELDS);
681+
rss_fields = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
682+
spin_unlock_irqrestore(&adapter->cmd_lock, flags);
683+
} else {
684+
rss_fields = adapter->rss_fields;
685+
}
686+
687+
info->data = 0;
688+
689+
/* Report default options for RSS on vmxnet3 */
690+
switch (info->flow_type) {
691+
case TCP_V4_FLOW:
692+
case TCP_V6_FLOW:
693+
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3 |
694+
RXH_IP_SRC | RXH_IP_DST;
695+
break;
696+
case UDP_V4_FLOW:
697+
if (rss_fields & VMXNET3_RSS_FIELDS_UDPIP4)
698+
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
699+
info->data |= RXH_IP_SRC | RXH_IP_DST;
700+
break;
701+
case AH_ESP_V4_FLOW:
702+
case AH_V4_FLOW:
703+
case ESP_V4_FLOW:
704+
if (rss_fields & VMXNET3_RSS_FIELDS_ESPIP4)
705+
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
706+
/* fallthrough */
707+
case SCTP_V4_FLOW:
708+
case IPV4_FLOW:
709+
info->data |= RXH_IP_SRC | RXH_IP_DST;
710+
break;
711+
case UDP_V6_FLOW:
712+
if (rss_fields & VMXNET3_RSS_FIELDS_UDPIP6)
713+
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
714+
info->data |= RXH_IP_SRC | RXH_IP_DST;
715+
break;
716+
case AH_ESP_V6_FLOW:
717+
case AH_V6_FLOW:
718+
case ESP_V6_FLOW:
719+
case SCTP_V6_FLOW:
720+
case IPV6_FLOW:
721+
info->data |= RXH_IP_SRC | RXH_IP_DST;
722+
break;
723+
default:
724+
return -EINVAL;
725+
}
726+
727+
return 0;
728+
}
729+
730+
static int
731+
vmxnet3_set_rss_hash_opt(struct net_device *netdev,
732+
struct vmxnet3_adapter *adapter,
733+
struct ethtool_rxnfc *nfc)
734+
{
735+
enum Vmxnet3_RSSField rss_fields = adapter->rss_fields;
736+
737+
/* RSS does not support anything other than hashing
738+
* to queues on src and dst IPs and ports
739+
*/
740+
if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
741+
RXH_L4_B_0_1 | RXH_L4_B_2_3))
742+
return -EINVAL;
743+
744+
switch (nfc->flow_type) {
745+
case TCP_V4_FLOW:
746+
case TCP_V6_FLOW:
747+
if (!(nfc->data & RXH_IP_SRC) ||
748+
!(nfc->data & RXH_IP_DST) ||
749+
!(nfc->data & RXH_L4_B_0_1) ||
750+
!(nfc->data & RXH_L4_B_2_3))
751+
return -EINVAL;
752+
break;
753+
case UDP_V4_FLOW:
754+
if (!(nfc->data & RXH_IP_SRC) ||
755+
!(nfc->data & RXH_IP_DST))
756+
return -EINVAL;
757+
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
758+
case 0:
759+
rss_fields &= ~VMXNET3_RSS_FIELDS_UDPIP4;
760+
break;
761+
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
762+
rss_fields |= VMXNET3_RSS_FIELDS_UDPIP4;
763+
break;
764+
default:
765+
return -EINVAL;
766+
}
767+
break;
768+
case UDP_V6_FLOW:
769+
if (!(nfc->data & RXH_IP_SRC) ||
770+
!(nfc->data & RXH_IP_DST))
771+
return -EINVAL;
772+
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
773+
case 0:
774+
rss_fields &= ~VMXNET3_RSS_FIELDS_UDPIP6;
775+
break;
776+
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
777+
rss_fields |= VMXNET3_RSS_FIELDS_UDPIP6;
778+
break;
779+
default:
780+
return -EINVAL;
781+
}
782+
break;
783+
case ESP_V4_FLOW:
784+
case AH_V4_FLOW:
785+
case AH_ESP_V4_FLOW:
786+
if (!(nfc->data & RXH_IP_SRC) ||
787+
!(nfc->data & RXH_IP_DST))
788+
return -EINVAL;
789+
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
790+
case 0:
791+
rss_fields &= ~VMXNET3_RSS_FIELDS_ESPIP4;
792+
break;
793+
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
794+
rss_fields |= VMXNET3_RSS_FIELDS_ESPIP4;
795+
break;
796+
default:
797+
return -EINVAL;
798+
}
799+
break;
800+
case ESP_V6_FLOW:
801+
case AH_V6_FLOW:
802+
case AH_ESP_V6_FLOW:
803+
case SCTP_V4_FLOW:
804+
case SCTP_V6_FLOW:
805+
if (!(nfc->data & RXH_IP_SRC) ||
806+
!(nfc->data & RXH_IP_DST) ||
807+
(nfc->data & RXH_L4_B_0_1) ||
808+
(nfc->data & RXH_L4_B_2_3))
809+
return -EINVAL;
810+
break;
811+
default:
812+
return -EINVAL;
813+
}
814+
815+
/* if we changed something we need to update flags */
816+
if (rss_fields != adapter->rss_fields) {
817+
adapter->default_rss_fields = false;
818+
if (netif_running(netdev)) {
819+
struct Vmxnet3_DriverShared *shared = adapter->shared;
820+
union Vmxnet3_CmdInfo *cmdInfo = &shared->cu.cmdInfo;
821+
unsigned long flags;
822+
823+
spin_lock_irqsave(&adapter->cmd_lock, flags);
824+
cmdInfo->setRssFields = rss_fields;
825+
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
826+
VMXNET3_CMD_SET_RSS_FIELDS);
827+
828+
/* Not all requested RSS may get applied, so get and
829+
* cache what was actually applied.
830+
*/
831+
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
832+
VMXNET3_CMD_GET_RSS_FIELDS);
833+
adapter->rss_fields =
834+
VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
835+
spin_unlock_irqrestore(&adapter->cmd_lock, flags);
836+
} else {
837+
/* When the device is activated, we will try to apply
838+
* these rules and cache the applied value later.
839+
*/
840+
adapter->rss_fields = rss_fields;
841+
}
842+
}
843+
return 0;
844+
}
668845

669846
static int
670847
vmxnet3_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info,
671848
u32 *rules)
672849
{
673850
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
851+
int err = 0;
852+
674853
switch (info->cmd) {
675854
case ETHTOOL_GRXRINGS:
676855
info->data = adapter->num_rx_queues;
677-
return 0;
856+
break;
857+
case ETHTOOL_GRXFH:
858+
if (!VMXNET3_VERSION_GE_4(adapter)) {
859+
err = -EOPNOTSUPP;
860+
break;
861+
}
862+
err = vmxnet3_get_rss_hash_opts(adapter, info);
863+
break;
864+
default:
865+
err = -EOPNOTSUPP;
866+
break;
678867
}
679-
return -EOPNOTSUPP;
868+
869+
return err;
870+
}
871+
872+
static int
873+
vmxnet3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info)
874+
{
875+
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
876+
int err = 0;
877+
878+
if (!VMXNET3_VERSION_GE_4(adapter)) {
879+
err = -EOPNOTSUPP;
880+
goto done;
881+
}
882+
883+
switch (info->cmd) {
884+
case ETHTOOL_SRXFH:
885+
err = vmxnet3_set_rss_hash_opt(netdev, adapter, info);
886+
break;
887+
default:
888+
err = -EOPNOTSUPP;
889+
break;
890+
}
891+
892+
done:
893+
return err;
680894
}
681895

682896
#ifdef VMXNET3_RSS
@@ -887,6 +1101,7 @@ static const struct ethtool_ops vmxnet3_ethtool_ops = {
8871101
.get_ringparam = vmxnet3_get_ringparam,
8881102
.set_ringparam = vmxnet3_set_ringparam,
8891103
.get_rxnfc = vmxnet3_get_rxnfc,
1104+
.set_rxnfc = vmxnet3_set_rxnfc,
8901105
#ifdef VMXNET3_RSS
8911106
.get_rxfh_indir_size = vmxnet3_get_rss_indir_size,
8921107
.get_rxfh = vmxnet3_get_rss,

drivers/net/vmxnet3/vmxnet3_int.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ struct vmxnet3_adapter {
377377
u16 rxdata_desc_size;
378378

379379
bool rxdataring_enabled;
380+
bool default_rss_fields;
381+
enum Vmxnet3_RSSField rss_fields;
380382

381383
struct work_struct work;
382384

@@ -438,6 +440,8 @@ struct vmxnet3_adapter {
438440

439441
#define VMXNET3_COAL_RBC_RATE(usecs) (1000000 / usecs)
440442
#define VMXNET3_COAL_RBC_USECS(rbc_rate) (1000000 / rbc_rate)
443+
#define VMXNET3_RSS_FIELDS_DEFAULT (VMXNET3_RSS_FIELDS_TCPIP4 | \
444+
VMXNET3_RSS_FIELDS_TCPIP6)
441445

442446
int
443447
vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter);

0 commit comments

Comments
 (0)