431 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2/*3 * Microsemi Ocelot Switch driver4 *5 * Copyright (c) 2017 Microsemi Corporation6 */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 12827#define VSC7514_VCAP_POLICER_MAX 19128 29static 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 49static 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 70out: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 79static 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 88static const struct of_device_id mscc_ocelot_match[] = {89 { .compatible = "mscc,vsc7514-switch" },90 { }91};92MODULE_DEVICE_TABLE(of, mscc_ocelot_match);93 94static 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 103static 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 120static 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 128static 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 144static 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", ®))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 223out_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 234static 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 387out_ocelot_release_ports:388 mscc_ocelot_release_ports(ocelot);389 mscc_ocelot_teardown_devlink_ports(ocelot);390out_ocelot_devlink_unregister:391 ocelot_deinit(ocelot);392out_put_ports:393 of_node_put(ports);394out_free_devlink:395 devlink_free(devlink);396 return err;397}398 399static 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 417static struct platform_driver mscc_ocelot_driver = {418 .probe = mscc_ocelot_probe,419 .remove_new = mscc_ocelot_remove,420 .driver = {421 .name = "ocelot-switch",422 .of_match_table = mscc_ocelot_match,423 },424};425 426module_platform_driver(mscc_ocelot_driver);427 428MODULE_DESCRIPTION("Microsemi Ocelot switch driver");429MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");430MODULE_LICENSE("Dual MIT/GPL");431