mirror of
				https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
				synced 2025-10-31 16:18:51 +01: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
	
	 awab228
						awab228