ixgbe: driver for Intel(R) 82598 PCI-Express 10GbE adapters (v4)

This patch adds support for the Intel 82598 PCI-Express 10GbE
chipset. Devices will be available on the market soon.

This version of the driver is largely the same as the last release:

  * Driver uses a single RX and single TX queue, each using 1 MSI-X
  irq vector.
  * Driver runs in NAPI mode only
  * Driver is largely multiqueue-ready (TM)

Changes since 20070803:
  * removed wrappers for hardware functions
  * incorporated e1000e-style HW api reorganization code
  * sparse/checkpatch cleanups, namespace cleanups
  * driver prints out extra debugging information at load time
    identifying adapter board number, mac, phy types
  * removed ixgbe_api.c, ixgbe_api.h, ixgbe_osdep.h
  * driver update to 1.1.18
  * removed ixgbe.txt which contained no useful info anymore

[ Integrated napi_struct changes from Auke as well... -DaveM ]

Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
Signed-off-by: Ayyappan Veeraiyan <ayyappan.veeraiyan@intel.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Auke Kok 2007-09-15 14:07:45 -07:00 committed by David S. Miller
parent dc029ad97f
commit 9a799d7103
13 changed files with 7867 additions and 8 deletions

View File

@ -2030,16 +2030,14 @@ W: http://sourceforge.net/projects/e1000/
S: Supported
INTEL PRO/10GbE SUPPORT
P: Jeff Kirsher
M: jeffrey.t.kirsher@intel.com
P: Ayyappan Veeraiyan
M: ayyappan.veeraiyan@intel.com
P: John Ronciak
M: john.ronciak@intel.com
P: Jesse Brandeburg
M: jesse.brandeburg@intel.com
P: Auke Kok
M: auke-jan.h.kok@intel.com
P: Jesse Brandeburg
M: jesse.brandeburg@intel.com
P: John Ronciak
M: john.ronciak@intel.com
L: e1000-devel@lists.sourceforge.net
W: http://sourceforge.net/projects/e1000/
S: Supported

View File

@ -2518,12 +2518,35 @@ config EHEA
To compile the driver as a module, choose M here. The module
will be called ehea.
config IXGBE
tristate "Intel(R) 10GbE PCI Express adapters support"
depends on PCI
---help---
This driver supports Intel(R) 10GbE PCI Express family of
adapters. For more information on how to identify your adapter, go
to the Adapter & Driver ID Guide at:
<http://support.intel.com/support/network/adapter/pro100/21397.htm>
For general information and support, go to the Intel support
website at:
<http://support.intel.com>
More specific information on configuring the driver is in
<file:Documentation/networking/ixgbe.txt>.
To compile this driver as a module, choose M here and read
<file:Documentation/networking/net-modules.txt>. The module
will be called ixgbe.
config IXGB
tristate "Intel(R) PRO/10GbE support"
depends on PCI
---help---
This driver supports Intel(R) PRO/10GbE family of
adapters. For more information on how to identify your adapter, go
This driver supports Intel(R) PRO/10GbE family of adapters for
PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver
instead. For more information on how to identify your adapter, go
to the Adapter & Driver ID Guide at:
<http://support.intel.com/support/network/adapter/pro100/21397.htm>

View File

@ -5,6 +5,7 @@
obj-$(CONFIG_E1000) += e1000/
obj-$(CONFIG_E1000E) += e1000e/
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
obj-$(CONFIG_IXGBE) += ixgbe/
obj-$(CONFIG_IXGB) += ixgb/
obj-$(CONFIG_CHELSIO_T1) += chelsio/
obj-$(CONFIG_CHELSIO_T3) += cxgb3/

View File

@ -0,0 +1,36 @@
################################################################################
#
# Intel 10 Gigabit PCI Express Linux driver
# Copyright(c) 1999 - 2007 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2, as published by the Free Software Foundation.
#
# This program is distributed in the hope 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, write to the Free Software Foundation, Inc.,
# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
#
# The full GNU General Public License is included in this distribution in
# the file called "COPYING".
#
# Contact Information:
# Linux NICS <linux.nics@intel.com>
# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
#
################################################################################
#
# Makefile for the Intel(R) 10GbE PCI Express ethernet driver
#
obj-$(CONFIG_IXGBE) += ixgbe.o
ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
ixgbe_82598.o ixgbe_phy.o

259
drivers/net/ixgbe/ixgbe.h Normal file
View File

@ -0,0 +1,259 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
Copyright(c) 1999 - 2007 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
#ifndef _IXGBE_H_
#define _IXGBE_H_
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include "ixgbe_type.h"
#include "ixgbe_common.h"
#define IXGBE_ERR(args...) printk(KERN_ERR "ixgbe: " args)
#define PFX "ixgbe: "
#define DPRINTK(nlevel, klevel, fmt, args...) \
((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \
__FUNCTION__ , ## args)))
/* TX/RX descriptor defines */
#define IXGBE_DEFAULT_TXD 1024
#define IXGBE_MAX_TXD 4096
#define IXGBE_MIN_TXD 64
#define IXGBE_DEFAULT_RXD 1024
#define IXGBE_MAX_RXD 4096
#define IXGBE_MIN_RXD 64
#define IXGBE_DEFAULT_RXQ 1
#define IXGBE_MAX_RXQ 1
#define IXGBE_MIN_RXQ 1
#define IXGBE_DEFAULT_ITR_RX_USECS 125 /* 8k irqs/sec */
#define IXGBE_DEFAULT_ITR_TX_USECS 250 /* 4k irqs/sec */
#define IXGBE_MIN_ITR_USECS 100 /* 500k irqs/sec */
#define IXGBE_MAX_ITR_USECS 10000 /* 100 irqs/sec */
/* flow control */
#define IXGBE_DEFAULT_FCRTL 0x10000
#define IXGBE_MIN_FCRTL 0
#define IXGBE_MAX_FCRTL 0x7FF80
#define IXGBE_DEFAULT_FCRTH 0x20000
#define IXGBE_MIN_FCRTH 0
#define IXGBE_MAX_FCRTH 0x7FFF0
#define IXGBE_DEFAULT_FCPAUSE 0x6800 /* may be too long */
#define IXGBE_MIN_FCPAUSE 0
#define IXGBE_MAX_FCPAUSE 0xFFFF
/* Supported Rx Buffer Sizes */
#define IXGBE_RXBUFFER_64 64 /* Used for packet split */
#define IXGBE_RXBUFFER_128 128 /* Used for packet split */
#define IXGBE_RXBUFFER_256 256 /* Used for packet split */
#define IXGBE_RXBUFFER_2048 2048
#define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256
#define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
/* How many Tx Descriptors do we need to call netif_wake_queue? */
#define IXGBE_TX_QUEUE_WAKE 16
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define IXGBE_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define IXGBE_TX_FLAGS_CSUM (u32)(1)
#define IXGBE_TX_FLAGS_VLAN (u32)(1 << 1)
#define IXGBE_TX_FLAGS_TSO (u32)(1 << 2)
#define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3)
#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000
#define IXGBE_TX_FLAGS_VLAN_SHIFT 16
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct ixgbe_tx_buffer {
struct sk_buff *skb;
dma_addr_t dma;
unsigned long time_stamp;
u16 length;
u16 next_to_watch;
};
struct ixgbe_rx_buffer {
struct sk_buff *skb;
dma_addr_t dma;
struct page *page;
dma_addr_t page_dma;
};
struct ixgbe_queue_stats {
u64 packets;
u64 bytes;
};
struct ixgbe_ring {
struct ixgbe_adapter *adapter; /* backlink */
void *desc; /* descriptor ring memory */
dma_addr_t dma; /* phys. address of descriptor ring */
unsigned int size; /* length in bytes */
unsigned int count; /* amount of descriptors */
unsigned int next_to_use;
unsigned int next_to_clean;
union {
struct ixgbe_tx_buffer *tx_buffer_info;
struct ixgbe_rx_buffer *rx_buffer_info;
};
u16 head;
u16 tail;
/* To protect race between sender and clean_tx_irq */
spinlock_t tx_lock;
struct ixgbe_queue_stats stats;
u32 eims_value;
u16 itr_register;
char name[IFNAMSIZ + 5];
u16 work_limit; /* max work per interrupt */
};
/* Helper macros to switch between ints/sec and what the register uses.
* And yes, it's the same math going both ways.
*/
#define EITR_INTS_PER_SEC_TO_REG(_eitr) \
((_eitr) ? (1000000000 / ((_eitr) * 256)) : 0)
#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG
#define IXGBE_DESC_UNUSED(R) \
((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
(R)->next_to_clean - (R)->next_to_use - 1)
#define IXGBE_RX_DESC_ADV(R, i) \
(&(((union ixgbe_adv_rx_desc *)((R).desc))[i]))
#define IXGBE_TX_DESC_ADV(R, i) \
(&(((union ixgbe_adv_tx_desc *)((R).desc))[i]))
#define IXGBE_TX_CTXTDESC_ADV(R, i) \
(&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i]))
#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128
/* board specific private data structure */
struct ixgbe_adapter {
struct timer_list watchdog_timer;
struct vlan_group *vlgrp;
u16 bd_number;
u16 rx_buf_len;
atomic_t irq_sem;
struct work_struct reset_task;
/* TX */
struct ixgbe_ring *tx_ring; /* One per active queue */
struct napi_struct napi;
u64 restart_queue;
u64 lsc_int;
u64 hw_tso_ctxt;
u64 hw_tso6_ctxt;
u32 tx_timeout_count;
bool detect_tx_hung;
/* RX */
struct ixgbe_ring *rx_ring; /* One per active queue */
u64 hw_csum_tx_good;
u64 hw_csum_rx_error;
u64 hw_csum_rx_good;
u64 non_eop_descs;
int num_tx_queues;
int num_rx_queues;
struct msix_entry *msix_entries;
u64 rx_hdr_split;
u32 alloc_rx_page_failed;
u32 alloc_rx_buff_failed;
u32 flags;
#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1)
#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 1)
#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 2)
#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 3)
#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 4)
/* Interrupt Throttle Rate */
u32 rx_eitr;
u32 tx_eitr;
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
struct net_device_stats net_stats;
/* structs defined in ixgbe_hw.h */
struct ixgbe_hw hw;
u16 msg_enable;
struct ixgbe_hw_stats stats;
char lsc_name[IFNAMSIZ + 5];
unsigned long state;
u64 tx_busy;
};
enum ixbge_state_t {
__IXGBE_TESTING,
__IXGBE_RESETTING,
__IXGBE_DOWN
};
enum ixgbe_boards {
board_82598AF,
board_82598EB,
board_82598AT,
};
extern struct ixgbe_info ixgbe_82598AF_info;
extern struct ixgbe_info ixgbe_82598EB_info;
extern struct ixgbe_info ixgbe_82598AT_info;
extern char ixgbe_driver_name[];
extern char ixgbe_driver_version[];
extern int ixgbe_up(struct ixgbe_adapter *adapter);
extern void ixgbe_down(struct ixgbe_adapter *adapter);
extern void ixgbe_reset(struct ixgbe_adapter *adapter);
extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
extern void ixgbe_set_ethtool_ops(struct net_device *netdev);
extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
struct ixgbe_ring *rxdr);
extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
struct ixgbe_ring *txdr);
#endif /* _IXGBE_H_ */

View File

@ -0,0 +1,589 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
Copyright(c) 1999 - 2007 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include "ixgbe_type.h"
#include "ixgbe_common.h"
#include "ixgbe_phy.h"
#define IXGBE_82598_MAX_TX_QUEUES 32
#define IXGBE_82598_MAX_RX_QUEUES 64
#define IXGBE_82598_RAR_ENTRIES 16
static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw);
static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed,
bool *autoneg);
static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw,
u32 *speed, bool *autoneg);
static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw);
static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw);
static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed,
bool *link_up);
static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
bool autoneg,
bool autoneg_wait_to_complete);
static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw);
static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed,
bool *link_up);
static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
bool autoneg,
bool autoneg_wait_to_complete);
static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw);
static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw)
{
hw->mac.num_rx_queues = IXGBE_82598_MAX_TX_QUEUES;
hw->mac.num_tx_queues = IXGBE_82598_MAX_RX_QUEUES;
hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES;
return 0;
}
/**
* ixgbe_get_link_settings_82598 - Determines default link settings
* @hw: pointer to hardware structure
* @speed: pointer to link speed
* @autoneg: boolean auto-negotiation value
*
* Determines the default link settings by reading the AUTOC register.
**/
static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed,
bool *autoneg)
{
s32 status = 0;
s32 autoc_reg;
autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
if (hw->mac.link_settings_loaded) {
autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE;
autoc_reg &= ~IXGBE_AUTOC_LMS_MASK;
autoc_reg |= hw->mac.link_attach_type;
autoc_reg |= hw->mac.link_mode_select;
}
switch (autoc_reg & IXGBE_AUTOC_LMS_MASK) {
case IXGBE_AUTOC_LMS_1G_LINK_NO_AN:
*speed = IXGBE_LINK_SPEED_1GB_FULL;
*autoneg = false;
break;
case IXGBE_AUTOC_LMS_10G_LINK_NO_AN:
*speed = IXGBE_LINK_SPEED_10GB_FULL;
*autoneg = false;
break;
case IXGBE_AUTOC_LMS_1G_AN:
*speed = IXGBE_LINK_SPEED_1GB_FULL;
*autoneg = true;
break;
case IXGBE_AUTOC_LMS_KX4_AN:
case IXGBE_AUTOC_LMS_KX4_AN_1G_AN:
*speed = IXGBE_LINK_SPEED_UNKNOWN;
if (autoc_reg & IXGBE_AUTOC_KX4_SUPP)
*speed |= IXGBE_LINK_SPEED_10GB_FULL;
if (autoc_reg & IXGBE_AUTOC_KX_SUPP)
*speed |= IXGBE_LINK_SPEED_1GB_FULL;
*autoneg = true;
break;
default:
status = IXGBE_ERR_LINK_SETUP;
break;
}
return status;
}
/**
* ixgbe_get_copper_link_settings_82598 - Determines default link settings
* @hw: pointer to hardware structure
* @speed: pointer to link speed
* @autoneg: boolean auto-negotiation value
*
* Determines the default link settings by reading the AUTOC register.
**/
static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw,
u32 *speed, bool *autoneg)
{
s32 status = IXGBE_ERR_LINK_SETUP;
u16 speed_ability;
*speed = 0;
*autoneg = true;
status = ixgbe_read_phy_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY,
IXGBE_MDIO_PMA_PMD_DEV_TYPE,
&speed_ability);
if (status == 0) {
if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G)
*speed |= IXGBE_LINK_SPEED_10GB_FULL;
if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G)
*speed |= IXGBE_LINK_SPEED_1GB_FULL;
}
return status;
}
/**
* ixgbe_get_media_type_82598 - Determines media type
* @hw: pointer to hardware structure
*
* Returns the media type (fiber, copper, backplane)
**/
static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw)
{
enum ixgbe_media_type media_type;
/* Media type for I82598 is based on device ID */
switch (hw->device_id) {
case IXGBE_DEV_ID_82598AF_DUAL_PORT:
case IXGBE_DEV_ID_82598AF_SINGLE_PORT:
case IXGBE_DEV_ID_82598EB_CX4:
media_type = ixgbe_media_type_fiber;
break;
case IXGBE_DEV_ID_82598AT_DUAL_PORT:
media_type = ixgbe_media_type_copper;
break;
default:
media_type = ixgbe_media_type_unknown;
break;
}
return media_type;
}
/**
* ixgbe_setup_mac_link_82598 - Configures MAC link settings
* @hw: pointer to hardware structure
*
* Configures link settings based on values in the ixgbe_hw struct.
* Restarts the link. Performs autonegotiation if needed.
**/
static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw)
{
u32 autoc_reg;
u32 links_reg;
u32 i;
s32 status = 0;
autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
if (hw->mac.link_settings_loaded) {
autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE;
autoc_reg &= ~IXGBE_AUTOC_LMS_MASK;
autoc_reg |= hw->mac.link_attach_type;
autoc_reg |= hw->mac.link_mode_select;
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
msleep(50);
}
/* Restart link */
autoc_reg |= IXGBE_AUTOC_AN_RESTART;
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
/* Only poll for autoneg to complete if specified to do so */
if (hw->phy.autoneg_wait_to_complete) {
if (hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN ||
hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN_1G_AN) {
links_reg = 0; /* Just in case Autoneg time = 0 */
for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) {
links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
if (links_reg & IXGBE_LINKS_KX_AN_COMP)
break;
msleep(100);
}
if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
status = IXGBE_ERR_AUTONEG_NOT_COMPLETE;
hw_dbg(hw,
"Autonegotiation did not complete.\n");
}
}
}
/*
* We want to save off the original Flow Control configuration just in
* case we get disconnected and then reconnected into a different hub
* or switch with different Flow Control capabilities.
*/
hw->fc.type = hw->fc.original_type;
ixgbe_setup_fc(hw, 0);
/* Add delay to filter out noises during initial link setup */
msleep(50);
return status;
}
/**
* ixgbe_check_mac_link_82598 - Get link/speed status
* @hw: pointer to hardware structure
* @speed: pointer to link speed
* @link_up: true is link is up, false otherwise
*
* Reads the links register to determine if link is up and the current speed
**/
static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed,
bool *link_up)
{
u32 links_reg;
links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
if (links_reg & IXGBE_LINKS_UP)
*link_up = true;
else
*link_up = false;
if (links_reg & IXGBE_LINKS_SPEED)
*speed = IXGBE_LINK_SPEED_10GB_FULL;
else
*speed = IXGBE_LINK_SPEED_1GB_FULL;
return 0;
}
/**
* ixgbe_setup_mac_link_speed_82598 - Set MAC link speed
* @hw: pointer to hardware structure
* @speed: new link speed
* @autoneg: true if auto-negotiation enabled
* @autoneg_wait_to_complete: true if waiting is needed to complete
*
* Set the link speed in the AUTOC register and restarts link.
**/
static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw,
u32 speed, bool autoneg,
bool autoneg_wait_to_complete)
{
s32 status = 0;
/* If speed is 10G, then check for CX4 or XAUI. */
if ((speed == IXGBE_LINK_SPEED_10GB_FULL) &&
(!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4)))
hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;
else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg))
hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_LINK_NO_AN;
else if (autoneg) {
/* BX mode - Autonegotiate 1G */
if (!(hw->mac.link_attach_type & IXGBE_AUTOC_1G_PMA_PMD))
hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_AN;
else /* KX/KX4 mode */
hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN_1G_AN;
} else {
status = IXGBE_ERR_LINK_SETUP;
}
if (status == 0) {
hw->phy.autoneg_wait_to_complete = autoneg_wait_to_complete;
hw->mac.link_settings_loaded = true;
/*
* Setup and restart the link based on the new values in
* ixgbe_hw This will write the AUTOC register based on the new
* stored values
*/
hw->phy.ops.setup(hw);
}
return status;
}
/**
* ixgbe_setup_copper_link_82598 - Setup copper link settings
* @hw: pointer to hardware structure
*
* Configures link settings based on values in the ixgbe_hw struct.
* Restarts the link. Performs autonegotiation if needed. Restart
* phy and wait for autonegotiate to finish. Then synchronize the
* MAC and PHY.
**/
static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw)
{
s32 status;
u32 speed = 0;
bool link_up = false;
/* Set up MAC */
hw->phy.ops.setup(hw);
/* Restart autonegotiation on PHY */
status = hw->phy.ops.setup(hw);
/* Synchronize MAC to PHY speed */
if (status == 0)
status = hw->phy.ops.check(hw, &speed, &link_up);
return status;
}
/**
* ixgbe_check_copper_link_82598 - Syncs MAC & PHY link settings
* @hw: pointer to hardware structure
* @speed: pointer to link speed
* @link_up: true if link is up, false otherwise
*
* Reads the mac link, phy link, and synchronizes the MAC to PHY.
**/
static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed,
bool *link_up)
{
s32 status;
u32 phy_speed = 0;
bool phy_link = false;
/* This is the speed and link the MAC is set at */
hw->phy.ops.check(hw, speed, link_up);
/*
* Check current speed and link status of the PHY register.
* This is a vendor specific register and may have to
* be changed for other copper PHYs.
*/
status = hw->phy.ops.check(hw, &phy_speed, &phy_link);
if ((status == 0) && (phy_link)) {
/*
* Check current link status of the MACs link's register
* matches that of the speed in the PHY register
*/
if (*speed != phy_speed) {
/*
* The copper PHY requires 82598 attach type to be XAUI
* for 10G and BX for 1G
*/
hw->mac.link_attach_type =
(IXGBE_AUTOC_10G_XAUI | IXGBE_AUTOC_1G_BX);
/* Synchronize the MAC speed to the PHY speed */
status = hw->phy.ops.setup_speed(hw, phy_speed, false,
false);
if (status == 0)
hw->phy.ops.check(hw, speed, link_up);
else
status = IXGBE_ERR_LINK_SETUP;
}
} else {
*link_up = phy_link;
}
return status;
}
/**
* ixgbe_setup_copper_link_speed_82598 - Set the PHY autoneg advertised field
* @hw: pointer to hardware structure
* @speed: new link speed
* @autoneg: true if autonegotiation enabled
* @autoneg_wait_to_complete: true if waiting is needed to complete
*
* Sets the link speed in the AUTOC register in the MAC and restarts link.
**/
static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
bool autoneg,
bool autoneg_wait_to_complete)
{
s32 status;
bool link_up = 0;
/* Setup the PHY according to input speed */
status = hw->phy.ops.setup_speed(hw, speed, autoneg,
autoneg_wait_to_complete);
/* Synchronize MAC to PHY speed */
if (status == 0)
status = hw->phy.ops.check(hw, &speed, &link_up);
return status;
}
/**
* ixgbe_reset_hw_82598 - Performs hardware reset
* @hw: pointer to hardware structure
*
* Resets the hardware by reseting the transmit and receive units, masks and
* clears all interrupts, performing a PHY reset, and performing a link (MAC)
* reset.
**/
static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw)
{
s32 status = 0;
u32 ctrl;
u32 gheccr;
u32 i;
u32 autoc;
u8 analog_val;
/* Call adapter stop to disable tx/rx and clear interrupts */
ixgbe_stop_adapter(hw);
/*
* Power up the Atlas TX lanes if they are currently powered down.
* Atlas TX lanes are powered down for MAC loopback tests, but
* they are not automatically restored on reset.
*/
ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val);
if (analog_val & IXGBE_ATLAS_PDN_TX_REG_EN) {
/* Enable TX Atlas so packets can be transmitted again */
ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val);
analog_val &= ~IXGBE_ATLAS_PDN_TX_REG_EN;
ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, analog_val);
ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &analog_val);
analog_val &= ~IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, analog_val);
ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &analog_val);
analog_val &= ~IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, analog_val);
ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &analog_val);
analog_val &= ~IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, analog_val);
}
/* Reset PHY */
ixgbe_reset_phy(hw);
/*
* Prevent the PCI-E bus from from hanging by disabling PCI-E master
* access and verify no pending requests before reset
*/
if (ixgbe_disable_pcie_master(hw) != 0) {
status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
}
/*
* Issue global reset to the MAC. This needs to be a SW reset.
* If link reset is used, it might reset the MAC when mng is using it
*/
ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST));
IXGBE_WRITE_FLUSH(hw);
/* Poll for reset bit to self-clear indicating reset is complete */
for (i = 0; i < 10; i++) {
udelay(1);
ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
if (!(ctrl & IXGBE_CTRL_RST))
break;
}
if (ctrl & IXGBE_CTRL_RST) {
status = IXGBE_ERR_RESET_FAILED;
hw_dbg(hw, "Reset polling failed to complete.\n");
}
msleep(50);
gheccr = IXGBE_READ_REG(hw, IXGBE_GHECCR);
gheccr &= ~((1 << 21) | (1 << 18) | (1 << 9) | (1 << 6));
IXGBE_WRITE_REG(hw, IXGBE_GHECCR, gheccr);
/*
* AUTOC register which stores link settings gets cleared
* and reloaded from EEPROM after reset. We need to restore
* our stored value from init in case SW changed the attach
* type or speed. If this is the first time and link settings
* have not been stored, store default settings from AUTOC.
*/
autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
if (hw->mac.link_settings_loaded) {
autoc &= ~(IXGBE_AUTOC_LMS_ATTACH_TYPE);
autoc &= ~(IXGBE_AUTOC_LMS_MASK);
autoc |= hw->mac.link_attach_type;
autoc |= hw->mac.link_mode_select;
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
} else {
hw->mac.link_attach_type =
(autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE);
hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK);
hw->mac.link_settings_loaded = true;
}
/* Store the permanent mac address */
ixgbe_get_mac_addr(hw, hw->mac.perm_addr);
return status;
}
static struct ixgbe_mac_operations mac_ops_82598 = {
.reset = &ixgbe_reset_hw_82598,
.get_media_type = &ixgbe_get_media_type_82598,
};
static struct ixgbe_phy_operations phy_ops_82598EB = {
.setup = &ixgbe_setup_copper_link_82598,
.check = &ixgbe_check_copper_link_82598,
.setup_speed = &ixgbe_setup_copper_link_speed_82598,
.get_settings = &ixgbe_get_copper_link_settings_82598,
};
struct ixgbe_info ixgbe_82598EB_info = {
.mac = ixgbe_mac_82598EB,
.get_invariants = &ixgbe_get_invariants_82598,
.mac_ops = &mac_ops_82598,
.phy_ops = &phy_ops_82598EB,
};
static struct ixgbe_phy_operations phy_ops_82598AT = {
.setup = &ixgbe_setup_tnx_phy_link,
.check = &ixgbe_check_tnx_phy_link,
.setup_speed = &ixgbe_setup_tnx_phy_link_speed,
.get_settings = &ixgbe_get_copper_link_settings_82598,
};
struct ixgbe_info ixgbe_82598AT_info = {
.mac = ixgbe_mac_82598EB,
.get_invariants = &ixgbe_get_invariants_82598,
.mac_ops = &mac_ops_82598,
.phy_ops = &phy_ops_82598AT,
};
static struct ixgbe_phy_operations phy_ops_82598AF = {
.setup = &ixgbe_setup_mac_link_82598,
.check = &ixgbe_check_mac_link_82598,
.setup_speed = &ixgbe_setup_mac_link_speed_82598,
.get_settings = &ixgbe_get_link_settings_82598,
};
struct ixgbe_info ixgbe_82598AF_info = {
.mac = ixgbe_mac_82598EB,
.get_invariants = &ixgbe_get_invariants_82598,
.mac_ops = &mac_ops_82598,
.phy_ops = &phy_ops_82598AF,
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
Copyright(c) 1999 - 2007 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
#ifndef _IXGBE_COMMON_H_
#define _IXGBE_COMMON_H_
#include "ixgbe_type.h"
s32 ixgbe_init_hw(struct ixgbe_hw *hw);
s32 ixgbe_start_hw(struct ixgbe_hw *hw);
s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr);
s32 ixgbe_stop_adapter(struct ixgbe_hw *hw);
s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num);
s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index);
s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index);
s32 ixgbe_init_eeprom(struct ixgbe_hw *hw);
s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data);
s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val);
s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind,
u32 enable_addr);
s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list,
u32 mc_addr_count, u32 pad);
s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on);
s32 ixgbe_validate_mac_addr(u8 *mac_addr);
s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packtetbuf_num);
s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask);
void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask);
s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw);
s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val);
s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val);
#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg))
#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) (\
writel((value), ((a)->hw_addr + (reg) + ((offset) << 2))))
#define IXGBE_READ_REG_ARRAY(a, reg, offset) (\
readl((a)->hw_addr + (reg) + ((offset) << 2)))
#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
#ifdef DEBUG
#define hw_dbg(hw, format, arg...) \
printk(KERN_DEBUG, "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg);
#else
static inline int __attribute__ ((format (printf, 2, 3)))
hw_dbg(struct ixgbe_hw *hw, const char *format, ...)
{
return 0;
}
#endif
#endif /* IXGBE_COMMON */

View File

@ -0,0 +1,943 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
Copyright(c) 1999 - 2007 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/* ethtool support for ixgbe */
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include "ixgbe.h"
#define IXGBE_ALL_RAR_ENTRIES 16
struct ixgbe_stats {
char stat_string[ETH_GSTRING_LEN];
int sizeof_stat;
int stat_offset;
};
#define IXGBE_STAT(m) sizeof(((struct ixgbe_adapter *)0)->m), \
offsetof(struct ixgbe_adapter, m)
static struct ixgbe_stats ixgbe_gstrings_stats[] = {
{"rx_packets", IXGBE_STAT(net_stats.rx_packets)},
{"tx_packets", IXGBE_STAT(net_stats.tx_packets)},
{"rx_bytes", IXGBE_STAT(net_stats.rx_bytes)},
{"tx_bytes", IXGBE_STAT(net_stats.tx_bytes)},
{"lsc_int", IXGBE_STAT(lsc_int)},
{"tx_busy", IXGBE_STAT(tx_busy)},
{"non_eop_descs", IXGBE_STAT(non_eop_descs)},
{"rx_errors", IXGBE_STAT(net_stats.rx_errors)},
{"tx_errors", IXGBE_STAT(net_stats.tx_errors)},
{"rx_dropped", IXGBE_STAT(net_stats.rx_dropped)},
{"tx_dropped", IXGBE_STAT(net_stats.tx_dropped)},
{"multicast", IXGBE_STAT(net_stats.multicast)},
{"broadcast", IXGBE_STAT(stats.bprc)},
{"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) },
{"collisions", IXGBE_STAT(net_stats.collisions)},
{"rx_over_errors", IXGBE_STAT(net_stats.rx_over_errors)},
{"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)},
{"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)},
{"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)},
{"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)},
{"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)},
{"tx_carrier_errors", IXGBE_STAT(net_stats.tx_carrier_errors)},
{"tx_fifo_errors", IXGBE_STAT(net_stats.tx_fifo_errors)},
{"tx_heartbeat_errors", IXGBE_STAT(net_stats.tx_heartbeat_errors)},
{"tx_timeout_count", IXGBE_STAT(tx_timeout_count)},
{"tx_restart_queue", IXGBE_STAT(restart_queue)},
{"rx_long_length_errors", IXGBE_STAT(stats.roc)},
{"rx_short_length_errors", IXGBE_STAT(stats.ruc)},
{"tx_tcp4_seg_ctxt", IXGBE_STAT(hw_tso_ctxt)},
{"tx_tcp6_seg_ctxt", IXGBE_STAT(hw_tso6_ctxt)},
{"tx_flow_control_xon", IXGBE_STAT(stats.lxontxc)},
{"rx_flow_control_xon", IXGBE_STAT(stats.lxonrxc)},
{"tx_flow_control_xoff", IXGBE_STAT(stats.lxofftxc)},
{"rx_flow_control_xoff", IXGBE_STAT(stats.lxoffrxc)},
{"rx_csum_offload_good", IXGBE_STAT(hw_csum_rx_good)},
{"rx_csum_offload_errors", IXGBE_STAT(hw_csum_rx_error)},
{"tx_csum_offload_ctxt", IXGBE_STAT(hw_csum_tx_good)},
{"rx_header_split", IXGBE_STAT(rx_hdr_split)},
{"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)},
{"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)},
};
#define IXGBE_QUEUE_STATS_LEN \
((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \
((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \
(sizeof(struct ixgbe_queue_stats) / sizeof(u64)))
#define IXGBE_GLOBAL_STATS_LEN \
sizeof(ixgbe_gstrings_stats) / sizeof(struct ixgbe_stats)
#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
static int ixgbe_get_settings(struct net_device *netdev,
struct ethtool_cmd *ecmd)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
ecmd->port = PORT_FIBRE;
ecmd->transceiver = XCVR_EXTERNAL;
if (netif_carrier_ok(adapter->netdev)) {
ecmd->speed = SPEED_10000;
ecmd->duplex = DUPLEX_FULL;
} else {
ecmd->speed = -1;
ecmd->duplex = -1;
}
ecmd->autoneg = AUTONEG_DISABLE;
return 0;
}
static int ixgbe_set_settings(struct net_device *netdev,
struct ethtool_cmd *ecmd)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
if (ecmd->autoneg == AUTONEG_ENABLE ||
ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
return -EINVAL;
if (netif_running(adapter->netdev)) {
ixgbe_down(adapter);
ixgbe_reset(adapter);
ixgbe_up(adapter);
} else {
ixgbe_reset(adapter);
}
return 0;
}
static void ixgbe_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
pause->autoneg = AUTONEG_DISABLE;
if (hw->fc.type == ixgbe_fc_rx_pause) {
pause->rx_pause = 1;
} else if (hw->fc.type == ixgbe_fc_tx_pause) {
pause->tx_pause = 1;
} else if (hw->fc.type == ixgbe_fc_full) {
pause->rx_pause = 1;
pause->tx_pause = 1;
}
}
static int ixgbe_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
if (pause->autoneg == AUTONEG_ENABLE)
return -EINVAL;
if (pause->rx_pause && pause->tx_pause)
hw->fc.type = ixgbe_fc_full;
else if (pause->rx_pause && !pause->tx_pause)
hw->fc.type = ixgbe_fc_rx_pause;
else if (!pause->rx_pause && pause->tx_pause)
hw->fc.type = ixgbe_fc_tx_pause;
else if (!pause->rx_pause && !pause->tx_pause)
hw->fc.type = ixgbe_fc_none;
hw->fc.original_type = hw->fc.type;
if (netif_running(adapter->netdev)) {
ixgbe_down(adapter);
ixgbe_up(adapter);
} else {
ixgbe_reset(adapter);
}
return 0;
}
static u32 ixgbe_get_rx_csum(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
return (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED);
}
static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
if (data)
adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
else
adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
if (netif_running(netdev)) {
ixgbe_down(adapter);
ixgbe_up(adapter);
} else {
ixgbe_reset(adapter);
}
return 0;
}
static u32 ixgbe_get_tx_csum(struct net_device *netdev)
{
return (netdev->features & NETIF_F_HW_CSUM) != 0;
}
static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data)
{
if (data)
netdev->features |= NETIF_F_HW_CSUM;
else
netdev->features &= ~NETIF_F_HW_CSUM;
return 0;
}
static int ixgbe_set_tso(struct net_device *netdev, u32 data)
{
if (data) {
netdev->features |= NETIF_F_TSO;
netdev->features |= NETIF_F_TSO6;
} else {
netdev->features &= ~NETIF_F_TSO;
netdev->features &= ~NETIF_F_TSO6;
}
return 0;
}
static u32 ixgbe_get_msglevel(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
return adapter->msg_enable;
}
static void ixgbe_set_msglevel(struct net_device *netdev, u32 data)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
adapter->msg_enable = data;
}
static int ixgbe_get_regs_len(struct net_device *netdev)
{
#define IXGBE_REGS_LEN 1128
return IXGBE_REGS_LEN * sizeof(u32);
}
#define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_
static void ixgbe_get_regs(struct net_device *netdev,
struct ethtool_regs *regs, void *p)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
u32 *regs_buff = p;
u8 i;
memset(p, 0, IXGBE_REGS_LEN * sizeof(u32));
regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id;
/* General Registers */
regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_CTRL);
regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_STATUS);
regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_ESDP);
regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_EODSDP);
regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_FRTIMER);
regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_TCPTIMER);
/* NVM Register */
regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_EEC);
regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_EERD);
regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_FLA);
regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_EEMNGCTL);
regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_EEMNGDATA);
regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_FLMNGCTL);
regs_buff[14] = IXGBE_READ_REG(hw, IXGBE_FLMNGDATA);
regs_buff[15] = IXGBE_READ_REG(hw, IXGBE_FLMNGCNT);
regs_buff[16] = IXGBE_READ_REG(hw, IXGBE_FLOP);
regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC);
/* Interrupt */
regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICR);
regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS);
regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS);
regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC);
regs_buff[22] = IXGBE_READ_REG(hw, IXGBE_EIAC);
regs_buff[23] = IXGBE_READ_REG(hw, IXGBE_EIAM);
regs_buff[24] = IXGBE_READ_REG(hw, IXGBE_EITR(0));
regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0));
regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT);
regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA);
regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL);
regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE);
/* Flow Control */
regs_buff[30] = IXGBE_READ_REG(hw, IXGBE_PFCTOP);
regs_buff[31] = IXGBE_READ_REG(hw, IXGBE_FCTTV(0));
regs_buff[32] = IXGBE_READ_REG(hw, IXGBE_FCTTV(1));
regs_buff[33] = IXGBE_READ_REG(hw, IXGBE_FCTTV(2));
regs_buff[34] = IXGBE_READ_REG(hw, IXGBE_FCTTV(3));
for (i = 0; i < 8; i++)
regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL(i));
for (i = 0; i < 8; i++)
regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH(i));
regs_buff[51] = IXGBE_READ_REG(hw, IXGBE_FCRTV);
regs_buff[52] = IXGBE_READ_REG(hw, IXGBE_TFCS);
/* Receive DMA */
for (i = 0; i < 64; i++)
regs_buff[53 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAL(i));
for (i = 0; i < 64; i++)
regs_buff[117 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAH(i));
for (i = 0; i < 64; i++)
regs_buff[181 + i] = IXGBE_READ_REG(hw, IXGBE_RDLEN(i));
for (i = 0; i < 64; i++)
regs_buff[245 + i] = IXGBE_READ_REG(hw, IXGBE_RDH(i));
for (i = 0; i < 64; i++)
regs_buff[309 + i] = IXGBE_READ_REG(hw, IXGBE_RDT(i));
for (i = 0; i < 64; i++)
regs_buff[373 + i] = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
for (i = 0; i < 16; i++)
regs_buff[437 + i] = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i));
for (i = 0; i < 16; i++)
regs_buff[453 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i));
regs_buff[469] = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
for (i = 0; i < 8; i++)
regs_buff[470 + i] = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
regs_buff[478] = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
regs_buff[479] = IXGBE_READ_REG(hw, IXGBE_DROPEN);
/* Receive */
regs_buff[480] = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
regs_buff[481] = IXGBE_READ_REG(hw, IXGBE_RFCTL);
for (i = 0; i < 16; i++)
regs_buff[482 + i] = IXGBE_READ_REG(hw, IXGBE_RAL(i));
for (i = 0; i < 16; i++)
regs_buff[498 + i] = IXGBE_READ_REG(hw, IXGBE_RAH(i));
regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE);
regs_buff[515] = IXGBE_READ_REG(hw, IXGBE_FCTRL);
regs_buff[516] = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
regs_buff[517] = IXGBE_READ_REG(hw, IXGBE_MCSTCTRL);
regs_buff[518] = IXGBE_READ_REG(hw, IXGBE_MRQC);
regs_buff[519] = IXGBE_READ_REG(hw, IXGBE_VMD_CTL);
for (i = 0; i < 8; i++)
regs_buff[520 + i] = IXGBE_READ_REG(hw, IXGBE_IMIR(i));
for (i = 0; i < 8; i++)
regs_buff[528 + i] = IXGBE_READ_REG(hw, IXGBE_IMIREXT(i));
regs_buff[536] = IXGBE_READ_REG(hw, IXGBE_IMIRVP);
/* Transmit */
for (i = 0; i < 32; i++)
regs_buff[537 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAL(i));
for (i = 0; i < 32; i++)
regs_buff[569 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAH(i));
for (i = 0; i < 32; i++)
regs_buff[601 + i] = IXGBE_READ_REG(hw, IXGBE_TDLEN(i));
for (i = 0; i < 32; i++)
regs_buff[633 + i] = IXGBE_READ_REG(hw, IXGBE_TDH(i));
for (i = 0; i < 32; i++)
regs_buff[665 + i] = IXGBE_READ_REG(hw, IXGBE_TDT(i));
for (i = 0; i < 32; i++)
regs_buff[697 + i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
for (i = 0; i < 32; i++)
regs_buff[729 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAL(i));
for (i = 0; i < 32; i++)
regs_buff[761 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAH(i));
regs_buff[793] = IXGBE_READ_REG(hw, IXGBE_DTXCTL);
for (i = 0; i < 16; i++)
regs_buff[794 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i));
regs_buff[810] = IXGBE_READ_REG(hw, IXGBE_TIPG);
for (i = 0; i < 8; i++)
regs_buff[811 + i] = IXGBE_READ_REG(hw, IXGBE_TXPBSIZE(i));
regs_buff[819] = IXGBE_READ_REG(hw, IXGBE_MNGTXMAP);
/* Wake Up */
regs_buff[820] = IXGBE_READ_REG(hw, IXGBE_WUC);
regs_buff[821] = IXGBE_READ_REG(hw, IXGBE_WUFC);
regs_buff[822] = IXGBE_READ_REG(hw, IXGBE_WUS);
regs_buff[823] = IXGBE_READ_REG(hw, IXGBE_IPAV);
regs_buff[824] = IXGBE_READ_REG(hw, IXGBE_IP4AT);
regs_buff[825] = IXGBE_READ_REG(hw, IXGBE_IP6AT);
regs_buff[826] = IXGBE_READ_REG(hw, IXGBE_WUPL);
regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM);
regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT);
/* DCE */
regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS);
regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS);
regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS);
regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RUPPBMR);
for (i = 0; i < 8; i++)
regs_buff[833 + i] = IXGBE_READ_REG(hw, IXGBE_RT2CR(i));
for (i = 0; i < 8; i++)
regs_buff[841 + i] = IXGBE_READ_REG(hw, IXGBE_RT2SR(i));
for (i = 0; i < 8; i++)
regs_buff[849 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCCR(i));
for (i = 0; i < 8; i++)
regs_buff[857 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCSR(i));
for (i = 0; i < 8; i++)
regs_buff[865 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCCR(i));
for (i = 0; i < 8; i++)
regs_buff[873 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCSR(i));
/* Statistics */
regs_buff[881] = IXGBE_GET_STAT(adapter, crcerrs);
regs_buff[882] = IXGBE_GET_STAT(adapter, illerrc);
regs_buff[883] = IXGBE_GET_STAT(adapter, errbc);
regs_buff[884] = IXGBE_GET_STAT(adapter, mspdc);
for (i = 0; i < 8; i++)
regs_buff[885 + i] = IXGBE_GET_STAT(adapter, mpc[i]);
regs_buff[893] = IXGBE_GET_STAT(adapter, mlfc);
regs_buff[894] = IXGBE_GET_STAT(adapter, mrfc);
regs_buff[895] = IXGBE_GET_STAT(adapter, rlec);
regs_buff[896] = IXGBE_GET_STAT(adapter, lxontxc);
regs_buff[897] = IXGBE_GET_STAT(adapter, lxonrxc);
regs_buff[898] = IXGBE_GET_STAT(adapter, lxofftxc);
regs_buff[899] = IXGBE_GET_STAT(adapter, lxoffrxc);
for (i = 0; i < 8; i++)
regs_buff[900 + i] = IXGBE_GET_STAT(adapter, pxontxc[i]);
for (i = 0; i < 8; i++)
regs_buff[908 + i] = IXGBE_GET_STAT(adapter, pxonrxc[i]);
for (i = 0; i < 8; i++)
regs_buff[916 + i] = IXGBE_GET_STAT(adapter, pxofftxc[i]);
for (i = 0; i < 8; i++)
regs_buff[924 + i] = IXGBE_GET_STAT(adapter, pxoffrxc[i]);
regs_buff[932] = IXGBE_GET_STAT(adapter, prc64);
regs_buff[933] = IXGBE_GET_STAT(adapter, prc127);
regs_buff[934] = IXGBE_GET_STAT(adapter, prc255);
regs_buff[935] = IXGBE_GET_STAT(adapter, prc511);
regs_buff[936] = IXGBE_GET_STAT(adapter, prc1023);
regs_buff[937] = IXGBE_GET_STAT(adapter, prc1522);
regs_buff[938] = IXGBE_GET_STAT(adapter, gprc);
regs_buff[939] = IXGBE_GET_STAT(adapter, bprc);
regs_buff[940] = IXGBE_GET_STAT(adapter, mprc);
regs_buff[941] = IXGBE_GET_STAT(adapter, gptc);
regs_buff[942] = IXGBE_GET_STAT(adapter, gorc);
regs_buff[944] = IXGBE_GET_STAT(adapter, gotc);
for (i = 0; i < 8; i++)
regs_buff[946 + i] = IXGBE_GET_STAT(adapter, rnbc[i]);
regs_buff[954] = IXGBE_GET_STAT(adapter, ruc);
regs_buff[955] = IXGBE_GET_STAT(adapter, rfc);
regs_buff[956] = IXGBE_GET_STAT(adapter, roc);
regs_buff[957] = IXGBE_GET_STAT(adapter, rjc);
regs_buff[958] = IXGBE_GET_STAT(adapter, mngprc);
regs_buff[959] = IXGBE_GET_STAT(adapter, mngpdc);
regs_buff[960] = IXGBE_GET_STAT(adapter, mngptc);
regs_buff[961] = IXGBE_GET_STAT(adapter, tor);
regs_buff[963] = IXGBE_GET_STAT(adapter, tpr);
regs_buff[964] = IXGBE_GET_STAT(adapter, tpt);
regs_buff[965] = IXGBE_GET_STAT(adapter, ptc64);
regs_buff[966] = IXGBE_GET_STAT(adapter, ptc127);
regs_buff[967] = IXGBE_GET_STAT(adapter, ptc255);
regs_buff[968] = IXGBE_GET_STAT(adapter, ptc511);
regs_buff[969] = IXGBE_GET_STAT(adapter, ptc1023);
regs_buff[970] = IXGBE_GET_STAT(adapter, ptc1522);
regs_buff[971] = IXGBE_GET_STAT(adapter, mptc);
regs_buff[972] = IXGBE_GET_STAT(adapter, bptc);
regs_buff[973] = IXGBE_GET_STAT(adapter, xec);
for (i = 0; i < 16; i++)
regs_buff[974 + i] = IXGBE_GET_STAT(adapter, qprc[i]);
for (i = 0; i < 16; i++)
regs_buff[990 + i] = IXGBE_GET_STAT(adapter, qptc[i]);
for (i = 0; i < 16; i++)
regs_buff[1006 + i] = IXGBE_GET_STAT(adapter, qbrc[i]);
for (i = 0; i < 16; i++)
regs_buff[1022 + i] = IXGBE_GET_STAT(adapter, qbtc[i]);
/* MAC */
regs_buff[1038] = IXGBE_READ_REG(hw, IXGBE_PCS1GCFIG);
regs_buff[1039] = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL);
regs_buff[1040] = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA);
regs_buff[1041] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG0);
regs_buff[1042] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG1);
regs_buff[1043] = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
regs_buff[1044] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
regs_buff[1045] = IXGBE_READ_REG(hw, IXGBE_PCS1GANNP);
regs_buff[1046] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLPNP);
regs_buff[1047] = IXGBE_READ_REG(hw, IXGBE_HLREG0);
regs_buff[1048] = IXGBE_READ_REG(hw, IXGBE_HLREG1);
regs_buff[1049] = IXGBE_READ_REG(hw, IXGBE_PAP);
regs_buff[1050] = IXGBE_READ_REG(hw, IXGBE_MACA);
regs_buff[1051] = IXGBE_READ_REG(hw, IXGBE_APAE);
regs_buff[1052] = IXGBE_READ_REG(hw, IXGBE_ARD);
regs_buff[1053] = IXGBE_READ_REG(hw, IXGBE_AIS);
regs_buff[1054] = IXGBE_READ_REG(hw, IXGBE_MSCA);
regs_buff[1055] = IXGBE_READ_REG(hw, IXGBE_MSRWD);
regs_buff[1056] = IXGBE_READ_REG(hw, IXGBE_MLADD);
regs_buff[1057] = IXGBE_READ_REG(hw, IXGBE_MHADD);
regs_buff[1058] = IXGBE_READ_REG(hw, IXGBE_TREG);
regs_buff[1059] = IXGBE_READ_REG(hw, IXGBE_PCSS1);
regs_buff[1060] = IXGBE_READ_REG(hw, IXGBE_PCSS2);
regs_buff[1061] = IXGBE_READ_REG(hw, IXGBE_XPCSS);
regs_buff[1062] = IXGBE_READ_REG(hw, IXGBE_SERDESC);
regs_buff[1063] = IXGBE_READ_REG(hw, IXGBE_MACS);
regs_buff[1064] = IXGBE_READ_REG(hw, IXGBE_AUTOC);
regs_buff[1065] = IXGBE_READ_REG(hw, IXGBE_LINKS);
regs_buff[1066] = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
regs_buff[1067] = IXGBE_READ_REG(hw, IXGBE_AUTOC3);
regs_buff[1068] = IXGBE_READ_REG(hw, IXGBE_ANLP1);
regs_buff[1069] = IXGBE_READ_REG(hw, IXGBE_ANLP2);
regs_buff[1070] = IXGBE_READ_REG(hw, IXGBE_ATLASCTL);
/* Diagnostic */
regs_buff[1071] = IXGBE_READ_REG(hw, IXGBE_RDSTATCTL);
for (i = 0; i < 8; i++)
regs_buff[1072] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i));
regs_buff[1080] = IXGBE_READ_REG(hw, IXGBE_RDHMPN);
regs_buff[1081] = IXGBE_READ_REG(hw, IXGBE_RIC_DW0);
regs_buff[1082] = IXGBE_READ_REG(hw, IXGBE_RIC_DW1);
regs_buff[1083] = IXGBE_READ_REG(hw, IXGBE_RIC_DW2);
regs_buff[1084] = IXGBE_READ_REG(hw, IXGBE_RIC_DW3);
regs_buff[1085] = IXGBE_READ_REG(hw, IXGBE_RDPROBE);
regs_buff[1086] = IXGBE_READ_REG(hw, IXGBE_TDSTATCTL);
for (i = 0; i < 8; i++)
regs_buff[1087] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i));
regs_buff[1095] = IXGBE_READ_REG(hw, IXGBE_TDHMPN);
regs_buff[1096] = IXGBE_READ_REG(hw, IXGBE_TIC_DW0);
regs_buff[1097] = IXGBE_READ_REG(hw, IXGBE_TIC_DW1);
regs_buff[1098] = IXGBE_READ_REG(hw, IXGBE_TIC_DW2);
regs_buff[1099] = IXGBE_READ_REG(hw, IXGBE_TIC_DW3);
regs_buff[1100] = IXGBE_READ_REG(hw, IXGBE_TDPROBE);
regs_buff[1101] = IXGBE_READ_REG(hw, IXGBE_TXBUFCTRL);
regs_buff[1102] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA0);
regs_buff[1103] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA1);
regs_buff[1104] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA2);
regs_buff[1105] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA3);
regs_buff[1106] = IXGBE_READ_REG(hw, IXGBE_RXBUFCTRL);
regs_buff[1107] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA0);
regs_buff[1108] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA1);
regs_buff[1109] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA2);
regs_buff[1110] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA3);
for (i = 0; i < 8; i++)
regs_buff[1111] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i));
regs_buff[1119] = IXGBE_READ_REG(hw, IXGBE_RFVAL);
regs_buff[1120] = IXGBE_READ_REG(hw, IXGBE_MDFTC1);
regs_buff[1121] = IXGBE_READ_REG(hw, IXGBE_MDFTC2);
regs_buff[1122] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO1);
regs_buff[1123] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO2);
regs_buff[1124] = IXGBE_READ_REG(hw, IXGBE_MDFTS);
regs_buff[1125] = IXGBE_READ_REG(hw, IXGBE_PCIEECCCTL);
regs_buff[1126] = IXGBE_READ_REG(hw, IXGBE_PBTXECC);
regs_buff[1127] = IXGBE_READ_REG(hw, IXGBE_PBRXECC);
}
static int ixgbe_get_eeprom_len(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
return adapter->hw.eeprom.word_size * 2;
}
static int ixgbe_get_eeprom(struct net_device *netdev,
struct ethtool_eeprom *eeprom, u8 *bytes)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
u16 *eeprom_buff;
int first_word, last_word, eeprom_len;
int ret_val = 0;
u16 i;
if (eeprom->len == 0)
return -EINVAL;
eeprom->magic = hw->vendor_id | (hw->device_id << 16);
first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
eeprom_len = last_word - first_word + 1;
eeprom_buff = kmalloc(sizeof(u16) * eeprom_len, GFP_KERNEL);
if (!eeprom_buff)
return -ENOMEM;
for (i = 0; i < eeprom_len; i++) {
if ((ret_val = ixgbe_read_eeprom(hw, first_word + i,
&eeprom_buff[i])))
break;
}
/* Device's eeprom is always little-endian, word addressable */
for (i = 0; i < eeprom_len; i++)
le16_to_cpus(&eeprom_buff[i]);
memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
kfree(eeprom_buff);
return ret_val;
}
static void ixgbe_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
strncpy(drvinfo->driver, ixgbe_driver_name, 32);
strncpy(drvinfo->version, ixgbe_driver_version, 32);
strncpy(drvinfo->fw_version, "N/A", 32);
strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
drvinfo->n_stats = IXGBE_STATS_LEN;
drvinfo->regdump_len = ixgbe_get_regs_len(netdev);
}
static void ixgbe_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_ring *tx_ring = adapter->tx_ring;
struct ixgbe_ring *rx_ring = adapter->rx_ring;
ring->rx_max_pending = IXGBE_MAX_RXD;
ring->tx_max_pending = IXGBE_MAX_TXD;
ring->rx_mini_max_pending = 0;
ring->rx_jumbo_max_pending = 0;
ring->rx_pending = rx_ring->count;
ring->tx_pending = tx_ring->count;
ring->rx_mini_pending = 0;
ring->rx_jumbo_pending = 0;
}
static int ixgbe_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_tx_buffer *old_buf;
struct ixgbe_rx_buffer *old_rx_buf;
void *old_desc;
int i, err;
u32 new_rx_count, new_tx_count, old_size;
dma_addr_t old_dma;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
new_rx_count = max(ring->rx_pending, (u32)IXGBE_MIN_RXD);
new_rx_count = min(new_rx_count, (u32)IXGBE_MAX_RXD);
new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE);
new_tx_count = max(ring->tx_pending, (u32)IXGBE_MIN_TXD);
new_tx_count = min(new_tx_count, (u32)IXGBE_MAX_TXD);
new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE);
if ((new_tx_count == adapter->tx_ring->count) &&
(new_rx_count == adapter->rx_ring->count)) {
/* nothing to do */
return 0;
}
if (netif_running(adapter->netdev))
ixgbe_down(adapter);
/*
* We can't just free everything and then setup again,
* because the ISRs in MSI-X mode get passed pointers
* to the tx and rx ring structs.
*/
if (new_tx_count != adapter->tx_ring->count) {
for (i = 0; i < adapter->num_tx_queues; i++) {
/* Save existing descriptor ring */
old_buf = adapter->tx_ring[i].tx_buffer_info;
old_desc = adapter->tx_ring[i].desc;
old_size = adapter->tx_ring[i].size;
old_dma = adapter->tx_ring[i].dma;
/* Try to allocate a new one */
adapter->tx_ring[i].tx_buffer_info = NULL;
adapter->tx_ring[i].desc = NULL;
adapter->tx_ring[i].count = new_tx_count;
err = ixgbe_setup_tx_resources(adapter,
&adapter->tx_ring[i]);
if (err) {
/* Restore the old one so at least
the adapter still works, even if
we failed the request */
adapter->tx_ring[i].tx_buffer_info = old_buf;
adapter->tx_ring[i].desc = old_desc;
adapter->tx_ring[i].size = old_size;
adapter->tx_ring[i].dma = old_dma;
goto err_setup;
}
/* Free the old buffer manually */
vfree(old_buf);
pci_free_consistent(adapter->pdev, old_size,
old_desc, old_dma);
}
}
if (new_rx_count != adapter->rx_ring->count) {
for (i = 0; i < adapter->num_rx_queues; i++) {
old_rx_buf = adapter->rx_ring[i].rx_buffer_info;
old_desc = adapter->rx_ring[i].desc;
old_size = adapter->rx_ring[i].size;
old_dma = adapter->rx_ring[i].dma;
adapter->rx_ring[i].rx_buffer_info = NULL;
adapter->rx_ring[i].desc = NULL;
adapter->rx_ring[i].dma = 0;
adapter->rx_ring[i].count = new_rx_count;
err = ixgbe_setup_rx_resources(adapter,
&adapter->rx_ring[i]);
if (err) {
adapter->rx_ring[i].rx_buffer_info = old_rx_buf;
adapter->rx_ring[i].desc = old_desc;
adapter->rx_ring[i].size = old_size;
adapter->rx_ring[i].dma = old_dma;
goto err_setup;
}
vfree(old_rx_buf);
pci_free_consistent(adapter->pdev, old_size, old_desc,
old_dma);
}
}
err = 0;
err_setup:
if (netif_running(adapter->netdev))
ixgbe_up(adapter);
return err;
}
static int ixgbe_get_stats_count(struct net_device *netdev)
{
return IXGBE_STATS_LEN;
}
static void ixgbe_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, u64 *data)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
u64 *queue_stat;
int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
int j, k;
int i;
ixgbe_update_stats(adapter);
for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
char *p = (char *)adapter + ixgbe_gstrings_stats[i].stat_offset;
data[i] = (ixgbe_gstrings_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
for (j = 0; j < adapter->num_tx_queues; j++) {
queue_stat = (u64 *)&adapter->tx_ring[j].stats;
for (k = 0; k < stat_count; k++)
data[i + k] = queue_stat[k];
i += k;
}
for (j = 0; j < adapter->num_rx_queues; j++) {
queue_stat = (u64 *)&adapter->rx_ring[j].stats;
for (k = 0; k < stat_count; k++)
data[i + k] = queue_stat[k];
i += k;
}
}
static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
u8 *data)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
u8 *p = data;
int i;
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
memcpy(p, ixgbe_gstrings_stats[i].stat_string,
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
for (i = 0; i < adapter->num_tx_queues; i++) {
sprintf(p, "tx_queue_%u_packets", i);
p += ETH_GSTRING_LEN;
sprintf(p, "tx_queue_%u_bytes", i);
p += ETH_GSTRING_LEN;
}
for (i = 0; i < adapter->num_rx_queues; i++) {
sprintf(p, "rx_queue_%u_packets", i);
p += ETH_GSTRING_LEN;
sprintf(p, "rx_queue_%u_bytes", i);
p += ETH_GSTRING_LEN;
}
/* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */
break;
}
}
static void ixgbe_get_wol(struct net_device *netdev,
struct ethtool_wolinfo *wol)
{
wol->supported = 0;
wol->wolopts = 0;
return;
}
static int ixgbe_nway_reset(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
if (netif_running(netdev)) {
ixgbe_down(adapter);
ixgbe_reset(adapter);
ixgbe_up(adapter);
}
return 0;
}
static int ixgbe_phys_id(struct net_device *netdev, u32 data)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
u32 led_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_LEDCTL);
u32 i;
if (!data || data > 300)
data = 300;
for (i = 0; i < (data * 1000); i += 400) {
ixgbe_led_on(&adapter->hw, IXGBE_LED_ON);
msleep_interruptible(200);
ixgbe_led_off(&adapter->hw, IXGBE_LED_ON);
msleep_interruptible(200);
}
/* Restore LED settings */
IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, led_reg);
return 0;
}
static int ixgbe_get_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
if (adapter->rx_eitr == 0)
ec->rx_coalesce_usecs = 0;
else
ec->rx_coalesce_usecs = 1000000 / adapter->rx_eitr;
if (adapter->tx_eitr == 0)
ec->tx_coalesce_usecs = 0;
else
ec->tx_coalesce_usecs = 1000000 / adapter->tx_eitr;
ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0].work_limit;
return 0;
}
static int ixgbe_set_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
if ((ec->rx_coalesce_usecs > IXGBE_MAX_ITR_USECS) ||
((ec->rx_coalesce_usecs > 0) &&
(ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS)))
return -EINVAL;
if ((ec->tx_coalesce_usecs > IXGBE_MAX_ITR_USECS) ||
((ec->tx_coalesce_usecs > 0) &&
(ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS)))
return -EINVAL;
/* convert to rate of irq's per second */
if (ec->rx_coalesce_usecs == 0)
adapter->rx_eitr = 0;
else
adapter->rx_eitr = (1000000 / ec->rx_coalesce_usecs);
if (ec->tx_coalesce_usecs == 0)
adapter->tx_eitr = 0;
else
adapter->tx_eitr = (1000000 / ec->tx_coalesce_usecs);
if (ec->tx_max_coalesced_frames_irq)
adapter->tx_ring[0].work_limit =
ec->tx_max_coalesced_frames_irq;
if (netif_running(netdev)) {
ixgbe_down(adapter);
ixgbe_up(adapter);
}
return 0;
}
static struct ethtool_ops ixgbe_ethtool_ops = {
.get_settings = ixgbe_get_settings,
.set_settings = ixgbe_set_settings,
.get_drvinfo = ixgbe_get_drvinfo,
.get_regs_len = ixgbe_get_regs_len,
.get_regs = ixgbe_get_regs,
.get_wol = ixgbe_get_wol,
.nway_reset = ixgbe_nway_reset,
.get_link = ethtool_op_get_link,
.get_eeprom_len = ixgbe_get_eeprom_len,
.get_eeprom = ixgbe_get_eeprom,
.get_ringparam = ixgbe_get_ringparam,
.set_ringparam = ixgbe_set_ringparam,
.get_pauseparam = ixgbe_get_pauseparam,
.set_pauseparam = ixgbe_set_pauseparam,
.get_rx_csum = ixgbe_get_rx_csum,
.set_rx_csum = ixgbe_set_rx_csum,
.get_tx_csum = ixgbe_get_tx_csum,
.set_tx_csum = ixgbe_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_msglevel = ixgbe_get_msglevel,
.set_msglevel = ixgbe_set_msglevel,
.get_tso = ethtool_op_get_tso,
.set_tso = ixgbe_set_tso,
.get_strings = ixgbe_get_strings,
.phys_id = ixgbe_phys_id,
.get_stats_count = ixgbe_get_stats_count,
.get_ethtool_stats = ixgbe_get_ethtool_stats,
.get_coalesce = ixgbe_get_coalesce,
.set_coalesce = ixgbe_set_coalesce,
};
void ixgbe_set_ethtool_ops(struct net_device *netdev)
{
SET_ETHTOOL_OPS(netdev, &ixgbe_ethtool_ops);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,494 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
Copyright(c) 1999 - 2007 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include "ixgbe_common.h"
#include "ixgbe_phy.h"
static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id);
static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw);
static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr);
static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
u32 device_type, u16 phy_data);
/**
* ixgbe_identify_phy - Get physical layer module
* @hw: pointer to hardware structure
*
* Determines the physical layer module found on the current adapter.
**/
s32 ixgbe_identify_phy(struct ixgbe_hw *hw)
{
s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
u32 phy_addr;
for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
if (ixgbe_validate_phy_addr(hw, phy_addr)) {
hw->phy.addr = phy_addr;
ixgbe_get_phy_id(hw);
hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id);
status = 0;
break;
}
}
return status;
}
/**
* ixgbe_validate_phy_addr - Determines phy address is valid
* @hw: pointer to hardware structure
*
**/
static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr)
{
u16 phy_id = 0;
bool valid = false;
hw->phy.addr = phy_addr;
ixgbe_read_phy_reg(hw,
IXGBE_MDIO_PHY_ID_HIGH,
IXGBE_MDIO_PMA_PMD_DEV_TYPE,
&phy_id);
if (phy_id != 0xFFFF && phy_id != 0x0)
valid = true;
return valid;
}
/**
* ixgbe_get_phy_id - Get the phy type
* @hw: pointer to hardware structure
*
**/
static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw)
{
u32 status;
u16 phy_id_high = 0;
u16 phy_id_low = 0;
status = ixgbe_read_phy_reg(hw,
IXGBE_MDIO_PHY_ID_HIGH,
IXGBE_MDIO_PMA_PMD_DEV_TYPE,
&phy_id_high);
if (status == 0) {
hw->phy.id = (u32)(phy_id_high << 16);
status = ixgbe_read_phy_reg(hw,
IXGBE_MDIO_PHY_ID_LOW,
IXGBE_MDIO_PMA_PMD_DEV_TYPE,
&phy_id_low);
hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
}
return status;
}
/**
* ixgbe_get_phy_type_from_id - Get the phy type
* @hw: pointer to hardware structure
*
**/
static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
{
enum ixgbe_phy_type phy_type;
switch (phy_id) {
case TN1010_PHY_ID:
phy_type = ixgbe_phy_tn;
break;
case QT2022_PHY_ID:
phy_type = ixgbe_phy_qt;
break;
default:
phy_type = ixgbe_phy_unknown;
break;
}
return phy_type;
}
/**
* ixgbe_reset_phy - Performs a PHY reset
* @hw: pointer to hardware structure
**/
s32 ixgbe_reset_phy(struct ixgbe_hw *hw)
{
/*
* Perform soft PHY reset to the PHY_XS.
* This will cause a soft reset to the PHY
*/
return ixgbe_write_phy_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
IXGBE_MDIO_PHY_XS_DEV_TYPE,
IXGBE_MDIO_PHY_XS_RESET);
}
/**
* ixgbe_read_phy_reg - Reads a value from a specified PHY register
* @hw: pointer to hardware structure
* @reg_addr: 32 bit address of PHY register to read
* @phy_data: Pointer to read data from PHY register
**/
s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
u32 device_type, u16 *phy_data)
{
u32 command;
u32 i;
u32 timeout = 10;
u32 data;
s32 status = 0;
u16 gssr;
if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
gssr = IXGBE_GSSR_PHY1_SM;
else
gssr = IXGBE_GSSR_PHY0_SM;
if (ixgbe_acquire_swfw_sync(hw, gssr) != 0)
status = IXGBE_ERR_SWFW_SYNC;
if (status == 0) {
/* Setup and write the address cycle command */
command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
(device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
(hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
(IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
/*
* Check every 10 usec to see if the address cycle completed.
* The MDI Command bit will clear when the operation is
* complete
*/
for (i = 0; i < timeout; i++) {
udelay(10);
command = IXGBE_READ_REG(hw, IXGBE_MSCA);
if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
break;
}
if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
hw_dbg(hw, "PHY address command did not complete.\n");
status = IXGBE_ERR_PHY;
}
if (status == 0) {
/*
* Address cycle complete, setup and write the read
* command
*/
command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
(device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
(hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
(IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
/*
* Check every 10 usec to see if the address cycle
* completed. The MDI Command bit will clear when the
* operation is complete
*/
for (i = 0; i < timeout; i++) {
udelay(10);
command = IXGBE_READ_REG(hw, IXGBE_MSCA);
if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
break;
}
if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
hw_dbg(hw,
"PHY read command didn't complete\n");
status = IXGBE_ERR_PHY;
} else {
/*
* Read operation is complete. Get the data
* from MSRWD
*/
data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
*phy_data = (u16)(data);
}
}
ixgbe_release_swfw_sync(hw, gssr);
}
return status;
}
/**
* ixgbe_write_phy_reg - Writes a value to specified PHY register
* @hw: pointer to hardware structure
* @reg_addr: 32 bit PHY register to write
* @device_type: 5 bit device type
* @phy_data: Data to write to the PHY register
**/
static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
u32 device_type, u16 phy_data)
{
u32 command;
u32 i;
u32 timeout = 10;
s32 status = 0;
u16 gssr;
if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
gssr = IXGBE_GSSR_PHY1_SM;
else
gssr = IXGBE_GSSR_PHY0_SM;
if (ixgbe_acquire_swfw_sync(hw, gssr) != 0)
status = IXGBE_ERR_SWFW_SYNC;
if (status == 0) {
/* Put the data in the MDI single read and write data register*/
IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
/* Setup and write the address cycle command */
command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
(device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
(hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
(IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
/*
* Check every 10 usec to see if the address cycle completed.
* The MDI Command bit will clear when the operation is
* complete
*/
for (i = 0; i < timeout; i++) {
udelay(10);
command = IXGBE_READ_REG(hw, IXGBE_MSCA);
if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
hw_dbg(hw, "PHY address cmd didn't complete\n");
break;
}
}
if ((command & IXGBE_MSCA_MDI_COMMAND) != 0)
status = IXGBE_ERR_PHY;
if (status == 0) {
/*
* Address cycle complete, setup and write the write
* command
*/
command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
(device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
(hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
(IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
/*
* Check every 10 usec to see if the address cycle
* completed. The MDI Command bit will clear when the
* operation is complete
*/
for (i = 0; i < timeout; i++) {
udelay(10);
command = IXGBE_READ_REG(hw, IXGBE_MSCA);
if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
hw_dbg(hw, "PHY write command did not "
"complete.\n");
break;
}
}
if ((command & IXGBE_MSCA_MDI_COMMAND) != 0)
status = IXGBE_ERR_PHY;
}
ixgbe_release_swfw_sync(hw, gssr);
}
return status;
}
/**
* ixgbe_setup_tnx_phy_link - Set and restart autoneg
* @hw: pointer to hardware structure
*
* Restart autonegotiation and PHY and waits for completion.
**/
s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw)
{
s32 status = IXGBE_NOT_IMPLEMENTED;
u32 time_out;
u32 max_time_out = 10;
u16 autoneg_speed_selection_register = 0x10;
u16 autoneg_restart_mask = 0x0200;
u16 autoneg_complete_mask = 0x0020;
u16 autoneg_reg = 0;
/*
* Set advertisement settings in PHY based on autoneg_advertised
* settings. If autoneg_advertised = 0, then advertise default values
* txn devices cannot be "forced" to a autoneg 10G and fail. But can
* for a 1G.
*/
ixgbe_read_phy_reg(hw,
autoneg_speed_selection_register,
IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
&autoneg_reg);
if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL)
autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */
else
autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */
ixgbe_write_phy_reg(hw,
autoneg_speed_selection_register,
IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
autoneg_reg);
/* Restart PHY autonegotiation and wait for completion */
ixgbe_read_phy_reg(hw,
IXGBE_MDIO_AUTO_NEG_CONTROL,
IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
&autoneg_reg);
autoneg_reg |= autoneg_restart_mask;
ixgbe_write_phy_reg(hw,
IXGBE_MDIO_AUTO_NEG_CONTROL,
IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
autoneg_reg);
/* Wait for autonegotiation to finish */
for (time_out = 0; time_out < max_time_out; time_out++) {
udelay(10);
/* Restart PHY autonegotiation and wait for completion */
status = ixgbe_read_phy_reg(hw,
IXGBE_MDIO_AUTO_NEG_STATUS,
IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
&autoneg_reg);
autoneg_reg &= autoneg_complete_mask;
if (autoneg_reg == autoneg_complete_mask) {
status = 0;
break;
}
}
if (time_out == max_time_out)
status = IXGBE_ERR_LINK_SETUP;
return status;
}
/**
* ixgbe_check_tnx_phy_link - Determine link and speed status
* @hw: pointer to hardware structure
*
* Reads the VS1 register to determine if link is up and the current speed for
* the PHY.
**/
s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed,
bool *link_up)
{
s32 status = 0;
u32 time_out;
u32 max_time_out = 10;
u16 phy_link = 0;
u16 phy_speed = 0;
u16 phy_data = 0;
/* Initialize speed and link to default case */
*link_up = false;
*speed = IXGBE_LINK_SPEED_10GB_FULL;
/*
* Check current speed and link status of the PHY register.
* This is a vendor specific register and may have to
* be changed for other copper PHYs.
*/
for (time_out = 0; time_out < max_time_out; time_out++) {
udelay(10);
if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
*link_up = true;
if (phy_speed ==
IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
*speed = IXGBE_LINK_SPEED_1GB_FULL;
break;
} else {
status = ixgbe_read_phy_reg(hw,
IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS,
IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
&phy_data);
phy_link = phy_data &
IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
phy_speed = phy_data &
IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
}
}
return status;
}
/**
* ixgbe_setup_tnx_phy_link_speed - Sets the auto advertised capabilities
* @hw: pointer to hardware structure
* @speed: new link speed
* @autoneg: true if autonegotiation enabled
**/
s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed,
bool autoneg,
bool autoneg_wait_to_complete)
{
/*
* Clear autoneg_advertised and set new values based on input link
* speed.
*/
hw->phy.autoneg_advertised = 0;
if (speed & IXGBE_LINK_SPEED_10GB_FULL)
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
if (speed & IXGBE_LINK_SPEED_1GB_FULL)
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
/* Setup link based on the new speed settings */
ixgbe_setup_tnx_phy_link(hw);
return 0;
}

View File

@ -0,0 +1,50 @@
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
Copyright(c) 1999 - 2007 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope 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, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
#ifndef _IXGBE_PHY_H_
#define _IXGBE_PHY_H_
#include "ixgbe_type.h"
s32 ixgbe_init_shared_code_phy(struct ixgbe_hw *hw);
s32 ixgbe_setup_phy_link(struct ixgbe_hw *hw);
s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up);
s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg,
bool autoneg_wait_to_complete);
s32 ixgbe_identify_phy(struct ixgbe_hw *hw);
s32 ixgbe_reset_phy(struct ixgbe_hw *hw);
s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
u32 device_type, u16 *phy_data);
/* PHY specific */
s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw);
s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up);
s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg,
bool autoneg_wait_to_complete);
#endif /* _IXGBE_PHY_H_ */

File diff suppressed because it is too large Load Diff