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 void fe_get_strings(struct net_device
*dev
, u32 stringset
, u8
*data
)
147 memcpy(data
, *fe_gdma_str
, sizeof(fe_gdma_str
));
152 static int fe_get_sset_count(struct net_device
*dev
, int sset
)
156 return ARRAY_SIZE(fe_gdma_str
);
162 static void fe_get_ethtool_stats(struct net_device
*dev
,
163 struct ethtool_stats
*stats
, u64
*data
)
165 struct fe_priv
*priv
= netdev_priv(dev
);
166 struct fe_hw_stats
*hwstats
= priv
->hw_stats
;
167 u64
*data_src
, *data_dst
;
171 if (netif_running(dev
) && netif_device_present(dev
)) {
172 if (spin_trylock(&hwstats
->stats_lock
)) {
173 fe_stats_update(priv
);
174 spin_unlock(&hwstats
->stats_lock
);
179 data_src
= &hwstats
->tx_bytes
;
181 start
= u64_stats_fetch_begin_bh(&hwstats
->syncp
);
183 for (i
= 0; i
< ARRAY_SIZE(fe_gdma_str
); i
++)
184 *data_dst
++ = *data_src
++;
186 } while (u64_stats_fetch_retry_bh(&hwstats
->syncp
, start
));
189 static struct ethtool_ops fe_ethtool_ops
= {
190 .get_settings
= fe_get_settings
,
191 .set_settings
= fe_set_settings
,
192 .get_drvinfo
= fe_get_drvinfo
,
193 .get_msglevel
= fe_get_msglevel
,
194 .set_msglevel
= fe_set_msglevel
,
195 .nway_reset
= fe_nway_reset
,
196 .get_link
= fe_get_link
,
197 .get_ringparam
= fe_get_ringparam
,
200 void fe_set_ethtool_ops(struct net_device
*netdev
)
202 struct fe_priv
*priv
= netdev_priv(netdev
);
203 struct fe_soc_data
*soc
= priv
->soc
;
205 if (soc
->reg_table
[FE_REG_FE_COUNTER_BASE
]) {
206 fe_ethtool_ops
.get_strings
= fe_get_strings
;
207 fe_ethtool_ops
.get_sset_count
= fe_get_sset_count
;
208 fe_ethtool_ops
.get_ethtool_stats
= fe_get_ethtool_stats
;
211 netdev
->ethtool_ops
= &fe_ethtool_ops
;