Blame view
net/dsa/dsa.c
6.9 KB
91da11f87 net: Distributed ... |
1 2 |
/* * net/dsa/dsa.c - Hardware switch handling |
e84665c9c dsa: add switch c... |
3 |
* Copyright (c) 2008-2009 Marvell Semiconductor |
5e95329b7 dsa: add device t... |
4 |
* Copyright (c) 2013 Florian Fainelli <florian@openwrt.org> |
91da11f87 net: Distributed ... |
5 6 7 8 9 10 |
* * 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. */ |
51579c3f1 net: dsa: Add sup... |
11 |
#include <linux/device.h> |
91da11f87 net: Distributed ... |
12 |
#include <linux/list.h> |
91da11f87 net: Distributed ... |
13 |
#include <linux/platform_device.h> |
5a0e3ad6a include cleanup: ... |
14 |
#include <linux/slab.h> |
3a9a231d9 net: Fix files ex... |
15 |
#include <linux/module.h> |
5e95329b7 dsa: add device t... |
16 17 18 |
#include <linux/of.h> #include <linux/of_mdio.h> #include <linux/of_platform.h> |
769a02028 net: dsa: utilize... |
19 |
#include <linux/of_net.h> |
cc30c1634 net: dsa: Add sup... |
20 |
#include <linux/of_gpio.h> |
c6e970a04 net: break includ... |
21 |
#include <linux/netdevice.h> |
51579c3f1 net: dsa: Add sup... |
22 |
#include <linux/sysfs.h> |
cbc5d90b3 net: dsa: complet... |
23 |
#include <linux/phy_fixed.h> |
85beabfec net: dsa: include... |
24 |
#include <linux/gpio/consumer.h> |
a86d8becc net: dsa: Factor ... |
25 |
#include <linux/etherdevice.h> |
ea5dd34be net: dsa: include... |
26 |
|
91da11f87 net: Distributed ... |
27 |
#include "dsa_priv.h" |
39a7f2a4e net: dsa: Refacto... |
28 29 30 31 32 33 34 35 36 37 38 39 40 |
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 = { .xmit = dsa_slave_notag_xmit, .rcv = NULL, }; const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = { |
eb7b72112 net: dsa: Sort DS... |
41 42 43 |
#ifdef CONFIG_NET_DSA_TAG_BRCM [DSA_TAG_PROTO_BRCM] = &brcm_netdev_ops, #endif |
39a7f2a4e net: dsa: Refacto... |
44 45 46 47 48 49 |
#ifdef CONFIG_NET_DSA_TAG_DSA [DSA_TAG_PROTO_DSA] = &dsa_netdev_ops, #endif #ifdef CONFIG_NET_DSA_TAG_EDSA [DSA_TAG_PROTO_EDSA] = &edsa_netdev_ops, #endif |
8b8010fb7 dsa: add support ... |
50 51 52 |
#ifdef CONFIG_NET_DSA_TAG_KSZ [DSA_TAG_PROTO_KSZ] = &ksz_netdev_ops, #endif |
eb7b72112 net: dsa: Sort DS... |
53 54 |
#ifdef CONFIG_NET_DSA_TAG_LAN9303 [DSA_TAG_PROTO_LAN9303] = &lan9303_netdev_ops, |
39a7f2a4e net: dsa: Refacto... |
55 |
#endif |
eb7b72112 net: dsa: Sort DS... |
56 57 |
#ifdef CONFIG_NET_DSA_TAG_MTK [DSA_TAG_PROTO_MTK] = &mtk_netdev_ops, |
39a7f2a4e net: dsa: Refacto... |
58 |
#endif |
cafdc45c9 net-next: dsa: ad... |
59 60 61 |
#ifdef CONFIG_NET_DSA_TAG_QCA [DSA_TAG_PROTO_QCA] = &qca_netdev_ops, #endif |
eb7b72112 net: dsa: Sort DS... |
62 63 |
#ifdef CONFIG_NET_DSA_TAG_TRAILER [DSA_TAG_PROTO_TRAILER] = &trailer_netdev_ops, |
e8fe177a6 net: dsa: add sup... |
64 |
#endif |
39a7f2a4e net: dsa: Refacto... |
65 66 |
[DSA_TAG_PROTO_NONE] = &none_ops, }; |
91da11f87 net: Distributed ... |
67 |
|
47d0dcc35 net: dsa: remove ... |
68 |
int dsa_cpu_dsa_setup(struct dsa_port *port) |
39b0c7051 net: dsa: Allow c... |
69 |
{ |
47d0dcc35 net: dsa: remove ... |
70 71 |
struct device_node *port_dn = port->dn; struct dsa_switch *ds = port->ds; |
39b0c7051 net: dsa: Allow c... |
72 |
struct phy_device *phydev; |
9b8e895c4 net: dsa: Split u... |
73 74 75 76 77 |
int ret, mode; if (of_phy_is_fixed_link(port_dn)) { ret = of_phy_register_fixed_link(port_dn); if (ret) { |
47d0dcc35 net: dsa: remove ... |
78 79 |
dev_err(ds->dev, "failed to register fixed PHY "); |
9b8e895c4 net: dsa: Split u... |
80 81 82 83 84 85 86 87 88 89 90 |
return ret; } phydev = of_phy_find_device(port_dn); mode = of_get_phy_mode(port_dn); if (mode < 0) mode = PHY_INTERFACE_MODE_NA; phydev->interface = mode; genphy_config_init(phydev); genphy_read_status(phydev); |
9d490b4ee net: dsa: rename ... |
91 |
if (ds->ops->adjust_link) |
47d0dcc35 net: dsa: remove ... |
92 |
ds->ops->adjust_link(ds, port->index, phydev); |
fd05d7b18 net: dsa: fix fix... |
93 94 |
put_device(&phydev->mdio.dev); |
9b8e895c4 net: dsa: Split u... |
95 96 97 98 |
} return 0; } |
39a7f2a4e net: dsa: Refacto... |
99 100 101 102 103 104 105 106 107 108 109 110 111 |
const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol) { const struct dsa_device_ops *ops; if (tag_protocol >= DSA_TAG_LAST) return ERR_PTR(-EINVAL); ops = dsa_device_ops[tag_protocol]; if (!ops) return ERR_PTR(-ENOPROTOOPT); return ops; } |
937c7df85 net: dsa: Pass ds... |
112 |
int dsa_cpu_port_ethtool_setup(struct dsa_port *cpu_dp) |
0c73c523c net: dsa: Initial... |
113 |
{ |
937c7df85 net: dsa: Pass ds... |
114 |
struct dsa_switch *ds = cpu_dp->ds; |
0c73c523c net: dsa: Initial... |
115 116 |
struct net_device *master; struct ethtool_ops *cpu_ops; |
67dbb9d43 net: dsa: Relocat... |
117 |
master = cpu_dp->netdev; |
0c73c523c net: dsa: Initial... |
118 119 120 |
cpu_ops = devm_kzalloc(ds->dev, sizeof(*cpu_ops), GFP_KERNEL); if (!cpu_ops) return -ENOMEM; |
67dbb9d43 net: dsa: Relocat... |
121 |
memcpy(&cpu_dp->ethtool_ops, master->ethtool_ops, |
0c73c523c net: dsa: Initial... |
122 |
sizeof(struct ethtool_ops)); |
67dbb9d43 net: dsa: Relocat... |
123 124 |
cpu_dp->orig_ethtool_ops = master->ethtool_ops; memcpy(cpu_ops, &cpu_dp->ethtool_ops, |
0c73c523c net: dsa: Initial... |
125 126 127 128 129 130 |
sizeof(struct ethtool_ops)); dsa_cpu_port_ethtool_init(cpu_ops); master->ethtool_ops = cpu_ops; return 0; } |
937c7df85 net: dsa: Pass ds... |
131 |
void dsa_cpu_port_ethtool_restore(struct dsa_port *cpu_dp) |
0c73c523c net: dsa: Initial... |
132 |
{ |
67dbb9d43 net: dsa: Relocat... |
133 |
cpu_dp->netdev->ethtool_ops = cpu_dp->orig_ethtool_ops; |
0c73c523c net: dsa: Initial... |
134 |
} |
293784a8f net: dsa: Make mo... |
135 |
void dsa_cpu_dsa_destroy(struct dsa_port *port) |
91da11f87 net: Distributed ... |
136 |
{ |
293784a8f net: dsa: Make mo... |
137 |
struct device_node *port_dn = port->dn; |
3f65047c8 of_mdio: add help... |
138 139 |
if (of_phy_is_fixed_link(port_dn)) of_phy_deregister_fixed_link(port_dn); |
9b8e895c4 net: dsa: Split u... |
140 |
} |
91da11f87 net: Distributed ... |
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
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 ... |
158 |
struct net_device *dsa_dev_to_net_device(struct device *dev) |
91da11f87 net: Distributed ... |
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
{ 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 ... |
175 |
EXPORT_SYMBOL_GPL(dsa_dev_to_net_device); |
91da11f87 net: Distributed ... |
176 |
|
3e8a72d1d net: dsa: reduce ... |
177 |
static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, |
89e49506b dsa: remove unuse... |
178 |
struct packet_type *pt, struct net_device *unused) |
3e8a72d1d net: dsa: reduce ... |
179 180 |
{ struct dsa_switch_tree *dst = dev->dsa_ptr; |
a86d8becc net: dsa: Factor ... |
181 |
struct sk_buff *nskb = NULL; |
5f6b4e14c net: dsa: User pe... |
182 |
struct pcpu_sw_netstats *s; |
f613ed665 net: dsa: Add sup... |
183 |
struct dsa_slave_priv *p; |
3e8a72d1d net: dsa: reduce ... |
184 185 186 187 188 |
if (unlikely(dst == NULL)) { kfree_skb(skb); return 0; } |
16c5dcb13 net: dsa: Move sk... |
189 190 191 |
skb = skb_unshare(skb, GFP_ATOMIC); if (!skb) return 0; |
89e49506b dsa: remove unuse... |
192 |
nskb = dst->rcv(skb, dev, pt); |
a86d8becc net: dsa: Factor ... |
193 194 195 196 197 198 |
if (!nskb) { kfree_skb(skb); return 0; } skb = nskb; |
f613ed665 net: dsa: Add sup... |
199 |
p = netdev_priv(skb->dev); |
a86d8becc net: dsa: Factor ... |
200 201 202 |
skb_push(skb, ETH_HLEN); skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, skb->dev); |
5f6b4e14c net: dsa: User pe... |
203 204 205 206 207 |
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 ... |
208 209 210 211 |
netif_receive_skb(skb); return 0; |
3e8a72d1d net: dsa: reduce ... |
212 |
} |
ac2629a47 net: dsa: Move ds... |
213 |
#ifdef CONFIG_PM_SLEEP |
e7d53ad32 net: dsa: unexpor... |
214 215 216 217 |
static bool dsa_is_port_initialized(struct dsa_switch *ds, int p) { return ds->enabled_port_mask & (1 << p) && ds->ports[p].netdev; } |
ac2629a47 net: dsa: Move ds... |
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
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; ret = dsa_slave_suspend(ds->ports[i].netdev); 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; ret = dsa_slave_resume(ds->ports[i].netdev); if (ret) return ret; } return 0; } EXPORT_SYMBOL_GPL(dsa_switch_resume); #endif |
61b7363ff net: dsa: make ds... |
263 |
static struct packet_type dsa_pack_type __read_mostly = { |
3e8a72d1d net: dsa: reduce ... |
264 265 266 |
.type = cpu_to_be16(ETH_P_XDSA), .func = dsa_switch_rcv, }; |
c9eb3e0f8 net: dsa: Add sup... |
267 268 269 270 271 272 |
static struct workqueue_struct *dsa_owq; bool dsa_schedule_work(struct work_struct *work) { return queue_work(dsa_owq, work); } |
91da11f87 net: Distributed ... |
273 274 |
static int __init dsa_init_module(void) { |
7df899c36 dsa: Combine core... |
275 |
int rc; |
c9eb3e0f8 net: dsa: Add sup... |
276 277 278 279 |
dsa_owq = alloc_ordered_workqueue("dsa_ordered", WQ_MEM_RECLAIM); if (!dsa_owq) return -ENOMEM; |
88e4f0ca4 net: dsa: move ne... |
280 281 282 |
rc = dsa_slave_register_notifier(); if (rc) return rc; |
b73adef67 net: dsa: integra... |
283 |
|
a6a71f19f net: dsa: isolate... |
284 |
rc = dsa_legacy_register(); |
7df899c36 dsa: Combine core... |
285 286 |
if (rc) return rc; |
3e8a72d1d net: dsa: reduce ... |
287 |
dev_add_pack(&dsa_pack_type); |
7df899c36 dsa: Combine core... |
288 |
return 0; |
91da11f87 net: Distributed ... |
289 290 291 292 293 |
} module_init(dsa_init_module); static void __exit dsa_cleanup_module(void) { |
88e4f0ca4 net: dsa: move ne... |
294 |
dsa_slave_unregister_notifier(); |
3e8a72d1d net: dsa: reduce ... |
295 |
dev_remove_pack(&dsa_pack_type); |
a6a71f19f net: dsa: isolate... |
296 |
dsa_legacy_unregister(); |
c9eb3e0f8 net: dsa: Add sup... |
297 |
destroy_workqueue(dsa_owq); |
91da11f87 net: Distributed ... |
298 299 |
} module_exit(dsa_cleanup_module); |
577d6a7c3 module: fix missi... |
300 |
MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>"); |
91da11f87 net: Distributed ... |
301 302 303 |
MODULE_DESCRIPTION("Driver for Distributed Switch Architecture switch chips"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:dsa"); |