xref: /linux/drivers/net/ethernet/mscc/ocelot_vsc7514.c (revision 3fd6c59042dbba50391e30862beac979491145fe)
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/dsa/ocelot.h>
8 #include <linux/interrupt.h>
9 #include <linux/module.h>
10 #include <linux/of_net.h>
11 #include <linux/netdevice.h>
12 #include <linux/phylink.h>
13 #include <linux/of.h>
14 #include <linux/of_mdio.h>
15 #include <linux/platform_device.h>
16 #include <linux/mfd/syscon.h>
17 #include <linux/skbuff.h>
18 #include <net/switchdev.h>
19 
20 #include <soc/mscc/ocelot.h>
21 #include <soc/mscc/ocelot_vcap.h>
22 #include <soc/mscc/vsc7514_regs.h>
23 #include "ocelot_fdma.h"
24 #include "ocelot.h"
25 
26 #define VSC7514_VCAP_POLICER_BASE			128
27 #define VSC7514_VCAP_POLICER_MAX			191
28 
ocelot_chip_init(struct ocelot * ocelot,const struct ocelot_ops * ops)29 static int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops)
30 {
31 	int ret;
32 
33 	ocelot->map = vsc7514_regmap;
34 	ocelot->num_mact_rows = 1024;
35 	ocelot->ops = ops;
36 
37 	ret = ocelot_regfields_init(ocelot, vsc7514_regfields);
38 	if (ret)
39 		return ret;
40 
41 	ocelot_pll5_init(ocelot);
42 
43 	eth_random_addr(ocelot->base_mac);
44 	ocelot->base_mac[5] &= 0xf0;
45 
46 	return 0;
47 }
48 
ocelot_xtr_irq_handler(int irq,void * arg)49 static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
50 {
51 	struct ocelot *ocelot = arg;
52 	int grp = 0, err;
53 
54 	ocelot_lock_xtr_grp(ocelot, grp);
55 
56 	while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)) {
57 		struct sk_buff *skb;
58 
59 		err = ocelot_xtr_poll_frame(ocelot, grp, &skb);
60 		if (err)
61 			goto out;
62 
63 		skb->dev->stats.rx_bytes += skb->len;
64 		skb->dev->stats.rx_packets++;
65 
66 		if (!skb_defer_rx_timestamp(skb))
67 			netif_rx(skb);
68 	}
69 
70 out:
71 	if (err < 0)
72 		ocelot_drain_cpu_queue(ocelot, 0);
73 
74 	ocelot_unlock_xtr_grp(ocelot, grp);
75 
76 	return IRQ_HANDLED;
77 }
78 
ocelot_ptp_rdy_irq_handler(int irq,void * arg)79 static irqreturn_t ocelot_ptp_rdy_irq_handler(int irq, void *arg)
80 {
81 	struct ocelot *ocelot = arg;
82 
83 	ocelot_get_txtstamp(ocelot);
84 
85 	return IRQ_HANDLED;
86 }
87 
88 static const struct of_device_id mscc_ocelot_match[] = {
89 	{ .compatible = "mscc,vsc7514-switch" },
90 	{ }
91 };
92 MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
93 
94 static const struct ocelot_ops ocelot_ops = {
95 	.reset			= ocelot_reset,
96 	.wm_enc			= ocelot_wm_enc,
97 	.wm_dec			= ocelot_wm_dec,
98 	.wm_stat		= ocelot_wm_stat,
99 	.port_to_netdev		= ocelot_port_to_netdev,
100 	.netdev_to_port		= ocelot_netdev_to_port,
101 };
102 
103 static struct ptp_clock_info ocelot_ptp_clock_info = {
104 	.owner		= THIS_MODULE,
105 	.name		= "ocelot ptp",
106 	.max_adj	= 0x7fffffff,
107 	.n_alarm	= 0,
108 	.n_ext_ts	= 0,
109 	.n_per_out	= OCELOT_PTP_PINS_NUM,
110 	.n_pins		= OCELOT_PTP_PINS_NUM,
111 	.pps		= 0,
112 	.gettime64	= ocelot_ptp_gettime64,
113 	.settime64	= ocelot_ptp_settime64,
114 	.adjtime	= ocelot_ptp_adjtime,
115 	.adjfine	= ocelot_ptp_adjfine,
116 	.verify		= ocelot_ptp_verify,
117 	.enable		= ocelot_ptp_enable,
118 };
119 
mscc_ocelot_teardown_devlink_ports(struct ocelot * ocelot)120 static void mscc_ocelot_teardown_devlink_ports(struct ocelot *ocelot)
121 {
122 	int port;
123 
124 	for (port = 0; port < ocelot->num_phys_ports; port++)
125 		ocelot_port_devlink_teardown(ocelot, port);
126 }
127 
mscc_ocelot_release_ports(struct ocelot * ocelot)128 static void mscc_ocelot_release_ports(struct ocelot *ocelot)
129 {
130 	int port;
131 
132 	for (port = 0; port < ocelot->num_phys_ports; port++) {
133 		struct ocelot_port *ocelot_port;
134 
135 		ocelot_port = ocelot->ports[port];
136 		if (!ocelot_port)
137 			continue;
138 
139 		ocelot_deinit_port(ocelot, port);
140 		ocelot_release_port(ocelot_port);
141 	}
142 }
143 
mscc_ocelot_init_ports(struct platform_device * pdev,struct device_node * ports)144 static int mscc_ocelot_init_ports(struct platform_device *pdev,
145 				  struct device_node *ports)
146 {
147 	struct ocelot *ocelot = platform_get_drvdata(pdev);
148 	u32 devlink_ports_registered = 0;
149 	struct device_node *portnp;
150 	int port, err;
151 	u32 reg;
152 
153 	ocelot->ports = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports,
154 				     sizeof(struct ocelot_port *), GFP_KERNEL);
155 	if (!ocelot->ports)
156 		return -ENOMEM;
157 
158 	ocelot->devlink_ports = devm_kcalloc(ocelot->dev,
159 					     ocelot->num_phys_ports,
160 					     sizeof(*ocelot->devlink_ports),
161 					     GFP_KERNEL);
162 	if (!ocelot->devlink_ports)
163 		return -ENOMEM;
164 
165 	for_each_available_child_of_node(ports, portnp) {
166 		struct regmap *target;
167 		struct resource *res;
168 		char res_name[8];
169 
170 		if (of_property_read_u32(portnp, "reg", &reg))
171 			continue;
172 
173 		port = reg;
174 		if (port < 0 || port >= ocelot->num_phys_ports) {
175 			dev_err(ocelot->dev,
176 				"invalid port number: %d >= %d\n", port,
177 				ocelot->num_phys_ports);
178 			continue;
179 		}
180 
181 		snprintf(res_name, sizeof(res_name), "port%d", port);
182 
183 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
184 						   res_name);
185 		target = ocelot_regmap_init(ocelot, res);
186 		if (IS_ERR(target)) {
187 			err = PTR_ERR(target);
188 			of_node_put(portnp);
189 			goto out_teardown;
190 		}
191 
192 		err = ocelot_port_devlink_init(ocelot, port,
193 					       DEVLINK_PORT_FLAVOUR_PHYSICAL);
194 		if (err) {
195 			of_node_put(portnp);
196 			goto out_teardown;
197 		}
198 
199 		err = ocelot_probe_port(ocelot, port, target, portnp);
200 		if (err) {
201 			ocelot_port_devlink_teardown(ocelot, port);
202 			continue;
203 		}
204 
205 		devlink_ports_registered |= BIT(port);
206 	}
207 
208 	/* Initialize unused devlink ports at the end */
209 	for (port = 0; port < ocelot->num_phys_ports; port++) {
210 		if (devlink_ports_registered & BIT(port))
211 			continue;
212 
213 		err = ocelot_port_devlink_init(ocelot, port,
214 					       DEVLINK_PORT_FLAVOUR_UNUSED);
215 		if (err)
216 			goto out_teardown;
217 
218 		devlink_ports_registered |= BIT(port);
219 	}
220 
221 	return 0;
222 
223 out_teardown:
224 	/* Unregister the network interfaces */
225 	mscc_ocelot_release_ports(ocelot);
226 	/* Tear down devlink ports for the registered network interfaces */
227 	for (port = 0; port < ocelot->num_phys_ports; port++) {
228 		if (devlink_ports_registered & BIT(port))
229 			ocelot_port_devlink_teardown(ocelot, port);
230 	}
231 	return err;
232 }
233 
mscc_ocelot_probe(struct platform_device * pdev)234 static int mscc_ocelot_probe(struct platform_device *pdev)
235 {
236 	struct device_node *np = pdev->dev.of_node;
237 	int err, irq_xtr, irq_ptp_rdy;
238 	struct device_node *ports;
239 	struct devlink *devlink;
240 	struct ocelot *ocelot;
241 	struct regmap *hsio;
242 	unsigned int i;
243 
244 	struct {
245 		enum ocelot_target id;
246 		char *name;
247 		u8 optional:1;
248 	} io_target[] = {
249 		{ SYS, "sys" },
250 		{ REW, "rew" },
251 		{ QSYS, "qsys" },
252 		{ ANA, "ana" },
253 		{ QS, "qs" },
254 		{ S0, "s0" },
255 		{ S1, "s1" },
256 		{ S2, "s2" },
257 		{ PTP, "ptp", 1 },
258 		{ FDMA, "fdma", 1 },
259 	};
260 
261 	if (!np && !pdev->dev.platform_data)
262 		return -ENODEV;
263 
264 	devlink =
265 		devlink_alloc(&ocelot_devlink_ops, sizeof(*ocelot), &pdev->dev);
266 	if (!devlink)
267 		return -ENOMEM;
268 
269 	ocelot = devlink_priv(devlink);
270 	ocelot->devlink = priv_to_devlink(ocelot);
271 	platform_set_drvdata(pdev, ocelot);
272 	ocelot->dev = &pdev->dev;
273 
274 	for (i = 0; i < ARRAY_SIZE(io_target); i++) {
275 		struct regmap *target;
276 		struct resource *res;
277 
278 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
279 						   io_target[i].name);
280 
281 		target = ocelot_regmap_init(ocelot, res);
282 		if (IS_ERR(target)) {
283 			if (io_target[i].optional) {
284 				ocelot->targets[io_target[i].id] = NULL;
285 				continue;
286 			}
287 			err = PTR_ERR(target);
288 			goto out_free_devlink;
289 		}
290 
291 		ocelot->targets[io_target[i].id] = target;
292 	}
293 
294 	if (ocelot->targets[FDMA])
295 		ocelot_fdma_init(pdev, ocelot);
296 
297 	hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio");
298 	if (IS_ERR(hsio)) {
299 		dev_err(&pdev->dev, "missing hsio syscon\n");
300 		err = PTR_ERR(hsio);
301 		goto out_free_devlink;
302 	}
303 
304 	ocelot->targets[HSIO] = hsio;
305 
306 	err = ocelot_chip_init(ocelot, &ocelot_ops);
307 	if (err)
308 		goto out_free_devlink;
309 
310 	irq_xtr = platform_get_irq_byname(pdev, "xtr");
311 	if (irq_xtr < 0) {
312 		err = irq_xtr;
313 		goto out_free_devlink;
314 	}
315 
316 	err = devm_request_threaded_irq(&pdev->dev, irq_xtr, NULL,
317 					ocelot_xtr_irq_handler, IRQF_ONESHOT,
318 					"frame extraction", ocelot);
319 	if (err)
320 		goto out_free_devlink;
321 
322 	irq_ptp_rdy = platform_get_irq_byname(pdev, "ptp_rdy");
323 	if (irq_ptp_rdy > 0 && ocelot->targets[PTP]) {
324 		err = devm_request_threaded_irq(&pdev->dev, irq_ptp_rdy, NULL,
325 						ocelot_ptp_rdy_irq_handler,
326 						IRQF_ONESHOT, "ptp ready",
327 						ocelot);
328 		if (err)
329 			goto out_free_devlink;
330 
331 		/* Both the PTP interrupt and the PTP bank are available */
332 		ocelot->ptp = 1;
333 	}
334 
335 	ports = of_get_child_by_name(np, "ethernet-ports");
336 	if (!ports) {
337 		dev_err(ocelot->dev, "no ethernet-ports child node found\n");
338 		err = -ENODEV;
339 		goto out_free_devlink;
340 	}
341 
342 	ocelot->num_phys_ports = of_get_child_count(ports);
343 	ocelot->num_flooding_pgids = 1;
344 
345 	ocelot->vcap = vsc7514_vcap_props;
346 
347 	ocelot->vcap_pol.base = VSC7514_VCAP_POLICER_BASE;
348 	ocelot->vcap_pol.max = VSC7514_VCAP_POLICER_MAX;
349 
350 	ocelot->npi = -1;
351 
352 	err = ocelot_init(ocelot);
353 	if (err)
354 		goto out_put_ports;
355 
356 	err = mscc_ocelot_init_ports(pdev, ports);
357 	if (err)
358 		goto out_ocelot_devlink_unregister;
359 
360 	if (ocelot->fdma)
361 		ocelot_fdma_start(ocelot);
362 
363 	err = ocelot_devlink_sb_register(ocelot);
364 	if (err)
365 		goto out_ocelot_release_ports;
366 
367 	if (ocelot->ptp) {
368 		err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info);
369 		if (err) {
370 			dev_err(ocelot->dev,
371 				"Timestamp initialization failed\n");
372 			ocelot->ptp = 0;
373 		}
374 	}
375 
376 	register_netdevice_notifier(&ocelot_netdevice_nb);
377 	register_switchdev_notifier(&ocelot_switchdev_nb);
378 	register_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
379 
380 	of_node_put(ports);
381 	devlink_register(devlink);
382 
383 	dev_info(&pdev->dev, "Ocelot switch probed\n");
384 
385 	return 0;
386 
387 out_ocelot_release_ports:
388 	mscc_ocelot_release_ports(ocelot);
389 	mscc_ocelot_teardown_devlink_ports(ocelot);
390 out_ocelot_devlink_unregister:
391 	ocelot_deinit(ocelot);
392 out_put_ports:
393 	of_node_put(ports);
394 out_free_devlink:
395 	devlink_free(devlink);
396 	return err;
397 }
398 
mscc_ocelot_remove(struct platform_device * pdev)399 static void mscc_ocelot_remove(struct platform_device *pdev)
400 {
401 	struct ocelot *ocelot = platform_get_drvdata(pdev);
402 
403 	if (ocelot->fdma)
404 		ocelot_fdma_deinit(ocelot);
405 	devlink_unregister(ocelot->devlink);
406 	ocelot_deinit_timestamp(ocelot);
407 	ocelot_devlink_sb_unregister(ocelot);
408 	mscc_ocelot_release_ports(ocelot);
409 	mscc_ocelot_teardown_devlink_ports(ocelot);
410 	ocelot_deinit(ocelot);
411 	unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
412 	unregister_switchdev_notifier(&ocelot_switchdev_nb);
413 	unregister_netdevice_notifier(&ocelot_netdevice_nb);
414 	devlink_free(ocelot->devlink);
415 }
416 
417 static struct platform_driver mscc_ocelot_driver = {
418 	.probe = mscc_ocelot_probe,
419 	.remove = mscc_ocelot_remove,
420 	.driver = {
421 		.name = "ocelot-switch",
422 		.of_match_table = mscc_ocelot_match,
423 	},
424 };
425 
426 module_platform_driver(mscc_ocelot_driver);
427 
428 MODULE_DESCRIPTION("Microsemi Ocelot switch driver");
429 MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
430 MODULE_LICENSE("Dual MIT/GPL");
431