2 * Handling of a master device, switching frames via its switch fabric CPU port
4 * Copyright (c) 2017 Savoir-faire Linux Inc.
5 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
15 static void dsa_master_get_ethtool_stats(struct net_device
*dev
,
16 struct ethtool_stats
*stats
,
19 struct dsa_port
*cpu_dp
= dev
->dsa_ptr
;
20 const struct ethtool_ops
*ops
= cpu_dp
->orig_ethtool_ops
;
21 struct dsa_switch
*ds
= cpu_dp
->ds
;
22 int port
= cpu_dp
->index
;
25 if (ops
->get_sset_count
&& ops
->get_ethtool_stats
) {
26 count
= ops
->get_sset_count(dev
, ETH_SS_STATS
);
27 ops
->get_ethtool_stats(dev
, stats
, data
);
30 if (ds
->ops
->get_ethtool_stats
)
31 ds
->ops
->get_ethtool_stats(ds
, port
, data
+ count
);
34 static void dsa_master_get_ethtool_phy_stats(struct net_device
*dev
,
35 struct ethtool_stats
*stats
,
38 struct dsa_port
*cpu_dp
= dev
->dsa_ptr
;
39 const struct ethtool_ops
*ops
= cpu_dp
->orig_ethtool_ops
;
40 struct dsa_switch
*ds
= cpu_dp
->ds
;
41 int port
= cpu_dp
->index
;
44 if (dev
->phydev
&& !ops
->get_ethtool_phy_stats
) {
45 count
= phy_ethtool_get_sset_count(dev
->phydev
);
47 phy_ethtool_get_stats(dev
->phydev
, stats
, data
);
48 } else if (ops
->get_sset_count
&& ops
->get_ethtool_phy_stats
) {
49 count
= ops
->get_sset_count(dev
, ETH_SS_PHY_STATS
);
50 ops
->get_ethtool_phy_stats(dev
, stats
, data
);
56 if (ds
->ops
->get_ethtool_phy_stats
)
57 ds
->ops
->get_ethtool_phy_stats(ds
, port
, data
+ count
);
60 static int dsa_master_get_sset_count(struct net_device
*dev
, int sset
)
62 struct dsa_port
*cpu_dp
= dev
->dsa_ptr
;
63 const struct ethtool_ops
*ops
= cpu_dp
->orig_ethtool_ops
;
64 struct dsa_switch
*ds
= cpu_dp
->ds
;
67 if (sset
== ETH_SS_PHY_STATS
&& dev
->phydev
&&
68 !ops
->get_ethtool_phy_stats
)
69 count
= phy_ethtool_get_sset_count(dev
->phydev
);
70 else if (ops
->get_sset_count
)
71 count
= ops
->get_sset_count(dev
, sset
);
76 if (ds
->ops
->get_sset_count
)
77 count
+= ds
->ops
->get_sset_count(ds
, cpu_dp
->index
, sset
);
82 static void dsa_master_get_strings(struct net_device
*dev
, uint32_t stringset
,
85 struct dsa_port
*cpu_dp
= dev
->dsa_ptr
;
86 const struct ethtool_ops
*ops
= cpu_dp
->orig_ethtool_ops
;
87 struct dsa_switch
*ds
= cpu_dp
->ds
;
88 int port
= cpu_dp
->index
;
89 int len
= ETH_GSTRING_LEN
;
90 int mcount
= 0, count
;
95 snprintf(pfx
, sizeof(pfx
), "p%.2d", port
);
96 /* We do not want to be NULL-terminated, since this is a prefix */
97 pfx
[sizeof(pfx
) - 1] = '_';
99 if (stringset
== ETH_SS_PHY_STATS
&& dev
->phydev
&&
100 !ops
->get_ethtool_phy_stats
) {
101 mcount
= phy_ethtool_get_sset_count(dev
->phydev
);
105 phy_ethtool_get_strings(dev
->phydev
, data
);
106 } else if (ops
->get_sset_count
&& ops
->get_strings
) {
107 mcount
= ops
->get_sset_count(dev
, stringset
);
110 ops
->get_strings(dev
, stringset
, data
);
113 if (ds
->ops
->get_strings
) {
114 ndata
= data
+ mcount
* len
;
115 /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle
116 * the output after to prepend our CPU port prefix we
117 * constructed earlier
119 ds
->ops
->get_strings(ds
, port
, stringset
, ndata
);
120 count
= ds
->ops
->get_sset_count(ds
, port
, stringset
);
121 for (i
= 0; i
< count
; i
++) {
122 memmove(ndata
+ (i
* len
+ sizeof(pfx
)),
123 ndata
+ i
* len
, len
- sizeof(pfx
));
124 memcpy(ndata
+ i
* len
, pfx
, sizeof(pfx
));
129 static int dsa_master_ethtool_setup(struct net_device
*dev
)
131 struct dsa_port
*cpu_dp
= dev
->dsa_ptr
;
132 struct dsa_switch
*ds
= cpu_dp
->ds
;
133 struct ethtool_ops
*ops
;
135 ops
= devm_kzalloc(ds
->dev
, sizeof(*ops
), GFP_KERNEL
);
139 cpu_dp
->orig_ethtool_ops
= dev
->ethtool_ops
;
140 if (cpu_dp
->orig_ethtool_ops
)
141 memcpy(ops
, cpu_dp
->orig_ethtool_ops
, sizeof(*ops
));
143 ops
->get_sset_count
= dsa_master_get_sset_count
;
144 ops
->get_ethtool_stats
= dsa_master_get_ethtool_stats
;
145 ops
->get_strings
= dsa_master_get_strings
;
146 ops
->get_ethtool_phy_stats
= dsa_master_get_ethtool_phy_stats
;
148 dev
->ethtool_ops
= ops
;
153 static void dsa_master_ethtool_teardown(struct net_device
*dev
)
155 struct dsa_port
*cpu_dp
= dev
->dsa_ptr
;
157 dev
->ethtool_ops
= cpu_dp
->orig_ethtool_ops
;
158 cpu_dp
->orig_ethtool_ops
= NULL
;
161 static ssize_t
tagging_show(struct device
*d
, struct device_attribute
*attr
,
164 struct net_device
*dev
= to_net_dev(d
);
165 struct dsa_port
*cpu_dp
= dev
->dsa_ptr
;
167 return sprintf(buf
, "%s\n",
168 dsa_tag_protocol_to_str(cpu_dp
->tag_ops
));
170 static DEVICE_ATTR_RO(tagging
);
172 static struct attribute
*dsa_slave_attrs
[] = {
173 &dev_attr_tagging
.attr
,
177 static const struct attribute_group dsa_group
= {
179 .attrs
= dsa_slave_attrs
,
182 int dsa_master_setup(struct net_device
*dev
, struct dsa_port
*cpu_dp
)
186 /* If we use a tagging format that doesn't have an ethertype
187 * field, make sure that all packets from this point on get
188 * sent to the tag format's receive function.
192 dev
->dsa_ptr
= cpu_dp
;
194 ret
= dsa_master_ethtool_setup(dev
);
198 ret
= sysfs_create_group(&dev
->dev
.kobj
, &dsa_group
);
200 dsa_master_ethtool_teardown(dev
);
205 void dsa_master_teardown(struct net_device
*dev
)
207 sysfs_remove_group(&dev
->dev
.kobj
, &dsa_group
);
208 dsa_master_ethtool_teardown(dev
);
212 /* If we used a tagging format that doesn't have an ethertype
213 * field, make sure that all packets from this point get sent
214 * without the tag and go through the regular receive path.