1501ef306SVadym Kochan // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2501ef306SVadym Kochan /* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
3501ef306SVadym Kochan 
4501ef306SVadym Kochan #include <linux/bitfield.h>
5501ef306SVadym Kochan #include <linux/bitops.h>
6501ef306SVadym Kochan #include <linux/errno.h>
7501ef306SVadym Kochan #include <linux/string.h>
8501ef306SVadym Kochan 
9501ef306SVadym Kochan #include "prestera_dsa.h"
10501ef306SVadym Kochan 
11501ef306SVadym Kochan #define PRESTERA_DSA_W0_CMD		GENMASK(31, 30)
12501ef306SVadym Kochan #define PRESTERA_DSA_W0_IS_TAGGED	BIT(29)
13501ef306SVadym Kochan #define PRESTERA_DSA_W0_DEV_NUM		GENMASK(28, 24)
14501ef306SVadym Kochan #define PRESTERA_DSA_W0_PORT_NUM	GENMASK(23, 19)
15501ef306SVadym Kochan #define PRESTERA_DSA_W0_VPT		GENMASK(15, 13)
16501ef306SVadym Kochan #define PRESTERA_DSA_W0_EXT_BIT		BIT(12)
17501ef306SVadym Kochan #define PRESTERA_DSA_W0_VID		GENMASK(11, 0)
18501ef306SVadym Kochan 
19501ef306SVadym Kochan #define PRESTERA_DSA_W1_EXT_BIT		BIT(31)
20501ef306SVadym Kochan #define PRESTERA_DSA_W1_CFI_BIT		BIT(30)
21501ef306SVadym Kochan #define PRESTERA_DSA_W1_PORT_NUM	GENMASK(11, 10)
22*0a9003f4SOleksandr Mazur #define PRESTERA_DSA_W1_MASK_CPU_CODE	GENMASK(7, 0)
23501ef306SVadym Kochan 
24501ef306SVadym Kochan #define PRESTERA_DSA_W2_EXT_BIT		BIT(31)
25501ef306SVadym Kochan #define PRESTERA_DSA_W2_PORT_NUM	BIT(20)
26501ef306SVadym Kochan 
27501ef306SVadym Kochan #define PRESTERA_DSA_W3_VID		GENMASK(30, 27)
28501ef306SVadym Kochan #define PRESTERA_DSA_W3_DST_EPORT	GENMASK(23, 7)
29501ef306SVadym Kochan #define PRESTERA_DSA_W3_DEV_NUM		GENMASK(6, 0)
30501ef306SVadym Kochan 
31501ef306SVadym Kochan #define PRESTERA_DSA_VID		GENMASK(15, 12)
32501ef306SVadym Kochan #define PRESTERA_DSA_DEV_NUM		GENMASK(11, 5)
33501ef306SVadym Kochan 
prestera_dsa_parse(struct prestera_dsa * dsa,const u8 * dsa_buf)34501ef306SVadym Kochan int prestera_dsa_parse(struct prestera_dsa *dsa, const u8 *dsa_buf)
35501ef306SVadym Kochan {
36501ef306SVadym Kochan 	__be32 *dsa_words = (__be32 *)dsa_buf;
37501ef306SVadym Kochan 	enum prestera_dsa_cmd cmd;
38501ef306SVadym Kochan 	u32 words[4];
39501ef306SVadym Kochan 	u32 field;
40501ef306SVadym Kochan 
41501ef306SVadym Kochan 	words[0] = ntohl(dsa_words[0]);
42501ef306SVadym Kochan 	words[1] = ntohl(dsa_words[1]);
43501ef306SVadym Kochan 	words[2] = ntohl(dsa_words[2]);
44501ef306SVadym Kochan 	words[3] = ntohl(dsa_words[3]);
45501ef306SVadym Kochan 
46501ef306SVadym Kochan 	/* set the common parameters */
47501ef306SVadym Kochan 	cmd = (enum prestera_dsa_cmd)FIELD_GET(PRESTERA_DSA_W0_CMD, words[0]);
48501ef306SVadym Kochan 
49501ef306SVadym Kochan 	/* only to CPU is supported */
50501ef306SVadym Kochan 	if (unlikely(cmd != PRESTERA_DSA_CMD_TO_CPU))
51501ef306SVadym Kochan 		return -EINVAL;
52501ef306SVadym Kochan 
53501ef306SVadym Kochan 	if (FIELD_GET(PRESTERA_DSA_W0_EXT_BIT, words[0]) == 0)
54501ef306SVadym Kochan 		return -EINVAL;
55501ef306SVadym Kochan 	if (FIELD_GET(PRESTERA_DSA_W1_EXT_BIT, words[1]) == 0)
56501ef306SVadym Kochan 		return -EINVAL;
57501ef306SVadym Kochan 	if (FIELD_GET(PRESTERA_DSA_W2_EXT_BIT, words[2]) == 0)
58501ef306SVadym Kochan 		return -EINVAL;
59501ef306SVadym Kochan 
60501ef306SVadym Kochan 	field = FIELD_GET(PRESTERA_DSA_W3_VID, words[3]);
61501ef306SVadym Kochan 
62501ef306SVadym Kochan 	dsa->vlan.is_tagged = FIELD_GET(PRESTERA_DSA_W0_IS_TAGGED, words[0]);
63501ef306SVadym Kochan 	dsa->vlan.cfi_bit = FIELD_GET(PRESTERA_DSA_W1_CFI_BIT, words[1]);
64501ef306SVadym Kochan 	dsa->vlan.vpt = FIELD_GET(PRESTERA_DSA_W0_VPT, words[0]);
65501ef306SVadym Kochan 	dsa->vlan.vid = FIELD_GET(PRESTERA_DSA_W0_VID, words[0]);
66501ef306SVadym Kochan 	dsa->vlan.vid &= ~PRESTERA_DSA_VID;
67501ef306SVadym Kochan 	dsa->vlan.vid |= FIELD_PREP(PRESTERA_DSA_VID, field);
68501ef306SVadym Kochan 
69501ef306SVadym Kochan 	field = FIELD_GET(PRESTERA_DSA_W3_DEV_NUM, words[3]);
70501ef306SVadym Kochan 
71501ef306SVadym Kochan 	dsa->hw_dev_num = FIELD_GET(PRESTERA_DSA_W0_DEV_NUM, words[0]);
72501ef306SVadym Kochan 	dsa->hw_dev_num |= FIELD_PREP(PRESTERA_DSA_DEV_NUM, field);
73501ef306SVadym Kochan 
74501ef306SVadym Kochan 	dsa->port_num = (FIELD_GET(PRESTERA_DSA_W0_PORT_NUM, words[0]) << 0) |
75501ef306SVadym Kochan 			(FIELD_GET(PRESTERA_DSA_W1_PORT_NUM, words[1]) << 5) |
76501ef306SVadym Kochan 			(FIELD_GET(PRESTERA_DSA_W2_PORT_NUM, words[2]) << 7);
77501ef306SVadym Kochan 
78*0a9003f4SOleksandr Mazur 	dsa->cpu_code = FIELD_GET(PRESTERA_DSA_W1_MASK_CPU_CODE, words[1]);
79*0a9003f4SOleksandr Mazur 
80501ef306SVadym Kochan 	return 0;
81501ef306SVadym Kochan }
82501ef306SVadym Kochan 
prestera_dsa_build(const struct prestera_dsa * dsa,u8 * dsa_buf)83501ef306SVadym Kochan int prestera_dsa_build(const struct prestera_dsa *dsa, u8 *dsa_buf)
84501ef306SVadym Kochan {
85501ef306SVadym Kochan 	__be32 *dsa_words = (__be32 *)dsa_buf;
86501ef306SVadym Kochan 	u32 dev_num = dsa->hw_dev_num;
87501ef306SVadym Kochan 	u32 words[4] = { 0 };
88501ef306SVadym Kochan 
89501ef306SVadym Kochan 	words[0] |= FIELD_PREP(PRESTERA_DSA_W0_CMD, PRESTERA_DSA_CMD_FROM_CPU);
90501ef306SVadym Kochan 
91501ef306SVadym Kochan 	words[0] |= FIELD_PREP(PRESTERA_DSA_W0_DEV_NUM, dev_num);
92501ef306SVadym Kochan 	dev_num = FIELD_GET(PRESTERA_DSA_DEV_NUM, dev_num);
93501ef306SVadym Kochan 	words[3] |= FIELD_PREP(PRESTERA_DSA_W3_DEV_NUM, dev_num);
94501ef306SVadym Kochan 
95501ef306SVadym Kochan 	words[3] |= FIELD_PREP(PRESTERA_DSA_W3_DST_EPORT, dsa->port_num);
96501ef306SVadym Kochan 
97501ef306SVadym Kochan 	words[0] |= FIELD_PREP(PRESTERA_DSA_W0_EXT_BIT, 1);
98501ef306SVadym Kochan 	words[1] |= FIELD_PREP(PRESTERA_DSA_W1_EXT_BIT, 1);
99501ef306SVadym Kochan 	words[2] |= FIELD_PREP(PRESTERA_DSA_W2_EXT_BIT, 1);
100501ef306SVadym Kochan 
101501ef306SVadym Kochan 	dsa_words[0] = htonl(words[0]);
102501ef306SVadym Kochan 	dsa_words[1] = htonl(words[1]);
103501ef306SVadym Kochan 	dsa_words[2] = htonl(words[2]);
104501ef306SVadym Kochan 	dsa_words[3] = htonl(words[3]);
105501ef306SVadym Kochan 
106501ef306SVadym Kochan 	return 0;
107501ef306SVadym Kochan }
108