blob: 78ffc87dc25eb06114ee9165ed1a1dfd869720da [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00002/*
3 * net/dsa/slave.c - Slave device handling
Lennert Buytenheke84665c2009-03-20 09:52:09 +00004 * Copyright (c) 2008-2009 Marvell Semiconductor
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00005 */
6
7#include <linux/list.h>
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -08008#include <linux/etherdevice.h>
Florian Fainellib73adef2015-02-24 13:15:33 -08009#include <linux/netdevice.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000010#include <linux/phy.h>
Florian Fainellia2820542014-10-17 16:02:13 -070011#include <linux/phy_fixed.h>
Florian Fainelliaab9c402018-05-10 13:17:36 -070012#include <linux/phylink.h>
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -070013#include <linux/of_net.h>
14#include <linux/of_mdio.h>
Andrew Lunn7f854422016-01-06 20:11:18 +010015#include <linux/mdio.h>
Florian Fainellib73adef2015-02-24 13:15:33 -080016#include <net/rtnetlink.h>
Florian Fainellif50f2122017-01-30 12:41:40 -080017#include <net/pkt_cls.h>
18#include <net/tc_act/tc_mirred.h>
Florian Fainellib73adef2015-02-24 13:15:33 -080019#include <linux/if_bridge.h>
Florian Fainelli04ff53f2015-07-31 11:42:57 -070020#include <linux/netpoll.h>
Brandon Streiff90af1052018-02-14 01:07:49 +010021#include <linux/ptp_classify.h>
Vivien Didelotea5dd342017-05-17 15:46:03 -040022
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000023#include "dsa_priv.h"
24
Vivien Didelotf3b78042019-06-14 13:49:21 -040025static bool dsa_slave_dev_check(const struct net_device *dev);
Florian Fainellif50f2122017-01-30 12:41:40 -080026
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000027/* slave mii_bus handling ***************************************************/
28static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
29{
30 struct dsa_switch *ds = bus->priv;
31
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -070032 if (ds->phys_mii_mask & (1 << addr))
Vivien Didelot9d490b42016-08-23 12:38:56 -040033 return ds->ops->phy_read(ds, addr, reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000034
35 return 0xffff;
36}
37
38static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
39{
40 struct dsa_switch *ds = bus->priv;
41
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -070042 if (ds->phys_mii_mask & (1 << addr))
Vivien Didelot9d490b42016-08-23 12:38:56 -040043 return ds->ops->phy_write(ds, addr, reg, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000044
45 return 0;
46}
47
48void dsa_slave_mii_bus_init(struct dsa_switch *ds)
49{
50 ds->slave_mii_bus->priv = (void *)ds;
51 ds->slave_mii_bus->name = "dsa slave smi";
52 ds->slave_mii_bus->read = dsa_slave_phy_read;
53 ds->slave_mii_bus->write = dsa_slave_phy_write;
Florian Fainelli0b7b4982016-06-07 16:32:38 -070054 snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d",
Vivien Didelot49463b72017-11-03 19:05:21 -040055 ds->dst->index, ds->index);
Andrew Lunnc33063d2016-05-10 23:27:23 +020056 ds->slave_mii_bus->parent = ds->dev;
Vivien Didelot24df8982015-01-20 19:13:32 -050057 ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000058}
59
60
61/* slave device handling ****************************************************/
Nicolas Dichtelabd2be02015-04-02 17:07:08 +020062static int dsa_slave_get_iflink(const struct net_device *dev)
Lennert Buytenhekc0840802009-03-20 09:49:49 +000063{
Vivien Didelotd0006b02017-10-16 11:12:16 -040064 return dsa_slave_to_master(dev)->ifindex;
Lennert Buytenhekc0840802009-03-20 09:49:49 +000065}
66
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000067static int dsa_slave_open(struct net_device *dev)
68{
Vivien Didelotd0006b02017-10-16 11:12:16 -040069 struct net_device *master = dsa_slave_to_master(dev);
Vivien Didelotd9450972017-10-16 11:12:15 -040070 struct dsa_port *dp = dsa_slave_to_port(dev);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -080071 int err;
72
73 if (!(master->flags & IFF_UP))
74 return -ENETDOWN;
75
Joe Perches8feedbb2012-05-08 18:56:57 +000076 if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) {
Jiri Pirkoa748ee22010-04-01 21:22:09 +000077 err = dev_uc_add(master, dev->dev_addr);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -080078 if (err < 0)
79 goto out;
80 }
81
82 if (dev->flags & IFF_ALLMULTI) {
83 err = dev_set_allmulti(master, 1);
84 if (err < 0)
85 goto del_unicast;
86 }
87 if (dev->flags & IFF_PROMISC) {
88 err = dev_set_promiscuity(master, 1);
89 if (err < 0)
90 goto clear_allmulti;
91 }
92
Vivien Didelot0115dcd2017-09-26 17:15:32 -040093 err = dsa_port_enable(dp, dev->phydev);
Vivien Didelotfb8a6a22017-09-22 19:01:56 -040094 if (err)
95 goto clear_promisc;
Florian Fainellib73adef2015-02-24 13:15:33 -080096
Florian Fainelliaab9c402018-05-10 13:17:36 -070097 phylink_start(dp->pl);
Florian Fainellif7f1de52014-09-24 17:05:17 -070098
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000099 return 0;
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800100
Florian Fainellib2f2af22014-09-24 17:05:18 -0700101clear_promisc:
102 if (dev->flags & IFF_PROMISC)
Gilad Ben-Yossef4fdeddf2015-06-25 16:50:13 +0300103 dev_set_promiscuity(master, -1);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800104clear_allmulti:
105 if (dev->flags & IFF_ALLMULTI)
106 dev_set_allmulti(master, -1);
107del_unicast:
Joe Perches8feedbb2012-05-08 18:56:57 +0000108 if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000109 dev_uc_del(master, dev->dev_addr);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800110out:
111 return err;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000112}
113
114static int dsa_slave_close(struct net_device *dev)
115{
Vivien Didelotd0006b02017-10-16 11:12:16 -0400116 struct net_device *master = dsa_slave_to_master(dev);
Vivien Didelotd9450972017-10-16 11:12:15 -0400117 struct dsa_port *dp = dsa_slave_to_port(dev);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800118
Vladimir Oltean97a69a02019-05-05 13:19:25 +0300119 cancel_work_sync(&dp->xmit_work);
120 skb_queue_purge(&dp->xmit_queue);
121
Florian Fainelliaab9c402018-05-10 13:17:36 -0700122 phylink_stop(dp->pl);
Florian Fainellif7f1de52014-09-24 17:05:17 -0700123
Andrew Lunn75104db2019-02-24 20:44:43 +0100124 dsa_port_disable(dp);
Vivien Didelot6457edf2017-09-22 19:01:55 -0400125
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800126 dev_mc_unsync(master, dev);
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000127 dev_uc_unsync(master, dev);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800128 if (dev->flags & IFF_ALLMULTI)
129 dev_set_allmulti(master, -1);
130 if (dev->flags & IFF_PROMISC)
131 dev_set_promiscuity(master, -1);
132
Joe Perches8feedbb2012-05-08 18:56:57 +0000133 if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000134 dev_uc_del(master, dev->dev_addr);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800135
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000136 return 0;
137}
138
139static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
140{
Vivien Didelotd0006b02017-10-16 11:12:16 -0400141 struct net_device *master = dsa_slave_to_master(dev);
Rundong Ge17ab4f62019-02-02 14:29:35 +0000142 if (dev->flags & IFF_UP) {
143 if (change & IFF_ALLMULTI)
144 dev_set_allmulti(master,
145 dev->flags & IFF_ALLMULTI ? 1 : -1);
146 if (change & IFF_PROMISC)
147 dev_set_promiscuity(master,
148 dev->flags & IFF_PROMISC ? 1 : -1);
149 }
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000150}
151
152static void dsa_slave_set_rx_mode(struct net_device *dev)
153{
Vivien Didelotd0006b02017-10-16 11:12:16 -0400154 struct net_device *master = dsa_slave_to_master(dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000155
156 dev_mc_sync(master, dev);
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000157 dev_uc_sync(master, dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000158}
159
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800160static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000161{
Vivien Didelotd0006b02017-10-16 11:12:16 -0400162 struct net_device *master = dsa_slave_to_master(dev);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800163 struct sockaddr *addr = a;
164 int err;
165
166 if (!is_valid_ether_addr(addr->sa_data))
167 return -EADDRNOTAVAIL;
168
169 if (!(dev->flags & IFF_UP))
170 goto out;
171
Joe Perches8feedbb2012-05-08 18:56:57 +0000172 if (!ether_addr_equal(addr->sa_data, master->dev_addr)) {
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000173 err = dev_uc_add(master, addr->sa_data);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800174 if (err < 0)
175 return err;
176 }
177
Joe Perches8feedbb2012-05-08 18:56:57 +0000178 if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000179 dev_uc_del(master, dev->dev_addr);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800180
181out:
Joe Perchesd08f1612014-01-20 09:52:20 -0800182 ether_addr_copy(dev->dev_addr, addr->sa_data);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000183
184 return 0;
185}
186
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +0300187struct dsa_slave_dump_ctx {
188 struct net_device *dev;
189 struct sk_buff *skb;
190 struct netlink_callback *cb;
191 int idx;
192};
193
194static int
195dsa_slave_port_fdb_do_dump(const unsigned char *addr, u16 vid,
196 bool is_static, void *data)
197{
198 struct dsa_slave_dump_ctx *dump = data;
199 u32 portid = NETLINK_CB(dump->cb->skb).portid;
200 u32 seq = dump->cb->nlh->nlmsg_seq;
201 struct nlmsghdr *nlh;
202 struct ndmsg *ndm;
203
204 if (dump->idx < dump->cb->args[2])
205 goto skip;
206
207 nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH,
208 sizeof(*ndm), NLM_F_MULTI);
209 if (!nlh)
210 return -EMSGSIZE;
211
212 ndm = nlmsg_data(nlh);
213 ndm->ndm_family = AF_BRIDGE;
214 ndm->ndm_pad1 = 0;
215 ndm->ndm_pad2 = 0;
216 ndm->ndm_flags = NTF_SELF;
217 ndm->ndm_type = 0;
218 ndm->ndm_ifindex = dump->dev->ifindex;
219 ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE;
220
221 if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr))
222 goto nla_put_failure;
223
224 if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid))
225 goto nla_put_failure;
226
227 nlmsg_end(dump->skb, nlh);
228
229skip:
230 dump->idx++;
231 return 0;
232
233nla_put_failure:
234 nlmsg_cancel(dump->skb, nlh);
235 return -EMSGSIZE;
236}
237
238static int
239dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
240 struct net_device *dev, struct net_device *filter_dev,
241 int *idx)
242{
Vivien Didelotd9450972017-10-16 11:12:15 -0400243 struct dsa_port *dp = dsa_slave_to_port(dev);
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +0300244 struct dsa_slave_dump_ctx dump = {
245 .dev = dev,
246 .skb = skb,
247 .cb = cb,
248 .idx = *idx,
249 };
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +0300250 int err;
251
Vivien Didelotde40fc52017-09-20 19:32:14 -0400252 err = dsa_port_fdb_dump(dp, dsa_slave_port_fdb_do_dump, &dump);
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +0300253 *idx = dump.idx;
Vivien Didelotde40fc52017-09-20 19:32:14 -0400254
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +0300255 return err;
256}
257
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000258static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
259{
Brandon Streiff03363692018-02-14 01:07:48 +0100260 struct dsa_slave_priv *p = netdev_priv(dev);
261 struct dsa_switch *ds = p->dp->ds;
262 int port = p->dp->index;
263
264 /* Pass through to switch driver if it supports timestamping */
265 switch (cmd) {
266 case SIOCGHWTSTAMP:
267 if (ds->ops->port_hwtstamp_get)
268 return ds->ops->port_hwtstamp_get(ds, port, ifr);
269 break;
270 case SIOCSHWTSTAMP:
271 if (ds->ops->port_hwtstamp_set)
272 return ds->ops->port_hwtstamp_set(ds, port, ifr);
273 break;
274 }
275
Florian Fainelliaab9c402018-05-10 13:17:36 -0700276 return phylink_mii_ioctl(p->dp->pl, ifr, cmd);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000277}
278
Scott Feldman35636062015-05-10 09:47:51 -0700279static int dsa_slave_port_attr_set(struct net_device *dev,
Jiri Pirkof7fadf32015-10-14 19:40:49 +0200280 const struct switchdev_attr *attr,
Jiri Pirko7ea6eb32015-09-24 10:02:41 +0200281 struct switchdev_trans *trans)
Scott Feldman35636062015-05-10 09:47:51 -0700282{
Vivien Didelotd9450972017-10-16 11:12:15 -0400283 struct dsa_port *dp = dsa_slave_to_port(dev);
Vivien Didelotb8d866a2015-09-29 12:38:36 -0400284 int ret;
Scott Feldman35636062015-05-10 09:47:51 -0700285
286 switch (attr->id) {
Jiri Pirko1f868392015-10-01 11:03:42 +0200287 case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
Vivien Didelotfd364542017-05-19 17:00:36 -0400288 ret = dsa_port_set_state(dp, attr->u.stp_state, trans);
Scott Feldman35636062015-05-10 09:47:51 -0700289 break;
Vivien Didelotfb2daba2016-02-26 13:16:00 -0500290 case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
Vivien Didelotc02c4172017-05-19 17:00:42 -0400291 ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering,
292 trans);
Vivien Didelotfb2daba2016-02-26 13:16:00 -0500293 break;
Vivien Didelot34a79f62016-07-18 20:45:38 -0400294 case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
Vivien Didelot072bb192017-05-19 17:00:43 -0400295 ret = dsa_port_ageing_time(dp, attr->u.ageing_time, trans);
Vivien Didelot34a79f62016-07-18 20:45:38 -0400296 break;
Florian Fainelliea870052019-02-20 16:58:22 -0800297 case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
298 ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags,
299 trans);
300 break;
Russell King57652792019-02-20 15:35:04 -0800301 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
302 ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, trans);
303 break;
Vivien Didelot08cc83c2019-07-08 23:31:13 -0400304 case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER:
305 ret = dsa_port_mrouter(dp->cpu_dp, attr->u.mrouter, trans);
306 break;
Scott Feldman35636062015-05-10 09:47:51 -0700307 default:
308 ret = -EOPNOTSUPP;
309 break;
310 }
311
312 return ret;
313}
314
Vivien Didelotbdcff082019-08-25 13:25:17 -0400315static int dsa_slave_vlan_add(struct net_device *dev,
316 const struct switchdev_obj *obj,
317 struct switchdev_trans *trans)
318{
319 struct dsa_port *dp = dsa_slave_to_port(dev);
320 struct switchdev_obj_port_vlan vlan;
321 int err;
322
323 if (obj->orig_dev != dev)
324 return -EOPNOTSUPP;
325
Vivien Didelotc5335d72019-08-25 13:25:18 -0400326 if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev))
327 return 0;
328
Vivien Didelotbdcff082019-08-25 13:25:17 -0400329 vlan = *SWITCHDEV_OBJ_PORT_VLAN(obj);
330
331 err = dsa_port_vlan_add(dp, &vlan, trans);
332 if (err)
333 return err;
334
Vivien Didelotb9499902019-08-25 13:25:20 -0400335 /* We need the dedicated CPU port to be a member of the VLAN as well.
336 * Even though drivers often handle CPU membership in special ways,
337 * it doesn't make sense to program a PVID, so clear this flag.
338 */
339 vlan.flags &= ~BRIDGE_VLAN_INFO_PVID;
340
Vivien Didelot7e1741b2019-08-25 13:25:19 -0400341 err = dsa_port_vlan_add(dp->cpu_dp, &vlan, trans);
342 if (err)
343 return err;
344
Vivien Didelotbdcff082019-08-25 13:25:17 -0400345 return 0;
346}
347
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400348static int dsa_slave_port_obj_add(struct net_device *dev,
Jiri Pirko648b4a92015-10-01 11:03:45 +0200349 const struct switchdev_obj *obj,
Vivien Didelot79b139f2019-06-14 13:49:22 -0400350 struct switchdev_trans *trans,
351 struct netlink_ext_ack *extack)
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400352{
Vivien Didelotd9450972017-10-16 11:12:15 -0400353 struct dsa_port *dp = dsa_slave_to_port(dev);
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400354 int err;
355
356 /* For the prepare phase, ensure the full set of changes is feasable in
357 * one go in order to signal a failure properly. If an operation is not
358 * supported, return -EOPNOTSUPP.
359 */
360
Jiri Pirko9e8f4a52015-10-01 11:03:46 +0200361 switch (obj->id) {
Vivien Didelot8df30252016-08-31 11:50:03 -0400362 case SWITCHDEV_OBJ_ID_PORT_MDB:
Vivien Didelot79b139f2019-06-14 13:49:22 -0400363 if (obj->orig_dev != dev)
364 return -EOPNOTSUPP;
Vivien Didelotbcebb972017-05-19 17:00:40 -0400365 err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj), trans);
Vivien Didelot8df30252016-08-31 11:50:03 -0400366 break;
Andrew Lunn5f4dbc52017-11-09 23:11:00 +0100367 case SWITCHDEV_OBJ_ID_HOST_MDB:
368 /* DSA can directly translate this to a normal MDB add,
369 * but on the CPU port.
370 */
371 err = dsa_port_mdb_add(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj),
372 trans);
373 break;
Jiri Pirko57d80832015-10-01 11:03:41 +0200374 case SWITCHDEV_OBJ_ID_PORT_VLAN:
Vivien Didelotbdcff082019-08-25 13:25:17 -0400375 err = dsa_slave_vlan_add(dev, obj, trans);
Vivien Didelot11149532015-08-13 12:52:17 -0400376 break;
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400377 default:
378 err = -EOPNOTSUPP;
379 break;
380 }
381
382 return err;
383}
384
Vivien Didelotbdcff082019-08-25 13:25:17 -0400385static int dsa_slave_vlan_del(struct net_device *dev,
386 const struct switchdev_obj *obj)
387{
388 struct dsa_port *dp = dsa_slave_to_port(dev);
389
390 if (obj->orig_dev != dev)
391 return -EOPNOTSUPP;
392
Vivien Didelotc5335d72019-08-25 13:25:18 -0400393 if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev))
394 return 0;
395
Vivien Didelot7e1741b2019-08-25 13:25:19 -0400396 /* Do not deprogram the CPU port as it may be shared with other user
397 * ports which can be members of this VLAN as well.
398 */
Vivien Didelotbdcff082019-08-25 13:25:17 -0400399 return dsa_port_vlan_del(dp, SWITCHDEV_OBJ_PORT_VLAN(obj));
400}
401
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400402static int dsa_slave_port_obj_del(struct net_device *dev,
Jiri Pirko648b4a92015-10-01 11:03:45 +0200403 const struct switchdev_obj *obj)
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400404{
Vivien Didelotd9450972017-10-16 11:12:15 -0400405 struct dsa_port *dp = dsa_slave_to_port(dev);
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400406 int err;
407
Jiri Pirko9e8f4a52015-10-01 11:03:46 +0200408 switch (obj->id) {
Vivien Didelot8df30252016-08-31 11:50:03 -0400409 case SWITCHDEV_OBJ_ID_PORT_MDB:
Vivien Didelot79b139f2019-06-14 13:49:22 -0400410 if (obj->orig_dev != dev)
411 return -EOPNOTSUPP;
Vivien Didelotbcebb972017-05-19 17:00:40 -0400412 err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
Vivien Didelot8df30252016-08-31 11:50:03 -0400413 break;
Andrew Lunn5f4dbc52017-11-09 23:11:00 +0100414 case SWITCHDEV_OBJ_ID_HOST_MDB:
415 /* DSA can directly translate this to a normal MDB add,
416 * but on the CPU port.
417 */
418 err = dsa_port_mdb_del(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj));
419 break;
Jiri Pirko57d80832015-10-01 11:03:41 +0200420 case SWITCHDEV_OBJ_ID_PORT_VLAN:
Vivien Didelotbdcff082019-08-25 13:25:17 -0400421 err = dsa_slave_vlan_del(dev, obj);
Vivien Didelot11149532015-08-13 12:52:17 -0400422 break;
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400423 default:
424 err = -EOPNOTSUPP;
425 break;
426 }
427
428 return err;
429}
430
Florian Fainelli929d6c12019-02-06 09:45:45 -0800431static int dsa_slave_get_port_parent_id(struct net_device *dev,
432 struct netdev_phys_item_id *ppid)
Florian Fainellib73adef2015-02-24 13:15:33 -0800433{
Vivien Didelotd9450972017-10-16 11:12:15 -0400434 struct dsa_port *dp = dsa_slave_to_port(dev);
435 struct dsa_switch *ds = dp->ds;
Andrew Lunna42c8e32017-11-09 22:29:51 +0100436 struct dsa_switch_tree *dst = ds->dst;
Florian Fainellib73adef2015-02-24 13:15:33 -0800437
Jiri Pirko15b04ac2019-04-03 14:24:26 +0200438 /* For non-legacy ports, devlink is used and it takes
439 * care of the name generation. This ndo implementation
440 * should be removed with legacy support.
441 */
442 if (dp->ds->devlink)
443 return -EOPNOTSUPP;
444
Florian Fainelli929d6c12019-02-06 09:45:45 -0800445 ppid->id_len = sizeof(dst->index);
446 memcpy(&ppid->id, &dst->index, ppid->id_len);
447
448 return 0;
449}
450
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400451static inline netdev_tx_t dsa_slave_netpoll_send_skb(struct net_device *dev,
452 struct sk_buff *skb)
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700453{
454#ifdef CONFIG_NET_POLL_CONTROLLER
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400455 struct dsa_slave_priv *p = netdev_priv(dev);
456
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700457 if (p->netpoll)
458 netpoll_send_skb(p->netpoll, skb);
459#else
460 BUG();
461#endif
462 return NETDEV_TX_OK;
463}
464
Brandon Streiff90af1052018-02-14 01:07:49 +0100465static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p,
466 struct sk_buff *skb)
467{
468 struct dsa_switch *ds = p->dp->ds;
469 struct sk_buff *clone;
470 unsigned int type;
471
472 type = ptp_classify_raw(skb);
473 if (type == PTP_CLASS_NONE)
474 return;
475
476 if (!ds->ops->port_txtstamp)
477 return;
478
479 clone = skb_clone_sk(skb);
480 if (!clone)
481 return;
482
Vladimir Oltean146d4422019-06-08 15:04:27 +0300483 DSA_SKB_CB(skb)->clone = clone;
484
Brandon Streiff90af1052018-02-14 01:07:49 +0100485 if (ds->ops->port_txtstamp(ds, p->dp->index, clone, type))
486 return;
487
488 kfree_skb(clone);
489}
490
Vladimir Oltean97a69a02019-05-05 13:19:25 +0300491netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev)
492{
493 /* SKB for netpoll still need to be mangled with the protocol-specific
494 * tag to be successfully transmitted
495 */
496 if (unlikely(netpoll_tx_running(dev)))
497 return dsa_slave_netpoll_send_skb(dev, skb);
498
499 /* Queue the SKB for transmission on the parent interface, but
500 * do not modify its EtherType
501 */
502 skb->dev = dsa_slave_to_master(dev);
503 dev_queue_xmit(skb);
504
505 return NETDEV_TX_OK;
506}
507EXPORT_SYMBOL_GPL(dsa_enqueue_skb);
508
Florian Fainelli3e8a72d2014-08-27 17:04:46 -0700509static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
510{
511 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700512 struct pcpu_sw_netstats *s;
Florian Fainelli4ed70ce2015-07-31 11:42:56 -0700513 struct sk_buff *nskb;
Florian Fainelli3e8a72d2014-08-27 17:04:46 -0700514
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700515 s = this_cpu_ptr(p->stats64);
516 u64_stats_update_begin(&s->syncp);
517 s->tx_packets++;
518 s->tx_bytes += skb->len;
519 u64_stats_update_end(&s->syncp);
Florian Fainelli3e8a72d2014-08-27 17:04:46 -0700520
Vladimir Oltean87671372019-05-11 23:14:45 +0300521 DSA_SKB_CB(skb)->deferred_xmit = false;
Vladimir Oltean146d4422019-06-08 15:04:27 +0300522 DSA_SKB_CB(skb)->clone = NULL;
Vladimir Oltean87671372019-05-11 23:14:45 +0300523
Brandon Streiff90af1052018-02-14 01:07:49 +0100524 /* Identify PTP protocol packets, clone them, and pass them to the
525 * switch driver
526 */
527 dsa_skb_tx_timestamp(p, skb);
528
Vivien Didelotfe47d562017-06-01 16:07:15 -0400529 /* Transmit function may have to reallocate the original SKB,
530 * in which case it must have freed it. Only free it here on error.
531 */
Florian Fainelli4ed70ce2015-07-31 11:42:56 -0700532 nskb = p->xmit(skb, dev);
Vivien Didelotfe47d562017-06-01 16:07:15 -0400533 if (!nskb) {
Vladimir Oltean97a69a02019-05-05 13:19:25 +0300534 if (!DSA_SKB_CB(skb)->deferred_xmit)
535 kfree_skb(skb);
Florian Fainelli4ed70ce2015-07-31 11:42:56 -0700536 return NETDEV_TX_OK;
Vivien Didelotfe47d562017-06-01 16:07:15 -0400537 }
Florian Fainelli5aed85c2014-08-27 17:04:52 -0700538
Vladimir Oltean97a69a02019-05-05 13:19:25 +0300539 return dsa_enqueue_skb(nskb, dev);
540}
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700541
Vladimir Oltean97a69a02019-05-05 13:19:25 +0300542void *dsa_defer_xmit(struct sk_buff *skb, struct net_device *dev)
543{
544 struct dsa_port *dp = dsa_slave_to_port(dev);
Florian Fainelli5aed85c2014-08-27 17:04:52 -0700545
Vladimir Oltean97a69a02019-05-05 13:19:25 +0300546 DSA_SKB_CB(skb)->deferred_xmit = true;
547
548 skb_queue_tail(&dp->xmit_queue, skb);
549 schedule_work(&dp->xmit_work);
550 return NULL;
551}
552EXPORT_SYMBOL_GPL(dsa_defer_xmit);
553
554static void dsa_port_xmit_work(struct work_struct *work)
555{
556 struct dsa_port *dp = container_of(work, struct dsa_port, xmit_work);
557 struct dsa_switch *ds = dp->ds;
558 struct sk_buff *skb;
559
560 if (unlikely(!ds->ops->port_deferred_xmit))
561 return;
562
563 while ((skb = skb_dequeue(&dp->xmit_queue)) != NULL)
564 ds->ops->port_deferred_xmit(ds, dp->index, skb);
Florian Fainelli5aed85c2014-08-27 17:04:52 -0700565}
566
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000567/* ethtool operations *******************************************************/
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000568
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000569static void dsa_slave_get_drvinfo(struct net_device *dev,
570 struct ethtool_drvinfo *drvinfo)
571{
Jiri Pirko7826d432013-01-06 00:44:26 +0000572 strlcpy(drvinfo->driver, "dsa", sizeof(drvinfo->driver));
Jiri Pirko7826d432013-01-06 00:44:26 +0000573 strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
574 strlcpy(drvinfo->bus_info, "platform", sizeof(drvinfo->bus_info));
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000575}
576
Guenter Roeck3d762a02014-10-29 10:45:04 -0700577static int dsa_slave_get_regs_len(struct net_device *dev)
578{
Vivien Didelotd9450972017-10-16 11:12:15 -0400579 struct dsa_port *dp = dsa_slave_to_port(dev);
580 struct dsa_switch *ds = dp->ds;
Guenter Roeck3d762a02014-10-29 10:45:04 -0700581
Vivien Didelot9d490b42016-08-23 12:38:56 -0400582 if (ds->ops->get_regs_len)
Vivien Didelotd9450972017-10-16 11:12:15 -0400583 return ds->ops->get_regs_len(ds, dp->index);
Guenter Roeck3d762a02014-10-29 10:45:04 -0700584
585 return -EOPNOTSUPP;
586}
587
588static void
589dsa_slave_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
590{
Vivien Didelotd9450972017-10-16 11:12:15 -0400591 struct dsa_port *dp = dsa_slave_to_port(dev);
592 struct dsa_switch *ds = dp->ds;
Guenter Roeck3d762a02014-10-29 10:45:04 -0700593
Vivien Didelot9d490b42016-08-23 12:38:56 -0400594 if (ds->ops->get_regs)
Vivien Didelotd9450972017-10-16 11:12:15 -0400595 ds->ops->get_regs(ds, dp->index, regs, _p);
Guenter Roeck3d762a02014-10-29 10:45:04 -0700596}
597
Florian Fainelliaab9c402018-05-10 13:17:36 -0700598static int dsa_slave_nway_reset(struct net_device *dev)
599{
600 struct dsa_port *dp = dsa_slave_to_port(dev);
601
602 return phylink_ethtool_nway_reset(dp->pl);
603}
604
Guenter Roeck6793abb2014-10-29 10:45:01 -0700605static int dsa_slave_get_eeprom_len(struct net_device *dev)
606{
Vivien Didelotd9450972017-10-16 11:12:15 -0400607 struct dsa_port *dp = dsa_slave_to_port(dev);
608 struct dsa_switch *ds = dp->ds;
Guenter Roeck6793abb2014-10-29 10:45:01 -0700609
Andrew Lunn0e576042016-06-04 21:16:52 +0200610 if (ds->cd && ds->cd->eeprom_len)
Andrew Lunnff049552016-05-10 23:27:24 +0200611 return ds->cd->eeprom_len;
Guenter Roeck6793abb2014-10-29 10:45:01 -0700612
Vivien Didelot9d490b42016-08-23 12:38:56 -0400613 if (ds->ops->get_eeprom_len)
614 return ds->ops->get_eeprom_len(ds);
Guenter Roeck6793abb2014-10-29 10:45:01 -0700615
616 return 0;
617}
618
619static int dsa_slave_get_eeprom(struct net_device *dev,
620 struct ethtool_eeprom *eeprom, u8 *data)
621{
Vivien Didelotd9450972017-10-16 11:12:15 -0400622 struct dsa_port *dp = dsa_slave_to_port(dev);
623 struct dsa_switch *ds = dp->ds;
Guenter Roeck6793abb2014-10-29 10:45:01 -0700624
Vivien Didelot9d490b42016-08-23 12:38:56 -0400625 if (ds->ops->get_eeprom)
626 return ds->ops->get_eeprom(ds, eeprom, data);
Guenter Roeck6793abb2014-10-29 10:45:01 -0700627
628 return -EOPNOTSUPP;
629}
630
631static int dsa_slave_set_eeprom(struct net_device *dev,
632 struct ethtool_eeprom *eeprom, u8 *data)
633{
Vivien Didelotd9450972017-10-16 11:12:15 -0400634 struct dsa_port *dp = dsa_slave_to_port(dev);
635 struct dsa_switch *ds = dp->ds;
Guenter Roeck6793abb2014-10-29 10:45:01 -0700636
Vivien Didelot9d490b42016-08-23 12:38:56 -0400637 if (ds->ops->set_eeprom)
638 return ds->ops->set_eeprom(ds, eeprom, data);
Guenter Roeck6793abb2014-10-29 10:45:01 -0700639
640 return -EOPNOTSUPP;
641}
642
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000643static void dsa_slave_get_strings(struct net_device *dev,
644 uint32_t stringset, uint8_t *data)
645{
Vivien Didelotd9450972017-10-16 11:12:15 -0400646 struct dsa_port *dp = dsa_slave_to_port(dev);
647 struct dsa_switch *ds = dp->ds;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000648
649 if (stringset == ETH_SS_STATS) {
650 int len = ETH_GSTRING_LEN;
651
652 strncpy(data, "tx_packets", len);
653 strncpy(data + len, "tx_bytes", len);
654 strncpy(data + 2 * len, "rx_packets", len);
655 strncpy(data + 3 * len, "rx_bytes", len);
Vivien Didelot9d490b42016-08-23 12:38:56 -0400656 if (ds->ops->get_strings)
Florian Fainelli89f09042018-04-25 12:12:50 -0700657 ds->ops->get_strings(ds, dp->index, stringset,
658 data + 4 * len);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000659 }
660}
661
662static void dsa_slave_get_ethtool_stats(struct net_device *dev,
663 struct ethtool_stats *stats,
664 uint64_t *data)
665{
Vivien Didelotd9450972017-10-16 11:12:15 -0400666 struct dsa_port *dp = dsa_slave_to_port(dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000667 struct dsa_slave_priv *p = netdev_priv(dev);
Vivien Didelotd9450972017-10-16 11:12:15 -0400668 struct dsa_switch *ds = dp->ds;
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700669 struct pcpu_sw_netstats *s;
Florian Fainellif613ed62017-08-01 15:00:36 -0700670 unsigned int start;
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700671 int i;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000672
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700673 for_each_possible_cpu(i) {
674 u64 tx_packets, tx_bytes, rx_packets, rx_bytes;
675
676 s = per_cpu_ptr(p->stats64, i);
677 do {
678 start = u64_stats_fetch_begin_irq(&s->syncp);
679 tx_packets = s->tx_packets;
680 tx_bytes = s->tx_bytes;
681 rx_packets = s->rx_packets;
682 rx_bytes = s->rx_bytes;
683 } while (u64_stats_fetch_retry_irq(&s->syncp, start));
684 data[0] += tx_packets;
685 data[1] += tx_bytes;
686 data[2] += rx_packets;
687 data[3] += rx_bytes;
688 }
Vivien Didelot9d490b42016-08-23 12:38:56 -0400689 if (ds->ops->get_ethtool_stats)
Vivien Didelotd9450972017-10-16 11:12:15 -0400690 ds->ops->get_ethtool_stats(ds, dp->index, data + 4);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000691}
692
693static int dsa_slave_get_sset_count(struct net_device *dev, int sset)
694{
Vivien Didelotd9450972017-10-16 11:12:15 -0400695 struct dsa_port *dp = dsa_slave_to_port(dev);
696 struct dsa_switch *ds = dp->ds;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000697
698 if (sset == ETH_SS_STATS) {
699 int count;
700
701 count = 4;
Vivien Didelot9d490b42016-08-23 12:38:56 -0400702 if (ds->ops->get_sset_count)
Florian Fainelli89f09042018-04-25 12:12:50 -0700703 count += ds->ops->get_sset_count(ds, dp->index, sset);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000704
705 return count;
706 }
707
708 return -EOPNOTSUPP;
709}
710
Florian Fainelli19e57c42014-09-18 17:31:24 -0700711static void dsa_slave_get_wol(struct net_device *dev, struct ethtool_wolinfo *w)
712{
Vivien Didelotd9450972017-10-16 11:12:15 -0400713 struct dsa_port *dp = dsa_slave_to_port(dev);
714 struct dsa_switch *ds = dp->ds;
Florian Fainelli19e57c42014-09-18 17:31:24 -0700715
Florian Fainelliaab9c402018-05-10 13:17:36 -0700716 phylink_ethtool_get_wol(dp->pl, w);
717
Vivien Didelot9d490b42016-08-23 12:38:56 -0400718 if (ds->ops->get_wol)
Vivien Didelotd9450972017-10-16 11:12:15 -0400719 ds->ops->get_wol(ds, dp->index, w);
Florian Fainelli19e57c42014-09-18 17:31:24 -0700720}
721
722static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w)
723{
Vivien Didelotd9450972017-10-16 11:12:15 -0400724 struct dsa_port *dp = dsa_slave_to_port(dev);
725 struct dsa_switch *ds = dp->ds;
Florian Fainelli19e57c42014-09-18 17:31:24 -0700726 int ret = -EOPNOTSUPP;
727
Florian Fainelliaab9c402018-05-10 13:17:36 -0700728 phylink_ethtool_set_wol(dp->pl, w);
729
Vivien Didelot9d490b42016-08-23 12:38:56 -0400730 if (ds->ops->set_wol)
Vivien Didelotd9450972017-10-16 11:12:15 -0400731 ret = ds->ops->set_wol(ds, dp->index, w);
Florian Fainelli19e57c42014-09-18 17:31:24 -0700732
733 return ret;
734}
735
Florian Fainelli79052882014-09-24 17:05:21 -0700736static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e)
737{
Vivien Didelotd9450972017-10-16 11:12:15 -0400738 struct dsa_port *dp = dsa_slave_to_port(dev);
739 struct dsa_switch *ds = dp->ds;
Florian Fainelli79052882014-09-24 17:05:21 -0700740 int ret;
741
Vivien Didelot7b9cc732017-08-01 16:32:31 -0400742 /* Port's PHY and MAC both need to be EEE capable */
Dan Carpenter00670cb2019-02-06 18:35:15 +0300743 if (!dev->phydev || !dp->pl)
Vivien Didelot7b9cc732017-08-01 16:32:31 -0400744 return -ENODEV;
745
Vivien Didelot08f50062017-08-01 16:32:41 -0400746 if (!ds->ops->set_mac_eee)
Florian Fainelli79052882014-09-24 17:05:21 -0700747 return -EOPNOTSUPP;
748
Vivien Didelotd9450972017-10-16 11:12:15 -0400749 ret = ds->ops->set_mac_eee(ds, dp->index, e);
Florian Fainelli79052882014-09-24 17:05:21 -0700750 if (ret)
751 return ret;
752
Florian Fainelliaab9c402018-05-10 13:17:36 -0700753 return phylink_ethtool_set_eee(dp->pl, e);
Florian Fainelli79052882014-09-24 17:05:21 -0700754}
755
756static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)
757{
Vivien Didelotd9450972017-10-16 11:12:15 -0400758 struct dsa_port *dp = dsa_slave_to_port(dev);
759 struct dsa_switch *ds = dp->ds;
Florian Fainelli79052882014-09-24 17:05:21 -0700760 int ret;
761
Vivien Didelot7b9cc732017-08-01 16:32:31 -0400762 /* Port's PHY and MAC both need to be EEE capable */
Dan Carpenter00670cb2019-02-06 18:35:15 +0300763 if (!dev->phydev || !dp->pl)
Vivien Didelot7b9cc732017-08-01 16:32:31 -0400764 return -ENODEV;
765
Vivien Didelot08f50062017-08-01 16:32:41 -0400766 if (!ds->ops->get_mac_eee)
Florian Fainelli79052882014-09-24 17:05:21 -0700767 return -EOPNOTSUPP;
768
Vivien Didelotd9450972017-10-16 11:12:15 -0400769 ret = ds->ops->get_mac_eee(ds, dp->index, e);
Florian Fainelli79052882014-09-24 17:05:21 -0700770 if (ret)
771 return ret;
772
Florian Fainelliaab9c402018-05-10 13:17:36 -0700773 return phylink_ethtool_get_eee(dp->pl, e);
774}
775
776static int dsa_slave_get_link_ksettings(struct net_device *dev,
777 struct ethtool_link_ksettings *cmd)
778{
779 struct dsa_port *dp = dsa_slave_to_port(dev);
780
781 return phylink_ethtool_ksettings_get(dp->pl, cmd);
782}
783
784static int dsa_slave_set_link_ksettings(struct net_device *dev,
785 const struct ethtool_link_ksettings *cmd)
786{
787 struct dsa_port *dp = dsa_slave_to_port(dev);
788
789 return phylink_ethtool_ksettings_set(dp->pl, cmd);
Florian Fainelli79052882014-09-24 17:05:21 -0700790}
791
Heiner Kallweita2a1a132019-10-29 22:32:48 +0100792static void dsa_slave_get_pauseparam(struct net_device *dev,
793 struct ethtool_pauseparam *pause)
794{
795 struct dsa_port *dp = dsa_slave_to_port(dev);
796
797 phylink_ethtool_get_pauseparam(dp->pl, pause);
798}
799
800static int dsa_slave_set_pauseparam(struct net_device *dev,
801 struct ethtool_pauseparam *pause)
802{
803 struct dsa_port *dp = dsa_slave_to_port(dev);
804
805 return phylink_ethtool_set_pauseparam(dp->pl, pause);
806}
807
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700808#ifdef CONFIG_NET_POLL_CONTROLLER
809static int dsa_slave_netpoll_setup(struct net_device *dev,
810 struct netpoll_info *ni)
811{
Vivien Didelotd0006b02017-10-16 11:12:16 -0400812 struct net_device *master = dsa_slave_to_master(dev);
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700813 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700814 struct netpoll *netpoll;
815 int err = 0;
816
817 netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
818 if (!netpoll)
819 return -ENOMEM;
820
821 err = __netpoll_setup(netpoll, master);
822 if (err) {
823 kfree(netpoll);
824 goto out;
825 }
826
827 p->netpoll = netpoll;
828out:
829 return err;
830}
831
832static void dsa_slave_netpoll_cleanup(struct net_device *dev)
833{
834 struct dsa_slave_priv *p = netdev_priv(dev);
835 struct netpoll *netpoll = p->netpoll;
836
837 if (!netpoll)
838 return;
839
840 p->netpoll = NULL;
841
Debabrata Banerjeec9fbd712018-10-18 11:18:26 -0400842 __netpoll_free(netpoll);
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700843}
844
845static void dsa_slave_poll_controller(struct net_device *dev)
846{
847}
848#endif
849
Florian Fainelli44bb7652017-01-10 12:32:36 -0800850static int dsa_slave_get_phys_port_name(struct net_device *dev,
851 char *name, size_t len)
852{
Vivien Didelotd9450972017-10-16 11:12:15 -0400853 struct dsa_port *dp = dsa_slave_to_port(dev);
Florian Fainelli44bb7652017-01-10 12:32:36 -0800854
Jiri Pirkod4842102019-03-28 13:56:44 +0100855 /* For non-legacy ports, devlink is used and it takes
856 * care of the name generation. This ndo implementation
857 * should be removed with legacy support.
858 */
859 if (dp->ds->devlink)
860 return -EOPNOTSUPP;
861
Vivien Didelotd9450972017-10-16 11:12:15 -0400862 if (snprintf(name, len, "p%d", dp->index) >= len)
Florian Fainelli44bb7652017-01-10 12:32:36 -0800863 return -EINVAL;
Florian Fainelli3a543ef2016-12-29 14:20:56 -0800864
865 return 0;
866}
867
Florian Fainellif50f2122017-01-30 12:41:40 -0800868static struct dsa_mall_tc_entry *
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400869dsa_slave_mall_tc_entry_find(struct net_device *dev, unsigned long cookie)
Florian Fainellif50f2122017-01-30 12:41:40 -0800870{
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400871 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainellif50f2122017-01-30 12:41:40 -0800872 struct dsa_mall_tc_entry *mall_tc_entry;
873
874 list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list)
875 if (mall_tc_entry->cookie == cookie)
876 return mall_tc_entry;
877
878 return NULL;
879}
880
881static int dsa_slave_add_cls_matchall(struct net_device *dev,
Florian Fainellif50f2122017-01-30 12:41:40 -0800882 struct tc_cls_matchall_offload *cls,
883 bool ingress)
884{
Vivien Didelotd9450972017-10-16 11:12:15 -0400885 struct dsa_port *dp = dsa_slave_to_port(dev);
Florian Fainellif50f2122017-01-30 12:41:40 -0800886 struct dsa_slave_priv *p = netdev_priv(dev);
887 struct dsa_mall_tc_entry *mall_tc_entry;
Jiri Pirko5fd9fc42017-08-07 10:15:29 +0200888 __be16 protocol = cls->common.protocol;
Vivien Didelotd9450972017-10-16 11:12:15 -0400889 struct dsa_switch *ds = dp->ds;
Pieter Jansen van Vuuren9681e8b2019-05-04 04:46:19 -0700890 struct flow_action_entry *act;
Vivien Didelotd9450972017-10-16 11:12:15 -0400891 struct dsa_port *to_dp;
Florian Fainellif50f2122017-01-30 12:41:40 -0800892 int err = -EOPNOTSUPP;
Florian Fainellif50f2122017-01-30 12:41:40 -0800893
894 if (!ds->ops->port_mirror_add)
895 return err;
896
Pieter Jansen van Vuuren9681e8b2019-05-04 04:46:19 -0700897 if (!flow_offload_has_one_action(&cls->rule->action))
Florian Fainellif50f2122017-01-30 12:41:40 -0800898 return err;
899
Pieter Jansen van Vuuren9681e8b2019-05-04 04:46:19 -0700900 act = &cls->rule->action.entries[0];
Florian Fainellif50f2122017-01-30 12:41:40 -0800901
Pieter Jansen van Vuuren9681e8b2019-05-04 04:46:19 -0700902 if (act->id == FLOW_ACTION_MIRRED && protocol == htons(ETH_P_ALL)) {
Florian Fainellif50f2122017-01-30 12:41:40 -0800903 struct dsa_mall_mirror_tc_entry *mirror;
904
Pieter Jansen van Vuuren9681e8b2019-05-04 04:46:19 -0700905 if (!act->dev)
Florian Fainellif50f2122017-01-30 12:41:40 -0800906 return -EINVAL;
907
Pieter Jansen van Vuuren9681e8b2019-05-04 04:46:19 -0700908 if (!dsa_slave_dev_check(act->dev))
Florian Fainellif50f2122017-01-30 12:41:40 -0800909 return -EOPNOTSUPP;
910
911 mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL);
912 if (!mall_tc_entry)
913 return -ENOMEM;
914
915 mall_tc_entry->cookie = cls->cookie;
916 mall_tc_entry->type = DSA_PORT_MALL_MIRROR;
917 mirror = &mall_tc_entry->mirror;
918
Pieter Jansen van Vuuren9681e8b2019-05-04 04:46:19 -0700919 to_dp = dsa_slave_to_port(act->dev);
Florian Fainellif50f2122017-01-30 12:41:40 -0800920
Vivien Didelotd9450972017-10-16 11:12:15 -0400921 mirror->to_local_port = to_dp->index;
Florian Fainellif50f2122017-01-30 12:41:40 -0800922 mirror->ingress = ingress;
923
Vivien Didelotd9450972017-10-16 11:12:15 -0400924 err = ds->ops->port_mirror_add(ds, dp->index, mirror, ingress);
Florian Fainellif50f2122017-01-30 12:41:40 -0800925 if (err) {
926 kfree(mall_tc_entry);
927 return err;
928 }
929
930 list_add_tail(&mall_tc_entry->list, &p->mall_tc_list);
931 }
932
933 return 0;
934}
935
936static void dsa_slave_del_cls_matchall(struct net_device *dev,
937 struct tc_cls_matchall_offload *cls)
938{
Vivien Didelotd9450972017-10-16 11:12:15 -0400939 struct dsa_port *dp = dsa_slave_to_port(dev);
Florian Fainellif50f2122017-01-30 12:41:40 -0800940 struct dsa_mall_tc_entry *mall_tc_entry;
Vivien Didelotd9450972017-10-16 11:12:15 -0400941 struct dsa_switch *ds = dp->ds;
Florian Fainellif50f2122017-01-30 12:41:40 -0800942
943 if (!ds->ops->port_mirror_del)
944 return;
945
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400946 mall_tc_entry = dsa_slave_mall_tc_entry_find(dev, cls->cookie);
Florian Fainellif50f2122017-01-30 12:41:40 -0800947 if (!mall_tc_entry)
948 return;
949
950 list_del(&mall_tc_entry->list);
951
952 switch (mall_tc_entry->type) {
953 case DSA_PORT_MALL_MIRROR:
Vivien Didelotd9450972017-10-16 11:12:15 -0400954 ds->ops->port_mirror_del(ds, dp->index, &mall_tc_entry->mirror);
Florian Fainellif50f2122017-01-30 12:41:40 -0800955 break;
956 default:
957 WARN_ON(1);
958 }
959
960 kfree(mall_tc_entry);
961}
962
Jiri Pirko3fbae382017-08-07 10:15:26 +0200963static int dsa_slave_setup_tc_cls_matchall(struct net_device *dev,
Jiri Pirko6b3eb752017-10-19 15:50:45 +0200964 struct tc_cls_matchall_offload *cls,
965 bool ingress)
Florian Fainellif50f2122017-01-30 12:41:40 -0800966{
Jiri Pirko5fd9fc42017-08-07 10:15:29 +0200967 if (cls->common.chain_index)
Jiri Pirkoa5fcf8a2017-06-06 17:00:16 +0200968 return -EOPNOTSUPP;
Florian Fainellif50f2122017-01-30 12:41:40 -0800969
Jiri Pirko3fbae382017-08-07 10:15:26 +0200970 switch (cls->command) {
971 case TC_CLSMATCHALL_REPLACE:
Jiri Pirko5fd9fc42017-08-07 10:15:29 +0200972 return dsa_slave_add_cls_matchall(dev, cls, ingress);
Jiri Pirko3fbae382017-08-07 10:15:26 +0200973 case TC_CLSMATCHALL_DESTROY:
974 dsa_slave_del_cls_matchall(dev, cls);
975 return 0;
976 default:
977 return -EOPNOTSUPP;
978 }
979}
980
Jiri Pirko6b3eb752017-10-19 15:50:45 +0200981static int dsa_slave_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
982 void *cb_priv, bool ingress)
983{
984 struct net_device *dev = cb_priv;
985
Jiri Pirko44ae12a2017-11-01 11:47:39 +0100986 if (!tc_can_offload(dev))
987 return -EOPNOTSUPP;
988
Jiri Pirko6b3eb752017-10-19 15:50:45 +0200989 switch (type) {
990 case TC_SETUP_CLSMATCHALL:
991 return dsa_slave_setup_tc_cls_matchall(dev, type_data, ingress);
992 default:
993 return -EOPNOTSUPP;
994 }
995}
996
997static int dsa_slave_setup_tc_block_cb_ig(enum tc_setup_type type,
998 void *type_data, void *cb_priv)
999{
1000 return dsa_slave_setup_tc_block_cb(type, type_data, cb_priv, true);
1001}
1002
1003static int dsa_slave_setup_tc_block_cb_eg(enum tc_setup_type type,
1004 void *type_data, void *cb_priv)
1005{
1006 return dsa_slave_setup_tc_block_cb(type, type_data, cb_priv, false);
1007}
1008
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +02001009static LIST_HEAD(dsa_slave_block_cb_list);
1010
Jiri Pirko6b3eb752017-10-19 15:50:45 +02001011static int dsa_slave_setup_tc_block(struct net_device *dev,
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +02001012 struct flow_block_offload *f)
Jiri Pirko6b3eb752017-10-19 15:50:45 +02001013{
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +02001014 struct flow_block_cb *block_cb;
Pablo Neira Ayusoa7323312019-07-19 18:20:15 +02001015 flow_setup_cb_t *cb;
Jiri Pirko6b3eb752017-10-19 15:50:45 +02001016
Pablo Neira Ayuso32f8c402019-07-09 22:55:41 +02001017 if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
Jiri Pirko6b3eb752017-10-19 15:50:45 +02001018 cb = dsa_slave_setup_tc_block_cb_ig;
Pablo Neira Ayuso32f8c402019-07-09 22:55:41 +02001019 else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
Jiri Pirko6b3eb752017-10-19 15:50:45 +02001020 cb = dsa_slave_setup_tc_block_cb_eg;
1021 else
1022 return -EOPNOTSUPP;
1023
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +02001024 f->driver_block_list = &dsa_slave_block_cb_list;
1025
Jiri Pirko6b3eb752017-10-19 15:50:45 +02001026 switch (f->command) {
Pablo Neira Ayuso9c0e1892019-07-09 22:55:40 +02001027 case FLOW_BLOCK_BIND:
Pablo Neira Ayuso0d4fd022019-07-09 22:55:48 +02001028 if (flow_block_cb_is_busy(cb, dev, &dsa_slave_block_cb_list))
1029 return -EBUSY;
1030
Pablo Neira Ayuso0c7294d2019-07-19 18:20:14 +02001031 block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +02001032 if (IS_ERR(block_cb))
1033 return PTR_ERR(block_cb);
1034
1035 flow_block_cb_add(block_cb, f);
1036 list_add_tail(&block_cb->driver_list, &dsa_slave_block_cb_list);
1037 return 0;
Pablo Neira Ayuso9c0e1892019-07-09 22:55:40 +02001038 case FLOW_BLOCK_UNBIND:
Pablo Neira Ayuso14bfb132019-07-19 18:20:16 +02001039 block_cb = flow_block_cb_lookup(f->block, cb, dev);
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +02001040 if (!block_cb)
1041 return -ENOENT;
1042
1043 flow_block_cb_remove(block_cb, f);
1044 list_del(&block_cb->driver_list);
Jiri Pirko6b3eb752017-10-19 15:50:45 +02001045 return 0;
1046 default:
1047 return -EOPNOTSUPP;
1048 }
1049}
1050
Jiri Pirko3fbae382017-08-07 10:15:26 +02001051static int dsa_slave_setup_tc(struct net_device *dev, enum tc_setup_type type,
Jiri Pirkode4784c2017-08-07 10:15:32 +02001052 void *type_data)
Jiri Pirko3fbae382017-08-07 10:15:26 +02001053{
Vladimir Oltean47d23af2019-09-15 04:59:59 +03001054 struct dsa_port *dp = dsa_slave_to_port(dev);
1055 struct dsa_switch *ds = dp->ds;
1056
1057 if (type == TC_SETUP_BLOCK)
Jiri Pirko6b3eb752017-10-19 15:50:45 +02001058 return dsa_slave_setup_tc_block(dev, type_data);
Vladimir Oltean47d23af2019-09-15 04:59:59 +03001059
1060 if (!ds->ops->port_setup_tc)
Jiri Pirkoa5fcf8a2017-06-06 17:00:16 +02001061 return -EOPNOTSUPP;
Vladimir Oltean47d23af2019-09-15 04:59:59 +03001062
1063 return ds->ops->port_setup_tc(ds, dp->index, type, type_data);
Florian Fainellif50f2122017-01-30 12:41:40 -08001064}
1065
Florian Fainellif613ed62017-08-01 15:00:36 -07001066static void dsa_slave_get_stats64(struct net_device *dev,
1067 struct rtnl_link_stats64 *stats)
1068{
1069 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainelli5f6b4e142017-08-03 21:33:27 -07001070 struct pcpu_sw_netstats *s;
Florian Fainellif613ed62017-08-01 15:00:36 -07001071 unsigned int start;
Florian Fainelli5f6b4e142017-08-03 21:33:27 -07001072 int i;
Florian Fainellif613ed62017-08-01 15:00:36 -07001073
1074 netdev_stats_to_stats64(stats, &dev->stats);
Florian Fainelli5f6b4e142017-08-03 21:33:27 -07001075 for_each_possible_cpu(i) {
1076 u64 tx_packets, tx_bytes, rx_packets, rx_bytes;
1077
1078 s = per_cpu_ptr(p->stats64, i);
1079 do {
1080 start = u64_stats_fetch_begin_irq(&s->syncp);
1081 tx_packets = s->tx_packets;
1082 tx_bytes = s->tx_bytes;
1083 rx_packets = s->rx_packets;
1084 rx_bytes = s->rx_bytes;
1085 } while (u64_stats_fetch_retry_irq(&s->syncp, start));
1086
1087 stats->tx_packets += tx_packets;
1088 stats->tx_bytes += tx_bytes;
1089 stats->rx_packets += rx_packets;
1090 stats->rx_bytes += rx_bytes;
1091 }
Florian Fainellif613ed62017-08-01 15:00:36 -07001092}
1093
Florian Fainellibf9f2642017-01-30 09:48:40 -08001094static int dsa_slave_get_rxnfc(struct net_device *dev,
1095 struct ethtool_rxnfc *nfc, u32 *rule_locs)
1096{
Vivien Didelotd9450972017-10-16 11:12:15 -04001097 struct dsa_port *dp = dsa_slave_to_port(dev);
1098 struct dsa_switch *ds = dp->ds;
Florian Fainellibf9f2642017-01-30 09:48:40 -08001099
1100 if (!ds->ops->get_rxnfc)
1101 return -EOPNOTSUPP;
1102
Vivien Didelotd9450972017-10-16 11:12:15 -04001103 return ds->ops->get_rxnfc(ds, dp->index, nfc, rule_locs);
Florian Fainellibf9f2642017-01-30 09:48:40 -08001104}
1105
1106static int dsa_slave_set_rxnfc(struct net_device *dev,
1107 struct ethtool_rxnfc *nfc)
1108{
Vivien Didelotd9450972017-10-16 11:12:15 -04001109 struct dsa_port *dp = dsa_slave_to_port(dev);
1110 struct dsa_switch *ds = dp->ds;
Florian Fainellibf9f2642017-01-30 09:48:40 -08001111
1112 if (!ds->ops->set_rxnfc)
1113 return -EOPNOTSUPP;
1114
Vivien Didelotd9450972017-10-16 11:12:15 -04001115 return ds->ops->set_rxnfc(ds, dp->index, nfc);
Florian Fainellibf9f2642017-01-30 09:48:40 -08001116}
1117
Brandon Streiff03363692018-02-14 01:07:48 +01001118static int dsa_slave_get_ts_info(struct net_device *dev,
1119 struct ethtool_ts_info *ts)
1120{
1121 struct dsa_slave_priv *p = netdev_priv(dev);
1122 struct dsa_switch *ds = p->dp->ds;
1123
1124 if (!ds->ops->get_ts_info)
1125 return -EOPNOTSUPP;
1126
1127 return ds->ops->get_ts_info(ds, p->dp->index, ts);
1128}
1129
Florian Fainelli061f6a52019-02-20 14:35:39 -08001130static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
1131 u16 vid)
1132{
1133 struct dsa_port *dp = dsa_slave_to_port(dev);
Florian Fainelli061f6a52019-02-20 14:35:39 -08001134 struct bridge_vlan_info info;
1135 int ret;
1136
1137 /* Check for a possible bridge VLAN entry now since there is no
1138 * need to emulate the switchdev prepare + commit phase.
1139 */
1140 if (dp->bridge_dev) {
Vivien Didelotc5335d72019-08-25 13:25:18 -04001141 if (!br_vlan_enabled(dp->bridge_dev))
1142 return 0;
1143
Florian Fainelli061f6a52019-02-20 14:35:39 -08001144 /* br_vlan_get_info() returns -EINVAL or -ENOENT if the
1145 * device, respectively the VID is not found, returning
1146 * 0 means success, which is a failure for us here.
1147 */
1148 ret = br_vlan_get_info(dp->bridge_dev, vid, &info);
1149 if (ret == 0)
1150 return -EBUSY;
1151 }
1152
Vivien Didelotcf360862019-08-25 13:25:16 -04001153 ret = dsa_port_vid_add(dp, vid, 0);
Vladimir Oltean9b236d22019-08-25 22:46:29 +03001154 if (ret)
Vivien Didelotcf360862019-08-25 13:25:16 -04001155 return ret;
1156
Vivien Didelot7e1741b2019-08-25 13:25:19 -04001157 ret = dsa_port_vid_add(dp->cpu_dp, vid, 0);
Vladimir Oltean9b236d22019-08-25 22:46:29 +03001158 if (ret)
Vivien Didelot7e1741b2019-08-25 13:25:19 -04001159 return ret;
1160
Vivien Didelotcf360862019-08-25 13:25:16 -04001161 return 0;
Florian Fainelli061f6a52019-02-20 14:35:39 -08001162}
1163
1164static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
1165 u16 vid)
1166{
1167 struct dsa_port *dp = dsa_slave_to_port(dev);
Florian Fainelli061f6a52019-02-20 14:35:39 -08001168 struct bridge_vlan_info info;
1169 int ret;
1170
1171 /* Check for a possible bridge VLAN entry now since there is no
1172 * need to emulate the switchdev prepare + commit phase.
1173 */
1174 if (dp->bridge_dev) {
Vivien Didelotc5335d72019-08-25 13:25:18 -04001175 if (!br_vlan_enabled(dp->bridge_dev))
1176 return 0;
1177
Florian Fainelli061f6a52019-02-20 14:35:39 -08001178 /* br_vlan_get_info() returns -EINVAL or -ENOENT if the
1179 * device, respectively the VID is not found, returning
1180 * 0 means success, which is a failure for us here.
1181 */
1182 ret = br_vlan_get_info(dp->bridge_dev, vid, &info);
1183 if (ret == 0)
1184 return -EBUSY;
1185 }
1186
Vivien Didelot7e1741b2019-08-25 13:25:19 -04001187 /* Do not deprogram the CPU port as it may be shared with other user
1188 * ports which can be members of this VLAN as well.
1189 */
Vladimir Oltean9b236d22019-08-25 22:46:29 +03001190 return dsa_port_vid_del(dp, vid);
Florian Fainelli061f6a52019-02-20 14:35:39 -08001191}
1192
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001193static const struct ethtool_ops dsa_slave_ethtool_ops = {
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001194 .get_drvinfo = dsa_slave_get_drvinfo,
Guenter Roeck3d762a02014-10-29 10:45:04 -07001195 .get_regs_len = dsa_slave_get_regs_len,
1196 .get_regs = dsa_slave_get_regs,
Florian Fainelliaab9c402018-05-10 13:17:36 -07001197 .nway_reset = dsa_slave_nway_reset,
Florian Fainellic4aef9f2018-05-10 13:17:34 -07001198 .get_link = ethtool_op_get_link,
Guenter Roeck6793abb2014-10-29 10:45:01 -07001199 .get_eeprom_len = dsa_slave_get_eeprom_len,
1200 .get_eeprom = dsa_slave_get_eeprom,
1201 .set_eeprom = dsa_slave_set_eeprom,
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001202 .get_strings = dsa_slave_get_strings,
1203 .get_ethtool_stats = dsa_slave_get_ethtool_stats,
1204 .get_sset_count = dsa_slave_get_sset_count,
Florian Fainelli19e57c42014-09-18 17:31:24 -07001205 .set_wol = dsa_slave_set_wol,
1206 .get_wol = dsa_slave_get_wol,
Florian Fainelli79052882014-09-24 17:05:21 -07001207 .set_eee = dsa_slave_set_eee,
1208 .get_eee = dsa_slave_get_eee,
Florian Fainelliaab9c402018-05-10 13:17:36 -07001209 .get_link_ksettings = dsa_slave_get_link_ksettings,
1210 .set_link_ksettings = dsa_slave_set_link_ksettings,
Heiner Kallweita2a1a132019-10-29 22:32:48 +01001211 .get_pauseparam = dsa_slave_get_pauseparam,
1212 .set_pauseparam = dsa_slave_set_pauseparam,
Florian Fainellibf9f2642017-01-30 09:48:40 -08001213 .get_rxnfc = dsa_slave_get_rxnfc,
1214 .set_rxnfc = dsa_slave_set_rxnfc,
Brandon Streiff03363692018-02-14 01:07:48 +01001215 .get_ts_info = dsa_slave_get_ts_info,
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001216};
1217
Florian Fainelli2a93c1a2017-12-06 15:03:33 -08001218/* legacy way, bypassing the bridge *****************************************/
1219int dsa_legacy_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
1220 struct net_device *dev,
1221 const unsigned char *addr, u16 vid,
Petr Machata87b09842019-01-16 23:06:50 +00001222 u16 flags,
1223 struct netlink_ext_ack *extack)
Florian Fainelli2a93c1a2017-12-06 15:03:33 -08001224{
1225 struct dsa_port *dp = dsa_slave_to_port(dev);
1226
1227 return dsa_port_fdb_add(dp, addr, vid);
1228}
1229
1230int dsa_legacy_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
1231 struct net_device *dev,
1232 const unsigned char *addr, u16 vid)
1233{
1234 struct dsa_port *dp = dsa_slave_to_port(dev);
1235
1236 return dsa_port_fdb_del(dp, addr, vid);
1237}
1238
Jiri Pirko716efee2019-03-28 13:56:43 +01001239static struct devlink_port *dsa_slave_get_devlink_port(struct net_device *dev)
1240{
1241 struct dsa_port *dp = dsa_slave_to_port(dev);
1242
1243 return dp->ds->devlink ? &dp->devlink_port : NULL;
1244}
1245
Florian Fainelli3e8a72d2014-08-27 17:04:46 -07001246static const struct net_device_ops dsa_slave_netdev_ops = {
Stephen Hemmingerd442ad42009-01-06 16:45:26 -08001247 .ndo_open = dsa_slave_open,
1248 .ndo_stop = dsa_slave_close,
Florian Fainelli3e8a72d2014-08-27 17:04:46 -07001249 .ndo_start_xmit = dsa_slave_xmit,
Stephen Hemmingerd442ad42009-01-06 16:45:26 -08001250 .ndo_change_rx_flags = dsa_slave_change_rx_flags,
1251 .ndo_set_rx_mode = dsa_slave_set_rx_mode,
Stephen Hemmingerd442ad42009-01-06 16:45:26 -08001252 .ndo_set_mac_address = dsa_slave_set_mac_address,
Arkadi Sharshevsky37b8da12017-08-06 16:15:43 +03001253 .ndo_fdb_add = dsa_legacy_fdb_add,
1254 .ndo_fdb_del = dsa_legacy_fdb_del,
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +03001255 .ndo_fdb_dump = dsa_slave_fdb_dump,
Stephen Hemmingerd442ad42009-01-06 16:45:26 -08001256 .ndo_do_ioctl = dsa_slave_ioctl,
Nicolas Dichtelabd2be02015-04-02 17:07:08 +02001257 .ndo_get_iflink = dsa_slave_get_iflink,
Florian Fainelli04ff53f2015-07-31 11:42:57 -07001258#ifdef CONFIG_NET_POLL_CONTROLLER
1259 .ndo_netpoll_setup = dsa_slave_netpoll_setup,
1260 .ndo_netpoll_cleanup = dsa_slave_netpoll_cleanup,
1261 .ndo_poll_controller = dsa_slave_poll_controller,
1262#endif
Florian Fainelli44bb7652017-01-10 12:32:36 -08001263 .ndo_get_phys_port_name = dsa_slave_get_phys_port_name,
Florian Fainellif50f2122017-01-30 12:41:40 -08001264 .ndo_setup_tc = dsa_slave_setup_tc,
Florian Fainellif613ed62017-08-01 15:00:36 -07001265 .ndo_get_stats64 = dsa_slave_get_stats64,
Florian Fainelli929d6c12019-02-06 09:45:45 -08001266 .ndo_get_port_parent_id = dsa_slave_get_port_parent_id,
Florian Fainelli061f6a52019-02-20 14:35:39 -08001267 .ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid,
1268 .ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid,
Jiri Pirko716efee2019-03-28 13:56:43 +01001269 .ndo_get_devlink_port = dsa_slave_get_devlink_port,
Scott Feldman98237d42015-03-15 21:07:15 -07001270};
1271
Florian Fainellif37db852015-09-23 18:19:58 -07001272static struct device_type dsa_type = {
1273 .name = "dsa",
1274};
1275
Florian Fainelliaab9c402018-05-10 13:17:36 -07001276void dsa_port_phylink_mac_change(struct dsa_switch *ds, int port, bool up)
1277{
1278 const struct dsa_port *dp = dsa_to_port(ds, port);
1279
1280 phylink_mac_change(dp->pl, up);
1281}
1282EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_change);
1283
1284static void dsa_slave_phylink_fixed_state(struct net_device *dev,
1285 struct phylink_link_state *state)
1286{
1287 struct dsa_port *dp = dsa_slave_to_port(dev);
1288 struct dsa_switch *ds = dp->ds;
1289
1290 /* No need to check that this operation is valid, the callback would
1291 * not be called if it was not.
1292 */
1293 ds->ops->phylink_fixed_state(ds, dp->index, state);
Florian Fainellice31b312014-08-27 17:04:54 -07001294}
1295
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001296/* slave device setup *******************************************************/
Vivien Didelot4fa7b712017-09-20 19:31:57 -04001297static int dsa_slave_phy_connect(struct net_device *slave_dev, int addr)
Florian Fainellic305c162015-03-10 16:57:12 -07001298{
Vivien Didelotd9450972017-10-16 11:12:15 -04001299 struct dsa_port *dp = dsa_slave_to_port(slave_dev);
Vivien Didelotd9450972017-10-16 11:12:15 -04001300 struct dsa_switch *ds = dp->ds;
Florian Fainellic305c162015-03-10 16:57:12 -07001301
Vivien Didelot0115dcd2017-09-26 17:15:32 -04001302 slave_dev->phydev = mdiobus_get_phy(ds->slave_mii_bus, addr);
1303 if (!slave_dev->phydev) {
Russell Kingd25b8e72015-10-03 18:09:07 +01001304 netdev_err(slave_dev, "no phy at %d\n", addr);
Florian Fainellic305c162015-03-10 16:57:12 -07001305 return -ENODEV;
Russell Kingd25b8e72015-10-03 18:09:07 +01001306 }
Florian Fainellic305c162015-03-10 16:57:12 -07001307
Florian Fainelliaab9c402018-05-10 13:17:36 -07001308 return phylink_connect_phy(dp->pl, slave_dev->phydev);
Florian Fainellic305c162015-03-10 16:57:12 -07001309}
1310
Vivien Didelot4fa7b712017-09-20 19:31:57 -04001311static int dsa_slave_phy_setup(struct net_device *slave_dev)
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001312{
Vivien Didelotd9450972017-10-16 11:12:15 -04001313 struct dsa_port *dp = dsa_slave_to_port(slave_dev);
Vivien Didelotd9450972017-10-16 11:12:15 -04001314 struct device_node *port_dn = dp->dn;
1315 struct dsa_switch *ds = dp->ds;
Andrew Lunn0c65b2b2019-11-04 02:40:33 +01001316 phy_interface_t mode;
Florian Fainelli68195632014-09-19 13:07:54 -07001317 u32 phy_flags = 0;
Andrew Lunn0c65b2b2019-11-04 02:40:33 +01001318 int ret;
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001319
Andrew Lunn0c65b2b2019-11-04 02:40:33 +01001320 ret = of_get_phy_mode(port_dn, &mode);
1321 if (ret)
Guenter Roeck19334922015-02-16 21:23:51 -08001322 mode = PHY_INTERFACE_MODE_NA;
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001323
Ioana Ciornei44cc27e2019-05-28 20:38:12 +03001324 dp->pl_config.dev = &slave_dev->dev;
1325 dp->pl_config.type = PHYLINK_NETDEV;
1326
1327 dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), mode,
Ioana Ciornei77373d42019-05-28 20:38:15 +03001328 &dsa_port_phylink_mac_ops);
Florian Fainelliaab9c402018-05-10 13:17:36 -07001329 if (IS_ERR(dp->pl)) {
1330 netdev_err(slave_dev,
1331 "error creating PHYLINK: %ld\n", PTR_ERR(dp->pl));
1332 return PTR_ERR(dp->pl);
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001333 }
1334
Florian Fainelliaab9c402018-05-10 13:17:36 -07001335 /* Register only if the switch provides such a callback, since this
1336 * callback takes precedence over polling the link GPIO in PHYLINK
1337 * (see phylink_get_fixed_state).
1338 */
1339 if (ds->ops->phylink_fixed_state)
1340 phylink_fixed_state_cb(dp->pl, dsa_slave_phylink_fixed_state);
1341
Vivien Didelot9d490b42016-08-23 12:38:56 -04001342 if (ds->ops->get_phy_flags)
Vivien Didelotd9450972017-10-16 11:12:15 -04001343 phy_flags = ds->ops->get_phy_flags(ds, dp->index);
Florian Fainelli68195632014-09-19 13:07:54 -07001344
Florian Fainelliaab9c402018-05-10 13:17:36 -07001345 ret = phylink_of_phy_connect(dp->pl, port_dn, phy_flags);
Vladimir Oltean6146dd42019-03-24 01:24:07 +02001346 if (ret == -ENODEV && ds->slave_mii_bus) {
1347 /* We could not connect to a designated PHY or SFP, so try to
1348 * use the switch internal MDIO bus instead
Florian Fainelliaab9c402018-05-10 13:17:36 -07001349 */
Vivien Didelotd9450972017-10-16 11:12:15 -04001350 ret = dsa_slave_phy_connect(slave_dev, dp->index);
Russell Kingd25b8e72015-10-03 18:09:07 +01001351 if (ret) {
Florian Fainelliaab9c402018-05-10 13:17:36 -07001352 netdev_err(slave_dev,
1353 "failed to connect to port %d: %d\n",
Vivien Didelotd9450972017-10-16 11:12:15 -04001354 dp->index, ret);
Florian Fainelliaab9c402018-05-10 13:17:36 -07001355 phylink_destroy(dp->pl);
Florian Fainellic305c162015-03-10 16:57:12 -07001356 return ret;
Russell Kingd25b8e72015-10-03 18:09:07 +01001357 }
Andrew Lunnb31f65f2014-11-05 19:47:28 +01001358 }
Florian Fainelli9697f1c2014-12-11 12:49:16 -08001359
Vladimir Oltean6146dd42019-03-24 01:24:07 +02001360 return ret;
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001361}
1362
Florian Fainelli24462542014-09-18 17:31:22 -07001363int dsa_slave_suspend(struct net_device *slave_dev)
1364{
Florian Fainelliaab9c402018-05-10 13:17:36 -07001365 struct dsa_port *dp = dsa_slave_to_port(slave_dev);
Florian Fainelli24462542014-09-18 17:31:22 -07001366
Florian Fainellia94c6892018-07-31 17:12:52 -07001367 if (!netif_running(slave_dev))
1368 return 0;
1369
Vladimir Oltean97a69a02019-05-05 13:19:25 +03001370 cancel_work_sync(&dp->xmit_work);
1371 skb_queue_purge(&dp->xmit_queue);
1372
Florian Fainellif154be22017-01-25 09:10:41 -08001373 netif_device_detach(slave_dev);
1374
Florian Fainelliaab9c402018-05-10 13:17:36 -07001375 rtnl_lock();
1376 phylink_stop(dp->pl);
1377 rtnl_unlock();
Florian Fainelli24462542014-09-18 17:31:22 -07001378
1379 return 0;
1380}
1381
1382int dsa_slave_resume(struct net_device *slave_dev)
1383{
Florian Fainelliaab9c402018-05-10 13:17:36 -07001384 struct dsa_port *dp = dsa_slave_to_port(slave_dev);
1385
Florian Fainellia94c6892018-07-31 17:12:52 -07001386 if (!netif_running(slave_dev))
1387 return 0;
1388
Florian Fainelli24462542014-09-18 17:31:22 -07001389 netif_device_attach(slave_dev);
1390
Florian Fainelliaab9c402018-05-10 13:17:36 -07001391 rtnl_lock();
1392 phylink_start(dp->pl);
1393 rtnl_unlock();
Florian Fainelli24462542014-09-18 17:31:22 -07001394
1395 return 0;
1396}
1397
Vivien Didelot6158eaa2017-10-16 11:12:14 -04001398static void dsa_slave_notify(struct net_device *dev, unsigned long val)
1399{
Vivien Didelotd0006b02017-10-16 11:12:16 -04001400 struct net_device *master = dsa_slave_to_master(dev);
Vivien Didelotd9450972017-10-16 11:12:15 -04001401 struct dsa_port *dp = dsa_slave_to_port(dev);
Vivien Didelot6158eaa2017-10-16 11:12:14 -04001402 struct dsa_notifier_register_info rinfo = {
1403 .switch_number = dp->ds->index,
1404 .port_number = dp->index,
1405 .master = master,
1406 .info.dev = dev,
1407 };
1408
1409 call_dsa_notifiers(val, dev, &rinfo.info);
1410}
1411
Vivien Didelot951259aa2017-10-27 15:55:19 -04001412int dsa_slave_create(struct dsa_port *port)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001413{
Vivien Didelot24a93322017-11-06 16:11:43 -05001414 const struct dsa_port *cpu_dp = port->cpu_dp;
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -04001415 struct net_device *master = cpu_dp->master;
Vivien Didelot4cfbf092017-08-05 16:20:19 -04001416 struct dsa_switch *ds = port->ds;
Vivien Didelot951259aa2017-10-27 15:55:19 -04001417 const char *name = port->name;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001418 struct net_device *slave_dev;
1419 struct dsa_slave_priv *p;
1420 int ret;
1421
Florian Fainelli55199df2017-09-03 20:27:00 -07001422 if (!ds->num_tx_queues)
1423 ds->num_tx_queues = 1;
1424
1425 slave_dev = alloc_netdev_mqs(sizeof(struct dsa_slave_priv), name,
1426 NET_NAME_UNKNOWN, ether_setup,
1427 ds->num_tx_queues, 1);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001428 if (slave_dev == NULL)
Guenter Roeckd87d6f42015-02-24 13:15:32 -08001429 return -ENOMEM;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001430
Vladimir Oltean9b236d22019-08-25 22:46:29 +03001431 slave_dev->features = master->vlan_features | NETIF_F_HW_TC;
1432 if (ds->ops->port_vlan_add && ds->ops->port_vlan_del)
1433 slave_dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
Florian Fainellif50f2122017-01-30 12:41:40 -08001434 slave_dev->hw_features |= NETIF_F_HW_TC;
Wilfried Klaebe7ad24ea2014-05-11 00:12:32 +00001435 slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
Petr Å tetiar4974f9b2019-05-06 23:24:45 +02001436 if (!IS_ERR_OR_NULL(port->mac))
Xiaofei Shena2c70232019-03-29 11:04:58 +05301437 ether_addr_copy(slave_dev->dev_addr, port->mac);
1438 else
1439 eth_hw_addr_inherit(slave_dev, master);
Phil Sutter0a5f1072015-08-18 10:30:41 +02001440 slave_dev->priv_flags |= IFF_NO_QUEUE;
Florian Fainelli3e8a72d2014-08-27 17:04:46 -07001441 slave_dev->netdev_ops = &dsa_slave_netdev_ops;
Jarod Wilson8b1efc02016-10-20 23:25:27 -04001442 slave_dev->min_mtu = 0;
1443 slave_dev->max_mtu = ETH_MAX_MTU;
Florian Fainellif37db852015-09-23 18:19:58 -07001444 SET_NETDEV_DEVTYPE(slave_dev, &dsa_type);
Stephen Hemmingerd442ad42009-01-06 16:45:26 -08001445
Vivien Didelot4cfbf092017-08-05 16:20:19 -04001446 SET_NETDEV_DEV(slave_dev, port->ds->dev);
1447 slave_dev->dev.of_node = port->dn;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001448 slave_dev->vlan_features = master->vlan_features;
1449
1450 p = netdev_priv(slave_dev);
Florian Fainelli5f6b4e142017-08-03 21:33:27 -07001451 p->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
1452 if (!p->stats64) {
1453 free_netdev(slave_dev);
1454 return -ENOMEM;
1455 }
Vivien Didelot4cfbf092017-08-05 16:20:19 -04001456 p->dp = port;
Florian Fainellif50f2122017-01-30 12:41:40 -08001457 INIT_LIST_HEAD(&p->mall_tc_list);
Vladimir Oltean97a69a02019-05-05 13:19:25 +03001458 INIT_WORK(&port->xmit_work, dsa_port_xmit_work);
1459 skb_queue_head_init(&port->xmit_queue);
Vivien Didelot15240242017-09-29 17:19:18 -04001460 p->xmit = cpu_dp->tag_ops->xmit;
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -04001461 port->slave = slave_dev;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001462
1463 netif_carrier_off(slave_dev);
1464
Vivien Didelot4fa7b712017-09-20 19:31:57 -04001465 ret = dsa_slave_phy_setup(slave_dev);
Andrew Lunn0071f562016-01-06 20:11:20 +01001466 if (ret) {
1467 netdev_err(master, "error %d setting up slave phy\n", ret);
Florian Fainellie8044412017-09-25 15:55:53 -07001468 goto out_free;
1469 }
1470
Vivien Didelot6158eaa2017-10-16 11:12:14 -04001471 dsa_slave_notify(slave_dev, DSA_PORT_REGISTER);
Florian Fainelli60724d42017-10-11 10:57:48 -07001472
Florian Fainellie8044412017-09-25 15:55:53 -07001473 ret = register_netdev(slave_dev);
1474 if (ret) {
1475 netdev_err(master, "error %d registering interface %s\n",
1476 ret, slave_dev->name);
1477 goto out_phy;
Andrew Lunn0071f562016-01-06 20:11:20 +01001478 }
1479
Guenter Roeckd87d6f42015-02-24 13:15:32 -08001480 return 0;
Florian Fainellie8044412017-09-25 15:55:53 -07001481
1482out_phy:
Florian Fainelliaab9c402018-05-10 13:17:36 -07001483 rtnl_lock();
1484 phylink_disconnect_phy(p->dp->pl);
1485 rtnl_unlock();
1486 phylink_destroy(p->dp->pl);
Florian Fainellie8044412017-09-25 15:55:53 -07001487out_free:
1488 free_percpu(p->stats64);
1489 free_netdev(slave_dev);
Vivien Didelotf8b8b1c2017-10-16 11:12:18 -04001490 port->slave = NULL;
Florian Fainellie8044412017-09-25 15:55:53 -07001491 return ret;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001492}
Florian Fainellib73adef2015-02-24 13:15:33 -08001493
Neil Armstrongcda5c152015-12-07 13:57:35 +01001494void dsa_slave_destroy(struct net_device *slave_dev)
1495{
Vivien Didelotd9450972017-10-16 11:12:15 -04001496 struct dsa_port *dp = dsa_slave_to_port(slave_dev);
Neil Armstrongcda5c152015-12-07 13:57:35 +01001497 struct dsa_slave_priv *p = netdev_priv(slave_dev);
1498
1499 netif_carrier_off(slave_dev);
Florian Fainelliaab9c402018-05-10 13:17:36 -07001500 rtnl_lock();
1501 phylink_disconnect_phy(dp->pl);
1502 rtnl_unlock();
Johan Hovold881eada2016-11-28 19:25:09 +01001503
Vivien Didelot6158eaa2017-10-16 11:12:14 -04001504 dsa_slave_notify(slave_dev, DSA_PORT_UNREGISTER);
Neil Armstrongcda5c152015-12-07 13:57:35 +01001505 unregister_netdev(slave_dev);
Florian Fainelliaab9c402018-05-10 13:17:36 -07001506 phylink_destroy(dp->pl);
Florian Fainelli5f6b4e142017-08-03 21:33:27 -07001507 free_percpu(p->stats64);
Neil Armstrongcda5c152015-12-07 13:57:35 +01001508 free_netdev(slave_dev);
1509}
1510
Vivien Didelotf3b78042019-06-14 13:49:21 -04001511static bool dsa_slave_dev_check(const struct net_device *dev)
Florian Fainellib73adef2015-02-24 13:15:33 -08001512{
1513 return dev->netdev_ops == &dsa_slave_netdev_ops;
1514}
1515
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001516static int dsa_slave_changeupper(struct net_device *dev,
1517 struct netdev_notifier_changeupper_info *info)
Florian Fainellib73adef2015-02-24 13:15:33 -08001518{
Vivien Didelotd9450972017-10-16 11:12:15 -04001519 struct dsa_port *dp = dsa_slave_to_port(dev);
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001520 int err = NOTIFY_DONE;
Florian Fainellib73adef2015-02-24 13:15:33 -08001521
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001522 if (netif_is_bridge_master(info->upper_dev)) {
1523 if (info->linking) {
Vivien Didelot17d78022017-05-19 17:00:38 -04001524 err = dsa_port_bridge_join(dp, info->upper_dev);
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001525 err = notifier_from_errno(err);
1526 } else {
Vivien Didelot17d78022017-05-19 17:00:38 -04001527 dsa_port_bridge_leave(dp, info->upper_dev);
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001528 err = NOTIFY_OK;
Vivien Didelot6debb682016-03-13 16:21:34 -04001529 }
Vivien Didelot6debb682016-03-13 16:21:34 -04001530 }
1531
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001532 return err;
Florian Fainellib73adef2015-02-24 13:15:33 -08001533}
1534
Florian Fainellicc1d5bd2019-02-20 14:35:38 -08001535static int dsa_slave_upper_vlan_check(struct net_device *dev,
1536 struct netdev_notifier_changeupper_info *
1537 info)
1538{
1539 struct netlink_ext_ack *ext_ack;
1540 struct net_device *slave;
1541 struct dsa_port *dp;
1542
1543 ext_ack = netdev_notifier_info_to_extack(&info->info);
1544
1545 if (!is_vlan_dev(dev))
1546 return NOTIFY_DONE;
1547
1548 slave = vlan_dev_real_dev(dev);
1549 if (!dsa_slave_dev_check(slave))
1550 return NOTIFY_DONE;
1551
1552 dp = dsa_slave_to_port(slave);
1553 if (!dp->bridge_dev)
1554 return NOTIFY_DONE;
1555
1556 /* Deny enslaving a VLAN device into a VLAN-aware bridge */
1557 if (br_vlan_enabled(dp->bridge_dev) &&
1558 netif_is_bridge_master(info->upper_dev) && info->linking) {
1559 NL_SET_ERR_MSG_MOD(ext_ack,
1560 "Cannot enslave VLAN device into VLAN aware bridge");
1561 return notifier_from_errno(-EINVAL);
1562 }
1563
1564 return NOTIFY_DONE;
1565}
1566
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001567static int dsa_slave_netdevice_event(struct notifier_block *nb,
1568 unsigned long event, void *ptr)
Florian Fainellib73adef2015-02-24 13:15:33 -08001569{
Vivien Didelot6debb682016-03-13 16:21:34 -04001570 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Florian Fainellib73adef2015-02-24 13:15:33 -08001571
Florian Fainellicc1d5bd2019-02-20 14:35:38 -08001572 if (event == NETDEV_CHANGEUPPER) {
1573 if (!dsa_slave_dev_check(dev))
1574 return dsa_slave_upper_vlan_check(dev, ptr);
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001575
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001576 return dsa_slave_changeupper(dev, ptr);
Florian Fainellicc1d5bd2019-02-20 14:35:38 -08001577 }
Florian Fainellib73adef2015-02-24 13:15:33 -08001578
Florian Fainellib73adef2015-02-24 13:15:33 -08001579 return NOTIFY_DONE;
1580}
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001581
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001582struct dsa_switchdev_event_work {
1583 struct work_struct work;
1584 struct switchdev_notifier_fdb_info fdb_info;
1585 struct net_device *dev;
1586 unsigned long event;
1587};
1588
1589static void dsa_slave_switchdev_event_work(struct work_struct *work)
1590{
1591 struct dsa_switchdev_event_work *switchdev_work =
1592 container_of(work, struct dsa_switchdev_event_work, work);
1593 struct net_device *dev = switchdev_work->dev;
1594 struct switchdev_notifier_fdb_info *fdb_info;
Vivien Didelotd9450972017-10-16 11:12:15 -04001595 struct dsa_port *dp = dsa_slave_to_port(dev);
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001596 int err;
1597
1598 rtnl_lock();
1599 switch (switchdev_work->event) {
1600 case SWITCHDEV_FDB_ADD_TO_DEVICE:
1601 fdb_info = &switchdev_work->fdb_info;
Vivien Didelota37fb852018-05-08 23:03:12 -04001602 if (!fdb_info->added_by_user)
1603 break;
1604
Vivien Didelotd9450972017-10-16 11:12:15 -04001605 err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid);
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001606 if (err) {
1607 netdev_dbg(dev, "fdb add failed err=%d\n", err);
1608 break;
1609 }
Ido Schimmele9ba0fb2018-10-17 08:53:29 +00001610 fdb_info->offloaded = true;
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001611 call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev,
Petr Machata66859872019-01-16 23:06:56 +00001612 &fdb_info->info, NULL);
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001613 break;
1614
1615 case SWITCHDEV_FDB_DEL_TO_DEVICE:
1616 fdb_info = &switchdev_work->fdb_info;
Vivien Didelota37fb852018-05-08 23:03:12 -04001617 if (!fdb_info->added_by_user)
1618 break;
1619
Vivien Didelotd9450972017-10-16 11:12:15 -04001620 err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid);
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001621 if (err) {
1622 netdev_dbg(dev, "fdb del failed err=%d\n", err);
1623 dev_close(dev);
1624 }
1625 break;
1626 }
1627 rtnl_unlock();
1628
1629 kfree(switchdev_work->fdb_info.addr);
1630 kfree(switchdev_work);
1631 dev_put(dev);
1632}
1633
1634static int
1635dsa_slave_switchdev_fdb_work_init(struct dsa_switchdev_event_work *
1636 switchdev_work,
1637 const struct switchdev_notifier_fdb_info *
1638 fdb_info)
1639{
1640 memcpy(&switchdev_work->fdb_info, fdb_info,
1641 sizeof(switchdev_work->fdb_info));
1642 switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
1643 if (!switchdev_work->fdb_info.addr)
1644 return -ENOMEM;
1645 ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
1646 fdb_info->addr);
1647 return 0;
1648}
1649
1650/* Called under rcu_read_lock() */
1651static int dsa_slave_switchdev_event(struct notifier_block *unused,
1652 unsigned long event, void *ptr)
1653{
1654 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
1655 struct dsa_switchdev_event_work *switchdev_work;
Vivien Didelot79b139f2019-06-14 13:49:22 -04001656 int err;
1657
1658 if (event == SWITCHDEV_PORT_ATTR_SET) {
1659 err = switchdev_handle_port_attr_set(dev, ptr,
1660 dsa_slave_dev_check,
1661 dsa_slave_port_attr_set);
1662 return notifier_from_errno(err);
1663 }
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001664
1665 if (!dsa_slave_dev_check(dev))
1666 return NOTIFY_DONE;
1667
1668 switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
1669 if (!switchdev_work)
1670 return NOTIFY_BAD;
1671
1672 INIT_WORK(&switchdev_work->work,
1673 dsa_slave_switchdev_event_work);
1674 switchdev_work->dev = dev;
1675 switchdev_work->event = event;
1676
1677 switch (event) {
1678 case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */
1679 case SWITCHDEV_FDB_DEL_TO_DEVICE:
Vivien Didelota37fb852018-05-08 23:03:12 -04001680 if (dsa_slave_switchdev_fdb_work_init(switchdev_work, ptr))
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001681 goto err_fdb_work_init;
1682 dev_hold(dev);
1683 break;
1684 default:
1685 kfree(switchdev_work);
1686 return NOTIFY_DONE;
1687 }
1688
1689 dsa_schedule_work(&switchdev_work->work);
1690 return NOTIFY_OK;
1691
1692err_fdb_work_init:
1693 kfree(switchdev_work);
1694 return NOTIFY_BAD;
1695}
1696
Petr Machata2b239f62018-11-22 23:29:05 +00001697static int dsa_slave_switchdev_blocking_event(struct notifier_block *unused,
1698 unsigned long event, void *ptr)
1699{
1700 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
Vivien Didelot79b139f2019-06-14 13:49:22 -04001701 int err;
Petr Machata2b239f62018-11-22 23:29:05 +00001702
1703 switch (event) {
Vivien Didelot79b139f2019-06-14 13:49:22 -04001704 case SWITCHDEV_PORT_OBJ_ADD:
1705 err = switchdev_handle_port_obj_add(dev, ptr,
1706 dsa_slave_dev_check,
1707 dsa_slave_port_obj_add);
1708 return notifier_from_errno(err);
Petr Machata2b239f62018-11-22 23:29:05 +00001709 case SWITCHDEV_PORT_OBJ_DEL:
Vivien Didelot79b139f2019-06-14 13:49:22 -04001710 err = switchdev_handle_port_obj_del(dev, ptr,
1711 dsa_slave_dev_check,
1712 dsa_slave_port_obj_del);
1713 return notifier_from_errno(err);
Florian Fainelli9ed1ece2019-02-27 11:44:27 -08001714 case SWITCHDEV_PORT_ATTR_SET:
Vivien Didelot79b139f2019-06-14 13:49:22 -04001715 err = switchdev_handle_port_attr_set(dev, ptr,
1716 dsa_slave_dev_check,
1717 dsa_slave_port_attr_set);
1718 return notifier_from_errno(err);
Petr Machata2b239f62018-11-22 23:29:05 +00001719 }
1720
1721 return NOTIFY_DONE;
1722}
1723
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001724static struct notifier_block dsa_slave_nb __read_mostly = {
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001725 .notifier_call = dsa_slave_netdevice_event,
1726};
1727
1728static struct notifier_block dsa_slave_switchdev_notifier = {
1729 .notifier_call = dsa_slave_switchdev_event,
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001730};
1731
Petr Machata2b239f62018-11-22 23:29:05 +00001732static struct notifier_block dsa_slave_switchdev_blocking_notifier = {
1733 .notifier_call = dsa_slave_switchdev_blocking_event,
1734};
1735
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001736int dsa_slave_register_notifier(void)
1737{
Petr Machata2b239f62018-11-22 23:29:05 +00001738 struct notifier_block *nb;
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001739 int err;
1740
1741 err = register_netdevice_notifier(&dsa_slave_nb);
1742 if (err)
1743 return err;
1744
1745 err = register_switchdev_notifier(&dsa_slave_switchdev_notifier);
1746 if (err)
1747 goto err_switchdev_nb;
1748
Petr Machata2b239f62018-11-22 23:29:05 +00001749 nb = &dsa_slave_switchdev_blocking_notifier;
1750 err = register_switchdev_blocking_notifier(nb);
1751 if (err)
1752 goto err_switchdev_blocking_nb;
1753
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001754 return 0;
1755
Petr Machata2b239f62018-11-22 23:29:05 +00001756err_switchdev_blocking_nb:
1757 unregister_switchdev_notifier(&dsa_slave_switchdev_notifier);
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001758err_switchdev_nb:
1759 unregister_netdevice_notifier(&dsa_slave_nb);
1760 return err;
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001761}
1762
1763void dsa_slave_unregister_notifier(void)
1764{
Petr Machata2b239f62018-11-22 23:29:05 +00001765 struct notifier_block *nb;
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001766 int err;
1767
Petr Machata2b239f62018-11-22 23:29:05 +00001768 nb = &dsa_slave_switchdev_blocking_notifier;
1769 err = unregister_switchdev_blocking_notifier(nb);
1770 if (err)
1771 pr_err("DSA: failed to unregister switchdev blocking notifier (%d)\n", err);
1772
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001773 err = unregister_switchdev_notifier(&dsa_slave_switchdev_notifier);
1774 if (err)
1775 pr_err("DSA: failed to unregister switchdev notifier (%d)\n", err);
1776
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001777 err = unregister_netdevice_notifier(&dsa_slave_nb);
1778 if (err)
1779 pr_err("DSA: failed to unregister slave notifier (%d)\n", err);
1780}