mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	igc: Add ethtool support
This patch adds basic ethtool support to the device to allow for configuration. Signed-off-by: Sasha Neftin <sasha.neftin@intel.com> Tested-by: Aaron Brown <aaron.f.brown@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
		
							parent
							
								
									a865d22d59
								
							
						
					
					
						commit
						8c5ad0dae9
					
				
					 8 changed files with 1169 additions and 18 deletions
				
			
		| 
						 | 
				
			
			@ -7,4 +7,5 @@
 | 
			
		|||
 | 
			
		||||
obj-$(CONFIG_IGC) += igc.o
 | 
			
		||||
 | 
			
		||||
igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o
 | 
			
		||||
igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o \
 | 
			
		||||
igc_ethtool.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,19 +13,43 @@
 | 
			
		|||
 | 
			
		||||
#include "igc_hw.h"
 | 
			
		||||
 | 
			
		||||
/* main */
 | 
			
		||||
/* forward declaration */
 | 
			
		||||
void igc_set_ethtool_ops(struct net_device *);
 | 
			
		||||
 | 
			
		||||
struct igc_adapter;
 | 
			
		||||
struct igc_ring;
 | 
			
		||||
 | 
			
		||||
void igc_up(struct igc_adapter *adapter);
 | 
			
		||||
void igc_down(struct igc_adapter *adapter);
 | 
			
		||||
int igc_setup_tx_resources(struct igc_ring *ring);
 | 
			
		||||
int igc_setup_rx_resources(struct igc_ring *ring);
 | 
			
		||||
void igc_free_tx_resources(struct igc_ring *ring);
 | 
			
		||||
void igc_free_rx_resources(struct igc_ring *ring);
 | 
			
		||||
unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter);
 | 
			
		||||
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
 | 
			
		||||
			      const u32 max_rss_queues);
 | 
			
		||||
int igc_reinit_queues(struct igc_adapter *adapter);
 | 
			
		||||
bool igc_has_link(struct igc_adapter *adapter);
 | 
			
		||||
void igc_reset(struct igc_adapter *adapter);
 | 
			
		||||
int igc_set_spd_dplx(struct igc_adapter *adapter, u32 spd, u8 dplx);
 | 
			
		||||
 | 
			
		||||
extern char igc_driver_name[];
 | 
			
		||||
extern char igc_driver_version[];
 | 
			
		||||
 | 
			
		||||
#define IGC_REGS_LEN			740
 | 
			
		||||
#define IGC_RETA_SIZE			128
 | 
			
		||||
 | 
			
		||||
/* Interrupt defines */
 | 
			
		||||
#define IGC_START_ITR			648 /* ~6000 ints/sec */
 | 
			
		||||
#define IGC_FLAG_HAS_MSI		BIT(0)
 | 
			
		||||
#define IGC_FLAG_QUEUE_PAIRS		BIT(4)
 | 
			
		||||
#define IGC_FLAG_QUEUE_PAIRS		BIT(3)
 | 
			
		||||
#define IGC_FLAG_DMAC			BIT(4)
 | 
			
		||||
#define IGC_FLAG_NEED_LINK_UPDATE	BIT(9)
 | 
			
		||||
#define IGC_FLAG_MEDIA_RESET		BIT(10)
 | 
			
		||||
#define IGC_FLAG_MAS_ENABLE		BIT(12)
 | 
			
		||||
#define IGC_FLAG_HAS_MSIX		BIT(13)
 | 
			
		||||
#define IGC_FLAG_VLAN_PROMISC		BIT(15)
 | 
			
		||||
#define IGC_FLAG_RX_LEGACY		BIT(16)
 | 
			
		||||
 | 
			
		||||
#define IGC_START_ITR			648 /* ~6000 ints/sec */
 | 
			
		||||
#define IGC_4K_ITR			980
 | 
			
		||||
| 
						 | 
				
			
			@ -60,6 +84,7 @@ extern char igc_driver_version[];
 | 
			
		|||
#define IGC_RXBUFFER_2048		2048
 | 
			
		||||
#define IGC_RXBUFFER_3072		3072
 | 
			
		||||
 | 
			
		||||
#define AUTO_ALL_MODES		0
 | 
			
		||||
#define IGC_RX_HDR_LEN			IGC_RXBUFFER_256
 | 
			
		||||
 | 
			
		||||
/* RX and TX descriptor control thresholds.
 | 
			
		||||
| 
						 | 
				
			
			@ -340,6 +365,8 @@ struct igc_adapter {
 | 
			
		|||
 | 
			
		||||
	struct igc_mac_addr *mac_table;
 | 
			
		||||
 | 
			
		||||
	u8 rss_indir_tbl[IGC_RETA_SIZE];
 | 
			
		||||
 | 
			
		||||
	unsigned long link_check_timeout;
 | 
			
		||||
	struct igc_info ei;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -418,6 +445,9 @@ static inline s32 igc_read_phy_reg(struct igc_hw *hw, u32 offset, u16 *data)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* forward declaration */
 | 
			
		||||
void igc_reinit_locked(struct igc_adapter *);
 | 
			
		||||
 | 
			
		||||
#define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring))
 | 
			
		||||
 | 
			
		||||
#define IGC_TXD_DCMD	(IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -131,6 +131,7 @@ static s32 igc_init_nvm_params_base(struct igc_hw *hw)
 | 
			
		|||
	if (size > 15)
 | 
			
		||||
		size = 15;
 | 
			
		||||
 | 
			
		||||
	nvm->type = igc_nvm_eeprom_spi;
 | 
			
		||||
	nvm->word_size = BIT(size);
 | 
			
		||||
	nvm->opcode_bits = 8;
 | 
			
		||||
	nvm->delay_usec = 1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,10 @@
 | 
			
		|||
#ifndef _IGC_DEFINES_H_
 | 
			
		||||
#define _IGC_DEFINES_H_
 | 
			
		||||
 | 
			
		||||
/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
 | 
			
		||||
#define REQ_TX_DESCRIPTOR_MULTIPLE  8
 | 
			
		||||
#define REQ_RX_DESCRIPTOR_MULTIPLE  8
 | 
			
		||||
 | 
			
		||||
#define IGC_CTRL_EXT_DRV_LOAD	0x10000000 /* Drv loaded bit for FW */
 | 
			
		||||
 | 
			
		||||
/* PCI Bus Info */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1032
									
								
								drivers/net/ethernet/intel/igc/igc_ethtool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1032
									
								
								drivers/net/ethernet/intel/igc/igc_ethtool.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -55,6 +55,7 @@ enum igc_media_type {
 | 
			
		|||
 | 
			
		||||
enum igc_nvm_type {
 | 
			
		||||
	igc_nvm_unknown = 0,
 | 
			
		||||
	igc_nvm_eeprom_spi,
 | 
			
		||||
	igc_nvm_flash_hw,
 | 
			
		||||
	igc_nvm_invm,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,8 @@
 | 
			
		|||
#define DRV_VERSION	"0.0.1-k"
 | 
			
		||||
#define DRV_SUMMARY	"Intel(R) 2.5G Ethernet Linux Driver"
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
 | 
			
		||||
 | 
			
		||||
static int debug = -1;
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +68,7 @@ enum latency_range {
 | 
			
		|||
	latency_invalid = 255
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void igc_reset(struct igc_adapter *adapter)
 | 
			
		||||
void igc_reset(struct igc_adapter *adapter)
 | 
			
		||||
{
 | 
			
		||||
	struct pci_dev *pdev = adapter->pdev;
 | 
			
		||||
	struct igc_hw *hw = &adapter->hw;
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +152,7 @@ static void igc_get_hw_control(struct igc_adapter *adapter)
 | 
			
		|||
 *
 | 
			
		||||
 * Free all transmit software resources
 | 
			
		||||
 */
 | 
			
		||||
static void igc_free_tx_resources(struct igc_ring *tx_ring)
 | 
			
		||||
void igc_free_tx_resources(struct igc_ring *tx_ring)
 | 
			
		||||
{
 | 
			
		||||
	igc_clean_tx_ring(tx_ring);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -261,7 +263,7 @@ static void igc_clean_all_tx_rings(struct igc_adapter *adapter)
 | 
			
		|||
 *
 | 
			
		||||
 * Return 0 on success, negative on failure
 | 
			
		||||
 */
 | 
			
		||||
static int igc_setup_tx_resources(struct igc_ring *tx_ring)
 | 
			
		||||
int igc_setup_tx_resources(struct igc_ring *tx_ring)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = tx_ring->dev;
 | 
			
		||||
	int size = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -381,7 +383,7 @@ static void igc_clean_all_rx_rings(struct igc_adapter *adapter)
 | 
			
		|||
 *
 | 
			
		||||
 * Free all receive software resources
 | 
			
		||||
 */
 | 
			
		||||
static void igc_free_rx_resources(struct igc_ring *rx_ring)
 | 
			
		||||
void igc_free_rx_resources(struct igc_ring *rx_ring)
 | 
			
		||||
{
 | 
			
		||||
	igc_clean_rx_ring(rx_ring);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -418,7 +420,7 @@ static void igc_free_all_rx_resources(struct igc_adapter *adapter)
 | 
			
		|||
 *
 | 
			
		||||
 * Returns 0 on success, negative on failure
 | 
			
		||||
 */
 | 
			
		||||
static int igc_setup_rx_resources(struct igc_ring *rx_ring)
 | 
			
		||||
int igc_setup_rx_resources(struct igc_ring *rx_ring)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = rx_ring->dev;
 | 
			
		||||
	int size, desc_len;
 | 
			
		||||
| 
						 | 
				
			
			@ -1703,7 +1705,7 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
 | 
			
		|||
 * igc_up - Open the interface and prepare it to handle traffic
 | 
			
		||||
 * @adapter: board private structure
 | 
			
		||||
 */
 | 
			
		||||
static void igc_up(struct igc_adapter *adapter)
 | 
			
		||||
void igc_up(struct igc_adapter *adapter)
 | 
			
		||||
{
 | 
			
		||||
	struct igc_hw *hw = &adapter->hw;
 | 
			
		||||
	int i = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1748,7 +1750,7 @@ static void igc_nfc_filter_exit(struct igc_adapter *adapter)
 | 
			
		|||
 * igc_down - Close the interface
 | 
			
		||||
 * @adapter: board private structure
 | 
			
		||||
 */
 | 
			
		||||
static void igc_down(struct igc_adapter *adapter)
 | 
			
		||||
void igc_down(struct igc_adapter *adapter)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *netdev = adapter->netdev;
 | 
			
		||||
	struct igc_hw *hw = &adapter->hw;
 | 
			
		||||
| 
						 | 
				
			
			@ -1810,7 +1812,7 @@ static void igc_down(struct igc_adapter *adapter)
 | 
			
		|||
	igc_clean_all_rx_rings(adapter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void igc_reinit_locked(struct igc_adapter *adapter)
 | 
			
		||||
void igc_reinit_locked(struct igc_adapter *adapter)
 | 
			
		||||
{
 | 
			
		||||
	WARN_ON(in_interrupt());
 | 
			
		||||
	while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
 | 
			
		||||
| 
						 | 
				
			
			@ -1922,7 +1924,7 @@ static void igc_configure(struct igc_adapter *adapter)
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * igc_rar_set_index - Sync RAL[index] and RAH[index] registers with MAC table
 | 
			
		||||
 * @adapter: Pointer to adapter structure
 | 
			
		||||
 * @adapter: address of board private structure
 | 
			
		||||
 * @index: Index of the RAR entry which need to be synced with MAC table
 | 
			
		||||
 */
 | 
			
		||||
static void igc_rar_set_index(struct igc_adapter *adapter, u32 index)
 | 
			
		||||
| 
						 | 
				
			
			@ -2298,7 +2300,7 @@ static void igc_update_phy_info(struct timer_list *t)
 | 
			
		|||
 * igc_has_link - check shared code for link and determine up/down
 | 
			
		||||
 * @adapter: pointer to driver private info
 | 
			
		||||
 */
 | 
			
		||||
static bool igc_has_link(struct igc_adapter *adapter)
 | 
			
		||||
bool igc_has_link(struct igc_adapter *adapter)
 | 
			
		||||
{
 | 
			
		||||
	struct igc_hw *hw = &adapter->hw;
 | 
			
		||||
	bool link_active = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -3501,6 +3503,57 @@ u32 igc_rd32(struct igc_hw *hw, u32 reg)
 | 
			
		|||
	return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int igc_set_spd_dplx(struct igc_adapter *adapter, u32 spd, u8 dplx)
 | 
			
		||||
{
 | 
			
		||||
	struct pci_dev *pdev = adapter->pdev;
 | 
			
		||||
	struct igc_mac_info *mac = &adapter->hw.mac;
 | 
			
		||||
 | 
			
		||||
	mac->autoneg = 0;
 | 
			
		||||
 | 
			
		||||
	/* Make sure dplx is at most 1 bit and lsb of speed is not set
 | 
			
		||||
	 * for the switch() below to work
 | 
			
		||||
	 */
 | 
			
		||||
	if ((spd & 1) || (dplx & ~1))
 | 
			
		||||
		goto err_inval;
 | 
			
		||||
 | 
			
		||||
	switch (spd + dplx) {
 | 
			
		||||
	case SPEED_10 + DUPLEX_HALF:
 | 
			
		||||
		mac->forced_speed_duplex = ADVERTISE_10_HALF;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPEED_10 + DUPLEX_FULL:
 | 
			
		||||
		mac->forced_speed_duplex = ADVERTISE_10_FULL;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPEED_100 + DUPLEX_HALF:
 | 
			
		||||
		mac->forced_speed_duplex = ADVERTISE_100_HALF;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPEED_100 + DUPLEX_FULL:
 | 
			
		||||
		mac->forced_speed_duplex = ADVERTISE_100_FULL;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPEED_1000 + DUPLEX_FULL:
 | 
			
		||||
		mac->autoneg = 1;
 | 
			
		||||
		adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPEED_1000 + DUPLEX_HALF: /* not supported */
 | 
			
		||||
		goto err_inval;
 | 
			
		||||
	case SPEED_2500 + DUPLEX_FULL:
 | 
			
		||||
		mac->autoneg = 1;
 | 
			
		||||
		adapter->hw.phy.autoneg_advertised = ADVERTISE_2500_FULL;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPEED_2500 + DUPLEX_HALF: /* not supported */
 | 
			
		||||
	default:
 | 
			
		||||
		goto err_inval;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* clear MDI, MDI(-X) override is only allowed when autoneg enabled */
 | 
			
		||||
	adapter->hw.phy.mdix = AUTO_ALL_MODES;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_inval:
 | 
			
		||||
	dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n");
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * igc_probe - Device Initialization Routine
 | 
			
		||||
 * @pdev: PCI device information struct
 | 
			
		||||
| 
						 | 
				
			
			@ -3568,7 +3621,7 @@ static int igc_probe(struct pci_dev *pdev,
 | 
			
		|||
	hw = &adapter->hw;
 | 
			
		||||
	hw->back = adapter;
 | 
			
		||||
	adapter->port_num = hw->bus.func;
 | 
			
		||||
	adapter->msg_enable = GENMASK(debug - 1, 0);
 | 
			
		||||
	adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
 | 
			
		||||
 | 
			
		||||
	err = pci_save_state(pdev);
 | 
			
		||||
	if (err)
 | 
			
		||||
| 
						 | 
				
			
			@ -3584,7 +3637,7 @@ static int igc_probe(struct pci_dev *pdev,
 | 
			
		|||
	hw->hw_addr = adapter->io_addr;
 | 
			
		||||
 | 
			
		||||
	netdev->netdev_ops = &igc_netdev_ops;
 | 
			
		||||
 | 
			
		||||
	igc_set_ethtool_ops(netdev);
 | 
			
		||||
	netdev->watchdog_timeo = 5 * HZ;
 | 
			
		||||
 | 
			
		||||
	netdev->mem_start = pci_resource_start(pdev, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -3744,8 +3797,8 @@ static struct pci_driver igc_driver = {
 | 
			
		|||
	.remove   = igc_remove,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
 | 
			
		||||
				     const u32 max_rss_queues)
 | 
			
		||||
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
 | 
			
		||||
			      const u32 max_rss_queues)
 | 
			
		||||
{
 | 
			
		||||
	/* Determine if we need to pair queues. */
 | 
			
		||||
	/* If rss_queues > half of max_rss_queues, pair the queues in
 | 
			
		||||
| 
						 | 
				
			
			@ -3757,7 +3810,7 @@ static void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
 | 
			
		|||
		adapter->flags &= ~IGC_FLAG_QUEUE_PAIRS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter)
 | 
			
		||||
unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int max_rss_queues;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3836,6 +3889,32 @@ static int igc_sw_init(struct igc_adapter *adapter)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * igc_reinit_queues - return error
 | 
			
		||||
 * @adapter: pointer to adapter structure
 | 
			
		||||
 */
 | 
			
		||||
int igc_reinit_queues(struct igc_adapter *adapter)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *netdev = adapter->netdev;
 | 
			
		||||
	struct pci_dev *pdev = adapter->pdev;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
	if (netif_running(netdev))
 | 
			
		||||
		igc_close(netdev);
 | 
			
		||||
 | 
			
		||||
	igc_reset_interrupt_capability(adapter);
 | 
			
		||||
 | 
			
		||||
	if (igc_init_interrupt_scheme(adapter, true)) {
 | 
			
		||||
		dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (netif_running(netdev))
 | 
			
		||||
		err = igc_open(netdev);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * igc_get_hw_dev - return device
 | 
			
		||||
 * @hw: pointer to hardware structure
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,6 +80,9 @@
 | 
			
		|||
/* MSI-X Table Register Descriptions */
 | 
			
		||||
#define IGC_PBACL		0x05B68  /* MSIx PBA Clear - R/W 1 to clear */
 | 
			
		||||
 | 
			
		||||
/* Redirection Table - RW Array */
 | 
			
		||||
#define IGC_RETA(_i)		(0x05C00 + ((_i) * 4))
 | 
			
		||||
 | 
			
		||||
/* Receive Register Descriptions */
 | 
			
		||||
#define IGC_RCTL		0x00100  /* Rx Control - RW */
 | 
			
		||||
#define IGC_SRRCTL(_n)		(0x0C00C + ((_n) * 0x40))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue