Blame view
net/dsa/slave.c
33 KB
91da11f87 net: Distributed ... |
1 2 |
/* * net/dsa/slave.c - Slave device handling |
e84665c9c dsa: add switch c... |
3 |
* Copyright (c) 2008-2009 Marvell Semiconductor |
91da11f87 net: Distributed ... |
4 5 6 7 8 9 10 11 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include <linux/list.h> |
df02c6ff2 dsa: fix master i... |
12 |
#include <linux/etherdevice.h> |
b73adef67 net: dsa: integra... |
13 |
#include <linux/netdevice.h> |
91da11f87 net: Distributed ... |
14 |
#include <linux/phy.h> |
a28205437 net: dsa: add inc... |
15 |
#include <linux/phy_fixed.h> |
0d8bcdd38 net: dsa: allow f... |
16 17 |
#include <linux/of_net.h> #include <linux/of_mdio.h> |
7f854420f phy: Add API for ... |
18 |
#include <linux/mdio.h> |
b73adef67 net: dsa: integra... |
19 |
#include <net/rtnetlink.h> |
98237d433 switchdev: use ne... |
20 |
#include <net/switchdev.h> |
b73adef67 net: dsa: integra... |
21 |
#include <linux/if_bridge.h> |
04ff53f96 net: dsa: Add net... |
22 |
#include <linux/netpoll.h> |
91da11f87 net: Distributed ... |
23 24 25 26 27 28 |
#include "dsa_priv.h" /* 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... |
29 |
if (ds->phys_mii_mask & (1 << addr)) |
9d490b4ee net: dsa: rename ... |
30 |
return ds->ops->phy_read(ds, addr, reg); |
91da11f87 net: Distributed ... |
31 32 33 34 35 36 37 |
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... |
38 |
if (ds->phys_mii_mask & (1 << addr)) |
9d490b4ee net: dsa: rename ... |
39 |
return ds->ops->phy_write(ds, addr, reg, val); |
91da11f87 net: Distributed ... |
40 41 42 43 44 45 46 47 48 49 |
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... |
50 51 |
snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d", ds->dst->tree, ds->index); |
c33063d6a dsa: Remove maste... |
52 |
ds->slave_mii_bus->parent = ds->dev; |
24df8986f net: dsa: set sla... |
53 |
ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; |
91da11f87 net: Distributed ... |
54 55 56 57 |
} /* slave device handling ****************************************************/ |
abd2be00d dsa: implement nd... |
58 |
static int dsa_slave_get_iflink(const struct net_device *dev) |
c08408015 dsa: set ->iflink... |
59 60 |
{ struct dsa_slave_priv *p = netdev_priv(dev); |
c08408015 dsa: set ->iflink... |
61 |
|
abd2be00d dsa: implement nd... |
62 |
return p->parent->dst->master_netdev->ifindex; |
c08408015 dsa: set ->iflink... |
63 |
} |
b73adef67 net: dsa: integra... |
64 65 66 67 |
static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p) { return !!p->bridge_dev; } |
4acfee814 net: dsa: add por... |
68 69 |
static void dsa_port_set_stp_state(struct dsa_switch *ds, int port, u8 state) { |
732f794c1 net: dsa: add por... |
70 |
struct dsa_port *dp = &ds->ports[port]; |
4acfee814 net: dsa: add por... |
71 72 |
if (ds->ops->port_stp_state_set) ds->ops->port_stp_state_set(ds, port, state); |
732f794c1 net: dsa: add por... |
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
if (ds->ops->port_fast_age) { /* Fast age FDB entries or flush appropriate forwarding database * for the given port, if we are moving it from Learning or * Forwarding state, to Disabled or Blocking or Listening state. */ if ((dp->stp_state == BR_STATE_LEARNING || dp->stp_state == BR_STATE_FORWARDING) && (state == BR_STATE_DISABLED || state == BR_STATE_BLOCKING || state == BR_STATE_LISTENING)) ds->ops->port_fast_age(ds, port); } dp->stp_state = state; |
4acfee814 net: dsa: add por... |
89 |
} |
91da11f87 net: Distributed ... |
90 91 |
static int dsa_slave_open(struct net_device *dev) { |
df02c6ff2 dsa: fix master i... |
92 |
struct dsa_slave_priv *p = netdev_priv(dev); |
e84665c9c dsa: add switch c... |
93 |
struct net_device *master = p->parent->dst->master_netdev; |
b2f2af21e net: dsa: allow e... |
94 |
struct dsa_switch *ds = p->parent; |
b73adef67 net: dsa: integra... |
95 96 |
u8 stp_state = dsa_port_is_bridged(p) ? BR_STATE_BLOCKING : BR_STATE_FORWARDING; |
df02c6ff2 dsa: fix master i... |
97 98 99 100 |
int err; if (!(master->flags & IFF_UP)) return -ENETDOWN; |
8feedbb4a dsa: Convert comp... |
101 |
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) { |
a748ee242 net: move address... |
102 |
err = dev_uc_add(master, dev->dev_addr); |
df02c6ff2 dsa: fix master i... |
103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
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; } |
9d490b4ee net: dsa: rename ... |
117 118 |
if (ds->ops->port_enable) { err = ds->ops->port_enable(ds, p->port, p->phy); |
b2f2af21e net: dsa: allow e... |
119 120 121 |
if (err) goto clear_promisc; } |
4acfee814 net: dsa: add por... |
122 |
dsa_port_set_stp_state(ds, p->port, stp_state); |
b73adef67 net: dsa: integra... |
123 |
|
f7f1de51e net: dsa: start a... |
124 125 |
if (p->phy) phy_start(p->phy); |
91da11f87 net: Distributed ... |
126 |
return 0; |
df02c6ff2 dsa: fix master i... |
127 |
|
b2f2af21e net: dsa: allow e... |
128 129 |
clear_promisc: if (dev->flags & IFF_PROMISC) |
4fdeddfe0 dsa: fix promiscu... |
130 |
dev_set_promiscuity(master, -1); |
df02c6ff2 dsa: fix master i... |
131 132 133 134 |
clear_allmulti: if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(master, -1); del_unicast: |
8feedbb4a dsa: Convert comp... |
135 |
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) |
a748ee242 net: move address... |
136 |
dev_uc_del(master, dev->dev_addr); |
df02c6ff2 dsa: fix master i... |
137 138 |
out: return err; |
91da11f87 net: Distributed ... |
139 140 141 142 |
} static int dsa_slave_close(struct net_device *dev) { |
df02c6ff2 dsa: fix master i... |
143 |
struct dsa_slave_priv *p = netdev_priv(dev); |
e84665c9c dsa: add switch c... |
144 |
struct net_device *master = p->parent->dst->master_netdev; |
b2f2af21e net: dsa: allow e... |
145 |
struct dsa_switch *ds = p->parent; |
df02c6ff2 dsa: fix master i... |
146 |
|
f7f1de51e net: dsa: start a... |
147 148 |
if (p->phy) phy_stop(p->phy); |
df02c6ff2 dsa: fix master i... |
149 |
dev_mc_unsync(master, dev); |
a748ee242 net: move address... |
150 |
dev_uc_unsync(master, dev); |
df02c6ff2 dsa: fix master i... |
151 152 153 154 |
if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(master, -1); if (dev->flags & IFF_PROMISC) dev_set_promiscuity(master, -1); |
8feedbb4a dsa: Convert comp... |
155 |
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) |
a748ee242 net: move address... |
156 |
dev_uc_del(master, dev->dev_addr); |
df02c6ff2 dsa: fix master i... |
157 |
|
9d490b4ee net: dsa: rename ... |
158 159 |
if (ds->ops->port_disable) ds->ops->port_disable(ds, p->port, p->phy); |
b2f2af21e net: dsa: allow e... |
160 |
|
4acfee814 net: dsa: add por... |
161 |
dsa_port_set_stp_state(ds, p->port, BR_STATE_DISABLED); |
b73adef67 net: dsa: integra... |
162 |
|
91da11f87 net: Distributed ... |
163 164 165 166 167 168 |
return 0; } static void dsa_slave_change_rx_flags(struct net_device *dev, int change) { struct dsa_slave_priv *p = netdev_priv(dev); |
e84665c9c dsa: add switch c... |
169 |
struct net_device *master = p->parent->dst->master_netdev; |
91da11f87 net: Distributed ... |
170 171 172 173 174 175 176 177 178 179 |
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); } static void dsa_slave_set_rx_mode(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); |
e84665c9c dsa: add switch c... |
180 |
struct net_device *master = p->parent->dst->master_netdev; |
91da11f87 net: Distributed ... |
181 182 |
dev_mc_sync(master, dev); |
a748ee242 net: move address... |
183 |
dev_uc_sync(master, dev); |
91da11f87 net: Distributed ... |
184 |
} |
df02c6ff2 dsa: fix master i... |
185 |
static int dsa_slave_set_mac_address(struct net_device *dev, void *a) |
91da11f87 net: Distributed ... |
186 |
{ |
df02c6ff2 dsa: fix master i... |
187 |
struct dsa_slave_priv *p = netdev_priv(dev); |
e84665c9c dsa: add switch c... |
188 |
struct net_device *master = p->parent->dst->master_netdev; |
df02c6ff2 dsa: fix master i... |
189 190 191 192 193 194 195 196 |
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... |
197 |
if (!ether_addr_equal(addr->sa_data, master->dev_addr)) { |
a748ee242 net: move address... |
198 |
err = dev_uc_add(master, addr->sa_data); |
df02c6ff2 dsa: fix master i... |
199 200 201 |
if (err < 0) return err; } |
8feedbb4a dsa: Convert comp... |
202 |
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) |
a748ee242 net: move address... |
203 |
dev_uc_del(master, dev->dev_addr); |
df02c6ff2 dsa: fix master i... |
204 205 |
out: |
d08f161a1 dsa: Use ether_ad... |
206 |
ether_addr_copy(dev->dev_addr, addr->sa_data); |
91da11f87 net: Distributed ... |
207 208 209 |
return 0; } |
111495361 net: dsa: add sup... |
210 |
static int dsa_slave_port_vlan_add(struct net_device *dev, |
8f24f3095 switchdev: rename... |
211 |
const struct switchdev_obj_port_vlan *vlan, |
f8db83486 switchdev: move t... |
212 |
struct switchdev_trans *trans) |
111495361 net: dsa: add sup... |
213 |
{ |
111495361 net: dsa: add sup... |
214 215 |
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
111495361 net: dsa: add sup... |
216 |
|
79a62eb22 dsa: use prepare/... |
217 |
if (switchdev_trans_ph_prepare(trans)) { |
9d490b4ee net: dsa: rename ... |
218 |
if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add) |
111495361 net: dsa: add sup... |
219 |
return -EOPNOTSUPP; |
9d490b4ee net: dsa: rename ... |
220 |
return ds->ops->port_vlan_prepare(ds, p->port, vlan, trans); |
111495361 net: dsa: add sup... |
221 |
} |
9d490b4ee net: dsa: rename ... |
222 |
ds->ops->port_vlan_add(ds, p->port, vlan, trans); |
4d5770b39 net: dsa: make th... |
223 |
|
111495361 net: dsa: add sup... |
224 225 226 227 |
return 0; } static int dsa_slave_port_vlan_del(struct net_device *dev, |
8f24f3095 switchdev: rename... |
228 |
const struct switchdev_obj_port_vlan *vlan) |
111495361 net: dsa: add sup... |
229 |
{ |
111495361 net: dsa: add sup... |
230 231 |
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
111495361 net: dsa: add sup... |
232 |
|
9d490b4ee net: dsa: rename ... |
233 |
if (!ds->ops->port_vlan_del) |
111495361 net: dsa: add sup... |
234 |
return -EOPNOTSUPP; |
9d490b4ee net: dsa: rename ... |
235 |
return ds->ops->port_vlan_del(ds, p->port, vlan); |
111495361 net: dsa: add sup... |
236 237 238 |
} static int dsa_slave_port_vlan_dump(struct net_device *dev, |
8f24f3095 switchdev: rename... |
239 |
struct switchdev_obj_port_vlan *vlan, |
648b4a995 switchdev: bring ... |
240 |
switchdev_obj_dump_cb_t *cb) |
111495361 net: dsa: add sup... |
241 |
{ |
111495361 net: dsa: add sup... |
242 243 |
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
111495361 net: dsa: add sup... |
244 |
|
9d490b4ee net: dsa: rename ... |
245 246 |
if (ds->ops->port_vlan_dump) return ds->ops->port_vlan_dump(ds, p->port, vlan, cb); |
65aebfc00 net: dsa: add por... |
247 |
|
477b18452 net: dsa: drop vl... |
248 |
return -EOPNOTSUPP; |
111495361 net: dsa: add sup... |
249 |
} |
ba14d9eb1 net: dsa: add sup... |
250 |
static int dsa_slave_port_fdb_add(struct net_device *dev, |
52ba57cfd switchdev: rename... |
251 |
const struct switchdev_obj_port_fdb *fdb, |
f8db83486 switchdev: move t... |
252 |
struct switchdev_trans *trans) |
cdf096976 Revert "Merge bra... |
253 254 255 |
{ struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
146a32067 net: dsa: add por... |
256 |
|
8497aa618 net: dsa: make th... |
257 |
if (switchdev_trans_ph_prepare(trans)) { |
9d490b4ee net: dsa: rename ... |
258 |
if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add) |
8497aa618 net: dsa: make th... |
259 |
return -EOPNOTSUPP; |
cdf096976 Revert "Merge bra... |
260 |
|
9d490b4ee net: dsa: rename ... |
261 |
return ds->ops->port_fdb_prepare(ds, p->port, fdb, trans); |
8497aa618 net: dsa: make th... |
262 |
} |
9d490b4ee net: dsa: rename ... |
263 |
ds->ops->port_fdb_add(ds, p->port, fdb, trans); |
cdf096976 Revert "Merge bra... |
264 |
|
8497aa618 net: dsa: make th... |
265 |
return 0; |
cdf096976 Revert "Merge bra... |
266 |
} |
ba14d9eb1 net: dsa: add sup... |
267 |
static int dsa_slave_port_fdb_del(struct net_device *dev, |
52ba57cfd switchdev: rename... |
268 |
const struct switchdev_obj_port_fdb *fdb) |
cdf096976 Revert "Merge bra... |
269 270 271 272 |
{ struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; int ret = -EOPNOTSUPP; |
9d490b4ee net: dsa: rename ... |
273 274 |
if (ds->ops->port_fdb_del) ret = ds->ops->port_fdb_del(ds, p->port, fdb); |
cdf096976 Revert "Merge bra... |
275 276 277 |
return ret; } |
ba14d9eb1 net: dsa: add sup... |
278 |
static int dsa_slave_port_fdb_dump(struct net_device *dev, |
52ba57cfd switchdev: rename... |
279 |
struct switchdev_obj_port_fdb *fdb, |
648b4a995 switchdev: bring ... |
280 |
switchdev_obj_dump_cb_t *cb) |
cdf096976 Revert "Merge bra... |
281 282 283 |
{ struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
cdf096976 Revert "Merge bra... |
284 |
|
9d490b4ee net: dsa: rename ... |
285 286 |
if (ds->ops->port_fdb_dump) return ds->ops->port_fdb_dump(ds, p->port, fdb, cb); |
ea70ba980 net: dsa: add por... |
287 |
|
1a49a2fbf net: dsa: remove ... |
288 |
return -EOPNOTSUPP; |
cdf096976 Revert "Merge bra... |
289 |
} |
8df302552 net: dsa: add MDB... |
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
static int dsa_slave_port_mdb_add(struct net_device *dev, const struct switchdev_obj_port_mdb *mdb, struct switchdev_trans *trans) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; if (switchdev_trans_ph_prepare(trans)) { if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add) return -EOPNOTSUPP; return ds->ops->port_mdb_prepare(ds, p->port, mdb, trans); } ds->ops->port_mdb_add(ds, p->port, mdb, trans); return 0; } static int dsa_slave_port_mdb_del(struct net_device *dev, const struct switchdev_obj_port_mdb *mdb) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; if (ds->ops->port_mdb_del) return ds->ops->port_mdb_del(ds, p->port, mdb); return -EOPNOTSUPP; } static int dsa_slave_port_mdb_dump(struct net_device *dev, struct switchdev_obj_port_mdb *mdb, switchdev_obj_dump_cb_t *cb) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; if (ds->ops->port_mdb_dump) return ds->ops->port_mdb_dump(ds, p->port, mdb, cb); return -EOPNOTSUPP; } |
91da11f87 net: Distributed ... |
333 334 335 |
static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct dsa_slave_priv *p = netdev_priv(dev); |
91da11f87 net: Distributed ... |
336 337 |
if (p->phy != NULL) |
28b041139 net: preserve ifr... |
338 |
return phy_mii_ioctl(p->phy, ifr, cmd); |
91da11f87 net: Distributed ... |
339 340 341 |
return -EOPNOTSUPP; } |
43c44a9f6 net: dsa: make th... |
342 343 344 |
static int dsa_slave_stp_state_set(struct net_device *dev, const struct switchdev_attr *attr, struct switchdev_trans *trans) |
b73adef67 net: dsa: integra... |
345 346 347 |
{ struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
b73adef67 net: dsa: integra... |
348 |
|
43c44a9f6 net: dsa: make th... |
349 |
if (switchdev_trans_ph_prepare(trans)) |
9d490b4ee net: dsa: rename ... |
350 |
return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP; |
b73adef67 net: dsa: integra... |
351 |
|
4acfee814 net: dsa: add por... |
352 |
dsa_port_set_stp_state(ds, p->port, attr->u.stp_state); |
43c44a9f6 net: dsa: make th... |
353 354 |
return 0; |
b73adef67 net: dsa: integra... |
355 |
} |
fb2dabad6 net: dsa: support... |
356 357 358 359 360 361 362 363 364 365 |
static int dsa_slave_vlan_filtering(struct net_device *dev, const struct switchdev_attr *attr, struct switchdev_trans *trans) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; /* bridge skips -EOPNOTSUPP, so skip the prepare phase */ if (switchdev_trans_ph_prepare(trans)) return 0; |
9d490b4ee net: dsa: rename ... |
366 367 |
if (ds->ops->port_vlan_filtering) return ds->ops->port_vlan_filtering(ds, p->port, |
fb2dabad6 net: dsa: support... |
368 369 370 371 |
attr->u.vlan_filtering); return 0; } |
34a79f63b net: dsa: support... |
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
static int dsa_fastest_ageing_time(struct dsa_switch *ds, unsigned int ageing_time) { int i; for (i = 0; i < DSA_MAX_PORTS; ++i) { struct dsa_port *dp = &ds->ports[i]; if (dp && dp->ageing_time && dp->ageing_time < ageing_time) ageing_time = dp->ageing_time; } return ageing_time; } static int dsa_slave_ageing_time(struct net_device *dev, const struct switchdev_attr *attr, struct switchdev_trans *trans) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; unsigned long ageing_jiffies = clock_t_to_jiffies(attr->u.ageing_time); unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies); /* bridge skips -EOPNOTSUPP, so skip the prepare phase */ if (switchdev_trans_ph_prepare(trans)) return 0; /* Keep the fastest ageing time in case of multiple bridges */ ds->ports[p->port].ageing_time = ageing_time; ageing_time = dsa_fastest_ageing_time(ds, ageing_time); |
9d490b4ee net: dsa: rename ... |
403 404 |
if (ds->ops->set_ageing_time) return ds->ops->set_ageing_time(ds, ageing_time); |
34a79f63b net: dsa: support... |
405 406 407 |
return 0; } |
356360625 switchdev: conver... |
408 |
static int dsa_slave_port_attr_set(struct net_device *dev, |
f7fadf304 switchdev: make s... |
409 |
const struct switchdev_attr *attr, |
7ea6eb3f5 switchdev: introd... |
410 |
struct switchdev_trans *trans) |
356360625 switchdev: conver... |
411 |
{ |
b8d866ac6 net: dsa: fix pre... |
412 |
int ret; |
356360625 switchdev: conver... |
413 414 |
switch (attr->id) { |
1f8683987 switchdev: rename... |
415 |
case SWITCHDEV_ATTR_ID_PORT_STP_STATE: |
43c44a9f6 net: dsa: make th... |
416 |
ret = dsa_slave_stp_state_set(dev, attr, trans); |
356360625 switchdev: conver... |
417 |
break; |
fb2dabad6 net: dsa: support... |
418 419 420 |
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: ret = dsa_slave_vlan_filtering(dev, attr, trans); break; |
34a79f63b net: dsa: support... |
421 422 423 |
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: ret = dsa_slave_ageing_time(dev, attr, trans); break; |
356360625 switchdev: conver... |
424 425 426 427 428 429 430 |
default: ret = -EOPNOTSUPP; break; } return ret; } |
ba14d9eb1 net: dsa: add sup... |
431 |
static int dsa_slave_port_obj_add(struct net_device *dev, |
648b4a995 switchdev: bring ... |
432 |
const struct switchdev_obj *obj, |
7ea6eb3f5 switchdev: introd... |
433 |
struct switchdev_trans *trans) |
ba14d9eb1 net: dsa: add sup... |
434 435 436 437 438 439 440 |
{ 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... |
441 |
switch (obj->id) { |
57d80838d switchdev: rename... |
442 |
case SWITCHDEV_OBJ_ID_PORT_FDB: |
648b4a995 switchdev: bring ... |
443 444 445 |
err = dsa_slave_port_fdb_add(dev, SWITCHDEV_OBJ_PORT_FDB(obj), trans); |
ba14d9eb1 net: dsa: add sup... |
446 |
break; |
8df302552 net: dsa: add MDB... |
447 448 449 450 |
case SWITCHDEV_OBJ_ID_PORT_MDB: err = dsa_slave_port_mdb_add(dev, SWITCHDEV_OBJ_PORT_MDB(obj), trans); break; |
57d80838d switchdev: rename... |
451 |
case SWITCHDEV_OBJ_ID_PORT_VLAN: |
648b4a995 switchdev: bring ... |
452 453 454 |
err = dsa_slave_port_vlan_add(dev, SWITCHDEV_OBJ_PORT_VLAN(obj), trans); |
111495361 net: dsa: add sup... |
455 |
break; |
ba14d9eb1 net: dsa: add sup... |
456 457 458 459 460 461 462 463 464 |
default: err = -EOPNOTSUPP; break; } return err; } static int dsa_slave_port_obj_del(struct net_device *dev, |
648b4a995 switchdev: bring ... |
465 |
const struct switchdev_obj *obj) |
ba14d9eb1 net: dsa: add sup... |
466 467 |
{ int err; |
9e8f4a548 switchdev: push o... |
468 |
switch (obj->id) { |
57d80838d switchdev: rename... |
469 |
case SWITCHDEV_OBJ_ID_PORT_FDB: |
648b4a995 switchdev: bring ... |
470 471 |
err = dsa_slave_port_fdb_del(dev, SWITCHDEV_OBJ_PORT_FDB(obj)); |
ba14d9eb1 net: dsa: add sup... |
472 |
break; |
8df302552 net: dsa: add MDB... |
473 474 475 |
case SWITCHDEV_OBJ_ID_PORT_MDB: err = dsa_slave_port_mdb_del(dev, SWITCHDEV_OBJ_PORT_MDB(obj)); break; |
57d80838d switchdev: rename... |
476 |
case SWITCHDEV_OBJ_ID_PORT_VLAN: |
648b4a995 switchdev: bring ... |
477 478 |
err = dsa_slave_port_vlan_del(dev, SWITCHDEV_OBJ_PORT_VLAN(obj)); |
111495361 net: dsa: add sup... |
479 |
break; |
ba14d9eb1 net: dsa: add sup... |
480 481 482 483 484 485 486 487 488 |
default: err = -EOPNOTSUPP; break; } return err; } static int dsa_slave_port_obj_dump(struct net_device *dev, |
648b4a995 switchdev: bring ... |
489 490 |
struct switchdev_obj *obj, switchdev_obj_dump_cb_t *cb) |
ba14d9eb1 net: dsa: add sup... |
491 492 |
{ int err; |
9e8f4a548 switchdev: push o... |
493 |
switch (obj->id) { |
57d80838d switchdev: rename... |
494 |
case SWITCHDEV_OBJ_ID_PORT_FDB: |
648b4a995 switchdev: bring ... |
495 496 497 |
err = dsa_slave_port_fdb_dump(dev, SWITCHDEV_OBJ_PORT_FDB(obj), cb); |
ba14d9eb1 net: dsa: add sup... |
498 |
break; |
8df302552 net: dsa: add MDB... |
499 500 501 502 |
case SWITCHDEV_OBJ_ID_PORT_MDB: err = dsa_slave_port_mdb_dump(dev, SWITCHDEV_OBJ_PORT_MDB(obj), cb); break; |
57d80838d switchdev: rename... |
503 |
case SWITCHDEV_OBJ_ID_PORT_VLAN: |
648b4a995 switchdev: bring ... |
504 505 506 |
err = dsa_slave_port_vlan_dump(dev, SWITCHDEV_OBJ_PORT_VLAN(obj), cb); |
111495361 net: dsa: add sup... |
507 |
break; |
ba14d9eb1 net: dsa: add sup... |
508 509 510 511 512 513 514 |
default: err = -EOPNOTSUPP; break; } return err; } |
b73adef67 net: dsa: integra... |
515 516 517 518 519 520 521 522 |
static int dsa_slave_bridge_port_join(struct net_device *dev, struct net_device *br) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; int ret = -EOPNOTSUPP; p->bridge_dev = br; |
9d490b4ee net: dsa: rename ... |
523 524 |
if (ds->ops->port_bridge_join) ret = ds->ops->port_bridge_join(ds, p->port, br); |
b73adef67 net: dsa: integra... |
525 |
|
6debb68a2 net: dsa: refine ... |
526 |
return ret == -EOPNOTSUPP ? 0 : ret; |
b73adef67 net: dsa: integra... |
527 |
} |
16bfa7024 net: dsa: make po... |
528 |
static void dsa_slave_bridge_port_leave(struct net_device *dev) |
b73adef67 net: dsa: integra... |
529 530 531 |
{ struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
b73adef67 net: dsa: integra... |
532 |
|
9d490b4ee net: dsa: rename ... |
533 534 |
if (ds->ops->port_bridge_leave) ds->ops->port_bridge_leave(ds, p->port); |
b73adef67 net: dsa: integra... |
535 536 537 538 539 540 |
p->bridge_dev = NULL; /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, * so allow it to be in BR_STATE_FORWARDING to be kept functional */ |
4acfee814 net: dsa: add por... |
541 |
dsa_port_set_stp_state(ds, p->port, BR_STATE_FORWARDING); |
b73adef67 net: dsa: integra... |
542 |
} |
f8e20a9f8 switchdev: conver... |
543 544 |
static int dsa_slave_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) |
b73adef67 net: dsa: integra... |
545 546 547 |
{ struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
f8e20a9f8 switchdev: conver... |
548 |
switch (attr->id) { |
1f8683987 switchdev: rename... |
549 |
case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: |
42275bd8f switchdev: don't ... |
550 551 |
attr->u.ppid.id_len = sizeof(ds->index); memcpy(&attr->u.ppid.id, &ds->index, attr->u.ppid.id_len); |
f8e20a9f8 switchdev: conver... |
552 553 554 555 |
break; default: return -EOPNOTSUPP; } |
b73adef67 net: dsa: integra... |
556 557 558 |
return 0; } |
04ff53f96 net: dsa: Add net... |
559 560 561 562 563 564 565 566 567 568 569 |
static inline netdev_tx_t dsa_netpoll_send_skb(struct dsa_slave_priv *p, struct sk_buff *skb) { #ifdef CONFIG_NET_POLL_CONTROLLER if (p->netpoll) netpoll_send_skb(p->netpoll, skb); #else BUG(); #endif return NETDEV_TX_OK; } |
3e8a72d1d net: dsa: reduce ... |
570 571 572 |
static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); |
4ed70ce9f net: dsa: Refacto... |
573 |
struct sk_buff *nskb; |
3e8a72d1d net: dsa: reduce ... |
574 |
|
4ed70ce9f net: dsa: Refacto... |
575 576 |
dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; |
3e8a72d1d net: dsa: reduce ... |
577 |
|
4ed70ce9f net: dsa: Refacto... |
578 579 580 581 |
/* Transmit function may have to reallocate the original SKB */ nskb = p->xmit(skb, dev); if (!nskb) return NETDEV_TX_OK; |
5aed85cec net: dsa: allow s... |
582 |
|
04ff53f96 net: dsa: Add net... |
583 584 585 586 587 |
/* 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_netpoll_send_skb(p, nskb); |
4ed70ce9f net: dsa: Refacto... |
588 589 590 591 592 |
/* Queue the SKB for transmission on the parent interface, but * do not modify its EtherType */ nskb->dev = p->parent->dst->master_netdev; dev_queue_xmit(nskb); |
5aed85cec net: dsa: allow s... |
593 594 595 |
return NETDEV_TX_OK; } |
91da11f87 net: Distributed ... |
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
/* ethtool operations *******************************************************/ static int dsa_slave_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct dsa_slave_priv *p = netdev_priv(dev); int err; err = -EOPNOTSUPP; if (p->phy != NULL) { err = phy_read_status(p->phy); if (err == 0) err = phy_ethtool_gset(p->phy, cmd); } return err; } static int dsa_slave_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct dsa_slave_priv *p = netdev_priv(dev); if (p->phy != NULL) return phy_ethtool_sset(p->phy, cmd); return -EOPNOTSUPP; } static void dsa_slave_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { |
7826d43f2 ethtool: fix drvi... |
627 628 629 630 |
strlcpy(drvinfo->driver, "dsa", sizeof(drvinfo->driver)); strlcpy(drvinfo->version, dsa_driver_version, sizeof(drvinfo->version)); strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); strlcpy(drvinfo->bus_info, "platform", sizeof(drvinfo->bus_info)); |
91da11f87 net: Distributed ... |
631 |
} |
3d762a0f0 net: dsa: Add sup... |
632 633 634 635 |
static int dsa_slave_get_regs_len(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
9d490b4ee net: dsa: rename ... |
636 637 |
if (ds->ops->get_regs_len) return ds->ops->get_regs_len(ds, p->port); |
3d762a0f0 net: dsa: Add sup... |
638 639 640 641 642 643 644 645 646 |
return -EOPNOTSUPP; } static void dsa_slave_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
9d490b4ee net: dsa: rename ... |
647 648 |
if (ds->ops->get_regs) ds->ops->get_regs(ds, p->port, regs, _p); |
3d762a0f0 net: dsa: Add sup... |
649 |
} |
91da11f87 net: Distributed ... |
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 |
static int dsa_slave_nway_reset(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); if (p->phy != NULL) return genphy_restart_aneg(p->phy); return -EOPNOTSUPP; } static u32 dsa_slave_get_link(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); if (p->phy != NULL) { genphy_update_link(p->phy); return p->phy->link; } return -EOPNOTSUPP; } |
6793abb4e net: dsa: Add sup... |
671 672 673 674 |
static int dsa_slave_get_eeprom_len(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
0e5760440 net: dsa: slave: ... |
675 |
if (ds->cd && ds->cd->eeprom_len) |
ff04955c2 dsa: Rename switc... |
676 |
return ds->cd->eeprom_len; |
6793abb4e net: dsa: Add sup... |
677 |
|
9d490b4ee net: dsa: rename ... |
678 679 |
if (ds->ops->get_eeprom_len) return ds->ops->get_eeprom_len(ds); |
6793abb4e net: dsa: Add sup... |
680 681 682 683 684 685 686 687 688 |
return 0; } static int dsa_slave_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
9d490b4ee net: dsa: rename ... |
689 690 |
if (ds->ops->get_eeprom) return ds->ops->get_eeprom(ds, eeprom, data); |
6793abb4e net: dsa: Add sup... |
691 692 693 694 695 696 697 698 699 |
return -EOPNOTSUPP; } static int dsa_slave_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
9d490b4ee net: dsa: rename ... |
700 701 |
if (ds->ops->set_eeprom) return ds->ops->set_eeprom(ds, eeprom, data); |
6793abb4e net: dsa: Add sup... |
702 703 704 |
return -EOPNOTSUPP; } |
91da11f87 net: Distributed ... |
705 706 707 708 709 710 711 712 713 714 715 716 717 |
static void dsa_slave_get_strings(struct net_device *dev, uint32_t stringset, uint8_t *data) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; 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 ... |
718 719 |
if (ds->ops->get_strings) ds->ops->get_strings(ds, p->port, data + 4 * len); |
91da11f87 net: Distributed ... |
720 721 |
} } |
badf3ada6 net: dsa: Provide... |
722 723 724 725 726 727 728 729 730 731 732 733 734 735 |
static void dsa_cpu_port_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, uint64_t *data) { struct dsa_switch_tree *dst = dev->dsa_ptr; struct dsa_switch *ds = dst->ds[0]; s8 cpu_port = dst->cpu_port; int count = 0; if (dst->master_ethtool_ops.get_sset_count) { count = dst->master_ethtool_ops.get_sset_count(dev, ETH_SS_STATS); dst->master_ethtool_ops.get_ethtool_stats(dev, stats, data); } |
9d490b4ee net: dsa: rename ... |
736 737 |
if (ds->ops->get_ethtool_stats) ds->ops->get_ethtool_stats(ds, cpu_port, data + count); |
badf3ada6 net: dsa: Provide... |
738 739 740 741 742 743 744 745 746 747 |
} static int dsa_cpu_port_get_sset_count(struct net_device *dev, int sset) { struct dsa_switch_tree *dst = dev->dsa_ptr; struct dsa_switch *ds = dst->ds[0]; int count = 0; if (dst->master_ethtool_ops.get_sset_count) count += dst->master_ethtool_ops.get_sset_count(dev, sset); |
9d490b4ee net: dsa: rename ... |
748 749 |
if (sset == ETH_SS_STATS && ds->ops->get_sset_count) count += ds->ops->get_sset_count(ds); |
badf3ada6 net: dsa: Provide... |
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 |
return count; } static void dsa_cpu_port_get_strings(struct net_device *dev, uint32_t stringset, uint8_t *data) { struct dsa_switch_tree *dst = dev->dsa_ptr; struct dsa_switch *ds = dst->ds[0]; s8 cpu_port = dst->cpu_port; int len = ETH_GSTRING_LEN; int mcount = 0, count; unsigned int i; uint8_t pfx[4]; uint8_t *ndata; snprintf(pfx, sizeof(pfx), "p%.2d", cpu_port); /* We do not want to be NULL-terminated, since this is a prefix */ pfx[sizeof(pfx) - 1] = '_'; if (dst->master_ethtool_ops.get_sset_count) { mcount = dst->master_ethtool_ops.get_sset_count(dev, ETH_SS_STATS); dst->master_ethtool_ops.get_strings(dev, stringset, data); } |
9d490b4ee net: dsa: rename ... |
775 |
if (stringset == ETH_SS_STATS && ds->ops->get_strings) { |
badf3ada6 net: dsa: Provide... |
776 777 778 779 780 |
ndata = data + mcount * len; /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle * the output after to prepend our CPU port prefix we * constructed earlier */ |
9d490b4ee net: dsa: rename ... |
781 782 |
ds->ops->get_strings(ds, cpu_port, ndata); count = ds->ops->get_sset_count(ds); |
badf3ada6 net: dsa: Provide... |
783 784 785 786 787 788 789 |
for (i = 0; i < count; i++) { memmove(ndata + (i * len + sizeof(pfx)), ndata + i * len, len - sizeof(pfx)); memcpy(ndata + i * len, pfx, sizeof(pfx)); } } } |
91da11f87 net: Distributed ... |
790 791 792 793 794 795 |
static void dsa_slave_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, uint64_t *data) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
46e7b8d8d net: dsa: kill ci... |
796 797 798 799 |
data[0] = dev->stats.tx_packets; data[1] = dev->stats.tx_bytes; data[2] = dev->stats.rx_packets; data[3] = dev->stats.rx_bytes; |
9d490b4ee net: dsa: rename ... |
800 801 |
if (ds->ops->get_ethtool_stats) ds->ops->get_ethtool_stats(ds, p->port, data + 4); |
91da11f87 net: Distributed ... |
802 803 804 805 806 807 808 809 810 811 812 |
} static int dsa_slave_get_sset_count(struct net_device *dev, int sset) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; if (sset == ETH_SS_STATS) { int count; count = 4; |
9d490b4ee net: dsa: rename ... |
813 814 |
if (ds->ops->get_sset_count) count += ds->ops->get_sset_count(ds); |
91da11f87 net: Distributed ... |
815 816 817 818 819 820 |
return count; } return -EOPNOTSUPP; } |
19e57c4e6 net: dsa: add {ge... |
821 822 823 824 |
static void dsa_slave_get_wol(struct net_device *dev, struct ethtool_wolinfo *w) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; |
9d490b4ee net: dsa: rename ... |
825 826 |
if (ds->ops->get_wol) ds->ops->get_wol(ds, p->port, w); |
19e57c4e6 net: dsa: add {ge... |
827 828 829 830 831 832 833 |
} static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; int ret = -EOPNOTSUPP; |
9d490b4ee net: dsa: rename ... |
834 835 |
if (ds->ops->set_wol) ret = ds->ops->set_wol(ds, p->port, w); |
19e57c4e6 net: dsa: add {ge... |
836 837 838 |
return ret; } |
7905288f0 net: dsa: allow s... |
839 840 841 842 843 |
static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; int ret; |
9d490b4ee net: dsa: rename ... |
844 |
if (!ds->ops->set_eee) |
7905288f0 net: dsa: allow s... |
845 |
return -EOPNOTSUPP; |
9d490b4ee net: dsa: rename ... |
846 |
ret = ds->ops->set_eee(ds, p->port, p->phy, e); |
7905288f0 net: dsa: allow s... |
847 848 849 850 851 852 853 854 855 856 857 858 859 860 |
if (ret) return ret; if (p->phy) ret = phy_ethtool_set_eee(p->phy, e); return ret; } static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; int ret; |
9d490b4ee net: dsa: rename ... |
861 |
if (!ds->ops->get_eee) |
7905288f0 net: dsa: allow s... |
862 |
return -EOPNOTSUPP; |
9d490b4ee net: dsa: rename ... |
863 |
ret = ds->ops->get_eee(ds, p->port, e); |
7905288f0 net: dsa: allow s... |
864 865 866 867 868 869 870 871 |
if (ret) return ret; if (p->phy) ret = phy_ethtool_get_eee(p->phy, e); return ret; } |
04ff53f96 net: dsa: Add net... |
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 |
#ifdef CONFIG_NET_POLL_CONTROLLER static int dsa_slave_netpoll_setup(struct net_device *dev, struct netpoll_info *ni) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; struct net_device *master = ds->dst->master_netdev; 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; __netpoll_free_async(netpoll); } static void dsa_slave_poll_controller(struct net_device *dev) { } #endif |
af42192c4 net: dsa: Add ini... |
914 915 916 917 918 919 |
void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops) { ops->get_sset_count = dsa_cpu_port_get_sset_count; ops->get_ethtool_stats = dsa_cpu_port_get_ethtool_stats; ops->get_strings = dsa_cpu_port_get_strings; } |
91da11f87 net: Distributed ... |
920 921 922 923 |
static const struct ethtool_ops dsa_slave_ethtool_ops = { .get_settings = dsa_slave_get_settings, .set_settings = dsa_slave_set_settings, .get_drvinfo = dsa_slave_get_drvinfo, |
3d762a0f0 net: dsa: Add sup... |
924 925 |
.get_regs_len = dsa_slave_get_regs_len, .get_regs = dsa_slave_get_regs, |
91da11f87 net: Distributed ... |
926 927 |
.nway_reset = dsa_slave_nway_reset, .get_link = dsa_slave_get_link, |
6793abb4e net: dsa: Add sup... |
928 929 930 |
.get_eeprom_len = dsa_slave_get_eeprom_len, .get_eeprom = dsa_slave_get_eeprom, .set_eeprom = dsa_slave_set_eeprom, |
91da11f87 net: Distributed ... |
931 932 933 |
.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... |
934 935 |
.set_wol = dsa_slave_set_wol, .get_wol = dsa_slave_get_wol, |
7905288f0 net: dsa: allow s... |
936 937 |
.set_eee = dsa_slave_set_eee, .get_eee = dsa_slave_get_eee, |
91da11f87 net: Distributed ... |
938 |
}; |
3e8a72d1d net: dsa: reduce ... |
939 |
static const struct net_device_ops dsa_slave_netdev_ops = { |
d442ad4ab dsa: convert to n... |
940 941 |
.ndo_open = dsa_slave_open, .ndo_stop = dsa_slave_close, |
3e8a72d1d net: dsa: reduce ... |
942 |
.ndo_start_xmit = dsa_slave_xmit, |
d442ad4ab dsa: convert to n... |
943 944 |
.ndo_change_rx_flags = dsa_slave_change_rx_flags, .ndo_set_rx_mode = dsa_slave_set_rx_mode, |
d442ad4ab dsa: convert to n... |
945 |
.ndo_set_mac_address = dsa_slave_set_mac_address, |
ba14d9eb1 net: dsa: add sup... |
946 947 948 |
.ndo_fdb_add = switchdev_port_fdb_add, .ndo_fdb_del = switchdev_port_fdb_del, .ndo_fdb_dump = switchdev_port_fdb_dump, |
d442ad4ab dsa: convert to n... |
949 |
.ndo_do_ioctl = dsa_slave_ioctl, |
abd2be00d dsa: implement nd... |
950 |
.ndo_get_iflink = dsa_slave_get_iflink, |
04ff53f96 net: dsa: Add net... |
951 952 953 954 955 |
#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 |
111495361 net: dsa: add sup... |
956 957 958 |
.ndo_bridge_getlink = switchdev_port_bridge_getlink, .ndo_bridge_setlink = switchdev_port_bridge_setlink, .ndo_bridge_dellink = switchdev_port_bridge_dellink, |
98237d433 switchdev: use ne... |
959 |
}; |
9d47c0a2d switchdev: s/swde... |
960 |
static const struct switchdev_ops dsa_slave_switchdev_ops = { |
f8e20a9f8 switchdev: conver... |
961 |
.switchdev_port_attr_get = dsa_slave_port_attr_get, |
356360625 switchdev: conver... |
962 |
.switchdev_port_attr_set = dsa_slave_port_attr_set, |
ba14d9eb1 net: dsa: add sup... |
963 964 965 |
.switchdev_port_obj_add = dsa_slave_port_obj_add, .switchdev_port_obj_del = dsa_slave_port_obj_del, .switchdev_port_obj_dump = dsa_slave_port_obj_dump, |
d442ad4ab dsa: convert to n... |
966 |
}; |
91da11f87 net: Distributed ... |
967 |
|
f37db85d0 net: dsa: Set a "... |
968 969 970 |
static struct device_type dsa_type = { .name = "dsa", }; |
0d8bcdd38 net: dsa: allow f... |
971 972 973 |
static void dsa_slave_adjust_link(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); |
ec9436bae net: dsa: allow d... |
974 |
struct dsa_switch *ds = p->parent; |
0d8bcdd38 net: dsa: allow f... |
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 |
unsigned int status_changed = 0; if (p->old_link != p->phy->link) { status_changed = 1; p->old_link = p->phy->link; } if (p->old_duplex != p->phy->duplex) { status_changed = 1; p->old_duplex = p->phy->duplex; } if (p->old_pause != p->phy->pause) { status_changed = 1; p->old_pause = p->phy->pause; } |
9d490b4ee net: dsa: rename ... |
991 992 |
if (ds->ops->adjust_link && status_changed) ds->ops->adjust_link(ds, p->port, p->phy); |
ec9436bae net: dsa: allow d... |
993 |
|
0d8bcdd38 net: dsa: allow f... |
994 995 996 |
if (status_changed) phy_print_status(p->phy); } |
ce31b31c6 net: dsa: allow u... |
997 998 999 |
static int dsa_slave_fixed_link_update(struct net_device *dev, struct fixed_phy_status *status) { |
b71be352f dsa: slave: Don't... |
1000 1001 1002 1003 1004 1005 |
struct dsa_slave_priv *p; struct dsa_switch *ds; if (dev) { p = netdev_priv(dev); ds = p->parent; |
9d490b4ee net: dsa: rename ... |
1006 1007 |
if (ds->ops->fixed_link_update) ds->ops->fixed_link_update(ds, p->port, status); |
b71be352f dsa: slave: Don't... |
1008 |
} |
ce31b31c6 net: dsa: allow u... |
1009 1010 1011 |
return 0; } |
91da11f87 net: Distributed ... |
1012 |
/* slave device setup *******************************************************/ |
c305c1651 net: dsa: move PH... |
1013 |
static int dsa_slave_phy_connect(struct dsa_slave_priv *p, |
cd28a1a9b net: dsa: fully d... |
1014 1015 |
struct net_device *slave_dev, int addr) |
c305c1651 net: dsa: move PH... |
1016 1017 |
{ struct dsa_switch *ds = p->parent; |
7f854420f phy: Add API for ... |
1018 |
p->phy = mdiobus_get_phy(ds->slave_mii_bus, addr); |
d25b8e742 net: dsa: better ... |
1019 1020 1021 |
if (!p->phy) { netdev_err(slave_dev, "no phy at %d ", addr); |
c305c1651 net: dsa: move PH... |
1022 |
return -ENODEV; |
d25b8e742 net: dsa: better ... |
1023 |
} |
c305c1651 net: dsa: move PH... |
1024 1025 |
/* Use already configured phy mode */ |
211c504a4 net: dsa: Do not ... |
1026 1027 |
if (p->phy_interface == PHY_INTERFACE_MODE_NA) p->phy_interface = p->phy->interface; |
c305c1651 net: dsa: move PH... |
1028 1029 1030 1031 1032 |
phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link, p->phy_interface); return 0; } |
9697f1cde net: dsa: propaga... |
1033 |
static int dsa_slave_phy_setup(struct dsa_slave_priv *p, |
0d8bcdd38 net: dsa: allow f... |
1034 1035 1036 |
struct net_device *slave_dev) { struct dsa_switch *ds = p->parent; |
0d8bcdd38 net: dsa: allow f... |
1037 |
struct device_node *phy_dn, *port_dn; |
ce31b31c6 net: dsa: allow u... |
1038 |
bool phy_is_fixed = false; |
6819563e6 net: dsa: allow s... |
1039 |
u32 phy_flags = 0; |
19334920e net: dsa: Set val... |
1040 |
int mode, ret; |
0d8bcdd38 net: dsa: allow f... |
1041 |
|
189b0d93e net: dsa: Move po... |
1042 |
port_dn = ds->ports[p->port].dn; |
19334920e net: dsa: Set val... |
1043 1044 1045 1046 |
mode = of_get_phy_mode(port_dn); if (mode < 0) mode = PHY_INTERFACE_MODE_NA; p->phy_interface = mode; |
0d8bcdd38 net: dsa: allow f... |
1047 1048 |
phy_dn = of_parse_phandle(port_dn, "phy-handle", 0); |
0d8f3c671 net: dsa: slave: ... |
1049 |
if (!phy_dn && of_phy_is_fixed_link(port_dn)) { |
0d8bcdd38 net: dsa: allow f... |
1050 1051 1052 1053 1054 |
/* In the case of a fixed PHY, the DT node associated * to the fixed PHY is the Port DT node */ ret = of_phy_register_fixed_link(port_dn); if (ret) { |
d25b8e742 net: dsa: better ... |
1055 1056 |
netdev_err(slave_dev, "failed to register fixed PHY: %d ", ret); |
9697f1cde net: dsa: propaga... |
1057 |
return ret; |
0d8bcdd38 net: dsa: allow f... |
1058 |
} |
ce31b31c6 net: dsa: allow u... |
1059 |
phy_is_fixed = true; |
0d8f3c671 net: dsa: slave: ... |
1060 |
phy_dn = of_node_get(port_dn); |
0d8bcdd38 net: dsa: allow f... |
1061 |
} |
9d490b4ee net: dsa: rename ... |
1062 1063 |
if (ds->ops->get_phy_flags) phy_flags = ds->ops->get_phy_flags(ds, p->port); |
6819563e6 net: dsa: allow s... |
1064 |
|
cd28a1a9b net: dsa: fully d... |
1065 |
if (phy_dn) { |
d25b8e742 net: dsa: better ... |
1066 |
int phy_id = of_mdio_parse_addr(&slave_dev->dev, phy_dn); |
cd28a1a9b net: dsa: fully d... |
1067 1068 1069 1070 1071 |
/* If this PHY address is part of phys_mii_mask, which means * that we need to divert reads and writes to/from it, then we * want to bind this device using the slave MII bus created by * DSA to make that happen. */ |
d25b8e742 net: dsa: better ... |
1072 1073 1074 1075 1076 1077 |
if (!phy_is_fixed && phy_id >= 0 && (ds->phys_mii_mask & (1 << phy_id))) { ret = dsa_slave_phy_connect(p, slave_dev, phy_id); if (ret) { netdev_err(slave_dev, "failed to connect to phy%d: %d ", phy_id, ret); |
0d8f3c671 net: dsa: slave: ... |
1078 |
of_node_put(phy_dn); |
cd28a1a9b net: dsa: fully d... |
1079 |
return ret; |
d25b8e742 net: dsa: better ... |
1080 |
} |
cd28a1a9b net: dsa: fully d... |
1081 1082 1083 1084 1085 1086 |
} else { p->phy = of_phy_connect(slave_dev, phy_dn, dsa_slave_adjust_link, phy_flags, p->phy_interface); } |
0d8f3c671 net: dsa: slave: ... |
1087 1088 |
of_node_put(phy_dn); |
cd28a1a9b net: dsa: fully d... |
1089 |
} |
0d8bcdd38 net: dsa: allow f... |
1090 |
|
ce31b31c6 net: dsa: allow u... |
1091 1092 |
if (p->phy && phy_is_fixed) fixed_phy_set_link_update(p->phy, dsa_slave_fixed_link_update); |
0d8bcdd38 net: dsa: allow f... |
1093 1094 1095 |
/* We could not connect to a designated PHY, so use the switch internal * MDIO bus instead */ |
b31f65fb4 net: dsa: slave: ... |
1096 |
if (!p->phy) { |
cd28a1a9b net: dsa: fully d... |
1097 |
ret = dsa_slave_phy_connect(p, slave_dev, p->port); |
d25b8e742 net: dsa: better ... |
1098 1099 1100 |
if (ret) { netdev_err(slave_dev, "failed to connect to port %d: %d ", p->port, ret); |
881eadabe net: dsa: slave: ... |
1101 1102 |
if (phy_is_fixed) of_phy_deregister_fixed_link(port_dn); |
c305c1651 net: dsa: move PH... |
1103 |
return ret; |
d25b8e742 net: dsa: better ... |
1104 |
} |
b31f65fb4 net: dsa: slave: ... |
1105 |
} |
9697f1cde net: dsa: propaga... |
1106 |
|
2220943a2 phy: Centralise p... |
1107 |
phy_attached_info(p->phy); |
9697f1cde net: dsa: propaga... |
1108 |
return 0; |
0d8bcdd38 net: dsa: allow f... |
1109 |
} |
448b4482c net: dsa: Add loc... |
1110 1111 1112 1113 1114 1115 1116 1117 |
static struct lock_class_key dsa_slave_netdev_xmit_lock_key; static void dsa_slave_set_lockdep_class_one(struct net_device *dev, struct netdev_queue *txq, void *_unused) { lockdep_set_class(&txq->_xmit_lock, &dsa_slave_netdev_xmit_lock_key); } |
244625491 net: dsa: allow s... |
1118 1119 1120 |
int dsa_slave_suspend(struct net_device *slave_dev) { struct dsa_slave_priv *p = netdev_priv(slave_dev); |
9f42bc4f9 net: dsa: Bring b... |
1121 |
netif_device_detach(slave_dev); |
244625491 net: dsa: allow s... |
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 |
if (p->phy) { phy_stop(p->phy); p->old_pause = -1; p->old_link = -1; p->old_duplex = -1; phy_suspend(p->phy); } return 0; } int dsa_slave_resume(struct net_device *slave_dev) { struct dsa_slave_priv *p = netdev_priv(slave_dev); netif_device_attach(slave_dev); if (p->phy) { phy_resume(p->phy); phy_start(p->phy); } return 0; } |
d87d6f44d net: dsa: Ensure ... |
1146 |
int dsa_slave_create(struct dsa_switch *ds, struct device *parent, |
83c0afaec net: dsa: Add new... |
1147 |
int port, const char *name) |
91da11f87 net: Distributed ... |
1148 |
{ |
badf3ada6 net: dsa: Provide... |
1149 |
struct dsa_switch_tree *dst = ds->dst; |
83c0afaec net: dsa: Add new... |
1150 |
struct net_device *master; |
91da11f87 net: Distributed ... |
1151 1152 1153 |
struct net_device *slave_dev; struct dsa_slave_priv *p; int ret; |
83c0afaec net: dsa: Add new... |
1154 1155 1156 |
master = ds->dst->master_netdev; if (ds->master_netdev) master = ds->master_netdev; |
c835a6773 net: set name_ass... |
1157 1158 |
slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name, NET_NAME_UNKNOWN, ether_setup); |
91da11f87 net: Distributed ... |
1159 |
if (slave_dev == NULL) |
d87d6f44d net: dsa: Ensure ... |
1160 |
return -ENOMEM; |
91da11f87 net: Distributed ... |
1161 1162 |
slave_dev->features = master->vlan_features; |
7ad24ea4b net: get rid of S... |
1163 |
slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; |
2fcc80058 net: dsa: inherit... |
1164 |
eth_hw_addr_inherit(slave_dev, master); |
0a5f107b6 net: dsa: convert... |
1165 |
slave_dev->priv_flags |= IFF_NO_QUEUE; |
3e8a72d1d net: dsa: reduce ... |
1166 |
slave_dev->netdev_ops = &dsa_slave_netdev_ops; |
9d47c0a2d switchdev: s/swde... |
1167 |
slave_dev->switchdev_ops = &dsa_slave_switchdev_ops; |
f37db85d0 net: dsa: Set a "... |
1168 |
SET_NETDEV_DEVTYPE(slave_dev, &dsa_type); |
d442ad4ab dsa: convert to n... |
1169 |
|
448b4482c net: dsa: Add loc... |
1170 1171 |
netdev_for_each_tx_queue(slave_dev, dsa_slave_set_lockdep_class_one, NULL); |
5075314e4 dsa: Split ops up... |
1172 |
SET_NETDEV_DEV(slave_dev, parent); |
189b0d93e net: dsa: Move po... |
1173 |
slave_dev->dev.of_node = ds->ports[port].dn; |
5075314e4 dsa: Split ops up... |
1174 1175 1176 |
slave_dev->vlan_features = master->vlan_features; p = netdev_priv(slave_dev); |
5075314e4 dsa: Split ops up... |
1177 1178 |
p->parent = ds; p->port = port; |
39a7f2a4e net: dsa: Refacto... |
1179 |
p->xmit = dst->tag_ops->xmit; |
d442ad4ab dsa: convert to n... |
1180 |
|
0d8bcdd38 net: dsa: allow f... |
1181 1182 1183 |
p->old_pause = -1; p->old_link = -1; p->old_duplex = -1; |
c8b098086 net: dsa: Add a p... |
1184 |
ds->ports[port].netdev = slave_dev; |
91da11f87 net: Distributed ... |
1185 1186 |
ret = register_netdev(slave_dev); if (ret) { |
a2ae6007a dsa: Use netdev_<... |
1187 1188 1189 |
netdev_err(master, "error %d registering interface %s ", ret, slave_dev->name); |
c8b098086 net: dsa: Add a p... |
1190 |
ds->ports[port].netdev = NULL; |
91da11f87 net: Distributed ... |
1191 |
free_netdev(slave_dev); |
d87d6f44d net: dsa: Ensure ... |
1192 |
return ret; |
91da11f87 net: Distributed ... |
1193 1194 1195 |
} netif_carrier_off(slave_dev); |
0071f56e4 dsa: Register net... |
1196 1197 1198 1199 |
ret = dsa_slave_phy_setup(p, slave_dev); if (ret) { netdev_err(master, "error %d setting up slave phy ", ret); |
73dcb5565 net: dsa: Unregis... |
1200 |
unregister_netdev(slave_dev); |
0071f56e4 dsa: Register net... |
1201 1202 1203 |
free_netdev(slave_dev); return ret; } |
d87d6f44d net: dsa: Ensure ... |
1204 |
return 0; |
91da11f87 net: Distributed ... |
1205 |
} |
b73adef67 net: dsa: integra... |
1206 |
|
cda5c15b2 net: dsa: move ds... |
1207 1208 1209 |
void dsa_slave_destroy(struct net_device *slave_dev) { struct dsa_slave_priv *p = netdev_priv(slave_dev); |
881eadabe net: dsa: slave: ... |
1210 1211 1212 1213 |
struct dsa_switch *ds = p->parent; struct device_node *port_dn; port_dn = ds->ports[p->port].dn; |
cda5c15b2 net: dsa: move ds... |
1214 1215 |
netif_carrier_off(slave_dev); |
881eadabe net: dsa: slave: ... |
1216 |
if (p->phy) { |
cda5c15b2 net: dsa: move ds... |
1217 |
phy_disconnect(p->phy); |
881eadabe net: dsa: slave: ... |
1218 1219 1220 1221 |
if (of_phy_is_fixed_link(port_dn)) of_phy_deregister_fixed_link(port_dn); } |
cda5c15b2 net: dsa: move ds... |
1222 1223 1224 |
unregister_netdev(slave_dev); free_netdev(slave_dev); } |
b73adef67 net: dsa: integra... |
1225 1226 1227 1228 |
static bool dsa_slave_dev_check(struct net_device *dev) { return dev->netdev_ops == &dsa_slave_netdev_ops; } |
6debb68a2 net: dsa: refine ... |
1229 1230 |
static int dsa_slave_port_upper_event(struct net_device *dev, unsigned long event, void *ptr) |
b73adef67 net: dsa: integra... |
1231 |
{ |
6debb68a2 net: dsa: refine ... |
1232 1233 |
struct netdev_notifier_changeupper_info *info = ptr; struct net_device *upper = info->upper_dev; |
b73adef67 net: dsa: integra... |
1234 |
int err = 0; |
6debb68a2 net: dsa: refine ... |
1235 1236 1237 1238 1239 1240 1241 1242 |
switch (event) { case NETDEV_CHANGEUPPER: if (netif_is_bridge_master(upper)) { if (info->linking) err = dsa_slave_bridge_port_join(dev, upper); else dsa_slave_bridge_port_leave(dev); } |
b73adef67 net: dsa: integra... |
1243 |
|
6debb68a2 net: dsa: refine ... |
1244 1245 1246 1247 |
break; } return notifier_from_errno(err); |
b73adef67 net: dsa: integra... |
1248 |
} |
6debb68a2 net: dsa: refine ... |
1249 1250 |
static int dsa_slave_port_event(struct net_device *dev, unsigned long event, void *ptr) |
b73adef67 net: dsa: integra... |
1251 |
{ |
b73adef67 net: dsa: integra... |
1252 1253 |
switch (event) { case NETDEV_CHANGEUPPER: |
6debb68a2 net: dsa: refine ... |
1254 1255 |
return dsa_slave_port_upper_event(dev, event, ptr); } |
b73adef67 net: dsa: integra... |
1256 |
|
6debb68a2 net: dsa: refine ... |
1257 1258 |
return NOTIFY_DONE; } |
b73adef67 net: dsa: integra... |
1259 |
|
6debb68a2 net: dsa: refine ... |
1260 1261 1262 1263 1264 1265 1266 |
int dsa_slave_netdevice_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); if (dsa_slave_dev_check(dev)) return dsa_slave_port_event(dev, event, ptr); |
b73adef67 net: dsa: integra... |
1267 |
|
b73adef67 net: dsa: integra... |
1268 1269 |
return NOTIFY_DONE; } |