Blame view
net/dsa/dsa.c
8.08 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
91da11f87 net: Distributed ... |
2 3 |
/* * net/dsa/dsa.c - Hardware switch handling |
e84665c9c dsa: add switch c... |
4 |
* Copyright (c) 2008-2009 Marvell Semiconductor |
5e95329b7 dsa: add device t... |
5 |
* Copyright (c) 2013 Florian Fainelli <florian@openwrt.org> |
91da11f87 net: Distributed ... |
6 |
*/ |
51579c3f1 net: dsa: Add sup... |
7 |
#include <linux/device.h> |
91da11f87 net: Distributed ... |
8 |
#include <linux/list.h> |
91da11f87 net: Distributed ... |
9 |
#include <linux/platform_device.h> |
5a0e3ad6a include cleanup: ... |
10 |
#include <linux/slab.h> |
3a9a231d9 net: Fix files ex... |
11 |
#include <linux/module.h> |
60724d4ba net: dsa: Add sup... |
12 |
#include <linux/notifier.h> |
5e95329b7 dsa: add device t... |
13 14 15 |
#include <linux/of.h> #include <linux/of_mdio.h> #include <linux/of_platform.h> |
769a02028 net: dsa: utilize... |
16 |
#include <linux/of_net.h> |
c6e970a04 net: break includ... |
17 |
#include <linux/netdevice.h> |
51579c3f1 net: dsa: Add sup... |
18 |
#include <linux/sysfs.h> |
cbc5d90b3 net: dsa: complet... |
19 |
#include <linux/phy_fixed.h> |
90af1059c net: dsa: forward... |
20 |
#include <linux/ptp_classify.h> |
a86d8becc net: dsa: Factor ... |
21 |
#include <linux/etherdevice.h> |
ea5dd34be net: dsa: include... |
22 |
|
91da11f87 net: Distributed ... |
23 |
#include "dsa_priv.h" |
bdc6fe5bb dsa: Keep link li... |
24 25 |
static LIST_HEAD(dsa_tag_drivers_list); static DEFINE_MUTEX(dsa_tag_drivers_lock); |
39a7f2a4e net: dsa: Refacto... |
26 27 28 29 30 31 32 33 |
static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb, struct net_device *dev) { /* Just return the original SKB */ return skb; } static const struct dsa_device_ops none_ops = { |
875138f81 dsa: Move tagger ... |
34 |
.name = "none", |
056eed2fb dsa: Add TAG prot... |
35 |
.proto = DSA_TAG_PROTO_NONE, |
39a7f2a4e net: dsa: Refacto... |
36 37 38 |
.xmit = dsa_slave_notag_xmit, .rcv = NULL, }; |
409065b06 dsa: Register the... |
39 |
DSA_TAG_DRIVER(none_ops); |
bdc6fe5bb dsa: Keep link li... |
40 41 42 43 44 45 46 47 48 |
static void dsa_tag_driver_register(struct dsa_tag_driver *dsa_tag_driver, struct module *owner) { dsa_tag_driver->owner = owner; mutex_lock(&dsa_tag_drivers_lock); list_add_tail(&dsa_tag_driver->list, &dsa_tag_drivers_list); mutex_unlock(&dsa_tag_drivers_lock); } |
d3b8c0498 dsa: Add boilerpl... |
49 50 51 |
void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[], unsigned int count, struct module *owner) { |
bdc6fe5bb dsa: Keep link li... |
52 53 54 55 56 57 58 59 60 61 62 |
unsigned int i; for (i = 0; i < count; i++) dsa_tag_driver_register(dsa_tag_driver_array[i], owner); } static void dsa_tag_driver_unregister(struct dsa_tag_driver *dsa_tag_driver) { mutex_lock(&dsa_tag_drivers_lock); list_del(&dsa_tag_driver->list); mutex_unlock(&dsa_tag_drivers_lock); |
d3b8c0498 dsa: Add boilerpl... |
63 64 65 66 67 68 |
} EXPORT_SYMBOL_GPL(dsa_tag_drivers_register); void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[], unsigned int count) { |
bdc6fe5bb dsa: Keep link li... |
69 70 71 72 |
unsigned int i; for (i = 0; i < count; i++) dsa_tag_driver_unregister(dsa_tag_driver_array[i]); |
d3b8c0498 dsa: Add boilerpl... |
73 74 |
} EXPORT_SYMBOL_GPL(dsa_tag_drivers_unregister); |
98cdb4807 net: dsa: Expose ... |
75 76 |
const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops) { |
875138f81 dsa: Move tagger ... |
77 |
return ops->name; |
98cdb4807 net: dsa: Expose ... |
78 |
}; |
c39e2a1d7 dsa: Rename dsa_r... |
79 |
const struct dsa_device_ops *dsa_tag_driver_get(int tag_protocol) |
39a7f2a4e net: dsa: Refacto... |
80 |
{ |
367561753 dsa: Make use of ... |
81 |
struct dsa_tag_driver *dsa_tag_driver; |
39a7f2a4e net: dsa: Refacto... |
82 |
const struct dsa_device_ops *ops; |
367561753 dsa: Make use of ... |
83 84 |
char module_name[128]; bool found = false; |
39a7f2a4e net: dsa: Refacto... |
85 |
|
367561753 dsa: Make use of ... |
86 87 |
snprintf(module_name, 127, "%s%d", DSA_TAG_DRIVER_ALIAS, tag_protocol); |
39a7f2a4e net: dsa: Refacto... |
88 |
|
367561753 dsa: Make use of ... |
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
request_module(module_name); mutex_lock(&dsa_tag_drivers_lock); list_for_each_entry(dsa_tag_driver, &dsa_tag_drivers_list, list) { ops = dsa_tag_driver->ops; if (ops->proto == tag_protocol) { found = true; break; } } if (found) { if (!try_module_get(dsa_tag_driver->owner)) ops = ERR_PTR(-ENOPROTOOPT); } else { ops = ERR_PTR(-ENOPROTOOPT); } mutex_unlock(&dsa_tag_drivers_lock); |
39a7f2a4e net: dsa: Refacto... |
108 109 110 |
return ops; } |
4dad81ee1 dsa: Add stub tag... |
111 112 |
void dsa_tag_driver_put(const struct dsa_device_ops *ops) { |
367561753 dsa: Make use of ... |
113 114 115 116 117 118 119 120 121 122 |
struct dsa_tag_driver *dsa_tag_driver; mutex_lock(&dsa_tag_drivers_lock); list_for_each_entry(dsa_tag_driver, &dsa_tag_drivers_list, list) { if (dsa_tag_driver->ops == ops) { module_put(dsa_tag_driver->owner); break; } } mutex_unlock(&dsa_tag_drivers_lock); |
4dad81ee1 dsa: Add stub tag... |
123 |
} |
91da11f87 net: Distributed ... |
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
static int dev_is_class(struct device *dev, void *class) { if (dev->class != NULL && !strcmp(dev->class->name, class)) return 1; return 0; } static struct device *dev_find_class(struct device *parent, char *class) { if (dev_is_class(parent, class)) { get_device(parent); return parent; } return device_find_child(parent, class, dev_is_class); } |
14b89f36e net: dsa: Rename ... |
141 |
struct net_device *dsa_dev_to_net_device(struct device *dev) |
91da11f87 net: Distributed ... |
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
{ struct device *d; d = dev_find_class(dev, "net"); if (d != NULL) { struct net_device *nd; nd = to_net_dev(d); dev_hold(nd); put_device(d); return nd; } return NULL; } |
14b89f36e net: dsa: Rename ... |
158 |
EXPORT_SYMBOL_GPL(dsa_dev_to_net_device); |
91da11f87 net: Distributed ... |
159 |
|
90af1059c net: dsa: forward... |
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
/* Determine if we should defer delivery of skb until we have a rx timestamp. * * Called from dsa_switch_rcv. For now, this will only work if tagging is * enabled on the switch. Normally the MAC driver would retrieve the hardware * timestamp when it reads the packet out of the hardware. However in a DSA * switch, the DSA driver owning the interface to which the packet is * delivered is never notified unless we do so here. */ static bool dsa_skb_defer_rx_timestamp(struct dsa_slave_priv *p, struct sk_buff *skb) { struct dsa_switch *ds = p->dp->ds; unsigned int type; if (skb_headroom(skb) < ETH_HLEN) return false; __skb_push(skb, ETH_HLEN); type = ptp_classify_raw(skb); __skb_pull(skb, ETH_HLEN); if (type == PTP_CLASS_NONE) return false; if (likely(ds->ops->port_rxtstamp)) return ds->ops->port_rxtstamp(ds, p->dp->index, skb, type); return false; } |
3e8a72d1d net: dsa: reduce ... |
191 |
static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, |
89e49506b dsa: remove unuse... |
192 |
struct packet_type *pt, struct net_device *unused) |
3e8a72d1d net: dsa: reduce ... |
193 |
{ |
2f657a600 net: dsa: change ... |
194 |
struct dsa_port *cpu_dp = dev->dsa_ptr; |
a86d8becc net: dsa: Factor ... |
195 |
struct sk_buff *nskb = NULL; |
5f6b4e14c net: dsa: User pe... |
196 |
struct pcpu_sw_netstats *s; |
f613ed665 net: dsa: Add sup... |
197 |
struct dsa_slave_priv *p; |
3e8a72d1d net: dsa: reduce ... |
198 |
|
2f657a600 net: dsa: change ... |
199 |
if (unlikely(!cpu_dp)) { |
3e8a72d1d net: dsa: reduce ... |
200 201 202 |
kfree_skb(skb); return 0; } |
16c5dcb13 net: dsa: Move sk... |
203 204 205 |
skb = skb_unshare(skb, GFP_ATOMIC); if (!skb) return 0; |
2f657a600 net: dsa: change ... |
206 |
nskb = cpu_dp->rcv(skb, dev, pt); |
a86d8becc net: dsa: Factor ... |
207 208 209 210 211 212 |
if (!nskb) { kfree_skb(skb); return 0; } skb = nskb; |
f613ed665 net: dsa: Add sup... |
213 |
p = netdev_priv(skb->dev); |
a86d8becc net: dsa: Factor ... |
214 215 216 |
skb_push(skb, ETH_HLEN); skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, skb->dev); |
5f6b4e14c net: dsa: User pe... |
217 218 219 220 221 |
s = this_cpu_ptr(p->stats64); u64_stats_update_begin(&s->syncp); s->rx_packets++; s->rx_bytes += skb->len; u64_stats_update_end(&s->syncp); |
a86d8becc net: dsa: Factor ... |
222 |
|
90af1059c net: dsa: forward... |
223 224 |
if (dsa_skb_defer_rx_timestamp(p, skb)) return 0; |
a86d8becc net: dsa: Factor ... |
225 226 227 |
netif_receive_skb(skb); return 0; |
3e8a72d1d net: dsa: reduce ... |
228 |
} |
ac2629a47 net: dsa: Move ds... |
229 |
#ifdef CONFIG_PM_SLEEP |
e7d53ad32 net: dsa: unexpor... |
230 231 |
static bool dsa_is_port_initialized(struct dsa_switch *ds, int p) { |
4a5b85ffe net: dsa: use dsa... |
232 |
return dsa_is_user_port(ds, p) && ds->ports[p].slave; |
e7d53ad32 net: dsa: unexpor... |
233 |
} |
ac2629a47 net: dsa: Move ds... |
234 235 236 237 238 239 240 241 |
int dsa_switch_suspend(struct dsa_switch *ds) { int i, ret = 0; /* Suspend slave network devices */ for (i = 0; i < ds->num_ports; i++) { if (!dsa_is_port_initialized(ds, i)) continue; |
f8b8b1cd5 net: dsa: split d... |
242 |
ret = dsa_slave_suspend(ds->ports[i].slave); |
ac2629a47 net: dsa: Move ds... |
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
if (ret) return ret; } if (ds->ops->suspend) ret = ds->ops->suspend(ds); return ret; } EXPORT_SYMBOL_GPL(dsa_switch_suspend); int dsa_switch_resume(struct dsa_switch *ds) { int i, ret = 0; if (ds->ops->resume) ret = ds->ops->resume(ds); if (ret) return ret; /* Resume slave network devices */ for (i = 0; i < ds->num_ports; i++) { if (!dsa_is_port_initialized(ds, i)) continue; |
f8b8b1cd5 net: dsa: split d... |
268 |
ret = dsa_slave_resume(ds->ports[i].slave); |
ac2629a47 net: dsa: Move ds... |
269 270 271 272 273 274 275 276 |
if (ret) return ret; } return 0; } EXPORT_SYMBOL_GPL(dsa_switch_resume); #endif |
61b7363ff net: dsa: make ds... |
277 |
static struct packet_type dsa_pack_type __read_mostly = { |
3e8a72d1d net: dsa: reduce ... |
278 279 280 |
.type = cpu_to_be16(ETH_P_XDSA), .func = dsa_switch_rcv, }; |
c9eb3e0f8 net: dsa: Add sup... |
281 282 283 284 285 286 |
static struct workqueue_struct *dsa_owq; bool dsa_schedule_work(struct work_struct *work) { return queue_work(dsa_owq, work); } |
60724d4ba net: dsa: Add sup... |
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
static ATOMIC_NOTIFIER_HEAD(dsa_notif_chain); int register_dsa_notifier(struct notifier_block *nb) { return atomic_notifier_chain_register(&dsa_notif_chain, nb); } EXPORT_SYMBOL_GPL(register_dsa_notifier); int unregister_dsa_notifier(struct notifier_block *nb) { return atomic_notifier_chain_unregister(&dsa_notif_chain, nb); } EXPORT_SYMBOL_GPL(unregister_dsa_notifier); int call_dsa_notifiers(unsigned long val, struct net_device *dev, struct dsa_notifier_info *info) { info->dev = dev; return atomic_notifier_call_chain(&dsa_notif_chain, val, info); } EXPORT_SYMBOL_GPL(call_dsa_notifiers); |
91da11f87 net: Distributed ... |
308 309 |
static int __init dsa_init_module(void) { |
7df899c36 dsa: Combine core... |
310 |
int rc; |
c9eb3e0f8 net: dsa: Add sup... |
311 312 313 314 |
dsa_owq = alloc_ordered_workqueue("dsa_ordered", WQ_MEM_RECLAIM); if (!dsa_owq) return -ENOMEM; |
88e4f0ca4 net: dsa: move ne... |
315 316 |
rc = dsa_slave_register_notifier(); if (rc) |
68be93024 net: dsa: Fix err... |
317 |
goto register_notifier_fail; |
b73adef67 net: dsa: integra... |
318 |
|
3e8a72d1d net: dsa: reduce ... |
319 |
dev_add_pack(&dsa_pack_type); |
409065b06 dsa: Register the... |
320 321 |
dsa_tag_driver_register(&DSA_TAG_DRIVER_NAME(none_ops), THIS_MODULE); |
7df899c36 dsa: Combine core... |
322 |
return 0; |
68be93024 net: dsa: Fix err... |
323 |
|
68be93024 net: dsa: Fix err... |
324 325 326 327 |
register_notifier_fail: destroy_workqueue(dsa_owq); return rc; |
91da11f87 net: Distributed ... |
328 329 330 331 332 |
} module_init(dsa_init_module); static void __exit dsa_cleanup_module(void) { |
409065b06 dsa: Register the... |
333 |
dsa_tag_driver_unregister(&DSA_TAG_DRIVER_NAME(none_ops)); |
88e4f0ca4 net: dsa: move ne... |
334 |
dsa_slave_unregister_notifier(); |
3e8a72d1d net: dsa: reduce ... |
335 |
dev_remove_pack(&dsa_pack_type); |
c9eb3e0f8 net: dsa: Add sup... |
336 |
destroy_workqueue(dsa_owq); |
91da11f87 net: Distributed ... |
337 338 |
} module_exit(dsa_cleanup_module); |
577d6a7c3 module: fix missi... |
339 |
MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); |
91da11f87 net: Distributed ... |
340 341 342 |
MODULE_DESCRIPTION("Driver for Distributed Switch Architecture switch chips"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:dsa"); |