2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; version 2 of the License
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
15 * Copyright (C) 2009-2013 Michael Lee <igvtee@gmail.com>
18 #include "ralink_soc_eth.h"
20 static const char fe_gdma_str
[][ETH_GSTRING_LEN
] = {
21 #define _FE(x...) # x,
26 static int fe_get_settings(struct net_device
*dev
,
27 struct ethtool_cmd
*cmd
)
29 struct fe_priv
*priv
= netdev_priv(dev
);
35 if (priv
->phy_flags
== FE_PHY_FLAG_ATTACH
) {
36 err
= phy_read_status(priv
->phy_dev
);
41 return phy_ethtool_gset(priv
->phy_dev
, cmd
);
47 static int fe_set_settings(struct net_device
*dev
,
48 struct ethtool_cmd
*cmd
)
50 struct fe_priv
*priv
= netdev_priv(dev
);
55 if (cmd
->phy_address
!= priv
->phy_dev
->addr
) {
56 if (priv
->phy
->phy_node
[cmd
->phy_address
]) {
57 priv
->phy_dev
= priv
->phy
->phy
[cmd
->phy_address
];
58 priv
->phy_flags
= FE_PHY_FLAG_PORT
;
59 } else if (priv
->mii_bus
&&
60 priv
->mii_bus
->phy_map
[cmd
->phy_address
]) {
61 priv
->phy_dev
= priv
->mii_bus
->phy_map
[cmd
->phy_address
];
62 priv
->phy_flags
= FE_PHY_FLAG_ATTACH
;
67 return phy_ethtool_sset(priv
->phy_dev
, cmd
);
73 static void fe_get_drvinfo (struct net_device
*dev
,
74 struct ethtool_drvinfo
*info
)
76 struct fe_priv
*priv
= netdev_priv(dev
);
77 struct fe_soc_data
*soc
= priv
->soc
;
79 strlcpy(info
->driver
, priv
->device
->driver
->name
, sizeof(info
->driver
));
80 strlcpy(info
->version
, FE_DRV_VERSION
, sizeof(info
->version
));
81 strlcpy(info
->bus_info
, dev_name(priv
->device
), sizeof(info
->bus_info
));
83 if (soc
->reg_table
[FE_REG_FE_COUNTER_BASE
])
84 info
->n_stats
= ARRAY_SIZE(fe_gdma_str
);
87 static u32
fe_get_msglevel(struct net_device
*dev
)
89 struct fe_priv
*priv
= netdev_priv(dev
);
91 return priv
->msg_enable
;
94 static void fe_set_msglevel(struct net_device
*dev
, u32 value
)
96 struct fe_priv
*priv
= netdev_priv(dev
);
98 priv
->msg_enable
= value
;
101 static int fe_nway_reset(struct net_device
*dev
)
103 struct fe_priv
*priv
= netdev_priv(dev
);
108 return genphy_restart_aneg(priv
->phy_dev
);
114 static u32
fe_get_link(struct net_device
*dev
)
116 struct fe_priv
*priv
= netdev_priv(dev
);
122 if (priv
->phy_flags
== FE_PHY_FLAG_ATTACH
) {
123 err
= genphy_update_link(priv
->phy_dev
);
128 return priv
->phy_dev
->link
;
131 return ethtool_op_get_link(dev
);
134 static void fe_get_ringparam(struct net_device
*dev
,
135 struct ethtool_ringparam
*ring
)
137 ring
->rx_max_pending
= MAX_DMA_DESC
;
138 ring
->tx_max_pending
= MAX_DMA_DESC
;
139 ring
->rx_pending
= NUM_DMA_DESC
;
140 ring
->tx_pending
= NUM_DMA_DESC
;
143 static int fe_get_coalesce(struct net_device
*dev
,
144 struct ethtool_coalesce
*coal
)
146 u32 delay_cfg
= fe_reg_r32(FE_REG_DLY_INT_CFG
);
148 coal
->rx_coalesce_usecs
= (delay_cfg
& 0xff) * FE_DELAY_TIME
;
149 coal
->rx_max_coalesced_frames
= ((delay_cfg
>> 8) & 0x7f);
150 coal
->use_adaptive_rx_coalesce
= (delay_cfg
>> 15) & 0x1;
152 coal
->tx_coalesce_usecs
= ((delay_cfg
>> 16 )& 0xff) * FE_DELAY_TIME
;
153 coal
->tx_max_coalesced_frames
= ((delay_cfg
>> 24) & 0x7f);
154 coal
->use_adaptive_tx_coalesce
= (delay_cfg
>> 31) & 0x1;
159 static int fe_set_coalesce(struct net_device
*dev
,
160 struct ethtool_coalesce
*coal
)
163 u32 rx_usecs
, tx_usecs
;
164 u32 rx_frames
, tx_frames
;
166 if (!coal
->use_adaptive_rx_coalesce
|| !coal
->use_adaptive_tx_coalesce
)
169 rx_usecs
= DIV_ROUND_UP(coal
->rx_coalesce_usecs
, FE_DELAY_TIME
);
170 rx_frames
= coal
->rx_max_coalesced_frames
;
171 tx_usecs
= DIV_ROUND_UP(coal
->tx_coalesce_usecs
, FE_DELAY_TIME
);
172 tx_frames
= coal
->tx_max_coalesced_frames
;
174 if (((tx_usecs
== 0) && (tx_frames
==0)) ||
175 ((rx_usecs
== 0) && (rx_frames
==0)))
178 if (rx_usecs
> 0xff) rx_usecs
= 0xff;
179 if (rx_frames
> 0x7f) rx_frames
= 0x7f;
180 if (tx_usecs
> 0xff) tx_usecs
= 0xff;
181 if (tx_frames
> 0x7f) tx_frames
= 0x7f;
183 delay_cfg
= ((((FE_DELAY_EN_INT
| tx_frames
) << 8) | tx_usecs
) << 16) |
184 (((FE_DELAY_EN_INT
| rx_frames
) << 8) | rx_usecs
);
186 fe_reg_w32(delay_cfg
, FE_REG_DLY_INT_CFG
);
191 static void fe_get_strings(struct net_device
*dev
, u32 stringset
, u8
*data
)
195 memcpy(data
, *fe_gdma_str
, sizeof(fe_gdma_str
));
200 static int fe_get_sset_count(struct net_device
*dev
, int sset
)
204 return ARRAY_SIZE(fe_gdma_str
);
210 static void fe_get_ethtool_stats(struct net_device
*dev
,
211 struct ethtool_stats
*stats
, u64
*data
)
213 struct fe_priv
*priv
= netdev_priv(dev
);
214 struct fe_hw_stats
*hwstats
= priv
->hw_stats
;
215 u64
*data_src
, *data_dst
;
219 if (netif_running(dev
) && netif_device_present(dev
)) {
220 if (spin_trylock(&hwstats
->stats_lock
)) {
221 fe_stats_update(priv
);
222 spin_unlock(&hwstats
->stats_lock
);
227 data_src
= &hwstats
->tx_bytes
;
229 start
= u64_stats_fetch_begin_bh(&hwstats
->syncp
);
231 for (i
= 0; i
< ARRAY_SIZE(fe_gdma_str
); i
++)
232 *data_dst
++ = *data_src
++;
234 } while (u64_stats_fetch_retry_bh(&hwstats
->syncp
, start
));
237 static struct ethtool_ops fe_ethtool_ops
= {
238 .get_settings
= fe_get_settings
,
239 .set_settings
= fe_set_settings
,
240 .get_drvinfo
= fe_get_drvinfo
,
241 .get_msglevel
= fe_get_msglevel
,
242 .set_msglevel
= fe_set_msglevel
,
243 .nway_reset
= fe_nway_reset
,
244 .get_link
= fe_get_link
,
245 .get_ringparam
= fe_get_ringparam
,
246 .get_coalesce
= fe_get_coalesce
,
247 .set_coalesce
= fe_set_coalesce
,
250 void fe_set_ethtool_ops(struct net_device
*netdev
)
252 struct fe_priv
*priv
= netdev_priv(netdev
);
253 struct fe_soc_data
*soc
= priv
->soc
;
255 if (soc
->reg_table
[FE_REG_FE_COUNTER_BASE
]) {
256 fe_ethtool_ops
.get_strings
= fe_get_strings
;
257 fe_ethtool_ops
.get_sset_count
= fe_get_sset_count
;
258 fe_ethtool_ops
.get_ethtool_stats
= fe_get_ethtool_stats
;
261 SET_ETHTOOL_OPS(netdev
, &fe_ethtool_ops
);