Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Intel / Lantiq GSWIP V2.0 PMAC tag support
  4 *
  5 * Copyright (C) 2017 - 2018 Hauke Mehrtens <hauke@hauke-m.de>
  6 */
  7
  8#include <linux/bitops.h>
  9#include <linux/etherdevice.h>
 10#include <linux/skbuff.h>
 11#include <net/dsa.h>
 12
 13#include "dsa_priv.h"
 14
 15#define GSWIP_TX_HEADER_LEN		4
 16
 17/* special tag in TX path header */
 18/* Byte 0 */
 19#define GSWIP_TX_SLPID_SHIFT		0	/* source port ID */
 20#define  GSWIP_TX_SLPID_CPU		2
 21#define  GSWIP_TX_SLPID_APP1		3
 22#define  GSWIP_TX_SLPID_APP2		4
 23#define  GSWIP_TX_SLPID_APP3		5
 24#define  GSWIP_TX_SLPID_APP4		6
 25#define  GSWIP_TX_SLPID_APP5		7
 26
 27/* Byte 1 */
 28#define GSWIP_TX_CRCGEN_DIS		BIT(7)
 29#define GSWIP_TX_DPID_SHIFT		0	/* destination group ID */
 30#define  GSWIP_TX_DPID_ELAN		0
 31#define  GSWIP_TX_DPID_EWAN		1
 32#define  GSWIP_TX_DPID_CPU		2
 33#define  GSWIP_TX_DPID_APP1		3
 34#define  GSWIP_TX_DPID_APP2		4
 35#define  GSWIP_TX_DPID_APP3		5
 36#define  GSWIP_TX_DPID_APP4		6
 37#define  GSWIP_TX_DPID_APP5		7
 38
 39/* Byte 2 */
 40#define GSWIP_TX_PORT_MAP_EN		BIT(7)
 41#define GSWIP_TX_PORT_MAP_SEL		BIT(6)
 42#define GSWIP_TX_LRN_DIS		BIT(5)
 43#define GSWIP_TX_CLASS_EN		BIT(4)
 44#define GSWIP_TX_CLASS_SHIFT		0
 45#define GSWIP_TX_CLASS_MASK		GENMASK(3, 0)
 46
 47/* Byte 3 */
 48#define GSWIP_TX_DPID_EN		BIT(0)
 49#define GSWIP_TX_PORT_MAP_SHIFT		1
 50#define GSWIP_TX_PORT_MAP_MASK		GENMASK(6, 1)
 51
 52#define GSWIP_RX_HEADER_LEN	8
 53
 54/* special tag in RX path header */
 55/* Byte 7 */
 56#define GSWIP_RX_SPPID_SHIFT		4
 57#define GSWIP_RX_SPPID_MASK		GENMASK(6, 4)
 58
 59static struct sk_buff *gswip_tag_xmit(struct sk_buff *skb,
 60				      struct net_device *dev)
 61{
 62	struct dsa_port *dp = dsa_slave_to_port(dev);
 63	u8 *gswip_tag;
 64
 65	skb_push(skb, GSWIP_TX_HEADER_LEN);
 66
 67	gswip_tag = skb->data;
 68	gswip_tag[0] = GSWIP_TX_SLPID_CPU;
 69	gswip_tag[1] = GSWIP_TX_DPID_ELAN;
 70	gswip_tag[2] = GSWIP_TX_PORT_MAP_EN | GSWIP_TX_PORT_MAP_SEL;
 71	gswip_tag[3] = BIT(dp->index + GSWIP_TX_PORT_MAP_SHIFT) & GSWIP_TX_PORT_MAP_MASK;
 72	gswip_tag[3] |= GSWIP_TX_DPID_EN;
 73
 74	return skb;
 75}
 76
 77static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb,
 78				     struct net_device *dev,
 79				     struct packet_type *pt)
 80{
 81	int port;
 82	u8 *gswip_tag;
 83
 84	if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN)))
 85		return NULL;
 86
 87	gswip_tag = skb->data - ETH_HLEN;
 88
 89	/* Get source port information */
 90	port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT;
 91	skb->dev = dsa_master_find_slave(dev, 0, port);
 92	if (!skb->dev)
 93		return NULL;
 94
 95	/* remove GSWIP tag */
 96	skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN);
 97
 98	return skb;
 99}
100
101static const struct dsa_device_ops gswip_netdev_ops = {
102	.name = "gswip",
103	.proto	= DSA_TAG_PROTO_GSWIP,
104	.xmit = gswip_tag_xmit,
105	.rcv = gswip_tag_rcv,
106	.needed_headroom = GSWIP_RX_HEADER_LEN,
107};
108
109MODULE_LICENSE("GPL");
110MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_GSWIP);
111
112module_dsa_tag_driver(gswip_netdev_ops);