File Index
Files and directories
Sign in
FILE

tag_rzn1_a5psw.c

File preview with syntax highlighting.

linux-6.19.14/net/dsa/tag_rzn1_a5psw.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2022 Schneider Electric
  4 *
  5 * Clément Léger <clement.leger@bootlin.com>
  6 */
  7
  8#include <linux/bitfield.h>
  9#include <linux/etherdevice.h>
 10#include <linux/if_ether.h>
 11#include <net/dsa.h>
 12
 13#include "tag.h"
 14
 15/* To define the outgoing port and to discover the incoming port a TAG is
 16 * inserted after Src MAC :
 17 *
 18 *       Dest MAC       Src MAC           TAG         Type
 19 * ...| 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 5 6 7 8 | 1 2 |...
 20 *                                |<--------------->|
 21 *
 22 * See struct a5psw_tag for layout
 23 */
 24
 25#define A5PSW_NAME			"a5psw"
 26
 27#define ETH_P_DSA_A5PSW			0xE001
 28#define A5PSW_TAG_LEN			8
 29#define A5PSW_CTRL_DATA_FORCE_FORWARD	BIT(0)
 30/* This is both used for xmit tag and rcv tagging */
 31#define A5PSW_CTRL_DATA_PORT		GENMASK(3, 0)
 32
 33struct a5psw_tag {
 34	__be16 ctrl_tag;
 35	__be16 ctrl_data;
 36	__be16 ctrl_data2_hi;
 37	__be16 ctrl_data2_lo;
 38};
 39
 40static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *dev)
 41{
 42	struct a5psw_tag *ptag;
 43	u32 data2_val;
 44
 45	BUILD_BUG_ON(sizeof(*ptag) != A5PSW_TAG_LEN);
 46
 47	/* The Ethernet switch we are interfaced with needs packets to be at
 48	 * least 60 bytes otherwise they will be discarded when they enter the
 49	 * switch port logic.
 50	 */
 51	if (__skb_put_padto(skb, ETH_ZLEN, false))
 52		return NULL;
 53
 54	/* provide 'A5PSW_TAG_LEN' bytes additional space */
 55	skb_push(skb, A5PSW_TAG_LEN);
 56
 57	/* make room between MACs and Ether-Type to insert tag */
 58	dsa_alloc_etype_header(skb, A5PSW_TAG_LEN);
 59
 60	ptag = dsa_etype_header_pos_tx(skb);
 61
 62	data2_val = FIELD_PREP(A5PSW_CTRL_DATA_PORT, dsa_xmit_port_mask(skb, dev));
 63	ptag->ctrl_tag = htons(ETH_P_DSA_A5PSW);
 64	ptag->ctrl_data = htons(A5PSW_CTRL_DATA_FORCE_FORWARD);
 65	ptag->ctrl_data2_lo = htons(data2_val);
 66	ptag->ctrl_data2_hi = 0;
 67
 68	return skb;
 69}
 70
 71static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb,
 72				     struct net_device *dev)
 73{
 74	struct a5psw_tag *tag;
 75	int port;
 76
 77	if (unlikely(!pskb_may_pull(skb, A5PSW_TAG_LEN))) {
 78		dev_warn_ratelimited(&dev->dev,
 79				     "Dropping packet, cannot pull\n");
 80		return NULL;
 81	}
 82
 83	tag = dsa_etype_header_pos_rx(skb);
 84
 85	if (tag->ctrl_tag != htons(ETH_P_DSA_A5PSW)) {
 86		dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid TAG marker\n");
 87		return NULL;
 88	}
 89
 90	port = FIELD_GET(A5PSW_CTRL_DATA_PORT, ntohs(tag->ctrl_data));
 91
 92	skb->dev = dsa_conduit_find_user(dev, 0, port);
 93	if (!skb->dev)
 94		return NULL;
 95
 96	skb_pull_rcsum(skb, A5PSW_TAG_LEN);
 97	dsa_strip_etype_header(skb, A5PSW_TAG_LEN);
 98
 99	dsa_default_offload_fwd_mark(skb);
100
101	return skb;
102}
103
104static const struct dsa_device_ops a5psw_netdev_ops = {
105	.name	= A5PSW_NAME,
106	.proto	= DSA_TAG_PROTO_RZN1_A5PSW,
107	.xmit	= a5psw_tag_xmit,
108	.rcv	= a5psw_tag_rcv,
109	.needed_headroom = A5PSW_TAG_LEN,
110};
111
112MODULE_DESCRIPTION("DSA tag driver for Renesas RZ/N1 A5PSW switch");
113MODULE_LICENSE("GPL v2");
114MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_A5PSW, A5PSW_NAME);
115module_dsa_tag_driver(a5psw_netdev_ops);
~/ Read-only file preview.