File Index
Files and directories
Sign in
FILE

tag_yt921x.c

File preview with syntax highlighting.

linux-6.19.14/net/dsa/tag_yt921x.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Motorcomm YT921x Switch Extended CPU Port Tagging
  4 *
  5 * Copyright (c) 2025 David Yang <mmyangfl@gmail.com>
  6 *
  7 * +----+----+-------+-----+----+---------
  8 * | DA | SA | TagET | Tag | ET | Payload ...
  9 * +----+----+-------+-----+----+---------
 10 *   6    6      2      6    2       N
 11 *
 12 * Tag Ethertype: CPU_TAG_TPID_TPID (default: ETH_P_YT921X = 0x9988)
 13 *   * Hardcoded for the moment, but still configurable. Discuss it if there
 14 *     are conflicts somewhere and/or you want to change it for some reason.
 15 * Tag:
 16 *   2: VLAN Tag
 17 *   2: Rx Port
 18 *     15b: Rx Port Valid
 19 *     14b-11b: Rx Port
 20 *     10b-0b: Cmd?
 21 *   2: Tx Port(s)
 22 *     15b: Tx Port(s) Valid
 23 *     10b-0b: Tx Port(s) Mask
 24 */
 25
 26#include <linux/etherdevice.h>
 27
 28#include "tag.h"
 29
 30#define YT921X_TAG_NAME	"yt921x"
 31
 32#define YT921X_TAG_LEN	8
 33
 34#define YT921X_TAG_PORT_EN		BIT(15)
 35#define YT921X_TAG_RX_PORT_M		GENMASK(14, 11)
 36#define YT921X_TAG_RX_CMD_M		GENMASK(10, 0)
 37#define  YT921X_TAG_RX_CMD(x)			FIELD_PREP(YT921X_TAG_RX_CMD_M, (x))
 38#define  YT921X_TAG_RX_CMD_FORWARDED		0x80
 39#define  YT921X_TAG_RX_CMD_UNK_UCAST		0xb2
 40#define  YT921X_TAG_RX_CMD_UNK_MCAST		0xb4
 41#define YT921X_TAG_TX_PORTS		GENMASK(10, 0)
 42
 43static struct sk_buff *
 44yt921x_tag_xmit(struct sk_buff *skb, struct net_device *netdev)
 45{
 46	__be16 *tag;
 47	u16 tx;
 48
 49	skb_push(skb, YT921X_TAG_LEN);
 50	dsa_alloc_etype_header(skb, YT921X_TAG_LEN);
 51
 52	tag = dsa_etype_header_pos_tx(skb);
 53
 54	tag[0] = htons(ETH_P_YT921X);
 55	/* VLAN tag unrelated when TX */
 56	tag[1] = 0;
 57	tag[2] = 0;
 58	tx = FIELD_PREP(YT921X_TAG_TX_PORTS, dsa_xmit_port_mask(skb, netdev)) |
 59	     YT921X_TAG_PORT_EN;
 60	tag[3] = htons(tx);
 61
 62	return skb;
 63}
 64
 65static struct sk_buff *
 66yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
 67{
 68	unsigned int port;
 69	__be16 *tag;
 70	u16 cmd;
 71	u16 rx;
 72
 73	if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN)))
 74		return NULL;
 75
 76	tag = dsa_etype_header_pos_rx(skb);
 77
 78	if (unlikely(tag[0] != htons(ETH_P_YT921X))) {
 79		dev_warn_ratelimited(&netdev->dev,
 80				     "Unexpected EtherType 0x%04x\n",
 81				     ntohs(tag[0]));
 82		return NULL;
 83	}
 84
 85	/* Locate which port this is coming from */
 86	rx = ntohs(tag[2]);
 87	if (unlikely((rx & YT921X_TAG_PORT_EN) == 0)) {
 88		dev_warn_ratelimited(&netdev->dev,
 89				     "Unexpected rx tag 0x%04x\n", rx);
 90		return NULL;
 91	}
 92
 93	port = FIELD_GET(YT921X_TAG_RX_PORT_M, rx);
 94	skb->dev = dsa_conduit_find_user(netdev, 0, port);
 95	if (unlikely(!skb->dev)) {
 96		dev_warn_ratelimited(&netdev->dev,
 97				     "Couldn't decode source port %u\n", port);
 98		return NULL;
 99	}
100
101	cmd = FIELD_GET(YT921X_TAG_RX_CMD_M, rx);
102	switch (cmd) {
103	case YT921X_TAG_RX_CMD_FORWARDED:
104		/* Already forwarded by hardware */
105		dsa_default_offload_fwd_mark(skb);
106		break;
107	case YT921X_TAG_RX_CMD_UNK_UCAST:
108	case YT921X_TAG_RX_CMD_UNK_MCAST:
109		/* NOTE: hardware doesn't distinguish between TRAP (copy to CPU
110		 * only) and COPY (forward and copy to CPU). In order to perform
111		 * a soft switch, NEVER use COPY action in the switch driver.
112		 */
113		break;
114	default:
115		dev_warn_ratelimited(&netdev->dev,
116				     "Unexpected rx cmd 0x%02x\n", cmd);
117		break;
118	}
119
120	/* Remove YT921x tag and update checksum */
121	skb_pull_rcsum(skb, YT921X_TAG_LEN);
122	dsa_strip_etype_header(skb, YT921X_TAG_LEN);
123
124	return skb;
125}
126
127static const struct dsa_device_ops yt921x_netdev_ops = {
128	.name	= YT921X_TAG_NAME,
129	.proto	= DSA_TAG_PROTO_YT921X,
130	.xmit	= yt921x_tag_xmit,
131	.rcv	= yt921x_tag_rcv,
132	.needed_headroom = YT921X_TAG_LEN,
133};
134
135MODULE_DESCRIPTION("DSA tag driver for Motorcomm YT921x switches");
136MODULE_LICENSE("GPL");
137MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_YT921X, YT921X_TAG_NAME);
138
139module_dsa_tag_driver(yt921x_netdev_ops);
~/ Read-only file preview.