brintos

brintos / linux-shallow public Read only

0
0
Text · 14.4 KiB · 541b8bc Raw
516 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 1999 - 2010 Intel Corporation.4 * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.5 *6 * This code was derived from the Intel e1000e Linux driver.7 */8#include "pch_gbe.h"9#include "pch_gbe_phy.h"10 11static const char pch_driver_version[] = "1.01";12 13/*14 * pch_gbe_stats - Stats item information15 */16struct pch_gbe_stats {17	char string[ETH_GSTRING_LEN];18	size_t size;19	size_t offset;20};21 22#define PCH_GBE_STAT(m)						\23{								\24	.string = #m,						\25	.size = sizeof_field(struct pch_gbe_hw_stats, m),	\26	.offset = offsetof(struct pch_gbe_hw_stats, m),		\27}28 29/*30 * pch_gbe_gstrings_stats - ethtool information status name list31 */32static const struct pch_gbe_stats pch_gbe_gstrings_stats[] = {33	PCH_GBE_STAT(rx_packets),34	PCH_GBE_STAT(tx_packets),35	PCH_GBE_STAT(rx_bytes),36	PCH_GBE_STAT(tx_bytes),37	PCH_GBE_STAT(rx_errors),38	PCH_GBE_STAT(tx_errors),39	PCH_GBE_STAT(rx_dropped),40	PCH_GBE_STAT(tx_dropped),41	PCH_GBE_STAT(multicast),42	PCH_GBE_STAT(collisions),43	PCH_GBE_STAT(rx_crc_errors),44	PCH_GBE_STAT(rx_frame_errors),45	PCH_GBE_STAT(rx_alloc_buff_failed),46	PCH_GBE_STAT(tx_length_errors),47	PCH_GBE_STAT(tx_aborted_errors),48	PCH_GBE_STAT(tx_carrier_errors),49	PCH_GBE_STAT(tx_timeout_count),50	PCH_GBE_STAT(tx_restart_count),51	PCH_GBE_STAT(intr_rx_dsc_empty_count),52	PCH_GBE_STAT(intr_rx_frame_err_count),53	PCH_GBE_STAT(intr_rx_fifo_err_count),54	PCH_GBE_STAT(intr_rx_dma_err_count),55	PCH_GBE_STAT(intr_tx_fifo_err_count),56	PCH_GBE_STAT(intr_tx_dma_err_count),57	PCH_GBE_STAT(intr_tcpip_err_count)58};59 60#define PCH_GBE_QUEUE_STATS_LEN 061#define PCH_GBE_GLOBAL_STATS_LEN	ARRAY_SIZE(pch_gbe_gstrings_stats)62#define PCH_GBE_STATS_LEN (PCH_GBE_GLOBAL_STATS_LEN + PCH_GBE_QUEUE_STATS_LEN)63 64#define PCH_GBE_MAC_REGS_LEN    (sizeof(struct pch_gbe_regs) / 4)65#define PCH_GBE_REGS_LEN        (PCH_GBE_MAC_REGS_LEN + PCH_GBE_PHY_REGS_LEN)66/**67 * pch_gbe_get_link_ksettings - Get device-specific settings68 * @netdev: Network interface device structure69 * @ecmd:   Ethtool command70 * Returns:71 *	0:			Successful.72 *	Negative value:		Failed.73 */74static int pch_gbe_get_link_ksettings(struct net_device *netdev,75				      struct ethtool_link_ksettings *ecmd)76{77	struct pch_gbe_adapter *adapter = netdev_priv(netdev);78	u32 supported, advertising;79 80	mii_ethtool_get_link_ksettings(&adapter->mii, ecmd);81 82	ethtool_convert_link_mode_to_legacy_u32(&supported,83						ecmd->link_modes.supported);84	ethtool_convert_link_mode_to_legacy_u32(&advertising,85						ecmd->link_modes.advertising);86 87	supported &= ~(SUPPORTED_TP | SUPPORTED_1000baseT_Half);88	advertising &= ~(ADVERTISED_TP | ADVERTISED_1000baseT_Half);89 90	ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported,91						supported);92	ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.advertising,93						advertising);94 95	if (!netif_carrier_ok(adapter->netdev))96		ecmd->base.speed = SPEED_UNKNOWN;97 98	return 0;99}100 101/**102 * pch_gbe_set_link_ksettings - Set device-specific settings103 * @netdev: Network interface device structure104 * @ecmd:   Ethtool command105 * Returns:106 *	0:			Successful.107 *	Negative value:		Failed.108 */109static int pch_gbe_set_link_ksettings(struct net_device *netdev,110				      const struct ethtool_link_ksettings *ecmd)111{112	struct pch_gbe_adapter *adapter = netdev_priv(netdev);113	struct pch_gbe_hw *hw = &adapter->hw;114	struct ethtool_link_ksettings copy_ecmd;115	u32 speed = ecmd->base.speed;116	u32 advertising;117	int ret;118 119	pch_gbe_phy_write_reg_miic(hw, MII_BMCR, BMCR_RESET);120 121	memcpy(&copy_ecmd, ecmd, sizeof(*ecmd));122 123	/* when set_settings() is called with a ethtool_cmd previously124	 * filled by get_settings() on a down link, speed is -1: */125	if (speed == UINT_MAX) {126		speed = SPEED_1000;127		copy_ecmd.base.speed = speed;128		copy_ecmd.base.duplex = DUPLEX_FULL;129	}130	ret = mii_ethtool_set_link_ksettings(&adapter->mii, &copy_ecmd);131	if (ret) {132		netdev_err(netdev, "Error: mii_ethtool_set_link_ksettings\n");133		return ret;134	}135	hw->mac.link_speed = speed;136	hw->mac.link_duplex = copy_ecmd.base.duplex;137	ethtool_convert_link_mode_to_legacy_u32(138		&advertising, copy_ecmd.link_modes.advertising);139	hw->phy.autoneg_advertised = advertising;140	hw->mac.autoneg = copy_ecmd.base.autoneg;141 142	/* reset the link */143	if (netif_running(adapter->netdev)) {144		pch_gbe_down(adapter);145		ret = pch_gbe_up(adapter);146	} else {147		pch_gbe_reset(adapter);148	}149	return ret;150}151 152/**153 * pch_gbe_get_regs_len - Report the size of device registers154 * @netdev: Network interface device structure155 * Returns: the size of device registers.156 */157static int pch_gbe_get_regs_len(struct net_device *netdev)158{159	return PCH_GBE_REGS_LEN * (int)sizeof(u32);160}161 162/**163 * pch_gbe_get_drvinfo - Report driver information164 * @netdev:  Network interface device structure165 * @drvinfo: Driver information structure166 */167static void pch_gbe_get_drvinfo(struct net_device *netdev,168				 struct ethtool_drvinfo *drvinfo)169{170	struct pch_gbe_adapter *adapter = netdev_priv(netdev);171 172	strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));173	strscpy(drvinfo->version, pch_driver_version, sizeof(drvinfo->version));174	strscpy(drvinfo->bus_info, pci_name(adapter->pdev),175		sizeof(drvinfo->bus_info));176}177 178/**179 * pch_gbe_get_regs - Get device registers180 * @netdev: Network interface device structure181 * @regs:   Ethtool register structure182 * @p:      Buffer pointer of read device register date183 */184static void pch_gbe_get_regs(struct net_device *netdev,185				struct ethtool_regs *regs, void *p)186{187	struct pch_gbe_adapter *adapter = netdev_priv(netdev);188	struct pch_gbe_hw *hw = &adapter->hw;189	struct pci_dev *pdev = adapter->pdev;190	u32 *regs_buff = p;191	u16 i, tmp;192 193	regs->version = 0x1000000 | (__u32)pdev->revision << 16 | pdev->device;194	for (i = 0; i < PCH_GBE_MAC_REGS_LEN; i++)195		*regs_buff++ = ioread32(&hw->reg->INT_ST + i);196	/* PHY register */197	for (i = 0; i < PCH_GBE_PHY_REGS_LEN; i++) {198		pch_gbe_phy_read_reg_miic(&adapter->hw, i, &tmp);199		*regs_buff++ = tmp;200	}201}202 203/**204 * pch_gbe_get_wol - Report whether Wake-on-Lan is enabled205 * @netdev: Network interface device structure206 * @wol:    Wake-on-Lan information207 */208static void pch_gbe_get_wol(struct net_device *netdev,209				struct ethtool_wolinfo *wol)210{211	struct pch_gbe_adapter *adapter = netdev_priv(netdev);212 213	wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;214	wol->wolopts = 0;215 216	if ((adapter->wake_up_evt & PCH_GBE_WLC_IND))217		wol->wolopts |= WAKE_UCAST;218	if ((adapter->wake_up_evt & PCH_GBE_WLC_MLT))219		wol->wolopts |= WAKE_MCAST;220	if ((adapter->wake_up_evt & PCH_GBE_WLC_BR))221		wol->wolopts |= WAKE_BCAST;222	if ((adapter->wake_up_evt & PCH_GBE_WLC_MP))223		wol->wolopts |= WAKE_MAGIC;224}225 226/**227 * pch_gbe_set_wol - Turn Wake-on-Lan on or off228 * @netdev: Network interface device structure229 * @wol:    Pointer of wake-on-Lan information straucture230 * Returns:231 *	0:			Successful.232 *	Negative value:		Failed.233 */234static int pch_gbe_set_wol(struct net_device *netdev,235				struct ethtool_wolinfo *wol)236{237	struct pch_gbe_adapter *adapter = netdev_priv(netdev);238 239	if ((wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)))240		return -EOPNOTSUPP;241	/* these settings will always override what we currently have */242	adapter->wake_up_evt = 0;243 244	if ((wol->wolopts & WAKE_UCAST))245		adapter->wake_up_evt |= PCH_GBE_WLC_IND;246	if ((wol->wolopts & WAKE_MCAST))247		adapter->wake_up_evt |= PCH_GBE_WLC_MLT;248	if ((wol->wolopts & WAKE_BCAST))249		adapter->wake_up_evt |= PCH_GBE_WLC_BR;250	if ((wol->wolopts & WAKE_MAGIC))251		adapter->wake_up_evt |= PCH_GBE_WLC_MP;252	return 0;253}254 255/**256 * pch_gbe_nway_reset - Restart autonegotiation257 * @netdev: Network interface device structure258 * Returns:259 *	0:			Successful.260 *	Negative value:		Failed.261 */262static int pch_gbe_nway_reset(struct net_device *netdev)263{264	struct pch_gbe_adapter *adapter = netdev_priv(netdev);265 266	return mii_nway_restart(&adapter->mii);267}268 269/**270 * pch_gbe_get_ringparam - Report ring sizes271 * @netdev:  Network interface device structure272 * @ring:    Ring param structure273 * @kernel_ring:	Ring external param structure274 * @extack:	netlink handle275 */276static void pch_gbe_get_ringparam(struct net_device *netdev,277				  struct ethtool_ringparam *ring,278				  struct kernel_ethtool_ringparam *kernel_ring,279				  struct netlink_ext_ack *extack)280{281	struct pch_gbe_adapter *adapter = netdev_priv(netdev);282	struct pch_gbe_tx_ring *txdr = adapter->tx_ring;283	struct pch_gbe_rx_ring *rxdr = adapter->rx_ring;284 285	ring->rx_max_pending = PCH_GBE_MAX_RXD;286	ring->tx_max_pending = PCH_GBE_MAX_TXD;287	ring->rx_pending = rxdr->count;288	ring->tx_pending = txdr->count;289}290 291/**292 * pch_gbe_set_ringparam - Set ring sizes293 * @netdev:  Network interface device structure294 * @ring:    Ring param structure295 * @kernel_ring:	Ring external param structure296 * @extack:	netlink handle297 * Returns298 *	0:			Successful.299 *	Negative value:		Failed.300 */301static int pch_gbe_set_ringparam(struct net_device *netdev,302				 struct ethtool_ringparam *ring,303				 struct kernel_ethtool_ringparam *kernel_ring,304				 struct netlink_ext_ack *extack)305{306	struct pch_gbe_adapter *adapter = netdev_priv(netdev);307	struct pch_gbe_tx_ring *txdr, *tx_old;308	struct pch_gbe_rx_ring *rxdr, *rx_old;309	int tx_ring_size, rx_ring_size;310	int err = 0;311 312	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))313		return -EINVAL;314	tx_ring_size = (int)sizeof(struct pch_gbe_tx_ring);315	rx_ring_size = (int)sizeof(struct pch_gbe_rx_ring);316 317	if ((netif_running(adapter->netdev)))318		pch_gbe_down(adapter);319	tx_old = adapter->tx_ring;320	rx_old = adapter->rx_ring;321 322	txdr = kzalloc(tx_ring_size, GFP_KERNEL);323	if (!txdr) {324		err = -ENOMEM;325		goto err_alloc_tx;326	}327	rxdr = kzalloc(rx_ring_size, GFP_KERNEL);328	if (!rxdr) {329		err = -ENOMEM;330		goto err_alloc_rx;331	}332	adapter->tx_ring = txdr;333	adapter->rx_ring = rxdr;334 335	rxdr->count =336		clamp_val(ring->rx_pending, PCH_GBE_MIN_RXD, PCH_GBE_MAX_RXD);337	rxdr->count = roundup(rxdr->count, PCH_GBE_RX_DESC_MULTIPLE);338 339	txdr->count =340		clamp_val(ring->tx_pending, PCH_GBE_MIN_RXD, PCH_GBE_MAX_RXD);341	txdr->count = roundup(txdr->count, PCH_GBE_TX_DESC_MULTIPLE);342 343	if ((netif_running(adapter->netdev))) {344		/* Try to get new resources before deleting old */345		err = pch_gbe_setup_rx_resources(adapter, adapter->rx_ring);346		if (err)347			goto err_setup_rx;348		err = pch_gbe_setup_tx_resources(adapter, adapter->tx_ring);349		if (err)350			goto err_setup_tx;351		pch_gbe_free_rx_resources(adapter, rx_old);352		pch_gbe_free_tx_resources(adapter, tx_old);353		kfree(tx_old);354		kfree(rx_old);355		adapter->rx_ring = rxdr;356		adapter->tx_ring = txdr;357		err = pch_gbe_up(adapter);358	}359	return err;360 361err_setup_tx:362	pch_gbe_free_rx_resources(adapter, adapter->rx_ring);363err_setup_rx:364	adapter->rx_ring = rx_old;365	adapter->tx_ring = tx_old;366	kfree(rxdr);367err_alloc_rx:368	kfree(txdr);369err_alloc_tx:370	if (netif_running(adapter->netdev))371		pch_gbe_up(adapter);372	return err;373}374 375/**376 * pch_gbe_get_pauseparam - Report pause parameters377 * @netdev:  Network interface device structure378 * @pause:   Pause parameters structure379 */380static void pch_gbe_get_pauseparam(struct net_device *netdev,381				       struct ethtool_pauseparam *pause)382{383	struct pch_gbe_adapter *adapter = netdev_priv(netdev);384	struct pch_gbe_hw *hw = &adapter->hw;385 386	pause->autoneg =387	    ((hw->mac.fc_autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE);388 389	if (hw->mac.fc == PCH_GBE_FC_RX_PAUSE) {390		pause->rx_pause = 1;391	} else if (hw->mac.fc == PCH_GBE_FC_TX_PAUSE) {392		pause->tx_pause = 1;393	} else if (hw->mac.fc == PCH_GBE_FC_FULL) {394		pause->rx_pause = 1;395		pause->tx_pause = 1;396	}397}398 399/**400 * pch_gbe_set_pauseparam - Set pause parameters401 * @netdev:  Network interface device structure402 * @pause:   Pause parameters structure403 * Returns:404 *	0:			Successful.405 *	Negative value:		Failed.406 */407static int pch_gbe_set_pauseparam(struct net_device *netdev,408				       struct ethtool_pauseparam *pause)409{410	struct pch_gbe_adapter *adapter = netdev_priv(netdev);411	struct pch_gbe_hw *hw = &adapter->hw;412	int ret = 0;413 414	hw->mac.fc_autoneg = pause->autoneg;415	if ((pause->rx_pause) && (pause->tx_pause))416		hw->mac.fc = PCH_GBE_FC_FULL;417	else if ((pause->rx_pause) && (!pause->tx_pause))418		hw->mac.fc = PCH_GBE_FC_RX_PAUSE;419	else if ((!pause->rx_pause) && (pause->tx_pause))420		hw->mac.fc = PCH_GBE_FC_TX_PAUSE;421	else if ((!pause->rx_pause) && (!pause->tx_pause))422		hw->mac.fc = PCH_GBE_FC_NONE;423 424	if (hw->mac.fc_autoneg == AUTONEG_ENABLE) {425		if ((netif_running(adapter->netdev))) {426			pch_gbe_down(adapter);427			ret = pch_gbe_up(adapter);428		} else {429			pch_gbe_reset(adapter);430		}431	} else {432		ret = pch_gbe_mac_force_mac_fc(hw);433	}434	return ret;435}436 437/**438 * pch_gbe_get_strings - Return a set of strings that describe the requested439 *			 objects440 * @netdev:    Network interface device structure441 * @stringset: Select the stringset. [ETH_SS_TEST] [ETH_SS_STATS]442 * @data:      Pointer of read string data.443 */444static void pch_gbe_get_strings(struct net_device *netdev, u32 stringset,445					u8 *data)446{447	u8 *p = data;448	int i;449 450	switch (stringset) {451	case (u32) ETH_SS_STATS:452		for (i = 0; i < PCH_GBE_GLOBAL_STATS_LEN; i++) {453			memcpy(p, pch_gbe_gstrings_stats[i].string,454			       ETH_GSTRING_LEN);455			p += ETH_GSTRING_LEN;456		}457		break;458	}459}460 461/**462 * pch_gbe_get_ethtool_stats - Return statistics about the device463 * @netdev: Network interface device structure464 * @stats:  Ethtool statue structure465 * @data:   Pointer of read status area466 */467static void pch_gbe_get_ethtool_stats(struct net_device *netdev,468				  struct ethtool_stats *stats, u64 *data)469{470	struct pch_gbe_adapter *adapter = netdev_priv(netdev);471	int i;472	const struct pch_gbe_stats *gstats = pch_gbe_gstrings_stats;473	char *hw_stats = (char *)&adapter->stats;474 475	pch_gbe_update_stats(adapter);476	for (i = 0; i < PCH_GBE_GLOBAL_STATS_LEN; i++) {477		char *p = hw_stats + gstats->offset;478		data[i] = gstats->size == sizeof(u64) ? *(u64 *)p:(*(u32 *)p);479		gstats++;480	}481}482 483static int pch_gbe_get_sset_count(struct net_device *netdev, int sset)484{485	switch (sset) {486	case ETH_SS_STATS:487		return PCH_GBE_STATS_LEN;488	default:489		return -EOPNOTSUPP;490	}491}492 493static const struct ethtool_ops pch_gbe_ethtool_ops = {494	.get_drvinfo = pch_gbe_get_drvinfo,495	.get_regs_len = pch_gbe_get_regs_len,496	.get_regs = pch_gbe_get_regs,497	.get_wol = pch_gbe_get_wol,498	.set_wol = pch_gbe_set_wol,499	.nway_reset = pch_gbe_nway_reset,500	.get_link = ethtool_op_get_link,501	.get_ringparam = pch_gbe_get_ringparam,502	.set_ringparam = pch_gbe_set_ringparam,503	.get_pauseparam = pch_gbe_get_pauseparam,504	.set_pauseparam = pch_gbe_set_pauseparam,505	.get_strings = pch_gbe_get_strings,506	.get_ethtool_stats = pch_gbe_get_ethtool_stats,507	.get_sset_count = pch_gbe_get_sset_count,508	.get_link_ksettings = pch_gbe_get_link_ksettings,509	.set_link_ksettings = pch_gbe_set_link_ksettings,510};511 512void pch_gbe_set_ethtool_ops(struct net_device *netdev)513{514	netdev->ethtool_ops = &pch_gbe_ethtool_ops;515}516