mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-10 09:22:44 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
36
drivers/net/ethernet/intel/igb/Makefile
Normal file
36
drivers/net/ethernet/intel/igb/Makefile
Normal file
|
@ -0,0 +1,36 @@
|
|||
################################################################################
|
||||
#
|
||||
# Intel 82575 PCI-Express Ethernet Linux driver
|
||||
# Copyright(c) 1999 - 2014 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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) 82575 PCI-Express ethernet driver
|
||||
#
|
||||
|
||||
obj-$(CONFIG_IGB) += igb.o
|
||||
|
||||
igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
|
||||
e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \
|
||||
e1000_i210.o igb_ptp.o igb_hwmon.o
|
2884
drivers/net/ethernet/intel/igb/e1000_82575.c
Normal file
2884
drivers/net/ethernet/intel/igb/e1000_82575.c
Normal file
File diff suppressed because it is too large
Load diff
279
drivers/net/ethernet/intel/igb/e1000_82575.h
Normal file
279
drivers/net/ethernet/intel/igb/e1000_82575.h
Normal file
|
@ -0,0 +1,279 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
#ifndef _E1000_82575_H_
|
||||
#define _E1000_82575_H_
|
||||
|
||||
void igb_shutdown_serdes_link_82575(struct e1000_hw *hw);
|
||||
void igb_power_up_serdes_link_82575(struct e1000_hw *hw);
|
||||
void igb_power_down_phy_copper_82575(struct e1000_hw *hw);
|
||||
void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
|
||||
s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset, u8 dev_addr,
|
||||
u8 *data);
|
||||
s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset, u8 dev_addr,
|
||||
u8 data);
|
||||
|
||||
#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
|
||||
(ID_LED_DEF1_DEF2 << 8) | \
|
||||
(ID_LED_DEF1_DEF2 << 4) | \
|
||||
(ID_LED_OFF1_ON2))
|
||||
|
||||
#define E1000_RAR_ENTRIES_82575 16
|
||||
#define E1000_RAR_ENTRIES_82576 24
|
||||
#define E1000_RAR_ENTRIES_82580 24
|
||||
#define E1000_RAR_ENTRIES_I350 32
|
||||
|
||||
#define E1000_SW_SYNCH_MB 0x00000100
|
||||
#define E1000_STAT_DEV_RST_SET 0x00100000
|
||||
#define E1000_CTRL_DEV_RST 0x20000000
|
||||
|
||||
/* SRRCTL bit definitions */
|
||||
#define E1000_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */
|
||||
#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */
|
||||
#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
|
||||
#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
|
||||
#define E1000_SRRCTL_DROP_EN 0x80000000
|
||||
#define E1000_SRRCTL_TIMESTAMP 0x40000000
|
||||
|
||||
|
||||
#define E1000_MRQC_ENABLE_RSS_4Q 0x00000002
|
||||
#define E1000_MRQC_ENABLE_VMDQ 0x00000003
|
||||
#define E1000_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
|
||||
#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q 0x00000005
|
||||
#define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
|
||||
#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000
|
||||
|
||||
#define E1000_EICR_TX_QUEUE ( \
|
||||
E1000_EICR_TX_QUEUE0 | \
|
||||
E1000_EICR_TX_QUEUE1 | \
|
||||
E1000_EICR_TX_QUEUE2 | \
|
||||
E1000_EICR_TX_QUEUE3)
|
||||
|
||||
#define E1000_EICR_RX_QUEUE ( \
|
||||
E1000_EICR_RX_QUEUE0 | \
|
||||
E1000_EICR_RX_QUEUE1 | \
|
||||
E1000_EICR_RX_QUEUE2 | \
|
||||
E1000_EICR_RX_QUEUE3)
|
||||
|
||||
/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */
|
||||
#define E1000_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */
|
||||
#define E1000_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of ctrl bits */
|
||||
|
||||
/* Receive Descriptor - Advanced */
|
||||
union e1000_adv_rx_desc {
|
||||
struct {
|
||||
__le64 pkt_addr; /* Packet buffer address */
|
||||
__le64 hdr_addr; /* Header buffer address */
|
||||
} read;
|
||||
struct {
|
||||
struct {
|
||||
struct {
|
||||
__le16 pkt_info; /* RSS type, Packet type */
|
||||
__le16 hdr_info; /* Split Head, buf len */
|
||||
} lo_dword;
|
||||
union {
|
||||
__le32 rss; /* RSS Hash */
|
||||
struct {
|
||||
__le16 ip_id; /* IP id */
|
||||
__le16 csum; /* Packet Checksum */
|
||||
} csum_ip;
|
||||
} hi_dword;
|
||||
} lower;
|
||||
struct {
|
||||
__le32 status_error; /* ext status/error */
|
||||
__le16 length; /* Packet length */
|
||||
__le16 vlan; /* VLAN tag */
|
||||
} upper;
|
||||
} wb; /* writeback */
|
||||
};
|
||||
|
||||
#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0
|
||||
#define E1000_RXDADV_HDRBUFLEN_SHIFT 5
|
||||
#define E1000_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */
|
||||
#define E1000_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */
|
||||
|
||||
/* Transmit Descriptor - Advanced */
|
||||
union e1000_adv_tx_desc {
|
||||
struct {
|
||||
__le64 buffer_addr; /* Address of descriptor's data buf */
|
||||
__le32 cmd_type_len;
|
||||
__le32 olinfo_status;
|
||||
} read;
|
||||
struct {
|
||||
__le64 rsvd; /* Reserved */
|
||||
__le32 nxtseq_seed;
|
||||
__le32 status;
|
||||
} wb;
|
||||
};
|
||||
|
||||
/* Adv Transmit Descriptor Config Masks */
|
||||
#define E1000_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
|
||||
#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
|
||||
#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
|
||||
#define E1000_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
|
||||
#define E1000_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
|
||||
#define E1000_ADVTXD_DCMD_RS 0x08000000 /* Report Status */
|
||||
#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */
|
||||
#define E1000_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */
|
||||
#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
|
||||
#define E1000_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
|
||||
|
||||
/* Context descriptors */
|
||||
struct e1000_adv_tx_context_desc {
|
||||
__le32 vlan_macip_lens;
|
||||
__le32 seqnum_seed;
|
||||
__le32 type_tucmd_mlhl;
|
||||
__le32 mss_l4len_idx;
|
||||
};
|
||||
|
||||
#define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
|
||||
#define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
|
||||
#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
|
||||
#define E1000_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */
|
||||
/* IPSec Encrypt Enable for ESP */
|
||||
#define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
|
||||
#define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
|
||||
/* Adv ctxt IPSec SA IDX mask */
|
||||
/* Adv ctxt IPSec ESP len mask */
|
||||
|
||||
/* Additional Transmit Descriptor Control definitions */
|
||||
#define E1000_TXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */
|
||||
/* Tx Queue Arbitration Priority 0=low, 1=high */
|
||||
|
||||
/* Additional Receive Descriptor Control definitions */
|
||||
#define E1000_RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Rx Queue */
|
||||
|
||||
/* Direct Cache Access (DCA) definitions */
|
||||
#define E1000_DCA_CTRL_DCA_MODE_DISABLE 0x01 /* DCA Disable */
|
||||
#define E1000_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */
|
||||
|
||||
#define E1000_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */
|
||||
#define E1000_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */
|
||||
#define E1000_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */
|
||||
#define E1000_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */
|
||||
#define E1000_DCA_RXCTRL_DESC_RRO_EN (1 << 9) /* DCA Rx rd Desc Relax Order */
|
||||
|
||||
#define E1000_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
|
||||
#define E1000_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */
|
||||
#define E1000_DCA_TXCTRL_DESC_RRO_EN (1 << 9) /* Tx rd Desc Relax Order */
|
||||
#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */
|
||||
#define E1000_DCA_TXCTRL_DATA_RRO_EN (1 << 13) /* Tx rd data Relax Order */
|
||||
|
||||
/* Additional DCA related definitions, note change in position of CPUID */
|
||||
#define E1000_DCA_TXCTRL_CPUID_MASK_82576 0xFF000000 /* Tx CPUID Mask */
|
||||
#define E1000_DCA_RXCTRL_CPUID_MASK_82576 0xFF000000 /* Rx CPUID Mask */
|
||||
#define E1000_DCA_TXCTRL_CPUID_SHIFT 24 /* Tx CPUID now in the last byte */
|
||||
#define E1000_DCA_RXCTRL_CPUID_SHIFT 24 /* Rx CPUID now in the last byte */
|
||||
|
||||
/* ETQF register bit definitions */
|
||||
#define E1000_ETQF_FILTER_ENABLE (1 << 26)
|
||||
#define E1000_ETQF_1588 (1 << 30)
|
||||
|
||||
/* FTQF register bit definitions */
|
||||
#define E1000_FTQF_VF_BP 0x00008000
|
||||
#define E1000_FTQF_1588_TIME_STAMP 0x08000000
|
||||
#define E1000_FTQF_MASK 0xF0000000
|
||||
#define E1000_FTQF_MASK_PROTO_BP 0x10000000
|
||||
#define E1000_FTQF_MASK_SOURCE_PORT_BP 0x80000000
|
||||
|
||||
#define E1000_NVM_APME_82575 0x0400
|
||||
#define MAX_NUM_VFS 8
|
||||
|
||||
#define E1000_DTXSWC_MAC_SPOOF_MASK 0x000000FF /* Per VF MAC spoof control */
|
||||
#define E1000_DTXSWC_VLAN_SPOOF_MASK 0x0000FF00 /* Per VF VLAN spoof control */
|
||||
#define E1000_DTXSWC_LLE_MASK 0x00FF0000 /* Per VF Local LB enables */
|
||||
#define E1000_DTXSWC_VLAN_SPOOF_SHIFT 8
|
||||
#define E1000_DTXSWC_VMDQ_LOOPBACK_EN (1 << 31) /* global VF LB enable */
|
||||
|
||||
/* Easy defines for setting default pool, would normally be left a zero */
|
||||
#define E1000_VT_CTL_DEFAULT_POOL_SHIFT 7
|
||||
#define E1000_VT_CTL_DEFAULT_POOL_MASK (0x7 << E1000_VT_CTL_DEFAULT_POOL_SHIFT)
|
||||
|
||||
/* Other useful VMD_CTL register defines */
|
||||
#define E1000_VT_CTL_IGNORE_MAC (1 << 28)
|
||||
#define E1000_VT_CTL_DISABLE_DEF_POOL (1 << 29)
|
||||
#define E1000_VT_CTL_VM_REPL_EN (1 << 30)
|
||||
|
||||
/* Per VM Offload register setup */
|
||||
#define E1000_VMOLR_RLPML_MASK 0x00003FFF /* Long Packet Maximum Length mask */
|
||||
#define E1000_VMOLR_LPE 0x00010000 /* Accept Long packet */
|
||||
#define E1000_VMOLR_RSSE 0x00020000 /* Enable RSS */
|
||||
#define E1000_VMOLR_AUPE 0x01000000 /* Accept untagged packets */
|
||||
#define E1000_VMOLR_ROMPE 0x02000000 /* Accept overflow multicast */
|
||||
#define E1000_VMOLR_ROPE 0x04000000 /* Accept overflow unicast */
|
||||
#define E1000_VMOLR_BAM 0x08000000 /* Accept Broadcast packets */
|
||||
#define E1000_VMOLR_MPME 0x10000000 /* Multicast promiscuous mode */
|
||||
#define E1000_VMOLR_STRVLAN 0x40000000 /* Vlan stripping enable */
|
||||
#define E1000_VMOLR_STRCRC 0x80000000 /* CRC stripping enable */
|
||||
|
||||
#define E1000_DVMOLR_HIDEVLAN 0x20000000 /* Hide vlan enable */
|
||||
#define E1000_DVMOLR_STRVLAN 0x40000000 /* Vlan stripping enable */
|
||||
#define E1000_DVMOLR_STRCRC 0x80000000 /* CRC stripping enable */
|
||||
|
||||
#define E1000_VLVF_ARRAY_SIZE 32
|
||||
#define E1000_VLVF_VLANID_MASK 0x00000FFF
|
||||
#define E1000_VLVF_POOLSEL_SHIFT 12
|
||||
#define E1000_VLVF_POOLSEL_MASK (0xFF << E1000_VLVF_POOLSEL_SHIFT)
|
||||
#define E1000_VLVF_LVLAN 0x00100000
|
||||
#define E1000_VLVF_VLANID_ENABLE 0x80000000
|
||||
|
||||
#define E1000_VMVIR_VLANA_DEFAULT 0x40000000 /* Always use default VLAN */
|
||||
#define E1000_VMVIR_VLANA_NEVER 0x80000000 /* Never insert VLAN tag */
|
||||
|
||||
#define E1000_IOVCTL 0x05BBC
|
||||
#define E1000_IOVCTL_REUSE_VFQ 0x00000001
|
||||
|
||||
#define E1000_RPLOLR_STRVLAN 0x40000000
|
||||
#define E1000_RPLOLR_STRCRC 0x80000000
|
||||
|
||||
#define E1000_DTXCTL_8023LL 0x0004
|
||||
#define E1000_DTXCTL_VLAN_ADDED 0x0008
|
||||
#define E1000_DTXCTL_OOS_ENABLE 0x0010
|
||||
#define E1000_DTXCTL_MDP_EN 0x0020
|
||||
#define E1000_DTXCTL_SPOOF_INT 0x0040
|
||||
|
||||
#define E1000_EEPROM_PCS_AUTONEG_DISABLE_BIT (1 << 14)
|
||||
|
||||
#define ALL_QUEUES 0xFFFF
|
||||
|
||||
/* RX packet buffer size defines */
|
||||
#define E1000_RXPBS_SIZE_MASK_82576 0x0000007F
|
||||
void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *, bool, int);
|
||||
void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool);
|
||||
void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
|
||||
u16 igb_rxpbs_adjust_82580(u32 data);
|
||||
s32 igb_read_emi_reg(struct e1000_hw *, u16 addr, u16 *data);
|
||||
s32 igb_set_eee_i350(struct e1000_hw *, bool adv1G, bool adv100M);
|
||||
s32 igb_set_eee_i354(struct e1000_hw *, bool adv1G, bool adv100M);
|
||||
s32 igb_get_eee_status_i354(struct e1000_hw *hw, bool *status);
|
||||
|
||||
#define E1000_I2C_THERMAL_SENSOR_ADDR 0xF8
|
||||
#define E1000_EMC_INTERNAL_DATA 0x00
|
||||
#define E1000_EMC_INTERNAL_THERM_LIMIT 0x20
|
||||
#define E1000_EMC_DIODE1_DATA 0x01
|
||||
#define E1000_EMC_DIODE1_THERM_LIMIT 0x19
|
||||
#define E1000_EMC_DIODE2_DATA 0x23
|
||||
#define E1000_EMC_DIODE2_THERM_LIMIT 0x1A
|
||||
#define E1000_EMC_DIODE3_DATA 0x2A
|
||||
#define E1000_EMC_DIODE3_THERM_LIMIT 0x30
|
||||
#endif
|
1016
drivers/net/ethernet/intel/igb/e1000_defines.h
Normal file
1016
drivers/net/ethernet/intel/igb/e1000_defines.h
Normal file
File diff suppressed because it is too large
Load diff
568
drivers/net/ethernet/intel/igb/e1000_hw.h
Normal file
568
drivers/net/ethernet/intel/igb/e1000_hw.h
Normal file
|
@ -0,0 +1,568 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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,
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
#ifndef _E1000_HW_H_
|
||||
#define _E1000_HW_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "e1000_regs.h"
|
||||
#include "e1000_defines.h"
|
||||
|
||||
struct e1000_hw;
|
||||
|
||||
#define E1000_DEV_ID_82576 0x10C9
|
||||
#define E1000_DEV_ID_82576_FIBER 0x10E6
|
||||
#define E1000_DEV_ID_82576_SERDES 0x10E7
|
||||
#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8
|
||||
#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526
|
||||
#define E1000_DEV_ID_82576_NS 0x150A
|
||||
#define E1000_DEV_ID_82576_NS_SERDES 0x1518
|
||||
#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D
|
||||
#define E1000_DEV_ID_82575EB_COPPER 0x10A7
|
||||
#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
|
||||
#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6
|
||||
#define E1000_DEV_ID_82580_COPPER 0x150E
|
||||
#define E1000_DEV_ID_82580_FIBER 0x150F
|
||||
#define E1000_DEV_ID_82580_SERDES 0x1510
|
||||
#define E1000_DEV_ID_82580_SGMII 0x1511
|
||||
#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
|
||||
#define E1000_DEV_ID_82580_QUAD_FIBER 0x1527
|
||||
#define E1000_DEV_ID_DH89XXCC_SGMII 0x0438
|
||||
#define E1000_DEV_ID_DH89XXCC_SERDES 0x043A
|
||||
#define E1000_DEV_ID_DH89XXCC_BACKPLANE 0x043C
|
||||
#define E1000_DEV_ID_DH89XXCC_SFP 0x0440
|
||||
#define E1000_DEV_ID_I350_COPPER 0x1521
|
||||
#define E1000_DEV_ID_I350_FIBER 0x1522
|
||||
#define E1000_DEV_ID_I350_SERDES 0x1523
|
||||
#define E1000_DEV_ID_I350_SGMII 0x1524
|
||||
#define E1000_DEV_ID_I210_COPPER 0x1533
|
||||
#define E1000_DEV_ID_I210_FIBER 0x1536
|
||||
#define E1000_DEV_ID_I210_SERDES 0x1537
|
||||
#define E1000_DEV_ID_I210_SGMII 0x1538
|
||||
#define E1000_DEV_ID_I210_COPPER_FLASHLESS 0x157B
|
||||
#define E1000_DEV_ID_I210_SERDES_FLASHLESS 0x157C
|
||||
#define E1000_DEV_ID_I211_COPPER 0x1539
|
||||
#define E1000_DEV_ID_I354_BACKPLANE_1GBPS 0x1F40
|
||||
#define E1000_DEV_ID_I354_SGMII 0x1F41
|
||||
#define E1000_DEV_ID_I354_BACKPLANE_2_5GBPS 0x1F45
|
||||
|
||||
#define E1000_REVISION_2 2
|
||||
#define E1000_REVISION_4 4
|
||||
|
||||
#define E1000_FUNC_0 0
|
||||
#define E1000_FUNC_1 1
|
||||
#define E1000_FUNC_2 2
|
||||
#define E1000_FUNC_3 3
|
||||
|
||||
#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0
|
||||
#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3
|
||||
#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN2 6
|
||||
#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN3 9
|
||||
|
||||
enum e1000_mac_type {
|
||||
e1000_undefined = 0,
|
||||
e1000_82575,
|
||||
e1000_82576,
|
||||
e1000_82580,
|
||||
e1000_i350,
|
||||
e1000_i354,
|
||||
e1000_i210,
|
||||
e1000_i211,
|
||||
e1000_num_macs /* List is 1-based, so subtract 1 for true count. */
|
||||
};
|
||||
|
||||
enum e1000_media_type {
|
||||
e1000_media_type_unknown = 0,
|
||||
e1000_media_type_copper = 1,
|
||||
e1000_media_type_fiber = 2,
|
||||
e1000_media_type_internal_serdes = 3,
|
||||
e1000_num_media_types
|
||||
};
|
||||
|
||||
enum e1000_nvm_type {
|
||||
e1000_nvm_unknown = 0,
|
||||
e1000_nvm_none,
|
||||
e1000_nvm_eeprom_spi,
|
||||
e1000_nvm_flash_hw,
|
||||
e1000_nvm_invm,
|
||||
e1000_nvm_flash_sw
|
||||
};
|
||||
|
||||
enum e1000_nvm_override {
|
||||
e1000_nvm_override_none = 0,
|
||||
e1000_nvm_override_spi_small,
|
||||
e1000_nvm_override_spi_large,
|
||||
};
|
||||
|
||||
enum e1000_phy_type {
|
||||
e1000_phy_unknown = 0,
|
||||
e1000_phy_none,
|
||||
e1000_phy_m88,
|
||||
e1000_phy_igp,
|
||||
e1000_phy_igp_2,
|
||||
e1000_phy_gg82563,
|
||||
e1000_phy_igp_3,
|
||||
e1000_phy_ife,
|
||||
e1000_phy_82580,
|
||||
e1000_phy_i210,
|
||||
};
|
||||
|
||||
enum e1000_bus_type {
|
||||
e1000_bus_type_unknown = 0,
|
||||
e1000_bus_type_pci,
|
||||
e1000_bus_type_pcix,
|
||||
e1000_bus_type_pci_express,
|
||||
e1000_bus_type_reserved
|
||||
};
|
||||
|
||||
enum e1000_bus_speed {
|
||||
e1000_bus_speed_unknown = 0,
|
||||
e1000_bus_speed_33,
|
||||
e1000_bus_speed_66,
|
||||
e1000_bus_speed_100,
|
||||
e1000_bus_speed_120,
|
||||
e1000_bus_speed_133,
|
||||
e1000_bus_speed_2500,
|
||||
e1000_bus_speed_5000,
|
||||
e1000_bus_speed_reserved
|
||||
};
|
||||
|
||||
enum e1000_bus_width {
|
||||
e1000_bus_width_unknown = 0,
|
||||
e1000_bus_width_pcie_x1,
|
||||
e1000_bus_width_pcie_x2,
|
||||
e1000_bus_width_pcie_x4 = 4,
|
||||
e1000_bus_width_pcie_x8 = 8,
|
||||
e1000_bus_width_32,
|
||||
e1000_bus_width_64,
|
||||
e1000_bus_width_reserved
|
||||
};
|
||||
|
||||
enum e1000_1000t_rx_status {
|
||||
e1000_1000t_rx_status_not_ok = 0,
|
||||
e1000_1000t_rx_status_ok,
|
||||
e1000_1000t_rx_status_undefined = 0xFF
|
||||
};
|
||||
|
||||
enum e1000_rev_polarity {
|
||||
e1000_rev_polarity_normal = 0,
|
||||
e1000_rev_polarity_reversed,
|
||||
e1000_rev_polarity_undefined = 0xFF
|
||||
};
|
||||
|
||||
enum e1000_fc_mode {
|
||||
e1000_fc_none = 0,
|
||||
e1000_fc_rx_pause,
|
||||
e1000_fc_tx_pause,
|
||||
e1000_fc_full,
|
||||
e1000_fc_default = 0xFF
|
||||
};
|
||||
|
||||
/* Statistics counters collected by the MAC */
|
||||
struct e1000_hw_stats {
|
||||
u64 crcerrs;
|
||||
u64 algnerrc;
|
||||
u64 symerrs;
|
||||
u64 rxerrc;
|
||||
u64 mpc;
|
||||
u64 scc;
|
||||
u64 ecol;
|
||||
u64 mcc;
|
||||
u64 latecol;
|
||||
u64 colc;
|
||||
u64 dc;
|
||||
u64 tncrs;
|
||||
u64 sec;
|
||||
u64 cexterr;
|
||||
u64 rlec;
|
||||
u64 xonrxc;
|
||||
u64 xontxc;
|
||||
u64 xoffrxc;
|
||||
u64 xofftxc;
|
||||
u64 fcruc;
|
||||
u64 prc64;
|
||||
u64 prc127;
|
||||
u64 prc255;
|
||||
u64 prc511;
|
||||
u64 prc1023;
|
||||
u64 prc1522;
|
||||
u64 gprc;
|
||||
u64 bprc;
|
||||
u64 mprc;
|
||||
u64 gptc;
|
||||
u64 gorc;
|
||||
u64 gotc;
|
||||
u64 rnbc;
|
||||
u64 ruc;
|
||||
u64 rfc;
|
||||
u64 roc;
|
||||
u64 rjc;
|
||||
u64 mgprc;
|
||||
u64 mgpdc;
|
||||
u64 mgptc;
|
||||
u64 tor;
|
||||
u64 tot;
|
||||
u64 tpr;
|
||||
u64 tpt;
|
||||
u64 ptc64;
|
||||
u64 ptc127;
|
||||
u64 ptc255;
|
||||
u64 ptc511;
|
||||
u64 ptc1023;
|
||||
u64 ptc1522;
|
||||
u64 mptc;
|
||||
u64 bptc;
|
||||
u64 tsctc;
|
||||
u64 tsctfc;
|
||||
u64 iac;
|
||||
u64 icrxptc;
|
||||
u64 icrxatc;
|
||||
u64 ictxptc;
|
||||
u64 ictxatc;
|
||||
u64 ictxqec;
|
||||
u64 ictxqmtc;
|
||||
u64 icrxdmtc;
|
||||
u64 icrxoc;
|
||||
u64 cbtmpc;
|
||||
u64 htdpmc;
|
||||
u64 cbrdpc;
|
||||
u64 cbrmpc;
|
||||
u64 rpthc;
|
||||
u64 hgptc;
|
||||
u64 htcbdpc;
|
||||
u64 hgorc;
|
||||
u64 hgotc;
|
||||
u64 lenerrs;
|
||||
u64 scvpc;
|
||||
u64 hrmpc;
|
||||
u64 doosync;
|
||||
u64 o2bgptc;
|
||||
u64 o2bspc;
|
||||
u64 b2ospc;
|
||||
u64 b2ogprc;
|
||||
};
|
||||
|
||||
struct e1000_host_mng_dhcp_cookie {
|
||||
u32 signature;
|
||||
u8 status;
|
||||
u8 reserved0;
|
||||
u16 vlan_id;
|
||||
u32 reserved1;
|
||||
u16 reserved2;
|
||||
u8 reserved3;
|
||||
u8 checksum;
|
||||
};
|
||||
|
||||
/* Host Interface "Rev 1" */
|
||||
struct e1000_host_command_header {
|
||||
u8 command_id;
|
||||
u8 command_length;
|
||||
u8 command_options;
|
||||
u8 checksum;
|
||||
};
|
||||
|
||||
#define E1000_HI_MAX_DATA_LENGTH 252
|
||||
struct e1000_host_command_info {
|
||||
struct e1000_host_command_header command_header;
|
||||
u8 command_data[E1000_HI_MAX_DATA_LENGTH];
|
||||
};
|
||||
|
||||
/* Host Interface "Rev 2" */
|
||||
struct e1000_host_mng_command_header {
|
||||
u8 command_id;
|
||||
u8 checksum;
|
||||
u16 reserved1;
|
||||
u16 reserved2;
|
||||
u16 command_length;
|
||||
};
|
||||
|
||||
#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
|
||||
struct e1000_host_mng_command_info {
|
||||
struct e1000_host_mng_command_header command_header;
|
||||
u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
|
||||
};
|
||||
|
||||
#include "e1000_mac.h"
|
||||
#include "e1000_phy.h"
|
||||
#include "e1000_nvm.h"
|
||||
#include "e1000_mbx.h"
|
||||
|
||||
struct e1000_mac_operations {
|
||||
s32 (*check_for_link)(struct e1000_hw *);
|
||||
s32 (*reset_hw)(struct e1000_hw *);
|
||||
s32 (*init_hw)(struct e1000_hw *);
|
||||
bool (*check_mng_mode)(struct e1000_hw *);
|
||||
s32 (*setup_physical_interface)(struct e1000_hw *);
|
||||
void (*rar_set)(struct e1000_hw *, u8 *, u32);
|
||||
s32 (*read_mac_addr)(struct e1000_hw *);
|
||||
s32 (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *);
|
||||
s32 (*acquire_swfw_sync)(struct e1000_hw *, u16);
|
||||
void (*release_swfw_sync)(struct e1000_hw *, u16);
|
||||
#ifdef CONFIG_IGB_HWMON
|
||||
s32 (*get_thermal_sensor_data)(struct e1000_hw *);
|
||||
s32 (*init_thermal_sensor_thresh)(struct e1000_hw *);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
struct e1000_phy_operations {
|
||||
s32 (*acquire)(struct e1000_hw *);
|
||||
s32 (*check_polarity)(struct e1000_hw *);
|
||||
s32 (*check_reset_block)(struct e1000_hw *);
|
||||
s32 (*force_speed_duplex)(struct e1000_hw *);
|
||||
s32 (*get_cfg_done)(struct e1000_hw *hw);
|
||||
s32 (*get_cable_length)(struct e1000_hw *);
|
||||
s32 (*get_phy_info)(struct e1000_hw *);
|
||||
s32 (*read_reg)(struct e1000_hw *, u32, u16 *);
|
||||
void (*release)(struct e1000_hw *);
|
||||
s32 (*reset)(struct e1000_hw *);
|
||||
s32 (*set_d0_lplu_state)(struct e1000_hw *, bool);
|
||||
s32 (*set_d3_lplu_state)(struct e1000_hw *, bool);
|
||||
s32 (*write_reg)(struct e1000_hw *, u32, u16);
|
||||
s32 (*read_i2c_byte)(struct e1000_hw *, u8, u8, u8 *);
|
||||
s32 (*write_i2c_byte)(struct e1000_hw *, u8, u8, u8);
|
||||
};
|
||||
|
||||
struct e1000_nvm_operations {
|
||||
s32 (*acquire)(struct e1000_hw *);
|
||||
s32 (*read)(struct e1000_hw *, u16, u16, u16 *);
|
||||
void (*release)(struct e1000_hw *);
|
||||
s32 (*write)(struct e1000_hw *, u16, u16, u16 *);
|
||||
s32 (*update)(struct e1000_hw *);
|
||||
s32 (*validate)(struct e1000_hw *);
|
||||
s32 (*valid_led_default)(struct e1000_hw *, u16 *);
|
||||
};
|
||||
|
||||
#define E1000_MAX_SENSORS 3
|
||||
|
||||
struct e1000_thermal_diode_data {
|
||||
u8 location;
|
||||
u8 temp;
|
||||
u8 caution_thresh;
|
||||
u8 max_op_thresh;
|
||||
};
|
||||
|
||||
struct e1000_thermal_sensor_data {
|
||||
struct e1000_thermal_diode_data sensor[E1000_MAX_SENSORS];
|
||||
};
|
||||
|
||||
struct e1000_info {
|
||||
s32 (*get_invariants)(struct e1000_hw *);
|
||||
struct e1000_mac_operations *mac_ops;
|
||||
struct e1000_phy_operations *phy_ops;
|
||||
struct e1000_nvm_operations *nvm_ops;
|
||||
};
|
||||
|
||||
extern const struct e1000_info e1000_82575_info;
|
||||
|
||||
struct e1000_mac_info {
|
||||
struct e1000_mac_operations ops;
|
||||
|
||||
u8 addr[6];
|
||||
u8 perm_addr[6];
|
||||
|
||||
enum e1000_mac_type type;
|
||||
|
||||
u32 ledctl_default;
|
||||
u32 ledctl_mode1;
|
||||
u32 ledctl_mode2;
|
||||
u32 mc_filter_type;
|
||||
u32 txcw;
|
||||
|
||||
u16 mta_reg_count;
|
||||
u16 uta_reg_count;
|
||||
|
||||
/* Maximum size of the MTA register table in all supported adapters */
|
||||
#define MAX_MTA_REG 128
|
||||
u32 mta_shadow[MAX_MTA_REG];
|
||||
u16 rar_entry_count;
|
||||
|
||||
u8 forced_speed_duplex;
|
||||
|
||||
bool adaptive_ifs;
|
||||
bool arc_subsystem_valid;
|
||||
bool asf_firmware_present;
|
||||
bool autoneg;
|
||||
bool autoneg_failed;
|
||||
bool disable_hw_init_bits;
|
||||
bool get_link_status;
|
||||
bool ifs_params_forced;
|
||||
bool in_ifs_mode;
|
||||
bool report_tx_early;
|
||||
bool serdes_has_link;
|
||||
bool tx_pkt_filtering;
|
||||
struct e1000_thermal_sensor_data thermal_sensor_data;
|
||||
};
|
||||
|
||||
struct e1000_phy_info {
|
||||
struct e1000_phy_operations ops;
|
||||
|
||||
enum e1000_phy_type type;
|
||||
|
||||
enum e1000_1000t_rx_status local_rx;
|
||||
enum e1000_1000t_rx_status remote_rx;
|
||||
enum e1000_ms_type ms_type;
|
||||
enum e1000_ms_type original_ms_type;
|
||||
enum e1000_rev_polarity cable_polarity;
|
||||
enum e1000_smart_speed smart_speed;
|
||||
|
||||
u32 addr;
|
||||
u32 id;
|
||||
u32 reset_delay_us; /* in usec */
|
||||
u32 revision;
|
||||
|
||||
enum e1000_media_type media_type;
|
||||
|
||||
u16 autoneg_advertised;
|
||||
u16 autoneg_mask;
|
||||
u16 cable_length;
|
||||
u16 max_cable_length;
|
||||
u16 min_cable_length;
|
||||
|
||||
u8 mdix;
|
||||
|
||||
bool disable_polarity_correction;
|
||||
bool is_mdix;
|
||||
bool polarity_correction;
|
||||
bool reset_disable;
|
||||
bool speed_downgraded;
|
||||
bool autoneg_wait_to_complete;
|
||||
};
|
||||
|
||||
struct e1000_nvm_info {
|
||||
struct e1000_nvm_operations ops;
|
||||
enum e1000_nvm_type type;
|
||||
enum e1000_nvm_override override;
|
||||
|
||||
u32 flash_bank_size;
|
||||
u32 flash_base_addr;
|
||||
|
||||
u16 word_size;
|
||||
u16 delay_usec;
|
||||
u16 address_bits;
|
||||
u16 opcode_bits;
|
||||
u16 page_size;
|
||||
};
|
||||
|
||||
struct e1000_bus_info {
|
||||
enum e1000_bus_type type;
|
||||
enum e1000_bus_speed speed;
|
||||
enum e1000_bus_width width;
|
||||
|
||||
u32 snoop;
|
||||
|
||||
u16 func;
|
||||
u16 pci_cmd_word;
|
||||
};
|
||||
|
||||
struct e1000_fc_info {
|
||||
u32 high_water; /* Flow control high-water mark */
|
||||
u32 low_water; /* Flow control low-water mark */
|
||||
u16 pause_time; /* Flow control pause timer */
|
||||
bool send_xon; /* Flow control send XON */
|
||||
bool strict_ieee; /* Strict IEEE mode */
|
||||
enum e1000_fc_mode current_mode; /* Type of flow control */
|
||||
enum e1000_fc_mode requested_mode;
|
||||
};
|
||||
|
||||
struct e1000_mbx_operations {
|
||||
s32 (*init_params)(struct e1000_hw *hw);
|
||||
s32 (*read)(struct e1000_hw *, u32 *, u16, u16);
|
||||
s32 (*write)(struct e1000_hw *, u32 *, u16, u16);
|
||||
s32 (*read_posted)(struct e1000_hw *, u32 *, u16, u16);
|
||||
s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16);
|
||||
s32 (*check_for_msg)(struct e1000_hw *, u16);
|
||||
s32 (*check_for_ack)(struct e1000_hw *, u16);
|
||||
s32 (*check_for_rst)(struct e1000_hw *, u16);
|
||||
};
|
||||
|
||||
struct e1000_mbx_stats {
|
||||
u32 msgs_tx;
|
||||
u32 msgs_rx;
|
||||
|
||||
u32 acks;
|
||||
u32 reqs;
|
||||
u32 rsts;
|
||||
};
|
||||
|
||||
struct e1000_mbx_info {
|
||||
struct e1000_mbx_operations ops;
|
||||
struct e1000_mbx_stats stats;
|
||||
u32 timeout;
|
||||
u32 usec_delay;
|
||||
u16 size;
|
||||
};
|
||||
|
||||
struct e1000_dev_spec_82575 {
|
||||
bool sgmii_active;
|
||||
bool global_device_reset;
|
||||
bool eee_disable;
|
||||
bool clear_semaphore_once;
|
||||
struct e1000_sfp_flags eth_flags;
|
||||
bool module_plugged;
|
||||
u8 media_port;
|
||||
bool media_changed;
|
||||
bool mas_capable;
|
||||
};
|
||||
|
||||
struct e1000_hw {
|
||||
void *back;
|
||||
|
||||
u8 __iomem *hw_addr;
|
||||
u8 __iomem *flash_address;
|
||||
unsigned long io_base;
|
||||
|
||||
struct e1000_mac_info mac;
|
||||
struct e1000_fc_info fc;
|
||||
struct e1000_phy_info phy;
|
||||
struct e1000_nvm_info nvm;
|
||||
struct e1000_bus_info bus;
|
||||
struct e1000_mbx_info mbx;
|
||||
struct e1000_host_mng_dhcp_cookie mng_cookie;
|
||||
|
||||
union {
|
||||
struct e1000_dev_spec_82575 _82575;
|
||||
} dev_spec;
|
||||
|
||||
u16 device_id;
|
||||
u16 subsystem_vendor_id;
|
||||
u16 subsystem_device_id;
|
||||
u16 vendor_id;
|
||||
|
||||
u8 revision_id;
|
||||
};
|
||||
|
||||
struct net_device *igb_get_hw_dev(struct e1000_hw *hw);
|
||||
#define hw_dbg(format, arg...) \
|
||||
netdev_dbg(igb_get_hw_dev(hw), format, ##arg)
|
||||
|
||||
/* These functions must be implemented by drivers */
|
||||
s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
|
||||
s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
|
||||
|
||||
void igb_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value);
|
||||
void igb_write_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value);
|
||||
#endif /* _E1000_HW_H_ */
|
902
drivers/net/ethernet/intel/igb/e1000_i210.c
Normal file
902
drivers/net/ethernet/intel/igb/e1000_i210.c
Normal file
|
@ -0,0 +1,902 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
/* e1000_i210
|
||||
* e1000_i211
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "e1000_hw.h"
|
||||
#include "e1000_i210.h"
|
||||
|
||||
static s32 igb_update_flash_i210(struct e1000_hw *hw);
|
||||
|
||||
/**
|
||||
* igb_get_hw_semaphore_i210 - Acquire hardware semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire the HW semaphore to access the PHY or NVM
|
||||
*/
|
||||
static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw)
|
||||
{
|
||||
u32 swsm;
|
||||
s32 timeout = hw->nvm.word_size + 1;
|
||||
s32 i = 0;
|
||||
|
||||
/* Get the SW semaphore */
|
||||
while (i < timeout) {
|
||||
swsm = rd32(E1000_SWSM);
|
||||
if (!(swsm & E1000_SWSM_SMBI))
|
||||
break;
|
||||
|
||||
udelay(50);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
/* In rare circumstances, the SW semaphore may already be held
|
||||
* unintentionally. Clear the semaphore once before giving up.
|
||||
*/
|
||||
if (hw->dev_spec._82575.clear_semaphore_once) {
|
||||
hw->dev_spec._82575.clear_semaphore_once = false;
|
||||
igb_put_hw_semaphore(hw);
|
||||
for (i = 0; i < timeout; i++) {
|
||||
swsm = rd32(E1000_SWSM);
|
||||
if (!(swsm & E1000_SWSM_SMBI))
|
||||
break;
|
||||
|
||||
udelay(50);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we do not have the semaphore here, we have to give up. */
|
||||
if (i == timeout) {
|
||||
hw_dbg("Driver can't access device - SMBI bit is set.\n");
|
||||
return -E1000_ERR_NVM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the FW semaphore. */
|
||||
for (i = 0; i < timeout; i++) {
|
||||
swsm = rd32(E1000_SWSM);
|
||||
wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
|
||||
|
||||
/* Semaphore acquired if bit latched */
|
||||
if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI)
|
||||
break;
|
||||
|
||||
udelay(50);
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
/* Release semaphores */
|
||||
igb_put_hw_semaphore(hw);
|
||||
hw_dbg("Driver can't access the NVM\n");
|
||||
return -E1000_ERR_NVM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_acquire_nvm_i210 - Request for access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire the necessary semaphores for exclusive access to the EEPROM.
|
||||
* Set the EEPROM access request bit and wait for EEPROM access grant bit.
|
||||
* Return successful if access grant bit set, else clear the request for
|
||||
* EEPROM access and return -E1000_ERR_NVM (-1).
|
||||
**/
|
||||
static s32 igb_acquire_nvm_i210(struct e1000_hw *hw)
|
||||
{
|
||||
return igb_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_release_nvm_i210 - Release exclusive access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Stop any current commands to the EEPROM and clear the EEPROM request bit,
|
||||
* then release the semaphores acquired.
|
||||
**/
|
||||
static void igb_release_nvm_i210(struct e1000_hw *hw)
|
||||
{
|
||||
igb_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_acquire_swfw_sync_i210 - Acquire SW/FW semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
* @mask: specifies which semaphore to acquire
|
||||
*
|
||||
* Acquire the SW/FW semaphore to access the PHY or NVM. The mask
|
||||
* will also specify which port we're acquiring the lock for.
|
||||
**/
|
||||
s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
|
||||
{
|
||||
u32 swfw_sync;
|
||||
u32 swmask = mask;
|
||||
u32 fwmask = mask << 16;
|
||||
s32 ret_val = 0;
|
||||
s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
|
||||
|
||||
while (i < timeout) {
|
||||
if (igb_get_hw_semaphore_i210(hw)) {
|
||||
ret_val = -E1000_ERR_SWFW_SYNC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
swfw_sync = rd32(E1000_SW_FW_SYNC);
|
||||
if (!(swfw_sync & (fwmask | swmask)))
|
||||
break;
|
||||
|
||||
/* Firmware currently using resource (fwmask) */
|
||||
igb_put_hw_semaphore(hw);
|
||||
mdelay(5);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
|
||||
ret_val = -E1000_ERR_SWFW_SYNC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
swfw_sync |= swmask;
|
||||
wr32(E1000_SW_FW_SYNC, swfw_sync);
|
||||
|
||||
igb_put_hw_semaphore(hw);
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_release_swfw_sync_i210 - Release SW/FW semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
* @mask: specifies which semaphore to acquire
|
||||
*
|
||||
* Release the SW/FW semaphore used to access the PHY or NVM. The mask
|
||||
* will also specify which port we're releasing the lock for.
|
||||
**/
|
||||
void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
|
||||
{
|
||||
u32 swfw_sync;
|
||||
|
||||
while (igb_get_hw_semaphore_i210(hw))
|
||||
; /* Empty */
|
||||
|
||||
swfw_sync = rd32(E1000_SW_FW_SYNC);
|
||||
swfw_sync &= ~mask;
|
||||
wr32(E1000_SW_FW_SYNC, swfw_sync);
|
||||
|
||||
igb_put_hw_semaphore(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_nvm_srrd_i210 - Reads Shadow Ram using EERD register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset of word in the Shadow Ram to read
|
||||
* @words: number of words to read
|
||||
* @data: word read from the Shadow Ram
|
||||
*
|
||||
* Reads a 16 bit word from the Shadow Ram using the EERD register.
|
||||
* Uses necessary synchronization semaphores.
|
||||
**/
|
||||
static s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
s32 status = 0;
|
||||
u16 i, count;
|
||||
|
||||
/* We cannot hold synchronization semaphores for too long,
|
||||
* because of forceful takeover procedure. However it is more efficient
|
||||
* to read in bursts than synchronizing access for each word.
|
||||
*/
|
||||
for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
|
||||
count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ?
|
||||
E1000_EERD_EEWR_MAX_COUNT : (words - i);
|
||||
if (!(hw->nvm.ops.acquire(hw))) {
|
||||
status = igb_read_nvm_eerd(hw, offset, count,
|
||||
data + i);
|
||||
hw->nvm.ops.release(hw);
|
||||
} else {
|
||||
status = E1000_ERR_SWFW_SYNC;
|
||||
}
|
||||
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_write_nvm_srwr - Write to Shadow Ram using EEWR
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset within the Shadow Ram to be written to
|
||||
* @words: number of words to write
|
||||
* @data: 16 bit word(s) to be written to the Shadow Ram
|
||||
*
|
||||
* Writes data to Shadow Ram at offset using EEWR register.
|
||||
*
|
||||
* If igb_update_nvm_checksum is not called after this function , the
|
||||
* Shadow Ram will most likely contain an invalid checksum.
|
||||
**/
|
||||
static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
struct e1000_nvm_info *nvm = &hw->nvm;
|
||||
u32 i, k, eewr = 0;
|
||||
u32 attempts = 100000;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* A check for invalid values: offset too large, too many words,
|
||||
* too many words for the offset, and not enough words.
|
||||
*/
|
||||
if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
|
||||
(words == 0)) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
ret_val = -E1000_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
eewr = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
|
||||
(data[i] << E1000_NVM_RW_REG_DATA) |
|
||||
E1000_NVM_RW_REG_START;
|
||||
|
||||
wr32(E1000_SRWR, eewr);
|
||||
|
||||
for (k = 0; k < attempts; k++) {
|
||||
if (E1000_NVM_RW_REG_DONE &
|
||||
rd32(E1000_SRWR)) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if (ret_val) {
|
||||
hw_dbg("Shadow RAM write EEWR timed out\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_write_nvm_srwr_i210 - Write to Shadow RAM using EEWR
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset within the Shadow RAM to be written to
|
||||
* @words: number of words to write
|
||||
* @data: 16 bit word(s) to be written to the Shadow RAM
|
||||
*
|
||||
* Writes data to Shadow RAM at offset using EEWR register.
|
||||
*
|
||||
* If e1000_update_nvm_checksum is not called after this function , the
|
||||
* data will not be committed to FLASH and also Shadow RAM will most likely
|
||||
* contain an invalid checksum.
|
||||
*
|
||||
* If error code is returned, data and Shadow RAM may be inconsistent - buffer
|
||||
* partially written.
|
||||
**/
|
||||
static s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
s32 status = 0;
|
||||
u16 i, count;
|
||||
|
||||
/* We cannot hold synchronization semaphores for too long,
|
||||
* because of forceful takeover procedure. However it is more efficient
|
||||
* to write in bursts than synchronizing access for each word.
|
||||
*/
|
||||
for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
|
||||
count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ?
|
||||
E1000_EERD_EEWR_MAX_COUNT : (words - i);
|
||||
if (!(hw->nvm.ops.acquire(hw))) {
|
||||
status = igb_write_nvm_srwr(hw, offset, count,
|
||||
data + i);
|
||||
hw->nvm.ops.release(hw);
|
||||
} else {
|
||||
status = E1000_ERR_SWFW_SYNC;
|
||||
}
|
||||
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_invm_word_i210 - Reads OTP
|
||||
* @hw: pointer to the HW structure
|
||||
* @address: the word address (aka eeprom offset) to read
|
||||
* @data: pointer to the data read
|
||||
*
|
||||
* Reads 16-bit words from the OTP. Return error when the word is not
|
||||
* stored in OTP.
|
||||
**/
|
||||
static s32 igb_read_invm_word_i210(struct e1000_hw *hw, u8 address, u16 *data)
|
||||
{
|
||||
s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND;
|
||||
u32 invm_dword;
|
||||
u16 i;
|
||||
u8 record_type, word_address;
|
||||
|
||||
for (i = 0; i < E1000_INVM_SIZE; i++) {
|
||||
invm_dword = rd32(E1000_INVM_DATA_REG(i));
|
||||
/* Get record type */
|
||||
record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword);
|
||||
if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE)
|
||||
break;
|
||||
if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE)
|
||||
i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS;
|
||||
if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE)
|
||||
i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS;
|
||||
if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) {
|
||||
word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword);
|
||||
if (word_address == address) {
|
||||
*data = INVM_DWORD_TO_WORD_DATA(invm_dword);
|
||||
hw_dbg("Read INVM Word 0x%02x = %x\n",
|
||||
address, *data);
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (status)
|
||||
hw_dbg("Requested word 0x%02x not found in OTP\n", address);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_invm_i210 - Read invm wrapper function for I210/I211
|
||||
* @hw: pointer to the HW structure
|
||||
* @words: number of words to read
|
||||
* @data: pointer to the data read
|
||||
*
|
||||
* Wrapper function to return data formerly found in the NVM.
|
||||
**/
|
||||
static s32 igb_read_invm_i210(struct e1000_hw *hw, u16 offset,
|
||||
u16 words __always_unused, u16 *data)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Only the MAC addr is required to be present in the iNVM */
|
||||
switch (offset) {
|
||||
case NVM_MAC_ADDR:
|
||||
ret_val = igb_read_invm_word_i210(hw, (u8)offset, &data[0]);
|
||||
ret_val |= igb_read_invm_word_i210(hw, (u8)offset+1,
|
||||
&data[1]);
|
||||
ret_val |= igb_read_invm_word_i210(hw, (u8)offset+2,
|
||||
&data[2]);
|
||||
if (ret_val)
|
||||
hw_dbg("MAC Addr not found in iNVM\n");
|
||||
break;
|
||||
case NVM_INIT_CTRL_2:
|
||||
ret_val = igb_read_invm_word_i210(hw, (u8)offset, data);
|
||||
if (ret_val) {
|
||||
*data = NVM_INIT_CTRL_2_DEFAULT_I211;
|
||||
ret_val = 0;
|
||||
}
|
||||
break;
|
||||
case NVM_INIT_CTRL_4:
|
||||
ret_val = igb_read_invm_word_i210(hw, (u8)offset, data);
|
||||
if (ret_val) {
|
||||
*data = NVM_INIT_CTRL_4_DEFAULT_I211;
|
||||
ret_val = 0;
|
||||
}
|
||||
break;
|
||||
case NVM_LED_1_CFG:
|
||||
ret_val = igb_read_invm_word_i210(hw, (u8)offset, data);
|
||||
if (ret_val) {
|
||||
*data = NVM_LED_1_CFG_DEFAULT_I211;
|
||||
ret_val = 0;
|
||||
}
|
||||
break;
|
||||
case NVM_LED_0_2_CFG:
|
||||
ret_val = igb_read_invm_word_i210(hw, (u8)offset, data);
|
||||
if (ret_val) {
|
||||
*data = NVM_LED_0_2_CFG_DEFAULT_I211;
|
||||
ret_val = 0;
|
||||
}
|
||||
break;
|
||||
case NVM_ID_LED_SETTINGS:
|
||||
ret_val = igb_read_invm_word_i210(hw, (u8)offset, data);
|
||||
if (ret_val) {
|
||||
*data = ID_LED_RESERVED_FFFF;
|
||||
ret_val = 0;
|
||||
}
|
||||
break;
|
||||
case NVM_SUB_DEV_ID:
|
||||
*data = hw->subsystem_device_id;
|
||||
break;
|
||||
case NVM_SUB_VEN_ID:
|
||||
*data = hw->subsystem_vendor_id;
|
||||
break;
|
||||
case NVM_DEV_ID:
|
||||
*data = hw->device_id;
|
||||
break;
|
||||
case NVM_VEN_ID:
|
||||
*data = hw->vendor_id;
|
||||
break;
|
||||
default:
|
||||
hw_dbg("NVM word 0x%02x is not mapped.\n", offset);
|
||||
*data = NVM_RESERVED_WORD;
|
||||
break;
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_invm_version - Reads iNVM version and image type
|
||||
* @hw: pointer to the HW structure
|
||||
* @invm_ver: version structure for the version read
|
||||
*
|
||||
* Reads iNVM version and image type.
|
||||
**/
|
||||
s32 igb_read_invm_version(struct e1000_hw *hw,
|
||||
struct e1000_fw_version *invm_ver) {
|
||||
u32 *record = NULL;
|
||||
u32 *next_record = NULL;
|
||||
u32 i = 0;
|
||||
u32 invm_dword = 0;
|
||||
u32 invm_blocks = E1000_INVM_SIZE - (E1000_INVM_ULT_BYTES_SIZE /
|
||||
E1000_INVM_RECORD_SIZE_IN_BYTES);
|
||||
u32 buffer[E1000_INVM_SIZE];
|
||||
s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND;
|
||||
u16 version = 0;
|
||||
|
||||
/* Read iNVM memory */
|
||||
for (i = 0; i < E1000_INVM_SIZE; i++) {
|
||||
invm_dword = rd32(E1000_INVM_DATA_REG(i));
|
||||
buffer[i] = invm_dword;
|
||||
}
|
||||
|
||||
/* Read version number */
|
||||
for (i = 1; i < invm_blocks; i++) {
|
||||
record = &buffer[invm_blocks - i];
|
||||
next_record = &buffer[invm_blocks - i + 1];
|
||||
|
||||
/* Check if we have first version location used */
|
||||
if ((i == 1) && ((*record & E1000_INVM_VER_FIELD_ONE) == 0)) {
|
||||
version = 0;
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
/* Check if we have second version location used */
|
||||
else if ((i == 1) &&
|
||||
((*record & E1000_INVM_VER_FIELD_TWO) == 0)) {
|
||||
version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3;
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
/* Check if we have odd version location
|
||||
* used and it is the last one used
|
||||
*/
|
||||
else if ((((*record & E1000_INVM_VER_FIELD_ONE) == 0) &&
|
||||
((*record & 0x3) == 0)) || (((*record & 0x3) != 0) &&
|
||||
(i != 1))) {
|
||||
version = (*next_record & E1000_INVM_VER_FIELD_TWO)
|
||||
>> 13;
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
/* Check if we have even version location
|
||||
* used and it is the last one used
|
||||
*/
|
||||
else if (((*record & E1000_INVM_VER_FIELD_TWO) == 0) &&
|
||||
((*record & 0x3) == 0)) {
|
||||
version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3;
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!status) {
|
||||
invm_ver->invm_major = (version & E1000_INVM_MAJOR_MASK)
|
||||
>> E1000_INVM_MAJOR_SHIFT;
|
||||
invm_ver->invm_minor = version & E1000_INVM_MINOR_MASK;
|
||||
}
|
||||
/* Read Image Type */
|
||||
for (i = 1; i < invm_blocks; i++) {
|
||||
record = &buffer[invm_blocks - i];
|
||||
next_record = &buffer[invm_blocks - i + 1];
|
||||
|
||||
/* Check if we have image type in first location used */
|
||||
if ((i == 1) && ((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) {
|
||||
invm_ver->invm_img_type = 0;
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
/* Check if we have image type in first location used */
|
||||
else if ((((*record & 0x3) == 0) &&
|
||||
((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) ||
|
||||
((((*record & 0x3) != 0) && (i != 1)))) {
|
||||
invm_ver->invm_img_type =
|
||||
(*next_record & E1000_INVM_IMGTYPE_FIELD) >> 23;
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_validate_nvm_checksum_i210 - Validate EEPROM checksum
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Calculates the EEPROM checksum by reading/adding each word of the EEPROM
|
||||
* and then verifies that the sum of the EEPROM is equal to 0xBABA.
|
||||
**/
|
||||
static s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
|
||||
{
|
||||
s32 status = 0;
|
||||
s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *);
|
||||
|
||||
if (!(hw->nvm.ops.acquire(hw))) {
|
||||
|
||||
/* Replace the read function with semaphore grabbing with
|
||||
* the one that skips this for a while.
|
||||
* We have semaphore taken already here.
|
||||
*/
|
||||
read_op_ptr = hw->nvm.ops.read;
|
||||
hw->nvm.ops.read = igb_read_nvm_eerd;
|
||||
|
||||
status = igb_validate_nvm_checksum(hw);
|
||||
|
||||
/* Revert original read operation. */
|
||||
hw->nvm.ops.read = read_op_ptr;
|
||||
|
||||
hw->nvm.ops.release(hw);
|
||||
} else {
|
||||
status = E1000_ERR_SWFW_SYNC;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_update_nvm_checksum_i210 - Update EEPROM checksum
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Updates the EEPROM checksum by reading/adding each word of the EEPROM
|
||||
* up to the checksum. Then calculates the EEPROM checksum and writes the
|
||||
* value to the EEPROM. Next commit EEPROM data onto the Flash.
|
||||
**/
|
||||
static s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u16 checksum = 0;
|
||||
u16 i, nvm_data;
|
||||
|
||||
/* Read the first word from the EEPROM. If this times out or fails, do
|
||||
* not continue or we could be in for a very long wait while every
|
||||
* EEPROM read fails
|
||||
*/
|
||||
ret_val = igb_read_nvm_eerd(hw, 0, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("EEPROM read failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(hw->nvm.ops.acquire(hw))) {
|
||||
/* Do not use hw->nvm.ops.write, hw->nvm.ops.read
|
||||
* because we do not want to take the synchronization
|
||||
* semaphores twice here.
|
||||
*/
|
||||
|
||||
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
|
||||
ret_val = igb_read_nvm_eerd(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw->nvm.ops.release(hw);
|
||||
hw_dbg("NVM Read Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
checksum = (u16) NVM_SUM - checksum;
|
||||
ret_val = igb_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,
|
||||
&checksum);
|
||||
if (ret_val) {
|
||||
hw->nvm.ops.release(hw);
|
||||
hw_dbg("NVM Write Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
hw->nvm.ops.release(hw);
|
||||
|
||||
ret_val = igb_update_flash_i210(hw);
|
||||
} else {
|
||||
ret_val = -E1000_ERR_SWFW_SYNC;
|
||||
}
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_pool_flash_update_done_i210 - Pool FLUDONE status.
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
**/
|
||||
static s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw)
|
||||
{
|
||||
s32 ret_val = -E1000_ERR_NVM;
|
||||
u32 i, reg;
|
||||
|
||||
for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) {
|
||||
reg = rd32(E1000_EECD);
|
||||
if (reg & E1000_EECD_FLUDONE_I210) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_get_flash_presence_i210 - Check if flash device is detected.
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
**/
|
||||
bool igb_get_flash_presence_i210(struct e1000_hw *hw)
|
||||
{
|
||||
u32 eec = 0;
|
||||
bool ret_val = false;
|
||||
|
||||
eec = rd32(E1000_EECD);
|
||||
if (eec & E1000_EECD_FLASH_DETECTED_I210)
|
||||
ret_val = true;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_update_flash_i210 - Commit EEPROM to the flash
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
**/
|
||||
static s32 igb_update_flash_i210(struct e1000_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 flup;
|
||||
|
||||
ret_val = igb_pool_flash_update_done_i210(hw);
|
||||
if (ret_val == -E1000_ERR_NVM) {
|
||||
hw_dbg("Flash update time out\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
flup = rd32(E1000_EECD) | E1000_EECD_FLUPD_I210;
|
||||
wr32(E1000_EECD, flup);
|
||||
|
||||
ret_val = igb_pool_flash_update_done_i210(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("Flash update complete\n");
|
||||
else
|
||||
hw_dbg("Flash update time out\n");
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_valid_led_default_i210 - Verify a valid default LED config
|
||||
* @hw: pointer to the HW structure
|
||||
* @data: pointer to the NVM (EEPROM)
|
||||
*
|
||||
* Read the EEPROM for the current default LED configuration. If the
|
||||
* LED configuration is not valid, set to a valid LED configuration.
|
||||
**/
|
||||
s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data)
|
||||
{
|
||||
s32 ret_val;
|
||||
|
||||
ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
|
||||
switch (hw->phy.media_type) {
|
||||
case e1000_media_type_internal_serdes:
|
||||
*data = ID_LED_DEFAULT_I210_SERDES;
|
||||
break;
|
||||
case e1000_media_type_copper:
|
||||
default:
|
||||
*data = ID_LED_DEFAULT_I210;
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* __igb_access_xmdio_reg - Read/write XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @address: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: pointer to value to read/write from/to the XMDIO address
|
||||
* @read: boolean flag to indicate read or write
|
||||
**/
|
||||
static s32 __igb_access_xmdio_reg(struct e1000_hw *hw, u16 address,
|
||||
u8 dev_addr, u16 *data, bool read)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, dev_addr);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, address);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, E1000_MMDAC_FUNC_DATA |
|
||||
dev_addr);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if (read)
|
||||
ret_val = hw->phy.ops.read_reg(hw, E1000_MMDAAD, data);
|
||||
else
|
||||
ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, *data);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
/* Recalibrate the device back to 0 */
|
||||
ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, 0);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_xmdio_reg - Read XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: value to be read from the EMI address
|
||||
**/
|
||||
s32 igb_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 *data)
|
||||
{
|
||||
return __igb_access_xmdio_reg(hw, addr, dev_addr, data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_write_xmdio_reg - Write XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: value to be written to the XMDIO address
|
||||
**/
|
||||
s32 igb_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 data)
|
||||
{
|
||||
return __igb_access_xmdio_reg(hw, addr, dev_addr, &data, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_init_nvm_params_i210 - Init NVM func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
**/
|
||||
s32 igb_init_nvm_params_i210(struct e1000_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
struct e1000_nvm_info *nvm = &hw->nvm;
|
||||
|
||||
nvm->ops.acquire = igb_acquire_nvm_i210;
|
||||
nvm->ops.release = igb_release_nvm_i210;
|
||||
nvm->ops.valid_led_default = igb_valid_led_default_i210;
|
||||
|
||||
/* NVM Function Pointers */
|
||||
if (igb_get_flash_presence_i210(hw)) {
|
||||
hw->nvm.type = e1000_nvm_flash_hw;
|
||||
nvm->ops.read = igb_read_nvm_srrd_i210;
|
||||
nvm->ops.write = igb_write_nvm_srwr_i210;
|
||||
nvm->ops.validate = igb_validate_nvm_checksum_i210;
|
||||
nvm->ops.update = igb_update_nvm_checksum_i210;
|
||||
} else {
|
||||
hw->nvm.type = e1000_nvm_invm;
|
||||
nvm->ops.read = igb_read_invm_i210;
|
||||
nvm->ops.write = NULL;
|
||||
nvm->ops.validate = NULL;
|
||||
nvm->ops.update = NULL;
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_pll_workaround_i210
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Works around an errata in the PLL circuit where it occasionally
|
||||
* provides the wrong clock frequency after power up.
|
||||
**/
|
||||
s32 igb_pll_workaround_i210(struct e1000_hw *hw)
|
||||
{
|
||||
s32 ret_val;
|
||||
u32 wuc, mdicnfg, ctrl, ctrl_ext, reg_val;
|
||||
u16 nvm_word, phy_word, pci_word, tmp_nvm;
|
||||
int i;
|
||||
|
||||
/* Get and set needed register values */
|
||||
wuc = rd32(E1000_WUC);
|
||||
mdicnfg = rd32(E1000_MDICNFG);
|
||||
reg_val = mdicnfg & ~E1000_MDICNFG_EXT_MDIO;
|
||||
wr32(E1000_MDICNFG, reg_val);
|
||||
|
||||
/* Get data from NVM, or set default */
|
||||
ret_val = igb_read_invm_word_i210(hw, E1000_INVM_AUTOLOAD,
|
||||
&nvm_word);
|
||||
if (ret_val)
|
||||
nvm_word = E1000_INVM_DEFAULT_AL;
|
||||
tmp_nvm = nvm_word | E1000_INVM_PLL_WO_VAL;
|
||||
for (i = 0; i < E1000_MAX_PLL_TRIES; i++) {
|
||||
/* check current state directly from internal PHY */
|
||||
igb_read_phy_reg_gs40g(hw, (E1000_PHY_PLL_FREQ_PAGE |
|
||||
E1000_PHY_PLL_FREQ_REG), &phy_word);
|
||||
if ((phy_word & E1000_PHY_PLL_UNCONF)
|
||||
!= E1000_PHY_PLL_UNCONF) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
} else {
|
||||
ret_val = -E1000_ERR_PHY;
|
||||
}
|
||||
/* directly reset the internal PHY */
|
||||
ctrl = rd32(E1000_CTRL);
|
||||
wr32(E1000_CTRL, ctrl|E1000_CTRL_PHY_RST);
|
||||
|
||||
ctrl_ext = rd32(E1000_CTRL_EXT);
|
||||
ctrl_ext |= (E1000_CTRL_EXT_PHYPDEN | E1000_CTRL_EXT_SDLPE);
|
||||
wr32(E1000_CTRL_EXT, ctrl_ext);
|
||||
|
||||
wr32(E1000_WUC, 0);
|
||||
reg_val = (E1000_INVM_AUTOLOAD << 4) | (tmp_nvm << 16);
|
||||
wr32(E1000_EEARBC_I210, reg_val);
|
||||
|
||||
igb_read_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word);
|
||||
pci_word |= E1000_PCI_PMCSR_D3;
|
||||
igb_write_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word);
|
||||
usleep_range(1000, 2000);
|
||||
pci_word &= ~E1000_PCI_PMCSR_D3;
|
||||
igb_write_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word);
|
||||
reg_val = (E1000_INVM_AUTOLOAD << 4) | (nvm_word << 16);
|
||||
wr32(E1000_EEARBC_I210, reg_val);
|
||||
|
||||
/* restore WUC register */
|
||||
wr32(E1000_WUC, wuc);
|
||||
}
|
||||
/* restore MDICNFG setting */
|
||||
wr32(E1000_MDICNFG, mdicnfg);
|
||||
return ret_val;
|
||||
}
|
93
drivers/net/ethernet/intel/igb/e1000_i210.h
Normal file
93
drivers/net/ethernet/intel/igb/e1000_i210.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
#ifndef _E1000_I210_H_
|
||||
#define _E1000_I210_H_
|
||||
|
||||
s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
|
||||
void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
|
||||
s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data);
|
||||
s32 igb_read_invm_version(struct e1000_hw *hw,
|
||||
struct e1000_fw_version *invm_ver);
|
||||
s32 igb_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 *data);
|
||||
s32 igb_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 data);
|
||||
s32 igb_init_nvm_params_i210(struct e1000_hw *hw);
|
||||
bool igb_get_flash_presence_i210(struct e1000_hw *hw);
|
||||
s32 igb_pll_workaround_i210(struct e1000_hw *hw);
|
||||
|
||||
#define E1000_STM_OPCODE 0xDB00
|
||||
#define E1000_EEPROM_FLASH_SIZE_WORD 0x11
|
||||
|
||||
#define INVM_DWORD_TO_RECORD_TYPE(invm_dword) \
|
||||
(u8)((invm_dword) & 0x7)
|
||||
#define INVM_DWORD_TO_WORD_ADDRESS(invm_dword) \
|
||||
(u8)(((invm_dword) & 0x0000FE00) >> 9)
|
||||
#define INVM_DWORD_TO_WORD_DATA(invm_dword) \
|
||||
(u16)(((invm_dword) & 0xFFFF0000) >> 16)
|
||||
|
||||
enum E1000_INVM_STRUCTURE_TYPE {
|
||||
E1000_INVM_UNINITIALIZED_STRUCTURE = 0x00,
|
||||
E1000_INVM_WORD_AUTOLOAD_STRUCTURE = 0x01,
|
||||
E1000_INVM_CSR_AUTOLOAD_STRUCTURE = 0x02,
|
||||
E1000_INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE = 0x03,
|
||||
E1000_INVM_RSA_KEY_SHA256_STRUCTURE = 0x04,
|
||||
E1000_INVM_INVALIDATED_STRUCTURE = 0x0F,
|
||||
};
|
||||
|
||||
#define E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS 8
|
||||
#define E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS 1
|
||||
#define E1000_INVM_ULT_BYTES_SIZE 8
|
||||
#define E1000_INVM_RECORD_SIZE_IN_BYTES 4
|
||||
#define E1000_INVM_VER_FIELD_ONE 0x1FF8
|
||||
#define E1000_INVM_VER_FIELD_TWO 0x7FE000
|
||||
#define E1000_INVM_IMGTYPE_FIELD 0x1F800000
|
||||
|
||||
#define E1000_INVM_MAJOR_MASK 0x3F0
|
||||
#define E1000_INVM_MINOR_MASK 0xF
|
||||
#define E1000_INVM_MAJOR_SHIFT 4
|
||||
|
||||
#define ID_LED_DEFAULT_I210 ((ID_LED_OFF1_ON2 << 8) | \
|
||||
(ID_LED_DEF1_DEF2 << 4) | \
|
||||
(ID_LED_OFF1_OFF2))
|
||||
#define ID_LED_DEFAULT_I210_SERDES ((ID_LED_DEF1_DEF2 << 8) | \
|
||||
(ID_LED_DEF1_DEF2 << 4) | \
|
||||
(ID_LED_OFF1_ON2))
|
||||
|
||||
/* NVM offset defaults for i211 device */
|
||||
#define NVM_INIT_CTRL_2_DEFAULT_I211 0X7243
|
||||
#define NVM_INIT_CTRL_4_DEFAULT_I211 0x00C1
|
||||
#define NVM_LED_1_CFG_DEFAULT_I211 0x0184
|
||||
#define NVM_LED_0_2_CFG_DEFAULT_I211 0x200C
|
||||
|
||||
/* PLL Defines */
|
||||
#define E1000_PCI_PMCSR 0x44
|
||||
#define E1000_PCI_PMCSR_D3 0x03
|
||||
#define E1000_MAX_PLL_TRIES 5
|
||||
#define E1000_PHY_PLL_UNCONF 0xFF
|
||||
#define E1000_PHY_PLL_FREQ_PAGE 0xFC0000
|
||||
#define E1000_PHY_PLL_FREQ_REG 0x000E
|
||||
#define E1000_INVM_DEFAULT_AL 0x202F
|
||||
#define E1000_INVM_AUTOLOAD 0x0A
|
||||
#define E1000_INVM_PLL_WO_VAL 0x0010
|
||||
|
||||
#endif
|
1606
drivers/net/ethernet/intel/igb/e1000_mac.c
Normal file
1606
drivers/net/ethernet/intel/igb/e1000_mac.c
Normal file
File diff suppressed because it is too large
Load diff
87
drivers/net/ethernet/intel/igb/e1000_mac.h
Normal file
87
drivers/net/ethernet/intel/igb/e1000_mac.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
#ifndef _E1000_MAC_H_
|
||||
#define _E1000_MAC_H_
|
||||
|
||||
#include "e1000_hw.h"
|
||||
|
||||
#include "e1000_phy.h"
|
||||
#include "e1000_nvm.h"
|
||||
#include "e1000_defines.h"
|
||||
#include "e1000_i210.h"
|
||||
|
||||
/* Functions that should not be called directly from drivers but can be used
|
||||
* by other files in this 'shared code'
|
||||
*/
|
||||
s32 igb_blink_led(struct e1000_hw *hw);
|
||||
s32 igb_check_for_copper_link(struct e1000_hw *hw);
|
||||
s32 igb_cleanup_led(struct e1000_hw *hw);
|
||||
s32 igb_config_fc_after_link_up(struct e1000_hw *hw);
|
||||
s32 igb_disable_pcie_master(struct e1000_hw *hw);
|
||||
s32 igb_force_mac_fc(struct e1000_hw *hw);
|
||||
s32 igb_get_auto_rd_done(struct e1000_hw *hw);
|
||||
s32 igb_get_bus_info_pcie(struct e1000_hw *hw);
|
||||
s32 igb_get_hw_semaphore(struct e1000_hw *hw);
|
||||
s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
|
||||
u16 *duplex);
|
||||
s32 igb_id_led_init(struct e1000_hw *hw);
|
||||
s32 igb_led_off(struct e1000_hw *hw);
|
||||
void igb_update_mc_addr_list(struct e1000_hw *hw,
|
||||
u8 *mc_addr_list, u32 mc_addr_count);
|
||||
s32 igb_setup_link(struct e1000_hw *hw);
|
||||
s32 igb_validate_mdi_setting(struct e1000_hw *hw);
|
||||
s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
|
||||
u32 offset, u8 data);
|
||||
|
||||
void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
|
||||
void igb_clear_vfta(struct e1000_hw *hw);
|
||||
void igb_clear_vfta_i350(struct e1000_hw *hw);
|
||||
s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add);
|
||||
void igb_config_collision_dist(struct e1000_hw *hw);
|
||||
void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
|
||||
void igb_mta_set(struct e1000_hw *hw, u32 hash_value);
|
||||
void igb_put_hw_semaphore(struct e1000_hw *hw);
|
||||
void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
|
||||
s32 igb_check_alt_mac_addr(struct e1000_hw *hw);
|
||||
|
||||
bool igb_enable_mng_pass_thru(struct e1000_hw *hw);
|
||||
|
||||
enum e1000_mng_mode {
|
||||
e1000_mng_mode_none = 0,
|
||||
e1000_mng_mode_asf,
|
||||
e1000_mng_mode_pt,
|
||||
e1000_mng_mode_ipmi,
|
||||
e1000_mng_mode_host_if_only
|
||||
};
|
||||
|
||||
#define E1000_FACTPS_MNGCG 0x20000000
|
||||
|
||||
#define E1000_FWSM_MODE_MASK 0xE
|
||||
#define E1000_FWSM_MODE_SHIFT 1
|
||||
|
||||
#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2
|
||||
|
||||
void e1000_init_function_pointers_82575(struct e1000_hw *hw);
|
||||
|
||||
#endif
|
443
drivers/net/ethernet/intel/igb/e1000_mbx.c
Normal file
443
drivers/net/ethernet/intel/igb/e1000_mbx.c
Normal file
|
@ -0,0 +1,443 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
#include "e1000_mbx.h"
|
||||
|
||||
/**
|
||||
* igb_read_mbx - Reads a message from the mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @mbx_id: id of mailbox to read
|
||||
*
|
||||
* returns SUCCESS if it successfully read message from buffer
|
||||
**/
|
||||
s32 igb_read_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
|
||||
{
|
||||
struct e1000_mbx_info *mbx = &hw->mbx;
|
||||
s32 ret_val = -E1000_ERR_MBX;
|
||||
|
||||
/* limit read to size of mailbox */
|
||||
if (size > mbx->size)
|
||||
size = mbx->size;
|
||||
|
||||
if (mbx->ops.read)
|
||||
ret_val = mbx->ops.read(hw, msg, size, mbx_id);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_write_mbx - Write a message to the mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @mbx_id: id of mailbox to write
|
||||
*
|
||||
* returns SUCCESS if it successfully copied message into the buffer
|
||||
**/
|
||||
s32 igb_write_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
|
||||
{
|
||||
struct e1000_mbx_info *mbx = &hw->mbx;
|
||||
s32 ret_val = 0;
|
||||
|
||||
if (size > mbx->size)
|
||||
ret_val = -E1000_ERR_MBX;
|
||||
|
||||
else if (mbx->ops.write)
|
||||
ret_val = mbx->ops.write(hw, msg, size, mbx_id);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_check_for_msg - checks to see if someone sent us mail
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to check
|
||||
*
|
||||
* returns SUCCESS if the Status bit was found or else ERR_MBX
|
||||
**/
|
||||
s32 igb_check_for_msg(struct e1000_hw *hw, u16 mbx_id)
|
||||
{
|
||||
struct e1000_mbx_info *mbx = &hw->mbx;
|
||||
s32 ret_val = -E1000_ERR_MBX;
|
||||
|
||||
if (mbx->ops.check_for_msg)
|
||||
ret_val = mbx->ops.check_for_msg(hw, mbx_id);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_check_for_ack - checks to see if someone sent us ACK
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to check
|
||||
*
|
||||
* returns SUCCESS if the Status bit was found or else ERR_MBX
|
||||
**/
|
||||
s32 igb_check_for_ack(struct e1000_hw *hw, u16 mbx_id)
|
||||
{
|
||||
struct e1000_mbx_info *mbx = &hw->mbx;
|
||||
s32 ret_val = -E1000_ERR_MBX;
|
||||
|
||||
if (mbx->ops.check_for_ack)
|
||||
ret_val = mbx->ops.check_for_ack(hw, mbx_id);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_check_for_rst - checks to see if other side has reset
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to check
|
||||
*
|
||||
* returns SUCCESS if the Status bit was found or else ERR_MBX
|
||||
**/
|
||||
s32 igb_check_for_rst(struct e1000_hw *hw, u16 mbx_id)
|
||||
{
|
||||
struct e1000_mbx_info *mbx = &hw->mbx;
|
||||
s32 ret_val = -E1000_ERR_MBX;
|
||||
|
||||
if (mbx->ops.check_for_rst)
|
||||
ret_val = mbx->ops.check_for_rst(hw, mbx_id);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_poll_for_msg - Wait for message notification
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to write
|
||||
*
|
||||
* returns SUCCESS if it successfully received a message notification
|
||||
**/
|
||||
static s32 igb_poll_for_msg(struct e1000_hw *hw, u16 mbx_id)
|
||||
{
|
||||
struct e1000_mbx_info *mbx = &hw->mbx;
|
||||
int countdown = mbx->timeout;
|
||||
|
||||
if (!countdown || !mbx->ops.check_for_msg)
|
||||
goto out;
|
||||
|
||||
while (countdown && mbx->ops.check_for_msg(hw, mbx_id)) {
|
||||
countdown--;
|
||||
if (!countdown)
|
||||
break;
|
||||
udelay(mbx->usec_delay);
|
||||
}
|
||||
|
||||
/* if we failed, all future posted messages fail until reset */
|
||||
if (!countdown)
|
||||
mbx->timeout = 0;
|
||||
out:
|
||||
return countdown ? 0 : -E1000_ERR_MBX;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_poll_for_ack - Wait for message acknowledgement
|
||||
* @hw: pointer to the HW structure
|
||||
* @mbx_id: id of mailbox to write
|
||||
*
|
||||
* returns SUCCESS if it successfully received a message acknowledgement
|
||||
**/
|
||||
static s32 igb_poll_for_ack(struct e1000_hw *hw, u16 mbx_id)
|
||||
{
|
||||
struct e1000_mbx_info *mbx = &hw->mbx;
|
||||
int countdown = mbx->timeout;
|
||||
|
||||
if (!countdown || !mbx->ops.check_for_ack)
|
||||
goto out;
|
||||
|
||||
while (countdown && mbx->ops.check_for_ack(hw, mbx_id)) {
|
||||
countdown--;
|
||||
if (!countdown)
|
||||
break;
|
||||
udelay(mbx->usec_delay);
|
||||
}
|
||||
|
||||
/* if we failed, all future posted messages fail until reset */
|
||||
if (!countdown)
|
||||
mbx->timeout = 0;
|
||||
out:
|
||||
return countdown ? 0 : -E1000_ERR_MBX;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_posted_mbx - Wait for message notification and receive message
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @mbx_id: id of mailbox to write
|
||||
*
|
||||
* returns SUCCESS if it successfully received a message notification and
|
||||
* copied it into the receive buffer.
|
||||
**/
|
||||
static s32 igb_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size,
|
||||
u16 mbx_id)
|
||||
{
|
||||
struct e1000_mbx_info *mbx = &hw->mbx;
|
||||
s32 ret_val = -E1000_ERR_MBX;
|
||||
|
||||
if (!mbx->ops.read)
|
||||
goto out;
|
||||
|
||||
ret_val = igb_poll_for_msg(hw, mbx_id);
|
||||
|
||||
if (!ret_val)
|
||||
ret_val = mbx->ops.read(hw, msg, size, mbx_id);
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_write_posted_mbx - Write a message to the mailbox, wait for ack
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @mbx_id: id of mailbox to write
|
||||
*
|
||||
* returns SUCCESS if it successfully copied message into the buffer and
|
||||
* received an ack to that message within delay * timeout period
|
||||
**/
|
||||
static s32 igb_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size,
|
||||
u16 mbx_id)
|
||||
{
|
||||
struct e1000_mbx_info *mbx = &hw->mbx;
|
||||
s32 ret_val = -E1000_ERR_MBX;
|
||||
|
||||
/* exit if either we can't write or there isn't a defined timeout */
|
||||
if (!mbx->ops.write || !mbx->timeout)
|
||||
goto out;
|
||||
|
||||
/* send msg */
|
||||
ret_val = mbx->ops.write(hw, msg, size, mbx_id);
|
||||
|
||||
/* if msg sent wait until we receive an ack */
|
||||
if (!ret_val)
|
||||
ret_val = igb_poll_for_ack(hw, mbx_id);
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static s32 igb_check_for_bit_pf(struct e1000_hw *hw, u32 mask)
|
||||
{
|
||||
u32 mbvficr = rd32(E1000_MBVFICR);
|
||||
s32 ret_val = -E1000_ERR_MBX;
|
||||
|
||||
if (mbvficr & mask) {
|
||||
ret_val = 0;
|
||||
wr32(E1000_MBVFICR, mask);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_check_for_msg_pf - checks to see if the VF has sent mail
|
||||
* @hw: pointer to the HW structure
|
||||
* @vf_number: the VF index
|
||||
*
|
||||
* returns SUCCESS if the VF has set the Status bit or else ERR_MBX
|
||||
**/
|
||||
static s32 igb_check_for_msg_pf(struct e1000_hw *hw, u16 vf_number)
|
||||
{
|
||||
s32 ret_val = -E1000_ERR_MBX;
|
||||
|
||||
if (!igb_check_for_bit_pf(hw, E1000_MBVFICR_VFREQ_VF1 << vf_number)) {
|
||||
ret_val = 0;
|
||||
hw->mbx.stats.reqs++;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_check_for_ack_pf - checks to see if the VF has ACKed
|
||||
* @hw: pointer to the HW structure
|
||||
* @vf_number: the VF index
|
||||
*
|
||||
* returns SUCCESS if the VF has set the Status bit or else ERR_MBX
|
||||
**/
|
||||
static s32 igb_check_for_ack_pf(struct e1000_hw *hw, u16 vf_number)
|
||||
{
|
||||
s32 ret_val = -E1000_ERR_MBX;
|
||||
|
||||
if (!igb_check_for_bit_pf(hw, E1000_MBVFICR_VFACK_VF1 << vf_number)) {
|
||||
ret_val = 0;
|
||||
hw->mbx.stats.acks++;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_check_for_rst_pf - checks to see if the VF has reset
|
||||
* @hw: pointer to the HW structure
|
||||
* @vf_number: the VF index
|
||||
*
|
||||
* returns SUCCESS if the VF has set the Status bit or else ERR_MBX
|
||||
**/
|
||||
static s32 igb_check_for_rst_pf(struct e1000_hw *hw, u16 vf_number)
|
||||
{
|
||||
u32 vflre = rd32(E1000_VFLRE);
|
||||
s32 ret_val = -E1000_ERR_MBX;
|
||||
|
||||
if (vflre & (1 << vf_number)) {
|
||||
ret_val = 0;
|
||||
wr32(E1000_VFLRE, (1 << vf_number));
|
||||
hw->mbx.stats.rsts++;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_obtain_mbx_lock_pf - obtain mailbox lock
|
||||
* @hw: pointer to the HW structure
|
||||
* @vf_number: the VF index
|
||||
*
|
||||
* return SUCCESS if we obtained the mailbox lock
|
||||
**/
|
||||
static s32 igb_obtain_mbx_lock_pf(struct e1000_hw *hw, u16 vf_number)
|
||||
{
|
||||
s32 ret_val = -E1000_ERR_MBX;
|
||||
u32 p2v_mailbox;
|
||||
|
||||
/* Take ownership of the buffer */
|
||||
wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU);
|
||||
|
||||
/* reserve mailbox for vf use */
|
||||
p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
|
||||
if (p2v_mailbox & E1000_P2VMAILBOX_PFU)
|
||||
ret_val = 0;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_write_mbx_pf - Places a message in the mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @vf_number: the VF index
|
||||
*
|
||||
* returns SUCCESS if it successfully copied message into the buffer
|
||||
**/
|
||||
static s32 igb_write_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
|
||||
u16 vf_number)
|
||||
{
|
||||
s32 ret_val;
|
||||
u16 i;
|
||||
|
||||
/* lock the mailbox to prevent pf/vf race condition */
|
||||
ret_val = igb_obtain_mbx_lock_pf(hw, vf_number);
|
||||
if (ret_val)
|
||||
goto out_no_write;
|
||||
|
||||
/* flush msg and acks as we are overwriting the message buffer */
|
||||
igb_check_for_msg_pf(hw, vf_number);
|
||||
igb_check_for_ack_pf(hw, vf_number);
|
||||
|
||||
/* copy the caller specified message to the mailbox memory buffer */
|
||||
for (i = 0; i < size; i++)
|
||||
array_wr32(E1000_VMBMEM(vf_number), i, msg[i]);
|
||||
|
||||
/* Interrupt VF to tell it a message has been sent and release buffer*/
|
||||
wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_STS);
|
||||
|
||||
/* update stats */
|
||||
hw->mbx.stats.msgs_tx++;
|
||||
|
||||
out_no_write:
|
||||
return ret_val;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_mbx_pf - Read a message from the mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
* @msg: The message buffer
|
||||
* @size: Length of buffer
|
||||
* @vf_number: the VF index
|
||||
*
|
||||
* This function copies a message from the mailbox buffer to the caller's
|
||||
* memory buffer. The presumption is that the caller knows that there was
|
||||
* a message due to a VF request so no polling for message is needed.
|
||||
**/
|
||||
static s32 igb_read_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
|
||||
u16 vf_number)
|
||||
{
|
||||
s32 ret_val;
|
||||
u16 i;
|
||||
|
||||
/* lock the mailbox to prevent pf/vf race condition */
|
||||
ret_val = igb_obtain_mbx_lock_pf(hw, vf_number);
|
||||
if (ret_val)
|
||||
goto out_no_read;
|
||||
|
||||
/* copy the message to the mailbox memory buffer */
|
||||
for (i = 0; i < size; i++)
|
||||
msg[i] = array_rd32(E1000_VMBMEM(vf_number), i);
|
||||
|
||||
/* Acknowledge the message and release buffer */
|
||||
wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_ACK);
|
||||
|
||||
/* update stats */
|
||||
hw->mbx.stats.msgs_rx++;
|
||||
|
||||
out_no_read:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_init_mbx_params_pf - set initial values for pf mailbox
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Initializes the hw->mbx struct to correct values for pf mailbox
|
||||
*/
|
||||
s32 igb_init_mbx_params_pf(struct e1000_hw *hw)
|
||||
{
|
||||
struct e1000_mbx_info *mbx = &hw->mbx;
|
||||
|
||||
mbx->timeout = 0;
|
||||
mbx->usec_delay = 0;
|
||||
|
||||
mbx->size = E1000_VFMAILBOX_SIZE;
|
||||
|
||||
mbx->ops.read = igb_read_mbx_pf;
|
||||
mbx->ops.write = igb_write_mbx_pf;
|
||||
mbx->ops.read_posted = igb_read_posted_mbx;
|
||||
mbx->ops.write_posted = igb_write_posted_mbx;
|
||||
mbx->ops.check_for_msg = igb_check_for_msg_pf;
|
||||
mbx->ops.check_for_ack = igb_check_for_ack_pf;
|
||||
mbx->ops.check_for_rst = igb_check_for_rst_pf;
|
||||
|
||||
mbx->stats.msgs_tx = 0;
|
||||
mbx->stats.msgs_rx = 0;
|
||||
mbx->stats.reqs = 0;
|
||||
mbx->stats.acks = 0;
|
||||
mbx->stats.rsts = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
73
drivers/net/ethernet/intel/igb/e1000_mbx.h
Normal file
73
drivers/net/ethernet/intel/igb/e1000_mbx.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
#ifndef _E1000_MBX_H_
|
||||
#define _E1000_MBX_H_
|
||||
|
||||
#include "e1000_hw.h"
|
||||
|
||||
#define E1000_P2VMAILBOX_STS 0x00000001 /* Initiate message send to VF */
|
||||
#define E1000_P2VMAILBOX_ACK 0x00000002 /* Ack message recv'd from VF */
|
||||
#define E1000_P2VMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */
|
||||
#define E1000_P2VMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */
|
||||
#define E1000_P2VMAILBOX_RVFU 0x00000010 /* Reset VFU - used when VF stuck */
|
||||
|
||||
#define E1000_MBVFICR_VFREQ_MASK 0x000000FF /* bits for VF messages */
|
||||
#define E1000_MBVFICR_VFREQ_VF1 0x00000001 /* bit for VF 1 message */
|
||||
#define E1000_MBVFICR_VFACK_MASK 0x00FF0000 /* bits for VF acks */
|
||||
#define E1000_MBVFICR_VFACK_VF1 0x00010000 /* bit for VF 1 ack */
|
||||
|
||||
#define E1000_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */
|
||||
|
||||
/* If it's a E1000_VF_* msg then it originates in the VF and is sent to the
|
||||
* PF. The reverse is true if it is E1000_PF_*.
|
||||
* Message ACK's are the value or'd with 0xF0000000
|
||||
*/
|
||||
/* Messages below or'd with this are the ACK */
|
||||
#define E1000_VT_MSGTYPE_ACK 0x80000000
|
||||
/* Messages below or'd with this are the NACK */
|
||||
#define E1000_VT_MSGTYPE_NACK 0x40000000
|
||||
/* Indicates that VF is still clear to send requests */
|
||||
#define E1000_VT_MSGTYPE_CTS 0x20000000
|
||||
#define E1000_VT_MSGINFO_SHIFT 16
|
||||
/* bits 23:16 are used for exra info for certain messages */
|
||||
#define E1000_VT_MSGINFO_MASK (0xFF << E1000_VT_MSGINFO_SHIFT)
|
||||
|
||||
#define E1000_VF_RESET 0x01 /* VF requests reset */
|
||||
#define E1000_VF_SET_MAC_ADDR 0x02 /* VF requests to set MAC addr */
|
||||
#define E1000_VF_SET_MULTICAST 0x03 /* VF requests to set MC addr */
|
||||
#define E1000_VF_SET_VLAN 0x04 /* VF requests to set VLAN */
|
||||
#define E1000_VF_SET_LPE 0x05 /* VF requests to set VMOLR.LPE */
|
||||
#define E1000_VF_SET_PROMISC 0x06 /*VF requests to clear VMOLR.ROPE/MPME*/
|
||||
#define E1000_VF_SET_PROMISC_MULTICAST (0x02 << E1000_VT_MSGINFO_SHIFT)
|
||||
|
||||
#define E1000_PF_CONTROL_MSG 0x0100 /* PF control message */
|
||||
|
||||
s32 igb_read_mbx(struct e1000_hw *, u32 *, u16, u16);
|
||||
s32 igb_write_mbx(struct e1000_hw *, u32 *, u16, u16);
|
||||
s32 igb_check_for_msg(struct e1000_hw *, u16);
|
||||
s32 igb_check_for_ack(struct e1000_hw *, u16);
|
||||
s32 igb_check_for_rst(struct e1000_hw *, u16);
|
||||
s32 igb_init_mbx_params_pf(struct e1000_hw *);
|
||||
|
||||
#endif /* _E1000_MBX_H_ */
|
801
drivers/net/ethernet/intel/igb/e1000_nvm.c
Normal file
801
drivers/net/ethernet/intel/igb/e1000_nvm.c
Normal file
|
@ -0,0 +1,801 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "e1000_mac.h"
|
||||
#include "e1000_nvm.h"
|
||||
|
||||
/**
|
||||
* igb_raise_eec_clk - Raise EEPROM clock
|
||||
* @hw: pointer to the HW structure
|
||||
* @eecd: pointer to the EEPROM
|
||||
*
|
||||
* Enable/Raise the EEPROM clock bit.
|
||||
**/
|
||||
static void igb_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
|
||||
{
|
||||
*eecd = *eecd | E1000_EECD_SK;
|
||||
wr32(E1000_EECD, *eecd);
|
||||
wrfl();
|
||||
udelay(hw->nvm.delay_usec);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_lower_eec_clk - Lower EEPROM clock
|
||||
* @hw: pointer to the HW structure
|
||||
* @eecd: pointer to the EEPROM
|
||||
*
|
||||
* Clear/Lower the EEPROM clock bit.
|
||||
**/
|
||||
static void igb_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
|
||||
{
|
||||
*eecd = *eecd & ~E1000_EECD_SK;
|
||||
wr32(E1000_EECD, *eecd);
|
||||
wrfl();
|
||||
udelay(hw->nvm.delay_usec);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_shift_out_eec_bits - Shift data bits our to the EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
* @data: data to send to the EEPROM
|
||||
* @count: number of bits to shift out
|
||||
*
|
||||
* We need to shift 'count' bits out to the EEPROM. So, the value in the
|
||||
* "data" parameter will be shifted out to the EEPROM one bit at a time.
|
||||
* In order to do this, "data" must be broken down into bits.
|
||||
**/
|
||||
static void igb_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
|
||||
{
|
||||
struct e1000_nvm_info *nvm = &hw->nvm;
|
||||
u32 eecd = rd32(E1000_EECD);
|
||||
u32 mask;
|
||||
|
||||
mask = 0x01 << (count - 1);
|
||||
if (nvm->type == e1000_nvm_eeprom_spi)
|
||||
eecd |= E1000_EECD_DO;
|
||||
|
||||
do {
|
||||
eecd &= ~E1000_EECD_DI;
|
||||
|
||||
if (data & mask)
|
||||
eecd |= E1000_EECD_DI;
|
||||
|
||||
wr32(E1000_EECD, eecd);
|
||||
wrfl();
|
||||
|
||||
udelay(nvm->delay_usec);
|
||||
|
||||
igb_raise_eec_clk(hw, &eecd);
|
||||
igb_lower_eec_clk(hw, &eecd);
|
||||
|
||||
mask >>= 1;
|
||||
} while (mask);
|
||||
|
||||
eecd &= ~E1000_EECD_DI;
|
||||
wr32(E1000_EECD, eecd);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_shift_in_eec_bits - Shift data bits in from the EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
* @count: number of bits to shift in
|
||||
*
|
||||
* In order to read a register from the EEPROM, we need to shift 'count' bits
|
||||
* in from the EEPROM. Bits are "shifted in" by raising the clock input to
|
||||
* the EEPROM (setting the SK bit), and then reading the value of the data out
|
||||
* "DO" bit. During this "shifting in" process the data in "DI" bit should
|
||||
* always be clear.
|
||||
**/
|
||||
static u16 igb_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
|
||||
{
|
||||
u32 eecd;
|
||||
u32 i;
|
||||
u16 data;
|
||||
|
||||
eecd = rd32(E1000_EECD);
|
||||
|
||||
eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
|
||||
data = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
data <<= 1;
|
||||
igb_raise_eec_clk(hw, &eecd);
|
||||
|
||||
eecd = rd32(E1000_EECD);
|
||||
|
||||
eecd &= ~E1000_EECD_DI;
|
||||
if (eecd & E1000_EECD_DO)
|
||||
data |= 1;
|
||||
|
||||
igb_lower_eec_clk(hw, &eecd);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_poll_eerd_eewr_done - Poll for EEPROM read/write completion
|
||||
* @hw: pointer to the HW structure
|
||||
* @ee_reg: EEPROM flag for polling
|
||||
*
|
||||
* Polls the EEPROM status bit for either read or write completion based
|
||||
* upon the value of 'ee_reg'.
|
||||
**/
|
||||
static s32 igb_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
|
||||
{
|
||||
u32 attempts = 100000;
|
||||
u32 i, reg = 0;
|
||||
s32 ret_val = -E1000_ERR_NVM;
|
||||
|
||||
for (i = 0; i < attempts; i++) {
|
||||
if (ee_reg == E1000_NVM_POLL_READ)
|
||||
reg = rd32(E1000_EERD);
|
||||
else
|
||||
reg = rd32(E1000_EEWR);
|
||||
|
||||
if (reg & E1000_NVM_RW_REG_DONE) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_acquire_nvm - Generic request for access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Set the EEPROM access request bit and wait for EEPROM access grant bit.
|
||||
* Return successful if access grant bit set, else clear the request for
|
||||
* EEPROM access and return -E1000_ERR_NVM (-1).
|
||||
**/
|
||||
s32 igb_acquire_nvm(struct e1000_hw *hw)
|
||||
{
|
||||
u32 eecd = rd32(E1000_EECD);
|
||||
s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
|
||||
s32 ret_val = 0;
|
||||
|
||||
|
||||
wr32(E1000_EECD, eecd | E1000_EECD_REQ);
|
||||
eecd = rd32(E1000_EECD);
|
||||
|
||||
while (timeout) {
|
||||
if (eecd & E1000_EECD_GNT)
|
||||
break;
|
||||
udelay(5);
|
||||
eecd = rd32(E1000_EECD);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
eecd &= ~E1000_EECD_REQ;
|
||||
wr32(E1000_EECD, eecd);
|
||||
hw_dbg("Could not acquire NVM grant\n");
|
||||
ret_val = -E1000_ERR_NVM;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_standby_nvm - Return EEPROM to standby state
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Return the EEPROM to a standby state.
|
||||
**/
|
||||
static void igb_standby_nvm(struct e1000_hw *hw)
|
||||
{
|
||||
struct e1000_nvm_info *nvm = &hw->nvm;
|
||||
u32 eecd = rd32(E1000_EECD);
|
||||
|
||||
if (nvm->type == e1000_nvm_eeprom_spi) {
|
||||
/* Toggle CS to flush commands */
|
||||
eecd |= E1000_EECD_CS;
|
||||
wr32(E1000_EECD, eecd);
|
||||
wrfl();
|
||||
udelay(nvm->delay_usec);
|
||||
eecd &= ~E1000_EECD_CS;
|
||||
wr32(E1000_EECD, eecd);
|
||||
wrfl();
|
||||
udelay(nvm->delay_usec);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_stop_nvm - Terminate EEPROM command
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Terminates the current command by inverting the EEPROM's chip select pin.
|
||||
**/
|
||||
static void e1000_stop_nvm(struct e1000_hw *hw)
|
||||
{
|
||||
u32 eecd;
|
||||
|
||||
eecd = rd32(E1000_EECD);
|
||||
if (hw->nvm.type == e1000_nvm_eeprom_spi) {
|
||||
/* Pull CS high */
|
||||
eecd |= E1000_EECD_CS;
|
||||
igb_lower_eec_clk(hw, &eecd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_release_nvm - Release exclusive access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Stop any current commands to the EEPROM and clear the EEPROM request bit.
|
||||
**/
|
||||
void igb_release_nvm(struct e1000_hw *hw)
|
||||
{
|
||||
u32 eecd;
|
||||
|
||||
e1000_stop_nvm(hw);
|
||||
|
||||
eecd = rd32(E1000_EECD);
|
||||
eecd &= ~E1000_EECD_REQ;
|
||||
wr32(E1000_EECD, eecd);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ready_nvm_eeprom - Prepares EEPROM for read/write
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Setups the EEPROM for reading and writing.
|
||||
**/
|
||||
static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw)
|
||||
{
|
||||
struct e1000_nvm_info *nvm = &hw->nvm;
|
||||
u32 eecd = rd32(E1000_EECD);
|
||||
s32 ret_val = 0;
|
||||
u16 timeout = 0;
|
||||
u8 spi_stat_reg;
|
||||
|
||||
|
||||
if (nvm->type == e1000_nvm_eeprom_spi) {
|
||||
/* Clear SK and CS */
|
||||
eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
|
||||
wr32(E1000_EECD, eecd);
|
||||
wrfl();
|
||||
udelay(1);
|
||||
timeout = NVM_MAX_RETRY_SPI;
|
||||
|
||||
/* Read "Status Register" repeatedly until the LSB is cleared.
|
||||
* The EEPROM will signal that the command has been completed
|
||||
* by clearing bit 0 of the internal status register. If it's
|
||||
* not cleared within 'timeout', then error out.
|
||||
*/
|
||||
while (timeout) {
|
||||
igb_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
|
||||
hw->nvm.opcode_bits);
|
||||
spi_stat_reg = (u8)igb_shift_in_eec_bits(hw, 8);
|
||||
if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
|
||||
break;
|
||||
|
||||
udelay(5);
|
||||
igb_standby_nvm(hw);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
hw_dbg("SPI NVM Status error\n");
|
||||
ret_val = -E1000_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_nvm_spi - Read EEPROM's using SPI
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset of word in the EEPROM to read
|
||||
* @words: number of words to read
|
||||
* @data: word read from the EEPROM
|
||||
*
|
||||
* Reads a 16 bit word from the EEPROM.
|
||||
**/
|
||||
s32 igb_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
|
||||
{
|
||||
struct e1000_nvm_info *nvm = &hw->nvm;
|
||||
u32 i = 0;
|
||||
s32 ret_val;
|
||||
u16 word_in;
|
||||
u8 read_opcode = NVM_READ_OPCODE_SPI;
|
||||
|
||||
/* A check for invalid values: offset too large, too many words,
|
||||
* and not enough words.
|
||||
*/
|
||||
if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
|
||||
(words == 0)) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
ret_val = -E1000_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = nvm->ops.acquire(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
ret_val = igb_ready_nvm_eeprom(hw);
|
||||
if (ret_val)
|
||||
goto release;
|
||||
|
||||
igb_standby_nvm(hw);
|
||||
|
||||
if ((nvm->address_bits == 8) && (offset >= 128))
|
||||
read_opcode |= NVM_A8_OPCODE_SPI;
|
||||
|
||||
/* Send the READ command (opcode + addr) */
|
||||
igb_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
|
||||
igb_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits);
|
||||
|
||||
/* Read the data. SPI NVMs increment the address with each byte
|
||||
* read and will roll over if reading beyond the end. This allows
|
||||
* us to read the whole NVM from any offset
|
||||
*/
|
||||
for (i = 0; i < words; i++) {
|
||||
word_in = igb_shift_in_eec_bits(hw, 16);
|
||||
data[i] = (word_in >> 8) | (word_in << 8);
|
||||
}
|
||||
|
||||
release:
|
||||
nvm->ops.release(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_nvm_eerd - Reads EEPROM using EERD register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset of word in the EEPROM to read
|
||||
* @words: number of words to read
|
||||
* @data: word read from the EEPROM
|
||||
*
|
||||
* Reads a 16 bit word from the EEPROM using the EERD register.
|
||||
**/
|
||||
s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
|
||||
{
|
||||
struct e1000_nvm_info *nvm = &hw->nvm;
|
||||
u32 i, eerd = 0;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* A check for invalid values: offset too large, too many words,
|
||||
* and not enough words.
|
||||
*/
|
||||
if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
|
||||
(words == 0)) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
ret_val = -E1000_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
|
||||
E1000_NVM_RW_REG_START;
|
||||
|
||||
wr32(E1000_EERD, eerd);
|
||||
ret_val = igb_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
|
||||
if (ret_val)
|
||||
break;
|
||||
|
||||
data[i] = (rd32(E1000_EERD) >>
|
||||
E1000_NVM_RW_REG_DATA);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_write_nvm_spi - Write to EEPROM using SPI
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset within the EEPROM to be written to
|
||||
* @words: number of words to write
|
||||
* @data: 16 bit word(s) to be written to the EEPROM
|
||||
*
|
||||
* Writes data to EEPROM at offset using SPI interface.
|
||||
*
|
||||
* If e1000_update_nvm_checksum is not called after this function , the
|
||||
* EEPROM will most likley contain an invalid checksum.
|
||||
**/
|
||||
s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
|
||||
{
|
||||
struct e1000_nvm_info *nvm = &hw->nvm;
|
||||
s32 ret_val = -E1000_ERR_NVM;
|
||||
u16 widx = 0;
|
||||
|
||||
/* A check for invalid values: offset too large, too many words,
|
||||
* and not enough words.
|
||||
*/
|
||||
if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
|
||||
(words == 0)) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
while (widx < words) {
|
||||
u8 write_opcode = NVM_WRITE_OPCODE_SPI;
|
||||
|
||||
ret_val = nvm->ops.acquire(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
ret_val = igb_ready_nvm_eeprom(hw);
|
||||
if (ret_val) {
|
||||
nvm->ops.release(hw);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
igb_standby_nvm(hw);
|
||||
|
||||
/* Send the WRITE ENABLE command (8 bit opcode) */
|
||||
igb_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
|
||||
nvm->opcode_bits);
|
||||
|
||||
igb_standby_nvm(hw);
|
||||
|
||||
/* Some SPI eeproms use the 8th address bit embedded in the
|
||||
* opcode
|
||||
*/
|
||||
if ((nvm->address_bits == 8) && (offset >= 128))
|
||||
write_opcode |= NVM_A8_OPCODE_SPI;
|
||||
|
||||
/* Send the Write command (8-bit opcode + addr) */
|
||||
igb_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
|
||||
igb_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
|
||||
nvm->address_bits);
|
||||
|
||||
/* Loop to allow for up to whole page write of eeprom */
|
||||
while (widx < words) {
|
||||
u16 word_out = data[widx];
|
||||
|
||||
word_out = (word_out >> 8) | (word_out << 8);
|
||||
igb_shift_out_eec_bits(hw, word_out, 16);
|
||||
widx++;
|
||||
|
||||
if ((((offset + widx) * 2) % nvm->page_size) == 0) {
|
||||
igb_standby_nvm(hw);
|
||||
break;
|
||||
}
|
||||
}
|
||||
usleep_range(1000, 2000);
|
||||
nvm->ops.release(hw);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_part_string - Read device part number
|
||||
* @hw: pointer to the HW structure
|
||||
* @part_num: pointer to device part number
|
||||
* @part_num_size: size of part number buffer
|
||||
*
|
||||
* Reads the product board assembly (PBA) number from the EEPROM and stores
|
||||
* the value in part_num.
|
||||
**/
|
||||
s32 igb_read_part_string(struct e1000_hw *hw, u8 *part_num, u32 part_num_size)
|
||||
{
|
||||
s32 ret_val;
|
||||
u16 nvm_data;
|
||||
u16 pointer;
|
||||
u16 offset;
|
||||
u16 length;
|
||||
|
||||
if (part_num == NULL) {
|
||||
hw_dbg("PBA string buffer was null\n");
|
||||
ret_val = E1000_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pointer);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if nvm_data is not ptr guard the PBA must be in legacy format which
|
||||
* means pointer is actually our second data word for the PBA number
|
||||
* and we can decode it into an ascii string
|
||||
*/
|
||||
if (nvm_data != NVM_PBA_PTR_GUARD) {
|
||||
hw_dbg("NVM PBA number is not stored as string\n");
|
||||
|
||||
/* we will need 11 characters to store the PBA */
|
||||
if (part_num_size < 11) {
|
||||
hw_dbg("PBA string buffer too small\n");
|
||||
return E1000_ERR_NO_SPACE;
|
||||
}
|
||||
|
||||
/* extract hex string from data and pointer */
|
||||
part_num[0] = (nvm_data >> 12) & 0xF;
|
||||
part_num[1] = (nvm_data >> 8) & 0xF;
|
||||
part_num[2] = (nvm_data >> 4) & 0xF;
|
||||
part_num[3] = nvm_data & 0xF;
|
||||
part_num[4] = (pointer >> 12) & 0xF;
|
||||
part_num[5] = (pointer >> 8) & 0xF;
|
||||
part_num[6] = '-';
|
||||
part_num[7] = 0;
|
||||
part_num[8] = (pointer >> 4) & 0xF;
|
||||
part_num[9] = pointer & 0xF;
|
||||
|
||||
/* put a null character on the end of our string */
|
||||
part_num[10] = '\0';
|
||||
|
||||
/* switch all the data but the '-' to hex char */
|
||||
for (offset = 0; offset < 10; offset++) {
|
||||
if (part_num[offset] < 0xA)
|
||||
part_num[offset] += '0';
|
||||
else if (part_num[offset] < 0x10)
|
||||
part_num[offset] += 'A' - 0xA;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = hw->nvm.ops.read(hw, pointer, 1, &length);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (length == 0xFFFF || length == 0) {
|
||||
hw_dbg("NVM PBA number section invalid length\n");
|
||||
ret_val = E1000_ERR_NVM_PBA_SECTION;
|
||||
goto out;
|
||||
}
|
||||
/* check if part_num buffer is big enough */
|
||||
if (part_num_size < (((u32)length * 2) - 1)) {
|
||||
hw_dbg("PBA string buffer too small\n");
|
||||
ret_val = E1000_ERR_NO_SPACE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* trim pba length from start of string */
|
||||
pointer++;
|
||||
length--;
|
||||
|
||||
for (offset = 0; offset < length; offset++) {
|
||||
ret_val = hw->nvm.ops.read(hw, pointer + offset, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error\n");
|
||||
goto out;
|
||||
}
|
||||
part_num[offset * 2] = (u8)(nvm_data >> 8);
|
||||
part_num[(offset * 2) + 1] = (u8)(nvm_data & 0xFF);
|
||||
}
|
||||
part_num[offset * 2] = '\0';
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_mac_addr - Read device MAC address
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Reads the device MAC address from the EEPROM and stores the value.
|
||||
* Since devices with two ports use the same EEPROM, we increment the
|
||||
* last bit in the MAC address for the second port.
|
||||
**/
|
||||
s32 igb_read_mac_addr(struct e1000_hw *hw)
|
||||
{
|
||||
u32 rar_high;
|
||||
u32 rar_low;
|
||||
u16 i;
|
||||
|
||||
rar_high = rd32(E1000_RAH(0));
|
||||
rar_low = rd32(E1000_RAL(0));
|
||||
|
||||
for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
|
||||
hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
|
||||
|
||||
for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
|
||||
hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
hw->mac.addr[i] = hw->mac.perm_addr[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_validate_nvm_checksum - Validate EEPROM checksum
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Calculates the EEPROM checksum by reading/adding each word of the EEPROM
|
||||
* and then verifies that the sum of the EEPROM is equal to 0xBABA.
|
||||
**/
|
||||
s32 igb_validate_nvm_checksum(struct e1000_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u16 checksum = 0;
|
||||
u16 i, nvm_data;
|
||||
|
||||
for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
|
||||
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
|
||||
if (checksum != (u16) NVM_SUM) {
|
||||
hw_dbg("NVM Checksum Invalid\n");
|
||||
ret_val = -E1000_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_update_nvm_checksum - Update EEPROM checksum
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Updates the EEPROM checksum by reading/adding each word of the EEPROM
|
||||
* up to the checksum. Then calculates the EEPROM checksum and writes the
|
||||
* value to the EEPROM.
|
||||
**/
|
||||
s32 igb_update_nvm_checksum(struct e1000_hw *hw)
|
||||
{
|
||||
s32 ret_val;
|
||||
u16 checksum = 0;
|
||||
u16 i, nvm_data;
|
||||
|
||||
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
|
||||
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
checksum = (u16) NVM_SUM - checksum;
|
||||
ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
|
||||
if (ret_val)
|
||||
hw_dbg("NVM Write Error while updating checksum.\n");
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_get_fw_version - Get firmware version information
|
||||
* @hw: pointer to the HW structure
|
||||
* @fw_vers: pointer to output structure
|
||||
*
|
||||
* unsupported MAC types will return all 0 version structure
|
||||
**/
|
||||
void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers)
|
||||
{
|
||||
u16 eeprom_verh, eeprom_verl, etrack_test, fw_version;
|
||||
u8 q, hval, rem, result;
|
||||
u16 comb_verh, comb_verl, comb_offset;
|
||||
|
||||
memset(fw_vers, 0, sizeof(struct e1000_fw_version));
|
||||
|
||||
/* basic eeprom version numbers and bits used vary by part and by tool
|
||||
* used to create the nvm images. Check which data format we have.
|
||||
*/
|
||||
hw->nvm.ops.read(hw, NVM_ETRACK_HIWORD, 1, &etrack_test);
|
||||
switch (hw->mac.type) {
|
||||
case e1000_i211:
|
||||
igb_read_invm_version(hw, fw_vers);
|
||||
return;
|
||||
case e1000_82575:
|
||||
case e1000_82576:
|
||||
case e1000_82580:
|
||||
/* Use this format, unless EETRACK ID exists,
|
||||
* then use alternate format
|
||||
*/
|
||||
if ((etrack_test & NVM_MAJOR_MASK) != NVM_ETRACK_VALID) {
|
||||
hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version);
|
||||
fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK)
|
||||
>> NVM_MAJOR_SHIFT;
|
||||
fw_vers->eep_minor = (fw_version & NVM_MINOR_MASK)
|
||||
>> NVM_MINOR_SHIFT;
|
||||
fw_vers->eep_build = (fw_version & NVM_IMAGE_ID_MASK);
|
||||
goto etrack_id;
|
||||
}
|
||||
break;
|
||||
case e1000_i210:
|
||||
if (!(igb_get_flash_presence_i210(hw))) {
|
||||
igb_read_invm_version(hw, fw_vers);
|
||||
return;
|
||||
}
|
||||
/* fall through */
|
||||
case e1000_i350:
|
||||
/* find combo image version */
|
||||
hw->nvm.ops.read(hw, NVM_COMB_VER_PTR, 1, &comb_offset);
|
||||
if ((comb_offset != 0x0) &&
|
||||
(comb_offset != NVM_VER_INVALID)) {
|
||||
|
||||
hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset
|
||||
+ 1), 1, &comb_verh);
|
||||
hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset),
|
||||
1, &comb_verl);
|
||||
|
||||
/* get Option Rom version if it exists and is valid */
|
||||
if ((comb_verh && comb_verl) &&
|
||||
((comb_verh != NVM_VER_INVALID) &&
|
||||
(comb_verl != NVM_VER_INVALID))) {
|
||||
|
||||
fw_vers->or_valid = true;
|
||||
fw_vers->or_major =
|
||||
comb_verl >> NVM_COMB_VER_SHFT;
|
||||
fw_vers->or_build =
|
||||
(comb_verl << NVM_COMB_VER_SHFT)
|
||||
| (comb_verh >> NVM_COMB_VER_SHFT);
|
||||
fw_vers->or_patch =
|
||||
comb_verh & NVM_COMB_VER_MASK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version);
|
||||
fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK)
|
||||
>> NVM_MAJOR_SHIFT;
|
||||
|
||||
/* check for old style version format in newer images*/
|
||||
if ((fw_version & NVM_NEW_DEC_MASK) == 0x0) {
|
||||
eeprom_verl = (fw_version & NVM_COMB_VER_MASK);
|
||||
} else {
|
||||
eeprom_verl = (fw_version & NVM_MINOR_MASK)
|
||||
>> NVM_MINOR_SHIFT;
|
||||
}
|
||||
/* Convert minor value to hex before assigning to output struct
|
||||
* Val to be converted will not be higher than 99, per tool output
|
||||
*/
|
||||
q = eeprom_verl / NVM_HEX_CONV;
|
||||
hval = q * NVM_HEX_TENS;
|
||||
rem = eeprom_verl % NVM_HEX_CONV;
|
||||
result = hval + rem;
|
||||
fw_vers->eep_minor = result;
|
||||
|
||||
etrack_id:
|
||||
if ((etrack_test & NVM_MAJOR_MASK) == NVM_ETRACK_VALID) {
|
||||
hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verl);
|
||||
hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verh);
|
||||
fw_vers->etrack_id = (eeprom_verh << NVM_ETRACK_SHIFT)
|
||||
| eeprom_verl;
|
||||
}
|
||||
}
|
56
drivers/net/ethernet/intel/igb/e1000_nvm.h
Normal file
56
drivers/net/ethernet/intel/igb/e1000_nvm.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
#ifndef _E1000_NVM_H_
|
||||
#define _E1000_NVM_H_
|
||||
|
||||
s32 igb_acquire_nvm(struct e1000_hw *hw);
|
||||
void igb_release_nvm(struct e1000_hw *hw);
|
||||
s32 igb_read_mac_addr(struct e1000_hw *hw);
|
||||
s32 igb_read_part_num(struct e1000_hw *hw, u32 *part_num);
|
||||
s32 igb_read_part_string(struct e1000_hw *hw, u8 *part_num,
|
||||
u32 part_num_size);
|
||||
s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
|
||||
s32 igb_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
|
||||
s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
|
||||
s32 igb_validate_nvm_checksum(struct e1000_hw *hw);
|
||||
s32 igb_update_nvm_checksum(struct e1000_hw *hw);
|
||||
|
||||
struct e1000_fw_version {
|
||||
u32 etrack_id;
|
||||
u16 eep_major;
|
||||
u16 eep_minor;
|
||||
u16 eep_build;
|
||||
|
||||
u8 invm_major;
|
||||
u8 invm_minor;
|
||||
u8 invm_img_type;
|
||||
|
||||
bool or_valid;
|
||||
u16 or_major;
|
||||
u16 or_build;
|
||||
u16 or_patch;
|
||||
};
|
||||
void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers);
|
||||
|
||||
#endif
|
2511
drivers/net/ethernet/intel/igb/e1000_phy.c
Normal file
2511
drivers/net/ethernet/intel/igb/e1000_phy.c
Normal file
File diff suppressed because it is too large
Load diff
174
drivers/net/ethernet/intel/igb/e1000_phy.h
Normal file
174
drivers/net/ethernet/intel/igb/e1000_phy.h
Normal file
|
@ -0,0 +1,174 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
#ifndef _E1000_PHY_H_
|
||||
#define _E1000_PHY_H_
|
||||
|
||||
enum e1000_ms_type {
|
||||
e1000_ms_hw_default = 0,
|
||||
e1000_ms_force_master,
|
||||
e1000_ms_force_slave,
|
||||
e1000_ms_auto
|
||||
};
|
||||
|
||||
enum e1000_smart_speed {
|
||||
e1000_smart_speed_default = 0,
|
||||
e1000_smart_speed_on,
|
||||
e1000_smart_speed_off
|
||||
};
|
||||
|
||||
s32 igb_check_downshift(struct e1000_hw *hw);
|
||||
s32 igb_check_reset_block(struct e1000_hw *hw);
|
||||
s32 igb_copper_link_setup_igp(struct e1000_hw *hw);
|
||||
s32 igb_copper_link_setup_m88(struct e1000_hw *hw);
|
||||
s32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw);
|
||||
s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw);
|
||||
s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw);
|
||||
s32 igb_get_cable_length_m88(struct e1000_hw *hw);
|
||||
s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw);
|
||||
s32 igb_get_cable_length_igp_2(struct e1000_hw *hw);
|
||||
s32 igb_get_phy_id(struct e1000_hw *hw);
|
||||
s32 igb_get_phy_info_igp(struct e1000_hw *hw);
|
||||
s32 igb_get_phy_info_m88(struct e1000_hw *hw);
|
||||
s32 igb_phy_sw_reset(struct e1000_hw *hw);
|
||||
s32 igb_phy_hw_reset(struct e1000_hw *hw);
|
||||
s32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||
s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active);
|
||||
s32 igb_setup_copper_link(struct e1000_hw *hw);
|
||||
s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
|
||||
s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
|
||||
u32 usec_interval, bool *success);
|
||||
void igb_power_up_phy_copper(struct e1000_hw *hw);
|
||||
void igb_power_down_phy_copper(struct e1000_hw *hw);
|
||||
s32 igb_phy_init_script_igp3(struct e1000_hw *hw);
|
||||
s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||
s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
|
||||
s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||
s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data);
|
||||
s32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data);
|
||||
s32 igb_copper_link_setup_82580(struct e1000_hw *hw);
|
||||
s32 igb_get_phy_info_82580(struct e1000_hw *hw);
|
||||
s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw);
|
||||
s32 igb_get_cable_length_82580(struct e1000_hw *hw);
|
||||
s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||
s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data);
|
||||
s32 igb_check_polarity_m88(struct e1000_hw *hw);
|
||||
|
||||
/* IGP01E1000 Specific Registers */
|
||||
#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
|
||||
#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */
|
||||
#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */
|
||||
#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */
|
||||
#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */
|
||||
#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */
|
||||
#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
|
||||
#define IGP01E1000_PHY_POLARITY_MASK 0x0078
|
||||
#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
|
||||
#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */
|
||||
#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
|
||||
|
||||
#define I82580_ADDR_REG 16
|
||||
#define I82580_CFG_REG 22
|
||||
#define I82580_CFG_ASSERT_CRS_ON_TX (1 << 15)
|
||||
#define I82580_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */
|
||||
#define I82580_CTRL_REG 23
|
||||
#define I82580_CTRL_DOWNSHIFT_MASK (7 << 10)
|
||||
|
||||
/* 82580 specific PHY registers */
|
||||
#define I82580_PHY_CTRL_2 18
|
||||
#define I82580_PHY_LBK_CTRL 19
|
||||
#define I82580_PHY_STATUS_2 26
|
||||
#define I82580_PHY_DIAG_STATUS 31
|
||||
|
||||
/* I82580 PHY Status 2 */
|
||||
#define I82580_PHY_STATUS2_REV_POLARITY 0x0400
|
||||
#define I82580_PHY_STATUS2_MDIX 0x0800
|
||||
#define I82580_PHY_STATUS2_SPEED_MASK 0x0300
|
||||
#define I82580_PHY_STATUS2_SPEED_1000MBPS 0x0200
|
||||
#define I82580_PHY_STATUS2_SPEED_100MBPS 0x0100
|
||||
|
||||
/* I82580 PHY Control 2 */
|
||||
#define I82580_PHY_CTRL2_MANUAL_MDIX 0x0200
|
||||
#define I82580_PHY_CTRL2_AUTO_MDI_MDIX 0x0400
|
||||
#define I82580_PHY_CTRL2_MDIX_CFG_MASK 0x0600
|
||||
|
||||
/* I82580 PHY Diagnostics Status */
|
||||
#define I82580_DSTATUS_CABLE_LENGTH 0x03FC
|
||||
#define I82580_DSTATUS_CABLE_LENGTH_SHIFT 2
|
||||
|
||||
/* 82580 PHY Power Management */
|
||||
#define E1000_82580_PHY_POWER_MGMT 0xE14
|
||||
#define E1000_82580_PM_SPD 0x0001 /* Smart Power Down */
|
||||
#define E1000_82580_PM_D0_LPLU 0x0002 /* For D0a states */
|
||||
#define E1000_82580_PM_D3_LPLU 0x0004 /* For all other states */
|
||||
#define E1000_82580_PM_GO_LINKD 0x0020 /* Go Link Disconnect */
|
||||
|
||||
/* Enable flexible speed on link-up */
|
||||
#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */
|
||||
#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */
|
||||
#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000
|
||||
#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
|
||||
#define IGP01E1000_PSSR_MDIX 0x0800
|
||||
#define IGP01E1000_PSSR_SPEED_MASK 0xC000
|
||||
#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000
|
||||
#define IGP02E1000_PHY_CHANNEL_NUM 4
|
||||
#define IGP02E1000_PHY_AGC_A 0x11B1
|
||||
#define IGP02E1000_PHY_AGC_B 0x12B1
|
||||
#define IGP02E1000_PHY_AGC_C 0x14B1
|
||||
#define IGP02E1000_PHY_AGC_D 0x18B1
|
||||
#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */
|
||||
#define IGP02E1000_AGC_LENGTH_MASK 0x7F
|
||||
#define IGP02E1000_AGC_RANGE 15
|
||||
|
||||
#define E1000_CABLE_LENGTH_UNDEFINED 0xFF
|
||||
|
||||
/* GS40G - I210 PHY defines */
|
||||
#define GS40G_PAGE_SELECT 0x16
|
||||
#define GS40G_PAGE_SHIFT 16
|
||||
#define GS40G_OFFSET_MASK 0xFFFF
|
||||
#define GS40G_PAGE_2 0x20000
|
||||
#define GS40G_MAC_REG2 0x15
|
||||
#define GS40G_MAC_LB 0x4140
|
||||
#define GS40G_MAC_SPEED_1G 0X0006
|
||||
#define GS40G_COPPER_SPEC 0x0010
|
||||
#define GS40G_LINE_LB 0x4000
|
||||
|
||||
/* SFP modules ID memory locations */
|
||||
#define E1000_SFF_IDENTIFIER_OFFSET 0x00
|
||||
#define E1000_SFF_IDENTIFIER_SFF 0x02
|
||||
#define E1000_SFF_IDENTIFIER_SFP 0x03
|
||||
|
||||
#define E1000_SFF_ETH_FLAGS_OFFSET 0x06
|
||||
/* Flags for SFP modules compatible with ETH up to 1Gb */
|
||||
struct e1000_sfp_flags {
|
||||
u8 e1000_base_sx:1;
|
||||
u8 e1000_base_lx:1;
|
||||
u8 e1000_base_cx:1;
|
||||
u8 e1000_base_t:1;
|
||||
u8 e100_base_lx:1;
|
||||
u8 e100_base_fx:1;
|
||||
u8 e10_base_bx10:1;
|
||||
u8 e10_base_px:1;
|
||||
};
|
||||
|
||||
#endif
|
426
drivers/net/ethernet/intel/igb/e1000_regs.h
Normal file
426
drivers/net/ethernet/intel/igb/e1000_regs.h
Normal file
|
@ -0,0 +1,426 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
#ifndef _E1000_REGS_H_
|
||||
#define _E1000_REGS_H_
|
||||
|
||||
#define E1000_CTRL 0x00000 /* Device Control - RW */
|
||||
#define E1000_STATUS 0x00008 /* Device Status - RO */
|
||||
#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
|
||||
#define E1000_EERD 0x00014 /* EEPROM Read - RW */
|
||||
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
|
||||
#define E1000_MDIC 0x00020 /* MDI Control - RW */
|
||||
#define E1000_MDICNFG 0x00E04 /* MDI Config - RW */
|
||||
#define E1000_SCTL 0x00024 /* SerDes Control - RW */
|
||||
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
|
||||
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
|
||||
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
|
||||
#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
|
||||
#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
|
||||
#define E1000_TSSDP 0x0003C /* Time Sync SDP Configuration Register - RW */
|
||||
#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */
|
||||
#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */
|
||||
#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */
|
||||
#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */
|
||||
#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
|
||||
#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */
|
||||
#define E1000_RCTL 0x00100 /* RX Control - RW */
|
||||
#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
|
||||
#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */
|
||||
#define E1000_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */
|
||||
#define E1000_EITR(_n) (0x01680 + (0x4 * (_n)))
|
||||
#define E1000_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */
|
||||
#define E1000_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */
|
||||
#define E1000_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */
|
||||
#define E1000_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */
|
||||
#define E1000_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */
|
||||
#define E1000_GPIE 0x01514 /* General Purpose Interrupt Enable - RW */
|
||||
#define E1000_IVAR0 0x01700 /* Interrupt Vector Allocation (array) - RW */
|
||||
#define E1000_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
|
||||
#define E1000_TCTL 0x00400 /* TX Control - RW */
|
||||
#define E1000_TCTL_EXT 0x00404 /* Extended TX Control - RW */
|
||||
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
|
||||
#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
|
||||
#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
|
||||
#define E1000_LEDMUX 0x08130 /* LED MUX Control */
|
||||
#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
|
||||
#define E1000_PBS 0x01008 /* Packet Buffer Size */
|
||||
#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
|
||||
#define E1000_EEARBC_I210 0x12024 /* EEPROM Auto Read Bus Control */
|
||||
#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */
|
||||
#define E1000_I2CCMD 0x01028 /* SFPI2C Command Register - RW */
|
||||
#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */
|
||||
#define E1000_TCPTIMER 0x0104C /* TCP Timer - RW */
|
||||
#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
|
||||
#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
|
||||
#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */
|
||||
#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
|
||||
#define E1000_I2CBB_EN 0x00000100 /* I2C - Bit Bang Enable */
|
||||
#define E1000_I2C_CLK_OUT 0x00000200 /* I2C- Clock */
|
||||
#define E1000_I2C_DATA_OUT 0x00000400 /* I2C- Data Out */
|
||||
#define E1000_I2C_DATA_OE_N 0x00000800 /* I2C- Data Output Enable */
|
||||
#define E1000_I2C_DATA_IN 0x00001000 /* I2C- Data In */
|
||||
#define E1000_I2C_CLK_OE_N 0x00002000 /* I2C- Clock Output Enable */
|
||||
#define E1000_I2C_CLK_IN 0x00004000 /* I2C- Clock In */
|
||||
#define E1000_MPHY_ADDR_CTRL 0x0024 /* GbE MPHY Address Control */
|
||||
#define E1000_MPHY_DATA 0x0E10 /* GBE MPHY Data */
|
||||
#define E1000_MPHY_STAT 0x0E0C /* GBE MPHY Statistics */
|
||||
|
||||
/* IEEE 1588 TIMESYNCH */
|
||||
#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
|
||||
#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */
|
||||
#define E1000_TSYNCRXCFG 0x05F50 /* Time Sync Rx Configuration - RW */
|
||||
#define E1000_RXSTMPL 0x0B624 /* Rx timestamp Low - RO */
|
||||
#define E1000_RXSTMPH 0x0B628 /* Rx timestamp High - RO */
|
||||
#define E1000_RXSATRL 0x0B62C /* Rx timestamp attribute low - RO */
|
||||
#define E1000_RXSATRH 0x0B630 /* Rx timestamp attribute high - RO */
|
||||
#define E1000_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
|
||||
#define E1000_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
|
||||
#define E1000_SYSTIML 0x0B600 /* System time register Low - RO */
|
||||
#define E1000_SYSTIMH 0x0B604 /* System time register High - RO */
|
||||
#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */
|
||||
#define E1000_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
|
||||
#define E1000_TRGTTIML0 0x0B644 /* Target Time Register 0 Low - RW */
|
||||
#define E1000_TRGTTIMH0 0x0B648 /* Target Time Register 0 High - RW */
|
||||
#define E1000_TRGTTIML1 0x0B64C /* Target Time Register 1 Low - RW */
|
||||
#define E1000_TRGTTIMH1 0x0B650 /* Target Time Register 1 High - RW */
|
||||
#define E1000_AUXSTMPL0 0x0B65C /* Auxiliary Time Stamp 0 Register Low - RO */
|
||||
#define E1000_AUXSTMPH0 0x0B660 /* Auxiliary Time Stamp 0 Register High - RO */
|
||||
#define E1000_AUXSTMPL1 0x0B664 /* Auxiliary Time Stamp 1 Register Low - RO */
|
||||
#define E1000_AUXSTMPH1 0x0B668 /* Auxiliary Time Stamp 1 Register High - RO */
|
||||
#define E1000_SYSTIMR 0x0B6F8 /* System time register Residue */
|
||||
#define E1000_TSICR 0x0B66C /* Interrupt Cause Register */
|
||||
#define E1000_TSIM 0x0B674 /* Interrupt Mask Register */
|
||||
|
||||
/* Filtering Registers */
|
||||
#define E1000_SAQF(_n) (0x5980 + 4 * (_n))
|
||||
#define E1000_DAQF(_n) (0x59A0 + 4 * (_n))
|
||||
#define E1000_SPQF(_n) (0x59C0 + 4 * (_n))
|
||||
#define E1000_FTQF(_n) (0x59E0 + 4 * (_n))
|
||||
#define E1000_SAQF0 E1000_SAQF(0)
|
||||
#define E1000_DAQF0 E1000_DAQF(0)
|
||||
#define E1000_SPQF0 E1000_SPQF(0)
|
||||
#define E1000_FTQF0 E1000_FTQF(0)
|
||||
#define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */
|
||||
#define E1000_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
|
||||
|
||||
#define E1000_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
|
||||
|
||||
/* DMA Coalescing registers */
|
||||
#define E1000_DMACR 0x02508 /* Control Register */
|
||||
#define E1000_DMCTXTH 0x03550 /* Transmit Threshold */
|
||||
#define E1000_DMCTLX 0x02514 /* Time to Lx Request */
|
||||
#define E1000_DMCRTRH 0x05DD0 /* Receive Packet Rate Threshold */
|
||||
#define E1000_DMCCNT 0x05DD4 /* Current Rx Count */
|
||||
#define E1000_FCRTC 0x02170 /* Flow Control Rx high watermark */
|
||||
#define E1000_PCIEMISC 0x05BB8 /* PCIE misc config register */
|
||||
|
||||
/* TX Rate Limit Registers */
|
||||
#define E1000_RTTDQSEL 0x3604 /* Tx Desc Plane Queue Select - WO */
|
||||
#define E1000_RTTBCNRM 0x3690 /* Tx BCN Rate-scheduler MMW */
|
||||
#define E1000_RTTBCNRC 0x36B0 /* Tx BCN Rate-Scheduler Config - WO */
|
||||
|
||||
/* Split and Replication RX Control - RW */
|
||||
#define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
|
||||
|
||||
/* Thermal sensor configuration and status registers */
|
||||
#define E1000_THMJT 0x08100 /* Junction Temperature */
|
||||
#define E1000_THLOWTC 0x08104 /* Low Threshold Control */
|
||||
#define E1000_THMIDTC 0x08108 /* Mid Threshold Control */
|
||||
#define E1000_THHIGHTC 0x0810C /* High Threshold Control */
|
||||
#define E1000_THSTAT 0x08110 /* Thermal Sensor Status */
|
||||
|
||||
/* Convenience macros
|
||||
*
|
||||
* Note: "_n" is the queue number of the register to be written to.
|
||||
*
|
||||
* Example usage:
|
||||
* E1000_RDBAL_REG(current_rx_queue)
|
||||
*/
|
||||
#define E1000_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) \
|
||||
: (0x0C000 + ((_n) * 0x40)))
|
||||
#define E1000_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) \
|
||||
: (0x0C004 + ((_n) * 0x40)))
|
||||
#define E1000_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) \
|
||||
: (0x0C008 + ((_n) * 0x40)))
|
||||
#define E1000_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) \
|
||||
: (0x0C00C + ((_n) * 0x40)))
|
||||
#define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) \
|
||||
: (0x0C010 + ((_n) * 0x40)))
|
||||
#define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) \
|
||||
: (0x0C018 + ((_n) * 0x40)))
|
||||
#define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) \
|
||||
: (0x0C028 + ((_n) * 0x40)))
|
||||
#define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) \
|
||||
: (0x0E000 + ((_n) * 0x40)))
|
||||
#define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) \
|
||||
: (0x0E004 + ((_n) * 0x40)))
|
||||
#define E1000_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) \
|
||||
: (0x0E008 + ((_n) * 0x40)))
|
||||
#define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) \
|
||||
: (0x0E010 + ((_n) * 0x40)))
|
||||
#define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) \
|
||||
: (0x0E018 + ((_n) * 0x40)))
|
||||
#define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) \
|
||||
: (0x0E028 + ((_n) * 0x40)))
|
||||
#define E1000_RXCTL(_n) ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \
|
||||
(0x0C014 + ((_n) * 0x40)))
|
||||
#define E1000_DCA_RXCTRL(_n) E1000_RXCTL(_n)
|
||||
#define E1000_TXCTL(_n) ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \
|
||||
(0x0E014 + ((_n) * 0x40)))
|
||||
#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n)
|
||||
#define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) \
|
||||
: (0x0E038 + ((_n) * 0x40)))
|
||||
#define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) \
|
||||
: (0x0E03C + ((_n) * 0x40)))
|
||||
|
||||
#define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
|
||||
#define E1000_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */
|
||||
|
||||
#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */
|
||||
#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */
|
||||
#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */
|
||||
#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */
|
||||
#define E1000_DTXCTL 0x03590 /* DMA TX Control - RW */
|
||||
#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */
|
||||
#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
|
||||
#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */
|
||||
#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */
|
||||
#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */
|
||||
#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */
|
||||
#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */
|
||||
#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */
|
||||
#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */
|
||||
#define E1000_COLC 0x04028 /* Collision Count - R/clr */
|
||||
#define E1000_DC 0x04030 /* Defer Count - R/clr */
|
||||
#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */
|
||||
#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */
|
||||
#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */
|
||||
#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */
|
||||
#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */
|
||||
#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */
|
||||
#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */
|
||||
#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */
|
||||
#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */
|
||||
#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */
|
||||
#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */
|
||||
#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */
|
||||
#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */
|
||||
#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */
|
||||
#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */
|
||||
#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */
|
||||
#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */
|
||||
#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */
|
||||
#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */
|
||||
#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */
|
||||
#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */
|
||||
#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */
|
||||
#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */
|
||||
#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */
|
||||
#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */
|
||||
#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */
|
||||
#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */
|
||||
#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */
|
||||
#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */
|
||||
#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */
|
||||
#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */
|
||||
#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */
|
||||
#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */
|
||||
#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */
|
||||
#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */
|
||||
#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */
|
||||
#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */
|
||||
#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */
|
||||
#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */
|
||||
#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */
|
||||
#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */
|
||||
#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */
|
||||
#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */
|
||||
#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */
|
||||
#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */
|
||||
#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */
|
||||
#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */
|
||||
#define E1000_IAC 0x04100 /* Interrupt Assertion Count */
|
||||
/* Interrupt Cause Rx Packet Timer Expire Count */
|
||||
#define E1000_ICRXPTC 0x04104
|
||||
/* Interrupt Cause Rx Absolute Timer Expire Count */
|
||||
#define E1000_ICRXATC 0x04108
|
||||
/* Interrupt Cause Tx Packet Timer Expire Count */
|
||||
#define E1000_ICTXPTC 0x0410C
|
||||
/* Interrupt Cause Tx Absolute Timer Expire Count */
|
||||
#define E1000_ICTXATC 0x04110
|
||||
/* Interrupt Cause Tx Queue Empty Count */
|
||||
#define E1000_ICTXQEC 0x04118
|
||||
/* Interrupt Cause Tx Queue Minimum Threshold Count */
|
||||
#define E1000_ICTXQMTC 0x0411C
|
||||
/* Interrupt Cause Rx Descriptor Minimum Threshold Count */
|
||||
#define E1000_ICRXDMTC 0x04120
|
||||
#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */
|
||||
#define E1000_PCS_CFG0 0x04200 /* PCS Configuration 0 - RW */
|
||||
#define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */
|
||||
#define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */
|
||||
#define E1000_CBTMPC 0x0402C /* Circuit Breaker TX Packet Count */
|
||||
#define E1000_HTDPMC 0x0403C /* Host Transmit Discarded Packets */
|
||||
#define E1000_CBRMPC 0x040FC /* Circuit Breaker RX Packet Count */
|
||||
#define E1000_RPTHC 0x04104 /* Rx Packets To Host */
|
||||
#define E1000_HGPTC 0x04118 /* Host Good Packets TX Count */
|
||||
#define E1000_HTCBDPC 0x04124 /* Host TX Circuit Breaker Dropped Count */
|
||||
#define E1000_HGORCL 0x04128 /* Host Good Octets Received Count Low */
|
||||
#define E1000_HGORCH 0x0412C /* Host Good Octets Received Count High */
|
||||
#define E1000_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */
|
||||
#define E1000_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */
|
||||
#define E1000_LENERRS 0x04138 /* Length Errors Count */
|
||||
#define E1000_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */
|
||||
#define E1000_PCS_ANADV 0x04218 /* AN advertisement - RW */
|
||||
#define E1000_PCS_LPAB 0x0421C /* Link Partner Ability - RW */
|
||||
#define E1000_PCS_NPTX 0x04220 /* AN Next Page Transmit - RW */
|
||||
#define E1000_PCS_LPABNP 0x04224 /* Link Partner Ability Next Page - RW */
|
||||
#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */
|
||||
#define E1000_RLPML 0x05004 /* RX Long Packet Max Length */
|
||||
#define E1000_RFCTL 0x05008 /* Receive Filter Control*/
|
||||
#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
|
||||
#define E1000_RA 0x05400 /* Receive Address - RW Array */
|
||||
#define E1000_RA2 0x054E0 /* 2nd half of Rx address array - RW Array */
|
||||
#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4))
|
||||
#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
|
||||
(0x054E0 + ((_i - 16) * 8)))
|
||||
#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
|
||||
(0x054E4 + ((_i - 16) * 8)))
|
||||
#define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8))
|
||||
#define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4))
|
||||
#define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4))
|
||||
#define E1000_FFMT_REG(_i) (0x09000 + ((_i) * 8))
|
||||
#define E1000_FFVT_REG(_i) (0x09800 + ((_i) * 8))
|
||||
#define E1000_FFLT_REG(_i) (0x05F00 + ((_i) * 8))
|
||||
#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */
|
||||
#define E1000_VT_CTL 0x0581C /* VMDq Control - RW */
|
||||
#define E1000_WUC 0x05800 /* Wakeup Control - RW */
|
||||
#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */
|
||||
#define E1000_WUS 0x05810 /* Wakeup Status - RO */
|
||||
#define E1000_MANC 0x05820 /* Management Control - RW */
|
||||
#define E1000_IPAV 0x05838 /* IP Address Valid - RW */
|
||||
#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */
|
||||
|
||||
#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
|
||||
#define E1000_CCMCTL 0x05B48 /* CCM Control Register */
|
||||
#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */
|
||||
#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */
|
||||
#define E1000_GCR 0x05B00 /* PCI-Ex Control */
|
||||
#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
|
||||
#define E1000_SWSM 0x05B50 /* SW Semaphore */
|
||||
#define E1000_FWSM 0x05B54 /* FW Semaphore */
|
||||
#define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */
|
||||
|
||||
/* RSS registers */
|
||||
#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */
|
||||
#define E1000_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */
|
||||
#define E1000_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate Interrupt Ext*/
|
||||
#define E1000_IMIRVP 0x05AC0 /* Immediate Interrupt RX VLAN Priority - RW */
|
||||
/* MSI-X Allocation Register (_i) - RW */
|
||||
#define E1000_MSIXBM(_i) (0x01600 + ((_i) * 4))
|
||||
/* Redirection Table - RW Array */
|
||||
#define E1000_RETA(_i) (0x05C00 + ((_i) * 4))
|
||||
#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW Array */
|
||||
|
||||
/* VT Registers */
|
||||
#define E1000_MBVFICR 0x00C80 /* Mailbox VF Cause - RWC */
|
||||
#define E1000_MBVFIMR 0x00C84 /* Mailbox VF int Mask - RW */
|
||||
#define E1000_VFLRE 0x00C88 /* VF Register Events - RWC */
|
||||
#define E1000_VFRE 0x00C8C /* VF Receive Enables */
|
||||
#define E1000_VFTE 0x00C90 /* VF Transmit Enables */
|
||||
#define E1000_QDE 0x02408 /* Queue Drop Enable - RW */
|
||||
#define E1000_DTXSWC 0x03500 /* DMA Tx Switch Control - RW */
|
||||
#define E1000_WVBR 0x03554 /* VM Wrong Behavior - RWS */
|
||||
#define E1000_RPLOLR 0x05AF0 /* Replication Offload - RW */
|
||||
#define E1000_UTA 0x0A000 /* Unicast Table Array - RW */
|
||||
#define E1000_IOVTCL 0x05BBC /* IOV Control Register */
|
||||
#define E1000_TXSWC 0x05ACC /* Tx Switch Control */
|
||||
#define E1000_LVMMC 0x03548 /* Last VM Misbehavior cause */
|
||||
/* These act per VF so an array friendly macro is used */
|
||||
#define E1000_P2VMAILBOX(_n) (0x00C00 + (4 * (_n)))
|
||||
#define E1000_VMBMEM(_n) (0x00800 + (64 * (_n)))
|
||||
#define E1000_VMOLR(_n) (0x05AD0 + (4 * (_n)))
|
||||
#define E1000_DVMOLR(_n) (0x0C038 + (64 * (_n)))
|
||||
#define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN VM Filter */
|
||||
#define E1000_VMVIR(_n) (0x03700 + (4 * (_n)))
|
||||
|
||||
struct e1000_hw;
|
||||
|
||||
u32 igb_rd32(struct e1000_hw *hw, u32 reg);
|
||||
|
||||
/* write operations, indexed using DWORDS */
|
||||
#define wr32(reg, val) \
|
||||
do { \
|
||||
u8 __iomem *hw_addr = ACCESS_ONCE((hw)->hw_addr); \
|
||||
if (!E1000_REMOVED(hw_addr)) \
|
||||
writel((val), &hw_addr[(reg)]); \
|
||||
} while (0)
|
||||
|
||||
#define rd32(reg) (igb_rd32(hw, reg))
|
||||
|
||||
#define wrfl() ((void)rd32(E1000_STATUS))
|
||||
|
||||
#define array_wr32(reg, offset, value) \
|
||||
wr32((reg) + ((offset) << 2), (value))
|
||||
|
||||
#define array_rd32(reg, offset) \
|
||||
(readl(hw->hw_addr + reg + ((offset) << 2)))
|
||||
|
||||
/* DMA Coalescing registers */
|
||||
#define E1000_PCIEMISC 0x05BB8 /* PCIE misc config register */
|
||||
|
||||
/* Energy Efficient Ethernet "EEE" register */
|
||||
#define E1000_IPCNFG 0x0E38 /* Internal PHY Configuration */
|
||||
#define E1000_EEER 0x0E30 /* Energy Efficient Ethernet */
|
||||
#define E1000_EEE_SU 0X0E34 /* EEE Setup */
|
||||
#define E1000_EMIADD 0x10 /* Extended Memory Indirect Address */
|
||||
#define E1000_EMIDATA 0x11 /* Extended Memory Indirect Data */
|
||||
#define E1000_MMDAC 13 /* MMD Access Control */
|
||||
#define E1000_MMDAAD 14 /* MMD Access Address/Data */
|
||||
|
||||
/* Thermal Sensor Register */
|
||||
#define E1000_THSTAT 0x08110 /* Thermal Sensor Status */
|
||||
|
||||
/* OS2BMC Registers */
|
||||
#define E1000_B2OSPC 0x08FE0 /* BMC2OS packets sent by BMC */
|
||||
#define E1000_B2OGPRC 0x04158 /* BMC2OS packets received by host */
|
||||
#define E1000_O2BGPTC 0x08FE4 /* OS2BMC packets received by BMC */
|
||||
#define E1000_O2BSPC 0x0415C /* OS2BMC packets transmitted by host */
|
||||
|
||||
#define E1000_SRWR 0x12018 /* Shadow Ram Write Register - RW */
|
||||
#define E1000_I210_FLMNGCTL 0x12038
|
||||
#define E1000_I210_FLMNGDATA 0x1203C
|
||||
#define E1000_I210_FLMNGCNT 0x12040
|
||||
|
||||
#define E1000_I210_FLSWCTL 0x12048
|
||||
#define E1000_I210_FLSWDATA 0x1204C
|
||||
#define E1000_I210_FLSWCNT 0x12050
|
||||
|
||||
#define E1000_I210_FLA 0x1201C
|
||||
|
||||
#define E1000_INVM_DATA_REG(_n) (0x12120 + 4*(_n))
|
||||
#define E1000_INVM_SIZE 64 /* Number of INVM Data Registers */
|
||||
|
||||
#define E1000_REMOVED(h) unlikely(!(h))
|
||||
|
||||
#endif
|
575
drivers/net/ethernet/intel/igb/igb.h
Normal file
575
drivers/net/ethernet/intel/igb/igb.h
Normal file
|
@ -0,0 +1,575 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
/* Linux PRO/1000 Ethernet Driver main header file */
|
||||
|
||||
#ifndef _IGB_H_
|
||||
#define _IGB_H_
|
||||
|
||||
#include "e1000_mac.h"
|
||||
#include "e1000_82575.h"
|
||||
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mdio.h>
|
||||
|
||||
struct igb_adapter;
|
||||
|
||||
#define E1000_PCS_CFG_IGN_SD 1
|
||||
|
||||
/* Interrupt defines */
|
||||
#define IGB_START_ITR 648 /* ~6000 ints/sec */
|
||||
#define IGB_4K_ITR 980
|
||||
#define IGB_20K_ITR 196
|
||||
#define IGB_70K_ITR 56
|
||||
|
||||
/* TX/RX descriptor defines */
|
||||
#define IGB_DEFAULT_TXD 256
|
||||
#define IGB_DEFAULT_TX_WORK 128
|
||||
#define IGB_MIN_TXD 80
|
||||
#define IGB_MAX_TXD 4096
|
||||
|
||||
#define IGB_DEFAULT_RXD 256
|
||||
#define IGB_MIN_RXD 80
|
||||
#define IGB_MAX_RXD 4096
|
||||
|
||||
#define IGB_DEFAULT_ITR 3 /* dynamic */
|
||||
#define IGB_MAX_ITR_USECS 10000
|
||||
#define IGB_MIN_ITR_USECS 10
|
||||
#define NON_Q_VECTORS 1
|
||||
#define MAX_Q_VECTORS 8
|
||||
#define MAX_MSIX_ENTRIES 10
|
||||
|
||||
/* Transmit and receive queues */
|
||||
#define IGB_MAX_RX_QUEUES 8
|
||||
#define IGB_MAX_RX_QUEUES_82575 4
|
||||
#define IGB_MAX_RX_QUEUES_I211 2
|
||||
#define IGB_MAX_TX_QUEUES 8
|
||||
#define IGB_MAX_VF_MC_ENTRIES 30
|
||||
#define IGB_MAX_VF_FUNCTIONS 8
|
||||
#define IGB_MAX_VFTA_ENTRIES 128
|
||||
#define IGB_82576_VF_DEV_ID 0x10CA
|
||||
#define IGB_I350_VF_DEV_ID 0x1520
|
||||
|
||||
/* NVM version defines */
|
||||
#define IGB_MAJOR_MASK 0xF000
|
||||
#define IGB_MINOR_MASK 0x0FF0
|
||||
#define IGB_BUILD_MASK 0x000F
|
||||
#define IGB_COMB_VER_MASK 0x00FF
|
||||
#define IGB_MAJOR_SHIFT 12
|
||||
#define IGB_MINOR_SHIFT 4
|
||||
#define IGB_COMB_VER_SHFT 8
|
||||
#define IGB_NVM_VER_INVALID 0xFFFF
|
||||
#define IGB_ETRACK_SHIFT 16
|
||||
#define NVM_ETRACK_WORD 0x0042
|
||||
#define NVM_COMB_VER_OFF 0x0083
|
||||
#define NVM_COMB_VER_PTR 0x003d
|
||||
|
||||
struct vf_data_storage {
|
||||
unsigned char vf_mac_addresses[ETH_ALEN];
|
||||
u16 vf_mc_hashes[IGB_MAX_VF_MC_ENTRIES];
|
||||
u16 num_vf_mc_hashes;
|
||||
u16 vlans_enabled;
|
||||
u32 flags;
|
||||
unsigned long last_nack;
|
||||
u16 pf_vlan; /* When set, guest VLAN config not allowed. */
|
||||
u16 pf_qos;
|
||||
u16 tx_rate;
|
||||
bool spoofchk_enabled;
|
||||
};
|
||||
|
||||
#define IGB_VF_FLAG_CTS 0x00000001 /* VF is clear to send data */
|
||||
#define IGB_VF_FLAG_UNI_PROMISC 0x00000002 /* VF has unicast promisc */
|
||||
#define IGB_VF_FLAG_MULTI_PROMISC 0x00000004 /* VF has multicast promisc */
|
||||
#define IGB_VF_FLAG_PF_SET_MAC 0x00000008 /* PF has set MAC address */
|
||||
|
||||
/* RX descriptor control thresholds.
|
||||
* PTHRESH - MAC will consider prefetch if it has fewer than this number of
|
||||
* descriptors available in its onboard memory.
|
||||
* Setting this to 0 disables RX descriptor prefetch.
|
||||
* HTHRESH - MAC will only prefetch if there are at least this many descriptors
|
||||
* available in host memory.
|
||||
* If PTHRESH is 0, this should also be 0.
|
||||
* WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
|
||||
* descriptors until either it has this many to write back, or the
|
||||
* ITR timer expires.
|
||||
*/
|
||||
#define IGB_RX_PTHRESH ((hw->mac.type == e1000_i354) ? 12 : 8)
|
||||
#define IGB_RX_HTHRESH 8
|
||||
#define IGB_TX_PTHRESH ((hw->mac.type == e1000_i354) ? 20 : 8)
|
||||
#define IGB_TX_HTHRESH 1
|
||||
#define IGB_RX_WTHRESH ((hw->mac.type == e1000_82576 && \
|
||||
(adapter->flags & IGB_FLAG_HAS_MSIX)) ? 1 : 4)
|
||||
#define IGB_TX_WTHRESH ((hw->mac.type == e1000_82576 && \
|
||||
(adapter->flags & IGB_FLAG_HAS_MSIX)) ? 1 : 16)
|
||||
|
||||
/* this is the size past which hardware will drop packets when setting LPE=0 */
|
||||
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
|
||||
|
||||
/* Supported Rx Buffer Sizes */
|
||||
#define IGB_RXBUFFER_256 256
|
||||
#define IGB_RXBUFFER_2048 2048
|
||||
#define IGB_RX_HDR_LEN IGB_RXBUFFER_256
|
||||
#define IGB_RX_BUFSZ IGB_RXBUFFER_2048
|
||||
|
||||
/* How many Rx Buffers do we bundle into one write to the hardware ? */
|
||||
#define IGB_RX_BUFFER_WRITE 16 /* Must be power of 2 */
|
||||
|
||||
#define AUTO_ALL_MODES 0
|
||||
#define IGB_EEPROM_APME 0x0400
|
||||
|
||||
#ifndef IGB_MASTER_SLAVE
|
||||
/* Switch to override PHY master/slave setting */
|
||||
#define IGB_MASTER_SLAVE e1000_ms_hw_default
|
||||
#endif
|
||||
|
||||
#define IGB_MNG_VLAN_NONE -1
|
||||
|
||||
enum igb_tx_flags {
|
||||
/* cmd_type flags */
|
||||
IGB_TX_FLAGS_VLAN = 0x01,
|
||||
IGB_TX_FLAGS_TSO = 0x02,
|
||||
IGB_TX_FLAGS_TSTAMP = 0x04,
|
||||
|
||||
/* olinfo flags */
|
||||
IGB_TX_FLAGS_IPV4 = 0x10,
|
||||
IGB_TX_FLAGS_CSUM = 0x20,
|
||||
};
|
||||
|
||||
/* VLAN info */
|
||||
#define IGB_TX_FLAGS_VLAN_MASK 0xffff0000
|
||||
#define IGB_TX_FLAGS_VLAN_SHIFT 16
|
||||
|
||||
/* The largest size we can write to the descriptor is 65535. In order to
|
||||
* maintain a power of two alignment we have to limit ourselves to 32K.
|
||||
*/
|
||||
#define IGB_MAX_TXD_PWR 15
|
||||
#define IGB_MAX_DATA_PER_TXD (1 << IGB_MAX_TXD_PWR)
|
||||
|
||||
/* Tx Descriptors needed, worst case */
|
||||
#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGB_MAX_DATA_PER_TXD)
|
||||
#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
|
||||
|
||||
/* EEPROM byte offsets */
|
||||
#define IGB_SFF_8472_SWAP 0x5C
|
||||
#define IGB_SFF_8472_COMP 0x5E
|
||||
|
||||
/* Bitmasks */
|
||||
#define IGB_SFF_ADDRESSING_MODE 0x4
|
||||
#define IGB_SFF_8472_UNSUP 0x00
|
||||
|
||||
/* wrapper around a pointer to a socket buffer,
|
||||
* so a DMA handle can be stored along with the buffer
|
||||
*/
|
||||
struct igb_tx_buffer {
|
||||
union e1000_adv_tx_desc *next_to_watch;
|
||||
unsigned long time_stamp;
|
||||
struct sk_buff *skb;
|
||||
unsigned int bytecount;
|
||||
u16 gso_segs;
|
||||
__be16 protocol;
|
||||
|
||||
DEFINE_DMA_UNMAP_ADDR(dma);
|
||||
DEFINE_DMA_UNMAP_LEN(len);
|
||||
u32 tx_flags;
|
||||
};
|
||||
|
||||
struct igb_rx_buffer {
|
||||
dma_addr_t dma;
|
||||
struct page *page;
|
||||
unsigned int page_offset;
|
||||
};
|
||||
|
||||
struct igb_tx_queue_stats {
|
||||
u64 packets;
|
||||
u64 bytes;
|
||||
u64 restart_queue;
|
||||
u64 restart_queue2;
|
||||
};
|
||||
|
||||
struct igb_rx_queue_stats {
|
||||
u64 packets;
|
||||
u64 bytes;
|
||||
u64 drops;
|
||||
u64 csum_err;
|
||||
u64 alloc_failed;
|
||||
};
|
||||
|
||||
struct igb_ring_container {
|
||||
struct igb_ring *ring; /* pointer to linked list of rings */
|
||||
unsigned int total_bytes; /* total bytes processed this int */
|
||||
unsigned int total_packets; /* total packets processed this int */
|
||||
u16 work_limit; /* total work allowed per interrupt */
|
||||
u8 count; /* total number of rings in vector */
|
||||
u8 itr; /* current ITR setting for ring */
|
||||
};
|
||||
|
||||
struct igb_ring {
|
||||
struct igb_q_vector *q_vector; /* backlink to q_vector */
|
||||
struct net_device *netdev; /* back pointer to net_device */
|
||||
struct device *dev; /* device pointer for dma mapping */
|
||||
union { /* array of buffer info structs */
|
||||
struct igb_tx_buffer *tx_buffer_info;
|
||||
struct igb_rx_buffer *rx_buffer_info;
|
||||
};
|
||||
void *desc; /* descriptor ring memory */
|
||||
unsigned long flags; /* ring specific flags */
|
||||
void __iomem *tail; /* pointer to ring tail register */
|
||||
dma_addr_t dma; /* phys address of the ring */
|
||||
unsigned int size; /* length of desc. ring in bytes */
|
||||
|
||||
u16 count; /* number of desc. in the ring */
|
||||
u8 queue_index; /* logical index of the ring*/
|
||||
u8 reg_idx; /* physical index of the ring */
|
||||
|
||||
/* everything past this point are written often */
|
||||
u16 next_to_clean;
|
||||
u16 next_to_use;
|
||||
u16 next_to_alloc;
|
||||
|
||||
union {
|
||||
/* TX */
|
||||
struct {
|
||||
struct igb_tx_queue_stats tx_stats;
|
||||
struct u64_stats_sync tx_syncp;
|
||||
struct u64_stats_sync tx_syncp2;
|
||||
};
|
||||
/* RX */
|
||||
struct {
|
||||
struct sk_buff *skb;
|
||||
struct igb_rx_queue_stats rx_stats;
|
||||
struct u64_stats_sync rx_syncp;
|
||||
};
|
||||
};
|
||||
} ____cacheline_internodealigned_in_smp;
|
||||
|
||||
struct igb_q_vector {
|
||||
struct igb_adapter *adapter; /* backlink */
|
||||
int cpu; /* CPU for DCA */
|
||||
u32 eims_value; /* EIMS mask value */
|
||||
|
||||
u16 itr_val;
|
||||
u8 set_itr;
|
||||
void __iomem *itr_register;
|
||||
|
||||
struct igb_ring_container rx, tx;
|
||||
|
||||
struct napi_struct napi;
|
||||
struct rcu_head rcu; /* to avoid race with update stats on free */
|
||||
char name[IFNAMSIZ + 9];
|
||||
|
||||
/* for dynamic allocation of rings associated with this q_vector */
|
||||
struct igb_ring ring[0] ____cacheline_internodealigned_in_smp;
|
||||
};
|
||||
|
||||
enum e1000_ring_flags_t {
|
||||
IGB_RING_FLAG_RX_SCTP_CSUM,
|
||||
IGB_RING_FLAG_RX_LB_VLAN_BSWAP,
|
||||
IGB_RING_FLAG_TX_CTX_IDX,
|
||||
IGB_RING_FLAG_TX_DETECT_HANG
|
||||
};
|
||||
|
||||
#define IGB_TXD_DCMD (E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS)
|
||||
|
||||
#define IGB_RX_DESC(R, i) \
|
||||
(&(((union e1000_adv_rx_desc *)((R)->desc))[i]))
|
||||
#define IGB_TX_DESC(R, i) \
|
||||
(&(((union e1000_adv_tx_desc *)((R)->desc))[i]))
|
||||
#define IGB_TX_CTXTDESC(R, i) \
|
||||
(&(((struct e1000_adv_tx_context_desc *)((R)->desc))[i]))
|
||||
|
||||
/* igb_test_staterr - tests bits within Rx descriptor status and error fields */
|
||||
static inline __le32 igb_test_staterr(union e1000_adv_rx_desc *rx_desc,
|
||||
const u32 stat_err_bits)
|
||||
{
|
||||
return rx_desc->wb.upper.status_error & cpu_to_le32(stat_err_bits);
|
||||
}
|
||||
|
||||
/* igb_desc_unused - calculate if we have unused descriptors */
|
||||
static inline int igb_desc_unused(struct igb_ring *ring)
|
||||
{
|
||||
if (ring->next_to_clean > ring->next_to_use)
|
||||
return ring->next_to_clean - ring->next_to_use - 1;
|
||||
|
||||
return ring->count + ring->next_to_clean - ring->next_to_use - 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IGB_HWMON
|
||||
|
||||
#define IGB_HWMON_TYPE_LOC 0
|
||||
#define IGB_HWMON_TYPE_TEMP 1
|
||||
#define IGB_HWMON_TYPE_CAUTION 2
|
||||
#define IGB_HWMON_TYPE_MAX 3
|
||||
|
||||
struct hwmon_attr {
|
||||
struct device_attribute dev_attr;
|
||||
struct e1000_hw *hw;
|
||||
struct e1000_thermal_diode_data *sensor;
|
||||
char name[12];
|
||||
};
|
||||
|
||||
struct hwmon_buff {
|
||||
struct attribute_group group;
|
||||
const struct attribute_group *groups[2];
|
||||
struct attribute *attrs[E1000_MAX_SENSORS * 4 + 1];
|
||||
struct hwmon_attr hwmon_list[E1000_MAX_SENSORS * 4];
|
||||
unsigned int n_hwmon;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define IGB_RETA_SIZE 128
|
||||
|
||||
/* board specific private data structure */
|
||||
struct igb_adapter {
|
||||
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
|
||||
|
||||
struct net_device *netdev;
|
||||
|
||||
unsigned long state;
|
||||
unsigned int flags;
|
||||
|
||||
unsigned int num_q_vectors;
|
||||
struct msix_entry msix_entries[MAX_MSIX_ENTRIES];
|
||||
|
||||
/* Interrupt Throttle Rate */
|
||||
u32 rx_itr_setting;
|
||||
u32 tx_itr_setting;
|
||||
u16 tx_itr;
|
||||
u16 rx_itr;
|
||||
|
||||
/* TX */
|
||||
u16 tx_work_limit;
|
||||
u32 tx_timeout_count;
|
||||
int num_tx_queues;
|
||||
struct igb_ring *tx_ring[16];
|
||||
|
||||
/* RX */
|
||||
int num_rx_queues;
|
||||
struct igb_ring *rx_ring[16];
|
||||
|
||||
u32 max_frame_size;
|
||||
u32 min_frame_size;
|
||||
|
||||
struct timer_list watchdog_timer;
|
||||
struct timer_list phy_info_timer;
|
||||
|
||||
u16 mng_vlan_id;
|
||||
u32 bd_number;
|
||||
u32 wol;
|
||||
u32 en_mng_pt;
|
||||
u16 link_speed;
|
||||
u16 link_duplex;
|
||||
|
||||
struct work_struct reset_task;
|
||||
struct work_struct watchdog_task;
|
||||
bool fc_autoneg;
|
||||
u8 tx_timeout_factor;
|
||||
struct timer_list blink_timer;
|
||||
unsigned long led_status;
|
||||
|
||||
/* OS defined structs */
|
||||
struct pci_dev *pdev;
|
||||
|
||||
spinlock_t stats64_lock;
|
||||
struct rtnl_link_stats64 stats64;
|
||||
|
||||
/* structs defined in e1000_hw.h */
|
||||
struct e1000_hw hw;
|
||||
struct e1000_hw_stats stats;
|
||||
struct e1000_phy_info phy_info;
|
||||
|
||||
u32 test_icr;
|
||||
struct igb_ring test_tx_ring;
|
||||
struct igb_ring test_rx_ring;
|
||||
|
||||
int msg_enable;
|
||||
|
||||
struct igb_q_vector *q_vector[MAX_Q_VECTORS];
|
||||
u32 eims_enable_mask;
|
||||
u32 eims_other;
|
||||
|
||||
/* to not mess up cache alignment, always add to the bottom */
|
||||
u16 tx_ring_count;
|
||||
u16 rx_ring_count;
|
||||
unsigned int vfs_allocated_count;
|
||||
struct vf_data_storage *vf_data;
|
||||
int vf_rate_link_speed;
|
||||
u32 rss_queues;
|
||||
u32 wvbr;
|
||||
u32 *shadow_vfta;
|
||||
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct ptp_clock_info ptp_caps;
|
||||
struct delayed_work ptp_overflow_work;
|
||||
struct work_struct ptp_tx_work;
|
||||
struct sk_buff *ptp_tx_skb;
|
||||
struct hwtstamp_config tstamp_config;
|
||||
unsigned long ptp_tx_start;
|
||||
unsigned long last_rx_ptp_check;
|
||||
unsigned long last_rx_timestamp;
|
||||
spinlock_t tmreg_lock;
|
||||
struct cyclecounter cc;
|
||||
struct timecounter tc;
|
||||
u32 tx_hwtstamp_timeouts;
|
||||
u32 rx_hwtstamp_cleared;
|
||||
|
||||
char fw_version[32];
|
||||
#ifdef CONFIG_IGB_HWMON
|
||||
struct hwmon_buff *igb_hwmon_buff;
|
||||
bool ets;
|
||||
#endif
|
||||
struct i2c_algo_bit_data i2c_algo;
|
||||
struct i2c_adapter i2c_adap;
|
||||
struct i2c_client *i2c_client;
|
||||
u32 rss_indir_tbl_init;
|
||||
u8 rss_indir_tbl[IGB_RETA_SIZE];
|
||||
|
||||
unsigned long link_check_timeout;
|
||||
int copper_tries;
|
||||
struct e1000_info ei;
|
||||
u16 eee_advert;
|
||||
};
|
||||
|
||||
#define IGB_FLAG_HAS_MSI (1 << 0)
|
||||
#define IGB_FLAG_DCA_ENABLED (1 << 1)
|
||||
#define IGB_FLAG_QUAD_PORT_A (1 << 2)
|
||||
#define IGB_FLAG_QUEUE_PAIRS (1 << 3)
|
||||
#define IGB_FLAG_DMAC (1 << 4)
|
||||
#define IGB_FLAG_PTP (1 << 5)
|
||||
#define IGB_FLAG_RSS_FIELD_IPV4_UDP (1 << 6)
|
||||
#define IGB_FLAG_RSS_FIELD_IPV6_UDP (1 << 7)
|
||||
#define IGB_FLAG_WOL_SUPPORTED (1 << 8)
|
||||
#define IGB_FLAG_NEED_LINK_UPDATE (1 << 9)
|
||||
#define IGB_FLAG_MEDIA_RESET (1 << 10)
|
||||
#define IGB_FLAG_MAS_CAPABLE (1 << 11)
|
||||
#define IGB_FLAG_MAS_ENABLE (1 << 12)
|
||||
#define IGB_FLAG_HAS_MSIX (1 << 13)
|
||||
#define IGB_FLAG_EEE (1 << 14)
|
||||
|
||||
/* Media Auto Sense */
|
||||
#define IGB_MAS_ENABLE_0 0X0001
|
||||
#define IGB_MAS_ENABLE_1 0X0002
|
||||
#define IGB_MAS_ENABLE_2 0X0004
|
||||
#define IGB_MAS_ENABLE_3 0X0008
|
||||
|
||||
/* DMA Coalescing defines */
|
||||
#define IGB_MIN_TXPBSIZE 20408
|
||||
#define IGB_TX_BUF_4096 4096
|
||||
#define IGB_DMCTLX_DCFLUSH_DIS 0x80000000 /* Disable DMA Coal Flush */
|
||||
|
||||
#define IGB_82576_TSYNC_SHIFT 19
|
||||
#define IGB_TS_HDR_LEN 16
|
||||
enum e1000_state_t {
|
||||
__IGB_TESTING,
|
||||
__IGB_RESETTING,
|
||||
__IGB_DOWN,
|
||||
__IGB_PTP_TX_IN_PROGRESS,
|
||||
};
|
||||
|
||||
enum igb_boards {
|
||||
board_82575,
|
||||
};
|
||||
|
||||
extern char igb_driver_name[];
|
||||
extern char igb_driver_version[];
|
||||
|
||||
int igb_up(struct igb_adapter *);
|
||||
void igb_down(struct igb_adapter *);
|
||||
void igb_reinit_locked(struct igb_adapter *);
|
||||
void igb_reset(struct igb_adapter *);
|
||||
int igb_reinit_queues(struct igb_adapter *);
|
||||
void igb_write_rss_indir_tbl(struct igb_adapter *);
|
||||
int igb_set_spd_dplx(struct igb_adapter *, u32, u8);
|
||||
int igb_setup_tx_resources(struct igb_ring *);
|
||||
int igb_setup_rx_resources(struct igb_ring *);
|
||||
void igb_free_tx_resources(struct igb_ring *);
|
||||
void igb_free_rx_resources(struct igb_ring *);
|
||||
void igb_configure_tx_ring(struct igb_adapter *, struct igb_ring *);
|
||||
void igb_configure_rx_ring(struct igb_adapter *, struct igb_ring *);
|
||||
void igb_setup_tctl(struct igb_adapter *);
|
||||
void igb_setup_rctl(struct igb_adapter *);
|
||||
netdev_tx_t igb_xmit_frame_ring(struct sk_buff *, struct igb_ring *);
|
||||
void igb_unmap_and_free_tx_resource(struct igb_ring *, struct igb_tx_buffer *);
|
||||
void igb_alloc_rx_buffers(struct igb_ring *, u16);
|
||||
void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *);
|
||||
bool igb_has_link(struct igb_adapter *adapter);
|
||||
void igb_set_ethtool_ops(struct net_device *);
|
||||
void igb_power_up_link(struct igb_adapter *);
|
||||
void igb_set_fw_version(struct igb_adapter *);
|
||||
void igb_ptp_init(struct igb_adapter *adapter);
|
||||
void igb_ptp_stop(struct igb_adapter *adapter);
|
||||
void igb_ptp_reset(struct igb_adapter *adapter);
|
||||
void igb_ptp_rx_hang(struct igb_adapter *adapter);
|
||||
void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb);
|
||||
void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, unsigned char *va,
|
||||
struct sk_buff *skb);
|
||||
int igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
|
||||
int igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr);
|
||||
#ifdef CONFIG_IGB_HWMON
|
||||
void igb_sysfs_exit(struct igb_adapter *adapter);
|
||||
int igb_sysfs_init(struct igb_adapter *adapter);
|
||||
#endif
|
||||
static inline s32 igb_reset_phy(struct e1000_hw *hw)
|
||||
{
|
||||
if (hw->phy.ops.reset)
|
||||
return hw->phy.ops.reset(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline s32 igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data)
|
||||
{
|
||||
if (hw->phy.ops.read_reg)
|
||||
return hw->phy.ops.read_reg(hw, offset, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline s32 igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data)
|
||||
{
|
||||
if (hw->phy.ops.write_reg)
|
||||
return hw->phy.ops.write_reg(hw, offset, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline s32 igb_get_phy_info(struct e1000_hw *hw)
|
||||
{
|
||||
if (hw->phy.ops.get_phy_info)
|
||||
return hw->phy.ops.get_phy_info(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct netdev_queue *txring_txq(const struct igb_ring *tx_ring)
|
||||
{
|
||||
return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index);
|
||||
}
|
||||
|
||||
#endif /* _IGB_H_ */
|
3052
drivers/net/ethernet/intel/igb/igb_ethtool.c
Normal file
3052
drivers/net/ethernet/intel/igb/igb_ethtool.c
Normal file
File diff suppressed because it is too large
Load diff
249
drivers/net/ethernet/intel/igb/igb_hwmon.c
Normal file
249
drivers/net/ethernet/intel/igb/igb_hwmon.c
Normal file
|
@ -0,0 +1,249 @@
|
|||
/* Intel(R) Gigabit Ethernet Linux driver
|
||||
* Copyright(c) 2007-2014 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*/
|
||||
|
||||
#include "igb.h"
|
||||
#include "e1000_82575.h"
|
||||
#include "e1000_hw.h"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#ifdef CONFIG_IGB_HWMON
|
||||
static struct i2c_board_info i350_sensor_info = {
|
||||
I2C_BOARD_INFO("i350bb", (0Xf8 >> 1)),
|
||||
};
|
||||
|
||||
/* hwmon callback functions */
|
||||
static ssize_t igb_hwmon_show_location(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
|
||||
dev_attr);
|
||||
return sprintf(buf, "loc%u\n",
|
||||
igb_attr->sensor->location);
|
||||
}
|
||||
|
||||
static ssize_t igb_hwmon_show_temp(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
|
||||
dev_attr);
|
||||
unsigned int value;
|
||||
|
||||
/* reset the temp field */
|
||||
igb_attr->hw->mac.ops.get_thermal_sensor_data(igb_attr->hw);
|
||||
|
||||
value = igb_attr->sensor->temp;
|
||||
|
||||
/* display millidegree */
|
||||
value *= 1000;
|
||||
|
||||
return sprintf(buf, "%u\n", value);
|
||||
}
|
||||
|
||||
static ssize_t igb_hwmon_show_cautionthresh(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
|
||||
dev_attr);
|
||||
unsigned int value = igb_attr->sensor->caution_thresh;
|
||||
|
||||
/* display millidegree */
|
||||
value *= 1000;
|
||||
|
||||
return sprintf(buf, "%u\n", value);
|
||||
}
|
||||
|
||||
static ssize_t igb_hwmon_show_maxopthresh(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
|
||||
dev_attr);
|
||||
unsigned int value = igb_attr->sensor->max_op_thresh;
|
||||
|
||||
/* display millidegree */
|
||||
value *= 1000;
|
||||
|
||||
return sprintf(buf, "%u\n", value);
|
||||
}
|
||||
|
||||
/* igb_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file.
|
||||
* @ adapter: pointer to the adapter structure
|
||||
* @ offset: offset in the eeprom sensor data table
|
||||
* @ type: type of sensor data to display
|
||||
*
|
||||
* For each file we want in hwmon's sysfs interface we need a device_attribute
|
||||
* This is included in our hwmon_attr struct that contains the references to
|
||||
* the data structures we need to get the data to display.
|
||||
*/
|
||||
static int igb_add_hwmon_attr(struct igb_adapter *adapter,
|
||||
unsigned int offset, int type)
|
||||
{
|
||||
int rc;
|
||||
unsigned int n_attr;
|
||||
struct hwmon_attr *igb_attr;
|
||||
|
||||
n_attr = adapter->igb_hwmon_buff->n_hwmon;
|
||||
igb_attr = &adapter->igb_hwmon_buff->hwmon_list[n_attr];
|
||||
|
||||
switch (type) {
|
||||
case IGB_HWMON_TYPE_LOC:
|
||||
igb_attr->dev_attr.show = igb_hwmon_show_location;
|
||||
snprintf(igb_attr->name, sizeof(igb_attr->name),
|
||||
"temp%u_label", offset + 1);
|
||||
break;
|
||||
case IGB_HWMON_TYPE_TEMP:
|
||||
igb_attr->dev_attr.show = igb_hwmon_show_temp;
|
||||
snprintf(igb_attr->name, sizeof(igb_attr->name),
|
||||
"temp%u_input", offset + 1);
|
||||
break;
|
||||
case IGB_HWMON_TYPE_CAUTION:
|
||||
igb_attr->dev_attr.show = igb_hwmon_show_cautionthresh;
|
||||
snprintf(igb_attr->name, sizeof(igb_attr->name),
|
||||
"temp%u_max", offset + 1);
|
||||
break;
|
||||
case IGB_HWMON_TYPE_MAX:
|
||||
igb_attr->dev_attr.show = igb_hwmon_show_maxopthresh;
|
||||
snprintf(igb_attr->name, sizeof(igb_attr->name),
|
||||
"temp%u_crit", offset + 1);
|
||||
break;
|
||||
default:
|
||||
rc = -EPERM;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* These always the same regardless of type */
|
||||
igb_attr->sensor =
|
||||
&adapter->hw.mac.thermal_sensor_data.sensor[offset];
|
||||
igb_attr->hw = &adapter->hw;
|
||||
igb_attr->dev_attr.store = NULL;
|
||||
igb_attr->dev_attr.attr.mode = S_IRUGO;
|
||||
igb_attr->dev_attr.attr.name = igb_attr->name;
|
||||
sysfs_attr_init(&igb_attr->dev_attr.attr);
|
||||
|
||||
adapter->igb_hwmon_buff->attrs[n_attr] = &igb_attr->dev_attr.attr;
|
||||
|
||||
++adapter->igb_hwmon_buff->n_hwmon;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void igb_sysfs_del_adapter(struct igb_adapter *adapter)
|
||||
{
|
||||
}
|
||||
|
||||
/* called from igb_main.c */
|
||||
void igb_sysfs_exit(struct igb_adapter *adapter)
|
||||
{
|
||||
igb_sysfs_del_adapter(adapter);
|
||||
}
|
||||
|
||||
/* called from igb_main.c */
|
||||
int igb_sysfs_init(struct igb_adapter *adapter)
|
||||
{
|
||||
struct hwmon_buff *igb_hwmon;
|
||||
struct i2c_client *client;
|
||||
struct device *hwmon_dev;
|
||||
unsigned int i;
|
||||
int rc = 0;
|
||||
|
||||
/* If this method isn't defined we don't support thermals */
|
||||
if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL)
|
||||
goto exit;
|
||||
|
||||
/* Don't create thermal hwmon interface if no sensors present */
|
||||
rc = (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw));
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
igb_hwmon = devm_kzalloc(&adapter->pdev->dev, sizeof(*igb_hwmon),
|
||||
GFP_KERNEL);
|
||||
if (!igb_hwmon) {
|
||||
rc = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
adapter->igb_hwmon_buff = igb_hwmon;
|
||||
|
||||
for (i = 0; i < E1000_MAX_SENSORS; i++) {
|
||||
|
||||
/* Only create hwmon sysfs entries for sensors that have
|
||||
* meaningful data.
|
||||
*/
|
||||
if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0)
|
||||
continue;
|
||||
|
||||
/* Bail if any hwmon attr struct fails to initialize */
|
||||
rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_CAUTION);
|
||||
if (rc)
|
||||
goto exit;
|
||||
rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC);
|
||||
if (rc)
|
||||
goto exit;
|
||||
rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP);
|
||||
if (rc)
|
||||
goto exit;
|
||||
rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX);
|
||||
if (rc)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* init i2c_client */
|
||||
client = i2c_new_device(&adapter->i2c_adap, &i350_sensor_info);
|
||||
if (client == NULL) {
|
||||
dev_info(&adapter->pdev->dev,
|
||||
"Failed to create new i2c device.\n");
|
||||
rc = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
adapter->i2c_client = client;
|
||||
|
||||
igb_hwmon->groups[0] = &igb_hwmon->group;
|
||||
igb_hwmon->group.attrs = igb_hwmon->attrs;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&adapter->pdev->dev,
|
||||
client->name,
|
||||
igb_hwmon,
|
||||
igb_hwmon->groups);
|
||||
if (IS_ERR(hwmon_dev)) {
|
||||
rc = PTR_ERR(hwmon_dev);
|
||||
goto err;
|
||||
}
|
||||
|
||||
goto exit;
|
||||
|
||||
err:
|
||||
igb_sysfs_del_adapter(adapter);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
#endif
|
8105
drivers/net/ethernet/intel/igb/igb_main.c
Normal file
8105
drivers/net/ethernet/intel/igb/igb_main.c
Normal file
File diff suppressed because it is too large
Load diff
944
drivers/net/ethernet/intel/igb/igb_ptp.c
Normal file
944
drivers/net/ethernet/intel/igb/igb_ptp.c
Normal file
|
@ -0,0 +1,944 @@
|
|||
/* PTP Hardware Clock (PHC) driver for the Intel 82576 and 82580
|
||||
*
|
||||
* Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ptp_classify.h>
|
||||
|
||||
#include "igb.h"
|
||||
|
||||
#define INCVALUE_MASK 0x7fffffff
|
||||
#define ISGN 0x80000000
|
||||
|
||||
/* The 82580 timesync updates the system timer every 8ns by 8ns,
|
||||
* and this update value cannot be reprogrammed.
|
||||
*
|
||||
* Neither the 82576 nor the 82580 offer registers wide enough to hold
|
||||
* nanoseconds time values for very long. For the 82580, SYSTIM always
|
||||
* counts nanoseconds, but the upper 24 bits are not availible. The
|
||||
* frequency is adjusted by changing the 32 bit fractional nanoseconds
|
||||
* register, TIMINCA.
|
||||
*
|
||||
* For the 82576, the SYSTIM register time unit is affect by the
|
||||
* choice of the 24 bit TININCA:IV (incvalue) field. Five bits of this
|
||||
* field are needed to provide the nominal 16 nanosecond period,
|
||||
* leaving 19 bits for fractional nanoseconds.
|
||||
*
|
||||
* We scale the NIC clock cycle by a large factor so that relatively
|
||||
* small clock corrections can be added or subtracted at each clock
|
||||
* tick. The drawbacks of a large factor are a) that the clock
|
||||
* register overflows more quickly (not such a big deal) and b) that
|
||||
* the increment per tick has to fit into 24 bits. As a result we
|
||||
* need to use a shift of 19 so we can fit a value of 16 into the
|
||||
* TIMINCA register.
|
||||
*
|
||||
*
|
||||
* SYSTIMH SYSTIML
|
||||
* +--------------+ +---+---+------+
|
||||
* 82576 | 32 | | 8 | 5 | 19 |
|
||||
* +--------------+ +---+---+------+
|
||||
* \________ 45 bits _______/ fract
|
||||
*
|
||||
* +----------+---+ +--------------+
|
||||
* 82580 | 24 | 8 | | 32 |
|
||||
* +----------+---+ +--------------+
|
||||
* reserved \______ 40 bits _____/
|
||||
*
|
||||
*
|
||||
* The 45 bit 82576 SYSTIM overflows every
|
||||
* 2^45 * 10^-9 / 3600 = 9.77 hours.
|
||||
*
|
||||
* The 40 bit 82580 SYSTIM overflows every
|
||||
* 2^40 * 10^-9 / 60 = 18.3 minutes.
|
||||
*/
|
||||
|
||||
#define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 9)
|
||||
#define IGB_PTP_TX_TIMEOUT (HZ * 15)
|
||||
#define INCPERIOD_82576 (1 << E1000_TIMINCA_16NS_SHIFT)
|
||||
#define INCVALUE_82576_MASK ((1 << E1000_TIMINCA_16NS_SHIFT) - 1)
|
||||
#define INCVALUE_82576 (16 << IGB_82576_TSYNC_SHIFT)
|
||||
#define IGB_NBITS_82580 40
|
||||
|
||||
static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter);
|
||||
|
||||
/* SYSTIM read access for the 82576 */
|
||||
static cycle_t igb_ptp_read_82576(const struct cyclecounter *cc)
|
||||
{
|
||||
struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc);
|
||||
struct e1000_hw *hw = &igb->hw;
|
||||
u64 val;
|
||||
u32 lo, hi;
|
||||
|
||||
lo = rd32(E1000_SYSTIML);
|
||||
hi = rd32(E1000_SYSTIMH);
|
||||
|
||||
val = ((u64) hi) << 32;
|
||||
val |= lo;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* SYSTIM read access for the 82580 */
|
||||
static cycle_t igb_ptp_read_82580(const struct cyclecounter *cc)
|
||||
{
|
||||
struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc);
|
||||
struct e1000_hw *hw = &igb->hw;
|
||||
u32 lo, hi;
|
||||
u64 val;
|
||||
|
||||
/* The timestamp latches on lowest register read. For the 82580
|
||||
* the lowest register is SYSTIMR instead of SYSTIML. However we only
|
||||
* need to provide nanosecond resolution, so we just ignore it.
|
||||
*/
|
||||
rd32(E1000_SYSTIMR);
|
||||
lo = rd32(E1000_SYSTIML);
|
||||
hi = rd32(E1000_SYSTIMH);
|
||||
|
||||
val = ((u64) hi) << 32;
|
||||
val |= lo;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* SYSTIM read access for I210/I211 */
|
||||
static void igb_ptp_read_i210(struct igb_adapter *adapter, struct timespec *ts)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
u32 sec, nsec;
|
||||
|
||||
/* The timestamp latches on lowest register read. For I210/I211, the
|
||||
* lowest register is SYSTIMR. Since we only need to provide nanosecond
|
||||
* resolution, we can ignore it.
|
||||
*/
|
||||
rd32(E1000_SYSTIMR);
|
||||
nsec = rd32(E1000_SYSTIML);
|
||||
sec = rd32(E1000_SYSTIMH);
|
||||
|
||||
ts->tv_sec = sec;
|
||||
ts->tv_nsec = nsec;
|
||||
}
|
||||
|
||||
static void igb_ptp_write_i210(struct igb_adapter *adapter,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
|
||||
/* Writing the SYSTIMR register is not necessary as it only provides
|
||||
* sub-nanosecond resolution.
|
||||
*/
|
||||
wr32(E1000_SYSTIML, ts->tv_nsec);
|
||||
wr32(E1000_SYSTIMH, ts->tv_sec);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_systim_to_hwtstamp - convert system time value to hw timestamp
|
||||
* @adapter: board private structure
|
||||
* @hwtstamps: timestamp structure to update
|
||||
* @systim: unsigned 64bit system time value.
|
||||
*
|
||||
* We need to convert the system time value stored in the RX/TXSTMP registers
|
||||
* into a hwtstamp which can be used by the upper level timestamping functions.
|
||||
*
|
||||
* The 'tmreg_lock' spinlock is used to protect the consistency of the
|
||||
* system time value. This is needed because reading the 64 bit time
|
||||
* value involves reading two (or three) 32 bit registers. The first
|
||||
* read latches the value. Ditto for writing.
|
||||
*
|
||||
* In addition, here have extended the system time with an overflow
|
||||
* counter in software.
|
||||
**/
|
||||
static void igb_ptp_systim_to_hwtstamp(struct igb_adapter *adapter,
|
||||
struct skb_shared_hwtstamps *hwtstamps,
|
||||
u64 systim)
|
||||
{
|
||||
unsigned long flags;
|
||||
u64 ns;
|
||||
|
||||
switch (adapter->hw.mac.type) {
|
||||
case e1000_82576:
|
||||
case e1000_82580:
|
||||
case e1000_i354:
|
||||
case e1000_i350:
|
||||
spin_lock_irqsave(&adapter->tmreg_lock, flags);
|
||||
|
||||
ns = timecounter_cyc2time(&adapter->tc, systim);
|
||||
|
||||
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
|
||||
|
||||
memset(hwtstamps, 0, sizeof(*hwtstamps));
|
||||
hwtstamps->hwtstamp = ns_to_ktime(ns);
|
||||
break;
|
||||
case e1000_i210:
|
||||
case e1000_i211:
|
||||
memset(hwtstamps, 0, sizeof(*hwtstamps));
|
||||
/* Upper 32 bits contain s, lower 32 bits contain ns. */
|
||||
hwtstamps->hwtstamp = ktime_set(systim >> 32,
|
||||
systim & 0xFFFFFFFF);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* PTP clock operations */
|
||||
static int igb_ptp_adjfreq_82576(struct ptp_clock_info *ptp, s32 ppb)
|
||||
{
|
||||
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
|
||||
ptp_caps);
|
||||
struct e1000_hw *hw = &igb->hw;
|
||||
int neg_adj = 0;
|
||||
u64 rate;
|
||||
u32 incvalue;
|
||||
|
||||
if (ppb < 0) {
|
||||
neg_adj = 1;
|
||||
ppb = -ppb;
|
||||
}
|
||||
rate = ppb;
|
||||
rate <<= 14;
|
||||
rate = div_u64(rate, 1953125);
|
||||
|
||||
incvalue = 16 << IGB_82576_TSYNC_SHIFT;
|
||||
|
||||
if (neg_adj)
|
||||
incvalue -= rate;
|
||||
else
|
||||
incvalue += rate;
|
||||
|
||||
wr32(E1000_TIMINCA, INCPERIOD_82576 | (incvalue & INCVALUE_82576_MASK));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igb_ptp_adjfreq_82580(struct ptp_clock_info *ptp, s32 ppb)
|
||||
{
|
||||
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
|
||||
ptp_caps);
|
||||
struct e1000_hw *hw = &igb->hw;
|
||||
int neg_adj = 0;
|
||||
u64 rate;
|
||||
u32 inca;
|
||||
|
||||
if (ppb < 0) {
|
||||
neg_adj = 1;
|
||||
ppb = -ppb;
|
||||
}
|
||||
rate = ppb;
|
||||
rate <<= 26;
|
||||
rate = div_u64(rate, 1953125);
|
||||
|
||||
inca = rate & INCVALUE_MASK;
|
||||
if (neg_adj)
|
||||
inca |= ISGN;
|
||||
|
||||
wr32(E1000_TIMINCA, inca);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igb_ptp_adjtime_82576(struct ptp_clock_info *ptp, s64 delta)
|
||||
{
|
||||
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
|
||||
ptp_caps);
|
||||
unsigned long flags;
|
||||
s64 now;
|
||||
|
||||
spin_lock_irqsave(&igb->tmreg_lock, flags);
|
||||
|
||||
now = timecounter_read(&igb->tc);
|
||||
now += delta;
|
||||
timecounter_init(&igb->tc, &igb->cc, now);
|
||||
|
||||
spin_unlock_irqrestore(&igb->tmreg_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igb_ptp_adjtime_i210(struct ptp_clock_info *ptp, s64 delta)
|
||||
{
|
||||
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
|
||||
ptp_caps);
|
||||
unsigned long flags;
|
||||
struct timespec now, then = ns_to_timespec(delta);
|
||||
|
||||
spin_lock_irqsave(&igb->tmreg_lock, flags);
|
||||
|
||||
igb_ptp_read_i210(igb, &now);
|
||||
now = timespec_add(now, then);
|
||||
igb_ptp_write_i210(igb, (const struct timespec *)&now);
|
||||
|
||||
spin_unlock_irqrestore(&igb->tmreg_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igb_ptp_gettime_82576(struct ptp_clock_info *ptp,
|
||||
struct timespec *ts)
|
||||
{
|
||||
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
|
||||
ptp_caps);
|
||||
unsigned long flags;
|
||||
u64 ns;
|
||||
u32 remainder;
|
||||
|
||||
spin_lock_irqsave(&igb->tmreg_lock, flags);
|
||||
|
||||
ns = timecounter_read(&igb->tc);
|
||||
|
||||
spin_unlock_irqrestore(&igb->tmreg_lock, flags);
|
||||
|
||||
ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
|
||||
ts->tv_nsec = remainder;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igb_ptp_gettime_i210(struct ptp_clock_info *ptp,
|
||||
struct timespec *ts)
|
||||
{
|
||||
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
|
||||
ptp_caps);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&igb->tmreg_lock, flags);
|
||||
|
||||
igb_ptp_read_i210(igb, ts);
|
||||
|
||||
spin_unlock_irqrestore(&igb->tmreg_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igb_ptp_settime_82576(struct ptp_clock_info *ptp,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
|
||||
ptp_caps);
|
||||
unsigned long flags;
|
||||
u64 ns;
|
||||
|
||||
ns = ts->tv_sec * 1000000000ULL;
|
||||
ns += ts->tv_nsec;
|
||||
|
||||
spin_lock_irqsave(&igb->tmreg_lock, flags);
|
||||
|
||||
timecounter_init(&igb->tc, &igb->cc, ns);
|
||||
|
||||
spin_unlock_irqrestore(&igb->tmreg_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igb_ptp_settime_i210(struct ptp_clock_info *ptp,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
|
||||
ptp_caps);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&igb->tmreg_lock, flags);
|
||||
|
||||
igb_ptp_write_i210(igb, ts);
|
||||
|
||||
spin_unlock_irqrestore(&igb->tmreg_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igb_ptp_feature_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *rq, int on)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_tx_work
|
||||
* @work: pointer to work struct
|
||||
*
|
||||
* This work function polls the TSYNCTXCTL valid bit to determine when a
|
||||
* timestamp has been taken for the current stored skb.
|
||||
**/
|
||||
static void igb_ptp_tx_work(struct work_struct *work)
|
||||
{
|
||||
struct igb_adapter *adapter = container_of(work, struct igb_adapter,
|
||||
ptp_tx_work);
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
u32 tsynctxctl;
|
||||
|
||||
if (!adapter->ptp_tx_skb)
|
||||
return;
|
||||
|
||||
if (time_is_before_jiffies(adapter->ptp_tx_start +
|
||||
IGB_PTP_TX_TIMEOUT)) {
|
||||
dev_kfree_skb_any(adapter->ptp_tx_skb);
|
||||
adapter->ptp_tx_skb = NULL;
|
||||
clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
|
||||
adapter->tx_hwtstamp_timeouts++;
|
||||
dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tsynctxctl = rd32(E1000_TSYNCTXCTL);
|
||||
if (tsynctxctl & E1000_TSYNCTXCTL_VALID)
|
||||
igb_ptp_tx_hwtstamp(adapter);
|
||||
else
|
||||
/* reschedule to check later */
|
||||
schedule_work(&adapter->ptp_tx_work);
|
||||
}
|
||||
|
||||
static void igb_ptp_overflow_check(struct work_struct *work)
|
||||
{
|
||||
struct igb_adapter *igb =
|
||||
container_of(work, struct igb_adapter, ptp_overflow_work.work);
|
||||
struct timespec ts;
|
||||
|
||||
igb->ptp_caps.gettime(&igb->ptp_caps, &ts);
|
||||
|
||||
pr_debug("igb overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec);
|
||||
|
||||
schedule_delayed_work(&igb->ptp_overflow_work,
|
||||
IGB_SYSTIM_OVERFLOW_PERIOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_rx_hang - detect error case when Rx timestamp registers latched
|
||||
* @adapter: private network adapter structure
|
||||
*
|
||||
* This watchdog task is scheduled to detect error case where hardware has
|
||||
* dropped an Rx packet that was timestamped when the ring is full. The
|
||||
* particular error is rare but leaves the device in a state unable to timestamp
|
||||
* any future packets.
|
||||
**/
|
||||
void igb_ptp_rx_hang(struct igb_adapter *adapter)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
u32 tsyncrxctl = rd32(E1000_TSYNCRXCTL);
|
||||
unsigned long rx_event;
|
||||
|
||||
if (hw->mac.type != e1000_82576)
|
||||
return;
|
||||
|
||||
/* If we don't have a valid timestamp in the registers, just update the
|
||||
* timeout counter and exit
|
||||
*/
|
||||
if (!(tsyncrxctl & E1000_TSYNCRXCTL_VALID)) {
|
||||
adapter->last_rx_ptp_check = jiffies;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Determine the most recent watchdog or rx_timestamp event */
|
||||
rx_event = adapter->last_rx_ptp_check;
|
||||
if (time_after(adapter->last_rx_timestamp, rx_event))
|
||||
rx_event = adapter->last_rx_timestamp;
|
||||
|
||||
/* Only need to read the high RXSTMP register to clear the lock */
|
||||
if (time_is_before_jiffies(rx_event + 5 * HZ)) {
|
||||
rd32(E1000_RXSTMPH);
|
||||
adapter->last_rx_ptp_check = jiffies;
|
||||
adapter->rx_hwtstamp_cleared++;
|
||||
dev_warn(&adapter->pdev->dev, "clearing Rx timestamp hang\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp
|
||||
* @adapter: Board private structure.
|
||||
*
|
||||
* If we were asked to do hardware stamping and such a time stamp is
|
||||
* available, then it must have been for this skb here because we only
|
||||
* allow only one such packet into the queue.
|
||||
**/
|
||||
static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct skb_shared_hwtstamps shhwtstamps;
|
||||
u64 regval;
|
||||
|
||||
regval = rd32(E1000_TXSTMPL);
|
||||
regval |= (u64)rd32(E1000_TXSTMPH) << 32;
|
||||
|
||||
igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
|
||||
skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
|
||||
dev_kfree_skb_any(adapter->ptp_tx_skb);
|
||||
adapter->ptp_tx_skb = NULL;
|
||||
clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_rx_pktstamp - retrieve Rx per packet timestamp
|
||||
* @q_vector: Pointer to interrupt specific structure
|
||||
* @va: Pointer to address containing Rx buffer
|
||||
* @skb: Buffer containing timestamp and packet
|
||||
*
|
||||
* This function is meant to retrieve a timestamp from the first buffer of an
|
||||
* incoming frame. The value is stored in little endian format starting on
|
||||
* byte 8.
|
||||
**/
|
||||
void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector,
|
||||
unsigned char *va,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
__le64 *regval = (__le64 *)va;
|
||||
|
||||
/* The timestamp is recorded in little endian format.
|
||||
* DWORD: 0 1 2 3
|
||||
* Field: Reserved Reserved SYSTIML SYSTIMH
|
||||
*/
|
||||
igb_ptp_systim_to_hwtstamp(q_vector->adapter, skb_hwtstamps(skb),
|
||||
le64_to_cpu(regval[1]));
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_rx_rgtstamp - retrieve Rx timestamp stored in register
|
||||
* @q_vector: Pointer to interrupt specific structure
|
||||
* @skb: Buffer containing timestamp and packet
|
||||
*
|
||||
* This function is meant to retrieve a timestamp from the internal registers
|
||||
* of the adapter and store it in the skb.
|
||||
**/
|
||||
void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct igb_adapter *adapter = q_vector->adapter;
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
u64 regval;
|
||||
|
||||
/* If this bit is set, then the RX registers contain the time stamp. No
|
||||
* other packet will be time stamped until we read these registers, so
|
||||
* read the registers to make them available again. Because only one
|
||||
* packet can be time stamped at a time, we know that the register
|
||||
* values must belong to this one here and therefore we don't need to
|
||||
* compare any of the additional attributes stored for it.
|
||||
*
|
||||
* If nothing went wrong, then it should have a shared tx_flags that we
|
||||
* can turn into a skb_shared_hwtstamps.
|
||||
*/
|
||||
if (!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID))
|
||||
return;
|
||||
|
||||
regval = rd32(E1000_RXSTMPL);
|
||||
regval |= (u64)rd32(E1000_RXSTMPH) << 32;
|
||||
|
||||
igb_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
|
||||
|
||||
/* Update the last_rx_timestamp timer in order to enable watchdog check
|
||||
* for error case of latched timestamp on a dropped packet.
|
||||
*/
|
||||
adapter->last_rx_timestamp = jiffies;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_get_ts_config - get hardware time stamping config
|
||||
* @netdev:
|
||||
* @ifreq:
|
||||
*
|
||||
* Get the hwtstamp_config settings to return to the user. Rather than attempt
|
||||
* to deconstruct the settings from the registers, just return a shadow copy
|
||||
* of the last known settings.
|
||||
**/
|
||||
int igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr)
|
||||
{
|
||||
struct igb_adapter *adapter = netdev_priv(netdev);
|
||||
struct hwtstamp_config *config = &adapter->tstamp_config;
|
||||
|
||||
return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
|
||||
-EFAULT : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_set_timestamp_mode - setup hardware for timestamping
|
||||
* @adapter: networking device structure
|
||||
* @config: hwtstamp configuration
|
||||
*
|
||||
* Outgoing time stamping can be enabled and disabled. Play nice and
|
||||
* disable it when requested, although it shouldn't case any overhead
|
||||
* when no packet needs it. At most one packet in the queue may be
|
||||
* marked for time stamping, otherwise it would be impossible to tell
|
||||
* for sure to which packet the hardware time stamp belongs.
|
||||
*
|
||||
* Incoming time stamping has to be configured via the hardware
|
||||
* filters. Not all combinations are supported, in particular event
|
||||
* type has to be specified. Matching the kind of event packet is
|
||||
* not supported, with the exception of "all V2 events regardless of
|
||||
* level 2 or 4".
|
||||
*/
|
||||
static int igb_ptp_set_timestamp_mode(struct igb_adapter *adapter,
|
||||
struct hwtstamp_config *config)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
|
||||
u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
|
||||
u32 tsync_rx_cfg = 0;
|
||||
bool is_l4 = false;
|
||||
bool is_l2 = false;
|
||||
u32 regval;
|
||||
|
||||
/* reserved for future extensions */
|
||||
if (config->flags)
|
||||
return -EINVAL;
|
||||
|
||||
switch (config->tx_type) {
|
||||
case HWTSTAMP_TX_OFF:
|
||||
tsync_tx_ctl = 0;
|
||||
case HWTSTAMP_TX_ON:
|
||||
break;
|
||||
default:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
switch (config->rx_filter) {
|
||||
case HWTSTAMP_FILTER_NONE:
|
||||
tsync_rx_ctl = 0;
|
||||
break;
|
||||
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
|
||||
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
|
||||
tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE;
|
||||
is_l4 = true;
|
||||
break;
|
||||
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
|
||||
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
|
||||
tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE;
|
||||
is_l4 = true;
|
||||
break;
|
||||
case HWTSTAMP_FILTER_PTP_V2_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
|
||||
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
|
||||
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
|
||||
is_l2 = true;
|
||||
is_l4 = true;
|
||||
break;
|
||||
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
|
||||
case HWTSTAMP_FILTER_ALL:
|
||||
/* 82576 cannot timestamp all packets, which it needs to do to
|
||||
* support both V1 Sync and Delay_Req messages
|
||||
*/
|
||||
if (hw->mac.type != e1000_82576) {
|
||||
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
|
||||
config->rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
config->rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (hw->mac.type == e1000_82575) {
|
||||
if (tsync_rx_ctl | tsync_tx_ctl)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Per-packet timestamping only works if all packets are
|
||||
* timestamped, so enable timestamping in all packets as
|
||||
* long as one Rx filter was configured.
|
||||
*/
|
||||
if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) {
|
||||
tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
|
||||
tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
|
||||
config->rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
is_l2 = true;
|
||||
is_l4 = true;
|
||||
|
||||
if ((hw->mac.type == e1000_i210) ||
|
||||
(hw->mac.type == e1000_i211)) {
|
||||
regval = rd32(E1000_RXPBS);
|
||||
regval |= E1000_RXPBS_CFG_TS_EN;
|
||||
wr32(E1000_RXPBS, regval);
|
||||
}
|
||||
}
|
||||
|
||||
/* enable/disable TX */
|
||||
regval = rd32(E1000_TSYNCTXCTL);
|
||||
regval &= ~E1000_TSYNCTXCTL_ENABLED;
|
||||
regval |= tsync_tx_ctl;
|
||||
wr32(E1000_TSYNCTXCTL, regval);
|
||||
|
||||
/* enable/disable RX */
|
||||
regval = rd32(E1000_TSYNCRXCTL);
|
||||
regval &= ~(E1000_TSYNCRXCTL_ENABLED | E1000_TSYNCRXCTL_TYPE_MASK);
|
||||
regval |= tsync_rx_ctl;
|
||||
wr32(E1000_TSYNCRXCTL, regval);
|
||||
|
||||
/* define which PTP packets are time stamped */
|
||||
wr32(E1000_TSYNCRXCFG, tsync_rx_cfg);
|
||||
|
||||
/* define ethertype filter for timestamped packets */
|
||||
if (is_l2)
|
||||
wr32(E1000_ETQF(3),
|
||||
(E1000_ETQF_FILTER_ENABLE | /* enable filter */
|
||||
E1000_ETQF_1588 | /* enable timestamping */
|
||||
ETH_P_1588)); /* 1588 eth protocol type */
|
||||
else
|
||||
wr32(E1000_ETQF(3), 0);
|
||||
|
||||
/* L4 Queue Filter[3]: filter by destination port and protocol */
|
||||
if (is_l4) {
|
||||
u32 ftqf = (IPPROTO_UDP /* UDP */
|
||||
| E1000_FTQF_VF_BP /* VF not compared */
|
||||
| E1000_FTQF_1588_TIME_STAMP /* Enable Timestamping */
|
||||
| E1000_FTQF_MASK); /* mask all inputs */
|
||||
ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */
|
||||
|
||||
wr32(E1000_IMIR(3), htons(PTP_EV_PORT));
|
||||
wr32(E1000_IMIREXT(3),
|
||||
(E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP));
|
||||
if (hw->mac.type == e1000_82576) {
|
||||
/* enable source port check */
|
||||
wr32(E1000_SPQF(3), htons(PTP_EV_PORT));
|
||||
ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
|
||||
}
|
||||
wr32(E1000_FTQF(3), ftqf);
|
||||
} else {
|
||||
wr32(E1000_FTQF(3), E1000_FTQF_MASK);
|
||||
}
|
||||
wrfl();
|
||||
|
||||
/* clear TX/RX time stamp registers, just to be sure */
|
||||
regval = rd32(E1000_TXSTMPL);
|
||||
regval = rd32(E1000_TXSTMPH);
|
||||
regval = rd32(E1000_RXSTMPL);
|
||||
regval = rd32(E1000_RXSTMPH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_set_ts_config - set hardware time stamping config
|
||||
* @netdev:
|
||||
* @ifreq:
|
||||
*
|
||||
**/
|
||||
int igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr)
|
||||
{
|
||||
struct igb_adapter *adapter = netdev_priv(netdev);
|
||||
struct hwtstamp_config config;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
|
||||
return -EFAULT;
|
||||
|
||||
err = igb_ptp_set_timestamp_mode(adapter, &config);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* save these settings for future reference */
|
||||
memcpy(&adapter->tstamp_config, &config,
|
||||
sizeof(adapter->tstamp_config));
|
||||
|
||||
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
|
||||
-EFAULT : 0;
|
||||
}
|
||||
|
||||
void igb_ptp_init(struct igb_adapter *adapter)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
|
||||
switch (hw->mac.type) {
|
||||
case e1000_82576:
|
||||
snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
|
||||
adapter->ptp_caps.owner = THIS_MODULE;
|
||||
adapter->ptp_caps.max_adj = 999999881;
|
||||
adapter->ptp_caps.n_ext_ts = 0;
|
||||
adapter->ptp_caps.pps = 0;
|
||||
adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576;
|
||||
adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576;
|
||||
adapter->ptp_caps.gettime = igb_ptp_gettime_82576;
|
||||
adapter->ptp_caps.settime = igb_ptp_settime_82576;
|
||||
adapter->ptp_caps.enable = igb_ptp_feature_enable;
|
||||
adapter->cc.read = igb_ptp_read_82576;
|
||||
adapter->cc.mask = CLOCKSOURCE_MASK(64);
|
||||
adapter->cc.mult = 1;
|
||||
adapter->cc.shift = IGB_82576_TSYNC_SHIFT;
|
||||
/* Dial the nominal frequency. */
|
||||
wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576);
|
||||
break;
|
||||
case e1000_82580:
|
||||
case e1000_i354:
|
||||
case e1000_i350:
|
||||
snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
|
||||
adapter->ptp_caps.owner = THIS_MODULE;
|
||||
adapter->ptp_caps.max_adj = 62499999;
|
||||
adapter->ptp_caps.n_ext_ts = 0;
|
||||
adapter->ptp_caps.pps = 0;
|
||||
adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580;
|
||||
adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576;
|
||||
adapter->ptp_caps.gettime = igb_ptp_gettime_82576;
|
||||
adapter->ptp_caps.settime = igb_ptp_settime_82576;
|
||||
adapter->ptp_caps.enable = igb_ptp_feature_enable;
|
||||
adapter->cc.read = igb_ptp_read_82580;
|
||||
adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580);
|
||||
adapter->cc.mult = 1;
|
||||
adapter->cc.shift = 0;
|
||||
/* Enable the timer functions by clearing bit 31. */
|
||||
wr32(E1000_TSAUXC, 0x0);
|
||||
break;
|
||||
case e1000_i210:
|
||||
case e1000_i211:
|
||||
snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
|
||||
adapter->ptp_caps.owner = THIS_MODULE;
|
||||
adapter->ptp_caps.max_adj = 62499999;
|
||||
adapter->ptp_caps.n_ext_ts = 0;
|
||||
adapter->ptp_caps.pps = 0;
|
||||
adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580;
|
||||
adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210;
|
||||
adapter->ptp_caps.gettime = igb_ptp_gettime_i210;
|
||||
adapter->ptp_caps.settime = igb_ptp_settime_i210;
|
||||
adapter->ptp_caps.enable = igb_ptp_feature_enable;
|
||||
/* Enable the timer functions by clearing bit 31. */
|
||||
wr32(E1000_TSAUXC, 0x0);
|
||||
break;
|
||||
default:
|
||||
adapter->ptp_clock = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
wrfl();
|
||||
|
||||
spin_lock_init(&adapter->tmreg_lock);
|
||||
INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work);
|
||||
|
||||
/* Initialize the clock and overflow work for devices that need it. */
|
||||
if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) {
|
||||
struct timespec ts = ktime_to_timespec(ktime_get_real());
|
||||
|
||||
igb_ptp_settime_i210(&adapter->ptp_caps, &ts);
|
||||
} else {
|
||||
timecounter_init(&adapter->tc, &adapter->cc,
|
||||
ktime_to_ns(ktime_get_real()));
|
||||
|
||||
INIT_DELAYED_WORK(&adapter->ptp_overflow_work,
|
||||
igb_ptp_overflow_check);
|
||||
|
||||
schedule_delayed_work(&adapter->ptp_overflow_work,
|
||||
IGB_SYSTIM_OVERFLOW_PERIOD);
|
||||
}
|
||||
|
||||
/* Initialize the time sync interrupts for devices that support it. */
|
||||
if (hw->mac.type >= e1000_82580) {
|
||||
wr32(E1000_TSIM, TSYNC_INTERRUPTS);
|
||||
wr32(E1000_IMS, E1000_IMS_TS);
|
||||
}
|
||||
|
||||
adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
|
||||
|
||||
adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
|
||||
&adapter->pdev->dev);
|
||||
if (IS_ERR(adapter->ptp_clock)) {
|
||||
adapter->ptp_clock = NULL;
|
||||
dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n");
|
||||
} else {
|
||||
dev_info(&adapter->pdev->dev, "added PHC on %s\n",
|
||||
adapter->netdev->name);
|
||||
adapter->flags |= IGB_FLAG_PTP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_stop - Disable PTP device and stop the overflow check.
|
||||
* @adapter: Board private structure.
|
||||
*
|
||||
* This function stops the PTP support and cancels the delayed work.
|
||||
**/
|
||||
void igb_ptp_stop(struct igb_adapter *adapter)
|
||||
{
|
||||
switch (adapter->hw.mac.type) {
|
||||
case e1000_82576:
|
||||
case e1000_82580:
|
||||
case e1000_i354:
|
||||
case e1000_i350:
|
||||
cancel_delayed_work_sync(&adapter->ptp_overflow_work);
|
||||
break;
|
||||
case e1000_i210:
|
||||
case e1000_i211:
|
||||
/* No delayed work to cancel. */
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
cancel_work_sync(&adapter->ptp_tx_work);
|
||||
if (adapter->ptp_tx_skb) {
|
||||
dev_kfree_skb_any(adapter->ptp_tx_skb);
|
||||
adapter->ptp_tx_skb = NULL;
|
||||
clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
|
||||
}
|
||||
|
||||
if (adapter->ptp_clock) {
|
||||
ptp_clock_unregister(adapter->ptp_clock);
|
||||
dev_info(&adapter->pdev->dev, "removed PHC on %s\n",
|
||||
adapter->netdev->name);
|
||||
adapter->flags &= ~IGB_FLAG_PTP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_reset - Re-enable the adapter for PTP following a reset.
|
||||
* @adapter: Board private structure.
|
||||
*
|
||||
* This function handles the reset work required to re-enable the PTP device.
|
||||
**/
|
||||
void igb_ptp_reset(struct igb_adapter *adapter)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
|
||||
if (!(adapter->flags & IGB_FLAG_PTP))
|
||||
return;
|
||||
|
||||
/* reset the tstamp_config */
|
||||
igb_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config);
|
||||
|
||||
switch (adapter->hw.mac.type) {
|
||||
case e1000_82576:
|
||||
/* Dial the nominal frequency. */
|
||||
wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576);
|
||||
break;
|
||||
case e1000_82580:
|
||||
case e1000_i354:
|
||||
case e1000_i350:
|
||||
case e1000_i210:
|
||||
case e1000_i211:
|
||||
/* Enable the timer functions and interrupts. */
|
||||
wr32(E1000_TSAUXC, 0x0);
|
||||
wr32(E1000_TSIM, TSYNC_INTERRUPTS);
|
||||
wr32(E1000_IMS, E1000_IMS_TS);
|
||||
break;
|
||||
default:
|
||||
/* No work to do. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Re-initialize the timer. */
|
||||
if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) {
|
||||
struct timespec ts = ktime_to_timespec(ktime_get_real());
|
||||
|
||||
igb_ptp_settime_i210(&adapter->ptp_caps, &ts);
|
||||
} else {
|
||||
timecounter_init(&adapter->tc, &adapter->cc,
|
||||
ktime_to_ns(ktime_get_real()));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue