Blame view
net/dsa/slave.c
43.1 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
91da11f87 net: Distributed ... |
2 3 |
/* * net/dsa/slave.c - Slave device handling |
e84665c9c dsa: add switch c... |
4 |
* Copyright (c) 2008-2009 Marvell Semiconductor |
91da11f87 net: Distributed ... |
5 6 7 |
*/ #include <linux/list.h> |
df02c6ff2 dsa: fix master i... |
8 |
#include <linux/etherdevice.h> |
b73adef67 net: dsa: integra... |
9 |
#include <linux/netdevice.h> |
91da11f87 net: Distributed ... |
10 |
#include <linux/phy.h> |
a28205437 net: dsa: add inc... |
11 |
#include <linux/phy_fixed.h> |
aab9c4067 net: dsa: Plug in... |
12 |
#include <linux/phylink.h> |
0d8bcdd38 net: dsa: allow f... |
13 14 |
#include <linux/of_net.h> #include <linux/of_mdio.h> |
7f854420f phy: Add API for ... |
15 |
#include <linux/mdio.h> |
b73adef67 net: dsa: integra... |
16 |
#include <net/rtnetlink.h> |
f50f21274 net: dsa: Add plu... |
17 18 |
#include <net/pkt_cls.h> #include <net/tc_act/tc_mirred.h> |
b73adef67 net: dsa: integra... |
19 |
#include <linux/if_bridge.h> |
04ff53f96 net: dsa: Add net... |
20 |
#include <linux/netpoll.h> |
90af1059c net: dsa: forward... |
21 |
#include <linux/ptp_classify.h> |
ea5dd34be net: dsa: include... |
22 |
|
91da11f87 net: Distributed ... |
23 |
#include "dsa_priv.h" |
f3b78049d net: dsa: make ds... |
24 |
static bool dsa_slave_dev_check(const struct net_device *dev); |
f50f21274 net: dsa: Add plu... |
25 |
|
91da11f87 net: Distributed ... |
26 27 28 29 |
/* slave mii_bus handling ***************************************************/ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) { struct dsa_switch *ds = bus->priv; |
0d8bcdd38 net: dsa: allow f... |
30 |
if (ds->phys_mii_mask & (1 << addr)) |
9d490b4ee net: dsa: rename ... |
31 |
return ds->ops->phy_read(ds, addr, reg); |
91da11f87 net: Distributed ... |
32 33 34 35 36 37 38 |
return 0xffff; } static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val) { struct dsa_switch *ds = bus->priv; |
0d8bcdd38 net: dsa: allow f... |
39 |
if (ds->phys_mii_mask & (1 << addr)) |
9d490b4ee net: dsa: rename ... |
40 |
return ds->ops->phy_write(ds, addr, reg, val); |
91da11f87 net: Distributed ... |
41 42 43 44 45 46 47 48 49 50 |
return 0; } void dsa_slave_mii_bus_init(struct dsa_switch *ds) { ds->slave_mii_bus->priv = (void *)ds; ds->slave_mii_bus->name = "dsa slave smi"; ds->slave_mii_bus->read = dsa_slave_phy_read; ds->slave_mii_bus->write = dsa_slave_phy_write; |
0b7b498d4 net: dsa: Provide... |
51 |
snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d", |
49463b7f2 net: dsa: make tr... |
52 |
ds->dst->index, ds->index); |
c33063d6a dsa: Remove maste... |
53 |
ds->slave_mii_bus->parent = ds->dev; |
24df8986f net: dsa: set sla... |
54 |
ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; |
91da11f87 net: Distributed ... |
55 56 57 58 |
} /* slave device handling ****************************************************/ |
abd2be00d dsa: implement nd... |
59 |
static int dsa_slave_get_iflink(const struct net_device *dev) |
c08408015 dsa: set ->iflink... |
60 |
{ |
d0006b002 net: dsa: add sla... |
61 |
return dsa_slave_to_master(dev)->ifindex; |
c08408015 dsa: set ->iflink... |
62 |
} |
91da11f87 net: Distributed ... |
63 64 |
static int dsa_slave_open(struct net_device *dev) { |
d0006b002 net: dsa: add sla... |
65 |
struct net_device *master = dsa_slave_to_master(dev); |
d945097bb net: dsa: add sla... |
66 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
df02c6ff2 dsa: fix master i... |
67 68 69 70 |
int err; if (!(master->flags & IFF_UP)) return -ENETDOWN; |
8feedbb4a dsa: Convert comp... |
71 |
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) { |
a748ee242 net: move address... |
72 |
err = dev_uc_add(master, dev->dev_addr); |
df02c6ff2 dsa: fix master i... |
73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
if (err < 0) goto out; } if (dev->flags & IFF_ALLMULTI) { err = dev_set_allmulti(master, 1); if (err < 0) goto del_unicast; } if (dev->flags & IFF_PROMISC) { err = dev_set_promiscuity(master, 1); if (err < 0) goto clear_allmulti; } |
0115dcd17 net: dsa: use sla... |
87 |
err = dsa_port_enable(dp, dev->phydev); |
fb8a6a2b8 net: dsa: add por... |
88 89 |
if (err) goto clear_promisc; |
b73adef67 net: dsa: integra... |
90 |
|
aab9c4067 net: dsa: Plug in... |
91 |
phylink_start(dp->pl); |
f7f1de51e net: dsa: start a... |
92 |
|
91da11f87 net: Distributed ... |
93 |
return 0; |
df02c6ff2 dsa: fix master i... |
94 |
|
b2f2af21e net: dsa: allow e... |
95 96 |
clear_promisc: if (dev->flags & IFF_PROMISC) |
4fdeddfe0 dsa: fix promiscu... |
97 |
dev_set_promiscuity(master, -1); |
df02c6ff2 dsa: fix master i... |
98 99 100 101 |
clear_allmulti: if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(master, -1); del_unicast: |
8feedbb4a dsa: Convert comp... |
102 |
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) |
a748ee242 net: move address... |
103 |
dev_uc_del(master, dev->dev_addr); |
df02c6ff2 dsa: fix master i... |
104 105 |
out: return err; |
91da11f87 net: Distributed ... |
106 107 108 109 |
} static int dsa_slave_close(struct net_device *dev) { |
d0006b002 net: dsa: add sla... |
110 |
struct net_device *master = dsa_slave_to_master(dev); |
d945097bb net: dsa: add sla... |
111 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
df02c6ff2 dsa: fix master i... |
112 |
|
97a69a0de net: dsa: Add sup... |
113 114 |
cancel_work_sync(&dp->xmit_work); skb_queue_purge(&dp->xmit_queue); |
aab9c4067 net: dsa: Plug in... |
115 |
phylink_stop(dp->pl); |
f7f1de51e net: dsa: start a... |
116 |
|
75104db0c dsa: Remove phyde... |
117 |
dsa_port_disable(dp); |
6457edfe7 net: dsa: make sl... |
118 |
|
df02c6ff2 dsa: fix master i... |
119 |
dev_mc_unsync(master, dev); |
a748ee242 net: move address... |
120 |
dev_uc_unsync(master, dev); |
df02c6ff2 dsa: fix master i... |
121 122 123 124 |
if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(master, -1); if (dev->flags & IFF_PROMISC) dev_set_promiscuity(master, -1); |
8feedbb4a dsa: Convert comp... |
125 |
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) |
a748ee242 net: move address... |
126 |
dev_uc_del(master, dev->dev_addr); |
df02c6ff2 dsa: fix master i... |
127 |
|
91da11f87 net: Distributed ... |
128 129 130 131 132 |
return 0; } static void dsa_slave_change_rx_flags(struct net_device *dev, int change) { |
d0006b002 net: dsa: add sla... |
133 |
struct net_device *master = dsa_slave_to_master(dev); |
17ab4f61b net: dsa: slave: ... |
134 135 136 137 138 139 140 141 |
if (dev->flags & IFF_UP) { if (change & IFF_ALLMULTI) dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1); if (change & IFF_PROMISC) dev_set_promiscuity(master, dev->flags & IFF_PROMISC ? 1 : -1); } |
91da11f87 net: Distributed ... |
142 143 144 145 |
} static void dsa_slave_set_rx_mode(struct net_device *dev) { |
d0006b002 net: dsa: add sla... |
146 |
struct net_device *master = dsa_slave_to_master(dev); |
91da11f87 net: Distributed ... |
147 148 |
dev_mc_sync(master, dev); |
a748ee242 net: move address... |
149 |
dev_uc_sync(master, dev); |
91da11f87 net: Distributed ... |
150 |
} |
df02c6ff2 dsa: fix master i... |
151 |
static int dsa_slave_set_mac_address(struct net_device *dev, void *a) |
91da11f87 net: Distributed ... |
152 |
{ |
d0006b002 net: dsa: add sla... |
153 |
struct net_device *master = dsa_slave_to_master(dev); |
df02c6ff2 dsa: fix master i... |
154 155 156 157 158 159 160 161 |
struct sockaddr *addr = a; int err; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; if (!(dev->flags & IFF_UP)) goto out; |
8feedbb4a dsa: Convert comp... |
162 |
if (!ether_addr_equal(addr->sa_data, master->dev_addr)) { |
a748ee242 net: move address... |
163 |
err = dev_uc_add(master, addr->sa_data); |
df02c6ff2 dsa: fix master i... |
164 165 166 |
if (err < 0) return err; } |
8feedbb4a dsa: Convert comp... |
167 |
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) |
a748ee242 net: move address... |
168 |
dev_uc_del(master, dev->dev_addr); |
df02c6ff2 dsa: fix master i... |
169 170 |
out: |
d08f161a1 dsa: Use ether_ad... |
171 |
ether_addr_copy(dev->dev_addr, addr->sa_data); |
91da11f87 net: Distributed ... |
172 173 174 |
return 0; } |
2bedde1ab net: dsa: Move FD... |
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
struct dsa_slave_dump_ctx { struct net_device *dev; struct sk_buff *skb; struct netlink_callback *cb; int idx; }; static int dsa_slave_port_fdb_do_dump(const unsigned char *addr, u16 vid, bool is_static, void *data) { struct dsa_slave_dump_ctx *dump = data; u32 portid = NETLINK_CB(dump->cb->skb).portid; u32 seq = dump->cb->nlh->nlmsg_seq; struct nlmsghdr *nlh; struct ndmsg *ndm; if (dump->idx < dump->cb->args[2]) goto skip; nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, sizeof(*ndm), NLM_F_MULTI); if (!nlh) return -EMSGSIZE; ndm = nlmsg_data(nlh); ndm->ndm_family = AF_BRIDGE; ndm->ndm_pad1 = 0; ndm->ndm_pad2 = 0; ndm->ndm_flags = NTF_SELF; ndm->ndm_type = 0; ndm->ndm_ifindex = dump->dev->ifindex; ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr)) goto nla_put_failure; if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid)) goto nla_put_failure; nlmsg_end(dump->skb, nlh); skip: dump->idx++; return 0; nla_put_failure: nlmsg_cancel(dump->skb, nlh); return -EMSGSIZE; } static int dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *dev, struct net_device *filter_dev, int *idx) { |
d945097bb net: dsa: add sla... |
231 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
2bedde1ab net: dsa: Move FD... |
232 233 234 235 236 237 |
struct dsa_slave_dump_ctx dump = { .dev = dev, .skb = skb, .cb = cb, .idx = *idx, }; |
2bedde1ab net: dsa: Move FD... |
238 |
int err; |
de40fc5d2 net: dsa: add por... |
239 |
err = dsa_port_fdb_dump(dp, dsa_slave_port_fdb_do_dump, &dump); |
2bedde1ab net: dsa: Move FD... |
240 |
*idx = dump.idx; |
de40fc5d2 net: dsa: add por... |
241 |
|
2bedde1ab net: dsa: Move FD... |
242 243 |
return err; } |
91da11f87 net: Distributed ... |
244 245 |
static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { |
0336369d3 net: dsa: forward... |
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->dp->ds; int port = p->dp->index; /* Pass through to switch driver if it supports timestamping */ switch (cmd) { case SIOCGHWTSTAMP: if (ds->ops->port_hwtstamp_get) return ds->ops->port_hwtstamp_get(ds, port, ifr); break; case SIOCSHWTSTAMP: if (ds->ops->port_hwtstamp_set) return ds->ops->port_hwtstamp_set(ds, port, ifr); break; } |
aab9c4067 net: dsa: Plug in... |
261 |
return phylink_mii_ioctl(p->dp->pl, ifr, cmd); |
91da11f87 net: Distributed ... |
262 |
} |
356360625 switchdev: conver... |
263 |
static int dsa_slave_port_attr_set(struct net_device *dev, |
f7fadf304 switchdev: make s... |
264 |
const struct switchdev_attr *attr, |
7ea6eb3f5 switchdev: introd... |
265 |
struct switchdev_trans *trans) |
356360625 switchdev: conver... |
266 |
{ |
d945097bb net: dsa: add sla... |
267 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
b8d866ac6 net: dsa: fix pre... |
268 |
int ret; |
356360625 switchdev: conver... |
269 270 |
switch (attr->id) { |
1f8683987 switchdev: rename... |
271 |
case SWITCHDEV_ATTR_ID_PORT_STP_STATE: |
fd3645413 net: dsa: change ... |
272 |
ret = dsa_port_set_state(dp, attr->u.stp_state, trans); |
356360625 switchdev: conver... |
273 |
break; |
fb2dabad6 net: dsa: support... |
274 |
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: |
c02c4175c net: dsa: change ... |
275 276 |
ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering, trans); |
fb2dabad6 net: dsa: support... |
277 |
break; |
34a79f63b net: dsa: support... |
278 |
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: |
072bb1903 net: dsa: change ... |
279 |
ret = dsa_port_ageing_time(dp, attr->u.ageing_time, trans); |
34a79f63b net: dsa: support... |
280 |
break; |
ea87005a0 net: dsa: Add set... |
281 282 283 284 |
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags, trans); break; |
57652796a net: dsa: add sup... |
285 286 287 |
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, trans); break; |
08cc83cc7 net: dsa: add sup... |
288 289 290 |
case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER: ret = dsa_port_mrouter(dp->cpu_dp, attr->u.mrouter, trans); break; |
356360625 switchdev: conver... |
291 292 293 294 295 296 297 |
default: ret = -EOPNOTSUPP; break; } return ret; } |
bdcff080f net: dsa: add sla... |
298 299 300 301 302 303 304 305 306 307 |
static int dsa_slave_vlan_add(struct net_device *dev, const struct switchdev_obj *obj, struct switchdev_trans *trans) { struct dsa_port *dp = dsa_slave_to_port(dev); struct switchdev_obj_port_vlan vlan; int err; if (obj->orig_dev != dev) return -EOPNOTSUPP; |
c5335d737 net: dsa: check b... |
308 309 |
if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev)) return 0; |
bdcff080f net: dsa: add sla... |
310 311 312 313 314 |
vlan = *SWITCHDEV_OBJ_PORT_VLAN(obj); err = dsa_port_vlan_add(dp, &vlan, trans); if (err) return err; |
b9499904f net: dsa: clear V... |
315 316 317 318 319 |
/* We need the dedicated CPU port to be a member of the VLAN as well. * Even though drivers often handle CPU membership in special ways, * it doesn't make sense to program a PVID, so clear this flag. */ vlan.flags &= ~BRIDGE_VLAN_INFO_PVID; |
7e1741b47 net: dsa: program... |
320 321 322 |
err = dsa_port_vlan_add(dp->cpu_dp, &vlan, trans); if (err) return err; |
bdcff080f net: dsa: add sla... |
323 324 |
return 0; } |
ba14d9eb1 net: dsa: add sup... |
325 |
static int dsa_slave_port_obj_add(struct net_device *dev, |
648b4a995 switchdev: bring ... |
326 |
const struct switchdev_obj *obj, |
79b139f4b net: dsa: use swi... |
327 328 |
struct switchdev_trans *trans, struct netlink_ext_ack *extack) |
ba14d9eb1 net: dsa: add sup... |
329 |
{ |
d945097bb net: dsa: add sla... |
330 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
ba14d9eb1 net: dsa: add sup... |
331 332 333 334 335 336 |
int err; /* For the prepare phase, ensure the full set of changes is feasable in * one go in order to signal a failure properly. If an operation is not * supported, return -EOPNOTSUPP. */ |
9e8f4a548 switchdev: push o... |
337 |
switch (obj->id) { |
8df302552 net: dsa: add MDB... |
338 |
case SWITCHDEV_OBJ_ID_PORT_MDB: |
79b139f4b net: dsa: use swi... |
339 340 |
if (obj->orig_dev != dev) return -EOPNOTSUPP; |
bcebb976e net: dsa: change ... |
341 |
err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj), trans); |
8df302552 net: dsa: add MDB... |
342 |
break; |
5f4dbc50c net: dsa: slave: ... |
343 344 345 346 347 348 349 |
case SWITCHDEV_OBJ_ID_HOST_MDB: /* DSA can directly translate this to a normal MDB add, * but on the CPU port. */ err = dsa_port_mdb_add(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj), trans); break; |
57d80838d switchdev: rename... |
350 |
case SWITCHDEV_OBJ_ID_PORT_VLAN: |
bdcff080f net: dsa: add sla... |
351 |
err = dsa_slave_vlan_add(dev, obj, trans); |
111495361 net: dsa: add sup... |
352 |
break; |
ba14d9eb1 net: dsa: add sup... |
353 354 355 356 357 358 359 |
default: err = -EOPNOTSUPP; break; } return err; } |
bdcff080f net: dsa: add sla... |
360 361 362 363 364 365 366 |
static int dsa_slave_vlan_del(struct net_device *dev, const struct switchdev_obj *obj) { struct dsa_port *dp = dsa_slave_to_port(dev); if (obj->orig_dev != dev) return -EOPNOTSUPP; |
c5335d737 net: dsa: check b... |
367 368 |
if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev)) return 0; |
7e1741b47 net: dsa: program... |
369 370 371 |
/* Do not deprogram the CPU port as it may be shared with other user * ports which can be members of this VLAN as well. */ |
bdcff080f net: dsa: add sla... |
372 373 |
return dsa_port_vlan_del(dp, SWITCHDEV_OBJ_PORT_VLAN(obj)); } |
ba14d9eb1 net: dsa: add sup... |
374 |
static int dsa_slave_port_obj_del(struct net_device *dev, |
648b4a995 switchdev: bring ... |
375 |
const struct switchdev_obj *obj) |
ba14d9eb1 net: dsa: add sup... |
376 |
{ |
d945097bb net: dsa: add sla... |
377 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
ba14d9eb1 net: dsa: add sup... |
378 |
int err; |
9e8f4a548 switchdev: push o... |
379 |
switch (obj->id) { |
8df302552 net: dsa: add MDB... |
380 |
case SWITCHDEV_OBJ_ID_PORT_MDB: |
79b139f4b net: dsa: use swi... |
381 382 |
if (obj->orig_dev != dev) return -EOPNOTSUPP; |
bcebb976e net: dsa: change ... |
383 |
err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); |
8df302552 net: dsa: add MDB... |
384 |
break; |
5f4dbc50c net: dsa: slave: ... |
385 386 387 388 389 390 |
case SWITCHDEV_OBJ_ID_HOST_MDB: /* DSA can directly translate this to a normal MDB add, * but on the CPU port. */ err = dsa_port_mdb_del(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj)); break; |
57d80838d switchdev: rename... |
391 |
case SWITCHDEV_OBJ_ID_PORT_VLAN: |
bdcff080f net: dsa: add sla... |
392 |
err = dsa_slave_vlan_del(dev, obj); |
111495361 net: dsa: add sup... |
393 |
break; |
ba14d9eb1 net: dsa: add sup... |
394 395 396 397 398 399 400 |
default: err = -EOPNOTSUPP; break; } return err; } |
929d6c145 net: dsa: Impleme... |
401 402 |
static int dsa_slave_get_port_parent_id(struct net_device *dev, struct netdev_phys_item_id *ppid) |
b73adef67 net: dsa: integra... |
403 |
{ |
d945097bb net: dsa: add sla... |
404 405 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
a42c8e33f net: dsa: Fix SWI... |
406 |
struct dsa_switch_tree *dst = ds->dst; |
b73adef67 net: dsa: integra... |
407 |
|
15b04acee dsa: pass switch ... |
408 409 410 411 412 413 |
/* For non-legacy ports, devlink is used and it takes * care of the name generation. This ndo implementation * should be removed with legacy support. */ if (dp->ds->devlink) return -EOPNOTSUPP; |
929d6c145 net: dsa: Impleme... |
414 415 416 417 418 |
ppid->id_len = sizeof(dst->index); memcpy(&ppid->id, &dst->index, ppid->id_len); return 0; } |
4fa7b7188 net: dsa: better ... |
419 420 |
static inline netdev_tx_t dsa_slave_netpoll_send_skb(struct net_device *dev, struct sk_buff *skb) |
04ff53f96 net: dsa: Add net... |
421 422 |
{ #ifdef CONFIG_NET_POLL_CONTROLLER |
4fa7b7188 net: dsa: better ... |
423 |
struct dsa_slave_priv *p = netdev_priv(dev); |
04ff53f96 net: dsa: Add net... |
424 425 426 427 428 429 430 |
if (p->netpoll) netpoll_send_skb(p->netpoll, skb); #else BUG(); #endif return NETDEV_TX_OK; } |
90af1059c net: dsa: forward... |
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p, struct sk_buff *skb) { struct dsa_switch *ds = p->dp->ds; struct sk_buff *clone; unsigned int type; type = ptp_classify_raw(skb); if (type == PTP_CLASS_NONE) return; if (!ds->ops->port_txtstamp) return; clone = skb_clone_sk(skb); if (!clone) return; |
146d442c2 net: dsa: Keep a ... |
448 |
DSA_SKB_CB(skb)->clone = clone; |
90af1059c net: dsa: forward... |
449 450 451 452 453 |
if (ds->ops->port_txtstamp(ds, p->dp->index, clone, type)) return; kfree_skb(clone); } |
97a69a0de net: dsa: Add sup... |
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev) { /* SKB for netpoll still need to be mangled with the protocol-specific * tag to be successfully transmitted */ if (unlikely(netpoll_tx_running(dev))) return dsa_slave_netpoll_send_skb(dev, skb); /* Queue the SKB for transmission on the parent interface, but * do not modify its EtherType */ skb->dev = dsa_slave_to_master(dev); dev_queue_xmit(skb); return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(dsa_enqueue_skb); |
3e8a72d1d net: dsa: reduce ... |
471 472 473 |
static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); |
5f6b4e14c net: dsa: User pe... |
474 |
struct pcpu_sw_netstats *s; |
4ed70ce9f net: dsa: Refacto... |
475 |
struct sk_buff *nskb; |
3e8a72d1d net: dsa: reduce ... |
476 |
|
5f6b4e14c net: dsa: User pe... |
477 478 479 480 481 |
s = this_cpu_ptr(p->stats64); u64_stats_update_begin(&s->syncp); s->tx_packets++; s->tx_bytes += skb->len; u64_stats_update_end(&s->syncp); |
3e8a72d1d net: dsa: reduce ... |
482 |
|
876713751 net: dsa: Initial... |
483 |
DSA_SKB_CB(skb)->deferred_xmit = false; |
146d442c2 net: dsa: Keep a ... |
484 |
DSA_SKB_CB(skb)->clone = NULL; |
876713751 net: dsa: Initial... |
485 |
|
90af1059c net: dsa: forward... |
486 487 488 489 |
/* Identify PTP protocol packets, clone them, and pass them to the * switch driver */ dsa_skb_tx_timestamp(p, skb); |
fe47d5630 net: dsa: factor ... |
490 491 492 |
/* Transmit function may have to reallocate the original SKB, * in which case it must have freed it. Only free it here on error. */ |
4ed70ce9f net: dsa: Refacto... |
493 |
nskb = p->xmit(skb, dev); |
fe47d5630 net: dsa: factor ... |
494 |
if (!nskb) { |
97a69a0de net: dsa: Add sup... |
495 496 |
if (!DSA_SKB_CB(skb)->deferred_xmit) kfree_skb(skb); |
4ed70ce9f net: dsa: Refacto... |
497 |
return NETDEV_TX_OK; |
fe47d5630 net: dsa: factor ... |
498 |
} |
5aed85cec net: dsa: allow s... |
499 |
|
97a69a0de net: dsa: Add sup... |
500 501 |
return dsa_enqueue_skb(nskb, dev); } |
04ff53f96 net: dsa: Add net... |
502 |
|
97a69a0de net: dsa: Add sup... |
503 504 505 |
void *dsa_defer_xmit(struct sk_buff *skb, struct net_device *dev) { struct dsa_port *dp = dsa_slave_to_port(dev); |
5aed85cec net: dsa: allow s... |
506 |
|
97a69a0de net: dsa: Add sup... |
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 |
DSA_SKB_CB(skb)->deferred_xmit = true; skb_queue_tail(&dp->xmit_queue, skb); schedule_work(&dp->xmit_work); return NULL; } EXPORT_SYMBOL_GPL(dsa_defer_xmit); static void dsa_port_xmit_work(struct work_struct *work) { struct dsa_port *dp = container_of(work, struct dsa_port, xmit_work); struct dsa_switch *ds = dp->ds; struct sk_buff *skb; if (unlikely(!ds->ops->port_deferred_xmit)) return; while ((skb = skb_dequeue(&dp->xmit_queue)) != NULL) ds->ops->port_deferred_xmit(ds, dp->index, skb); |
5aed85cec net: dsa: allow s... |
526 |
} |
91da11f87 net: Distributed ... |
527 |
/* ethtool operations *******************************************************/ |
91da11f87 net: Distributed ... |
528 |
|
91da11f87 net: Distributed ... |
529 530 531 |
static void dsa_slave_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { |
7826d43f2 ethtool: fix drvi... |
532 |
strlcpy(drvinfo->driver, "dsa", sizeof(drvinfo->driver)); |
7826d43f2 ethtool: fix drvi... |
533 534 |
strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); strlcpy(drvinfo->bus_info, "platform", sizeof(drvinfo->bus_info)); |
91da11f87 net: Distributed ... |
535 |
} |
3d762a0f0 net: dsa: Add sup... |
536 537 |
static int dsa_slave_get_regs_len(struct net_device *dev) { |
d945097bb net: dsa: add sla... |
538 539 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
3d762a0f0 net: dsa: Add sup... |
540 |
|
9d490b4ee net: dsa: rename ... |
541 |
if (ds->ops->get_regs_len) |
d945097bb net: dsa: add sla... |
542 |
return ds->ops->get_regs_len(ds, dp->index); |
3d762a0f0 net: dsa: Add sup... |
543 544 545 546 547 548 549 |
return -EOPNOTSUPP; } static void dsa_slave_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) { |
d945097bb net: dsa: add sla... |
550 551 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
3d762a0f0 net: dsa: Add sup... |
552 |
|
9d490b4ee net: dsa: rename ... |
553 |
if (ds->ops->get_regs) |
d945097bb net: dsa: add sla... |
554 |
ds->ops->get_regs(ds, dp->index, regs, _p); |
3d762a0f0 net: dsa: Add sup... |
555 |
} |
aab9c4067 net: dsa: Plug in... |
556 557 558 559 560 561 |
static int dsa_slave_nway_reset(struct net_device *dev) { struct dsa_port *dp = dsa_slave_to_port(dev); return phylink_ethtool_nway_reset(dp->pl); } |
6793abb4e net: dsa: Add sup... |
562 563 |
static int dsa_slave_get_eeprom_len(struct net_device *dev) { |
d945097bb net: dsa: add sla... |
564 565 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
6793abb4e net: dsa: Add sup... |
566 |
|
0e5760440 net: dsa: slave: ... |
567 |
if (ds->cd && ds->cd->eeprom_len) |
ff04955c2 dsa: Rename switc... |
568 |
return ds->cd->eeprom_len; |
6793abb4e net: dsa: Add sup... |
569 |
|
9d490b4ee net: dsa: rename ... |
570 571 |
if (ds->ops->get_eeprom_len) return ds->ops->get_eeprom_len(ds); |
6793abb4e net: dsa: Add sup... |
572 573 574 575 576 577 578 |
return 0; } static int dsa_slave_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { |
d945097bb net: dsa: add sla... |
579 580 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
6793abb4e net: dsa: Add sup... |
581 |
|
9d490b4ee net: dsa: rename ... |
582 583 |
if (ds->ops->get_eeprom) return ds->ops->get_eeprom(ds, eeprom, data); |
6793abb4e net: dsa: Add sup... |
584 585 586 587 588 589 590 |
return -EOPNOTSUPP; } static int dsa_slave_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { |
d945097bb net: dsa: add sla... |
591 592 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
6793abb4e net: dsa: Add sup... |
593 |
|
9d490b4ee net: dsa: rename ... |
594 595 |
if (ds->ops->set_eeprom) return ds->ops->set_eeprom(ds, eeprom, data); |
6793abb4e net: dsa: Add sup... |
596 597 598 |
return -EOPNOTSUPP; } |
91da11f87 net: Distributed ... |
599 600 601 |
static void dsa_slave_get_strings(struct net_device *dev, uint32_t stringset, uint8_t *data) { |
d945097bb net: dsa: add sla... |
602 603 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
91da11f87 net: Distributed ... |
604 605 606 607 608 609 610 611 |
if (stringset == ETH_SS_STATS) { int len = ETH_GSTRING_LEN; strncpy(data, "tx_packets", len); strncpy(data + len, "tx_bytes", len); strncpy(data + 2 * len, "rx_packets", len); strncpy(data + 3 * len, "rx_bytes", len); |
9d490b4ee net: dsa: rename ... |
612 |
if (ds->ops->get_strings) |
89f090483 net: dsa: Pass st... |
613 614 |
ds->ops->get_strings(ds, dp->index, stringset, data + 4 * len); |
91da11f87 net: Distributed ... |
615 616 617 618 619 620 621 |
} } static void dsa_slave_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, uint64_t *data) { |
d945097bb net: dsa: add sla... |
622 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
91da11f87 net: Distributed ... |
623 |
struct dsa_slave_priv *p = netdev_priv(dev); |
d945097bb net: dsa: add sla... |
624 |
struct dsa_switch *ds = dp->ds; |
5f6b4e14c net: dsa: User pe... |
625 |
struct pcpu_sw_netstats *s; |
f613ed665 net: dsa: Add sup... |
626 |
unsigned int start; |
5f6b4e14c net: dsa: User pe... |
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 |
int i; for_each_possible_cpu(i) { u64 tx_packets, tx_bytes, rx_packets, rx_bytes; s = per_cpu_ptr(p->stats64, i); do { start = u64_stats_fetch_begin_irq(&s->syncp); tx_packets = s->tx_packets; tx_bytes = s->tx_bytes; rx_packets = s->rx_packets; rx_bytes = s->rx_bytes; } while (u64_stats_fetch_retry_irq(&s->syncp, start)); data[0] += tx_packets; data[1] += tx_bytes; data[2] += rx_packets; data[3] += rx_bytes; } |
9d490b4ee net: dsa: rename ... |
645 |
if (ds->ops->get_ethtool_stats) |
d945097bb net: dsa: add sla... |
646 |
ds->ops->get_ethtool_stats(ds, dp->index, data + 4); |
91da11f87 net: Distributed ... |
647 648 649 650 |
} static int dsa_slave_get_sset_count(struct net_device *dev, int sset) { |
d945097bb net: dsa: add sla... |
651 652 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
91da11f87 net: Distributed ... |
653 654 655 656 657 |
if (sset == ETH_SS_STATS) { int count; count = 4; |
9d490b4ee net: dsa: rename ... |
658 |
if (ds->ops->get_sset_count) |
89f090483 net: dsa: Pass st... |
659 |
count += ds->ops->get_sset_count(ds, dp->index, sset); |
91da11f87 net: Distributed ... |
660 661 662 663 664 665 |
return count; } return -EOPNOTSUPP; } |
19e57c4e6 net: dsa: add {ge... |
666 667 |
static void dsa_slave_get_wol(struct net_device *dev, struct ethtool_wolinfo *w) { |
d945097bb net: dsa: add sla... |
668 669 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
19e57c4e6 net: dsa: add {ge... |
670 |
|
aab9c4067 net: dsa: Plug in... |
671 |
phylink_ethtool_get_wol(dp->pl, w); |
9d490b4ee net: dsa: rename ... |
672 |
if (ds->ops->get_wol) |
d945097bb net: dsa: add sla... |
673 |
ds->ops->get_wol(ds, dp->index, w); |
19e57c4e6 net: dsa: add {ge... |
674 675 676 677 |
} static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) { |
d945097bb net: dsa: add sla... |
678 679 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
19e57c4e6 net: dsa: add {ge... |
680 |
int ret = -EOPNOTSUPP; |
aab9c4067 net: dsa: Plug in... |
681 |
phylink_ethtool_set_wol(dp->pl, w); |
9d490b4ee net: dsa: rename ... |
682 |
if (ds->ops->set_wol) |
d945097bb net: dsa: add sla... |
683 |
ret = ds->ops->set_wol(ds, dp->index, w); |
19e57c4e6 net: dsa: add {ge... |
684 685 686 |
return ret; } |
7905288f0 net: dsa: allow s... |
687 688 |
static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e) { |
d945097bb net: dsa: add sla... |
689 690 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
7905288f0 net: dsa: allow s... |
691 |
int ret; |
7b9cc7384 net: dsa: PHY dev... |
692 |
/* Port's PHY and MAC both need to be EEE capable */ |
00670cb8a net: dsa: Fix NUL... |
693 |
if (!dev->phydev || !dp->pl) |
7b9cc7384 net: dsa: PHY dev... |
694 |
return -ENODEV; |
08f500610 net: dsa: rename ... |
695 |
if (!ds->ops->set_mac_eee) |
7905288f0 net: dsa: allow s... |
696 |
return -EOPNOTSUPP; |
d945097bb net: dsa: add sla... |
697 |
ret = ds->ops->set_mac_eee(ds, dp->index, e); |
7905288f0 net: dsa: allow s... |
698 699 |
if (ret) return ret; |
aab9c4067 net: dsa: Plug in... |
700 |
return phylink_ethtool_set_eee(dp->pl, e); |
7905288f0 net: dsa: allow s... |
701 702 703 704 |
} static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e) { |
d945097bb net: dsa: add sla... |
705 706 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
7905288f0 net: dsa: allow s... |
707 |
int ret; |
7b9cc7384 net: dsa: PHY dev... |
708 |
/* Port's PHY and MAC both need to be EEE capable */ |
00670cb8a net: dsa: Fix NUL... |
709 |
if (!dev->phydev || !dp->pl) |
7b9cc7384 net: dsa: PHY dev... |
710 |
return -ENODEV; |
08f500610 net: dsa: rename ... |
711 |
if (!ds->ops->get_mac_eee) |
7905288f0 net: dsa: allow s... |
712 |
return -EOPNOTSUPP; |
d945097bb net: dsa: add sla... |
713 |
ret = ds->ops->get_mac_eee(ds, dp->index, e); |
7905288f0 net: dsa: allow s... |
714 715 |
if (ret) return ret; |
aab9c4067 net: dsa: Plug in... |
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
return phylink_ethtool_get_eee(dp->pl, e); } static int dsa_slave_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct dsa_port *dp = dsa_slave_to_port(dev); return phylink_ethtool_ksettings_get(dp->pl, cmd); } static int dsa_slave_set_link_ksettings(struct net_device *dev, const struct ethtool_link_ksettings *cmd) { struct dsa_port *dp = dsa_slave_to_port(dev); return phylink_ethtool_ksettings_set(dp->pl, cmd); |
7905288f0 net: dsa: allow s... |
733 |
} |
04ff53f96 net: dsa: Add net... |
734 735 736 737 |
#ifdef CONFIG_NET_POLL_CONTROLLER static int dsa_slave_netpoll_setup(struct net_device *dev, struct netpoll_info *ni) { |
d0006b002 net: dsa: add sla... |
738 |
struct net_device *master = dsa_slave_to_master(dev); |
04ff53f96 net: dsa: Add net... |
739 |
struct dsa_slave_priv *p = netdev_priv(dev); |
04ff53f96 net: dsa: Add net... |
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 |
struct netpoll *netpoll; int err = 0; netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL); if (!netpoll) return -ENOMEM; err = __netpoll_setup(netpoll, master); if (err) { kfree(netpoll); goto out; } p->netpoll = netpoll; out: return err; } static void dsa_slave_netpoll_cleanup(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct netpoll *netpoll = p->netpoll; if (!netpoll) return; p->netpoll = NULL; |
c9fbd71f7 netpoll: allow cl... |
767 |
__netpoll_free(netpoll); |
04ff53f96 net: dsa: Add net... |
768 769 770 771 772 773 |
} static void dsa_slave_poll_controller(struct net_device *dev) { } #endif |
44bb765cf net: dsa: Impleme... |
774 775 776 |
static int dsa_slave_get_phys_port_name(struct net_device *dev, char *name, size_t len) { |
d945097bb net: dsa: add sla... |
777 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
44bb765cf net: dsa: Impleme... |
778 |
|
d484210bf dsa: do not suppo... |
779 780 781 782 783 784 |
/* For non-legacy ports, devlink is used and it takes * care of the name generation. This ndo implementation * should be removed with legacy support. */ if (dp->ds->devlink) return -EOPNOTSUPP; |
d945097bb net: dsa: add sla... |
785 |
if (snprintf(name, len, "p%d", dp->index) >= len) |
44bb765cf net: dsa: Impleme... |
786 |
return -EINVAL; |
3a543ef47 net: dsa: Impleme... |
787 788 789 |
return 0; } |
f50f21274 net: dsa: Add plu... |
790 |
static struct dsa_mall_tc_entry * |
4fa7b7188 net: dsa: better ... |
791 |
dsa_slave_mall_tc_entry_find(struct net_device *dev, unsigned long cookie) |
f50f21274 net: dsa: Add plu... |
792 |
{ |
4fa7b7188 net: dsa: better ... |
793 |
struct dsa_slave_priv *p = netdev_priv(dev); |
f50f21274 net: dsa: Add plu... |
794 795 796 797 798 799 800 801 802 803 |
struct dsa_mall_tc_entry *mall_tc_entry; list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) if (mall_tc_entry->cookie == cookie) return mall_tc_entry; return NULL; } static int dsa_slave_add_cls_matchall(struct net_device *dev, |
f50f21274 net: dsa: Add plu... |
804 805 806 |
struct tc_cls_matchall_offload *cls, bool ingress) { |
d945097bb net: dsa: add sla... |
807 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
f50f21274 net: dsa: Add plu... |
808 809 |
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_mall_tc_entry *mall_tc_entry; |
5fd9fc4e2 net: sched: push ... |
810 |
__be16 protocol = cls->common.protocol; |
d945097bb net: dsa: add sla... |
811 |
struct dsa_switch *ds = dp->ds; |
9681e8b3e net/dsa: use inte... |
812 |
struct flow_action_entry *act; |
d945097bb net: dsa: add sla... |
813 |
struct dsa_port *to_dp; |
f50f21274 net: dsa: Add plu... |
814 |
int err = -EOPNOTSUPP; |
f50f21274 net: dsa: Add plu... |
815 816 817 |
if (!ds->ops->port_mirror_add) return err; |
9681e8b3e net/dsa: use inte... |
818 |
if (!flow_offload_has_one_action(&cls->rule->action)) |
f50f21274 net: dsa: Add plu... |
819 |
return err; |
9681e8b3e net/dsa: use inte... |
820 |
act = &cls->rule->action.entries[0]; |
f50f21274 net: dsa: Add plu... |
821 |
|
9681e8b3e net/dsa: use inte... |
822 |
if (act->id == FLOW_ACTION_MIRRED && protocol == htons(ETH_P_ALL)) { |
f50f21274 net: dsa: Add plu... |
823 |
struct dsa_mall_mirror_tc_entry *mirror; |
9681e8b3e net/dsa: use inte... |
824 |
if (!act->dev) |
f50f21274 net: dsa: Add plu... |
825 |
return -EINVAL; |
9681e8b3e net/dsa: use inte... |
826 |
if (!dsa_slave_dev_check(act->dev)) |
f50f21274 net: dsa: Add plu... |
827 828 829 830 831 832 833 834 835 |
return -EOPNOTSUPP; mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL); if (!mall_tc_entry) return -ENOMEM; mall_tc_entry->cookie = cls->cookie; mall_tc_entry->type = DSA_PORT_MALL_MIRROR; mirror = &mall_tc_entry->mirror; |
9681e8b3e net/dsa: use inte... |
836 |
to_dp = dsa_slave_to_port(act->dev); |
f50f21274 net: dsa: Add plu... |
837 |
|
d945097bb net: dsa: add sla... |
838 |
mirror->to_local_port = to_dp->index; |
f50f21274 net: dsa: Add plu... |
839 |
mirror->ingress = ingress; |
d945097bb net: dsa: add sla... |
840 |
err = ds->ops->port_mirror_add(ds, dp->index, mirror, ingress); |
f50f21274 net: dsa: Add plu... |
841 842 843 844 845 846 847 848 849 850 851 852 853 854 |
if (err) { kfree(mall_tc_entry); return err; } list_add_tail(&mall_tc_entry->list, &p->mall_tc_list); } return 0; } static void dsa_slave_del_cls_matchall(struct net_device *dev, struct tc_cls_matchall_offload *cls) { |
d945097bb net: dsa: add sla... |
855 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
f50f21274 net: dsa: Add plu... |
856 |
struct dsa_mall_tc_entry *mall_tc_entry; |
d945097bb net: dsa: add sla... |
857 |
struct dsa_switch *ds = dp->ds; |
f50f21274 net: dsa: Add plu... |
858 859 860 |
if (!ds->ops->port_mirror_del) return; |
4fa7b7188 net: dsa: better ... |
861 |
mall_tc_entry = dsa_slave_mall_tc_entry_find(dev, cls->cookie); |
f50f21274 net: dsa: Add plu... |
862 863 864 865 866 867 868 |
if (!mall_tc_entry) return; list_del(&mall_tc_entry->list); switch (mall_tc_entry->type) { case DSA_PORT_MALL_MIRROR: |
d945097bb net: dsa: add sla... |
869 |
ds->ops->port_mirror_del(ds, dp->index, &mall_tc_entry->mirror); |
f50f21274 net: dsa: Add plu... |
870 871 872 873 874 875 876 |
break; default: WARN_ON(1); } kfree(mall_tc_entry); } |
3fbae382f dsa: push cls_mat... |
877 |
static int dsa_slave_setup_tc_cls_matchall(struct net_device *dev, |
6b3eb752b dsa: Convert ndo_... |
878 879 |
struct tc_cls_matchall_offload *cls, bool ingress) |
f50f21274 net: dsa: Add plu... |
880 |
{ |
5fd9fc4e2 net: sched: push ... |
881 |
if (cls->common.chain_index) |
a5fcf8a6c net: propagate tc... |
882 |
return -EOPNOTSUPP; |
f50f21274 net: dsa: Add plu... |
883 |
|
3fbae382f dsa: push cls_mat... |
884 885 |
switch (cls->command) { case TC_CLSMATCHALL_REPLACE: |
5fd9fc4e2 net: sched: push ... |
886 |
return dsa_slave_add_cls_matchall(dev, cls, ingress); |
3fbae382f dsa: push cls_mat... |
887 888 889 890 891 892 893 |
case TC_CLSMATCHALL_DESTROY: dsa_slave_del_cls_matchall(dev, cls); return 0; default: return -EOPNOTSUPP; } } |
6b3eb752b dsa: Convert ndo_... |
894 895 896 897 |
static int dsa_slave_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv, bool ingress) { struct net_device *dev = cb_priv; |
44ae12a76 net: sched: move ... |
898 899 |
if (!tc_can_offload(dev)) return -EOPNOTSUPP; |
6b3eb752b dsa: Convert ndo_... |
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
switch (type) { case TC_SETUP_CLSMATCHALL: return dsa_slave_setup_tc_cls_matchall(dev, type_data, ingress); default: return -EOPNOTSUPP; } } static int dsa_slave_setup_tc_block_cb_ig(enum tc_setup_type type, void *type_data, void *cb_priv) { return dsa_slave_setup_tc_block_cb(type, type_data, cb_priv, true); } static int dsa_slave_setup_tc_block_cb_eg(enum tc_setup_type type, void *type_data, void *cb_priv) { return dsa_slave_setup_tc_block_cb(type, type_data, cb_priv, false); } |
955bcb6ea drivers: net: use... |
919 |
static LIST_HEAD(dsa_slave_block_cb_list); |
6b3eb752b dsa: Convert ndo_... |
920 |
static int dsa_slave_setup_tc_block(struct net_device *dev, |
955bcb6ea drivers: net: use... |
921 |
struct flow_block_offload *f) |
6b3eb752b dsa: Convert ndo_... |
922 |
{ |
955bcb6ea drivers: net: use... |
923 |
struct flow_block_cb *block_cb; |
a73233115 net: flow_offload... |
924 |
flow_setup_cb_t *cb; |
6b3eb752b dsa: Convert ndo_... |
925 |
|
32f8c4093 net: flow_offload... |
926 |
if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) |
6b3eb752b dsa: Convert ndo_... |
927 |
cb = dsa_slave_setup_tc_block_cb_ig; |
32f8c4093 net: flow_offload... |
928 |
else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) |
6b3eb752b dsa: Convert ndo_... |
929 930 931 |
cb = dsa_slave_setup_tc_block_cb_eg; else return -EOPNOTSUPP; |
955bcb6ea drivers: net: use... |
932 |
f->driver_block_list = &dsa_slave_block_cb_list; |
6b3eb752b dsa: Convert ndo_... |
933 |
switch (f->command) { |
9c0e189ec net: flow_offload... |
934 |
case FLOW_BLOCK_BIND: |
0d4fd02e7 net: flow_offload... |
935 936 |
if (flow_block_cb_is_busy(cb, dev, &dsa_slave_block_cb_list)) return -EBUSY; |
0c7294dda net: flow_offload... |
937 |
block_cb = flow_block_cb_alloc(cb, dev, dev, NULL); |
955bcb6ea drivers: net: use... |
938 939 940 941 942 943 |
if (IS_ERR(block_cb)) return PTR_ERR(block_cb); flow_block_cb_add(block_cb, f); list_add_tail(&block_cb->driver_list, &dsa_slave_block_cb_list); return 0; |
9c0e189ec net: flow_offload... |
944 |
case FLOW_BLOCK_UNBIND: |
14bfb13f0 net: flow_offload... |
945 |
block_cb = flow_block_cb_lookup(f->block, cb, dev); |
955bcb6ea drivers: net: use... |
946 947 948 949 950 |
if (!block_cb) return -ENOENT; flow_block_cb_remove(block_cb, f); list_del(&block_cb->driver_list); |
6b3eb752b dsa: Convert ndo_... |
951 952 953 954 955 |
return 0; default: return -EOPNOTSUPP; } } |
3fbae382f dsa: push cls_mat... |
956 |
static int dsa_slave_setup_tc(struct net_device *dev, enum tc_setup_type type, |
de4784ca0 net: sched: get r... |
957 |
void *type_data) |
3fbae382f dsa: push cls_mat... |
958 |
{ |
47d23af29 net: dsa: Pass nd... |
959 960 961 962 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; if (type == TC_SETUP_BLOCK) |
6b3eb752b dsa: Convert ndo_... |
963 |
return dsa_slave_setup_tc_block(dev, type_data); |
47d23af29 net: dsa: Pass nd... |
964 965 |
if (!ds->ops->port_setup_tc) |
a5fcf8a6c net: propagate tc... |
966 |
return -EOPNOTSUPP; |
47d23af29 net: dsa: Pass nd... |
967 968 |
return ds->ops->port_setup_tc(ds, dp->index, type, type_data); |
f50f21274 net: dsa: Add plu... |
969 |
} |
f613ed665 net: dsa: Add sup... |
970 971 972 973 |
static void dsa_slave_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { struct dsa_slave_priv *p = netdev_priv(dev); |
5f6b4e14c net: dsa: User pe... |
974 |
struct pcpu_sw_netstats *s; |
f613ed665 net: dsa: Add sup... |
975 |
unsigned int start; |
5f6b4e14c net: dsa: User pe... |
976 |
int i; |
f613ed665 net: dsa: Add sup... |
977 978 |
netdev_stats_to_stats64(stats, &dev->stats); |
5f6b4e14c net: dsa: User pe... |
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 |
for_each_possible_cpu(i) { u64 tx_packets, tx_bytes, rx_packets, rx_bytes; s = per_cpu_ptr(p->stats64, i); do { start = u64_stats_fetch_begin_irq(&s->syncp); tx_packets = s->tx_packets; tx_bytes = s->tx_bytes; rx_packets = s->rx_packets; rx_bytes = s->rx_bytes; } while (u64_stats_fetch_retry_irq(&s->syncp, start)); stats->tx_packets += tx_packets; stats->tx_bytes += tx_bytes; stats->rx_packets += rx_packets; stats->rx_bytes += rx_bytes; } |
f613ed665 net: dsa: Add sup... |
996 |
} |
bf9f26485 net: dsa: Hook {g... |
997 998 999 |
static int dsa_slave_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *nfc, u32 *rule_locs) { |
d945097bb net: dsa: add sla... |
1000 1001 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
bf9f26485 net: dsa: Hook {g... |
1002 1003 1004 |
if (!ds->ops->get_rxnfc) return -EOPNOTSUPP; |
d945097bb net: dsa: add sla... |
1005 |
return ds->ops->get_rxnfc(ds, dp->index, nfc, rule_locs); |
bf9f26485 net: dsa: Hook {g... |
1006 1007 1008 1009 1010 |
} static int dsa_slave_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *nfc) { |
d945097bb net: dsa: add sla... |
1011 1012 |
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; |
bf9f26485 net: dsa: Hook {g... |
1013 1014 1015 |
if (!ds->ops->set_rxnfc) return -EOPNOTSUPP; |
d945097bb net: dsa: add sla... |
1016 |
return ds->ops->set_rxnfc(ds, dp->index, nfc); |
bf9f26485 net: dsa: Hook {g... |
1017 |
} |
0336369d3 net: dsa: forward... |
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 |
static int dsa_slave_get_ts_info(struct net_device *dev, struct ethtool_ts_info *ts) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->dp->ds; if (!ds->ops->get_ts_info) return -EOPNOTSUPP; return ds->ops->get_ts_info(ds, p->dp->index, ts); } |
061f6a505 net: dsa: Add ndo... |
1029 1030 1031 1032 |
static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid) { struct dsa_port *dp = dsa_slave_to_port(dev); |
061f6a505 net: dsa: Add ndo... |
1033 1034 1035 1036 1037 1038 1039 |
struct bridge_vlan_info info; int ret; /* Check for a possible bridge VLAN entry now since there is no * need to emulate the switchdev prepare + commit phase. */ if (dp->bridge_dev) { |
c5335d737 net: dsa: check b... |
1040 1041 |
if (!br_vlan_enabled(dp->bridge_dev)) return 0; |
061f6a505 net: dsa: Add ndo... |
1042 1043 1044 1045 1046 1047 1048 1049 |
/* br_vlan_get_info() returns -EINVAL or -ENOENT if the * device, respectively the VID is not found, returning * 0 means success, which is a failure for us here. */ ret = br_vlan_get_info(dp->bridge_dev, vid, &info); if (ret == 0) return -EBUSY; } |
cf360866b net: dsa: do not ... |
1050 |
ret = dsa_port_vid_add(dp, vid, 0); |
9b236d2a6 net: dsa: Adverti... |
1051 |
if (ret) |
cf360866b net: dsa: do not ... |
1052 |
return ret; |
7e1741b47 net: dsa: program... |
1053 |
ret = dsa_port_vid_add(dp->cpu_dp, vid, 0); |
9b236d2a6 net: dsa: Adverti... |
1054 |
if (ret) |
7e1741b47 net: dsa: program... |
1055 |
return ret; |
cf360866b net: dsa: do not ... |
1056 |
return 0; |
061f6a505 net: dsa: Add ndo... |
1057 1058 1059 1060 1061 1062 |
} static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid) { struct dsa_port *dp = dsa_slave_to_port(dev); |
061f6a505 net: dsa: Add ndo... |
1063 1064 1065 1066 1067 1068 1069 |
struct bridge_vlan_info info; int ret; /* Check for a possible bridge VLAN entry now since there is no * need to emulate the switchdev prepare + commit phase. */ if (dp->bridge_dev) { |
c5335d737 net: dsa: check b... |
1070 1071 |
if (!br_vlan_enabled(dp->bridge_dev)) return 0; |
061f6a505 net: dsa: Add ndo... |
1072 1073 1074 1075 1076 1077 1078 1079 |
/* br_vlan_get_info() returns -EINVAL or -ENOENT if the * device, respectively the VID is not found, returning * 0 means success, which is a failure for us here. */ ret = br_vlan_get_info(dp->bridge_dev, vid, &info); if (ret == 0) return -EBUSY; } |
7e1741b47 net: dsa: program... |
1080 1081 1082 |
/* Do not deprogram the CPU port as it may be shared with other user * ports which can be members of this VLAN as well. */ |
9b236d2a6 net: dsa: Adverti... |
1083 |
return dsa_port_vid_del(dp, vid); |
061f6a505 net: dsa: Add ndo... |
1084 |
} |
91da11f87 net: Distributed ... |
1085 |
static const struct ethtool_ops dsa_slave_ethtool_ops = { |
91da11f87 net: Distributed ... |
1086 |
.get_drvinfo = dsa_slave_get_drvinfo, |
3d762a0f0 net: dsa: Add sup... |
1087 1088 |
.get_regs_len = dsa_slave_get_regs_len, .get_regs = dsa_slave_get_regs, |
aab9c4067 net: dsa: Plug in... |
1089 |
.nway_reset = dsa_slave_nway_reset, |
c4aef9fc0 net: dsa: Elimina... |
1090 |
.get_link = ethtool_op_get_link, |
6793abb4e net: dsa: Add sup... |
1091 1092 1093 |
.get_eeprom_len = dsa_slave_get_eeprom_len, .get_eeprom = dsa_slave_get_eeprom, .set_eeprom = dsa_slave_set_eeprom, |
91da11f87 net: Distributed ... |
1094 1095 1096 |
.get_strings = dsa_slave_get_strings, .get_ethtool_stats = dsa_slave_get_ethtool_stats, .get_sset_count = dsa_slave_get_sset_count, |
19e57c4e6 net: dsa: add {ge... |
1097 1098 |
.set_wol = dsa_slave_set_wol, .get_wol = dsa_slave_get_wol, |
7905288f0 net: dsa: allow s... |
1099 1100 |
.set_eee = dsa_slave_set_eee, .get_eee = dsa_slave_get_eee, |
aab9c4067 net: dsa: Plug in... |
1101 1102 |
.get_link_ksettings = dsa_slave_get_link_ksettings, .set_link_ksettings = dsa_slave_set_link_ksettings, |
bf9f26485 net: dsa: Hook {g... |
1103 1104 |
.get_rxnfc = dsa_slave_get_rxnfc, .set_rxnfc = dsa_slave_set_rxnfc, |
0336369d3 net: dsa: forward... |
1105 |
.get_ts_info = dsa_slave_get_ts_info, |
91da11f87 net: Distributed ... |
1106 |
}; |
2a93c1a36 net: dsa: Allow c... |
1107 1108 1109 1110 |
/* legacy way, bypassing the bridge *****************************************/ int dsa_legacy_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, |
87b0984eb net: Add extack a... |
1111 1112 |
u16 flags, struct netlink_ext_ack *extack) |
2a93c1a36 net: dsa: Allow c... |
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 |
{ struct dsa_port *dp = dsa_slave_to_port(dev); return dsa_port_fdb_add(dp, addr, vid); } int dsa_legacy_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid) { struct dsa_port *dp = dsa_slave_to_port(dev); return dsa_port_fdb_del(dp, addr, vid); } |
716efee20 dsa: implement nd... |
1127 1128 1129 1130 1131 1132 |
static struct devlink_port *dsa_slave_get_devlink_port(struct net_device *dev) { struct dsa_port *dp = dsa_slave_to_port(dev); return dp->ds->devlink ? &dp->devlink_port : NULL; } |
3e8a72d1d net: dsa: reduce ... |
1133 |
static const struct net_device_ops dsa_slave_netdev_ops = { |
d442ad4ab dsa: convert to n... |
1134 1135 |
.ndo_open = dsa_slave_open, .ndo_stop = dsa_slave_close, |
3e8a72d1d net: dsa: reduce ... |
1136 |
.ndo_start_xmit = dsa_slave_xmit, |
d442ad4ab dsa: convert to n... |
1137 1138 |
.ndo_change_rx_flags = dsa_slave_change_rx_flags, .ndo_set_rx_mode = dsa_slave_set_rx_mode, |
d442ad4ab dsa: convert to n... |
1139 |
.ndo_set_mac_address = dsa_slave_set_mac_address, |
37b8da1a3 net: dsa: Move FD... |
1140 1141 |
.ndo_fdb_add = dsa_legacy_fdb_add, .ndo_fdb_del = dsa_legacy_fdb_del, |
2bedde1ab net: dsa: Move FD... |
1142 |
.ndo_fdb_dump = dsa_slave_fdb_dump, |
d442ad4ab dsa: convert to n... |
1143 |
.ndo_do_ioctl = dsa_slave_ioctl, |
abd2be00d dsa: implement nd... |
1144 |
.ndo_get_iflink = dsa_slave_get_iflink, |
04ff53f96 net: dsa: Add net... |
1145 1146 1147 1148 1149 |
#ifdef CONFIG_NET_POLL_CONTROLLER .ndo_netpoll_setup = dsa_slave_netpoll_setup, .ndo_netpoll_cleanup = dsa_slave_netpoll_cleanup, .ndo_poll_controller = dsa_slave_poll_controller, #endif |
44bb765cf net: dsa: Impleme... |
1150 |
.ndo_get_phys_port_name = dsa_slave_get_phys_port_name, |
f50f21274 net: dsa: Add plu... |
1151 |
.ndo_setup_tc = dsa_slave_setup_tc, |
f613ed665 net: dsa: Add sup... |
1152 |
.ndo_get_stats64 = dsa_slave_get_stats64, |
929d6c145 net: dsa: Impleme... |
1153 |
.ndo_get_port_parent_id = dsa_slave_get_port_parent_id, |
061f6a505 net: dsa: Add ndo... |
1154 1155 |
.ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid, |
716efee20 dsa: implement nd... |
1156 |
.ndo_get_devlink_port = dsa_slave_get_devlink_port, |
98237d433 switchdev: use ne... |
1157 |
}; |
f37db85d0 net: dsa: Set a "... |
1158 1159 1160 |
static struct device_type dsa_type = { .name = "dsa", }; |
aab9c4067 net: dsa: Plug in... |
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 |
void dsa_port_phylink_mac_change(struct dsa_switch *ds, int port, bool up) { const struct dsa_port *dp = dsa_to_port(ds, port); phylink_mac_change(dp->pl, up); } EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_change); static void dsa_slave_phylink_fixed_state(struct net_device *dev, struct phylink_link_state *state) { struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_switch *ds = dp->ds; /* No need to check that this operation is valid, the callback would * not be called if it was not. */ ds->ops->phylink_fixed_state(ds, dp->index, state); |
ce31b31c6 net: dsa: allow u... |
1179 |
} |
91da11f87 net: Distributed ... |
1180 |
/* slave device setup *******************************************************/ |
4fa7b7188 net: dsa: better ... |
1181 |
static int dsa_slave_phy_connect(struct net_device *slave_dev, int addr) |
c305c1651 net: dsa: move PH... |
1182 |
{ |
d945097bb net: dsa: add sla... |
1183 |
struct dsa_port *dp = dsa_slave_to_port(slave_dev); |
d945097bb net: dsa: add sla... |
1184 |
struct dsa_switch *ds = dp->ds; |
c305c1651 net: dsa: move PH... |
1185 |
|
0115dcd17 net: dsa: use sla... |
1186 1187 |
slave_dev->phydev = mdiobus_get_phy(ds->slave_mii_bus, addr); if (!slave_dev->phydev) { |
d25b8e742 net: dsa: better ... |
1188 1189 |
netdev_err(slave_dev, "no phy at %d ", addr); |
c305c1651 net: dsa: move PH... |
1190 |
return -ENODEV; |
d25b8e742 net: dsa: better ... |
1191 |
} |
c305c1651 net: dsa: move PH... |
1192 |
|
aab9c4067 net: dsa: Plug in... |
1193 |
return phylink_connect_phy(dp->pl, slave_dev->phydev); |
11d8f3dda net: dsa: Add PHY... |
1194 |
} |
11d8f3dda net: dsa: Add PHY... |
1195 |
|
4fa7b7188 net: dsa: better ... |
1196 |
static int dsa_slave_phy_setup(struct net_device *slave_dev) |
0d8bcdd38 net: dsa: allow f... |
1197 |
{ |
d945097bb net: dsa: add sla... |
1198 |
struct dsa_port *dp = dsa_slave_to_port(slave_dev); |
d945097bb net: dsa: add sla... |
1199 1200 |
struct device_node *port_dn = dp->dn; struct dsa_switch *ds = dp->ds; |
6819563e6 net: dsa: allow s... |
1201 |
u32 phy_flags = 0; |
19334920e net: dsa: Set val... |
1202 |
int mode, ret; |
0d8bcdd38 net: dsa: allow f... |
1203 |
|
19334920e net: dsa: Set val... |
1204 1205 1206 |
mode = of_get_phy_mode(port_dn); if (mode < 0) mode = PHY_INTERFACE_MODE_NA; |
0d8bcdd38 net: dsa: allow f... |
1207 |
|
44cc27e43 net: phylink: Add... |
1208 1209 1210 1211 |
dp->pl_config.dev = &slave_dev->dev; dp->pl_config.type = PHYLINK_NETDEV; dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), mode, |
77373d49d net: dsa: Move th... |
1212 |
&dsa_port_phylink_mac_ops); |
aab9c4067 net: dsa: Plug in... |
1213 1214 1215 1216 1217 |
if (IS_ERR(dp->pl)) { netdev_err(slave_dev, "error creating PHYLINK: %ld ", PTR_ERR(dp->pl)); return PTR_ERR(dp->pl); |
0d8bcdd38 net: dsa: allow f... |
1218 |
} |
aab9c4067 net: dsa: Plug in... |
1219 1220 1221 1222 1223 1224 |
/* Register only if the switch provides such a callback, since this * callback takes precedence over polling the link GPIO in PHYLINK * (see phylink_get_fixed_state). */ if (ds->ops->phylink_fixed_state) phylink_fixed_state_cb(dp->pl, dsa_slave_phylink_fixed_state); |
9d490b4ee net: dsa: rename ... |
1225 |
if (ds->ops->get_phy_flags) |
d945097bb net: dsa: add sla... |
1226 |
phy_flags = ds->ops->get_phy_flags(ds, dp->index); |
6819563e6 net: dsa: allow s... |
1227 |
|
aab9c4067 net: dsa: Plug in... |
1228 |
ret = phylink_of_phy_connect(dp->pl, port_dn, phy_flags); |
6146dd453 net: dsa: Avoid n... |
1229 1230 1231 |
if (ret == -ENODEV && ds->slave_mii_bus) { /* We could not connect to a designated PHY or SFP, so try to * use the switch internal MDIO bus instead |
aab9c4067 net: dsa: Plug in... |
1232 |
*/ |
d945097bb net: dsa: add sla... |
1233 |
ret = dsa_slave_phy_connect(slave_dev, dp->index); |
d25b8e742 net: dsa: better ... |
1234 |
if (ret) { |
aab9c4067 net: dsa: Plug in... |
1235 1236 1237 |
netdev_err(slave_dev, "failed to connect to port %d: %d ", |
d945097bb net: dsa: add sla... |
1238 |
dp->index, ret); |
aab9c4067 net: dsa: Plug in... |
1239 |
phylink_destroy(dp->pl); |
c305c1651 net: dsa: move PH... |
1240 |
return ret; |
d25b8e742 net: dsa: better ... |
1241 |
} |
b31f65fb4 net: dsa: slave: ... |
1242 |
} |
9697f1cde net: dsa: propaga... |
1243 |
|
6146dd453 net: dsa: Avoid n... |
1244 |
return ret; |
0d8bcdd38 net: dsa: allow f... |
1245 |
} |
244625491 net: dsa: allow s... |
1246 1247 |
int dsa_slave_suspend(struct net_device *slave_dev) { |
aab9c4067 net: dsa: Plug in... |
1248 |
struct dsa_port *dp = dsa_slave_to_port(slave_dev); |
244625491 net: dsa: allow s... |
1249 |
|
a94c689e6 net: dsa: Do not ... |
1250 1251 |
if (!netif_running(slave_dev)) return 0; |
97a69a0de net: dsa: Add sup... |
1252 1253 |
cancel_work_sync(&dp->xmit_work); skb_queue_purge(&dp->xmit_queue); |
f154be241 net: dsa: Bring b... |
1254 |
netif_device_detach(slave_dev); |
aab9c4067 net: dsa: Plug in... |
1255 1256 1257 |
rtnl_lock(); phylink_stop(dp->pl); rtnl_unlock(); |
244625491 net: dsa: allow s... |
1258 1259 1260 1261 1262 1263 |
return 0; } int dsa_slave_resume(struct net_device *slave_dev) { |
aab9c4067 net: dsa: Plug in... |
1264 |
struct dsa_port *dp = dsa_slave_to_port(slave_dev); |
a94c689e6 net: dsa: Do not ... |
1265 1266 |
if (!netif_running(slave_dev)) return 0; |
244625491 net: dsa: allow s... |
1267 |
netif_device_attach(slave_dev); |
aab9c4067 net: dsa: Plug in... |
1268 1269 1270 |
rtnl_lock(); phylink_start(dp->pl); rtnl_unlock(); |
244625491 net: dsa: allow s... |
1271 1272 1273 |
return 0; } |
6158eaa7a net: dsa: add sla... |
1274 1275 |
static void dsa_slave_notify(struct net_device *dev, unsigned long val) { |
d0006b002 net: dsa: add sla... |
1276 |
struct net_device *master = dsa_slave_to_master(dev); |
d945097bb net: dsa: add sla... |
1277 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
6158eaa7a net: dsa: add sla... |
1278 1279 1280 1281 1282 1283 1284 1285 1286 |
struct dsa_notifier_register_info rinfo = { .switch_number = dp->ds->index, .port_number = dp->index, .master = master, .info.dev = dev, }; call_dsa_notifiers(val, dev, &rinfo.info); } |
951259aa6 net: dsa: remove ... |
1287 |
int dsa_slave_create(struct dsa_port *port) |
91da11f87 net: Distributed ... |
1288 |
{ |
24a9332a5 net: dsa: constif... |
1289 |
const struct dsa_port *cpu_dp = port->cpu_dp; |
f8b8b1cd5 net: dsa: split d... |
1290 |
struct net_device *master = cpu_dp->master; |
4cfbf09cf net: dsa: remove ... |
1291 |
struct dsa_switch *ds = port->ds; |
951259aa6 net: dsa: remove ... |
1292 |
const char *name = port->name; |
91da11f87 net: Distributed ... |
1293 1294 1295 |
struct net_device *slave_dev; struct dsa_slave_priv *p; int ret; |
55199df6d net: dsa: Allow s... |
1296 1297 1298 1299 1300 1301 |
if (!ds->num_tx_queues) ds->num_tx_queues = 1; slave_dev = alloc_netdev_mqs(sizeof(struct dsa_slave_priv), name, NET_NAME_UNKNOWN, ether_setup, ds->num_tx_queues, 1); |
91da11f87 net: Distributed ... |
1302 |
if (slave_dev == NULL) |
d87d6f44d net: dsa: Ensure ... |
1303 |
return -ENOMEM; |
91da11f87 net: Distributed ... |
1304 |
|
9b236d2a6 net: dsa: Adverti... |
1305 1306 1307 |
slave_dev->features = master->vlan_features | NETIF_F_HW_TC; if (ds->ops->port_vlan_add && ds->ops->port_vlan_del) slave_dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; |
f50f21274 net: dsa: Add plu... |
1308 |
slave_dev->hw_features |= NETIF_F_HW_TC; |
7ad24ea4b net: get rid of S... |
1309 |
slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; |
4974f9b7e net: dsa: support... |
1310 |
if (!IS_ERR_OR_NULL(port->mac)) |
a2c7023f7 net: dsa: read ma... |
1311 1312 1313 |
ether_addr_copy(slave_dev->dev_addr, port->mac); else eth_hw_addr_inherit(slave_dev, master); |
0a5f107b6 net: dsa: convert... |
1314 |
slave_dev->priv_flags |= IFF_NO_QUEUE; |
3e8a72d1d net: dsa: reduce ... |
1315 |
slave_dev->netdev_ops = &dsa_slave_netdev_ops; |
8b1efc0f8 net: remove MTU l... |
1316 1317 |
slave_dev->min_mtu = 0; slave_dev->max_mtu = ETH_MAX_MTU; |
f37db85d0 net: dsa: Set a "... |
1318 |
SET_NETDEV_DEVTYPE(slave_dev, &dsa_type); |
d442ad4ab dsa: convert to n... |
1319 |
|
4cfbf09cf net: dsa: remove ... |
1320 1321 |
SET_NETDEV_DEV(slave_dev, port->ds->dev); slave_dev->dev.of_node = port->dn; |
5075314e4 dsa: Split ops up... |
1322 1323 1324 |
slave_dev->vlan_features = master->vlan_features; p = netdev_priv(slave_dev); |
5f6b4e14c net: dsa: User pe... |
1325 1326 1327 1328 1329 |
p->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!p->stats64) { free_netdev(slave_dev); return -ENOMEM; } |
4cfbf09cf net: dsa: remove ... |
1330 |
p->dp = port; |
f50f21274 net: dsa: Add plu... |
1331 |
INIT_LIST_HEAD(&p->mall_tc_list); |
97a69a0de net: dsa: Add sup... |
1332 1333 |
INIT_WORK(&port->xmit_work, dsa_port_xmit_work); skb_queue_head_init(&port->xmit_queue); |
152402483 net: dsa: add tag... |
1334 |
p->xmit = cpu_dp->tag_ops->xmit; |
f8b8b1cd5 net: dsa: split d... |
1335 |
port->slave = slave_dev; |
91da11f87 net: Distributed ... |
1336 1337 |
netif_carrier_off(slave_dev); |
4fa7b7188 net: dsa: better ... |
1338 |
ret = dsa_slave_phy_setup(slave_dev); |
0071f56e4 dsa: Register net... |
1339 1340 1341 |
if (ret) { netdev_err(master, "error %d setting up slave phy ", ret); |
e804441cf net: dsa: Fix net... |
1342 1343 |
goto out_free; } |
6158eaa7a net: dsa: add sla... |
1344 |
dsa_slave_notify(slave_dev, DSA_PORT_REGISTER); |
60724d4ba net: dsa: Add sup... |
1345 |
|
e804441cf net: dsa: Fix net... |
1346 1347 1348 1349 1350 1351 |
ret = register_netdev(slave_dev); if (ret) { netdev_err(master, "error %d registering interface %s ", ret, slave_dev->name); goto out_phy; |
0071f56e4 dsa: Register net... |
1352 |
} |
d87d6f44d net: dsa: Ensure ... |
1353 |
return 0; |
e804441cf net: dsa: Fix net... |
1354 1355 |
out_phy: |
aab9c4067 net: dsa: Plug in... |
1356 1357 1358 1359 |
rtnl_lock(); phylink_disconnect_phy(p->dp->pl); rtnl_unlock(); phylink_destroy(p->dp->pl); |
e804441cf net: dsa: Fix net... |
1360 1361 1362 |
out_free: free_percpu(p->stats64); free_netdev(slave_dev); |
f8b8b1cd5 net: dsa: split d... |
1363 |
port->slave = NULL; |
e804441cf net: dsa: Fix net... |
1364 |
return ret; |
91da11f87 net: Distributed ... |
1365 |
} |
b73adef67 net: dsa: integra... |
1366 |
|
cda5c15b2 net: dsa: move ds... |
1367 1368 |
void dsa_slave_destroy(struct net_device *slave_dev) { |
d945097bb net: dsa: add sla... |
1369 |
struct dsa_port *dp = dsa_slave_to_port(slave_dev); |
cda5c15b2 net: dsa: move ds... |
1370 1371 1372 |
struct dsa_slave_priv *p = netdev_priv(slave_dev); netif_carrier_off(slave_dev); |
aab9c4067 net: dsa: Plug in... |
1373 1374 1375 |
rtnl_lock(); phylink_disconnect_phy(dp->pl); rtnl_unlock(); |
881eadabe net: dsa: slave: ... |
1376 |
|
6158eaa7a net: dsa: add sla... |
1377 |
dsa_slave_notify(slave_dev, DSA_PORT_UNREGISTER); |
cda5c15b2 net: dsa: move ds... |
1378 |
unregister_netdev(slave_dev); |
aab9c4067 net: dsa: Plug in... |
1379 |
phylink_destroy(dp->pl); |
5f6b4e14c net: dsa: User pe... |
1380 |
free_percpu(p->stats64); |
cda5c15b2 net: dsa: move ds... |
1381 1382 |
free_netdev(slave_dev); } |
f3b78049d net: dsa: make ds... |
1383 |
static bool dsa_slave_dev_check(const struct net_device *dev) |
b73adef67 net: dsa: integra... |
1384 1385 1386 |
{ return dev->netdev_ops == &dsa_slave_netdev_ops; } |
8e92ab3a4 net: dsa: simplif... |
1387 1388 |
static int dsa_slave_changeupper(struct net_device *dev, struct netdev_notifier_changeupper_info *info) |
b73adef67 net: dsa: integra... |
1389 |
{ |
d945097bb net: dsa: add sla... |
1390 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
8e92ab3a4 net: dsa: simplif... |
1391 |
int err = NOTIFY_DONE; |
b73adef67 net: dsa: integra... |
1392 |
|
8e92ab3a4 net: dsa: simplif... |
1393 1394 |
if (netif_is_bridge_master(info->upper_dev)) { if (info->linking) { |
17d7802b7 net: dsa: change ... |
1395 |
err = dsa_port_bridge_join(dp, info->upper_dev); |
8e92ab3a4 net: dsa: simplif... |
1396 1397 |
err = notifier_from_errno(err); } else { |
17d7802b7 net: dsa: change ... |
1398 |
dsa_port_bridge_leave(dp, info->upper_dev); |
8e92ab3a4 net: dsa: simplif... |
1399 |
err = NOTIFY_OK; |
6debb68a2 net: dsa: refine ... |
1400 |
} |
6debb68a2 net: dsa: refine ... |
1401 |
} |
b73adef67 net: dsa: integra... |
1402 |
|
8e92ab3a4 net: dsa: simplif... |
1403 |
return err; |
6debb68a2 net: dsa: refine ... |
1404 |
} |
b73adef67 net: dsa: integra... |
1405 |
|
cc1d5bda1 net: dsa: Deny en... |
1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 |
static int dsa_slave_upper_vlan_check(struct net_device *dev, struct netdev_notifier_changeupper_info * info) { struct netlink_ext_ack *ext_ack; struct net_device *slave; struct dsa_port *dp; ext_ack = netdev_notifier_info_to_extack(&info->info); if (!is_vlan_dev(dev)) return NOTIFY_DONE; slave = vlan_dev_real_dev(dev); if (!dsa_slave_dev_check(slave)) return NOTIFY_DONE; dp = dsa_slave_to_port(slave); if (!dp->bridge_dev) return NOTIFY_DONE; /* Deny enslaving a VLAN device into a VLAN-aware bridge */ if (br_vlan_enabled(dp->bridge_dev) && netif_is_bridge_master(info->upper_dev) && info->linking) { NL_SET_ERR_MSG_MOD(ext_ack, "Cannot enslave VLAN device into VLAN aware bridge"); return notifier_from_errno(-EINVAL); } return NOTIFY_DONE; } |
88e4f0ca4 net: dsa: move ne... |
1437 1438 |
static int dsa_slave_netdevice_event(struct notifier_block *nb, unsigned long event, void *ptr) |
6debb68a2 net: dsa: refine ... |
1439 1440 |
{ struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
cc1d5bda1 net: dsa: Deny en... |
1441 1442 1443 |
if (event == NETDEV_CHANGEUPPER) { if (!dsa_slave_dev_check(dev)) return dsa_slave_upper_vlan_check(dev, ptr); |
8e92ab3a4 net: dsa: simplif... |
1444 |
|
8e92ab3a4 net: dsa: simplif... |
1445 |
return dsa_slave_changeupper(dev, ptr); |
cc1d5bda1 net: dsa: Deny en... |
1446 |
} |
b73adef67 net: dsa: integra... |
1447 |
|
b73adef67 net: dsa: integra... |
1448 1449 |
return NOTIFY_DONE; } |
88e4f0ca4 net: dsa: move ne... |
1450 |
|
c9eb3e0f8 net: dsa: Add sup... |
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 |
struct dsa_switchdev_event_work { struct work_struct work; struct switchdev_notifier_fdb_info fdb_info; struct net_device *dev; unsigned long event; }; static void dsa_slave_switchdev_event_work(struct work_struct *work) { struct dsa_switchdev_event_work *switchdev_work = container_of(work, struct dsa_switchdev_event_work, work); struct net_device *dev = switchdev_work->dev; struct switchdev_notifier_fdb_info *fdb_info; |
d945097bb net: dsa: add sla... |
1464 |
struct dsa_port *dp = dsa_slave_to_port(dev); |
c9eb3e0f8 net: dsa: Add sup... |
1465 1466 1467 1468 1469 1470 |
int err; rtnl_lock(); switch (switchdev_work->event) { case SWITCHDEV_FDB_ADD_TO_DEVICE: fdb_info = &switchdev_work->fdb_info; |
a37fb855f net: dsa: fix add... |
1471 1472 |
if (!fdb_info->added_by_user) break; |
d945097bb net: dsa: add sla... |
1473 |
err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid); |
c9eb3e0f8 net: dsa: Add sup... |
1474 1475 1476 1477 1478 |
if (err) { netdev_dbg(dev, "fdb add failed err=%d ", err); break; } |
e9ba0fbc7 bridge: switchdev... |
1479 |
fdb_info->offloaded = true; |
c9eb3e0f8 net: dsa: Add sup... |
1480 |
call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev, |
6685987c2 switchdev: Add ex... |
1481 |
&fdb_info->info, NULL); |
c9eb3e0f8 net: dsa: Add sup... |
1482 1483 1484 1485 |
break; case SWITCHDEV_FDB_DEL_TO_DEVICE: fdb_info = &switchdev_work->fdb_info; |
a37fb855f net: dsa: fix add... |
1486 1487 |
if (!fdb_info->added_by_user) break; |
d945097bb net: dsa: add sla... |
1488 |
err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid); |
c9eb3e0f8 net: dsa: Add sup... |
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 |
if (err) { netdev_dbg(dev, "fdb del failed err=%d ", err); dev_close(dev); } break; } rtnl_unlock(); kfree(switchdev_work->fdb_info.addr); kfree(switchdev_work); dev_put(dev); } static int dsa_slave_switchdev_fdb_work_init(struct dsa_switchdev_event_work * switchdev_work, const struct switchdev_notifier_fdb_info * fdb_info) { memcpy(&switchdev_work->fdb_info, fdb_info, sizeof(switchdev_work->fdb_info)); switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); if (!switchdev_work->fdb_info.addr) return -ENOMEM; ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, fdb_info->addr); return 0; } /* Called under rcu_read_lock() */ static int dsa_slave_switchdev_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = switchdev_notifier_info_to_dev(ptr); struct dsa_switchdev_event_work *switchdev_work; |
79b139f4b net: dsa: use swi... |
1525 1526 1527 1528 1529 1530 1531 1532 |
int err; if (event == SWITCHDEV_PORT_ATTR_SET) { err = switchdev_handle_port_attr_set(dev, ptr, dsa_slave_dev_check, dsa_slave_port_attr_set); return notifier_from_errno(err); } |
c9eb3e0f8 net: dsa: Add sup... |
1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 |
if (!dsa_slave_dev_check(dev)) return NOTIFY_DONE; switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); if (!switchdev_work) return NOTIFY_BAD; INIT_WORK(&switchdev_work->work, dsa_slave_switchdev_event_work); switchdev_work->dev = dev; switchdev_work->event = event; switch (event) { case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */ case SWITCHDEV_FDB_DEL_TO_DEVICE: |
a37fb855f net: dsa: fix add... |
1549 |
if (dsa_slave_switchdev_fdb_work_init(switchdev_work, ptr)) |
c9eb3e0f8 net: dsa: Add sup... |
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 |
goto err_fdb_work_init; dev_hold(dev); break; default: kfree(switchdev_work); return NOTIFY_DONE; } dsa_schedule_work(&switchdev_work->work); return NOTIFY_OK; err_fdb_work_init: kfree(switchdev_work); return NOTIFY_BAD; } |
2b239f678 net: dsa: slave: ... |
1565 1566 1567 1568 |
static int dsa_slave_switchdev_blocking_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = switchdev_notifier_info_to_dev(ptr); |
79b139f4b net: dsa: use swi... |
1569 |
int err; |
2b239f678 net: dsa: slave: ... |
1570 1571 |
switch (event) { |
79b139f4b net: dsa: use swi... |
1572 1573 1574 1575 1576 |
case SWITCHDEV_PORT_OBJ_ADD: err = switchdev_handle_port_obj_add(dev, ptr, dsa_slave_dev_check, dsa_slave_port_obj_add); return notifier_from_errno(err); |
2b239f678 net: dsa: slave: ... |
1577 |
case SWITCHDEV_PORT_OBJ_DEL: |
79b139f4b net: dsa: use swi... |
1578 1579 1580 1581 |
err = switchdev_handle_port_obj_del(dev, ptr, dsa_slave_dev_check, dsa_slave_port_obj_del); return notifier_from_errno(err); |
9ed1eced2 net: dsa: Handle ... |
1582 |
case SWITCHDEV_PORT_ATTR_SET: |
79b139f4b net: dsa: use swi... |
1583 1584 1585 1586 |
err = switchdev_handle_port_attr_set(dev, ptr, dsa_slave_dev_check, dsa_slave_port_attr_set); return notifier_from_errno(err); |
2b239f678 net: dsa: slave: ... |
1587 1588 1589 1590 |
} return NOTIFY_DONE; } |
88e4f0ca4 net: dsa: move ne... |
1591 |
static struct notifier_block dsa_slave_nb __read_mostly = { |
c9eb3e0f8 net: dsa: Add sup... |
1592 1593 1594 1595 1596 |
.notifier_call = dsa_slave_netdevice_event, }; static struct notifier_block dsa_slave_switchdev_notifier = { .notifier_call = dsa_slave_switchdev_event, |
88e4f0ca4 net: dsa: move ne... |
1597 |
}; |
2b239f678 net: dsa: slave: ... |
1598 1599 1600 |
static struct notifier_block dsa_slave_switchdev_blocking_notifier = { .notifier_call = dsa_slave_switchdev_blocking_event, }; |
88e4f0ca4 net: dsa: move ne... |
1601 1602 |
int dsa_slave_register_notifier(void) { |
2b239f678 net: dsa: slave: ... |
1603 |
struct notifier_block *nb; |
c9eb3e0f8 net: dsa: Add sup... |
1604 1605 1606 1607 1608 1609 1610 1611 1612 |
int err; err = register_netdevice_notifier(&dsa_slave_nb); if (err) return err; err = register_switchdev_notifier(&dsa_slave_switchdev_notifier); if (err) goto err_switchdev_nb; |
2b239f678 net: dsa: slave: ... |
1613 1614 1615 1616 |
nb = &dsa_slave_switchdev_blocking_notifier; err = register_switchdev_blocking_notifier(nb); if (err) goto err_switchdev_blocking_nb; |
c9eb3e0f8 net: dsa: Add sup... |
1617 |
return 0; |
2b239f678 net: dsa: slave: ... |
1618 1619 |
err_switchdev_blocking_nb: unregister_switchdev_notifier(&dsa_slave_switchdev_notifier); |
c9eb3e0f8 net: dsa: Add sup... |
1620 1621 1622 |
err_switchdev_nb: unregister_netdevice_notifier(&dsa_slave_nb); return err; |
88e4f0ca4 net: dsa: move ne... |
1623 1624 1625 1626 |
} void dsa_slave_unregister_notifier(void) { |
2b239f678 net: dsa: slave: ... |
1627 |
struct notifier_block *nb; |
88e4f0ca4 net: dsa: move ne... |
1628 |
int err; |
2b239f678 net: dsa: slave: ... |
1629 1630 1631 1632 1633 |
nb = &dsa_slave_switchdev_blocking_notifier; err = unregister_switchdev_blocking_notifier(nb); if (err) pr_err("DSA: failed to unregister switchdev blocking notifier (%d) ", err); |
c9eb3e0f8 net: dsa: Add sup... |
1634 1635 1636 1637 |
err = unregister_switchdev_notifier(&dsa_slave_switchdev_notifier); if (err) pr_err("DSA: failed to unregister switchdev notifier (%d) ", err); |
88e4f0ca4 net: dsa: move ne... |
1638 1639 1640 1641 1642 |
err = unregister_netdevice_notifier(&dsa_slave_nb); if (err) pr_err("DSA: failed to unregister slave notifier (%d) ", err); } |