summaryrefslogtreecommitdiff
path: root/target/linux/mediatek/patches-4.14/0033-dsa-multi-cpu.patch
blob: 5c4edec077b1881723afa33b137e3105d26da92f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -670,6 +670,9 @@ static int
 mt7530_cpu_port_enable(struct mt7530_priv *priv,
 		       int port)
 {
+	u8 port_mask = 0;
+	int i;
+
 	/* Enable Mediatek header mode on the cpu port */
 	mt7530_write(priv, MT7530_PVC_P(port),
 		     PORT_SPEC_TAG);
@@ -686,8 +689,12 @@ mt7530_cpu_port_enable(struct mt7530_pri
 	/* CPU port gets connected to all user ports of
 	 * the switch
 	 */
+	for (i = 0; i < MT7530_NUM_PORTS; i++)
+		if ((priv->ds->enabled_port_mask & BIT(i)) &&
+		    (dsa_port_upstream_port(priv->ds, i) == port))
+			port_mask |= BIT(i);
 	mt7530_write(priv, MT7530_PCR_P(port),
-		     PCR_MATRIX(priv->ds->enabled_port_mask));
+		     PCR_MATRIX(port_mask));
 
 	return 0;
 }
@@ -697,6 +704,7 @@ mt7530_port_enable(struct dsa_switch *ds
 		   struct phy_device *phy)
 {
 	struct mt7530_priv *priv = ds->priv;
+	u8 upstream = dsa_port_upstream_port(ds, port);
 
 	mutex_lock(&priv->reg_mutex);
 
@@ -707,7 +715,7 @@ mt7530_port_enable(struct dsa_switch *ds
 	 * restore the port matrix if the port is the member of a certain
 	 * bridge.
 	 */
-	priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT));
+	priv->ports[port].pm |= PCR_MATRIX(BIT(upstream));
 	priv->ports[port].enable = true;
 	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
 		   priv->ports[port].pm);
@@ -770,7 +778,8 @@ mt7530_port_bridge_join(struct dsa_switc
 			struct net_device *bridge)
 {
 	struct mt7530_priv *priv = ds->priv;
-	u32 port_bitmap = BIT(MT7530_CPU_PORT);
+	u8 upstream = dsa_port_upstream_port(ds, port);
+	u32 port_bitmap = BIT(upstream);
 	int i;
 
 	mutex_lock(&priv->reg_mutex);
@@ -808,6 +817,7 @@ mt7530_port_bridge_leave(struct dsa_swit
 			 struct net_device *bridge)
 {
 	struct mt7530_priv *priv = ds->priv;
+	u8 upstream = dsa_port_upstream_port(ds, port);
 	int i;
 
 	mutex_lock(&priv->reg_mutex);
@@ -832,8 +842,8 @@ mt7530_port_bridge_leave(struct dsa_swit
 	 */
 	if (priv->ports[port].enable)
 		mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
-			   PCR_MATRIX(BIT(MT7530_CPU_PORT)));
-	priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT));
+			   PCR_MATRIX(BIT(upstream)));
+	priv->ports[port].pm = PCR_MATRIX(BIT(upstream));
 
 	mutex_unlock(&priv->reg_mutex);
 }
@@ -908,15 +918,7 @@ err:
 static enum dsa_tag_protocol
 mtk_get_tag_protocol(struct dsa_switch *ds)
 {
-	struct mt7530_priv *priv = ds->priv;
-
-	if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) {
-		dev_warn(priv->dev,
-			 "port not matched with tagging CPU port\n");
-		return DSA_TAG_PROTO_NONE;
-	} else {
-		return DSA_TAG_PROTO_MTK;
-	}
+	return DSA_TAG_PROTO_MTK;
 }
 
 static int
@@ -989,7 +991,7 @@ mt7530_setup(struct dsa_switch *ds)
 
 	/* Enable Port 6 only; P5 as GMAC5 which currently is not supported */
 	val = mt7530_read(priv, MT7530_MHWTRAP);
-	val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
+	val &= ~MHWTRAP_P5_DIS & ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
 	val |= MHWTRAP_MANUAL;
 	if (!dsa_is_cpu_port(ds, 5)) {
 		val |= MHWTRAP_P5_DIS;
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -185,6 +185,10 @@ struct dsa_port {
 	u8			stp_state;
 	struct net_device	*bridge_dev;
 	struct devlink_port	devlink_port;
+
+	struct net_device	*ethernet;
+	int			upstream;
+
 	/*
 	 * Original copy of the master netdev ethtool_ops
 	 */
@@ -266,6 +270,11 @@ static inline bool dsa_is_normal_port(st
 	return !dsa_is_cpu_port(ds, p) && !dsa_is_dsa_port(ds, p);
 }
 
+static inline bool dsa_is_upstream_port(struct dsa_switch *ds, int p)
+{
+	return dsa_is_cpu_port(ds, p) || dsa_is_dsa_port(ds, p);
+}
+
 static inline u8 dsa_upstream_port(struct dsa_switch *ds)
 {
 	struct dsa_switch_tree *dst = ds->dst;
@@ -282,6 +291,18 @@ static inline u8 dsa_upstream_port(struc
 		return ds->rtable[dst->cpu_dp->ds->index];
 }
 
+static inline u8 dsa_port_upstream_port(struct dsa_switch *ds, int port)
+{
+	/*
+	 * If this port has a specific upstream cpu port, use it,
+	 * otherwise use the switch default.
+	 */
+	if (ds->ports[port].upstream)
+		return ds->ports[port].upstream;
+	else
+		return dsa_upstream_port(ds);
+}
+
 typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid,
 			      bool is_static, void *data);
 struct dsa_switch_ops {
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -253,6 +253,8 @@ static int dsa_cpu_port_apply(struct dsa
 	memset(&port->devlink_port, 0, sizeof(port->devlink_port));
 	err = devlink_port_register(ds->devlink, &port->devlink_port,
 				    port->index);
+	if (port->netdev)
+		port->netdev->dsa_ptr = ds->dst;
 	return err;
 }
 
@@ -262,6 +264,12 @@ static void dsa_cpu_port_unapply(struct
 	dsa_cpu_dsa_destroy(port);
 	port->ds->cpu_port_mask &= ~BIT(port->index);
 
+	if (port->netdev)
+		port->netdev->dsa_ptr = NULL;
+	if (port->ethernet) {
+		dev_put(port->ethernet);
+		port->ethernet = NULL;
+	}
 }
 
 static int dsa_user_port_apply(struct dsa_port *port)
@@ -505,10 +513,9 @@ static int dsa_cpu_parse(struct dsa_port
 		dev_put(ethernet_dev);
 	}
 
-	if (!dst->cpu_dp) {
+	if (!dst->cpu_dp)
 		dst->cpu_dp = port;
-		dst->cpu_dp->netdev = ethernet_dev;
-	}
+	port->netdev = ethernet_dev;
 
 	/* Initialize cpu_port_mask now for drv->setup()
 	 * to have access to a correct value, just like what
@@ -526,6 +533,29 @@ static int dsa_cpu_parse(struct dsa_port
 
 	dst->rcv = dst->tag_ops->rcv;
 
+	dev_hold(ethernet_dev);
+	ds->ports[index].ethernet = ethernet_dev;
+	ds->cpu_port_mask |= BIT(index);
+
+	return 0;
+}
+
+static int dsa_user_parse(struct dsa_port *port, u32 index,
+			  struct dsa_switch *ds)
+{
+	struct device_node *cpu_port;
+	const unsigned int *cpu_port_reg;
+	int cpu_port_index;
+
+	cpu_port = of_parse_phandle(port->dn, "cpu", 0);
+	if (cpu_port) {
+		cpu_port_reg = of_get_property(cpu_port, "reg", NULL);
+		if (!cpu_port_reg)
+			return -EINVAL;
+		cpu_port_index = be32_to_cpup(cpu_port_reg);
+		ds->ports[index].upstream = cpu_port_index;
+	}
+
 	return 0;
 }
 
@@ -533,7 +563,7 @@ static int dsa_ds_parse(struct dsa_switc
 {
 	struct dsa_port *port;
 	u32 index;
-	int err;
+	int err = 0;
 
 	for (index = 0; index < ds->num_ports; index++) {
 		port = &ds->ports[index];
@@ -546,6 +576,9 @@ static int dsa_ds_parse(struct dsa_switc
 			if (err)
 				return err;
 		} else {
+			err = dsa_user_parse(port, index, ds);
+			if (err)
+				return err;
 			/* Initialize enabled_port_mask now for drv->setup()
 			 * to have access to a correct value, just like what
 			 * net/dsa/dsa.c::dsa_switch_setup_one does.
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -91,6 +91,8 @@ struct dsa_slave_priv {
 
 	/* TC context */
 	struct list_head	mall_tc_list;
+
+	struct net_device       *master;
 };
 
 /* dsa.c */
@@ -177,6 +179,9 @@ extern const struct dsa_device_ops trail
 
 static inline struct net_device *dsa_master_netdev(struct dsa_slave_priv *p)
 {
+	if (p->master)
+		return p->master;
+
 	return p->dp->cpu_dp->netdev;
 }
 
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -1257,7 +1257,7 @@ int dsa_slave_create(struct dsa_port *po
 	int ret;
 
 	cpu_dp = ds->dst->cpu_dp;
-	master = cpu_dp->netdev;
+	master = ds->ports[port->upstream].ethernet;
 
 	if (!ds->num_tx_queues)
 		ds->num_tx_queues = 1;
@@ -1295,6 +1295,7 @@ int dsa_slave_create(struct dsa_port *po
 	p->dp = port;
 	INIT_LIST_HEAD(&p->mall_tc_list);
 	p->xmit = dst->tag_ops->xmit;
+	p->master = master;
 
 	p->old_pause = -1;
 	p->old_link = -1;