Commit 308ce142 authored by Gerhard Engleder's avatar Gerhard Engleder Committed by David S. Miller
Browse files

tsnep: Add EtherType RX flow classification support



Received Ethernet frames are assigned to first RX queue per default.
Based on EtherType Ethernet frames can be assigned to other RX queues.
This enables processing of real-time Ethernet protocols on dedicated
RX queues.

Add RX flow classification interface for EtherType based RX queue
assignment.

Signed-off-by: default avatarGerhard Engleder <gerhard@engleder-embedded.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 76203137
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -6,5 +6,5 @@
obj-$(CONFIG_TSNEP) += tsnep.o

tsnep-objs := tsnep_main.o tsnep_ethtool.o tsnep_ptp.o tsnep_tc.o \
	      $(tsnep-y)
	      tsnep_rxnfc.o $(tsnep-y)
tsnep-$(CONFIG_TSNEP_SELFTESTS) += tsnep_selftests.o
+36 −0
Original line number Diff line number Diff line
@@ -37,6 +37,24 @@ struct tsnep_gcl {
	bool change;
};

enum tsnep_rxnfc_filter_type {
	TSNEP_RXNFC_ETHER_TYPE,
};

struct tsnep_rxnfc_filter {
	enum tsnep_rxnfc_filter_type type;
	union {
		u16 ether_type;
	};
};

struct tsnep_rxnfc_rule {
	struct list_head list;
	struct tsnep_rxnfc_filter filter;
	int queue_index;
	int location;
};

struct tsnep_tx_entry {
	struct tsnep_tx_desc *desc;
	struct tsnep_tx_desc_wb *desc_wb;
@@ -141,6 +159,12 @@ struct tsnep_adapter {
	/* ptp clock lock */
	spinlock_t ptp_lock;

	/* RX flow classification rules lock */
	struct mutex rxnfc_lock;
	struct list_head rxnfc_rules;
	int rxnfc_count;
	int rxnfc_max;

	int num_tx_queues;
	struct tsnep_tx tx[TSNEP_MAX_QUEUES];
	int num_rx_queues;
@@ -161,6 +185,18 @@ void tsnep_tc_cleanup(struct tsnep_adapter *adapter);
int tsnep_tc_setup(struct net_device *netdev, enum tc_setup_type type,
		   void *type_data);

int tsnep_rxnfc_init(struct tsnep_adapter *adapter);
void tsnep_rxnfc_cleanup(struct tsnep_adapter *adapter);
int tsnep_rxnfc_get_rule(struct tsnep_adapter *adapter,
			 struct ethtool_rxnfc *cmd);
int tsnep_rxnfc_get_all(struct tsnep_adapter *adapter,
			struct ethtool_rxnfc *cmd,
			u32 *rule_locs);
int tsnep_rxnfc_add_rule(struct tsnep_adapter *adapter,
			 struct ethtool_rxnfc *cmd);
int tsnep_rxnfc_del_rule(struct tsnep_adapter *adapter,
			 struct ethtool_rxnfc *cmd);

#if IS_ENABLED(CONFIG_TSNEP_SELFTESTS)
int tsnep_ethtool_get_test_count(void);
void tsnep_ethtool_get_test_strings(u8 *data);
+40 −0
Original line number Diff line number Diff line
@@ -250,6 +250,44 @@ static int tsnep_ethtool_get_sset_count(struct net_device *netdev, int sset)
	}
}

static int tsnep_ethtool_get_rxnfc(struct net_device *dev,
				   struct ethtool_rxnfc *cmd, u32 *rule_locs)
{
	struct tsnep_adapter *adapter = netdev_priv(dev);

	switch (cmd->cmd) {
	case ETHTOOL_GRXRINGS:
		cmd->data = adapter->num_rx_queues;
		return 0;
	case ETHTOOL_GRXCLSRLCNT:
		cmd->rule_cnt = adapter->rxnfc_count;
		cmd->data = adapter->rxnfc_max;
		cmd->data |= RX_CLS_LOC_SPECIAL;
		return 0;
	case ETHTOOL_GRXCLSRULE:
		return tsnep_rxnfc_get_rule(adapter, cmd);
	case ETHTOOL_GRXCLSRLALL:
		return tsnep_rxnfc_get_all(adapter, cmd, rule_locs);
	default:
		return -EOPNOTSUPP;
	}
}

static int tsnep_ethtool_set_rxnfc(struct net_device *dev,
				   struct ethtool_rxnfc *cmd)
{
	struct tsnep_adapter *adapter = netdev_priv(dev);

	switch (cmd->cmd) {
	case ETHTOOL_SRXCLSRLINS:
		return tsnep_rxnfc_add_rule(adapter, cmd);
	case ETHTOOL_SRXCLSRLDEL:
		return tsnep_rxnfc_del_rule(adapter, cmd);
	default:
		return -EOPNOTSUPP;
	}
}

static int tsnep_ethtool_get_ts_info(struct net_device *dev,
				     struct ethtool_ts_info *info)
{
@@ -287,6 +325,8 @@ const struct ethtool_ops tsnep_ethtool_ops = {
	.get_strings = tsnep_ethtool_get_strings,
	.get_ethtool_stats = tsnep_ethtool_get_ethtool_stats,
	.get_sset_count = tsnep_ethtool_get_sset_count,
	.get_rxnfc = tsnep_ethtool_get_rxnfc,
	.set_rxnfc = tsnep_ethtool_set_rxnfc,
	.get_ts_info = tsnep_ethtool_get_ts_info,
	.get_link_ksettings = phy_ethtool_get_link_ksettings,
	.set_link_ksettings = phy_ethtool_set_link_ksettings,
+8 −4
Original line number Diff line number Diff line
@@ -122,10 +122,6 @@
#define TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL 0x0191
#define TSNEP_RX_STATISTIC_FIFO_OVERFLOW 0x0192
#define TSNEP_RX_STATISTIC_INVALID_FRAME 0x0193
#define TSNEP_RX_ASSIGN 0x01A0
#define TSNEP_RX_ASSIGN_ETHER_TYPE_ACTIVE 0x00000001
#define TSNEP_RX_ASSIGN_ETHER_TYPE_MASK 0xFFFF0000
#define TSNEP_RX_ASSIGN_ETHER_TYPE_SHIFT 16
#define TSNEP_MAC_ADDRESS_LOW 0x0800
#define TSNEP_MAC_ADDRESS_HIGH 0x0804
#define TSNEP_RX_FILTER 0x0806
@@ -152,6 +148,14 @@
#define TSNEP_GCL_A 0x2000
#define TSNEP_GCL_B 0x2800
#define TSNEP_GCL_SIZE SZ_2K
#define TSNEP_RX_ASSIGN 0x0840
#define TSNEP_RX_ASSIGN_ACTIVE 0x00000001
#define TSNEP_RX_ASSIGN_QUEUE_MASK 0x00000006
#define TSNEP_RX_ASSIGN_QUEUE_SHIFT 1
#define TSNEP_RX_ASSIGN_OFFSET 1
#define TSNEP_RX_ASSIGN_ETHER_TYPE 0x0880
#define TSNEP_RX_ASSIGN_ETHER_TYPE_OFFSET 2
#define TSNEP_RX_ASSIGN_ETHER_TYPE_COUNT 2

/* tsnep gate control list operation */
struct tsnep_gcl_operation {
+11 −0
Original line number Diff line number Diff line
@@ -1341,6 +1341,8 @@ static int tsnep_probe(struct platform_device *pdev)
	netdev->max_mtu = TSNEP_MAX_FRAME_SIZE;

	mutex_init(&adapter->gate_control_lock);
	mutex_init(&adapter->rxnfc_lock);
	INIT_LIST_HEAD(&adapter->rxnfc_rules);

	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	adapter->addr = devm_ioremap_resource(&pdev->dev, io);
@@ -1354,6 +1356,7 @@ static int tsnep_probe(struct platform_device *pdev)
	version = (type & ECM_VERSION_MASK) >> ECM_VERSION_SHIFT;
	queue_count = (type & ECM_QUEUE_COUNT_MASK) >> ECM_QUEUE_COUNT_SHIFT;
	adapter->gate_control = type & ECM_GATE_CONTROL;
	adapter->rxnfc_max = TSNEP_RX_ASSIGN_ETHER_TYPE_COUNT;

	tsnep_disable_irq(adapter, ECM_INT_ALL);

@@ -1388,6 +1391,10 @@ static int tsnep_probe(struct platform_device *pdev)
	if (retval)
		goto tc_init_failed;

	retval = tsnep_rxnfc_init(adapter);
	if (retval)
		goto rxnfc_init_failed;

	netdev->netdev_ops = &tsnep_netdev_ops;
	netdev->ethtool_ops = &tsnep_ethtool_ops;
	netdev->features = NETIF_F_SG;
@@ -1408,6 +1415,8 @@ static int tsnep_probe(struct platform_device *pdev)
	return 0;

register_failed:
	tsnep_rxnfc_cleanup(adapter);
rxnfc_init_failed:
	tsnep_tc_cleanup(adapter);
tc_init_failed:
	tsnep_ptp_cleanup(adapter);
@@ -1425,6 +1434,8 @@ static int tsnep_remove(struct platform_device *pdev)

	unregister_netdev(adapter->netdev);

	tsnep_rxnfc_cleanup(adapter);

	tsnep_tc_cleanup(adapter);

	tsnep_ptp_cleanup(adapter);
Loading