1 /* This program is free software; you can redistribute it and/or modify
2 * it under the terms of the GNU General Public License as published by
3 * the Free Software Foundation; version 2 of the License
5 * This program is distributed in the hope that it will be useful,
6 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8 * GNU General Public License for more details.
10 * Copyright (C) 2009-2015 John Crispin <blogic@openwrt.org>
11 * Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
12 * Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
15 #include "mtk_eth_soc.h"
17 static const char fe_gdma_str
[][ETH_GSTRING_LEN
] = {
18 #define _FE(x...) # x,
23 static int fe_get_settings(struct net_device
*dev
,
24 struct ethtool_cmd
*cmd
)
26 struct fe_priv
*priv
= netdev_priv(dev
);
32 if (priv
->phy_flags
== FE_PHY_FLAG_ATTACH
) {
33 err
= phy_read_status(priv
->phy_dev
);
38 return phy_ethtool_gset(priv
->phy_dev
, cmd
);
44 static int fe_set_settings(struct net_device
*dev
,
45 struct ethtool_cmd
*cmd
)
47 struct fe_priv
*priv
= netdev_priv(dev
);
52 if (cmd
->phy_address
!= priv
->phy_dev
->mdio
.addr
) {
53 if (priv
->phy
->phy_node
[cmd
->phy_address
]) {
54 priv
->phy_dev
= priv
->phy
->phy
[cmd
->phy_address
];
55 priv
->phy_flags
= FE_PHY_FLAG_PORT
;
56 } else if (priv
->mii_bus
&& mdiobus_get_phy(priv
->mii_bus
, cmd
->phy_address
)) {
57 priv
->phy_dev
= mdiobus_get_phy(priv
->mii_bus
, cmd
->phy_address
);
58 priv
->phy_flags
= FE_PHY_FLAG_ATTACH
;
64 return phy_ethtool_sset(priv
->phy_dev
, cmd
);
70 static void fe_get_drvinfo(struct net_device
*dev
,
71 struct ethtool_drvinfo
*info
)
73 struct fe_priv
*priv
= netdev_priv(dev
);
74 struct fe_soc_data
*soc
= priv
->soc
;
76 strlcpy(info
->driver
, priv
->device
->driver
->name
, sizeof(info
->driver
));
77 strlcpy(info
->version
, MTK_FE_DRV_VERSION
, sizeof(info
->version
));
78 strlcpy(info
->bus_info
, dev_name(priv
->device
), sizeof(info
->bus_info
));
80 if (soc
->reg_table
[FE_REG_FE_COUNTER_BASE
])
81 info
->n_stats
= ARRAY_SIZE(fe_gdma_str
);
84 static u32
fe_get_msglevel(struct net_device
*dev
)
86 struct fe_priv
*priv
= netdev_priv(dev
);
88 return priv
->msg_enable
;
91 static void fe_set_msglevel(struct net_device
*dev
, u32 value
)
93 struct fe_priv
*priv
= netdev_priv(dev
);
95 priv
->msg_enable
= value
;
98 static int fe_nway_reset(struct net_device
*dev
)
100 struct fe_priv
*priv
= netdev_priv(dev
);
105 return genphy_restart_aneg(priv
->phy_dev
);
111 static u32
fe_get_link(struct net_device
*dev
)
113 struct fe_priv
*priv
= netdev_priv(dev
);
119 if (priv
->phy_flags
== FE_PHY_FLAG_ATTACH
) {
120 err
= genphy_update_link(priv
->phy_dev
);
125 return priv
->phy_dev
->link
;
128 return ethtool_op_get_link(dev
);
131 static int fe_set_ringparam(struct net_device
*dev
,
132 struct ethtool_ringparam
*ring
)
134 struct fe_priv
*priv
= netdev_priv(dev
);
136 if ((ring
->tx_pending
< 2) ||
137 (ring
->rx_pending
< 2) ||
138 (ring
->rx_pending
> MAX_DMA_DESC
) ||
139 (ring
->tx_pending
> MAX_DMA_DESC
))
142 dev
->netdev_ops
->ndo_stop(dev
);
144 priv
->tx_ring
.tx_ring_size
= BIT(fls(ring
->tx_pending
) - 1);
145 priv
->rx_ring
.rx_ring_size
= BIT(fls(ring
->rx_pending
) - 1);
147 dev
->netdev_ops
->ndo_open(dev
);
152 static void fe_get_ringparam(struct net_device
*dev
,
153 struct ethtool_ringparam
*ring
)
155 struct fe_priv
*priv
= netdev_priv(dev
);
157 ring
->rx_max_pending
= MAX_DMA_DESC
;
158 ring
->tx_max_pending
= MAX_DMA_DESC
;
159 ring
->rx_pending
= priv
->rx_ring
.rx_ring_size
;
160 ring
->tx_pending
= priv
->tx_ring
.tx_ring_size
;
163 static void fe_get_strings(struct net_device
*dev
, u32 stringset
, u8
*data
)
167 memcpy(data
, *fe_gdma_str
, sizeof(fe_gdma_str
));
172 static int fe_get_sset_count(struct net_device
*dev
, int sset
)
176 return ARRAY_SIZE(fe_gdma_str
);
182 static void fe_get_ethtool_stats(struct net_device
*dev
,
183 struct ethtool_stats
*stats
, u64
*data
)
185 struct fe_priv
*priv
= netdev_priv(dev
);
186 struct fe_hw_stats
*hwstats
= priv
->hw_stats
;
187 u64
*data_src
, *data_dst
;
191 if (netif_running(dev
) && netif_device_present(dev
)) {
192 if (spin_trylock(&hwstats
->stats_lock
)) {
193 fe_stats_update(priv
);
194 spin_unlock(&hwstats
->stats_lock
);
199 data_src
= &hwstats
->tx_bytes
;
201 start
= u64_stats_fetch_begin_irq(&hwstats
->syncp
);
203 for (i
= 0; i
< ARRAY_SIZE(fe_gdma_str
); i
++)
204 *data_dst
++ = *data_src
++;
206 } while (u64_stats_fetch_retry_irq(&hwstats
->syncp
, start
));
209 static struct ethtool_ops fe_ethtool_ops
= {
210 .get_settings
= fe_get_settings
,
211 .set_settings
= fe_set_settings
,
212 .get_drvinfo
= fe_get_drvinfo
,
213 .get_msglevel
= fe_get_msglevel
,
214 .set_msglevel
= fe_set_msglevel
,
215 .nway_reset
= fe_nway_reset
,
216 .get_link
= fe_get_link
,
217 .set_ringparam
= fe_set_ringparam
,
218 .get_ringparam
= fe_get_ringparam
,
221 void fe_set_ethtool_ops(struct net_device
*netdev
)
223 struct fe_priv
*priv
= netdev_priv(netdev
);
224 struct fe_soc_data
*soc
= priv
->soc
;
226 if (soc
->reg_table
[FE_REG_FE_COUNTER_BASE
]) {
227 fe_ethtool_ops
.get_strings
= fe_get_strings
;
228 fe_ethtool_ops
.get_sset_count
= fe_get_sset_count
;
229 fe_ethtool_ops
.get_ethtool_stats
= fe_get_ethtool_stats
;
232 netdev
->ethtool_ops
= &fe_ethtool_ops
;