blob: 894602c88b096cacc32e9f940a70635e57d0ab37 [file] [log] [blame]
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001/*
2 * net/dsa/slave.c - Slave device handling
Lennert Buytenheke84665c2009-03-20 09:52:09 +00003 * Copyright (c) 2008-2009 Marvell Semiconductor
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11#include <linux/list.h>
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -080012#include <linux/etherdevice.h>
Florian Fainellib73adef2015-02-24 13:15:33 -080013#include <linux/netdevice.h>
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000014#include <linux/phy.h>
Florian Fainellia2820542014-10-17 16:02:13 -070015#include <linux/phy_fixed.h>
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -070016#include <linux/of_net.h>
17#include <linux/of_mdio.h>
Andrew Lunn7f854422016-01-06 20:11:18 +010018#include <linux/mdio.h>
Florian Fainellif50f2122017-01-30 12:41:40 -080019#include <linux/list.h>
Florian Fainellib73adef2015-02-24 13:15:33 -080020#include <net/rtnetlink.h>
Florian Fainellif50f2122017-01-30 12:41:40 -080021#include <net/pkt_cls.h>
22#include <net/tc_act/tc_mirred.h>
Florian Fainellib73adef2015-02-24 13:15:33 -080023#include <linux/if_bridge.h>
Florian Fainelli04ff53f2015-07-31 11:42:57 -070024#include <linux/netpoll.h>
Vivien Didelotea5dd342017-05-17 15:46:03 -040025
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000026#include "dsa_priv.h"
27
Florian Fainellif50f2122017-01-30 12:41:40 -080028static bool dsa_slave_dev_check(struct net_device *dev);
29
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000030/* slave mii_bus handling ***************************************************/
31static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
32{
33 struct dsa_switch *ds = bus->priv;
34
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -070035 if (ds->phys_mii_mask & (1 << addr))
Vivien Didelot9d490b42016-08-23 12:38:56 -040036 return ds->ops->phy_read(ds, addr, reg);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000037
38 return 0xffff;
39}
40
41static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
42{
43 struct dsa_switch *ds = bus->priv;
44
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -070045 if (ds->phys_mii_mask & (1 << addr))
Vivien Didelot9d490b42016-08-23 12:38:56 -040046 return ds->ops->phy_write(ds, addr, reg, val);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000047
48 return 0;
49}
50
51void dsa_slave_mii_bus_init(struct dsa_switch *ds)
52{
53 ds->slave_mii_bus->priv = (void *)ds;
54 ds->slave_mii_bus->name = "dsa slave smi";
55 ds->slave_mii_bus->read = dsa_slave_phy_read;
56 ds->slave_mii_bus->write = dsa_slave_phy_write;
Florian Fainelli0b7b4982016-06-07 16:32:38 -070057 snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d",
58 ds->dst->tree, ds->index);
Andrew Lunnc33063d2016-05-10 23:27:23 +020059 ds->slave_mii_bus->parent = ds->dev;
Vivien Didelot24df8982015-01-20 19:13:32 -050060 ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000061}
62
63
64/* slave device handling ****************************************************/
Nicolas Dichtelabd2be02015-04-02 17:07:08 +020065static int dsa_slave_get_iflink(const struct net_device *dev)
Lennert Buytenhekc0840802009-03-20 09:49:49 +000066{
67 struct dsa_slave_priv *p = netdev_priv(dev);
Lennert Buytenhekc0840802009-03-20 09:49:49 +000068
Florian Fainelli6d3c8c02017-06-13 13:27:19 -070069 return dsa_master_netdev(p)->ifindex;
Lennert Buytenhekc0840802009-03-20 09:49:49 +000070}
71
Lennert Buytenhek91da11f2008-10-07 13:44:02 +000072static int dsa_slave_open(struct net_device *dev)
73{
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -080074 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainelli6d3c8c02017-06-13 13:27:19 -070075 struct net_device *master = dsa_master_netdev(p);
Vivien Didelotd9450972017-10-16 11:12:15 -040076 struct dsa_port *dp = dsa_slave_to_port(dev);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -080077 int err;
78
79 if (!(master->flags & IFF_UP))
80 return -ENETDOWN;
81
Joe Perches8feedbb2012-05-08 18:56:57 +000082 if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) {
Jiri Pirkoa748ee22010-04-01 21:22:09 +000083 err = dev_uc_add(master, dev->dev_addr);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -080084 if (err < 0)
85 goto out;
86 }
87
88 if (dev->flags & IFF_ALLMULTI) {
89 err = dev_set_allmulti(master, 1);
90 if (err < 0)
91 goto del_unicast;
92 }
93 if (dev->flags & IFF_PROMISC) {
94 err = dev_set_promiscuity(master, 1);
95 if (err < 0)
96 goto clear_allmulti;
97 }
98
Vivien Didelot0115dcd2017-09-26 17:15:32 -040099 err = dsa_port_enable(dp, dev->phydev);
Vivien Didelotfb8a6a22017-09-22 19:01:56 -0400100 if (err)
101 goto clear_promisc;
Florian Fainellib73adef2015-02-24 13:15:33 -0800102
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400103 if (dev->phydev)
104 phy_start(dev->phydev);
Florian Fainellif7f1de52014-09-24 17:05:17 -0700105
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000106 return 0;
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800107
Florian Fainellib2f2af22014-09-24 17:05:18 -0700108clear_promisc:
109 if (dev->flags & IFF_PROMISC)
Gilad Ben-Yossef4fdeddf2015-06-25 16:50:13 +0300110 dev_set_promiscuity(master, -1);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800111clear_allmulti:
112 if (dev->flags & IFF_ALLMULTI)
113 dev_set_allmulti(master, -1);
114del_unicast:
Joe Perches8feedbb2012-05-08 18:56:57 +0000115 if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000116 dev_uc_del(master, dev->dev_addr);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800117out:
118 return err;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000119}
120
121static int dsa_slave_close(struct net_device *dev)
122{
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800123 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainelli6d3c8c02017-06-13 13:27:19 -0700124 struct net_device *master = dsa_master_netdev(p);
Vivien Didelotd9450972017-10-16 11:12:15 -0400125 struct dsa_port *dp = dsa_slave_to_port(dev);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800126
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400127 if (dev->phydev)
128 phy_stop(dev->phydev);
Florian Fainellif7f1de52014-09-24 17:05:17 -0700129
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400130 dsa_port_disable(dp, dev->phydev);
Vivien Didelot6457edf2017-09-22 19:01:55 -0400131
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800132 dev_mc_unsync(master, dev);
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000133 dev_uc_unsync(master, dev);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800134 if (dev->flags & IFF_ALLMULTI)
135 dev_set_allmulti(master, -1);
136 if (dev->flags & IFF_PROMISC)
137 dev_set_promiscuity(master, -1);
138
Joe Perches8feedbb2012-05-08 18:56:57 +0000139 if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000140 dev_uc_del(master, dev->dev_addr);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800141
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000142 return 0;
143}
144
145static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
146{
147 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainelli6d3c8c02017-06-13 13:27:19 -0700148 struct net_device *master = dsa_master_netdev(p);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000149
150 if (change & IFF_ALLMULTI)
151 dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1);
152 if (change & IFF_PROMISC)
153 dev_set_promiscuity(master, dev->flags & IFF_PROMISC ? 1 : -1);
154}
155
156static void dsa_slave_set_rx_mode(struct net_device *dev)
157{
158 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainelli6d3c8c02017-06-13 13:27:19 -0700159 struct net_device *master = dsa_master_netdev(p);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000160
161 dev_mc_sync(master, dev);
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000162 dev_uc_sync(master, dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000163}
164
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800165static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000166{
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800167 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainelli6d3c8c02017-06-13 13:27:19 -0700168 struct net_device *master = dsa_master_netdev(p);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800169 struct sockaddr *addr = a;
170 int err;
171
172 if (!is_valid_ether_addr(addr->sa_data))
173 return -EADDRNOTAVAIL;
174
175 if (!(dev->flags & IFF_UP))
176 goto out;
177
Joe Perches8feedbb2012-05-08 18:56:57 +0000178 if (!ether_addr_equal(addr->sa_data, master->dev_addr)) {
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000179 err = dev_uc_add(master, addr->sa_data);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800180 if (err < 0)
181 return err;
182 }
183
Joe Perches8feedbb2012-05-08 18:56:57 +0000184 if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
Jiri Pirkoa748ee22010-04-01 21:22:09 +0000185 dev_uc_del(master, dev->dev_addr);
Lennert Buytenhekdf02c6f2008-11-10 21:53:12 -0800186
187out:
Joe Perchesd08f1612014-01-20 09:52:20 -0800188 ether_addr_copy(dev->dev_addr, addr->sa_data);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000189
190 return 0;
191}
192
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +0300193struct dsa_slave_dump_ctx {
194 struct net_device *dev;
195 struct sk_buff *skb;
196 struct netlink_callback *cb;
197 int idx;
198};
199
200static int
201dsa_slave_port_fdb_do_dump(const unsigned char *addr, u16 vid,
202 bool is_static, void *data)
203{
204 struct dsa_slave_dump_ctx *dump = data;
205 u32 portid = NETLINK_CB(dump->cb->skb).portid;
206 u32 seq = dump->cb->nlh->nlmsg_seq;
207 struct nlmsghdr *nlh;
208 struct ndmsg *ndm;
209
210 if (dump->idx < dump->cb->args[2])
211 goto skip;
212
213 nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH,
214 sizeof(*ndm), NLM_F_MULTI);
215 if (!nlh)
216 return -EMSGSIZE;
217
218 ndm = nlmsg_data(nlh);
219 ndm->ndm_family = AF_BRIDGE;
220 ndm->ndm_pad1 = 0;
221 ndm->ndm_pad2 = 0;
222 ndm->ndm_flags = NTF_SELF;
223 ndm->ndm_type = 0;
224 ndm->ndm_ifindex = dump->dev->ifindex;
225 ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE;
226
227 if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr))
228 goto nla_put_failure;
229
230 if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid))
231 goto nla_put_failure;
232
233 nlmsg_end(dump->skb, nlh);
234
235skip:
236 dump->idx++;
237 return 0;
238
239nla_put_failure:
240 nlmsg_cancel(dump->skb, nlh);
241 return -EMSGSIZE;
242}
243
244static int
245dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
246 struct net_device *dev, struct net_device *filter_dev,
247 int *idx)
248{
Vivien Didelotd9450972017-10-16 11:12:15 -0400249 struct dsa_port *dp = dsa_slave_to_port(dev);
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +0300250 struct dsa_slave_dump_ctx dump = {
251 .dev = dev,
252 .skb = skb,
253 .cb = cb,
254 .idx = *idx,
255 };
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +0300256 int err;
257
Vivien Didelotde40fc52017-09-20 19:32:14 -0400258 err = dsa_port_fdb_dump(dp, dsa_slave_port_fdb_do_dump, &dump);
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +0300259 *idx = dump.idx;
Vivien Didelotde40fc52017-09-20 19:32:14 -0400260
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +0300261 return err;
262}
263
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000264static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
265{
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400266 if (!dev->phydev)
Vivien Didelotf4344e02017-09-26 17:15:31 -0400267 return -ENODEV;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000268
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400269 return phy_mii_ioctl(dev->phydev, ifr, cmd);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000270}
271
Scott Feldman35636062015-05-10 09:47:51 -0700272static int dsa_slave_port_attr_set(struct net_device *dev,
Jiri Pirkof7fadf32015-10-14 19:40:49 +0200273 const struct switchdev_attr *attr,
Jiri Pirko7ea6eb32015-09-24 10:02:41 +0200274 struct switchdev_trans *trans)
Scott Feldman35636062015-05-10 09:47:51 -0700275{
Vivien Didelotd9450972017-10-16 11:12:15 -0400276 struct dsa_port *dp = dsa_slave_to_port(dev);
Vivien Didelotb8d866a2015-09-29 12:38:36 -0400277 int ret;
Scott Feldman35636062015-05-10 09:47:51 -0700278
279 switch (attr->id) {
Jiri Pirko1f868392015-10-01 11:03:42 +0200280 case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
Vivien Didelotfd364542017-05-19 17:00:36 -0400281 ret = dsa_port_set_state(dp, attr->u.stp_state, trans);
Scott Feldman35636062015-05-10 09:47:51 -0700282 break;
Vivien Didelotfb2daba2016-02-26 13:16:00 -0500283 case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
Vivien Didelotc02c4172017-05-19 17:00:42 -0400284 ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering,
285 trans);
Vivien Didelotfb2daba2016-02-26 13:16:00 -0500286 break;
Vivien Didelot34a79f62016-07-18 20:45:38 -0400287 case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
Vivien Didelot072bb192017-05-19 17:00:43 -0400288 ret = dsa_port_ageing_time(dp, attr->u.ageing_time, trans);
Vivien Didelot34a79f62016-07-18 20:45:38 -0400289 break;
Scott Feldman35636062015-05-10 09:47:51 -0700290 default:
291 ret = -EOPNOTSUPP;
292 break;
293 }
294
295 return ret;
296}
297
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400298static int dsa_slave_port_obj_add(struct net_device *dev,
Jiri Pirko648b4a92015-10-01 11:03:45 +0200299 const struct switchdev_obj *obj,
Jiri Pirko7ea6eb32015-09-24 10:02:41 +0200300 struct switchdev_trans *trans)
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400301{
Vivien Didelotd9450972017-10-16 11:12:15 -0400302 struct dsa_port *dp = dsa_slave_to_port(dev);
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400303 int err;
304
305 /* For the prepare phase, ensure the full set of changes is feasable in
306 * one go in order to signal a failure properly. If an operation is not
307 * supported, return -EOPNOTSUPP.
308 */
309
Jiri Pirko9e8f4a52015-10-01 11:03:46 +0200310 switch (obj->id) {
Vivien Didelot8df30252016-08-31 11:50:03 -0400311 case SWITCHDEV_OBJ_ID_PORT_MDB:
Vivien Didelotbcebb972017-05-19 17:00:40 -0400312 err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj), trans);
Vivien Didelot8df30252016-08-31 11:50:03 -0400313 break;
Jiri Pirko57d80832015-10-01 11:03:41 +0200314 case SWITCHDEV_OBJ_ID_PORT_VLAN:
Vivien Didelot01676d12017-05-19 17:00:41 -0400315 err = dsa_port_vlan_add(dp, SWITCHDEV_OBJ_PORT_VLAN(obj),
316 trans);
Vivien Didelot11149532015-08-13 12:52:17 -0400317 break;
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400318 default:
319 err = -EOPNOTSUPP;
320 break;
321 }
322
323 return err;
324}
325
326static int dsa_slave_port_obj_del(struct net_device *dev,
Jiri Pirko648b4a92015-10-01 11:03:45 +0200327 const struct switchdev_obj *obj)
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400328{
Vivien Didelotd9450972017-10-16 11:12:15 -0400329 struct dsa_port *dp = dsa_slave_to_port(dev);
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400330 int err;
331
Jiri Pirko9e8f4a52015-10-01 11:03:46 +0200332 switch (obj->id) {
Vivien Didelot8df30252016-08-31 11:50:03 -0400333 case SWITCHDEV_OBJ_ID_PORT_MDB:
Vivien Didelotbcebb972017-05-19 17:00:40 -0400334 err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
Vivien Didelot8df30252016-08-31 11:50:03 -0400335 break;
Jiri Pirko57d80832015-10-01 11:03:41 +0200336 case SWITCHDEV_OBJ_ID_PORT_VLAN:
Vivien Didelot01676d12017-05-19 17:00:41 -0400337 err = dsa_port_vlan_del(dp, SWITCHDEV_OBJ_PORT_VLAN(obj));
Vivien Didelot11149532015-08-13 12:52:17 -0400338 break;
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400339 default:
340 err = -EOPNOTSUPP;
341 break;
342 }
343
344 return err;
345}
346
Scott Feldmanf8e20a92015-05-10 09:47:49 -0700347static int dsa_slave_port_attr_get(struct net_device *dev,
348 struct switchdev_attr *attr)
Florian Fainellib73adef2015-02-24 13:15:33 -0800349{
Vivien Didelotd9450972017-10-16 11:12:15 -0400350 struct dsa_port *dp = dsa_slave_to_port(dev);
351 struct dsa_switch *ds = dp->ds;
Florian Fainellib73adef2015-02-24 13:15:33 -0800352
Scott Feldmanf8e20a92015-05-10 09:47:49 -0700353 switch (attr->id) {
Jiri Pirko1f868392015-10-01 11:03:42 +0200354 case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
Scott Feldman42275bd2015-05-13 11:16:50 -0700355 attr->u.ppid.id_len = sizeof(ds->index);
356 memcpy(&attr->u.ppid.id, &ds->index, attr->u.ppid.id_len);
Scott Feldmanf8e20a92015-05-10 09:47:49 -0700357 break;
Arkadi Sharshevskyc9e21052017-08-06 16:15:44 +0300358 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT:
359 attr->u.brport_flags_support = 0;
360 break;
Scott Feldmanf8e20a92015-05-10 09:47:49 -0700361 default:
362 return -EOPNOTSUPP;
363 }
Florian Fainellib73adef2015-02-24 13:15:33 -0800364
365 return 0;
366}
367
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400368static inline netdev_tx_t dsa_slave_netpoll_send_skb(struct net_device *dev,
369 struct sk_buff *skb)
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700370{
371#ifdef CONFIG_NET_POLL_CONTROLLER
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400372 struct dsa_slave_priv *p = netdev_priv(dev);
373
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700374 if (p->netpoll)
375 netpoll_send_skb(p->netpoll, skb);
376#else
377 BUG();
378#endif
379 return NETDEV_TX_OK;
380}
381
Florian Fainelli3e8a72d2014-08-27 17:04:46 -0700382static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
383{
384 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700385 struct pcpu_sw_netstats *s;
Florian Fainelli4ed70ce2015-07-31 11:42:56 -0700386 struct sk_buff *nskb;
Florian Fainelli3e8a72d2014-08-27 17:04:46 -0700387
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700388 s = this_cpu_ptr(p->stats64);
389 u64_stats_update_begin(&s->syncp);
390 s->tx_packets++;
391 s->tx_bytes += skb->len;
392 u64_stats_update_end(&s->syncp);
Florian Fainelli3e8a72d2014-08-27 17:04:46 -0700393
Vivien Didelotfe47d562017-06-01 16:07:15 -0400394 /* Transmit function may have to reallocate the original SKB,
395 * in which case it must have freed it. Only free it here on error.
396 */
Florian Fainelli4ed70ce2015-07-31 11:42:56 -0700397 nskb = p->xmit(skb, dev);
Vivien Didelotfe47d562017-06-01 16:07:15 -0400398 if (!nskb) {
399 kfree_skb(skb);
Florian Fainelli4ed70ce2015-07-31 11:42:56 -0700400 return NETDEV_TX_OK;
Vivien Didelotfe47d562017-06-01 16:07:15 -0400401 }
Florian Fainelli5aed85c2014-08-27 17:04:52 -0700402
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700403 /* SKB for netpoll still need to be mangled with the protocol-specific
404 * tag to be successfully transmitted
405 */
406 if (unlikely(netpoll_tx_running(dev)))
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400407 return dsa_slave_netpoll_send_skb(dev, nskb);
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700408
Florian Fainelli4ed70ce2015-07-31 11:42:56 -0700409 /* Queue the SKB for transmission on the parent interface, but
410 * do not modify its EtherType
411 */
Florian Fainelli6d3c8c02017-06-13 13:27:19 -0700412 nskb->dev = dsa_master_netdev(p);
Florian Fainelli4ed70ce2015-07-31 11:42:56 -0700413 dev_queue_xmit(nskb);
Florian Fainelli5aed85c2014-08-27 17:04:52 -0700414
415 return NETDEV_TX_OK;
416}
417
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000418/* ethtool operations *******************************************************/
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000419
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000420static void dsa_slave_get_drvinfo(struct net_device *dev,
421 struct ethtool_drvinfo *drvinfo)
422{
Jiri Pirko7826d432013-01-06 00:44:26 +0000423 strlcpy(drvinfo->driver, "dsa", sizeof(drvinfo->driver));
Jiri Pirko7826d432013-01-06 00:44:26 +0000424 strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
425 strlcpy(drvinfo->bus_info, "platform", sizeof(drvinfo->bus_info));
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000426}
427
Guenter Roeck3d762a02014-10-29 10:45:04 -0700428static int dsa_slave_get_regs_len(struct net_device *dev)
429{
Vivien Didelotd9450972017-10-16 11:12:15 -0400430 struct dsa_port *dp = dsa_slave_to_port(dev);
431 struct dsa_switch *ds = dp->ds;
Guenter Roeck3d762a02014-10-29 10:45:04 -0700432
Vivien Didelot9d490b42016-08-23 12:38:56 -0400433 if (ds->ops->get_regs_len)
Vivien Didelotd9450972017-10-16 11:12:15 -0400434 return ds->ops->get_regs_len(ds, dp->index);
Guenter Roeck3d762a02014-10-29 10:45:04 -0700435
436 return -EOPNOTSUPP;
437}
438
439static void
440dsa_slave_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
441{
Vivien Didelotd9450972017-10-16 11:12:15 -0400442 struct dsa_port *dp = dsa_slave_to_port(dev);
443 struct dsa_switch *ds = dp->ds;
Guenter Roeck3d762a02014-10-29 10:45:04 -0700444
Vivien Didelot9d490b42016-08-23 12:38:56 -0400445 if (ds->ops->get_regs)
Vivien Didelotd9450972017-10-16 11:12:15 -0400446 ds->ops->get_regs(ds, dp->index, regs, _p);
Guenter Roeck3d762a02014-10-29 10:45:04 -0700447}
448
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000449static u32 dsa_slave_get_link(struct net_device *dev)
450{
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400451 if (!dev->phydev)
Vivien Didelotf4344e02017-09-26 17:15:31 -0400452 return -ENODEV;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000453
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400454 genphy_update_link(dev->phydev);
Vivien Didelotf4344e02017-09-26 17:15:31 -0400455
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400456 return dev->phydev->link;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000457}
458
Guenter Roeck6793abb2014-10-29 10:45:01 -0700459static int dsa_slave_get_eeprom_len(struct net_device *dev)
460{
Vivien Didelotd9450972017-10-16 11:12:15 -0400461 struct dsa_port *dp = dsa_slave_to_port(dev);
462 struct dsa_switch *ds = dp->ds;
Guenter Roeck6793abb2014-10-29 10:45:01 -0700463
Andrew Lunn0e576042016-06-04 21:16:52 +0200464 if (ds->cd && ds->cd->eeprom_len)
Andrew Lunnff049552016-05-10 23:27:24 +0200465 return ds->cd->eeprom_len;
Guenter Roeck6793abb2014-10-29 10:45:01 -0700466
Vivien Didelot9d490b42016-08-23 12:38:56 -0400467 if (ds->ops->get_eeprom_len)
468 return ds->ops->get_eeprom_len(ds);
Guenter Roeck6793abb2014-10-29 10:45:01 -0700469
470 return 0;
471}
472
473static int dsa_slave_get_eeprom(struct net_device *dev,
474 struct ethtool_eeprom *eeprom, u8 *data)
475{
Vivien Didelotd9450972017-10-16 11:12:15 -0400476 struct dsa_port *dp = dsa_slave_to_port(dev);
477 struct dsa_switch *ds = dp->ds;
Guenter Roeck6793abb2014-10-29 10:45:01 -0700478
Vivien Didelot9d490b42016-08-23 12:38:56 -0400479 if (ds->ops->get_eeprom)
480 return ds->ops->get_eeprom(ds, eeprom, data);
Guenter Roeck6793abb2014-10-29 10:45:01 -0700481
482 return -EOPNOTSUPP;
483}
484
485static int dsa_slave_set_eeprom(struct net_device *dev,
486 struct ethtool_eeprom *eeprom, u8 *data)
487{
Vivien Didelotd9450972017-10-16 11:12:15 -0400488 struct dsa_port *dp = dsa_slave_to_port(dev);
489 struct dsa_switch *ds = dp->ds;
Guenter Roeck6793abb2014-10-29 10:45:01 -0700490
Vivien Didelot9d490b42016-08-23 12:38:56 -0400491 if (ds->ops->set_eeprom)
492 return ds->ops->set_eeprom(ds, eeprom, data);
Guenter Roeck6793abb2014-10-29 10:45:01 -0700493
494 return -EOPNOTSUPP;
495}
496
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000497static void dsa_slave_get_strings(struct net_device *dev,
498 uint32_t stringset, uint8_t *data)
499{
Vivien Didelotd9450972017-10-16 11:12:15 -0400500 struct dsa_port *dp = dsa_slave_to_port(dev);
501 struct dsa_switch *ds = dp->ds;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000502
503 if (stringset == ETH_SS_STATS) {
504 int len = ETH_GSTRING_LEN;
505
506 strncpy(data, "tx_packets", len);
507 strncpy(data + len, "tx_bytes", len);
508 strncpy(data + 2 * len, "rx_packets", len);
509 strncpy(data + 3 * len, "rx_bytes", len);
Vivien Didelot9d490b42016-08-23 12:38:56 -0400510 if (ds->ops->get_strings)
Vivien Didelotd9450972017-10-16 11:12:15 -0400511 ds->ops->get_strings(ds, dp->index, data + 4 * len);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000512 }
513}
514
515static void dsa_slave_get_ethtool_stats(struct net_device *dev,
516 struct ethtool_stats *stats,
517 uint64_t *data)
518{
Vivien Didelotd9450972017-10-16 11:12:15 -0400519 struct dsa_port *dp = dsa_slave_to_port(dev);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000520 struct dsa_slave_priv *p = netdev_priv(dev);
Vivien Didelotd9450972017-10-16 11:12:15 -0400521 struct dsa_switch *ds = dp->ds;
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700522 struct pcpu_sw_netstats *s;
Florian Fainellif613ed62017-08-01 15:00:36 -0700523 unsigned int start;
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700524 int i;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000525
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700526 for_each_possible_cpu(i) {
527 u64 tx_packets, tx_bytes, rx_packets, rx_bytes;
528
529 s = per_cpu_ptr(p->stats64, i);
530 do {
531 start = u64_stats_fetch_begin_irq(&s->syncp);
532 tx_packets = s->tx_packets;
533 tx_bytes = s->tx_bytes;
534 rx_packets = s->rx_packets;
535 rx_bytes = s->rx_bytes;
536 } while (u64_stats_fetch_retry_irq(&s->syncp, start));
537 data[0] += tx_packets;
538 data[1] += tx_bytes;
539 data[2] += rx_packets;
540 data[3] += rx_bytes;
541 }
Vivien Didelot9d490b42016-08-23 12:38:56 -0400542 if (ds->ops->get_ethtool_stats)
Vivien Didelotd9450972017-10-16 11:12:15 -0400543 ds->ops->get_ethtool_stats(ds, dp->index, data + 4);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000544}
545
546static int dsa_slave_get_sset_count(struct net_device *dev, int sset)
547{
Vivien Didelotd9450972017-10-16 11:12:15 -0400548 struct dsa_port *dp = dsa_slave_to_port(dev);
549 struct dsa_switch *ds = dp->ds;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000550
551 if (sset == ETH_SS_STATS) {
552 int count;
553
554 count = 4;
Vivien Didelot9d490b42016-08-23 12:38:56 -0400555 if (ds->ops->get_sset_count)
556 count += ds->ops->get_sset_count(ds);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000557
558 return count;
559 }
560
561 return -EOPNOTSUPP;
562}
563
Florian Fainelli19e57c42014-09-18 17:31:24 -0700564static void dsa_slave_get_wol(struct net_device *dev, struct ethtool_wolinfo *w)
565{
Vivien Didelotd9450972017-10-16 11:12:15 -0400566 struct dsa_port *dp = dsa_slave_to_port(dev);
567 struct dsa_switch *ds = dp->ds;
Florian Fainelli19e57c42014-09-18 17:31:24 -0700568
Vivien Didelot9d490b42016-08-23 12:38:56 -0400569 if (ds->ops->get_wol)
Vivien Didelotd9450972017-10-16 11:12:15 -0400570 ds->ops->get_wol(ds, dp->index, w);
Florian Fainelli19e57c42014-09-18 17:31:24 -0700571}
572
573static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w)
574{
Vivien Didelotd9450972017-10-16 11:12:15 -0400575 struct dsa_port *dp = dsa_slave_to_port(dev);
576 struct dsa_switch *ds = dp->ds;
Florian Fainelli19e57c42014-09-18 17:31:24 -0700577 int ret = -EOPNOTSUPP;
578
Vivien Didelot9d490b42016-08-23 12:38:56 -0400579 if (ds->ops->set_wol)
Vivien Didelotd9450972017-10-16 11:12:15 -0400580 ret = ds->ops->set_wol(ds, dp->index, w);
Florian Fainelli19e57c42014-09-18 17:31:24 -0700581
582 return ret;
583}
584
Florian Fainelli79052882014-09-24 17:05:21 -0700585static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e)
586{
Vivien Didelotd9450972017-10-16 11:12:15 -0400587 struct dsa_port *dp = dsa_slave_to_port(dev);
588 struct dsa_switch *ds = dp->ds;
Florian Fainelli79052882014-09-24 17:05:21 -0700589 int ret;
590
Vivien Didelot7b9cc732017-08-01 16:32:31 -0400591 /* Port's PHY and MAC both need to be EEE capable */
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400592 if (!dev->phydev)
Vivien Didelot7b9cc732017-08-01 16:32:31 -0400593 return -ENODEV;
594
Vivien Didelot08f50062017-08-01 16:32:41 -0400595 if (!ds->ops->set_mac_eee)
Florian Fainelli79052882014-09-24 17:05:21 -0700596 return -EOPNOTSUPP;
597
Vivien Didelotd9450972017-10-16 11:12:15 -0400598 ret = ds->ops->set_mac_eee(ds, dp->index, e);
Florian Fainelli79052882014-09-24 17:05:21 -0700599 if (ret)
600 return ret;
601
Vivien Didelotc48f7eb2017-08-01 16:32:38 -0400602 if (e->eee_enabled) {
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400603 ret = phy_init_eee(dev->phydev, 0);
Vivien Didelotc48f7eb2017-08-01 16:32:38 -0400604 if (ret)
605 return ret;
606 }
607
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400608 return phy_ethtool_set_eee(dev->phydev, e);
Florian Fainelli79052882014-09-24 17:05:21 -0700609}
610
611static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)
612{
Vivien Didelotd9450972017-10-16 11:12:15 -0400613 struct dsa_port *dp = dsa_slave_to_port(dev);
614 struct dsa_switch *ds = dp->ds;
Florian Fainelli79052882014-09-24 17:05:21 -0700615 int ret;
616
Vivien Didelot7b9cc732017-08-01 16:32:31 -0400617 /* Port's PHY and MAC both need to be EEE capable */
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400618 if (!dev->phydev)
Vivien Didelot7b9cc732017-08-01 16:32:31 -0400619 return -ENODEV;
620
Vivien Didelot08f50062017-08-01 16:32:41 -0400621 if (!ds->ops->get_mac_eee)
Florian Fainelli79052882014-09-24 17:05:21 -0700622 return -EOPNOTSUPP;
623
Vivien Didelotd9450972017-10-16 11:12:15 -0400624 ret = ds->ops->get_mac_eee(ds, dp->index, e);
Florian Fainelli79052882014-09-24 17:05:21 -0700625 if (ret)
626 return ret;
627
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400628 return phy_ethtool_get_eee(dev->phydev, e);
Florian Fainelli79052882014-09-24 17:05:21 -0700629}
630
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700631#ifdef CONFIG_NET_POLL_CONTROLLER
632static int dsa_slave_netpoll_setup(struct net_device *dev,
633 struct netpoll_info *ni)
634{
635 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainelli6d3c8c02017-06-13 13:27:19 -0700636 struct net_device *master = dsa_master_netdev(p);
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700637 struct netpoll *netpoll;
638 int err = 0;
639
640 netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
641 if (!netpoll)
642 return -ENOMEM;
643
644 err = __netpoll_setup(netpoll, master);
645 if (err) {
646 kfree(netpoll);
647 goto out;
648 }
649
650 p->netpoll = netpoll;
651out:
652 return err;
653}
654
655static void dsa_slave_netpoll_cleanup(struct net_device *dev)
656{
657 struct dsa_slave_priv *p = netdev_priv(dev);
658 struct netpoll *netpoll = p->netpoll;
659
660 if (!netpoll)
661 return;
662
663 p->netpoll = NULL;
664
665 __netpoll_free_async(netpoll);
666}
667
668static void dsa_slave_poll_controller(struct net_device *dev)
669{
670}
671#endif
672
Florian Fainelli44bb7652017-01-10 12:32:36 -0800673static int dsa_slave_get_phys_port_name(struct net_device *dev,
674 char *name, size_t len)
675{
Vivien Didelotd9450972017-10-16 11:12:15 -0400676 struct dsa_port *dp = dsa_slave_to_port(dev);
Florian Fainelli44bb7652017-01-10 12:32:36 -0800677
Vivien Didelotd9450972017-10-16 11:12:15 -0400678 if (snprintf(name, len, "p%d", dp->index) >= len)
Florian Fainelli44bb7652017-01-10 12:32:36 -0800679 return -EINVAL;
Florian Fainelli3a543ef2016-12-29 14:20:56 -0800680
681 return 0;
682}
683
Florian Fainellif50f2122017-01-30 12:41:40 -0800684static struct dsa_mall_tc_entry *
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400685dsa_slave_mall_tc_entry_find(struct net_device *dev, unsigned long cookie)
Florian Fainellif50f2122017-01-30 12:41:40 -0800686{
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400687 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainellif50f2122017-01-30 12:41:40 -0800688 struct dsa_mall_tc_entry *mall_tc_entry;
689
690 list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list)
691 if (mall_tc_entry->cookie == cookie)
692 return mall_tc_entry;
693
694 return NULL;
695}
696
697static int dsa_slave_add_cls_matchall(struct net_device *dev,
Florian Fainellif50f2122017-01-30 12:41:40 -0800698 struct tc_cls_matchall_offload *cls,
699 bool ingress)
700{
Vivien Didelotd9450972017-10-16 11:12:15 -0400701 struct dsa_port *dp = dsa_slave_to_port(dev);
Florian Fainellif50f2122017-01-30 12:41:40 -0800702 struct dsa_slave_priv *p = netdev_priv(dev);
703 struct dsa_mall_tc_entry *mall_tc_entry;
Jiri Pirko5fd9fc42017-08-07 10:15:29 +0200704 __be16 protocol = cls->common.protocol;
Florian Fainellif50f2122017-01-30 12:41:40 -0800705 struct net *net = dev_net(dev);
Vivien Didelotd9450972017-10-16 11:12:15 -0400706 struct dsa_switch *ds = dp->ds;
Florian Fainellif50f2122017-01-30 12:41:40 -0800707 struct net_device *to_dev;
708 const struct tc_action *a;
Vivien Didelotd9450972017-10-16 11:12:15 -0400709 struct dsa_port *to_dp;
Florian Fainellif50f2122017-01-30 12:41:40 -0800710 int err = -EOPNOTSUPP;
711 LIST_HEAD(actions);
712 int ifindex;
713
714 if (!ds->ops->port_mirror_add)
715 return err;
716
Jiri Pirko3bcc0ce2017-08-04 14:28:58 +0200717 if (!tcf_exts_has_one_action(cls->exts))
Florian Fainellif50f2122017-01-30 12:41:40 -0800718 return err;
719
720 tcf_exts_to_list(cls->exts, &actions);
721 a = list_first_entry(&actions, struct tc_action, list);
722
723 if (is_tcf_mirred_egress_mirror(a) && protocol == htons(ETH_P_ALL)) {
724 struct dsa_mall_mirror_tc_entry *mirror;
725
726 ifindex = tcf_mirred_ifindex(a);
727 to_dev = __dev_get_by_index(net, ifindex);
728 if (!to_dev)
729 return -EINVAL;
730
731 if (!dsa_slave_dev_check(to_dev))
732 return -EOPNOTSUPP;
733
734 mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL);
735 if (!mall_tc_entry)
736 return -ENOMEM;
737
738 mall_tc_entry->cookie = cls->cookie;
739 mall_tc_entry->type = DSA_PORT_MALL_MIRROR;
740 mirror = &mall_tc_entry->mirror;
741
Vivien Didelotd9450972017-10-16 11:12:15 -0400742 to_dp = dsa_slave_to_port(to_dev);
Florian Fainellif50f2122017-01-30 12:41:40 -0800743
Vivien Didelotd9450972017-10-16 11:12:15 -0400744 mirror->to_local_port = to_dp->index;
Florian Fainellif50f2122017-01-30 12:41:40 -0800745 mirror->ingress = ingress;
746
Vivien Didelotd9450972017-10-16 11:12:15 -0400747 err = ds->ops->port_mirror_add(ds, dp->index, mirror, ingress);
Florian Fainellif50f2122017-01-30 12:41:40 -0800748 if (err) {
749 kfree(mall_tc_entry);
750 return err;
751 }
752
753 list_add_tail(&mall_tc_entry->list, &p->mall_tc_list);
754 }
755
756 return 0;
757}
758
759static void dsa_slave_del_cls_matchall(struct net_device *dev,
760 struct tc_cls_matchall_offload *cls)
761{
Vivien Didelotd9450972017-10-16 11:12:15 -0400762 struct dsa_port *dp = dsa_slave_to_port(dev);
Florian Fainellif50f2122017-01-30 12:41:40 -0800763 struct dsa_mall_tc_entry *mall_tc_entry;
Vivien Didelotd9450972017-10-16 11:12:15 -0400764 struct dsa_switch *ds = dp->ds;
Florian Fainellif50f2122017-01-30 12:41:40 -0800765
766 if (!ds->ops->port_mirror_del)
767 return;
768
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400769 mall_tc_entry = dsa_slave_mall_tc_entry_find(dev, cls->cookie);
Florian Fainellif50f2122017-01-30 12:41:40 -0800770 if (!mall_tc_entry)
771 return;
772
773 list_del(&mall_tc_entry->list);
774
775 switch (mall_tc_entry->type) {
776 case DSA_PORT_MALL_MIRROR:
Vivien Didelotd9450972017-10-16 11:12:15 -0400777 ds->ops->port_mirror_del(ds, dp->index, &mall_tc_entry->mirror);
Florian Fainellif50f2122017-01-30 12:41:40 -0800778 break;
779 default:
780 WARN_ON(1);
781 }
782
783 kfree(mall_tc_entry);
784}
785
Jiri Pirko3fbae382017-08-07 10:15:26 +0200786static int dsa_slave_setup_tc_cls_matchall(struct net_device *dev,
Jiri Pirko3fbae382017-08-07 10:15:26 +0200787 struct tc_cls_matchall_offload *cls)
Florian Fainellif50f2122017-01-30 12:41:40 -0800788{
Jiri Pirkoa2e8da92017-08-09 14:30:33 +0200789 bool ingress;
790
791 if (is_classid_clsact_ingress(cls->common.classid))
792 ingress = true;
793 else if (is_classid_clsact_egress(cls->common.classid))
794 ingress = false;
795 else
796 return -EOPNOTSUPP;
Jiri Pirkoa5fcf8a2017-06-06 17:00:16 +0200797
Jiri Pirko5fd9fc42017-08-07 10:15:29 +0200798 if (cls->common.chain_index)
Jiri Pirkoa5fcf8a2017-06-06 17:00:16 +0200799 return -EOPNOTSUPP;
Florian Fainellif50f2122017-01-30 12:41:40 -0800800
Jiri Pirko3fbae382017-08-07 10:15:26 +0200801 switch (cls->command) {
802 case TC_CLSMATCHALL_REPLACE:
Jiri Pirko5fd9fc42017-08-07 10:15:29 +0200803 return dsa_slave_add_cls_matchall(dev, cls, ingress);
Jiri Pirko3fbae382017-08-07 10:15:26 +0200804 case TC_CLSMATCHALL_DESTROY:
805 dsa_slave_del_cls_matchall(dev, cls);
806 return 0;
807 default:
808 return -EOPNOTSUPP;
809 }
810}
811
812static int dsa_slave_setup_tc(struct net_device *dev, enum tc_setup_type type,
Jiri Pirkode4784c2017-08-07 10:15:32 +0200813 void *type_data)
Jiri Pirko3fbae382017-08-07 10:15:26 +0200814{
Jiri Pirko2572ac52017-08-07 10:15:17 +0200815 switch (type) {
Jiri Pirkoade9b652017-08-07 10:15:18 +0200816 case TC_SETUP_CLSMATCHALL:
Jiri Pirkode4784c2017-08-07 10:15:32 +0200817 return dsa_slave_setup_tc_cls_matchall(dev, type_data);
Florian Fainellif50f2122017-01-30 12:41:40 -0800818 default:
Jiri Pirkoa5fcf8a2017-06-06 17:00:16 +0200819 return -EOPNOTSUPP;
Florian Fainellif50f2122017-01-30 12:41:40 -0800820 }
Florian Fainellif50f2122017-01-30 12:41:40 -0800821}
822
Florian Fainellif613ed62017-08-01 15:00:36 -0700823static void dsa_slave_get_stats64(struct net_device *dev,
824 struct rtnl_link_stats64 *stats)
825{
826 struct dsa_slave_priv *p = netdev_priv(dev);
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700827 struct pcpu_sw_netstats *s;
Florian Fainellif613ed62017-08-01 15:00:36 -0700828 unsigned int start;
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700829 int i;
Florian Fainellif613ed62017-08-01 15:00:36 -0700830
831 netdev_stats_to_stats64(stats, &dev->stats);
Florian Fainelli5f6b4e142017-08-03 21:33:27 -0700832 for_each_possible_cpu(i) {
833 u64 tx_packets, tx_bytes, rx_packets, rx_bytes;
834
835 s = per_cpu_ptr(p->stats64, i);
836 do {
837 start = u64_stats_fetch_begin_irq(&s->syncp);
838 tx_packets = s->tx_packets;
839 tx_bytes = s->tx_bytes;
840 rx_packets = s->rx_packets;
841 rx_bytes = s->rx_bytes;
842 } while (u64_stats_fetch_retry_irq(&s->syncp, start));
843
844 stats->tx_packets += tx_packets;
845 stats->tx_bytes += tx_bytes;
846 stats->rx_packets += rx_packets;
847 stats->rx_bytes += rx_bytes;
848 }
Florian Fainellif613ed62017-08-01 15:00:36 -0700849}
850
Florian Fainellibf9f2642017-01-30 09:48:40 -0800851static int dsa_slave_get_rxnfc(struct net_device *dev,
852 struct ethtool_rxnfc *nfc, u32 *rule_locs)
853{
Vivien Didelotd9450972017-10-16 11:12:15 -0400854 struct dsa_port *dp = dsa_slave_to_port(dev);
855 struct dsa_switch *ds = dp->ds;
Florian Fainellibf9f2642017-01-30 09:48:40 -0800856
857 if (!ds->ops->get_rxnfc)
858 return -EOPNOTSUPP;
859
Vivien Didelotd9450972017-10-16 11:12:15 -0400860 return ds->ops->get_rxnfc(ds, dp->index, nfc, rule_locs);
Florian Fainellibf9f2642017-01-30 09:48:40 -0800861}
862
863static int dsa_slave_set_rxnfc(struct net_device *dev,
864 struct ethtool_rxnfc *nfc)
865{
Vivien Didelotd9450972017-10-16 11:12:15 -0400866 struct dsa_port *dp = dsa_slave_to_port(dev);
867 struct dsa_switch *ds = dp->ds;
Florian Fainellibf9f2642017-01-30 09:48:40 -0800868
869 if (!ds->ops->set_rxnfc)
870 return -EOPNOTSUPP;
871
Vivien Didelotd9450972017-10-16 11:12:15 -0400872 return ds->ops->set_rxnfc(ds, dp->index, nfc);
Florian Fainellibf9f2642017-01-30 09:48:40 -0800873}
874
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000875static const struct ethtool_ops dsa_slave_ethtool_ops = {
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000876 .get_drvinfo = dsa_slave_get_drvinfo,
Guenter Roeck3d762a02014-10-29 10:45:04 -0700877 .get_regs_len = dsa_slave_get_regs_len,
878 .get_regs = dsa_slave_get_regs,
Vivien Didelot69b2c1622017-09-26 17:15:35 -0400879 .nway_reset = phy_ethtool_nway_reset,
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000880 .get_link = dsa_slave_get_link,
Guenter Roeck6793abb2014-10-29 10:45:01 -0700881 .get_eeprom_len = dsa_slave_get_eeprom_len,
882 .get_eeprom = dsa_slave_get_eeprom,
883 .set_eeprom = dsa_slave_set_eeprom,
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000884 .get_strings = dsa_slave_get_strings,
885 .get_ethtool_stats = dsa_slave_get_ethtool_stats,
886 .get_sset_count = dsa_slave_get_sset_count,
Florian Fainelli19e57c42014-09-18 17:31:24 -0700887 .set_wol = dsa_slave_set_wol,
888 .get_wol = dsa_slave_get_wol,
Florian Fainelli79052882014-09-24 17:05:21 -0700889 .set_eee = dsa_slave_set_eee,
890 .get_eee = dsa_slave_get_eee,
Vivien Didelot771df312017-09-26 17:15:33 -0400891 .get_link_ksettings = phy_ethtool_get_link_ksettings,
Vivien Didelotaa62a8c2017-09-26 17:15:34 -0400892 .set_link_ksettings = phy_ethtool_set_link_ksettings,
Florian Fainellibf9f2642017-01-30 09:48:40 -0800893 .get_rxnfc = dsa_slave_get_rxnfc,
894 .set_rxnfc = dsa_slave_set_rxnfc,
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000895};
896
Florian Fainelli3e8a72d2014-08-27 17:04:46 -0700897static const struct net_device_ops dsa_slave_netdev_ops = {
Stephen Hemmingerd442ad42009-01-06 16:45:26 -0800898 .ndo_open = dsa_slave_open,
899 .ndo_stop = dsa_slave_close,
Florian Fainelli3e8a72d2014-08-27 17:04:46 -0700900 .ndo_start_xmit = dsa_slave_xmit,
Stephen Hemmingerd442ad42009-01-06 16:45:26 -0800901 .ndo_change_rx_flags = dsa_slave_change_rx_flags,
902 .ndo_set_rx_mode = dsa_slave_set_rx_mode,
Stephen Hemmingerd442ad42009-01-06 16:45:26 -0800903 .ndo_set_mac_address = dsa_slave_set_mac_address,
Arkadi Sharshevsky37b8da12017-08-06 16:15:43 +0300904 .ndo_fdb_add = dsa_legacy_fdb_add,
905 .ndo_fdb_del = dsa_legacy_fdb_del,
Arkadi Sharshevsky2bedde12017-08-06 16:15:49 +0300906 .ndo_fdb_dump = dsa_slave_fdb_dump,
Stephen Hemmingerd442ad42009-01-06 16:45:26 -0800907 .ndo_do_ioctl = dsa_slave_ioctl,
Nicolas Dichtelabd2be02015-04-02 17:07:08 +0200908 .ndo_get_iflink = dsa_slave_get_iflink,
Florian Fainelli04ff53f2015-07-31 11:42:57 -0700909#ifdef CONFIG_NET_POLL_CONTROLLER
910 .ndo_netpoll_setup = dsa_slave_netpoll_setup,
911 .ndo_netpoll_cleanup = dsa_slave_netpoll_cleanup,
912 .ndo_poll_controller = dsa_slave_poll_controller,
913#endif
Florian Fainelli44bb7652017-01-10 12:32:36 -0800914 .ndo_get_phys_port_name = dsa_slave_get_phys_port_name,
Florian Fainellif50f2122017-01-30 12:41:40 -0800915 .ndo_setup_tc = dsa_slave_setup_tc,
Florian Fainellif613ed62017-08-01 15:00:36 -0700916 .ndo_get_stats64 = dsa_slave_get_stats64,
Scott Feldman98237d42015-03-15 21:07:15 -0700917};
918
Jiri Pirko9d47c0a2015-05-10 09:47:47 -0700919static const struct switchdev_ops dsa_slave_switchdev_ops = {
Scott Feldmanf8e20a92015-05-10 09:47:49 -0700920 .switchdev_port_attr_get = dsa_slave_port_attr_get,
Scott Feldman35636062015-05-10 09:47:51 -0700921 .switchdev_port_attr_set = dsa_slave_port_attr_set,
Vivien Didelotba14d9e2015-08-10 09:09:53 -0400922 .switchdev_port_obj_add = dsa_slave_port_obj_add,
923 .switchdev_port_obj_del = dsa_slave_port_obj_del,
Stephen Hemmingerd442ad42009-01-06 16:45:26 -0800924};
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000925
Florian Fainellif37db852015-09-23 18:19:58 -0700926static struct device_type dsa_type = {
927 .name = "dsa",
928};
929
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700930static void dsa_slave_adjust_link(struct net_device *dev)
931{
Vivien Didelotd9450972017-10-16 11:12:15 -0400932 struct dsa_port *dp = dsa_slave_to_port(dev);
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700933 struct dsa_slave_priv *p = netdev_priv(dev);
Vivien Didelotd9450972017-10-16 11:12:15 -0400934 struct dsa_switch *ds = dp->ds;
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700935 unsigned int status_changed = 0;
936
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400937 if (p->old_link != dev->phydev->link) {
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700938 status_changed = 1;
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400939 p->old_link = dev->phydev->link;
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700940 }
941
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400942 if (p->old_duplex != dev->phydev->duplex) {
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700943 status_changed = 1;
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400944 p->old_duplex = dev->phydev->duplex;
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700945 }
946
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400947 if (p->old_pause != dev->phydev->pause) {
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700948 status_changed = 1;
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400949 p->old_pause = dev->phydev->pause;
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700950 }
951
Vivien Didelot9d490b42016-08-23 12:38:56 -0400952 if (ds->ops->adjust_link && status_changed)
Vivien Didelotd9450972017-10-16 11:12:15 -0400953 ds->ops->adjust_link(ds, dp->index, dev->phydev);
Florian Fainelliec9436b2014-08-27 17:04:53 -0700954
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700955 if (status_changed)
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400956 phy_print_status(dev->phydev);
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700957}
958
Florian Fainellice31b312014-08-27 17:04:54 -0700959static int dsa_slave_fixed_link_update(struct net_device *dev,
960 struct fixed_phy_status *status)
961{
Andrew Lunnb71be352016-03-12 00:01:37 +0100962 struct dsa_switch *ds;
Vivien Didelotd9450972017-10-16 11:12:15 -0400963 struct dsa_port *dp;
Florian Fainellice31b312014-08-27 17:04:54 -0700964
Andrew Lunnb71be352016-03-12 00:01:37 +0100965 if (dev) {
Vivien Didelotd9450972017-10-16 11:12:15 -0400966 dp = dsa_slave_to_port(dev);
967 ds = dp->ds;
Vivien Didelot9d490b42016-08-23 12:38:56 -0400968 if (ds->ops->fixed_link_update)
Vivien Didelotd9450972017-10-16 11:12:15 -0400969 ds->ops->fixed_link_update(ds, dp->index, status);
Andrew Lunnb71be352016-03-12 00:01:37 +0100970 }
Florian Fainellice31b312014-08-27 17:04:54 -0700971
972 return 0;
973}
974
Lennert Buytenhek91da11f2008-10-07 13:44:02 +0000975/* slave device setup *******************************************************/
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400976static int dsa_slave_phy_connect(struct net_device *slave_dev, int addr)
Florian Fainellic305c162015-03-10 16:57:12 -0700977{
Vivien Didelotd9450972017-10-16 11:12:15 -0400978 struct dsa_port *dp = dsa_slave_to_port(slave_dev);
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400979 struct dsa_slave_priv *p = netdev_priv(slave_dev);
Vivien Didelotd9450972017-10-16 11:12:15 -0400980 struct dsa_switch *ds = dp->ds;
Florian Fainellic305c162015-03-10 16:57:12 -0700981
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400982 slave_dev->phydev = mdiobus_get_phy(ds->slave_mii_bus, addr);
983 if (!slave_dev->phydev) {
Russell Kingd25b8e72015-10-03 18:09:07 +0100984 netdev_err(slave_dev, "no phy at %d\n", addr);
Florian Fainellic305c162015-03-10 16:57:12 -0700985 return -ENODEV;
Russell Kingd25b8e72015-10-03 18:09:07 +0100986 }
Florian Fainellic305c162015-03-10 16:57:12 -0700987
988 /* Use already configured phy mode */
Florian Fainelli211c5042015-08-08 12:58:57 -0700989 if (p->phy_interface == PHY_INTERFACE_MODE_NA)
Vivien Didelot0115dcd2017-09-26 17:15:32 -0400990 p->phy_interface = slave_dev->phydev->interface;
991
992 return phy_connect_direct(slave_dev, slave_dev->phydev,
993 dsa_slave_adjust_link, p->phy_interface);
Florian Fainellic305c162015-03-10 16:57:12 -0700994}
995
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400996static int dsa_slave_phy_setup(struct net_device *slave_dev)
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -0700997{
Vivien Didelotd9450972017-10-16 11:12:15 -0400998 struct dsa_port *dp = dsa_slave_to_port(slave_dev);
Vivien Didelot4fa7b712017-09-20 19:31:57 -0400999 struct dsa_slave_priv *p = netdev_priv(slave_dev);
Vivien Didelotd9450972017-10-16 11:12:15 -04001000 struct device_node *port_dn = dp->dn;
1001 struct dsa_switch *ds = dp->ds;
1002 struct device_node *phy_dn;
Florian Fainellice31b312014-08-27 17:04:54 -07001003 bool phy_is_fixed = false;
Florian Fainelli68195632014-09-19 13:07:54 -07001004 u32 phy_flags = 0;
Guenter Roeck19334922015-02-16 21:23:51 -08001005 int mode, ret;
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001006
Guenter Roeck19334922015-02-16 21:23:51 -08001007 mode = of_get_phy_mode(port_dn);
1008 if (mode < 0)
1009 mode = PHY_INTERFACE_MODE_NA;
1010 p->phy_interface = mode;
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001011
1012 phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
Johan Hovold0d8f3c62016-11-28 19:24:54 +01001013 if (!phy_dn && of_phy_is_fixed_link(port_dn)) {
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001014 /* In the case of a fixed PHY, the DT node associated
1015 * to the fixed PHY is the Port DT node
1016 */
1017 ret = of_phy_register_fixed_link(port_dn);
1018 if (ret) {
Russell Kingd25b8e72015-10-03 18:09:07 +01001019 netdev_err(slave_dev, "failed to register fixed PHY: %d\n", ret);
Florian Fainelli9697f1c2014-12-11 12:49:16 -08001020 return ret;
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001021 }
Florian Fainellice31b312014-08-27 17:04:54 -07001022 phy_is_fixed = true;
Johan Hovold0d8f3c62016-11-28 19:24:54 +01001023 phy_dn = of_node_get(port_dn);
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001024 }
1025
Vivien Didelot9d490b42016-08-23 12:38:56 -04001026 if (ds->ops->get_phy_flags)
Vivien Didelotd9450972017-10-16 11:12:15 -04001027 phy_flags = ds->ops->get_phy_flags(ds, dp->index);
Florian Fainelli68195632014-09-19 13:07:54 -07001028
Florian Fainellicd28a1a2015-03-10 16:57:13 -07001029 if (phy_dn) {
Russell Kingd25b8e72015-10-03 18:09:07 +01001030 int phy_id = of_mdio_parse_addr(&slave_dev->dev, phy_dn);
1031
Florian Fainellicd28a1a2015-03-10 16:57:13 -07001032 /* If this PHY address is part of phys_mii_mask, which means
1033 * that we need to divert reads and writes to/from it, then we
1034 * want to bind this device using the slave MII bus created by
1035 * DSA to make that happen.
1036 */
Russell Kingd25b8e72015-10-03 18:09:07 +01001037 if (!phy_is_fixed && phy_id >= 0 &&
1038 (ds->phys_mii_mask & (1 << phy_id))) {
Vivien Didelot4fa7b712017-09-20 19:31:57 -04001039 ret = dsa_slave_phy_connect(slave_dev, phy_id);
Russell Kingd25b8e72015-10-03 18:09:07 +01001040 if (ret) {
1041 netdev_err(slave_dev, "failed to connect to phy%d: %d\n", phy_id, ret);
Johan Hovold0d8f3c62016-11-28 19:24:54 +01001042 of_node_put(phy_dn);
Florian Fainellicd28a1a2015-03-10 16:57:13 -07001043 return ret;
Russell Kingd25b8e72015-10-03 18:09:07 +01001044 }
Florian Fainellicd28a1a2015-03-10 16:57:13 -07001045 } else {
Vivien Didelot0115dcd2017-09-26 17:15:32 -04001046 slave_dev->phydev = of_phy_connect(slave_dev, phy_dn,
1047 dsa_slave_adjust_link,
1048 phy_flags,
1049 p->phy_interface);
Florian Fainellicd28a1a2015-03-10 16:57:13 -07001050 }
Johan Hovold0d8f3c62016-11-28 19:24:54 +01001051
1052 of_node_put(phy_dn);
Florian Fainellicd28a1a2015-03-10 16:57:13 -07001053 }
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001054
Vivien Didelot0115dcd2017-09-26 17:15:32 -04001055 if (slave_dev->phydev && phy_is_fixed)
1056 fixed_phy_set_link_update(slave_dev->phydev,
1057 dsa_slave_fixed_link_update);
Florian Fainellice31b312014-08-27 17:04:54 -07001058
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001059 /* We could not connect to a designated PHY, so use the switch internal
1060 * MDIO bus instead
1061 */
Vivien Didelot0115dcd2017-09-26 17:15:32 -04001062 if (!slave_dev->phydev) {
Vivien Didelotd9450972017-10-16 11:12:15 -04001063 ret = dsa_slave_phy_connect(slave_dev, dp->index);
Russell Kingd25b8e72015-10-03 18:09:07 +01001064 if (ret) {
Vivien Didelotafdcf152017-01-27 15:29:39 -05001065 netdev_err(slave_dev, "failed to connect to port %d: %d\n",
Vivien Didelotd9450972017-10-16 11:12:15 -04001066 dp->index, ret);
Johan Hovold881eada2016-11-28 19:25:09 +01001067 if (phy_is_fixed)
1068 of_phy_deregister_fixed_link(port_dn);
Florian Fainellic305c162015-03-10 16:57:12 -07001069 return ret;
Russell Kingd25b8e72015-10-03 18:09:07 +01001070 }
Andrew Lunnb31f65f2014-11-05 19:47:28 +01001071 }
Florian Fainelli9697f1c2014-12-11 12:49:16 -08001072
Vivien Didelot0115dcd2017-09-26 17:15:32 -04001073 phy_attached_info(slave_dev->phydev);
Andrew Lunn22209432016-01-06 20:11:13 +01001074
Florian Fainelli9697f1c2014-12-11 12:49:16 -08001075 return 0;
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001076}
1077
Andrew Lunn448b4482015-05-06 01:09:56 +02001078static struct lock_class_key dsa_slave_netdev_xmit_lock_key;
1079static void dsa_slave_set_lockdep_class_one(struct net_device *dev,
1080 struct netdev_queue *txq,
1081 void *_unused)
1082{
1083 lockdep_set_class(&txq->_xmit_lock,
1084 &dsa_slave_netdev_xmit_lock_key);
1085}
1086
Florian Fainelli24462542014-09-18 17:31:22 -07001087int dsa_slave_suspend(struct net_device *slave_dev)
1088{
1089 struct dsa_slave_priv *p = netdev_priv(slave_dev);
1090
Florian Fainellif154be22017-01-25 09:10:41 -08001091 netif_device_detach(slave_dev);
1092
Vivien Didelot0115dcd2017-09-26 17:15:32 -04001093 if (slave_dev->phydev) {
1094 phy_stop(slave_dev->phydev);
Florian Fainelli24462542014-09-18 17:31:22 -07001095 p->old_pause = -1;
1096 p->old_link = -1;
1097 p->old_duplex = -1;
Vivien Didelot0115dcd2017-09-26 17:15:32 -04001098 phy_suspend(slave_dev->phydev);
Florian Fainelli24462542014-09-18 17:31:22 -07001099 }
1100
1101 return 0;
1102}
1103
1104int dsa_slave_resume(struct net_device *slave_dev)
1105{
Florian Fainelli24462542014-09-18 17:31:22 -07001106 netif_device_attach(slave_dev);
1107
Vivien Didelot0115dcd2017-09-26 17:15:32 -04001108 if (slave_dev->phydev) {
1109 phy_resume(slave_dev->phydev);
1110 phy_start(slave_dev->phydev);
Florian Fainelli24462542014-09-18 17:31:22 -07001111 }
1112
1113 return 0;
1114}
1115
Vivien Didelot6158eaa2017-10-16 11:12:14 -04001116static void dsa_slave_notify(struct net_device *dev, unsigned long val)
1117{
1118 struct dsa_slave_priv *p = netdev_priv(dev);
1119 struct net_device *master = dsa_master_netdev(p);
Vivien Didelotd9450972017-10-16 11:12:15 -04001120 struct dsa_port *dp = dsa_slave_to_port(dev);
Vivien Didelot6158eaa2017-10-16 11:12:14 -04001121 struct dsa_notifier_register_info rinfo = {
1122 .switch_number = dp->ds->index,
1123 .port_number = dp->index,
1124 .master = master,
1125 .info.dev = dev,
1126 };
1127
1128 call_dsa_notifiers(val, dev, &rinfo.info);
1129}
1130
Vivien Didelot4cfbf092017-08-05 16:20:19 -04001131int dsa_slave_create(struct dsa_port *port, const char *name)
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001132{
Vivien Didelota5b930e2017-10-16 11:12:13 -04001133 struct dsa_port *cpu_dp = port->cpu_dp;
1134 struct net_device *master = cpu_dp->netdev;
Vivien Didelot4cfbf092017-08-05 16:20:19 -04001135 struct dsa_switch *ds = port->ds;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001136 struct net_device *slave_dev;
1137 struct dsa_slave_priv *p;
1138 int ret;
1139
Florian Fainelli55199df2017-09-03 20:27:00 -07001140 if (!ds->num_tx_queues)
1141 ds->num_tx_queues = 1;
1142
1143 slave_dev = alloc_netdev_mqs(sizeof(struct dsa_slave_priv), name,
1144 NET_NAME_UNKNOWN, ether_setup,
1145 ds->num_tx_queues, 1);
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001146 if (slave_dev == NULL)
Guenter Roeckd87d6f42015-02-24 13:15:32 -08001147 return -ENOMEM;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001148
Florian Fainellif50f2122017-01-30 12:41:40 -08001149 slave_dev->features = master->vlan_features | NETIF_F_HW_TC;
1150 slave_dev->hw_features |= NETIF_F_HW_TC;
Wilfried Klaebe7ad24ea2014-05-11 00:12:32 +00001151 slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
Bjørn Mork2fcc8002013-08-30 18:08:46 +02001152 eth_hw_addr_inherit(slave_dev, master);
Phil Sutter0a5f1072015-08-18 10:30:41 +02001153 slave_dev->priv_flags |= IFF_NO_QUEUE;
Florian Fainelli3e8a72d2014-08-27 17:04:46 -07001154 slave_dev->netdev_ops = &dsa_slave_netdev_ops;
Jiri Pirko9d47c0a2015-05-10 09:47:47 -07001155 slave_dev->switchdev_ops = &dsa_slave_switchdev_ops;
Jarod Wilson8b1efc02016-10-20 23:25:27 -04001156 slave_dev->min_mtu = 0;
1157 slave_dev->max_mtu = ETH_MAX_MTU;
Florian Fainellif37db852015-09-23 18:19:58 -07001158 SET_NETDEV_DEVTYPE(slave_dev, &dsa_type);
Stephen Hemmingerd442ad42009-01-06 16:45:26 -08001159
Andrew Lunn448b4482015-05-06 01:09:56 +02001160 netdev_for_each_tx_queue(slave_dev, dsa_slave_set_lockdep_class_one,
1161 NULL);
1162
Vivien Didelot4cfbf092017-08-05 16:20:19 -04001163 SET_NETDEV_DEV(slave_dev, port->ds->dev);
1164 slave_dev->dev.of_node = port->dn;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001165 slave_dev->vlan_features = master->vlan_features;
1166
1167 p = netdev_priv(slave_dev);
Florian Fainelli5f6b4e142017-08-03 21:33:27 -07001168 p->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
1169 if (!p->stats64) {
1170 free_netdev(slave_dev);
1171 return -ENOMEM;
1172 }
Vivien Didelot4cfbf092017-08-05 16:20:19 -04001173 p->dp = port;
Florian Fainellif50f2122017-01-30 12:41:40 -08001174 INIT_LIST_HEAD(&p->mall_tc_list);
Vivien Didelot15240242017-09-29 17:19:18 -04001175 p->xmit = cpu_dp->tag_ops->xmit;
Alexander Duyck50753142014-09-15 13:00:19 -04001176
Florian Fainelli0d8bcdd2014-08-27 17:04:51 -07001177 p->old_pause = -1;
1178 p->old_link = -1;
1179 p->old_duplex = -1;
1180
Vivien Didelot4cfbf092017-08-05 16:20:19 -04001181 port->netdev = slave_dev;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001182
1183 netif_carrier_off(slave_dev);
1184
Vivien Didelot4fa7b712017-09-20 19:31:57 -04001185 ret = dsa_slave_phy_setup(slave_dev);
Andrew Lunn0071f562016-01-06 20:11:20 +01001186 if (ret) {
1187 netdev_err(master, "error %d setting up slave phy\n", ret);
Florian Fainellie8044412017-09-25 15:55:53 -07001188 goto out_free;
1189 }
1190
Vivien Didelot6158eaa2017-10-16 11:12:14 -04001191 dsa_slave_notify(slave_dev, DSA_PORT_REGISTER);
Florian Fainelli60724d42017-10-11 10:57:48 -07001192
Florian Fainellie8044412017-09-25 15:55:53 -07001193 ret = register_netdev(slave_dev);
1194 if (ret) {
1195 netdev_err(master, "error %d registering interface %s\n",
1196 ret, slave_dev->name);
1197 goto out_phy;
Andrew Lunn0071f562016-01-06 20:11:20 +01001198 }
1199
Guenter Roeckd87d6f42015-02-24 13:15:32 -08001200 return 0;
Florian Fainellie8044412017-09-25 15:55:53 -07001201
1202out_phy:
David S. Miller53954cf2017-10-05 17:57:03 -07001203 phy_disconnect(slave_dev->phydev);
Vivien Didelotd9450972017-10-16 11:12:15 -04001204 if (of_phy_is_fixed_link(port->dn))
1205 of_phy_deregister_fixed_link(port->dn);
Florian Fainellie8044412017-09-25 15:55:53 -07001206out_free:
1207 free_percpu(p->stats64);
1208 free_netdev(slave_dev);
1209 port->netdev = NULL;
1210 return ret;
Lennert Buytenhek91da11f2008-10-07 13:44:02 +00001211}
Florian Fainellib73adef2015-02-24 13:15:33 -08001212
Neil Armstrongcda5c152015-12-07 13:57:35 +01001213void dsa_slave_destroy(struct net_device *slave_dev)
1214{
Vivien Didelotd9450972017-10-16 11:12:15 -04001215 struct dsa_port *dp = dsa_slave_to_port(slave_dev);
Neil Armstrongcda5c152015-12-07 13:57:35 +01001216 struct dsa_slave_priv *p = netdev_priv(slave_dev);
Vivien Didelotd9450972017-10-16 11:12:15 -04001217 struct device_node *port_dn = dp->dn;
Neil Armstrongcda5c152015-12-07 13:57:35 +01001218
1219 netif_carrier_off(slave_dev);
Vivien Didelot0115dcd2017-09-26 17:15:32 -04001220 if (slave_dev->phydev) {
1221 phy_disconnect(slave_dev->phydev);
Johan Hovold881eada2016-11-28 19:25:09 +01001222
1223 if (of_phy_is_fixed_link(port_dn))
1224 of_phy_deregister_fixed_link(port_dn);
1225 }
Vivien Didelot6158eaa2017-10-16 11:12:14 -04001226 dsa_slave_notify(slave_dev, DSA_PORT_UNREGISTER);
Neil Armstrongcda5c152015-12-07 13:57:35 +01001227 unregister_netdev(slave_dev);
Florian Fainelli5f6b4e142017-08-03 21:33:27 -07001228 free_percpu(p->stats64);
Neil Armstrongcda5c152015-12-07 13:57:35 +01001229 free_netdev(slave_dev);
1230}
1231
Florian Fainellib73adef2015-02-24 13:15:33 -08001232static bool dsa_slave_dev_check(struct net_device *dev)
1233{
1234 return dev->netdev_ops == &dsa_slave_netdev_ops;
1235}
1236
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001237static int dsa_slave_changeupper(struct net_device *dev,
1238 struct netdev_notifier_changeupper_info *info)
Florian Fainellib73adef2015-02-24 13:15:33 -08001239{
Vivien Didelotd9450972017-10-16 11:12:15 -04001240 struct dsa_port *dp = dsa_slave_to_port(dev);
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001241 int err = NOTIFY_DONE;
Florian Fainellib73adef2015-02-24 13:15:33 -08001242
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001243 if (netif_is_bridge_master(info->upper_dev)) {
1244 if (info->linking) {
Vivien Didelot17d78022017-05-19 17:00:38 -04001245 err = dsa_port_bridge_join(dp, info->upper_dev);
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001246 err = notifier_from_errno(err);
1247 } else {
Vivien Didelot17d78022017-05-19 17:00:38 -04001248 dsa_port_bridge_leave(dp, info->upper_dev);
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001249 err = NOTIFY_OK;
Vivien Didelot6debb682016-03-13 16:21:34 -04001250 }
Vivien Didelot6debb682016-03-13 16:21:34 -04001251 }
1252
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001253 return err;
Florian Fainellib73adef2015-02-24 13:15:33 -08001254}
1255
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001256static int dsa_slave_netdevice_event(struct notifier_block *nb,
1257 unsigned long event, void *ptr)
Florian Fainellib73adef2015-02-24 13:15:33 -08001258{
Vivien Didelot6debb682016-03-13 16:21:34 -04001259 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Florian Fainellib73adef2015-02-24 13:15:33 -08001260
Florian Fainelli53bade82017-09-19 18:00:37 -07001261 if (!dsa_slave_dev_check(dev))
Vivien Didelot8e92ab32017-02-03 13:20:17 -05001262 return NOTIFY_DONE;
1263
1264 if (event == NETDEV_CHANGEUPPER)
1265 return dsa_slave_changeupper(dev, ptr);
Florian Fainellib73adef2015-02-24 13:15:33 -08001266
Florian Fainellib73adef2015-02-24 13:15:33 -08001267 return NOTIFY_DONE;
1268}
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001269
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001270struct dsa_switchdev_event_work {
1271 struct work_struct work;
1272 struct switchdev_notifier_fdb_info fdb_info;
1273 struct net_device *dev;
1274 unsigned long event;
1275};
1276
1277static void dsa_slave_switchdev_event_work(struct work_struct *work)
1278{
1279 struct dsa_switchdev_event_work *switchdev_work =
1280 container_of(work, struct dsa_switchdev_event_work, work);
1281 struct net_device *dev = switchdev_work->dev;
1282 struct switchdev_notifier_fdb_info *fdb_info;
Vivien Didelotd9450972017-10-16 11:12:15 -04001283 struct dsa_port *dp = dsa_slave_to_port(dev);
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001284 int err;
1285
1286 rtnl_lock();
1287 switch (switchdev_work->event) {
1288 case SWITCHDEV_FDB_ADD_TO_DEVICE:
1289 fdb_info = &switchdev_work->fdb_info;
Vivien Didelotd9450972017-10-16 11:12:15 -04001290 err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid);
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001291 if (err) {
1292 netdev_dbg(dev, "fdb add failed err=%d\n", err);
1293 break;
1294 }
1295 call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev,
1296 &fdb_info->info);
1297 break;
1298
1299 case SWITCHDEV_FDB_DEL_TO_DEVICE:
1300 fdb_info = &switchdev_work->fdb_info;
Vivien Didelotd9450972017-10-16 11:12:15 -04001301 err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid);
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001302 if (err) {
1303 netdev_dbg(dev, "fdb del failed err=%d\n", err);
1304 dev_close(dev);
1305 }
1306 break;
1307 }
1308 rtnl_unlock();
1309
1310 kfree(switchdev_work->fdb_info.addr);
1311 kfree(switchdev_work);
1312 dev_put(dev);
1313}
1314
1315static int
1316dsa_slave_switchdev_fdb_work_init(struct dsa_switchdev_event_work *
1317 switchdev_work,
1318 const struct switchdev_notifier_fdb_info *
1319 fdb_info)
1320{
1321 memcpy(&switchdev_work->fdb_info, fdb_info,
1322 sizeof(switchdev_work->fdb_info));
1323 switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
1324 if (!switchdev_work->fdb_info.addr)
1325 return -ENOMEM;
1326 ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
1327 fdb_info->addr);
1328 return 0;
1329}
1330
1331/* Called under rcu_read_lock() */
1332static int dsa_slave_switchdev_event(struct notifier_block *unused,
1333 unsigned long event, void *ptr)
1334{
1335 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
1336 struct dsa_switchdev_event_work *switchdev_work;
1337
1338 if (!dsa_slave_dev_check(dev))
1339 return NOTIFY_DONE;
1340
1341 switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
1342 if (!switchdev_work)
1343 return NOTIFY_BAD;
1344
1345 INIT_WORK(&switchdev_work->work,
1346 dsa_slave_switchdev_event_work);
1347 switchdev_work->dev = dev;
1348 switchdev_work->event = event;
1349
1350 switch (event) {
1351 case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */
1352 case SWITCHDEV_FDB_DEL_TO_DEVICE:
1353 if (dsa_slave_switchdev_fdb_work_init(switchdev_work,
1354 ptr))
1355 goto err_fdb_work_init;
1356 dev_hold(dev);
1357 break;
1358 default:
1359 kfree(switchdev_work);
1360 return NOTIFY_DONE;
1361 }
1362
1363 dsa_schedule_work(&switchdev_work->work);
1364 return NOTIFY_OK;
1365
1366err_fdb_work_init:
1367 kfree(switchdev_work);
1368 return NOTIFY_BAD;
1369}
1370
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001371static struct notifier_block dsa_slave_nb __read_mostly = {
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001372 .notifier_call = dsa_slave_netdevice_event,
1373};
1374
1375static struct notifier_block dsa_slave_switchdev_notifier = {
1376 .notifier_call = dsa_slave_switchdev_event,
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001377};
1378
1379int dsa_slave_register_notifier(void)
1380{
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001381 int err;
1382
1383 err = register_netdevice_notifier(&dsa_slave_nb);
1384 if (err)
1385 return err;
1386
1387 err = register_switchdev_notifier(&dsa_slave_switchdev_notifier);
1388 if (err)
1389 goto err_switchdev_nb;
1390
1391 return 0;
1392
1393err_switchdev_nb:
1394 unregister_netdevice_notifier(&dsa_slave_nb);
1395 return err;
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001396}
1397
1398void dsa_slave_unregister_notifier(void)
1399{
1400 int err;
1401
Arkadi Sharshevskyc9eb3e02017-08-06 16:15:42 +03001402 err = unregister_switchdev_notifier(&dsa_slave_switchdev_notifier);
1403 if (err)
1404 pr_err("DSA: failed to unregister switchdev notifier (%d)\n", err);
1405
Vivien Didelot88e4f0c2017-02-03 13:20:16 -05001406 err = unregister_netdevice_notifier(&dsa_slave_nb);
1407 if (err)
1408 pr_err("DSA: failed to unregister slave notifier (%d)\n", err);
1409}