1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /*
3  * Microsemi Ocelot Switch driver
4  *
5  * Copyright (c) 2017 Microsemi Corporation
6  */
7 #include <linux/interrupt.h>
8 #include <linux/module.h>
9 #include <linux/netdevice.h>
10 #include <linux/of_mdio.h>
11 #include <linux/of_platform.h>
12 #include <linux/skbuff.h>
13 
14 #include "ocelot.h"
15 
ocelot_parse_ifh(u32 * ifh,struct frame_info * info)16 static int ocelot_parse_ifh(u32 *ifh, struct frame_info *info)
17 {
18 	int i;
19 	u8 llen, wlen;
20 
21 	/* The IFH is in network order, switch to CPU order */
22 	for (i = 0; i < IFH_LEN; i++)
23 		ifh[i] = ntohl((__force __be32)ifh[i]);
24 
25 	wlen = (ifh[1] >> 7) & 0xff;
26 	llen = (ifh[1] >> 15) & 0x3f;
27 	info->len = OCELOT_BUFFER_CELL_SZ * wlen + llen - 80;
28 
29 	info->port = (ifh[2] & GENMASK(14, 11)) >> 11;
30 
31 	info->cpuq = (ifh[3] & GENMASK(27, 20)) >> 20;
32 	info->tag_type = (ifh[3] & BIT(16)) >> 16;
33 	info->vid = ifh[3] & GENMASK(11, 0);
34 
35 	return 0;
36 }
37 
ocelot_rx_frame_word(struct ocelot * ocelot,u8 grp,bool ifh,u32 * rval)38 static int ocelot_rx_frame_word(struct ocelot *ocelot, u8 grp, bool ifh,
39 				u32 *rval)
40 {
41 	u32 val;
42 	u32 bytes_valid;
43 
44 	val = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
45 	if (val == XTR_NOT_READY) {
46 		if (ifh)
47 			return -EIO;
48 
49 		do {
50 			val = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
51 		} while (val == XTR_NOT_READY);
52 	}
53 
54 	switch (val) {
55 	case XTR_ABORT:
56 		return -EIO;
57 	case XTR_EOF_0:
58 	case XTR_EOF_1:
59 	case XTR_EOF_2:
60 	case XTR_EOF_3:
61 	case XTR_PRUNED:
62 		bytes_valid = XTR_VALID_BYTES(val);
63 		val = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
64 		if (val == XTR_ESCAPE)
65 			*rval = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
66 		else
67 			*rval = val;
68 
69 		return bytes_valid;
70 	case XTR_ESCAPE:
71 		*rval = ocelot_read_rix(ocelot, QS_XTR_RD, grp);
72 
73 		return 4;
74 	default:
75 		*rval = val;
76 
77 		return 4;
78 	}
79 }
80 
ocelot_xtr_irq_handler(int irq,void * arg)81 static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
82 {
83 	struct ocelot *ocelot = arg;
84 	int i = 0, grp = 0;
85 	int err = 0;
86 
87 	if (!(ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)))
88 		return IRQ_NONE;
89 
90 	do {
91 		struct sk_buff *skb;
92 		struct net_device *dev;
93 		u32 *buf;
94 		int sz, len, buf_len;
95 		u32 ifh[4];
96 		u32 val;
97 		struct frame_info info;
98 
99 		for (i = 0; i < IFH_LEN; i++) {
100 			err = ocelot_rx_frame_word(ocelot, grp, true, &ifh[i]);
101 			if (err != 4)
102 				break;
103 		}
104 
105 		if (err != 4)
106 			break;
107 
108 		ocelot_parse_ifh(ifh, &info);
109 
110 		dev = ocelot->ports[info.port]->dev;
111 
112 		skb = netdev_alloc_skb(dev, info.len);
113 
114 		if (unlikely(!skb)) {
115 			netdev_err(dev, "Unable to allocate sk_buff\n");
116 			err = -ENOMEM;
117 			break;
118 		}
119 		buf_len = info.len - ETH_FCS_LEN;
120 		buf = (u32 *)skb_put(skb, buf_len);
121 
122 		len = 0;
123 		do {
124 			sz = ocelot_rx_frame_word(ocelot, grp, false, &val);
125 			*buf++ = val;
126 			len += sz;
127 		} while (len < buf_len);
128 
129 		/* Read the FCS and discard it */
130 		sz = ocelot_rx_frame_word(ocelot, grp, false, &val);
131 		/* Update the statistics if part of the FCS was read before */
132 		len -= ETH_FCS_LEN - sz;
133 
134 		if (sz < 0) {
135 			err = sz;
136 			break;
137 		}
138 
139 		/* Everything we see on an interface that is in the HW bridge
140 		 * has already been forwarded.
141 		 */
142 		if (ocelot->bridge_mask & BIT(info.port))
143 			skb->offload_fwd_mark = 1;
144 
145 		skb->protocol = eth_type_trans(skb, dev);
146 		netif_rx(skb);
147 		dev->stats.rx_bytes += len;
148 		dev->stats.rx_packets++;
149 	} while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp));
150 
151 	if (err)
152 		while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp))
153 			ocelot_read_rix(ocelot, QS_XTR_RD, grp);
154 
155 	return IRQ_HANDLED;
156 }
157 
158 static const struct of_device_id mscc_ocelot_match[] = {
159 	{ .compatible = "mscc,vsc7514-switch" },
160 	{ }
161 };
162 MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
163 
mscc_ocelot_probe(struct platform_device * pdev)164 static int mscc_ocelot_probe(struct platform_device *pdev)
165 {
166 	int err, irq;
167 	unsigned int i;
168 	struct device_node *np = pdev->dev.of_node;
169 	struct device_node *ports, *portnp;
170 	struct ocelot *ocelot;
171 	u32 val;
172 
173 	struct {
174 		enum ocelot_target id;
175 		char *name;
176 	} res[] = {
177 		{ SYS, "sys" },
178 		{ REW, "rew" },
179 		{ QSYS, "qsys" },
180 		{ ANA, "ana" },
181 		{ QS, "qs" },
182 		{ HSIO, "hsio" },
183 	};
184 
185 	if (!np && !pdev->dev.platform_data)
186 		return -ENODEV;
187 
188 	ocelot = devm_kzalloc(&pdev->dev, sizeof(*ocelot), GFP_KERNEL);
189 	if (!ocelot)
190 		return -ENOMEM;
191 
192 	platform_set_drvdata(pdev, ocelot);
193 	ocelot->dev = &pdev->dev;
194 
195 	for (i = 0; i < ARRAY_SIZE(res); i++) {
196 		struct regmap *target;
197 
198 		target = ocelot_io_platform_init(ocelot, pdev, res[i].name);
199 		if (IS_ERR(target))
200 			return PTR_ERR(target);
201 
202 		ocelot->targets[res[i].id] = target;
203 	}
204 
205 	err = ocelot_chip_init(ocelot);
206 	if (err)
207 		return err;
208 
209 	irq = platform_get_irq_byname(pdev, "xtr");
210 	if (irq < 0)
211 		return -ENODEV;
212 
213 	err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
214 					ocelot_xtr_irq_handler, IRQF_ONESHOT,
215 					"frame extraction", ocelot);
216 	if (err)
217 		return err;
218 
219 	regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1);
220 	regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
221 
222 	do {
223 		msleep(1);
224 		regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT],
225 				  &val);
226 	} while (val);
227 
228 	regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
229 	regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1);
230 
231 	ocelot->num_cpu_ports = 1; /* 1 port on the switch, two groups */
232 
233 	ports = of_get_child_by_name(np, "ethernet-ports");
234 	if (!ports) {
235 		dev_err(&pdev->dev, "no ethernet-ports child node found\n");
236 		return -ENODEV;
237 	}
238 
239 	ocelot->num_phys_ports = of_get_child_count(ports);
240 
241 	ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports,
242 				     sizeof(struct ocelot_port *), GFP_KERNEL);
243 
244 	INIT_LIST_HEAD(&ocelot->multicast);
245 	ocelot_init(ocelot);
246 
247 	ocelot_rmw(ocelot, HSIO_HW_CFG_DEV1G_4_MODE |
248 		     HSIO_HW_CFG_DEV1G_6_MODE |
249 		     HSIO_HW_CFG_DEV1G_9_MODE,
250 		     HSIO_HW_CFG_DEV1G_4_MODE |
251 		     HSIO_HW_CFG_DEV1G_6_MODE |
252 		     HSIO_HW_CFG_DEV1G_9_MODE,
253 		     HSIO_HW_CFG);
254 
255 	for_each_available_child_of_node(ports, portnp) {
256 		struct device_node *phy_node;
257 		struct phy_device *phy;
258 		struct resource *res;
259 		void __iomem *regs;
260 		char res_name[8];
261 		u32 port;
262 
263 		if (of_property_read_u32(portnp, "reg", &port))
264 			continue;
265 
266 		snprintf(res_name, sizeof(res_name), "port%d", port);
267 
268 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
269 						   res_name);
270 		regs = devm_ioremap_resource(&pdev->dev, res);
271 		if (IS_ERR(regs))
272 			continue;
273 
274 		phy_node = of_parse_phandle(portnp, "phy-handle", 0);
275 		if (!phy_node)
276 			continue;
277 
278 		phy = of_phy_find_device(phy_node);
279 		if (!phy)
280 			continue;
281 
282 		err = ocelot_probe_port(ocelot, port, regs, phy);
283 		if (err) {
284 			dev_err(&pdev->dev, "failed to probe ports\n");
285 			goto err_probe_ports;
286 		}
287 	}
288 
289 	register_netdevice_notifier(&ocelot_netdevice_nb);
290 
291 	dev_info(&pdev->dev, "Ocelot switch probed\n");
292 
293 	return 0;
294 
295 err_probe_ports:
296 	return err;
297 }
298 
mscc_ocelot_remove(struct platform_device * pdev)299 static int mscc_ocelot_remove(struct platform_device *pdev)
300 {
301 	struct ocelot *ocelot = platform_get_drvdata(pdev);
302 
303 	ocelot_deinit(ocelot);
304 	unregister_netdevice_notifier(&ocelot_netdevice_nb);
305 
306 	return 0;
307 }
308 
309 static struct platform_driver mscc_ocelot_driver = {
310 	.probe = mscc_ocelot_probe,
311 	.remove = mscc_ocelot_remove,
312 	.driver = {
313 		.name = "ocelot-switch",
314 		.of_match_table = mscc_ocelot_match,
315 	},
316 };
317 
318 module_platform_driver(mscc_ocelot_driver);
319 
320 MODULE_DESCRIPTION("Microsemi Ocelot switch driver");
321 MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
322 MODULE_LICENSE("Dual MIT/GPL");
323