| /* | 
 |  * Applied Micro X-Gene SoC Ethernet v2 Driver | 
 |  * | 
 |  * Copyright (c) 2017, Applied Micro Circuits Corporation | 
 |  * Author(s): Iyappan Subramanian <isubramanian@apm.com> | 
 |  *	      Keyur Chudgar <kchudgar@apm.com> | 
 |  * | 
 |  * This program is free software; you can redistribute  it and/or modify it | 
 |  * under  the terms of  the GNU General  Public License as published by the | 
 |  * Free Software Foundation;  either version 2 of the  License, or (at your | 
 |  * option) any later version. | 
 |  * | 
 |  * This program is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
 |  * GNU General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU General Public License | 
 |  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
 |  */ | 
 |  | 
 | #include "main.h" | 
 |  | 
 | #define XGE_STAT(m)		{ #m, offsetof(struct xge_pdata, stats.m) } | 
 | #define XGE_EXTD_STAT(m, n)					\ | 
 | 	{							\ | 
 | 		#m,						\ | 
 | 		n,						\ | 
 | 		0						\ | 
 | 	} | 
 |  | 
 | static const struct xge_gstrings_stats gstrings_stats[] = { | 
 | 	XGE_STAT(rx_packets), | 
 | 	XGE_STAT(tx_packets), | 
 | 	XGE_STAT(rx_bytes), | 
 | 	XGE_STAT(tx_bytes), | 
 | 	XGE_STAT(rx_errors) | 
 | }; | 
 |  | 
 | static struct xge_gstrings_extd_stats gstrings_extd_stats[] = { | 
 | 	XGE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64), | 
 | 	XGE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127), | 
 | 	XGE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255), | 
 | 	XGE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511), | 
 | 	XGE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K), | 
 | 	XGE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX), | 
 | 	XGE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV), | 
 | 	XGE_EXTD_STAT(rx_fcs_error_cntr, RFCS), | 
 | 	XGE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA), | 
 | 	XGE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA), | 
 | 	XGE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF), | 
 | 	XGE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF), | 
 | 	XGE_EXTD_STAT(rx_unk_opcode_cntr, RXUO), | 
 | 	XGE_EXTD_STAT(rx_align_err_cntr, RALN), | 
 | 	XGE_EXTD_STAT(rx_frame_len_err_cntr, RFLR), | 
 | 	XGE_EXTD_STAT(rx_code_err_cntr, RCDE), | 
 | 	XGE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE), | 
 | 	XGE_EXTD_STAT(rx_undersize_pkt_cntr, RUND), | 
 | 	XGE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR), | 
 | 	XGE_EXTD_STAT(rx_fragments_cntr, RFRG), | 
 | 	XGE_EXTD_STAT(rx_jabber_cntr, RJBR), | 
 | 	XGE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP), | 
 | 	XGE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA), | 
 | 	XGE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA), | 
 | 	XGE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF), | 
 | 	XGE_EXTD_STAT(tx_defer_pkt_cntr, TDFR), | 
 | 	XGE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF), | 
 | 	XGE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL), | 
 | 	XGE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL), | 
 | 	XGE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL), | 
 | 	XGE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL), | 
 | 	XGE_EXTD_STAT(tx_total_col_cntr, TNCL), | 
 | 	XGE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH), | 
 | 	XGE_EXTD_STAT(tx_drop_frame_cntr, TDRP), | 
 | 	XGE_EXTD_STAT(tx_jabber_frame_cntr, TJBR), | 
 | 	XGE_EXTD_STAT(tx_fcs_error_cntr, TFCS), | 
 | 	XGE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF), | 
 | 	XGE_EXTD_STAT(tx_oversize_frame_cntr, TOVR), | 
 | 	XGE_EXTD_STAT(tx_undersize_frame_cntr, TUND), | 
 | 	XGE_EXTD_STAT(tx_fragments_cntr, TFRG) | 
 | }; | 
 |  | 
 | #define XGE_STATS_LEN		ARRAY_SIZE(gstrings_stats) | 
 | #define XGE_EXTD_STATS_LEN	ARRAY_SIZE(gstrings_extd_stats) | 
 |  | 
 | static void xge_mac_get_extd_stats(struct xge_pdata *pdata) | 
 | { | 
 | 	u32 data; | 
 | 	int i; | 
 |  | 
 | 	for (i = 0; i < XGE_EXTD_STATS_LEN; i++) { | 
 | 		data = xge_rd_csr(pdata, gstrings_extd_stats[i].addr); | 
 | 		gstrings_extd_stats[i].value += data; | 
 | 	} | 
 | } | 
 |  | 
 | static void xge_get_drvinfo(struct net_device *ndev, | 
 | 			    struct ethtool_drvinfo *info) | 
 | { | 
 | 	struct xge_pdata *pdata = netdev_priv(ndev); | 
 | 	struct platform_device *pdev = pdata->pdev; | 
 |  | 
 | 	strcpy(info->driver, "xgene-enet-v2"); | 
 | 	strcpy(info->version, XGENE_ENET_V2_VERSION); | 
 | 	snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A"); | 
 | 	sprintf(info->bus_info, "%s", pdev->name); | 
 | } | 
 |  | 
 | static void xge_get_strings(struct net_device *ndev, u32 stringset, u8 *data) | 
 | { | 
 | 	u8 *p = data; | 
 | 	int i; | 
 |  | 
 | 	if (stringset != ETH_SS_STATS) | 
 | 		return; | 
 |  | 
 | 	for (i = 0; i < XGE_STATS_LEN; i++) { | 
 | 		memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN); | 
 | 		p += ETH_GSTRING_LEN; | 
 | 	} | 
 |  | 
 | 	for (i = 0; i < XGE_EXTD_STATS_LEN; i++) { | 
 | 		memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN); | 
 | 		p += ETH_GSTRING_LEN; | 
 | 	} | 
 | } | 
 |  | 
 | static int xge_get_sset_count(struct net_device *ndev, int sset) | 
 | { | 
 | 	if (sset != ETH_SS_STATS) | 
 | 		return -EINVAL; | 
 |  | 
 | 	return XGE_STATS_LEN + XGE_EXTD_STATS_LEN; | 
 | } | 
 |  | 
 | static void xge_get_ethtool_stats(struct net_device *ndev, | 
 | 				  struct ethtool_stats *dummy, | 
 | 				  u64 *data) | 
 | { | 
 | 	void *pdata = netdev_priv(ndev); | 
 | 	int i; | 
 |  | 
 | 	for (i = 0; i < XGE_STATS_LEN; i++) | 
 | 		*data++ = *(u64 *)(pdata + gstrings_stats[i].offset); | 
 |  | 
 | 	xge_mac_get_extd_stats(pdata); | 
 |  | 
 | 	for (i = 0; i < XGE_EXTD_STATS_LEN; i++) | 
 | 		*data++ = gstrings_extd_stats[i].value; | 
 | } | 
 |  | 
 | static int xge_get_link_ksettings(struct net_device *ndev, | 
 | 				  struct ethtool_link_ksettings *cmd) | 
 | { | 
 | 	struct phy_device *phydev = ndev->phydev; | 
 |  | 
 | 	if (!phydev) | 
 | 		return -ENODEV; | 
 |  | 
 | 	phy_ethtool_ksettings_get(phydev, cmd); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int xge_set_link_ksettings(struct net_device *ndev, | 
 | 				  const struct ethtool_link_ksettings *cmd) | 
 | { | 
 | 	struct phy_device *phydev = ndev->phydev; | 
 |  | 
 | 	if (!phydev) | 
 | 		return -ENODEV; | 
 |  | 
 | 	return phy_ethtool_ksettings_set(phydev, cmd); | 
 | } | 
 |  | 
 | static const struct ethtool_ops xge_ethtool_ops = { | 
 | 	.get_drvinfo = xge_get_drvinfo, | 
 | 	.get_link = ethtool_op_get_link, | 
 | 	.get_strings = xge_get_strings, | 
 | 	.get_sset_count = xge_get_sset_count, | 
 | 	.get_ethtool_stats = xge_get_ethtool_stats, | 
 | 	.get_link_ksettings = xge_get_link_ksettings, | 
 | 	.set_link_ksettings = xge_set_link_ksettings, | 
 | }; | 
 |  | 
 | void xge_set_ethtool_ops(struct net_device *ndev) | 
 | { | 
 | 	ndev->ethtool_ops = &xge_ethtool_ops; | 
 | } |