2 * net/dsa/slave.c - Slave device handling
3 * Copyright (c) 2008-2009 Marvell Semiconductor
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
11 #include <linux/list.h>
12 #include <linux/netdevice.h>
13 #include <linux/etherdevice.h>
14 #include <linux/phy.h>
17 /* slave mii_bus handling ***************************************************/
18 static int dsa_slave_phy_read(struct mii_bus
*bus
, int addr
, int reg
)
20 struct dsa_switch
*ds
= bus
->priv
;
22 if (ds
->phys_port_mask
& (1 << addr
))
23 return ds
->drv
->phy_read(ds
, addr
, reg
);
28 static int dsa_slave_phy_write(struct mii_bus
*bus
, int addr
, int reg
, u16 val
)
30 struct dsa_switch
*ds
= bus
->priv
;
32 if (ds
->phys_port_mask
& (1 << addr
))
33 return ds
->drv
->phy_write(ds
, addr
, reg
, val
);
38 void dsa_slave_mii_bus_init(struct dsa_switch
*ds
)
40 ds
->slave_mii_bus
->priv
= (void *)ds
;
41 ds
->slave_mii_bus
->name
= "dsa slave smi";
42 ds
->slave_mii_bus
->read
= dsa_slave_phy_read
;
43 ds
->slave_mii_bus
->write
= dsa_slave_phy_write
;
44 snprintf(ds
->slave_mii_bus
->id
, MII_BUS_ID_SIZE
, "%s:%.2x",
45 ds
->master_mii_bus
->id
, ds
->pd
->sw_addr
);
46 ds
->slave_mii_bus
->parent
= &ds
->master_mii_bus
->dev
;
50 /* slave device handling ****************************************************/
51 static int dsa_slave_init(struct net_device
*dev
)
53 struct dsa_slave_priv
*p
= netdev_priv(dev
);
55 dev
->iflink
= p
->parent
->dst
->master_netdev
->ifindex
;
60 static int dsa_slave_open(struct net_device
*dev
)
62 struct dsa_slave_priv
*p
= netdev_priv(dev
);
63 struct net_device
*master
= p
->parent
->dst
->master_netdev
;
66 if (!(master
->flags
& IFF_UP
))
69 if (compare_ether_addr(dev
->dev_addr
, master
->dev_addr
)) {
70 err
= dev_unicast_add(master
, dev
->dev_addr
, ETH_ALEN
);
75 if (dev
->flags
& IFF_ALLMULTI
) {
76 err
= dev_set_allmulti(master
, 1);
80 if (dev
->flags
& IFF_PROMISC
) {
81 err
= dev_set_promiscuity(master
, 1);
89 if (dev
->flags
& IFF_ALLMULTI
)
90 dev_set_allmulti(master
, -1);
92 if (compare_ether_addr(dev
->dev_addr
, master
->dev_addr
))
93 dev_unicast_delete(master
, dev
->dev_addr
, ETH_ALEN
);
98 static int dsa_slave_close(struct net_device
*dev
)
100 struct dsa_slave_priv
*p
= netdev_priv(dev
);
101 struct net_device
*master
= p
->parent
->dst
->master_netdev
;
103 dev_mc_unsync(master
, dev
);
104 dev_unicast_unsync(master
, dev
);
105 if (dev
->flags
& IFF_ALLMULTI
)
106 dev_set_allmulti(master
, -1);
107 if (dev
->flags
& IFF_PROMISC
)
108 dev_set_promiscuity(master
, -1);
110 if (compare_ether_addr(dev
->dev_addr
, master
->dev_addr
))
111 dev_unicast_delete(master
, dev
->dev_addr
, ETH_ALEN
);
116 static void dsa_slave_change_rx_flags(struct net_device
*dev
, int change
)
118 struct dsa_slave_priv
*p
= netdev_priv(dev
);
119 struct net_device
*master
= p
->parent
->dst
->master_netdev
;
121 if (change
& IFF_ALLMULTI
)
122 dev_set_allmulti(master
, dev
->flags
& IFF_ALLMULTI
? 1 : -1);
123 if (change
& IFF_PROMISC
)
124 dev_set_promiscuity(master
, dev
->flags
& IFF_PROMISC
? 1 : -1);
127 static void dsa_slave_set_rx_mode(struct net_device
*dev
)
129 struct dsa_slave_priv
*p
= netdev_priv(dev
);
130 struct net_device
*master
= p
->parent
->dst
->master_netdev
;
132 dev_mc_sync(master
, dev
);
133 dev_unicast_sync(master
, dev
);
136 static int dsa_slave_set_mac_address(struct net_device
*dev
, void *a
)
138 struct dsa_slave_priv
*p
= netdev_priv(dev
);
139 struct net_device
*master
= p
->parent
->dst
->master_netdev
;
140 struct sockaddr
*addr
= a
;
143 if (!is_valid_ether_addr(addr
->sa_data
))
144 return -EADDRNOTAVAIL
;
146 if (!(dev
->flags
& IFF_UP
))
149 if (compare_ether_addr(addr
->sa_data
, master
->dev_addr
)) {
150 err
= dev_unicast_add(master
, addr
->sa_data
, ETH_ALEN
);
155 if (compare_ether_addr(dev
->dev_addr
, master
->dev_addr
))
156 dev_unicast_delete(master
, dev
->dev_addr
, ETH_ALEN
);
159 memcpy(dev
->dev_addr
, addr
->sa_data
, ETH_ALEN
);
164 static int dsa_slave_ioctl(struct net_device
*dev
, struct ifreq
*ifr
, int cmd
)
166 struct dsa_slave_priv
*p
= netdev_priv(dev
);
167 struct mii_ioctl_data
*mii_data
= if_mii(ifr
);
170 return phy_mii_ioctl(p
->phy
, mii_data
, cmd
);
176 /* ethtool operations *******************************************************/
178 dsa_slave_get_settings(struct net_device
*dev
, struct ethtool_cmd
*cmd
)
180 struct dsa_slave_priv
*p
= netdev_priv(dev
);
184 if (p
->phy
!= NULL
) {
185 err
= phy_read_status(p
->phy
);
187 err
= phy_ethtool_gset(p
->phy
, cmd
);
194 dsa_slave_set_settings(struct net_device
*dev
, struct ethtool_cmd
*cmd
)
196 struct dsa_slave_priv
*p
= netdev_priv(dev
);
199 return phy_ethtool_sset(p
->phy
, cmd
);
204 static void dsa_slave_get_drvinfo(struct net_device
*dev
,
205 struct ethtool_drvinfo
*drvinfo
)
207 strncpy(drvinfo
->driver
, "dsa", 32);
208 strncpy(drvinfo
->version
, dsa_driver_version
, 32);
209 strncpy(drvinfo
->fw_version
, "N/A", 32);
210 strncpy(drvinfo
->bus_info
, "platform", 32);
213 static int dsa_slave_nway_reset(struct net_device
*dev
)
215 struct dsa_slave_priv
*p
= netdev_priv(dev
);
218 return genphy_restart_aneg(p
->phy
);
223 static u32
dsa_slave_get_link(struct net_device
*dev
)
225 struct dsa_slave_priv
*p
= netdev_priv(dev
);
227 if (p
->phy
!= NULL
) {
228 genphy_update_link(p
->phy
);
235 static void dsa_slave_get_strings(struct net_device
*dev
,
236 uint32_t stringset
, uint8_t *data
)
238 struct dsa_slave_priv
*p
= netdev_priv(dev
);
239 struct dsa_switch
*ds
= p
->parent
;
241 if (stringset
== ETH_SS_STATS
) {
242 int len
= ETH_GSTRING_LEN
;
244 strncpy(data
, "tx_packets", len
);
245 strncpy(data
+ len
, "tx_bytes", len
);
246 strncpy(data
+ 2 * len
, "rx_packets", len
);
247 strncpy(data
+ 3 * len
, "rx_bytes", len
);
248 if (ds
->drv
->get_strings
!= NULL
)
249 ds
->drv
->get_strings(ds
, p
->port
, data
+ 4 * len
);
253 static void dsa_slave_get_ethtool_stats(struct net_device
*dev
,
254 struct ethtool_stats
*stats
,
257 struct dsa_slave_priv
*p
= netdev_priv(dev
);
258 struct dsa_switch
*ds
= p
->parent
;
260 data
[0] = p
->dev
->stats
.tx_packets
;
261 data
[1] = p
->dev
->stats
.tx_bytes
;
262 data
[2] = p
->dev
->stats
.rx_packets
;
263 data
[3] = p
->dev
->stats
.rx_bytes
;
264 if (ds
->drv
->get_ethtool_stats
!= NULL
)
265 ds
->drv
->get_ethtool_stats(ds
, p
->port
, data
+ 4);
268 static int dsa_slave_get_sset_count(struct net_device
*dev
, int sset
)
270 struct dsa_slave_priv
*p
= netdev_priv(dev
);
271 struct dsa_switch
*ds
= p
->parent
;
273 if (sset
== ETH_SS_STATS
) {
277 if (ds
->drv
->get_sset_count
!= NULL
)
278 count
+= ds
->drv
->get_sset_count(ds
);
286 static const struct ethtool_ops dsa_slave_ethtool_ops
= {
287 .get_settings
= dsa_slave_get_settings
,
288 .set_settings
= dsa_slave_set_settings
,
289 .get_drvinfo
= dsa_slave_get_drvinfo
,
290 .nway_reset
= dsa_slave_nway_reset
,
291 .get_link
= dsa_slave_get_link
,
292 .set_sg
= ethtool_op_set_sg
,
293 .get_strings
= dsa_slave_get_strings
,
294 .get_ethtool_stats
= dsa_slave_get_ethtool_stats
,
295 .get_sset_count
= dsa_slave_get_sset_count
,
298 #ifdef CONFIG_NET_DSA_TAG_DSA
299 static const struct net_device_ops dsa_netdev_ops
= {
300 .ndo_init
= dsa_slave_init
,
301 .ndo_open
= dsa_slave_open
,
302 .ndo_stop
= dsa_slave_close
,
303 .ndo_start_xmit
= dsa_xmit
,
304 .ndo_change_rx_flags
= dsa_slave_change_rx_flags
,
305 .ndo_set_rx_mode
= dsa_slave_set_rx_mode
,
306 .ndo_set_multicast_list
= dsa_slave_set_rx_mode
,
307 .ndo_set_mac_address
= dsa_slave_set_mac_address
,
308 .ndo_do_ioctl
= dsa_slave_ioctl
,
311 #ifdef CONFIG_NET_DSA_TAG_EDSA
312 static const struct net_device_ops edsa_netdev_ops
= {
313 .ndo_init
= dsa_slave_init
,
314 .ndo_open
= dsa_slave_open
,
315 .ndo_stop
= dsa_slave_close
,
316 .ndo_start_xmit
= edsa_xmit
,
317 .ndo_change_rx_flags
= dsa_slave_change_rx_flags
,
318 .ndo_set_rx_mode
= dsa_slave_set_rx_mode
,
319 .ndo_set_multicast_list
= dsa_slave_set_rx_mode
,
320 .ndo_set_mac_address
= dsa_slave_set_mac_address
,
321 .ndo_do_ioctl
= dsa_slave_ioctl
,
324 #ifdef CONFIG_NET_DSA_TAG_TRAILER
325 static const struct net_device_ops trailer_netdev_ops
= {
326 .ndo_init
= dsa_slave_init
,
327 .ndo_open
= dsa_slave_open
,
328 .ndo_stop
= dsa_slave_close
,
329 .ndo_start_xmit
= trailer_xmit
,
330 .ndo_change_rx_flags
= dsa_slave_change_rx_flags
,
331 .ndo_set_rx_mode
= dsa_slave_set_rx_mode
,
332 .ndo_set_multicast_list
= dsa_slave_set_rx_mode
,
333 .ndo_set_mac_address
= dsa_slave_set_mac_address
,
334 .ndo_do_ioctl
= dsa_slave_ioctl
,
338 /* slave device setup *******************************************************/
340 dsa_slave_create(struct dsa_switch
*ds
, struct device
*parent
,
341 int port
, char *name
)
343 struct net_device
*master
= ds
->dst
->master_netdev
;
344 struct net_device
*slave_dev
;
345 struct dsa_slave_priv
*p
;
348 slave_dev
= alloc_netdev(sizeof(struct dsa_slave_priv
),
350 if (slave_dev
== NULL
)
353 slave_dev
->features
= master
->vlan_features
;
354 SET_ETHTOOL_OPS(slave_dev
, &dsa_slave_ethtool_ops
);
355 memcpy(slave_dev
->dev_addr
, master
->dev_addr
, ETH_ALEN
);
356 slave_dev
->tx_queue_len
= 0;
358 switch (ds
->dst
->tag_protocol
) {
359 #ifdef CONFIG_NET_DSA_TAG_DSA
360 case htons(ETH_P_DSA
):
361 slave_dev
->netdev_ops
= &dsa_netdev_ops
;
364 #ifdef CONFIG_NET_DSA_TAG_EDSA
365 case htons(ETH_P_EDSA
):
366 slave_dev
->netdev_ops
= &edsa_netdev_ops
;
369 #ifdef CONFIG_NET_DSA_TAG_TRAILER
370 case htons(ETH_P_TRAILER
):
371 slave_dev
->netdev_ops
= &trailer_netdev_ops
;
378 SET_NETDEV_DEV(slave_dev
, parent
);
379 slave_dev
->vlan_features
= master
->vlan_features
;
381 p
= netdev_priv(slave_dev
);
385 p
->phy
= ds
->slave_mii_bus
->phy_map
[port
];
387 ret
= register_netdev(slave_dev
);
389 printk(KERN_ERR
"%s: error %d registering interface %s\n",
390 master
->name
, ret
, slave_dev
->name
);
391 free_netdev(slave_dev
);
395 netif_carrier_off(slave_dev
);
397 if (p
->phy
!= NULL
) {
398 phy_attach(slave_dev
, dev_name(&p
->phy
->dev
),
399 0, PHY_INTERFACE_MODE_GMII
);
401 p
->phy
->autoneg
= AUTONEG_ENABLE
;
404 p
->phy
->advertising
= p
->phy
->supported
| ADVERTISED_Autoneg
;
405 phy_start_aneg(p
->phy
);