162306a36Sopenharmony_ci/* Agere Systems Inc. 262306a36Sopenharmony_ci * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright © 2005 Agere Systems Inc. 562306a36Sopenharmony_ci * All rights reserved. 662306a36Sopenharmony_ci * http://www.agere.com 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (c) 2011 Mark Einon <mark.einon@gmail.com> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci *------------------------------------------------------------------------------ 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * SOFTWARE LICENSE 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This software is provided subject to the following terms and conditions, 1562306a36Sopenharmony_ci * which you should read carefully before using the software. Using this 1662306a36Sopenharmony_ci * software indicates your acceptance of these terms and conditions. If you do 1762306a36Sopenharmony_ci * not agree with these terms and conditions, do not use the software. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Copyright © 2005 Agere Systems Inc. 2062306a36Sopenharmony_ci * All rights reserved. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Redistribution and use in source or binary forms, with or without 2362306a36Sopenharmony_ci * modifications, are permitted provided that the following conditions are met: 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * . Redistributions of source code must retain the above copyright notice, this 2662306a36Sopenharmony_ci * list of conditions and the following Disclaimer as comments in the code as 2762306a36Sopenharmony_ci * well as in the documentation and/or other materials provided with the 2862306a36Sopenharmony_ci * distribution. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * . Redistributions in binary form must reproduce the above copyright notice, 3162306a36Sopenharmony_ci * this list of conditions and the following Disclaimer in the documentation 3262306a36Sopenharmony_ci * and/or other materials provided with the distribution. 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * . Neither the name of Agere Systems Inc. nor the names of the contributors 3562306a36Sopenharmony_ci * may be used to endorse or promote products derived from this software 3662306a36Sopenharmony_ci * without specific prior written permission. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * Disclaimer 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 4162306a36Sopenharmony_ci * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF 4262306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY 4362306a36Sopenharmony_ci * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN 4462306a36Sopenharmony_ci * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY 4562306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 4662306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 4762306a36Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 4862306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT 4962306a36Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 5062306a36Sopenharmony_ci * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 5162306a36Sopenharmony_ci * DAMAGE. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#include <linux/pci.h> 5762306a36Sopenharmony_ci#include <linux/module.h> 5862306a36Sopenharmony_ci#include <linux/types.h> 5962306a36Sopenharmony_ci#include <linux/kernel.h> 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#include <linux/sched.h> 6262306a36Sopenharmony_ci#include <linux/ptrace.h> 6362306a36Sopenharmony_ci#include <linux/slab.h> 6462306a36Sopenharmony_ci#include <linux/ctype.h> 6562306a36Sopenharmony_ci#include <linux/string.h> 6662306a36Sopenharmony_ci#include <linux/timer.h> 6762306a36Sopenharmony_ci#include <linux/interrupt.h> 6862306a36Sopenharmony_ci#include <linux/in.h> 6962306a36Sopenharmony_ci#include <linux/delay.h> 7062306a36Sopenharmony_ci#include <linux/bitops.h> 7162306a36Sopenharmony_ci#include <linux/io.h> 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#include <linux/netdevice.h> 7462306a36Sopenharmony_ci#include <linux/etherdevice.h> 7562306a36Sopenharmony_ci#include <linux/skbuff.h> 7662306a36Sopenharmony_ci#include <linux/if_arp.h> 7762306a36Sopenharmony_ci#include <linux/ioport.h> 7862306a36Sopenharmony_ci#include <linux/crc32.h> 7962306a36Sopenharmony_ci#include <linux/random.h> 8062306a36Sopenharmony_ci#include <linux/phy.h> 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#include "et131x.h" 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciMODULE_AUTHOR("Victor Soriano <vjsoriano@agere.com>"); 8562306a36Sopenharmony_ciMODULE_AUTHOR("Mark Einon <mark.einon@gmail.com>"); 8662306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 8762306a36Sopenharmony_ciMODULE_DESCRIPTION("10/100/1000 Base-T Ethernet Driver for the ET1310 by Agere Systems"); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* EEPROM defines */ 9062306a36Sopenharmony_ci#define MAX_NUM_REGISTER_POLLS 1000 9162306a36Sopenharmony_ci#define MAX_NUM_WRITE_RETRIES 2 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* MAC defines */ 9462306a36Sopenharmony_ci#define COUNTER_WRAP_16_BIT 0x10000 9562306a36Sopenharmony_ci#define COUNTER_WRAP_12_BIT 0x1000 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* PCI defines */ 9862306a36Sopenharmony_ci#define INTERNAL_MEM_SIZE 0x400 /* 1024 of internal memory */ 9962306a36Sopenharmony_ci#define INTERNAL_MEM_RX_OFFSET 0x1FF /* 50% Tx, 50% Rx */ 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* ISR defines */ 10262306a36Sopenharmony_ci/* For interrupts, normal running is: 10362306a36Sopenharmony_ci * rxdma_xfr_done, phy_interrupt, mac_stat_interrupt, 10462306a36Sopenharmony_ci * watchdog_interrupt & txdma_xfer_done 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * In both cases, when flow control is enabled for either Tx or bi-direction, 10762306a36Sopenharmony_ci * we additional enable rx_fbr0_low and rx_fbr1_low, so we know when the 10862306a36Sopenharmony_ci * buffer rings are running low. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ci#define INT_MASK_DISABLE 0xffffffff 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* NOTE: Masking out MAC_STAT Interrupt for now... 11362306a36Sopenharmony_ci * #define INT_MASK_ENABLE 0xfff6bf17 11462306a36Sopenharmony_ci * #define INT_MASK_ENABLE_NO_FLOW 0xfff6bfd7 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci#define INT_MASK_ENABLE 0xfffebf17 11762306a36Sopenharmony_ci#define INT_MASK_ENABLE_NO_FLOW 0xfffebfd7 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/* General defines */ 12062306a36Sopenharmony_ci/* Packet and header sizes */ 12162306a36Sopenharmony_ci#define NIC_MIN_PACKET_SIZE 60 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* Multicast list size */ 12462306a36Sopenharmony_ci#define NIC_MAX_MCAST_LIST 128 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* Supported Filters */ 12762306a36Sopenharmony_ci#define ET131X_PACKET_TYPE_DIRECTED 0x0001 12862306a36Sopenharmony_ci#define ET131X_PACKET_TYPE_MULTICAST 0x0002 12962306a36Sopenharmony_ci#define ET131X_PACKET_TYPE_BROADCAST 0x0004 13062306a36Sopenharmony_ci#define ET131X_PACKET_TYPE_PROMISCUOUS 0x0008 13162306a36Sopenharmony_ci#define ET131X_PACKET_TYPE_ALL_MULTICAST 0x0010 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* Tx Timeout */ 13462306a36Sopenharmony_ci#define ET131X_TX_TIMEOUT (1 * HZ) 13562306a36Sopenharmony_ci#define NIC_SEND_HANG_THRESHOLD 0 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* MP_ADAPTER flags */ 13862306a36Sopenharmony_ci#define FMP_ADAPTER_INTERRUPT_IN_USE 0x00000008 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* MP_SHARED flags */ 14162306a36Sopenharmony_ci#define FMP_ADAPTER_LOWER_POWER 0x00200000 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#define FMP_ADAPTER_NON_RECOVER_ERROR 0x00800000 14462306a36Sopenharmony_ci#define FMP_ADAPTER_HARDWARE_ERROR 0x04000000 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci#define FMP_ADAPTER_FAIL_SEND_MASK 0x3ff00000 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* Some offsets in PCI config space that are actually used. */ 14962306a36Sopenharmony_ci#define ET1310_PCI_MAC_ADDRESS 0xA4 15062306a36Sopenharmony_ci#define ET1310_PCI_EEPROM_STATUS 0xB2 15162306a36Sopenharmony_ci#define ET1310_PCI_ACK_NACK 0xC0 15262306a36Sopenharmony_ci#define ET1310_PCI_REPLAY 0xC2 15362306a36Sopenharmony_ci#define ET1310_PCI_L0L1LATENCY 0xCF 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* PCI Product IDs */ 15662306a36Sopenharmony_ci#define ET131X_PCI_DEVICE_ID_GIG 0xED00 /* ET1310 1000 Base-T 8 */ 15762306a36Sopenharmony_ci#define ET131X_PCI_DEVICE_ID_FAST 0xED01 /* ET1310 100 Base-T */ 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* Define order of magnitude converter */ 16062306a36Sopenharmony_ci#define NANO_IN_A_MICRO 1000 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci#define PARM_RX_NUM_BUFS_DEF 4 16362306a36Sopenharmony_ci#define PARM_RX_TIME_INT_DEF 10 16462306a36Sopenharmony_ci#define PARM_RX_MEM_END_DEF 0x2bc 16562306a36Sopenharmony_ci#define PARM_TX_TIME_INT_DEF 40 16662306a36Sopenharmony_ci#define PARM_TX_NUM_BUFS_DEF 4 16762306a36Sopenharmony_ci#define PARM_DMA_CACHE_DEF 0 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* RX defines */ 17062306a36Sopenharmony_ci#define FBR_CHUNKS 32 17162306a36Sopenharmony_ci#define MAX_DESC_PER_RING_RX 1024 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* number of RFDs - default and min */ 17462306a36Sopenharmony_ci#define RFD_LOW_WATER_MARK 40 17562306a36Sopenharmony_ci#define NIC_DEFAULT_NUM_RFD 1024 17662306a36Sopenharmony_ci#define NUM_FBRS 2 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci#define MAX_PACKETS_HANDLED 256 17962306a36Sopenharmony_ci#define ET131X_MIN_MTU 64 18062306a36Sopenharmony_ci#define ET131X_MAX_MTU 9216 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci#define ALCATEL_MULTICAST_PKT 0x01000000 18362306a36Sopenharmony_ci#define ALCATEL_BROADCAST_PKT 0x02000000 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/* typedefs for Free Buffer Descriptors */ 18662306a36Sopenharmony_cistruct fbr_desc { 18762306a36Sopenharmony_ci u32 addr_lo; 18862306a36Sopenharmony_ci u32 addr_hi; 18962306a36Sopenharmony_ci u32 word2; /* Bits 10-31 reserved, 0-9 descriptor */ 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/* Packet Status Ring Descriptors 19362306a36Sopenharmony_ci * 19462306a36Sopenharmony_ci * Word 0: 19562306a36Sopenharmony_ci * 19662306a36Sopenharmony_ci * top 16 bits are from the Alcatel Status Word as enumerated in 19762306a36Sopenharmony_ci * PE-MCXMAC Data Sheet IPD DS54 0210-1 (also IPD-DS80 0205-2) 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * 0: hp hash pass 20062306a36Sopenharmony_ci * 1: ipa IP checksum assist 20162306a36Sopenharmony_ci * 2: ipp IP checksum pass 20262306a36Sopenharmony_ci * 3: tcpa TCP checksum assist 20362306a36Sopenharmony_ci * 4: tcpp TCP checksum pass 20462306a36Sopenharmony_ci * 5: wol WOL Event 20562306a36Sopenharmony_ci * 6: rxmac_error RXMAC Error Indicator 20662306a36Sopenharmony_ci * 7: drop Drop packet 20762306a36Sopenharmony_ci * 8: ft Frame Truncated 20862306a36Sopenharmony_ci * 9: jp Jumbo Packet 20962306a36Sopenharmony_ci * 10: vp VLAN Packet 21062306a36Sopenharmony_ci * 11-15: unused 21162306a36Sopenharmony_ci * 16: asw_prev_pkt_dropped e.g. IFG too small on previous 21262306a36Sopenharmony_ci * 17: asw_RX_DV_event short receive event detected 21362306a36Sopenharmony_ci * 18: asw_false_carrier_event bad carrier since last good packet 21462306a36Sopenharmony_ci * 19: asw_code_err one or more nibbles signalled as errors 21562306a36Sopenharmony_ci * 20: asw_CRC_err CRC error 21662306a36Sopenharmony_ci * 21: asw_len_chk_err frame length field incorrect 21762306a36Sopenharmony_ci * 22: asw_too_long frame length > 1518 bytes 21862306a36Sopenharmony_ci * 23: asw_OK valid CRC + no code error 21962306a36Sopenharmony_ci * 24: asw_multicast has a multicast address 22062306a36Sopenharmony_ci * 25: asw_broadcast has a broadcast address 22162306a36Sopenharmony_ci * 26: asw_dribble_nibble spurious bits after EOP 22262306a36Sopenharmony_ci * 27: asw_control_frame is a control frame 22362306a36Sopenharmony_ci * 28: asw_pause_frame is a pause frame 22462306a36Sopenharmony_ci * 29: asw_unsupported_op unsupported OP code 22562306a36Sopenharmony_ci * 30: asw_VLAN_tag VLAN tag detected 22662306a36Sopenharmony_ci * 31: asw_long_evt Rx long event 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * Word 1: 22962306a36Sopenharmony_ci * 0-15: length length in bytes 23062306a36Sopenharmony_ci * 16-25: bi Buffer Index 23162306a36Sopenharmony_ci * 26-27: ri Ring Index 23262306a36Sopenharmony_ci * 28-31: reserved 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_cistruct pkt_stat_desc { 23562306a36Sopenharmony_ci u32 word0; 23662306a36Sopenharmony_ci u32 word1; 23762306a36Sopenharmony_ci}; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/* Typedefs for the RX DMA status word */ 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* rx status word 0 holds part of the status bits of the Rx DMA engine 24262306a36Sopenharmony_ci * that get copied out to memory by the ET-1310. Word 0 is a 32 bit word 24362306a36Sopenharmony_ci * which contains the Free Buffer ring 0 and 1 available offset. 24462306a36Sopenharmony_ci * 24562306a36Sopenharmony_ci * bit 0-9 FBR1 offset 24662306a36Sopenharmony_ci * bit 10 Wrap flag for FBR1 24762306a36Sopenharmony_ci * bit 16-25 FBR0 offset 24862306a36Sopenharmony_ci * bit 26 Wrap flag for FBR0 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/* RXSTAT_WORD1_t structure holds part of the status bits of the Rx DMA engine 25262306a36Sopenharmony_ci * that get copied out to memory by the ET-1310. Word 3 is a 32 bit word 25362306a36Sopenharmony_ci * which contains the Packet Status Ring available offset. 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * bit 0-15 reserved 25662306a36Sopenharmony_ci * bit 16-27 PSRoffset 25762306a36Sopenharmony_ci * bit 28 PSRwrap 25862306a36Sopenharmony_ci * bit 29-31 unused 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* struct rx_status_block is a structure representing the status of the Rx 26262306a36Sopenharmony_ci * DMA engine it sits in free memory, and is pointed to by 0x101c / 0x1020 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_cistruct rx_status_block { 26562306a36Sopenharmony_ci u32 word0; 26662306a36Sopenharmony_ci u32 word1; 26762306a36Sopenharmony_ci}; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/* Structure for look-up table holding free buffer ring pointers, addresses 27062306a36Sopenharmony_ci * and state. 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_cistruct fbr_lookup { 27362306a36Sopenharmony_ci void *virt[MAX_DESC_PER_RING_RX]; 27462306a36Sopenharmony_ci u32 bus_high[MAX_DESC_PER_RING_RX]; 27562306a36Sopenharmony_ci u32 bus_low[MAX_DESC_PER_RING_RX]; 27662306a36Sopenharmony_ci void *ring_virtaddr; 27762306a36Sopenharmony_ci dma_addr_t ring_physaddr; 27862306a36Sopenharmony_ci void *mem_virtaddrs[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; 27962306a36Sopenharmony_ci dma_addr_t mem_physaddrs[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; 28062306a36Sopenharmony_ci u32 local_full; 28162306a36Sopenharmony_ci u32 num_entries; 28262306a36Sopenharmony_ci dma_addr_t buffsize; 28362306a36Sopenharmony_ci}; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci/* struct rx_ring is the structure representing the adaptor's local 28662306a36Sopenharmony_ci * reference(s) to the rings 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_cistruct rx_ring { 28962306a36Sopenharmony_ci struct fbr_lookup *fbr[NUM_FBRS]; 29062306a36Sopenharmony_ci void *ps_ring_virtaddr; 29162306a36Sopenharmony_ci dma_addr_t ps_ring_physaddr; 29262306a36Sopenharmony_ci u32 local_psr_full; 29362306a36Sopenharmony_ci u32 psr_entries; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci struct rx_status_block *rx_status_block; 29662306a36Sopenharmony_ci dma_addr_t rx_status_bus; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci struct list_head recv_list; 29962306a36Sopenharmony_ci u32 num_ready_recv; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci u32 num_rfd; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci bool unfinished_receives; 30462306a36Sopenharmony_ci}; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/* TX defines */ 30762306a36Sopenharmony_ci/* word 2 of the control bits in the Tx Descriptor ring for the ET-1310 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * 0-15: length of packet 31062306a36Sopenharmony_ci * 16-27: VLAN tag 31162306a36Sopenharmony_ci * 28: VLAN CFI 31262306a36Sopenharmony_ci * 29-31: VLAN priority 31362306a36Sopenharmony_ci * 31462306a36Sopenharmony_ci * word 3 of the control bits in the Tx Descriptor ring for the ET-1310 31562306a36Sopenharmony_ci * 31662306a36Sopenharmony_ci * 0: last packet in the sequence 31762306a36Sopenharmony_ci * 1: first packet in the sequence 31862306a36Sopenharmony_ci * 2: interrupt the processor when this pkt sent 31962306a36Sopenharmony_ci * 3: Control word - no packet data 32062306a36Sopenharmony_ci * 4: Issue half-duplex backpressure : XON/XOFF 32162306a36Sopenharmony_ci * 5: send pause frame 32262306a36Sopenharmony_ci * 6: Tx frame has error 32362306a36Sopenharmony_ci * 7: append CRC 32462306a36Sopenharmony_ci * 8: MAC override 32562306a36Sopenharmony_ci * 9: pad packet 32662306a36Sopenharmony_ci * 10: Packet is a Huge packet 32762306a36Sopenharmony_ci * 11: append VLAN tag 32862306a36Sopenharmony_ci * 12: IP checksum assist 32962306a36Sopenharmony_ci * 13: TCP checksum assist 33062306a36Sopenharmony_ci * 14: UDP checksum assist 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ci#define TXDESC_FLAG_LASTPKT 0x0001 33362306a36Sopenharmony_ci#define TXDESC_FLAG_FIRSTPKT 0x0002 33462306a36Sopenharmony_ci#define TXDESC_FLAG_INTPROC 0x0004 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/* struct tx_desc represents each descriptor on the ring */ 33762306a36Sopenharmony_cistruct tx_desc { 33862306a36Sopenharmony_ci u32 addr_hi; 33962306a36Sopenharmony_ci u32 addr_lo; 34062306a36Sopenharmony_ci u32 len_vlan; /* control words how to xmit the */ 34162306a36Sopenharmony_ci u32 flags; /* data (detailed above) */ 34262306a36Sopenharmony_ci}; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci/* The status of the Tx DMA engine it sits in free memory, and is pointed to 34562306a36Sopenharmony_ci * by 0x101c / 0x1020. This is a DMA10 type 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/* TCB (Transmit Control Block: Host Side) */ 34962306a36Sopenharmony_cistruct tcb { 35062306a36Sopenharmony_ci struct tcb *next; /* Next entry in ring */ 35162306a36Sopenharmony_ci u32 count; /* Used to spot stuck/lost packets */ 35262306a36Sopenharmony_ci u32 stale; /* Used to spot stuck/lost packets */ 35362306a36Sopenharmony_ci struct sk_buff *skb; /* Network skb we are tied to */ 35462306a36Sopenharmony_ci u32 index; /* Ring indexes */ 35562306a36Sopenharmony_ci u32 index_start; 35662306a36Sopenharmony_ci}; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci/* Structure representing our local reference(s) to the ring */ 35962306a36Sopenharmony_cistruct tx_ring { 36062306a36Sopenharmony_ci /* TCB (Transmit Control Block) memory and lists */ 36162306a36Sopenharmony_ci struct tcb *tcb_ring; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* List of TCBs that are ready to be used */ 36462306a36Sopenharmony_ci struct tcb *tcb_qhead; 36562306a36Sopenharmony_ci struct tcb *tcb_qtail; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* list of TCBs that are currently being sent. */ 36862306a36Sopenharmony_ci struct tcb *send_head; 36962306a36Sopenharmony_ci struct tcb *send_tail; 37062306a36Sopenharmony_ci int used; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* The actual descriptor ring */ 37362306a36Sopenharmony_ci struct tx_desc *tx_desc_ring; 37462306a36Sopenharmony_ci dma_addr_t tx_desc_ring_pa; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* send_idx indicates where we last wrote to in the descriptor ring. */ 37762306a36Sopenharmony_ci u32 send_idx; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* The location of the write-back status block */ 38062306a36Sopenharmony_ci u32 *tx_status; 38162306a36Sopenharmony_ci dma_addr_t tx_status_pa; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Packets since the last IRQ: used for interrupt coalescing */ 38462306a36Sopenharmony_ci int since_irq; 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci/* Do not change these values: if changed, then change also in respective 38862306a36Sopenharmony_ci * TXdma and Rxdma engines 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci#define NUM_DESC_PER_RING_TX 512 /* TX Do not change these values */ 39162306a36Sopenharmony_ci#define NUM_TCB 64 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci/* These values are all superseded by registry entries to facilitate tuning. 39462306a36Sopenharmony_ci * Once the desired performance has been achieved, the optimal registry values 39562306a36Sopenharmony_ci * should be re-populated to these #defines: 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_ci#define TX_ERROR_PERIOD 1000 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci#define LO_MARK_PERCENT_FOR_PSR 15 40062306a36Sopenharmony_ci#define LO_MARK_PERCENT_FOR_RX 15 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/* RFD (Receive Frame Descriptor) */ 40362306a36Sopenharmony_cistruct rfd { 40462306a36Sopenharmony_ci struct list_head list_node; 40562306a36Sopenharmony_ci struct sk_buff *skb; 40662306a36Sopenharmony_ci u32 len; /* total size of receive frame */ 40762306a36Sopenharmony_ci u16 bufferindex; 40862306a36Sopenharmony_ci u8 ringindex; 40962306a36Sopenharmony_ci}; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci/* Flow Control */ 41262306a36Sopenharmony_ci#define FLOW_BOTH 0 41362306a36Sopenharmony_ci#define FLOW_TXONLY 1 41462306a36Sopenharmony_ci#define FLOW_RXONLY 2 41562306a36Sopenharmony_ci#define FLOW_NONE 3 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* Struct to define some device statistics */ 41862306a36Sopenharmony_cistruct ce_stats { 41962306a36Sopenharmony_ci u32 multicast_pkts_rcvd; 42062306a36Sopenharmony_ci u32 rcvd_pkts_dropped; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci u32 tx_underflows; 42362306a36Sopenharmony_ci u32 tx_collisions; 42462306a36Sopenharmony_ci u32 tx_excessive_collisions; 42562306a36Sopenharmony_ci u32 tx_first_collisions; 42662306a36Sopenharmony_ci u32 tx_late_collisions; 42762306a36Sopenharmony_ci u32 tx_max_pkt_errs; 42862306a36Sopenharmony_ci u32 tx_deferred; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci u32 rx_overflows; 43162306a36Sopenharmony_ci u32 rx_length_errs; 43262306a36Sopenharmony_ci u32 rx_align_errs; 43362306a36Sopenharmony_ci u32 rx_crc_errs; 43462306a36Sopenharmony_ci u32 rx_code_violations; 43562306a36Sopenharmony_ci u32 rx_other_errs; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci u32 interrupt_status; 43862306a36Sopenharmony_ci}; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci/* The private adapter structure */ 44162306a36Sopenharmony_cistruct et131x_adapter { 44262306a36Sopenharmony_ci struct net_device *netdev; 44362306a36Sopenharmony_ci struct pci_dev *pdev; 44462306a36Sopenharmony_ci struct mii_bus *mii_bus; 44562306a36Sopenharmony_ci struct napi_struct napi; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* Flags that indicate current state of the adapter */ 44862306a36Sopenharmony_ci u32 flags; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* local link state, to determine if a state change has occurred */ 45162306a36Sopenharmony_ci int link; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* Configuration */ 45462306a36Sopenharmony_ci u8 rom_addr[ETH_ALEN]; 45562306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 45662306a36Sopenharmony_ci bool has_eeprom; 45762306a36Sopenharmony_ci u8 eeprom_data[2]; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci spinlock_t tcb_send_qlock; /* protects the tx_ring send tcb list */ 46062306a36Sopenharmony_ci spinlock_t tcb_ready_qlock; /* protects the tx_ring ready tcb list */ 46162306a36Sopenharmony_ci spinlock_t rcv_lock; /* protects the rx_ring receive list */ 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Packet Filter and look ahead size */ 46462306a36Sopenharmony_ci u32 packet_filter; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* multicast list */ 46762306a36Sopenharmony_ci u32 multicast_addr_count; 46862306a36Sopenharmony_ci u8 multicast_list[NIC_MAX_MCAST_LIST][ETH_ALEN]; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* Pointer to the device's PCI register space */ 47162306a36Sopenharmony_ci struct address_map __iomem *regs; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* Registry parameters */ 47462306a36Sopenharmony_ci u8 wanted_flow; /* Flow we want for 802.3x flow control */ 47562306a36Sopenharmony_ci u32 registry_jumbo_packet; /* Max supported ethernet packet size */ 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* Derived from the registry: */ 47862306a36Sopenharmony_ci u8 flow; /* flow control validated by the far-end */ 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* Minimize init-time */ 48162306a36Sopenharmony_ci struct timer_list error_timer; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* variable putting the phy into coma mode when boot up with no cable 48462306a36Sopenharmony_ci * plugged in after 5 seconds 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci u8 boot_coma; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Tx Memory Variables */ 48962306a36Sopenharmony_ci struct tx_ring tx_ring; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* Rx Memory Variables */ 49262306a36Sopenharmony_ci struct rx_ring rx_ring; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci struct ce_stats stats; 49562306a36Sopenharmony_ci}; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic int eeprom_wait_ready(struct pci_dev *pdev, u32 *status) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci u32 reg; 50062306a36Sopenharmony_ci int i; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* 1. Check LBCIF Status Register for bits 6 & 3:2 all equal to 0 and 50362306a36Sopenharmony_ci * bits 7,1:0 both equal to 1, at least once after reset. 50462306a36Sopenharmony_ci * Subsequent operations need only to check that bits 1:0 are equal 50562306a36Sopenharmony_ci * to 1 prior to starting a single byte read/write 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_ci for (i = 0; i < MAX_NUM_REGISTER_POLLS; i++) { 50862306a36Sopenharmony_ci if (pci_read_config_dword(pdev, LBCIF_DWORD1_GROUP, ®)) 50962306a36Sopenharmony_ci return -EIO; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* I2C idle and Phy Queue Avail both true */ 51262306a36Sopenharmony_ci if ((reg & 0x3000) == 0x3000) { 51362306a36Sopenharmony_ci if (status) 51462306a36Sopenharmony_ci *status = reg; 51562306a36Sopenharmony_ci return reg & 0xFF; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci return -ETIMEDOUT; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic int eeprom_write(struct et131x_adapter *adapter, u32 addr, u8 data) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 52462306a36Sopenharmony_ci int index = 0; 52562306a36Sopenharmony_ci int retries; 52662306a36Sopenharmony_ci int err = 0; 52762306a36Sopenharmony_ci int writeok = 0; 52862306a36Sopenharmony_ci u32 status; 52962306a36Sopenharmony_ci u32 val = 0; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* For an EEPROM, an I2C single byte write is defined as a START 53262306a36Sopenharmony_ci * condition followed by the device address, EEPROM address, one byte 53362306a36Sopenharmony_ci * of data and a STOP condition. The STOP condition will trigger the 53462306a36Sopenharmony_ci * EEPROM's internally timed write cycle to the nonvolatile memory. 53562306a36Sopenharmony_ci * All inputs are disabled during this write cycle and the EEPROM will 53662306a36Sopenharmony_ci * not respond to any access until the internal write is complete. 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_ci err = eeprom_wait_ready(pdev, NULL); 53962306a36Sopenharmony_ci if (err < 0) 54062306a36Sopenharmony_ci return err; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* 2. Write to the LBCIF Control Register: bit 7=1, bit 6=1, bit 3=0, 54362306a36Sopenharmony_ci * and bits 1:0 both =0. Bit 5 should be set according to the 54462306a36Sopenharmony_ci * type of EEPROM being accessed (1=two byte addressing, 0=one 54562306a36Sopenharmony_ci * byte addressing). 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_ci if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER, 54862306a36Sopenharmony_ci LBCIF_CONTROL_LBCIF_ENABLE | 54962306a36Sopenharmony_ci LBCIF_CONTROL_I2C_WRITE)) 55062306a36Sopenharmony_ci return -EIO; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* Prepare EEPROM address for Step 3 */ 55362306a36Sopenharmony_ci for (retries = 0; retries < MAX_NUM_WRITE_RETRIES; retries++) { 55462306a36Sopenharmony_ci if (pci_write_config_dword(pdev, LBCIF_ADDRESS_REGISTER, addr)) 55562306a36Sopenharmony_ci break; 55662306a36Sopenharmony_ci /* Write the data to the LBCIF Data Register (the I2C write 55762306a36Sopenharmony_ci * will begin). 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ci if (pci_write_config_byte(pdev, LBCIF_DATA_REGISTER, data)) 56062306a36Sopenharmony_ci break; 56162306a36Sopenharmony_ci /* Monitor bit 1:0 of the LBCIF Status Register. When bits 56262306a36Sopenharmony_ci * 1:0 are both equal to 1, the I2C write has completed and the 56362306a36Sopenharmony_ci * internal write cycle of the EEPROM is about to start. 56462306a36Sopenharmony_ci * (bits 1:0 = 01 is a legal state while waiting from both 56562306a36Sopenharmony_ci * equal to 1, but bits 1:0 = 10 is invalid and implies that 56662306a36Sopenharmony_ci * something is broken). 56762306a36Sopenharmony_ci */ 56862306a36Sopenharmony_ci err = eeprom_wait_ready(pdev, &status); 56962306a36Sopenharmony_ci if (err < 0) 57062306a36Sopenharmony_ci return 0; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Check bit 3 of the LBCIF Status Register. If equal to 1, 57362306a36Sopenharmony_ci * an error has occurred.Don't break here if we are revision 57462306a36Sopenharmony_ci * 1, this is so we do a blind write for load bug. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_ci if ((status & LBCIF_STATUS_GENERAL_ERROR) && 57762306a36Sopenharmony_ci adapter->pdev->revision == 0) 57862306a36Sopenharmony_ci break; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* Check bit 2 of the LBCIF Status Register. If equal to 1 an 58162306a36Sopenharmony_ci * ACK error has occurred on the address phase of the write. 58262306a36Sopenharmony_ci * This could be due to an actual hardware failure or the 58362306a36Sopenharmony_ci * EEPROM may still be in its internal write cycle from a 58462306a36Sopenharmony_ci * previous write. This write operation was ignored and must be 58562306a36Sopenharmony_ci *repeated later. 58662306a36Sopenharmony_ci */ 58762306a36Sopenharmony_ci if (status & LBCIF_STATUS_ACK_ERROR) { 58862306a36Sopenharmony_ci /* This could be due to an actual hardware failure 58962306a36Sopenharmony_ci * or the EEPROM may still be in its internal write 59062306a36Sopenharmony_ci * cycle from a previous write. This write operation 59162306a36Sopenharmony_ci * was ignored and must be repeated later. 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_ci udelay(10); 59462306a36Sopenharmony_ci continue; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci writeok = 1; 59862306a36Sopenharmony_ci break; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci udelay(10); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci while (1) { 60462306a36Sopenharmony_ci if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER, 60562306a36Sopenharmony_ci LBCIF_CONTROL_LBCIF_ENABLE)) 60662306a36Sopenharmony_ci writeok = 0; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* Do read until internal ACK_ERROR goes away meaning write 60962306a36Sopenharmony_ci * completed 61062306a36Sopenharmony_ci */ 61162306a36Sopenharmony_ci do { 61262306a36Sopenharmony_ci pci_write_config_dword(pdev, 61362306a36Sopenharmony_ci LBCIF_ADDRESS_REGISTER, 61462306a36Sopenharmony_ci addr); 61562306a36Sopenharmony_ci do { 61662306a36Sopenharmony_ci pci_read_config_dword(pdev, 61762306a36Sopenharmony_ci LBCIF_DATA_REGISTER, 61862306a36Sopenharmony_ci &val); 61962306a36Sopenharmony_ci } while ((val & 0x00010000) == 0); 62062306a36Sopenharmony_ci } while (val & 0x00040000); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if ((val & 0xFF00) != 0xC000 || index == 10000) 62362306a36Sopenharmony_ci break; 62462306a36Sopenharmony_ci index++; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci return writeok ? 0 : -EIO; 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic int eeprom_read(struct et131x_adapter *adapter, u32 addr, u8 *pdata) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 63262306a36Sopenharmony_ci int err; 63362306a36Sopenharmony_ci u32 status; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* A single byte read is similar to the single byte write, with the 63662306a36Sopenharmony_ci * exception of the data flow: 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_ci err = eeprom_wait_ready(pdev, NULL); 63962306a36Sopenharmony_ci if (err < 0) 64062306a36Sopenharmony_ci return err; 64162306a36Sopenharmony_ci /* Write to the LBCIF Control Register: bit 7=1, bit 6=0, bit 3=0, 64262306a36Sopenharmony_ci * and bits 1:0 both =0. Bit 5 should be set according to the type 64362306a36Sopenharmony_ci * of EEPROM being accessed (1=two byte addressing, 0=one byte 64462306a36Sopenharmony_ci * addressing). 64562306a36Sopenharmony_ci */ 64662306a36Sopenharmony_ci if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER, 64762306a36Sopenharmony_ci LBCIF_CONTROL_LBCIF_ENABLE)) 64862306a36Sopenharmony_ci return -EIO; 64962306a36Sopenharmony_ci /* Write the address to the LBCIF Address Register (I2C read will 65062306a36Sopenharmony_ci * begin). 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_ci if (pci_write_config_dword(pdev, LBCIF_ADDRESS_REGISTER, addr)) 65362306a36Sopenharmony_ci return -EIO; 65462306a36Sopenharmony_ci /* Monitor bit 0 of the LBCIF Status Register. When = 1, I2C read 65562306a36Sopenharmony_ci * is complete. (if bit 1 =1 and bit 0 stays = 0, a hardware failure 65662306a36Sopenharmony_ci * has occurred). 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_ci err = eeprom_wait_ready(pdev, &status); 65962306a36Sopenharmony_ci if (err < 0) 66062306a36Sopenharmony_ci return err; 66162306a36Sopenharmony_ci /* Regardless of error status, read data byte from LBCIF Data 66262306a36Sopenharmony_ci * Register. 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_ci *pdata = err; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci return (status & LBCIF_STATUS_ACK_ERROR) ? -EIO : 0; 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic int et131x_init_eeprom(struct et131x_adapter *adapter) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 67262306a36Sopenharmony_ci u8 eestatus; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS, &eestatus); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* THIS IS A WORKAROUND: 67762306a36Sopenharmony_ci * I need to call this function twice to get my card in a 67862306a36Sopenharmony_ci * LG M1 Express Dual running. I tried also a msleep before this 67962306a36Sopenharmony_ci * function, because I thought there could be some time conditions 68062306a36Sopenharmony_ci * but it didn't work. Call the whole function twice also work. 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ci if (pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS, &eestatus)) { 68362306a36Sopenharmony_ci dev_err(&pdev->dev, 68462306a36Sopenharmony_ci "Could not read PCI config space for EEPROM Status\n"); 68562306a36Sopenharmony_ci return -EIO; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* Determine if the error(s) we care about are present. If they are 68962306a36Sopenharmony_ci * present we need to fail. 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_ci if (eestatus & 0x4C) { 69262306a36Sopenharmony_ci int write_failed = 0; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (pdev->revision == 0x01) { 69562306a36Sopenharmony_ci int i; 69662306a36Sopenharmony_ci static const u8 eedata[4] = { 0xFE, 0x13, 0x10, 0xFF }; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* Re-write the first 4 bytes if we have an eeprom 69962306a36Sopenharmony_ci * present and the revision id is 1, this fixes the 70062306a36Sopenharmony_ci * corruption seen with 1310 B Silicon 70162306a36Sopenharmony_ci */ 70262306a36Sopenharmony_ci for (i = 0; i < 3; i++) 70362306a36Sopenharmony_ci if (eeprom_write(adapter, i, eedata[i]) < 0) 70462306a36Sopenharmony_ci write_failed = 1; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci if (pdev->revision != 0x01 || write_failed) { 70762306a36Sopenharmony_ci dev_err(&pdev->dev, 70862306a36Sopenharmony_ci "Fatal EEPROM Status Error - 0x%04x\n", 70962306a36Sopenharmony_ci eestatus); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* This error could mean that there was an error 71262306a36Sopenharmony_ci * reading the eeprom or that the eeprom doesn't exist. 71362306a36Sopenharmony_ci * We will treat each case the same and not try to 71462306a36Sopenharmony_ci * gather additional information that normally would 71562306a36Sopenharmony_ci * come from the eeprom, like MAC Address 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_ci adapter->has_eeprom = false; 71862306a36Sopenharmony_ci return -EIO; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci adapter->has_eeprom = true; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci /* Read the EEPROM for information regarding LED behavior. Refer to 72462306a36Sopenharmony_ci * et131x_xcvr_init() for its use. 72562306a36Sopenharmony_ci */ 72662306a36Sopenharmony_ci eeprom_read(adapter, 0x70, &adapter->eeprom_data[0]); 72762306a36Sopenharmony_ci eeprom_read(adapter, 0x71, &adapter->eeprom_data[1]); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (adapter->eeprom_data[0] != 0xcd) 73062306a36Sopenharmony_ci /* Disable all optional features */ 73162306a36Sopenharmony_ci adapter->eeprom_data[1] = 0x00; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci return 0; 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic void et131x_rx_dma_enable(struct et131x_adapter *adapter) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci /* Setup the receive dma configuration register for normal operation */ 73962306a36Sopenharmony_ci u32 csr = ET_RXDMA_CSR_FBR1_ENABLE; 74062306a36Sopenharmony_ci struct rx_ring *rx_ring = &adapter->rx_ring; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (rx_ring->fbr[1]->buffsize == 4096) 74362306a36Sopenharmony_ci csr |= ET_RXDMA_CSR_FBR1_SIZE_LO; 74462306a36Sopenharmony_ci else if (rx_ring->fbr[1]->buffsize == 8192) 74562306a36Sopenharmony_ci csr |= ET_RXDMA_CSR_FBR1_SIZE_HI; 74662306a36Sopenharmony_ci else if (rx_ring->fbr[1]->buffsize == 16384) 74762306a36Sopenharmony_ci csr |= ET_RXDMA_CSR_FBR1_SIZE_LO | ET_RXDMA_CSR_FBR1_SIZE_HI; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci csr |= ET_RXDMA_CSR_FBR0_ENABLE; 75062306a36Sopenharmony_ci if (rx_ring->fbr[0]->buffsize == 256) 75162306a36Sopenharmony_ci csr |= ET_RXDMA_CSR_FBR0_SIZE_LO; 75262306a36Sopenharmony_ci else if (rx_ring->fbr[0]->buffsize == 512) 75362306a36Sopenharmony_ci csr |= ET_RXDMA_CSR_FBR0_SIZE_HI; 75462306a36Sopenharmony_ci else if (rx_ring->fbr[0]->buffsize == 1024) 75562306a36Sopenharmony_ci csr |= ET_RXDMA_CSR_FBR0_SIZE_LO | ET_RXDMA_CSR_FBR0_SIZE_HI; 75662306a36Sopenharmony_ci writel(csr, &adapter->regs->rxdma.csr); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci csr = readl(&adapter->regs->rxdma.csr); 75962306a36Sopenharmony_ci if (csr & ET_RXDMA_CSR_HALT_STATUS) { 76062306a36Sopenharmony_ci udelay(5); 76162306a36Sopenharmony_ci csr = readl(&adapter->regs->rxdma.csr); 76262306a36Sopenharmony_ci if (csr & ET_RXDMA_CSR_HALT_STATUS) { 76362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 76462306a36Sopenharmony_ci "RX Dma failed to exit halt state. CSR 0x%08x\n", 76562306a36Sopenharmony_ci csr); 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic void et131x_rx_dma_disable(struct et131x_adapter *adapter) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci u32 csr; 77362306a36Sopenharmony_ci /* Setup the receive dma configuration register */ 77462306a36Sopenharmony_ci writel(ET_RXDMA_CSR_HALT | ET_RXDMA_CSR_FBR1_ENABLE, 77562306a36Sopenharmony_ci &adapter->regs->rxdma.csr); 77662306a36Sopenharmony_ci csr = readl(&adapter->regs->rxdma.csr); 77762306a36Sopenharmony_ci if (!(csr & ET_RXDMA_CSR_HALT_STATUS)) { 77862306a36Sopenharmony_ci udelay(5); 77962306a36Sopenharmony_ci csr = readl(&adapter->regs->rxdma.csr); 78062306a36Sopenharmony_ci if (!(csr & ET_RXDMA_CSR_HALT_STATUS)) 78162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 78262306a36Sopenharmony_ci "RX Dma failed to enter halt state. CSR 0x%08x\n", 78362306a36Sopenharmony_ci csr); 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic void et131x_tx_dma_enable(struct et131x_adapter *adapter) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci /* Setup the transmit dma configuration register for normal 79062306a36Sopenharmony_ci * operation 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_ci writel(ET_TXDMA_SNGL_EPKT | (PARM_DMA_CACHE_DEF << ET_TXDMA_CACHE_SHIFT), 79362306a36Sopenharmony_ci &adapter->regs->txdma.csr); 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic inline void add_10bit(u32 *v, int n) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci *v = INDEX10(*v + n) | (*v & ET_DMA10_WRAP); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic inline void add_12bit(u32 *v, int n) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci *v = INDEX12(*v + n) | (*v & ET_DMA12_WRAP); 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic void et1310_config_mac_regs1(struct et131x_adapter *adapter) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct mac_regs __iomem *macregs = &adapter->regs->mac; 80962306a36Sopenharmony_ci u32 station1; 81062306a36Sopenharmony_ci u32 station2; 81162306a36Sopenharmony_ci u32 ipg; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci /* First we need to reset everything. Write to MAC configuration 81462306a36Sopenharmony_ci * register 1 to perform reset. 81562306a36Sopenharmony_ci */ 81662306a36Sopenharmony_ci writel(ET_MAC_CFG1_SOFT_RESET | ET_MAC_CFG1_SIM_RESET | 81762306a36Sopenharmony_ci ET_MAC_CFG1_RESET_RXMC | ET_MAC_CFG1_RESET_TXMC | 81862306a36Sopenharmony_ci ET_MAC_CFG1_RESET_RXFUNC | ET_MAC_CFG1_RESET_TXFUNC, 81962306a36Sopenharmony_ci ¯egs->cfg1); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* Next lets configure the MAC Inter-packet gap register */ 82262306a36Sopenharmony_ci ipg = 0x38005860; /* IPG1 0x38 IPG2 0x58 B2B 0x60 */ 82362306a36Sopenharmony_ci ipg |= 0x50 << 8; /* ifg enforce 0x50 */ 82462306a36Sopenharmony_ci writel(ipg, ¯egs->ipg); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci /* Next lets configure the MAC Half Duplex register */ 82762306a36Sopenharmony_ci /* BEB trunc 0xA, Ex Defer, Rexmit 0xF Coll 0x37 */ 82862306a36Sopenharmony_ci writel(0x00A1F037, ¯egs->hfdp); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci /* Next lets configure the MAC Interface Control register */ 83162306a36Sopenharmony_ci writel(0, ¯egs->if_ctrl); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci writel(ET_MAC_MIIMGMT_CLK_RST, ¯egs->mii_mgmt_cfg); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci /* Next lets configure the MAC Station Address register. These 83662306a36Sopenharmony_ci * values are read from the EEPROM during initialization and stored 83762306a36Sopenharmony_ci * in the adapter structure. We write what is stored in the adapter 83862306a36Sopenharmony_ci * structure to the MAC Station Address registers high and low. This 83962306a36Sopenharmony_ci * station address is used for generating and checking pause control 84062306a36Sopenharmony_ci * packets. 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_ci station2 = (adapter->addr[1] << ET_MAC_STATION_ADDR2_OC2_SHIFT) | 84362306a36Sopenharmony_ci (adapter->addr[0] << ET_MAC_STATION_ADDR2_OC1_SHIFT); 84462306a36Sopenharmony_ci station1 = (adapter->addr[5] << ET_MAC_STATION_ADDR1_OC6_SHIFT) | 84562306a36Sopenharmony_ci (adapter->addr[4] << ET_MAC_STATION_ADDR1_OC5_SHIFT) | 84662306a36Sopenharmony_ci (adapter->addr[3] << ET_MAC_STATION_ADDR1_OC4_SHIFT) | 84762306a36Sopenharmony_ci adapter->addr[2]; 84862306a36Sopenharmony_ci writel(station1, ¯egs->station_addr_1); 84962306a36Sopenharmony_ci writel(station2, ¯egs->station_addr_2); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci /* Max ethernet packet in bytes that will be passed by the mac without 85262306a36Sopenharmony_ci * being truncated. Allow the MAC to pass 4 more than our max packet 85362306a36Sopenharmony_ci * size. This is 4 for the Ethernet CRC. 85462306a36Sopenharmony_ci * 85562306a36Sopenharmony_ci * Packets larger than (registry_jumbo_packet) that do not contain a 85662306a36Sopenharmony_ci * VLAN ID will be dropped by the Rx function. 85762306a36Sopenharmony_ci */ 85862306a36Sopenharmony_ci writel(adapter->registry_jumbo_packet + 4, ¯egs->max_fm_len); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci /* clear out MAC config reset */ 86162306a36Sopenharmony_ci writel(0, ¯egs->cfg1); 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic void et1310_config_mac_regs2(struct et131x_adapter *adapter) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci int32_t delay = 0; 86762306a36Sopenharmony_ci struct mac_regs __iomem *mac = &adapter->regs->mac; 86862306a36Sopenharmony_ci struct phy_device *phydev = adapter->netdev->phydev; 86962306a36Sopenharmony_ci u32 cfg1; 87062306a36Sopenharmony_ci u32 cfg2; 87162306a36Sopenharmony_ci u32 ifctrl; 87262306a36Sopenharmony_ci u32 ctl; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci ctl = readl(&adapter->regs->txmac.ctl); 87562306a36Sopenharmony_ci cfg1 = readl(&mac->cfg1); 87662306a36Sopenharmony_ci cfg2 = readl(&mac->cfg2); 87762306a36Sopenharmony_ci ifctrl = readl(&mac->if_ctrl); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* Set up the if mode bits */ 88062306a36Sopenharmony_ci cfg2 &= ~ET_MAC_CFG2_IFMODE_MASK; 88162306a36Sopenharmony_ci if (phydev->speed == SPEED_1000) { 88262306a36Sopenharmony_ci cfg2 |= ET_MAC_CFG2_IFMODE_1000; 88362306a36Sopenharmony_ci ifctrl &= ~ET_MAC_IFCTRL_PHYMODE; 88462306a36Sopenharmony_ci } else { 88562306a36Sopenharmony_ci cfg2 |= ET_MAC_CFG2_IFMODE_100; 88662306a36Sopenharmony_ci ifctrl |= ET_MAC_IFCTRL_PHYMODE; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci cfg1 |= ET_MAC_CFG1_RX_ENABLE | ET_MAC_CFG1_TX_ENABLE | 89062306a36Sopenharmony_ci ET_MAC_CFG1_TX_FLOW; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci cfg1 &= ~(ET_MAC_CFG1_LOOPBACK | ET_MAC_CFG1_RX_FLOW); 89362306a36Sopenharmony_ci if (adapter->flow == FLOW_RXONLY || adapter->flow == FLOW_BOTH) 89462306a36Sopenharmony_ci cfg1 |= ET_MAC_CFG1_RX_FLOW; 89562306a36Sopenharmony_ci writel(cfg1, &mac->cfg1); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* Now we need to initialize the MAC Configuration 2 register */ 89862306a36Sopenharmony_ci /* preamble 7, check length, huge frame off, pad crc, crc enable 89962306a36Sopenharmony_ci * full duplex off 90062306a36Sopenharmony_ci */ 90162306a36Sopenharmony_ci cfg2 |= 0x7 << ET_MAC_CFG2_PREAMBLE_SHIFT; 90262306a36Sopenharmony_ci cfg2 |= ET_MAC_CFG2_IFMODE_LEN_CHECK; 90362306a36Sopenharmony_ci cfg2 |= ET_MAC_CFG2_IFMODE_PAD_CRC; 90462306a36Sopenharmony_ci cfg2 |= ET_MAC_CFG2_IFMODE_CRC_ENABLE; 90562306a36Sopenharmony_ci cfg2 &= ~ET_MAC_CFG2_IFMODE_HUGE_FRAME; 90662306a36Sopenharmony_ci cfg2 &= ~ET_MAC_CFG2_IFMODE_FULL_DPLX; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci if (phydev->duplex == DUPLEX_FULL) 90962306a36Sopenharmony_ci cfg2 |= ET_MAC_CFG2_IFMODE_FULL_DPLX; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci ifctrl &= ~ET_MAC_IFCTRL_GHDMODE; 91262306a36Sopenharmony_ci if (phydev->duplex == DUPLEX_HALF) 91362306a36Sopenharmony_ci ifctrl |= ET_MAC_IFCTRL_GHDMODE; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci writel(ifctrl, &mac->if_ctrl); 91662306a36Sopenharmony_ci writel(cfg2, &mac->cfg2); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci do { 91962306a36Sopenharmony_ci udelay(10); 92062306a36Sopenharmony_ci delay++; 92162306a36Sopenharmony_ci cfg1 = readl(&mac->cfg1); 92262306a36Sopenharmony_ci } while ((cfg1 & ET_MAC_CFG1_WAIT) != ET_MAC_CFG1_WAIT && delay < 100); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci if (delay == 100) { 92562306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, 92662306a36Sopenharmony_ci "Syncd bits did not respond correctly cfg1 word 0x%08x\n", 92762306a36Sopenharmony_ci cfg1); 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci ctl |= ET_TX_CTRL_TXMAC_ENABLE | ET_TX_CTRL_FC_DISABLE; 93162306a36Sopenharmony_ci writel(ctl, &adapter->regs->txmac.ctl); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (adapter->flags & FMP_ADAPTER_LOWER_POWER) { 93462306a36Sopenharmony_ci et131x_rx_dma_enable(adapter); 93562306a36Sopenharmony_ci et131x_tx_dma_enable(adapter); 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic int et1310_in_phy_coma(struct et131x_adapter *adapter) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci u32 pmcsr = readl(&adapter->regs->global.pm_csr); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci return ET_PM_PHY_SW_COMA & pmcsr ? 1 : 0; 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_cistatic void et1310_setup_device_for_multicast(struct et131x_adapter *adapter) 94762306a36Sopenharmony_ci{ 94862306a36Sopenharmony_ci struct rxmac_regs __iomem *rxmac = &adapter->regs->rxmac; 94962306a36Sopenharmony_ci u32 hash1 = 0; 95062306a36Sopenharmony_ci u32 hash2 = 0; 95162306a36Sopenharmony_ci u32 hash3 = 0; 95262306a36Sopenharmony_ci u32 hash4 = 0; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci /* If ET131X_PACKET_TYPE_MULTICAST is specified, then we provision 95562306a36Sopenharmony_ci * the multi-cast LIST. If it is NOT specified, (and "ALL" is not 95662306a36Sopenharmony_ci * specified) then we should pass NO multi-cast addresses to the 95762306a36Sopenharmony_ci * driver. 95862306a36Sopenharmony_ci */ 95962306a36Sopenharmony_ci if (adapter->packet_filter & ET131X_PACKET_TYPE_MULTICAST) { 96062306a36Sopenharmony_ci int i; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci /* Loop through our multicast array and set up the device */ 96362306a36Sopenharmony_ci for (i = 0; i < adapter->multicast_addr_count; i++) { 96462306a36Sopenharmony_ci u32 result; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci result = ether_crc(6, adapter->multicast_list[i]); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci result = (result & 0x3F800000) >> 23; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci if (result < 32) { 97162306a36Sopenharmony_ci hash1 |= (1 << result); 97262306a36Sopenharmony_ci } else if ((31 < result) && (result < 64)) { 97362306a36Sopenharmony_ci result -= 32; 97462306a36Sopenharmony_ci hash2 |= (1 << result); 97562306a36Sopenharmony_ci } else if ((63 < result) && (result < 96)) { 97662306a36Sopenharmony_ci result -= 64; 97762306a36Sopenharmony_ci hash3 |= (1 << result); 97862306a36Sopenharmony_ci } else { 97962306a36Sopenharmony_ci result -= 96; 98062306a36Sopenharmony_ci hash4 |= (1 << result); 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* Write out the new hash to the device */ 98662306a36Sopenharmony_ci if (!et1310_in_phy_coma(adapter)) { 98762306a36Sopenharmony_ci writel(hash1, &rxmac->multi_hash1); 98862306a36Sopenharmony_ci writel(hash2, &rxmac->multi_hash2); 98962306a36Sopenharmony_ci writel(hash3, &rxmac->multi_hash3); 99062306a36Sopenharmony_ci writel(hash4, &rxmac->multi_hash4); 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic void et1310_setup_device_for_unicast(struct et131x_adapter *adapter) 99562306a36Sopenharmony_ci{ 99662306a36Sopenharmony_ci struct rxmac_regs __iomem *rxmac = &adapter->regs->rxmac; 99762306a36Sopenharmony_ci u32 uni_pf1; 99862306a36Sopenharmony_ci u32 uni_pf2; 99962306a36Sopenharmony_ci u32 uni_pf3; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci /* Set up unicast packet filter reg 3 to be the first two octets of 100262306a36Sopenharmony_ci * the MAC address for both address 100362306a36Sopenharmony_ci * 100462306a36Sopenharmony_ci * Set up unicast packet filter reg 2 to be the octets 2 - 5 of the 100562306a36Sopenharmony_ci * MAC address for second address 100662306a36Sopenharmony_ci * 100762306a36Sopenharmony_ci * Set up unicast packet filter reg 3 to be the octets 2 - 5 of the 100862306a36Sopenharmony_ci * MAC address for first address 100962306a36Sopenharmony_ci */ 101062306a36Sopenharmony_ci uni_pf3 = (adapter->addr[0] << ET_RX_UNI_PF_ADDR2_1_SHIFT) | 101162306a36Sopenharmony_ci (adapter->addr[1] << ET_RX_UNI_PF_ADDR2_2_SHIFT) | 101262306a36Sopenharmony_ci (adapter->addr[0] << ET_RX_UNI_PF_ADDR1_1_SHIFT) | 101362306a36Sopenharmony_ci adapter->addr[1]; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci uni_pf2 = (adapter->addr[2] << ET_RX_UNI_PF_ADDR2_3_SHIFT) | 101662306a36Sopenharmony_ci (adapter->addr[3] << ET_RX_UNI_PF_ADDR2_4_SHIFT) | 101762306a36Sopenharmony_ci (adapter->addr[4] << ET_RX_UNI_PF_ADDR2_5_SHIFT) | 101862306a36Sopenharmony_ci adapter->addr[5]; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci uni_pf1 = (adapter->addr[2] << ET_RX_UNI_PF_ADDR1_3_SHIFT) | 102162306a36Sopenharmony_ci (adapter->addr[3] << ET_RX_UNI_PF_ADDR1_4_SHIFT) | 102262306a36Sopenharmony_ci (adapter->addr[4] << ET_RX_UNI_PF_ADDR1_5_SHIFT) | 102362306a36Sopenharmony_ci adapter->addr[5]; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci if (!et1310_in_phy_coma(adapter)) { 102662306a36Sopenharmony_ci writel(uni_pf1, &rxmac->uni_pf_addr1); 102762306a36Sopenharmony_ci writel(uni_pf2, &rxmac->uni_pf_addr2); 102862306a36Sopenharmony_ci writel(uni_pf3, &rxmac->uni_pf_addr3); 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic void et1310_config_rxmac_regs(struct et131x_adapter *adapter) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci struct rxmac_regs __iomem *rxmac = &adapter->regs->rxmac; 103562306a36Sopenharmony_ci struct phy_device *phydev = adapter->netdev->phydev; 103662306a36Sopenharmony_ci u32 sa_lo; 103762306a36Sopenharmony_ci u32 sa_hi = 0; 103862306a36Sopenharmony_ci u32 pf_ctrl = 0; 103962306a36Sopenharmony_ci u32 __iomem *wolw; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci /* Disable the MAC while it is being configured (also disable WOL) */ 104262306a36Sopenharmony_ci writel(0x8, &rxmac->ctrl); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci /* Initialize WOL to disabled. */ 104562306a36Sopenharmony_ci writel(0, &rxmac->crc0); 104662306a36Sopenharmony_ci writel(0, &rxmac->crc12); 104762306a36Sopenharmony_ci writel(0, &rxmac->crc34); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci /* We need to set the WOL mask0 - mask4 next. We initialize it to 105062306a36Sopenharmony_ci * its default Values of 0x00000000 because there are not WOL masks 105162306a36Sopenharmony_ci * as of this time. 105262306a36Sopenharmony_ci */ 105362306a36Sopenharmony_ci for (wolw = &rxmac->mask0_word0; wolw <= &rxmac->mask4_word3; wolw++) 105462306a36Sopenharmony_ci writel(0, wolw); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci /* Lets setup the WOL Source Address */ 105762306a36Sopenharmony_ci sa_lo = (adapter->addr[2] << ET_RX_WOL_LO_SA3_SHIFT) | 105862306a36Sopenharmony_ci (adapter->addr[3] << ET_RX_WOL_LO_SA4_SHIFT) | 105962306a36Sopenharmony_ci (adapter->addr[4] << ET_RX_WOL_LO_SA5_SHIFT) | 106062306a36Sopenharmony_ci adapter->addr[5]; 106162306a36Sopenharmony_ci writel(sa_lo, &rxmac->sa_lo); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci sa_hi = (u32)(adapter->addr[0] << ET_RX_WOL_HI_SA1_SHIFT) | 106462306a36Sopenharmony_ci adapter->addr[1]; 106562306a36Sopenharmony_ci writel(sa_hi, &rxmac->sa_hi); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci /* Disable all Packet Filtering */ 106862306a36Sopenharmony_ci writel(0, &rxmac->pf_ctrl); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci /* Let's initialize the Unicast Packet filtering address */ 107162306a36Sopenharmony_ci if (adapter->packet_filter & ET131X_PACKET_TYPE_DIRECTED) { 107262306a36Sopenharmony_ci et1310_setup_device_for_unicast(adapter); 107362306a36Sopenharmony_ci pf_ctrl |= ET_RX_PFCTRL_UNICST_FILTER_ENABLE; 107462306a36Sopenharmony_ci } else { 107562306a36Sopenharmony_ci writel(0, &rxmac->uni_pf_addr1); 107662306a36Sopenharmony_ci writel(0, &rxmac->uni_pf_addr2); 107762306a36Sopenharmony_ci writel(0, &rxmac->uni_pf_addr3); 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci /* Let's initialize the Multicast hash */ 108162306a36Sopenharmony_ci if (!(adapter->packet_filter & ET131X_PACKET_TYPE_ALL_MULTICAST)) { 108262306a36Sopenharmony_ci pf_ctrl |= ET_RX_PFCTRL_MLTCST_FILTER_ENABLE; 108362306a36Sopenharmony_ci et1310_setup_device_for_multicast(adapter); 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci /* Runt packet filtering. Didn't work in version A silicon. */ 108762306a36Sopenharmony_ci pf_ctrl |= (NIC_MIN_PACKET_SIZE + 4) << ET_RX_PFCTRL_MIN_PKT_SZ_SHIFT; 108862306a36Sopenharmony_ci pf_ctrl |= ET_RX_PFCTRL_FRAG_FILTER_ENABLE; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (adapter->registry_jumbo_packet > 8192) 109162306a36Sopenharmony_ci /* In order to transmit jumbo packets greater than 8k, the 109262306a36Sopenharmony_ci * FIFO between RxMAC and RxDMA needs to be reduced in size 109362306a36Sopenharmony_ci * to (16k - Jumbo packet size). In order to implement this, 109462306a36Sopenharmony_ci * we must use "cut through" mode in the RxMAC, which chops 109562306a36Sopenharmony_ci * packets down into segments which are (max_size * 16). In 109662306a36Sopenharmony_ci * this case we selected 256 bytes, since this is the size of 109762306a36Sopenharmony_ci * the PCI-Express TLP's that the 1310 uses. 109862306a36Sopenharmony_ci * 109962306a36Sopenharmony_ci * seg_en on, fc_en off, size 0x10 110062306a36Sopenharmony_ci */ 110162306a36Sopenharmony_ci writel(0x41, &rxmac->mcif_ctrl_max_seg); 110262306a36Sopenharmony_ci else 110362306a36Sopenharmony_ci writel(0, &rxmac->mcif_ctrl_max_seg); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci writel(0, &rxmac->mcif_water_mark); 110662306a36Sopenharmony_ci writel(0, &rxmac->mif_ctrl); 110762306a36Sopenharmony_ci writel(0, &rxmac->space_avail); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* Initialize the mif_ctrl register 111062306a36Sopenharmony_ci * bit 3: Receive code error. One or more nibbles were signaled as 111162306a36Sopenharmony_ci * errors during the reception of the packet. Clear this 111262306a36Sopenharmony_ci * bit in Gigabit, set it in 100Mbit. This was derived 111362306a36Sopenharmony_ci * experimentally at UNH. 111462306a36Sopenharmony_ci * bit 4: Receive CRC error. The packet's CRC did not match the 111562306a36Sopenharmony_ci * internally generated CRC. 111662306a36Sopenharmony_ci * bit 5: Receive length check error. Indicates that frame length 111762306a36Sopenharmony_ci * field value in the packet does not match the actual data 111862306a36Sopenharmony_ci * byte length and is not a type field. 111962306a36Sopenharmony_ci * bit 16: Receive frame truncated. 112062306a36Sopenharmony_ci * bit 17: Drop packet enable 112162306a36Sopenharmony_ci */ 112262306a36Sopenharmony_ci if (phydev && phydev->speed == SPEED_100) 112362306a36Sopenharmony_ci writel(0x30038, &rxmac->mif_ctrl); 112462306a36Sopenharmony_ci else 112562306a36Sopenharmony_ci writel(0x30030, &rxmac->mif_ctrl); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci /* Finally we initialize RxMac to be enabled & WOL disabled. Packet 112862306a36Sopenharmony_ci * filter is always enabled since it is where the runt packets are 112962306a36Sopenharmony_ci * supposed to be dropped. For version A silicon, runt packet 113062306a36Sopenharmony_ci * dropping doesn't work, so it is disabled in the pf_ctrl register, 113162306a36Sopenharmony_ci * but we still leave the packet filter on. 113262306a36Sopenharmony_ci */ 113362306a36Sopenharmony_ci writel(pf_ctrl, &rxmac->pf_ctrl); 113462306a36Sopenharmony_ci writel(ET_RX_CTRL_RXMAC_ENABLE | ET_RX_CTRL_WOL_DISABLE, &rxmac->ctrl); 113562306a36Sopenharmony_ci} 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_cistatic void et1310_config_txmac_regs(struct et131x_adapter *adapter) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci struct txmac_regs __iomem *txmac = &adapter->regs->txmac; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* We need to update the Control Frame Parameters 114262306a36Sopenharmony_ci * cfpt - control frame pause timer set to 64 (0x40) 114362306a36Sopenharmony_ci * cfep - control frame extended pause timer set to 0x0 114462306a36Sopenharmony_ci */ 114562306a36Sopenharmony_ci if (adapter->flow == FLOW_NONE) 114662306a36Sopenharmony_ci writel(0, &txmac->cf_param); 114762306a36Sopenharmony_ci else 114862306a36Sopenharmony_ci writel(0x40, &txmac->cf_param); 114962306a36Sopenharmony_ci} 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_cistatic void et1310_config_macstat_regs(struct et131x_adapter *adapter) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci struct macstat_regs __iomem *macstat = &adapter->regs->macstat; 115462306a36Sopenharmony_ci u32 __iomem *reg; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci /* initialize all the macstat registers to zero on the device */ 115762306a36Sopenharmony_ci for (reg = &macstat->txrx_0_64_byte_frames; 115862306a36Sopenharmony_ci reg <= &macstat->carry_reg2; reg++) 115962306a36Sopenharmony_ci writel(0, reg); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci /* Unmask any counters that we want to track the overflow of. 116262306a36Sopenharmony_ci * Initially this will be all counters. It may become clear later 116362306a36Sopenharmony_ci * that we do not need to track all counters. 116462306a36Sopenharmony_ci */ 116562306a36Sopenharmony_ci writel(0xFFFFBE32, &macstat->carry_reg1_mask); 116662306a36Sopenharmony_ci writel(0xFFFE7E8B, &macstat->carry_reg2_mask); 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_cistatic int et131x_phy_mii_read(struct et131x_adapter *adapter, u8 addr, 117062306a36Sopenharmony_ci u8 reg, u16 *value) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci struct mac_regs __iomem *mac = &adapter->regs->mac; 117362306a36Sopenharmony_ci int status = 0; 117462306a36Sopenharmony_ci u32 delay = 0; 117562306a36Sopenharmony_ci u32 mii_addr; 117662306a36Sopenharmony_ci u32 mii_cmd; 117762306a36Sopenharmony_ci u32 mii_indicator; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci /* Save a local copy of the registers we are dealing with so we can 118062306a36Sopenharmony_ci * set them back 118162306a36Sopenharmony_ci */ 118262306a36Sopenharmony_ci mii_addr = readl(&mac->mii_mgmt_addr); 118362306a36Sopenharmony_ci mii_cmd = readl(&mac->mii_mgmt_cmd); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci /* Stop the current operation */ 118662306a36Sopenharmony_ci writel(0, &mac->mii_mgmt_cmd); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci /* Set up the register we need to read from on the correct PHY */ 118962306a36Sopenharmony_ci writel(ET_MAC_MII_ADDR(addr, reg), &mac->mii_mgmt_addr); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci writel(0x1, &mac->mii_mgmt_cmd); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci do { 119462306a36Sopenharmony_ci udelay(50); 119562306a36Sopenharmony_ci delay++; 119662306a36Sopenharmony_ci mii_indicator = readl(&mac->mii_mgmt_indicator); 119762306a36Sopenharmony_ci } while ((mii_indicator & ET_MAC_MGMT_WAIT) && delay < 50); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci /* If we hit the max delay, we could not read the register */ 120062306a36Sopenharmony_ci if (delay == 50) { 120162306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, 120262306a36Sopenharmony_ci "reg 0x%08x could not be read\n", reg); 120362306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, "status is 0x%08x\n", 120462306a36Sopenharmony_ci mii_indicator); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci status = -EIO; 120762306a36Sopenharmony_ci goto out; 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* If we hit here we were able to read the register and we need to 121162306a36Sopenharmony_ci * return the value to the caller 121262306a36Sopenharmony_ci */ 121362306a36Sopenharmony_ci *value = readl(&mac->mii_mgmt_stat) & ET_MAC_MIIMGMT_STAT_PHYCRTL_MASK; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ciout: 121662306a36Sopenharmony_ci /* Stop the read operation */ 121762306a36Sopenharmony_ci writel(0, &mac->mii_mgmt_cmd); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci /* set the registers we touched back to the state at which we entered 122062306a36Sopenharmony_ci * this function 122162306a36Sopenharmony_ci */ 122262306a36Sopenharmony_ci writel(mii_addr, &mac->mii_mgmt_addr); 122362306a36Sopenharmony_ci writel(mii_cmd, &mac->mii_mgmt_cmd); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci return status; 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic int et131x_mii_read(struct et131x_adapter *adapter, u8 reg, u16 *value) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci struct phy_device *phydev = adapter->netdev->phydev; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci if (!phydev) 123362306a36Sopenharmony_ci return -EIO; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci return et131x_phy_mii_read(adapter, phydev->mdio.addr, reg, value); 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_cistatic int et131x_mii_write(struct et131x_adapter *adapter, u8 addr, u8 reg, 123962306a36Sopenharmony_ci u16 value) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci struct mac_regs __iomem *mac = &adapter->regs->mac; 124262306a36Sopenharmony_ci int status = 0; 124362306a36Sopenharmony_ci u32 delay = 0; 124462306a36Sopenharmony_ci u32 mii_addr; 124562306a36Sopenharmony_ci u32 mii_cmd; 124662306a36Sopenharmony_ci u32 mii_indicator; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci /* Save a local copy of the registers we are dealing with so we can 124962306a36Sopenharmony_ci * set them back 125062306a36Sopenharmony_ci */ 125162306a36Sopenharmony_ci mii_addr = readl(&mac->mii_mgmt_addr); 125262306a36Sopenharmony_ci mii_cmd = readl(&mac->mii_mgmt_cmd); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci /* Stop the current operation */ 125562306a36Sopenharmony_ci writel(0, &mac->mii_mgmt_cmd); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci /* Set up the register we need to write to on the correct PHY */ 125862306a36Sopenharmony_ci writel(ET_MAC_MII_ADDR(addr, reg), &mac->mii_mgmt_addr); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci /* Add the value to write to the registers to the mac */ 126162306a36Sopenharmony_ci writel(value, &mac->mii_mgmt_ctrl); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci do { 126462306a36Sopenharmony_ci udelay(50); 126562306a36Sopenharmony_ci delay++; 126662306a36Sopenharmony_ci mii_indicator = readl(&mac->mii_mgmt_indicator); 126762306a36Sopenharmony_ci } while ((mii_indicator & ET_MAC_MGMT_BUSY) && delay < 100); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci /* If we hit the max delay, we could not write the register */ 127062306a36Sopenharmony_ci if (delay == 100) { 127162306a36Sopenharmony_ci u16 tmp; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, 127462306a36Sopenharmony_ci "reg 0x%08x could not be written", reg); 127562306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, "status is 0x%08x\n", 127662306a36Sopenharmony_ci mii_indicator); 127762306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, "command is 0x%08x\n", 127862306a36Sopenharmony_ci readl(&mac->mii_mgmt_cmd)); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci et131x_mii_read(adapter, reg, &tmp); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci status = -EIO; 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci /* Stop the write operation */ 128562306a36Sopenharmony_ci writel(0, &mac->mii_mgmt_cmd); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci /* set the registers we touched back to the state at which we entered 128862306a36Sopenharmony_ci * this function 128962306a36Sopenharmony_ci */ 129062306a36Sopenharmony_ci writel(mii_addr, &mac->mii_mgmt_addr); 129162306a36Sopenharmony_ci writel(mii_cmd, &mac->mii_mgmt_cmd); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci return status; 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_cistatic void et1310_phy_read_mii_bit(struct et131x_adapter *adapter, 129762306a36Sopenharmony_ci u16 regnum, 129862306a36Sopenharmony_ci u16 bitnum, 129962306a36Sopenharmony_ci u8 *value) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci u16 reg; 130262306a36Sopenharmony_ci u16 mask = 1 << bitnum; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci et131x_mii_read(adapter, regnum, ®); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci *value = (reg & mask) >> bitnum; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic void et1310_config_flow_control(struct et131x_adapter *adapter) 131062306a36Sopenharmony_ci{ 131162306a36Sopenharmony_ci struct phy_device *phydev = adapter->netdev->phydev; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci if (phydev->duplex == DUPLEX_HALF) { 131462306a36Sopenharmony_ci adapter->flow = FLOW_NONE; 131562306a36Sopenharmony_ci } else { 131662306a36Sopenharmony_ci char remote_pause, remote_async_pause; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci et1310_phy_read_mii_bit(adapter, 5, 10, &remote_pause); 131962306a36Sopenharmony_ci et1310_phy_read_mii_bit(adapter, 5, 11, &remote_async_pause); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci if (remote_pause && remote_async_pause) { 132262306a36Sopenharmony_ci adapter->flow = adapter->wanted_flow; 132362306a36Sopenharmony_ci } else if (remote_pause && !remote_async_pause) { 132462306a36Sopenharmony_ci if (adapter->wanted_flow == FLOW_BOTH) 132562306a36Sopenharmony_ci adapter->flow = FLOW_BOTH; 132662306a36Sopenharmony_ci else 132762306a36Sopenharmony_ci adapter->flow = FLOW_NONE; 132862306a36Sopenharmony_ci } else if (!remote_pause && !remote_async_pause) { 132962306a36Sopenharmony_ci adapter->flow = FLOW_NONE; 133062306a36Sopenharmony_ci } else { 133162306a36Sopenharmony_ci if (adapter->wanted_flow == FLOW_BOTH) 133262306a36Sopenharmony_ci adapter->flow = FLOW_RXONLY; 133362306a36Sopenharmony_ci else 133462306a36Sopenharmony_ci adapter->flow = FLOW_NONE; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci/* et1310_update_macstat_host_counters - Update local copy of the statistics */ 134062306a36Sopenharmony_cistatic void et1310_update_macstat_host_counters(struct et131x_adapter *adapter) 134162306a36Sopenharmony_ci{ 134262306a36Sopenharmony_ci struct ce_stats *stats = &adapter->stats; 134362306a36Sopenharmony_ci struct macstat_regs __iomem *macstat = 134462306a36Sopenharmony_ci &adapter->regs->macstat; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci stats->tx_collisions += readl(&macstat->tx_total_collisions); 134762306a36Sopenharmony_ci stats->tx_first_collisions += readl(&macstat->tx_single_collisions); 134862306a36Sopenharmony_ci stats->tx_deferred += readl(&macstat->tx_deferred); 134962306a36Sopenharmony_ci stats->tx_excessive_collisions += 135062306a36Sopenharmony_ci readl(&macstat->tx_multiple_collisions); 135162306a36Sopenharmony_ci stats->tx_late_collisions += readl(&macstat->tx_late_collisions); 135262306a36Sopenharmony_ci stats->tx_underflows += readl(&macstat->tx_undersize_frames); 135362306a36Sopenharmony_ci stats->tx_max_pkt_errs += readl(&macstat->tx_oversize_frames); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci stats->rx_align_errs += readl(&macstat->rx_align_errs); 135662306a36Sopenharmony_ci stats->rx_crc_errs += readl(&macstat->rx_code_errs); 135762306a36Sopenharmony_ci stats->rcvd_pkts_dropped += readl(&macstat->rx_drops); 135862306a36Sopenharmony_ci stats->rx_overflows += readl(&macstat->rx_oversize_packets); 135962306a36Sopenharmony_ci stats->rx_code_violations += readl(&macstat->rx_fcs_errs); 136062306a36Sopenharmony_ci stats->rx_length_errs += readl(&macstat->rx_frame_len_errs); 136162306a36Sopenharmony_ci stats->rx_other_errs += readl(&macstat->rx_fragment_packets); 136262306a36Sopenharmony_ci} 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci/* et1310_handle_macstat_interrupt 136562306a36Sopenharmony_ci * 136662306a36Sopenharmony_ci * One of the MACSTAT counters has wrapped. Update the local copy of 136762306a36Sopenharmony_ci * the statistics held in the adapter structure, checking the "wrap" 136862306a36Sopenharmony_ci * bit for each counter. 136962306a36Sopenharmony_ci */ 137062306a36Sopenharmony_cistatic void et1310_handle_macstat_interrupt(struct et131x_adapter *adapter) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci u32 carry_reg1; 137362306a36Sopenharmony_ci u32 carry_reg2; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci /* Read the interrupt bits from the register(s). These are Clear On 137662306a36Sopenharmony_ci * Write. 137762306a36Sopenharmony_ci */ 137862306a36Sopenharmony_ci carry_reg1 = readl(&adapter->regs->macstat.carry_reg1); 137962306a36Sopenharmony_ci carry_reg2 = readl(&adapter->regs->macstat.carry_reg2); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci writel(carry_reg1, &adapter->regs->macstat.carry_reg1); 138262306a36Sopenharmony_ci writel(carry_reg2, &adapter->regs->macstat.carry_reg2); 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci /* We need to do update the host copy of all the MAC_STAT counters. 138562306a36Sopenharmony_ci * For each counter, check it's overflow bit. If the overflow bit is 138662306a36Sopenharmony_ci * set, then increment the host version of the count by one complete 138762306a36Sopenharmony_ci * revolution of the counter. This routine is called when the counter 138862306a36Sopenharmony_ci * block indicates that one of the counters has wrapped. 138962306a36Sopenharmony_ci */ 139062306a36Sopenharmony_ci if (carry_reg1 & (1 << 14)) 139162306a36Sopenharmony_ci adapter->stats.rx_code_violations += COUNTER_WRAP_16_BIT; 139262306a36Sopenharmony_ci if (carry_reg1 & (1 << 8)) 139362306a36Sopenharmony_ci adapter->stats.rx_align_errs += COUNTER_WRAP_12_BIT; 139462306a36Sopenharmony_ci if (carry_reg1 & (1 << 7)) 139562306a36Sopenharmony_ci adapter->stats.rx_length_errs += COUNTER_WRAP_16_BIT; 139662306a36Sopenharmony_ci if (carry_reg1 & (1 << 2)) 139762306a36Sopenharmony_ci adapter->stats.rx_other_errs += COUNTER_WRAP_16_BIT; 139862306a36Sopenharmony_ci if (carry_reg1 & (1 << 6)) 139962306a36Sopenharmony_ci adapter->stats.rx_crc_errs += COUNTER_WRAP_16_BIT; 140062306a36Sopenharmony_ci if (carry_reg1 & (1 << 3)) 140162306a36Sopenharmony_ci adapter->stats.rx_overflows += COUNTER_WRAP_16_BIT; 140262306a36Sopenharmony_ci if (carry_reg1 & (1 << 0)) 140362306a36Sopenharmony_ci adapter->stats.rcvd_pkts_dropped += COUNTER_WRAP_16_BIT; 140462306a36Sopenharmony_ci if (carry_reg2 & (1 << 16)) 140562306a36Sopenharmony_ci adapter->stats.tx_max_pkt_errs += COUNTER_WRAP_12_BIT; 140662306a36Sopenharmony_ci if (carry_reg2 & (1 << 15)) 140762306a36Sopenharmony_ci adapter->stats.tx_underflows += COUNTER_WRAP_12_BIT; 140862306a36Sopenharmony_ci if (carry_reg2 & (1 << 6)) 140962306a36Sopenharmony_ci adapter->stats.tx_first_collisions += COUNTER_WRAP_12_BIT; 141062306a36Sopenharmony_ci if (carry_reg2 & (1 << 8)) 141162306a36Sopenharmony_ci adapter->stats.tx_deferred += COUNTER_WRAP_12_BIT; 141262306a36Sopenharmony_ci if (carry_reg2 & (1 << 5)) 141362306a36Sopenharmony_ci adapter->stats.tx_excessive_collisions += COUNTER_WRAP_12_BIT; 141462306a36Sopenharmony_ci if (carry_reg2 & (1 << 4)) 141562306a36Sopenharmony_ci adapter->stats.tx_late_collisions += COUNTER_WRAP_12_BIT; 141662306a36Sopenharmony_ci if (carry_reg2 & (1 << 2)) 141762306a36Sopenharmony_ci adapter->stats.tx_collisions += COUNTER_WRAP_12_BIT; 141862306a36Sopenharmony_ci} 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_cistatic int et131x_mdio_read(struct mii_bus *bus, int phy_addr, int reg) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci struct net_device *netdev = bus->priv; 142362306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 142462306a36Sopenharmony_ci u16 value; 142562306a36Sopenharmony_ci int ret; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci ret = et131x_phy_mii_read(adapter, phy_addr, reg, &value); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci if (ret < 0) 143062306a36Sopenharmony_ci return ret; 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci return value; 143362306a36Sopenharmony_ci} 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_cistatic int et131x_mdio_write(struct mii_bus *bus, int phy_addr, 143662306a36Sopenharmony_ci int reg, u16 value) 143762306a36Sopenharmony_ci{ 143862306a36Sopenharmony_ci struct net_device *netdev = bus->priv; 143962306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci return et131x_mii_write(adapter, phy_addr, reg, value); 144262306a36Sopenharmony_ci} 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci/* et1310_phy_power_switch - PHY power control 144562306a36Sopenharmony_ci * @adapter: device to control 144662306a36Sopenharmony_ci * @down: true for off/false for back on 144762306a36Sopenharmony_ci * 144862306a36Sopenharmony_ci * one hundred, ten, one thousand megs 144962306a36Sopenharmony_ci * How would you like to have your LAN accessed 145062306a36Sopenharmony_ci * Can't you see that this code processed 145162306a36Sopenharmony_ci * Phy power, phy power.. 145262306a36Sopenharmony_ci */ 145362306a36Sopenharmony_cistatic void et1310_phy_power_switch(struct et131x_adapter *adapter, bool down) 145462306a36Sopenharmony_ci{ 145562306a36Sopenharmony_ci u16 data; 145662306a36Sopenharmony_ci struct phy_device *phydev = adapter->netdev->phydev; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci et131x_mii_read(adapter, MII_BMCR, &data); 145962306a36Sopenharmony_ci data &= ~BMCR_PDOWN; 146062306a36Sopenharmony_ci if (down) 146162306a36Sopenharmony_ci data |= BMCR_PDOWN; 146262306a36Sopenharmony_ci et131x_mii_write(adapter, phydev->mdio.addr, MII_BMCR, data); 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci/* et131x_xcvr_init - Init the phy if we are setting it into force mode */ 146662306a36Sopenharmony_cistatic void et131x_xcvr_init(struct et131x_adapter *adapter) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci u16 lcr2; 146962306a36Sopenharmony_ci struct phy_device *phydev = adapter->netdev->phydev; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci /* Set the LED behavior such that LED 1 indicates speed (off = 147262306a36Sopenharmony_ci * 10Mbits, blink = 100Mbits, on = 1000Mbits) and LED 2 indicates 147362306a36Sopenharmony_ci * link and activity (on for link, blink off for activity). 147462306a36Sopenharmony_ci * 147562306a36Sopenharmony_ci * NOTE: Some customizations have been added here for specific 147662306a36Sopenharmony_ci * vendors; The LED behavior is now determined by vendor data in the 147762306a36Sopenharmony_ci * EEPROM. However, the above description is the default. 147862306a36Sopenharmony_ci */ 147962306a36Sopenharmony_ci if ((adapter->eeprom_data[1] & 0x4) == 0) { 148062306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_LED_2, &lcr2); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci lcr2 &= (ET_LED2_LED_100TX | ET_LED2_LED_1000T); 148362306a36Sopenharmony_ci lcr2 |= (LED_VAL_LINKON_ACTIVE << LED_LINK_SHIFT); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci if ((adapter->eeprom_data[1] & 0x8) == 0) 148662306a36Sopenharmony_ci lcr2 |= (LED_VAL_1000BT_100BTX << LED_TXRX_SHIFT); 148762306a36Sopenharmony_ci else 148862306a36Sopenharmony_ci lcr2 |= (LED_VAL_LINKON << LED_TXRX_SHIFT); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci et131x_mii_write(adapter, phydev->mdio.addr, PHY_LED_2, lcr2); 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci} 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci/* et131x_configure_global_regs - configure JAGCore global regs */ 149562306a36Sopenharmony_cistatic void et131x_configure_global_regs(struct et131x_adapter *adapter) 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci struct global_regs __iomem *regs = &adapter->regs->global; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci writel(0, ®s->rxq_start_addr); 150062306a36Sopenharmony_ci writel(INTERNAL_MEM_SIZE - 1, ®s->txq_end_addr); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci if (adapter->registry_jumbo_packet < 2048) { 150362306a36Sopenharmony_ci /* Tx / RxDMA and Tx/Rx MAC interfaces have a 1k word 150462306a36Sopenharmony_ci * block of RAM that the driver can split between Tx 150562306a36Sopenharmony_ci * and Rx as it desires. Our default is to split it 150662306a36Sopenharmony_ci * 50/50: 150762306a36Sopenharmony_ci */ 150862306a36Sopenharmony_ci writel(PARM_RX_MEM_END_DEF, ®s->rxq_end_addr); 150962306a36Sopenharmony_ci writel(PARM_RX_MEM_END_DEF + 1, ®s->txq_start_addr); 151062306a36Sopenharmony_ci } else if (adapter->registry_jumbo_packet < 8192) { 151162306a36Sopenharmony_ci /* For jumbo packets > 2k but < 8k, split 50-50. */ 151262306a36Sopenharmony_ci writel(INTERNAL_MEM_RX_OFFSET, ®s->rxq_end_addr); 151362306a36Sopenharmony_ci writel(INTERNAL_MEM_RX_OFFSET + 1, ®s->txq_start_addr); 151462306a36Sopenharmony_ci } else { 151562306a36Sopenharmony_ci /* 9216 is the only packet size greater than 8k that 151662306a36Sopenharmony_ci * is available. The Tx buffer has to be big enough 151762306a36Sopenharmony_ci * for one whole packet on the Tx side. We'll make 151862306a36Sopenharmony_ci * the Tx 9408, and give the rest to Rx 151962306a36Sopenharmony_ci */ 152062306a36Sopenharmony_ci writel(0x01b3, ®s->rxq_end_addr); 152162306a36Sopenharmony_ci writel(0x01b4, ®s->txq_start_addr); 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci /* Initialize the loopback register. Disable all loopbacks. */ 152562306a36Sopenharmony_ci writel(0, ®s->loopback); 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci writel(0, ®s->msi_config); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci /* By default, disable the watchdog timer. It will be enabled when 153062306a36Sopenharmony_ci * a packet is queued. 153162306a36Sopenharmony_ci */ 153262306a36Sopenharmony_ci writel(0, ®s->watchdog_timer); 153362306a36Sopenharmony_ci} 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci/* et131x_config_rx_dma_regs - Start of Rx_DMA init sequence */ 153662306a36Sopenharmony_cistatic void et131x_config_rx_dma_regs(struct et131x_adapter *adapter) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci struct rxdma_regs __iomem *rx_dma = &adapter->regs->rxdma; 153962306a36Sopenharmony_ci struct rx_ring *rx_local = &adapter->rx_ring; 154062306a36Sopenharmony_ci struct fbr_desc *fbr_entry; 154162306a36Sopenharmony_ci u32 entry; 154262306a36Sopenharmony_ci u32 psr_num_des; 154362306a36Sopenharmony_ci unsigned long flags; 154462306a36Sopenharmony_ci u8 id; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci et131x_rx_dma_disable(adapter); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci /* Load the completion writeback physical address */ 154962306a36Sopenharmony_ci writel(upper_32_bits(rx_local->rx_status_bus), &rx_dma->dma_wb_base_hi); 155062306a36Sopenharmony_ci writel(lower_32_bits(rx_local->rx_status_bus), &rx_dma->dma_wb_base_lo); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci memset(rx_local->rx_status_block, 0, sizeof(struct rx_status_block)); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci /* Set the address and parameters of the packet status ring */ 155562306a36Sopenharmony_ci writel(upper_32_bits(rx_local->ps_ring_physaddr), &rx_dma->psr_base_hi); 155662306a36Sopenharmony_ci writel(lower_32_bits(rx_local->ps_ring_physaddr), &rx_dma->psr_base_lo); 155762306a36Sopenharmony_ci writel(rx_local->psr_entries - 1, &rx_dma->psr_num_des); 155862306a36Sopenharmony_ci writel(0, &rx_dma->psr_full_offset); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci psr_num_des = readl(&rx_dma->psr_num_des) & ET_RXDMA_PSR_NUM_DES_MASK; 156162306a36Sopenharmony_ci writel((psr_num_des * LO_MARK_PERCENT_FOR_PSR) / 100, 156262306a36Sopenharmony_ci &rx_dma->psr_min_des); 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci spin_lock_irqsave(&adapter->rcv_lock, flags); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci /* These local variables track the PSR in the adapter structure */ 156762306a36Sopenharmony_ci rx_local->local_psr_full = 0; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci for (id = 0; id < NUM_FBRS; id++) { 157062306a36Sopenharmony_ci u32 __iomem *num_des; 157162306a36Sopenharmony_ci u32 __iomem *full_offset; 157262306a36Sopenharmony_ci u32 __iomem *min_des; 157362306a36Sopenharmony_ci u32 __iomem *base_hi; 157462306a36Sopenharmony_ci u32 __iomem *base_lo; 157562306a36Sopenharmony_ci struct fbr_lookup *fbr = rx_local->fbr[id]; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci if (id == 0) { 157862306a36Sopenharmony_ci num_des = &rx_dma->fbr0_num_des; 157962306a36Sopenharmony_ci full_offset = &rx_dma->fbr0_full_offset; 158062306a36Sopenharmony_ci min_des = &rx_dma->fbr0_min_des; 158162306a36Sopenharmony_ci base_hi = &rx_dma->fbr0_base_hi; 158262306a36Sopenharmony_ci base_lo = &rx_dma->fbr0_base_lo; 158362306a36Sopenharmony_ci } else { 158462306a36Sopenharmony_ci num_des = &rx_dma->fbr1_num_des; 158562306a36Sopenharmony_ci full_offset = &rx_dma->fbr1_full_offset; 158662306a36Sopenharmony_ci min_des = &rx_dma->fbr1_min_des; 158762306a36Sopenharmony_ci base_hi = &rx_dma->fbr1_base_hi; 158862306a36Sopenharmony_ci base_lo = &rx_dma->fbr1_base_lo; 158962306a36Sopenharmony_ci } 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci /* Now's the best time to initialize FBR contents */ 159262306a36Sopenharmony_ci fbr_entry = fbr->ring_virtaddr; 159362306a36Sopenharmony_ci for (entry = 0; entry < fbr->num_entries; entry++) { 159462306a36Sopenharmony_ci fbr_entry->addr_hi = fbr->bus_high[entry]; 159562306a36Sopenharmony_ci fbr_entry->addr_lo = fbr->bus_low[entry]; 159662306a36Sopenharmony_ci fbr_entry->word2 = entry; 159762306a36Sopenharmony_ci fbr_entry++; 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci /* Set the address and parameters of Free buffer ring 1 and 0 */ 160162306a36Sopenharmony_ci writel(upper_32_bits(fbr->ring_physaddr), base_hi); 160262306a36Sopenharmony_ci writel(lower_32_bits(fbr->ring_physaddr), base_lo); 160362306a36Sopenharmony_ci writel(fbr->num_entries - 1, num_des); 160462306a36Sopenharmony_ci writel(ET_DMA10_WRAP, full_offset); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci /* This variable tracks the free buffer ring 1 full position, 160762306a36Sopenharmony_ci * so it has to match the above. 160862306a36Sopenharmony_ci */ 160962306a36Sopenharmony_ci fbr->local_full = ET_DMA10_WRAP; 161062306a36Sopenharmony_ci writel(((fbr->num_entries * LO_MARK_PERCENT_FOR_RX) / 100) - 1, 161162306a36Sopenharmony_ci min_des); 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci /* Program the number of packets we will receive before generating an 161562306a36Sopenharmony_ci * interrupt. 161662306a36Sopenharmony_ci * For version B silicon, this value gets updated once autoneg is 161762306a36Sopenharmony_ci *complete. 161862306a36Sopenharmony_ci */ 161962306a36Sopenharmony_ci writel(PARM_RX_NUM_BUFS_DEF, &rx_dma->num_pkt_done); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci /* The "time_done" is not working correctly to coalesce interrupts 162262306a36Sopenharmony_ci * after a given time period, but rather is giving us an interrupt 162362306a36Sopenharmony_ci * regardless of whether we have received packets. 162462306a36Sopenharmony_ci * This value gets updated once autoneg is complete. 162562306a36Sopenharmony_ci */ 162662306a36Sopenharmony_ci writel(PARM_RX_TIME_INT_DEF, &rx_dma->max_pkt_time); 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->rcv_lock, flags); 162962306a36Sopenharmony_ci} 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci/* et131x_config_tx_dma_regs - Set up the tx dma section of the JAGCore. 163262306a36Sopenharmony_ci * 163362306a36Sopenharmony_ci * Configure the transmit engine with the ring buffers we have created 163462306a36Sopenharmony_ci * and prepare it for use. 163562306a36Sopenharmony_ci */ 163662306a36Sopenharmony_cistatic void et131x_config_tx_dma_regs(struct et131x_adapter *adapter) 163762306a36Sopenharmony_ci{ 163862306a36Sopenharmony_ci struct txdma_regs __iomem *txdma = &adapter->regs->txdma; 163962306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci /* Load the hardware with the start of the transmit descriptor ring. */ 164262306a36Sopenharmony_ci writel(upper_32_bits(tx_ring->tx_desc_ring_pa), &txdma->pr_base_hi); 164362306a36Sopenharmony_ci writel(lower_32_bits(tx_ring->tx_desc_ring_pa), &txdma->pr_base_lo); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci /* Initialise the transmit DMA engine */ 164662306a36Sopenharmony_ci writel(NUM_DESC_PER_RING_TX - 1, &txdma->pr_num_des); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci /* Load the completion writeback physical address */ 164962306a36Sopenharmony_ci writel(upper_32_bits(tx_ring->tx_status_pa), &txdma->dma_wb_base_hi); 165062306a36Sopenharmony_ci writel(lower_32_bits(tx_ring->tx_status_pa), &txdma->dma_wb_base_lo); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci *tx_ring->tx_status = 0; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci writel(0, &txdma->service_request); 165562306a36Sopenharmony_ci tx_ring->send_idx = 0; 165662306a36Sopenharmony_ci} 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci/* et131x_adapter_setup - Set the adapter up as per cassini+ documentation */ 165962306a36Sopenharmony_cistatic void et131x_adapter_setup(struct et131x_adapter *adapter) 166062306a36Sopenharmony_ci{ 166162306a36Sopenharmony_ci et131x_configure_global_regs(adapter); 166262306a36Sopenharmony_ci et1310_config_mac_regs1(adapter); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci /* Configure the MMC registers */ 166562306a36Sopenharmony_ci /* All we need to do is initialize the Memory Control Register */ 166662306a36Sopenharmony_ci writel(ET_MMC_ENABLE, &adapter->regs->mmc.mmc_ctrl); 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci et1310_config_rxmac_regs(adapter); 166962306a36Sopenharmony_ci et1310_config_txmac_regs(adapter); 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci et131x_config_rx_dma_regs(adapter); 167262306a36Sopenharmony_ci et131x_config_tx_dma_regs(adapter); 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci et1310_config_macstat_regs(adapter); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci et1310_phy_power_switch(adapter, 0); 167762306a36Sopenharmony_ci et131x_xcvr_init(adapter); 167862306a36Sopenharmony_ci} 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci/* et131x_soft_reset - Issue soft reset to the hardware, complete for ET1310 */ 168162306a36Sopenharmony_cistatic void et131x_soft_reset(struct et131x_adapter *adapter) 168262306a36Sopenharmony_ci{ 168362306a36Sopenharmony_ci u32 reg; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci /* Disable MAC Core */ 168662306a36Sopenharmony_ci reg = ET_MAC_CFG1_SOFT_RESET | ET_MAC_CFG1_SIM_RESET | 168762306a36Sopenharmony_ci ET_MAC_CFG1_RESET_RXMC | ET_MAC_CFG1_RESET_TXMC | 168862306a36Sopenharmony_ci ET_MAC_CFG1_RESET_RXFUNC | ET_MAC_CFG1_RESET_TXFUNC; 168962306a36Sopenharmony_ci writel(reg, &adapter->regs->mac.cfg1); 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci reg = ET_RESET_ALL; 169262306a36Sopenharmony_ci writel(reg, &adapter->regs->global.sw_reset); 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci reg = ET_MAC_CFG1_RESET_RXMC | ET_MAC_CFG1_RESET_TXMC | 169562306a36Sopenharmony_ci ET_MAC_CFG1_RESET_RXFUNC | ET_MAC_CFG1_RESET_TXFUNC; 169662306a36Sopenharmony_ci writel(reg, &adapter->regs->mac.cfg1); 169762306a36Sopenharmony_ci writel(0, &adapter->regs->mac.cfg1); 169862306a36Sopenharmony_ci} 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_cistatic void et131x_enable_interrupts(struct et131x_adapter *adapter) 170162306a36Sopenharmony_ci{ 170262306a36Sopenharmony_ci u32 mask; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci if (adapter->flow == FLOW_TXONLY || adapter->flow == FLOW_BOTH) 170562306a36Sopenharmony_ci mask = INT_MASK_ENABLE; 170662306a36Sopenharmony_ci else 170762306a36Sopenharmony_ci mask = INT_MASK_ENABLE_NO_FLOW; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci writel(mask, &adapter->regs->global.int_mask); 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_cistatic void et131x_disable_interrupts(struct et131x_adapter *adapter) 171362306a36Sopenharmony_ci{ 171462306a36Sopenharmony_ci writel(INT_MASK_DISABLE, &adapter->regs->global.int_mask); 171562306a36Sopenharmony_ci} 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_cistatic void et131x_tx_dma_disable(struct et131x_adapter *adapter) 171862306a36Sopenharmony_ci{ 171962306a36Sopenharmony_ci /* Setup the transmit dma configuration register */ 172062306a36Sopenharmony_ci writel(ET_TXDMA_CSR_HALT | ET_TXDMA_SNGL_EPKT, 172162306a36Sopenharmony_ci &adapter->regs->txdma.csr); 172262306a36Sopenharmony_ci} 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_cistatic void et131x_enable_txrx(struct net_device *netdev) 172562306a36Sopenharmony_ci{ 172662306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci et131x_rx_dma_enable(adapter); 172962306a36Sopenharmony_ci et131x_tx_dma_enable(adapter); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci if (adapter->flags & FMP_ADAPTER_INTERRUPT_IN_USE) 173262306a36Sopenharmony_ci et131x_enable_interrupts(adapter); 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci netif_start_queue(netdev); 173562306a36Sopenharmony_ci} 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_cistatic void et131x_disable_txrx(struct net_device *netdev) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci netif_stop_queue(netdev); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci et131x_rx_dma_disable(adapter); 174462306a36Sopenharmony_ci et131x_tx_dma_disable(adapter); 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci et131x_disable_interrupts(adapter); 174762306a36Sopenharmony_ci} 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_cistatic void et131x_init_send(struct et131x_adapter *adapter) 175062306a36Sopenharmony_ci{ 175162306a36Sopenharmony_ci int i; 175262306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 175362306a36Sopenharmony_ci struct tcb *tcb = tx_ring->tcb_ring; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci tx_ring->tcb_qhead = tcb; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci memset(tcb, 0, sizeof(struct tcb) * NUM_TCB); 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci for (i = 0; i < NUM_TCB; i++) { 176062306a36Sopenharmony_ci tcb->next = tcb + 1; 176162306a36Sopenharmony_ci tcb++; 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci tcb--; 176562306a36Sopenharmony_ci tx_ring->tcb_qtail = tcb; 176662306a36Sopenharmony_ci tcb->next = NULL; 176762306a36Sopenharmony_ci /* Curr send queue should now be empty */ 176862306a36Sopenharmony_ci tx_ring->send_head = NULL; 176962306a36Sopenharmony_ci tx_ring->send_tail = NULL; 177062306a36Sopenharmony_ci} 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci/* et1310_enable_phy_coma 177362306a36Sopenharmony_ci * 177462306a36Sopenharmony_ci * driver receive an phy status change interrupt while in D0 and check that 177562306a36Sopenharmony_ci * phy_status is down. 177662306a36Sopenharmony_ci * 177762306a36Sopenharmony_ci * -- gate off JAGCore; 177862306a36Sopenharmony_ci * -- set gigE PHY in Coma mode 177962306a36Sopenharmony_ci * -- wake on phy_interrupt; Perform software reset JAGCore, 178062306a36Sopenharmony_ci * re-initialize jagcore and gigE PHY 178162306a36Sopenharmony_ci */ 178262306a36Sopenharmony_cistatic void et1310_enable_phy_coma(struct et131x_adapter *adapter) 178362306a36Sopenharmony_ci{ 178462306a36Sopenharmony_ci u32 pmcsr = readl(&adapter->regs->global.pm_csr); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci /* Stop sending packets. */ 178762306a36Sopenharmony_ci adapter->flags |= FMP_ADAPTER_LOWER_POWER; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci /* Wait for outstanding Receive packets */ 179062306a36Sopenharmony_ci et131x_disable_txrx(adapter->netdev); 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci /* Gate off JAGCore 3 clock domains */ 179362306a36Sopenharmony_ci pmcsr &= ~ET_PMCSR_INIT; 179462306a36Sopenharmony_ci writel(pmcsr, &adapter->regs->global.pm_csr); 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci /* Program gigE PHY in to Coma mode */ 179762306a36Sopenharmony_ci pmcsr |= ET_PM_PHY_SW_COMA; 179862306a36Sopenharmony_ci writel(pmcsr, &adapter->regs->global.pm_csr); 179962306a36Sopenharmony_ci} 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_cistatic void et1310_disable_phy_coma(struct et131x_adapter *adapter) 180262306a36Sopenharmony_ci{ 180362306a36Sopenharmony_ci u32 pmcsr; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci pmcsr = readl(&adapter->regs->global.pm_csr); 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci /* Disable phy_sw_coma register and re-enable JAGCore clocks */ 180862306a36Sopenharmony_ci pmcsr |= ET_PMCSR_INIT; 180962306a36Sopenharmony_ci pmcsr &= ~ET_PM_PHY_SW_COMA; 181062306a36Sopenharmony_ci writel(pmcsr, &adapter->regs->global.pm_csr); 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci /* Restore the GbE PHY speed and duplex modes; 181362306a36Sopenharmony_ci * Reset JAGCore; re-configure and initialize JAGCore and gigE PHY 181462306a36Sopenharmony_ci */ 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci /* Re-initialize the send structures */ 181762306a36Sopenharmony_ci et131x_init_send(adapter); 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci /* Bring the device back to the state it was during init prior to 182062306a36Sopenharmony_ci * autonegotiation being complete. This way, when we get the auto-neg 182162306a36Sopenharmony_ci * complete interrupt, we can complete init by calling ConfigMacREGS2. 182262306a36Sopenharmony_ci */ 182362306a36Sopenharmony_ci et131x_soft_reset(adapter); 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci et131x_adapter_setup(adapter); 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci /* Allow Tx to restart */ 182862306a36Sopenharmony_ci adapter->flags &= ~FMP_ADAPTER_LOWER_POWER; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci et131x_enable_txrx(adapter->netdev); 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_cistatic inline u32 bump_free_buff_ring(u32 *free_buff_ring, u32 limit) 183462306a36Sopenharmony_ci{ 183562306a36Sopenharmony_ci u32 tmp_free_buff_ring = *free_buff_ring; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci tmp_free_buff_ring++; 183862306a36Sopenharmony_ci /* This works for all cases where limit < 1024. The 1023 case 183962306a36Sopenharmony_ci * works because 1023++ is 1024 which means the if condition is not 184062306a36Sopenharmony_ci * taken but the carry of the bit into the wrap bit toggles the wrap 184162306a36Sopenharmony_ci * value correctly 184262306a36Sopenharmony_ci */ 184362306a36Sopenharmony_ci if ((tmp_free_buff_ring & ET_DMA10_MASK) > limit) { 184462306a36Sopenharmony_ci tmp_free_buff_ring &= ~ET_DMA10_MASK; 184562306a36Sopenharmony_ci tmp_free_buff_ring ^= ET_DMA10_WRAP; 184662306a36Sopenharmony_ci } 184762306a36Sopenharmony_ci /* For the 1023 case */ 184862306a36Sopenharmony_ci tmp_free_buff_ring &= (ET_DMA10_MASK | ET_DMA10_WRAP); 184962306a36Sopenharmony_ci *free_buff_ring = tmp_free_buff_ring; 185062306a36Sopenharmony_ci return tmp_free_buff_ring; 185162306a36Sopenharmony_ci} 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci/* et131x_rx_dma_memory_alloc 185462306a36Sopenharmony_ci * 185562306a36Sopenharmony_ci * Allocates Free buffer ring 1 for sure, free buffer ring 0 if required, 185662306a36Sopenharmony_ci * and the Packet Status Ring. 185762306a36Sopenharmony_ci */ 185862306a36Sopenharmony_cistatic int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter) 185962306a36Sopenharmony_ci{ 186062306a36Sopenharmony_ci u8 id; 186162306a36Sopenharmony_ci u32 i, j; 186262306a36Sopenharmony_ci u32 bufsize; 186362306a36Sopenharmony_ci u32 psr_size; 186462306a36Sopenharmony_ci u32 fbr_chunksize; 186562306a36Sopenharmony_ci struct rx_ring *rx_ring = &adapter->rx_ring; 186662306a36Sopenharmony_ci struct fbr_lookup *fbr; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci /* Alloc memory for the lookup table */ 186962306a36Sopenharmony_ci rx_ring->fbr[0] = kzalloc(sizeof(*fbr), GFP_KERNEL); 187062306a36Sopenharmony_ci if (rx_ring->fbr[0] == NULL) 187162306a36Sopenharmony_ci return -ENOMEM; 187262306a36Sopenharmony_ci rx_ring->fbr[1] = kzalloc(sizeof(*fbr), GFP_KERNEL); 187362306a36Sopenharmony_ci if (rx_ring->fbr[1] == NULL) 187462306a36Sopenharmony_ci return -ENOMEM; 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci /* The first thing we will do is configure the sizes of the buffer 187762306a36Sopenharmony_ci * rings. These will change based on jumbo packet support. Larger 187862306a36Sopenharmony_ci * jumbo packets increases the size of each entry in FBR0, and the 187962306a36Sopenharmony_ci * number of entries in FBR0, while at the same time decreasing the 188062306a36Sopenharmony_ci * number of entries in FBR1. 188162306a36Sopenharmony_ci * 188262306a36Sopenharmony_ci * FBR1 holds "large" frames, FBR0 holds "small" frames. If FBR1 188362306a36Sopenharmony_ci * entries are huge in order to accommodate a "jumbo" frame, then it 188462306a36Sopenharmony_ci * will have less entries. Conversely, FBR1 will now be relied upon 188562306a36Sopenharmony_ci * to carry more "normal" frames, thus it's entry size also increases 188662306a36Sopenharmony_ci * and the number of entries goes up too (since it now carries 188762306a36Sopenharmony_ci * "small" + "regular" packets. 188862306a36Sopenharmony_ci * 188962306a36Sopenharmony_ci * In this scheme, we try to maintain 512 entries between the two 189062306a36Sopenharmony_ci * rings. Also, FBR1 remains a constant size - when it's size doubles 189162306a36Sopenharmony_ci * the number of entries halves. FBR0 increases in size, however. 189262306a36Sopenharmony_ci */ 189362306a36Sopenharmony_ci if (adapter->registry_jumbo_packet < 2048) { 189462306a36Sopenharmony_ci rx_ring->fbr[0]->buffsize = 256; 189562306a36Sopenharmony_ci rx_ring->fbr[0]->num_entries = 512; 189662306a36Sopenharmony_ci rx_ring->fbr[1]->buffsize = 2048; 189762306a36Sopenharmony_ci rx_ring->fbr[1]->num_entries = 512; 189862306a36Sopenharmony_ci } else if (adapter->registry_jumbo_packet < 4096) { 189962306a36Sopenharmony_ci rx_ring->fbr[0]->buffsize = 512; 190062306a36Sopenharmony_ci rx_ring->fbr[0]->num_entries = 1024; 190162306a36Sopenharmony_ci rx_ring->fbr[1]->buffsize = 4096; 190262306a36Sopenharmony_ci rx_ring->fbr[1]->num_entries = 512; 190362306a36Sopenharmony_ci } else { 190462306a36Sopenharmony_ci rx_ring->fbr[0]->buffsize = 1024; 190562306a36Sopenharmony_ci rx_ring->fbr[0]->num_entries = 768; 190662306a36Sopenharmony_ci rx_ring->fbr[1]->buffsize = 16384; 190762306a36Sopenharmony_ci rx_ring->fbr[1]->num_entries = 128; 190862306a36Sopenharmony_ci } 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci rx_ring->psr_entries = rx_ring->fbr[0]->num_entries + 191162306a36Sopenharmony_ci rx_ring->fbr[1]->num_entries; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci for (id = 0; id < NUM_FBRS; id++) { 191462306a36Sopenharmony_ci fbr = rx_ring->fbr[id]; 191562306a36Sopenharmony_ci /* Allocate an area of memory for Free Buffer Ring */ 191662306a36Sopenharmony_ci bufsize = sizeof(struct fbr_desc) * fbr->num_entries; 191762306a36Sopenharmony_ci fbr->ring_virtaddr = dma_alloc_coherent(&adapter->pdev->dev, 191862306a36Sopenharmony_ci bufsize, 191962306a36Sopenharmony_ci &fbr->ring_physaddr, 192062306a36Sopenharmony_ci GFP_KERNEL); 192162306a36Sopenharmony_ci if (!fbr->ring_virtaddr) { 192262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 192362306a36Sopenharmony_ci "Cannot alloc memory for Free Buffer Ring %d\n", 192462306a36Sopenharmony_ci id); 192562306a36Sopenharmony_ci return -ENOMEM; 192662306a36Sopenharmony_ci } 192762306a36Sopenharmony_ci } 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci for (id = 0; id < NUM_FBRS; id++) { 193062306a36Sopenharmony_ci fbr = rx_ring->fbr[id]; 193162306a36Sopenharmony_ci fbr_chunksize = (FBR_CHUNKS * fbr->buffsize); 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci for (i = 0; i < fbr->num_entries / FBR_CHUNKS; i++) { 193462306a36Sopenharmony_ci dma_addr_t fbr_physaddr; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci fbr->mem_virtaddrs[i] = dma_alloc_coherent( 193762306a36Sopenharmony_ci &adapter->pdev->dev, fbr_chunksize, 193862306a36Sopenharmony_ci &fbr->mem_physaddrs[i], 193962306a36Sopenharmony_ci GFP_KERNEL); 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci if (!fbr->mem_virtaddrs[i]) { 194262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 194362306a36Sopenharmony_ci "Could not alloc memory\n"); 194462306a36Sopenharmony_ci return -ENOMEM; 194562306a36Sopenharmony_ci } 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci /* See NOTE in "Save Physical Address" comment above */ 194862306a36Sopenharmony_ci fbr_physaddr = fbr->mem_physaddrs[i]; 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci for (j = 0; j < FBR_CHUNKS; j++) { 195162306a36Sopenharmony_ci u32 k = (i * FBR_CHUNKS) + j; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci /* Save the Virtual address of this index for 195462306a36Sopenharmony_ci * quick access later 195562306a36Sopenharmony_ci */ 195662306a36Sopenharmony_ci fbr->virt[k] = (u8 *)fbr->mem_virtaddrs[i] + 195762306a36Sopenharmony_ci (j * fbr->buffsize); 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci /* now store the physical address in the 196062306a36Sopenharmony_ci * descriptor so the device can access it 196162306a36Sopenharmony_ci */ 196262306a36Sopenharmony_ci fbr->bus_high[k] = upper_32_bits(fbr_physaddr); 196362306a36Sopenharmony_ci fbr->bus_low[k] = lower_32_bits(fbr_physaddr); 196462306a36Sopenharmony_ci fbr_physaddr += fbr->buffsize; 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci } 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci /* Allocate an area of memory for FIFO of Packet Status ring entries */ 197062306a36Sopenharmony_ci psr_size = sizeof(struct pkt_stat_desc) * rx_ring->psr_entries; 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci rx_ring->ps_ring_virtaddr = dma_alloc_coherent(&adapter->pdev->dev, 197362306a36Sopenharmony_ci psr_size, 197462306a36Sopenharmony_ci &rx_ring->ps_ring_physaddr, 197562306a36Sopenharmony_ci GFP_KERNEL); 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci if (!rx_ring->ps_ring_virtaddr) { 197862306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 197962306a36Sopenharmony_ci "Cannot alloc memory for Packet Status Ring\n"); 198062306a36Sopenharmony_ci return -ENOMEM; 198162306a36Sopenharmony_ci } 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci /* Allocate an area of memory for writeback of status information */ 198462306a36Sopenharmony_ci rx_ring->rx_status_block = dma_alloc_coherent(&adapter->pdev->dev, 198562306a36Sopenharmony_ci sizeof(struct rx_status_block), 198662306a36Sopenharmony_ci &rx_ring->rx_status_bus, 198762306a36Sopenharmony_ci GFP_KERNEL); 198862306a36Sopenharmony_ci if (!rx_ring->rx_status_block) { 198962306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 199062306a36Sopenharmony_ci "Cannot alloc memory for Status Block\n"); 199162306a36Sopenharmony_ci return -ENOMEM; 199262306a36Sopenharmony_ci } 199362306a36Sopenharmony_ci rx_ring->num_rfd = NIC_DEFAULT_NUM_RFD; 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci /* The RFDs are going to be put on lists later on, so initialize the 199662306a36Sopenharmony_ci * lists now. 199762306a36Sopenharmony_ci */ 199862306a36Sopenharmony_ci INIT_LIST_HEAD(&rx_ring->recv_list); 199962306a36Sopenharmony_ci return 0; 200062306a36Sopenharmony_ci} 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_cistatic void et131x_rx_dma_memory_free(struct et131x_adapter *adapter) 200362306a36Sopenharmony_ci{ 200462306a36Sopenharmony_ci u8 id; 200562306a36Sopenharmony_ci u32 ii; 200662306a36Sopenharmony_ci u32 bufsize; 200762306a36Sopenharmony_ci u32 psr_size; 200862306a36Sopenharmony_ci struct rfd *rfd; 200962306a36Sopenharmony_ci struct rx_ring *rx_ring = &adapter->rx_ring; 201062306a36Sopenharmony_ci struct fbr_lookup *fbr; 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci /* Free RFDs and associated packet descriptors */ 201362306a36Sopenharmony_ci WARN_ON(rx_ring->num_ready_recv != rx_ring->num_rfd); 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci while (!list_empty(&rx_ring->recv_list)) { 201662306a36Sopenharmony_ci rfd = list_entry(rx_ring->recv_list.next, 201762306a36Sopenharmony_ci struct rfd, list_node); 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci list_del(&rfd->list_node); 202062306a36Sopenharmony_ci rfd->skb = NULL; 202162306a36Sopenharmony_ci kfree(rfd); 202262306a36Sopenharmony_ci } 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci /* Free Free Buffer Rings */ 202562306a36Sopenharmony_ci for (id = 0; id < NUM_FBRS; id++) { 202662306a36Sopenharmony_ci fbr = rx_ring->fbr[id]; 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci if (!fbr || !fbr->ring_virtaddr) 202962306a36Sopenharmony_ci continue; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci /* First the packet memory */ 203262306a36Sopenharmony_ci for (ii = 0; ii < fbr->num_entries / FBR_CHUNKS; ii++) { 203362306a36Sopenharmony_ci if (fbr->mem_virtaddrs[ii]) { 203462306a36Sopenharmony_ci bufsize = fbr->buffsize * FBR_CHUNKS; 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, 203762306a36Sopenharmony_ci bufsize, 203862306a36Sopenharmony_ci fbr->mem_virtaddrs[ii], 203962306a36Sopenharmony_ci fbr->mem_physaddrs[ii]); 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci fbr->mem_virtaddrs[ii] = NULL; 204262306a36Sopenharmony_ci } 204362306a36Sopenharmony_ci } 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci bufsize = sizeof(struct fbr_desc) * fbr->num_entries; 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, 204862306a36Sopenharmony_ci bufsize, 204962306a36Sopenharmony_ci fbr->ring_virtaddr, 205062306a36Sopenharmony_ci fbr->ring_physaddr); 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci fbr->ring_virtaddr = NULL; 205362306a36Sopenharmony_ci } 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci /* Free Packet Status Ring */ 205662306a36Sopenharmony_ci if (rx_ring->ps_ring_virtaddr) { 205762306a36Sopenharmony_ci psr_size = sizeof(struct pkt_stat_desc) * rx_ring->psr_entries; 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, psr_size, 206062306a36Sopenharmony_ci rx_ring->ps_ring_virtaddr, 206162306a36Sopenharmony_ci rx_ring->ps_ring_physaddr); 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci rx_ring->ps_ring_virtaddr = NULL; 206462306a36Sopenharmony_ci } 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci /* Free area of memory for the writeback of status information */ 206762306a36Sopenharmony_ci if (rx_ring->rx_status_block) { 206862306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, 206962306a36Sopenharmony_ci sizeof(struct rx_status_block), 207062306a36Sopenharmony_ci rx_ring->rx_status_block, 207162306a36Sopenharmony_ci rx_ring->rx_status_bus); 207262306a36Sopenharmony_ci rx_ring->rx_status_block = NULL; 207362306a36Sopenharmony_ci } 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci /* Free the FBR Lookup Table */ 207662306a36Sopenharmony_ci kfree(rx_ring->fbr[0]); 207762306a36Sopenharmony_ci kfree(rx_ring->fbr[1]); 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci /* Reset Counters */ 208062306a36Sopenharmony_ci rx_ring->num_ready_recv = 0; 208162306a36Sopenharmony_ci} 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci/* et131x_init_recv - Initialize receive data structures */ 208462306a36Sopenharmony_cistatic int et131x_init_recv(struct et131x_adapter *adapter) 208562306a36Sopenharmony_ci{ 208662306a36Sopenharmony_ci struct rfd *rfd; 208762306a36Sopenharmony_ci u32 rfdct; 208862306a36Sopenharmony_ci struct rx_ring *rx_ring = &adapter->rx_ring; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci /* Setup each RFD */ 209162306a36Sopenharmony_ci for (rfdct = 0; rfdct < rx_ring->num_rfd; rfdct++) { 209262306a36Sopenharmony_ci rfd = kzalloc(sizeof(*rfd), GFP_ATOMIC | GFP_DMA); 209362306a36Sopenharmony_ci if (!rfd) 209462306a36Sopenharmony_ci return -ENOMEM; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci rfd->skb = NULL; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci /* Add this RFD to the recv_list */ 209962306a36Sopenharmony_ci list_add_tail(&rfd->list_node, &rx_ring->recv_list); 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci /* Increment the available RFD's */ 210262306a36Sopenharmony_ci rx_ring->num_ready_recv++; 210362306a36Sopenharmony_ci } 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci return 0; 210662306a36Sopenharmony_ci} 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci/* et131x_set_rx_dma_timer - Set the heartbeat timer according to line rate */ 210962306a36Sopenharmony_cistatic void et131x_set_rx_dma_timer(struct et131x_adapter *adapter) 211062306a36Sopenharmony_ci{ 211162306a36Sopenharmony_ci struct phy_device *phydev = adapter->netdev->phydev; 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci /* For version B silicon, we do not use the RxDMA timer for 10 and 100 211462306a36Sopenharmony_ci * Mbits/s line rates. We do not enable and RxDMA interrupt coalescing. 211562306a36Sopenharmony_ci */ 211662306a36Sopenharmony_ci if ((phydev->speed == SPEED_100) || (phydev->speed == SPEED_10)) { 211762306a36Sopenharmony_ci writel(0, &adapter->regs->rxdma.max_pkt_time); 211862306a36Sopenharmony_ci writel(1, &adapter->regs->rxdma.num_pkt_done); 211962306a36Sopenharmony_ci } 212062306a36Sopenharmony_ci} 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci/* nic_return_rfd - Recycle a RFD and put it back onto the receive list */ 212362306a36Sopenharmony_cistatic void nic_return_rfd(struct et131x_adapter *adapter, struct rfd *rfd) 212462306a36Sopenharmony_ci{ 212562306a36Sopenharmony_ci struct rx_ring *rx_local = &adapter->rx_ring; 212662306a36Sopenharmony_ci struct rxdma_regs __iomem *rx_dma = &adapter->regs->rxdma; 212762306a36Sopenharmony_ci u16 buff_index = rfd->bufferindex; 212862306a36Sopenharmony_ci u8 ring_index = rfd->ringindex; 212962306a36Sopenharmony_ci unsigned long flags; 213062306a36Sopenharmony_ci struct fbr_lookup *fbr = rx_local->fbr[ring_index]; 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci /* We don't use any of the OOB data besides status. Otherwise, we 213362306a36Sopenharmony_ci * need to clean up OOB data 213462306a36Sopenharmony_ci */ 213562306a36Sopenharmony_ci if (buff_index < fbr->num_entries) { 213662306a36Sopenharmony_ci u32 free_buff_ring; 213762306a36Sopenharmony_ci u32 __iomem *offset; 213862306a36Sopenharmony_ci struct fbr_desc *next; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci if (ring_index == 0) 214162306a36Sopenharmony_ci offset = &rx_dma->fbr0_full_offset; 214262306a36Sopenharmony_ci else 214362306a36Sopenharmony_ci offset = &rx_dma->fbr1_full_offset; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci next = (struct fbr_desc *)(fbr->ring_virtaddr) + 214662306a36Sopenharmony_ci INDEX10(fbr->local_full); 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci /* Handle the Free Buffer Ring advancement here. Write 214962306a36Sopenharmony_ci * the PA / Buffer Index for the returned buffer into 215062306a36Sopenharmony_ci * the oldest (next to be freed)FBR entry 215162306a36Sopenharmony_ci */ 215262306a36Sopenharmony_ci next->addr_hi = fbr->bus_high[buff_index]; 215362306a36Sopenharmony_ci next->addr_lo = fbr->bus_low[buff_index]; 215462306a36Sopenharmony_ci next->word2 = buff_index; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci free_buff_ring = bump_free_buff_ring(&fbr->local_full, 215762306a36Sopenharmony_ci fbr->num_entries - 1); 215862306a36Sopenharmony_ci writel(free_buff_ring, offset); 215962306a36Sopenharmony_ci } else { 216062306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 216162306a36Sopenharmony_ci "%s illegal Buffer Index returned\n", __func__); 216262306a36Sopenharmony_ci } 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci /* The processing on this RFD is done, so put it back on the tail of 216562306a36Sopenharmony_ci * our list 216662306a36Sopenharmony_ci */ 216762306a36Sopenharmony_ci spin_lock_irqsave(&adapter->rcv_lock, flags); 216862306a36Sopenharmony_ci list_add_tail(&rfd->list_node, &rx_local->recv_list); 216962306a36Sopenharmony_ci rx_local->num_ready_recv++; 217062306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->rcv_lock, flags); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci WARN_ON(rx_local->num_ready_recv > rx_local->num_rfd); 217362306a36Sopenharmony_ci} 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci/* nic_rx_pkts - Checks the hardware for available packets 217662306a36Sopenharmony_ci * 217762306a36Sopenharmony_ci * Checks the hardware for available packets, using completion ring 217862306a36Sopenharmony_ci * If packets are available, it gets an RFD from the recv_list, attaches 217962306a36Sopenharmony_ci * the packet to it, puts the RFD in the RecvPendList, and also returns 218062306a36Sopenharmony_ci * the pointer to the RFD. 218162306a36Sopenharmony_ci */ 218262306a36Sopenharmony_cistatic struct rfd *nic_rx_pkts(struct et131x_adapter *adapter) 218362306a36Sopenharmony_ci{ 218462306a36Sopenharmony_ci struct rx_ring *rx_local = &adapter->rx_ring; 218562306a36Sopenharmony_ci struct rx_status_block *status; 218662306a36Sopenharmony_ci struct pkt_stat_desc *psr; 218762306a36Sopenharmony_ci struct rfd *rfd; 218862306a36Sopenharmony_ci unsigned long flags; 218962306a36Sopenharmony_ci struct list_head *element; 219062306a36Sopenharmony_ci u8 ring_index; 219162306a36Sopenharmony_ci u16 buff_index; 219262306a36Sopenharmony_ci u32 len; 219362306a36Sopenharmony_ci u32 word0; 219462306a36Sopenharmony_ci u32 word1; 219562306a36Sopenharmony_ci struct sk_buff *skb; 219662306a36Sopenharmony_ci struct fbr_lookup *fbr; 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci /* RX Status block is written by the DMA engine prior to every 219962306a36Sopenharmony_ci * interrupt. It contains the next to be used entry in the Packet 220062306a36Sopenharmony_ci * Status Ring, and also the two Free Buffer rings. 220162306a36Sopenharmony_ci */ 220262306a36Sopenharmony_ci status = rx_local->rx_status_block; 220362306a36Sopenharmony_ci word1 = status->word1 >> 16; 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci /* Check the PSR and wrap bits do not match */ 220662306a36Sopenharmony_ci if ((word1 & 0x1FFF) == (rx_local->local_psr_full & 0x1FFF)) 220762306a36Sopenharmony_ci return NULL; /* Looks like this ring is not updated yet */ 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci /* The packet status ring indicates that data is available. */ 221062306a36Sopenharmony_ci psr = (struct pkt_stat_desc *)(rx_local->ps_ring_virtaddr) + 221162306a36Sopenharmony_ci (rx_local->local_psr_full & 0xFFF); 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci /* Grab any information that is required once the PSR is advanced, 221462306a36Sopenharmony_ci * since we can no longer rely on the memory being accurate 221562306a36Sopenharmony_ci */ 221662306a36Sopenharmony_ci len = psr->word1 & 0xFFFF; 221762306a36Sopenharmony_ci ring_index = (psr->word1 >> 26) & 0x03; 221862306a36Sopenharmony_ci fbr = rx_local->fbr[ring_index]; 221962306a36Sopenharmony_ci buff_index = (psr->word1 >> 16) & 0x3FF; 222062306a36Sopenharmony_ci word0 = psr->word0; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci /* Indicate that we have used this PSR entry. */ 222362306a36Sopenharmony_ci /* FIXME wrap 12 */ 222462306a36Sopenharmony_ci add_12bit(&rx_local->local_psr_full, 1); 222562306a36Sopenharmony_ci if ((rx_local->local_psr_full & 0xFFF) > rx_local->psr_entries - 1) { 222662306a36Sopenharmony_ci /* Clear psr full and toggle the wrap bit */ 222762306a36Sopenharmony_ci rx_local->local_psr_full &= ~0xFFF; 222862306a36Sopenharmony_ci rx_local->local_psr_full ^= 0x1000; 222962306a36Sopenharmony_ci } 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci writel(rx_local->local_psr_full, &adapter->regs->rxdma.psr_full_offset); 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci if (ring_index > 1 || buff_index > fbr->num_entries - 1) { 223462306a36Sopenharmony_ci /* Illegal buffer or ring index cannot be used by S/W*/ 223562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 223662306a36Sopenharmony_ci "NICRxPkts PSR Entry %d indicates length of %d and/or bad bi(%d)\n", 223762306a36Sopenharmony_ci rx_local->local_psr_full & 0xFFF, len, buff_index); 223862306a36Sopenharmony_ci return NULL; 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci /* Get and fill the RFD. */ 224262306a36Sopenharmony_ci spin_lock_irqsave(&adapter->rcv_lock, flags); 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci element = rx_local->recv_list.next; 224562306a36Sopenharmony_ci rfd = list_entry(element, struct rfd, list_node); 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci if (!rfd) { 224862306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->rcv_lock, flags); 224962306a36Sopenharmony_ci return NULL; 225062306a36Sopenharmony_ci } 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci list_del(&rfd->list_node); 225362306a36Sopenharmony_ci rx_local->num_ready_recv--; 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->rcv_lock, flags); 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci rfd->bufferindex = buff_index; 225862306a36Sopenharmony_ci rfd->ringindex = ring_index; 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci /* In V1 silicon, there is a bug which screws up filtering of runt 226162306a36Sopenharmony_ci * packets. Therefore runt packet filtering is disabled in the MAC and 226262306a36Sopenharmony_ci * the packets are dropped here. They are also counted here. 226362306a36Sopenharmony_ci */ 226462306a36Sopenharmony_ci if (len < (NIC_MIN_PACKET_SIZE + 4)) { 226562306a36Sopenharmony_ci adapter->stats.rx_other_errs++; 226662306a36Sopenharmony_ci rfd->len = 0; 226762306a36Sopenharmony_ci goto out; 226862306a36Sopenharmony_ci } 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci if ((word0 & ALCATEL_MULTICAST_PKT) && !(word0 & ALCATEL_BROADCAST_PKT)) 227162306a36Sopenharmony_ci adapter->stats.multicast_pkts_rcvd++; 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci rfd->len = len; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci skb = dev_alloc_skb(rfd->len + 2); 227662306a36Sopenharmony_ci if (!skb) 227762306a36Sopenharmony_ci return NULL; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci adapter->netdev->stats.rx_bytes += rfd->len; 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci skb_put_data(skb, fbr->virt[buff_index], rfd->len); 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, adapter->netdev); 228462306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 228562306a36Sopenharmony_ci netif_receive_skb(skb); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ciout: 228862306a36Sopenharmony_ci nic_return_rfd(adapter, rfd); 228962306a36Sopenharmony_ci return rfd; 229062306a36Sopenharmony_ci} 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_cistatic int et131x_handle_recv_pkts(struct et131x_adapter *adapter, int budget) 229362306a36Sopenharmony_ci{ 229462306a36Sopenharmony_ci struct rfd *rfd = NULL; 229562306a36Sopenharmony_ci int count = 0; 229662306a36Sopenharmony_ci int limit = budget; 229762306a36Sopenharmony_ci bool done = true; 229862306a36Sopenharmony_ci struct rx_ring *rx_ring = &adapter->rx_ring; 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci if (budget > MAX_PACKETS_HANDLED) 230162306a36Sopenharmony_ci limit = MAX_PACKETS_HANDLED; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci /* Process up to available RFD's */ 230462306a36Sopenharmony_ci while (count < limit) { 230562306a36Sopenharmony_ci if (list_empty(&rx_ring->recv_list)) { 230662306a36Sopenharmony_ci WARN_ON(rx_ring->num_ready_recv != 0); 230762306a36Sopenharmony_ci done = false; 230862306a36Sopenharmony_ci break; 230962306a36Sopenharmony_ci } 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci rfd = nic_rx_pkts(adapter); 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci if (rfd == NULL) 231462306a36Sopenharmony_ci break; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci /* Do not receive any packets until a filter has been set. 231762306a36Sopenharmony_ci * Do not receive any packets until we have link. 231862306a36Sopenharmony_ci * If length is zero, return the RFD in order to advance the 231962306a36Sopenharmony_ci * Free buffer ring. 232062306a36Sopenharmony_ci */ 232162306a36Sopenharmony_ci if (!adapter->packet_filter || 232262306a36Sopenharmony_ci !netif_carrier_ok(adapter->netdev) || 232362306a36Sopenharmony_ci rfd->len == 0) 232462306a36Sopenharmony_ci continue; 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_ci adapter->netdev->stats.rx_packets++; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci if (rx_ring->num_ready_recv < RFD_LOW_WATER_MARK) 232962306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, "RFD's are running out\n"); 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci count++; 233262306a36Sopenharmony_ci } 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci if (count == limit || !done) { 233562306a36Sopenharmony_ci rx_ring->unfinished_receives = true; 233662306a36Sopenharmony_ci writel(PARM_TX_TIME_INT_DEF * NANO_IN_A_MICRO, 233762306a36Sopenharmony_ci &adapter->regs->global.watchdog_timer); 233862306a36Sopenharmony_ci } else { 233962306a36Sopenharmony_ci /* Watchdog timer will disable itself if appropriate. */ 234062306a36Sopenharmony_ci rx_ring->unfinished_receives = false; 234162306a36Sopenharmony_ci } 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci return count; 234462306a36Sopenharmony_ci} 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci/* et131x_tx_dma_memory_alloc 234762306a36Sopenharmony_ci * 234862306a36Sopenharmony_ci * Allocates memory that will be visible both to the device and to the CPU. 234962306a36Sopenharmony_ci * The OS will pass us packets, pointers to which we will insert in the Tx 235062306a36Sopenharmony_ci * Descriptor queue. The device will read this queue to find the packets in 235162306a36Sopenharmony_ci * memory. The device will update the "status" in memory each time it xmits a 235262306a36Sopenharmony_ci * packet. 235362306a36Sopenharmony_ci */ 235462306a36Sopenharmony_cistatic int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter) 235562306a36Sopenharmony_ci{ 235662306a36Sopenharmony_ci int desc_size = 0; 235762306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci /* Allocate memory for the TCB's (Transmit Control Block) */ 236062306a36Sopenharmony_ci tx_ring->tcb_ring = kcalloc(NUM_TCB, sizeof(struct tcb), 236162306a36Sopenharmony_ci GFP_KERNEL | GFP_DMA); 236262306a36Sopenharmony_ci if (!tx_ring->tcb_ring) 236362306a36Sopenharmony_ci return -ENOMEM; 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci desc_size = (sizeof(struct tx_desc) * NUM_DESC_PER_RING_TX); 236662306a36Sopenharmony_ci tx_ring->tx_desc_ring = dma_alloc_coherent(&adapter->pdev->dev, 236762306a36Sopenharmony_ci desc_size, 236862306a36Sopenharmony_ci &tx_ring->tx_desc_ring_pa, 236962306a36Sopenharmony_ci GFP_KERNEL); 237062306a36Sopenharmony_ci if (!tx_ring->tx_desc_ring) { 237162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 237262306a36Sopenharmony_ci "Cannot alloc memory for Tx Ring\n"); 237362306a36Sopenharmony_ci return -ENOMEM; 237462306a36Sopenharmony_ci } 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci tx_ring->tx_status = dma_alloc_coherent(&adapter->pdev->dev, 237762306a36Sopenharmony_ci sizeof(u32), 237862306a36Sopenharmony_ci &tx_ring->tx_status_pa, 237962306a36Sopenharmony_ci GFP_KERNEL); 238062306a36Sopenharmony_ci if (!tx_ring->tx_status) { 238162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 238262306a36Sopenharmony_ci "Cannot alloc memory for Tx status block\n"); 238362306a36Sopenharmony_ci return -ENOMEM; 238462306a36Sopenharmony_ci } 238562306a36Sopenharmony_ci return 0; 238662306a36Sopenharmony_ci} 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_cistatic void et131x_tx_dma_memory_free(struct et131x_adapter *adapter) 238962306a36Sopenharmony_ci{ 239062306a36Sopenharmony_ci int desc_size = 0; 239162306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci if (tx_ring->tx_desc_ring) { 239462306a36Sopenharmony_ci /* Free memory relating to Tx rings here */ 239562306a36Sopenharmony_ci desc_size = (sizeof(struct tx_desc) * NUM_DESC_PER_RING_TX); 239662306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, 239762306a36Sopenharmony_ci desc_size, 239862306a36Sopenharmony_ci tx_ring->tx_desc_ring, 239962306a36Sopenharmony_ci tx_ring->tx_desc_ring_pa); 240062306a36Sopenharmony_ci tx_ring->tx_desc_ring = NULL; 240162306a36Sopenharmony_ci } 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci /* Free memory for the Tx status block */ 240462306a36Sopenharmony_ci if (tx_ring->tx_status) { 240562306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, 240662306a36Sopenharmony_ci sizeof(u32), 240762306a36Sopenharmony_ci tx_ring->tx_status, 240862306a36Sopenharmony_ci tx_ring->tx_status_pa); 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci tx_ring->tx_status = NULL; 241162306a36Sopenharmony_ci } 241262306a36Sopenharmony_ci /* Free the memory for the tcb structures */ 241362306a36Sopenharmony_ci kfree(tx_ring->tcb_ring); 241462306a36Sopenharmony_ci} 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci#define MAX_TX_DESC_PER_PKT 24 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci/* nic_send_packet - NIC specific send handler for version B silicon. */ 241962306a36Sopenharmony_cistatic int nic_send_packet(struct et131x_adapter *adapter, struct tcb *tcb) 242062306a36Sopenharmony_ci{ 242162306a36Sopenharmony_ci u32 i; 242262306a36Sopenharmony_ci struct tx_desc desc[MAX_TX_DESC_PER_PKT]; 242362306a36Sopenharmony_ci u32 frag = 0; 242462306a36Sopenharmony_ci u32 thiscopy, remainder; 242562306a36Sopenharmony_ci struct sk_buff *skb = tcb->skb; 242662306a36Sopenharmony_ci u32 nr_frags = skb_shinfo(skb)->nr_frags + 1; 242762306a36Sopenharmony_ci skb_frag_t *frags = &skb_shinfo(skb)->frags[0]; 242862306a36Sopenharmony_ci struct phy_device *phydev = adapter->netdev->phydev; 242962306a36Sopenharmony_ci dma_addr_t dma_addr; 243062306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci /* Part of the optimizations of this send routine restrict us to 243362306a36Sopenharmony_ci * sending 24 fragments at a pass. In practice we should never see 243462306a36Sopenharmony_ci * more than 5 fragments. 243562306a36Sopenharmony_ci */ 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci memset(desc, 0, sizeof(struct tx_desc) * (nr_frags + 1)); 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci for (i = 0; i < nr_frags; i++) { 244062306a36Sopenharmony_ci /* If there is something in this element, lets get a 244162306a36Sopenharmony_ci * descriptor from the ring and get the necessary data 244262306a36Sopenharmony_ci */ 244362306a36Sopenharmony_ci if (i == 0) { 244462306a36Sopenharmony_ci /* If the fragments are smaller than a standard MTU, 244562306a36Sopenharmony_ci * then map them to a single descriptor in the Tx 244662306a36Sopenharmony_ci * Desc ring. However, if they're larger, as is 244762306a36Sopenharmony_ci * possible with support for jumbo packets, then 244862306a36Sopenharmony_ci * split them each across 2 descriptors. 244962306a36Sopenharmony_ci * 245062306a36Sopenharmony_ci * This will work until we determine why the hardware 245162306a36Sopenharmony_ci * doesn't seem to like large fragments. 245262306a36Sopenharmony_ci */ 245362306a36Sopenharmony_ci if (skb_headlen(skb) <= 1514) { 245462306a36Sopenharmony_ci /* Low 16bits are length, high is vlan and 245562306a36Sopenharmony_ci * unused currently so zero 245662306a36Sopenharmony_ci */ 245762306a36Sopenharmony_ci desc[frag].len_vlan = skb_headlen(skb); 245862306a36Sopenharmony_ci dma_addr = dma_map_single(&adapter->pdev->dev, 245962306a36Sopenharmony_ci skb->data, 246062306a36Sopenharmony_ci skb_headlen(skb), 246162306a36Sopenharmony_ci DMA_TO_DEVICE); 246262306a36Sopenharmony_ci desc[frag].addr_lo = lower_32_bits(dma_addr); 246362306a36Sopenharmony_ci desc[frag].addr_hi = upper_32_bits(dma_addr); 246462306a36Sopenharmony_ci frag++; 246562306a36Sopenharmony_ci } else { 246662306a36Sopenharmony_ci desc[frag].len_vlan = skb_headlen(skb) / 2; 246762306a36Sopenharmony_ci dma_addr = dma_map_single(&adapter->pdev->dev, 246862306a36Sopenharmony_ci skb->data, 246962306a36Sopenharmony_ci skb_headlen(skb) / 2, 247062306a36Sopenharmony_ci DMA_TO_DEVICE); 247162306a36Sopenharmony_ci desc[frag].addr_lo = lower_32_bits(dma_addr); 247262306a36Sopenharmony_ci desc[frag].addr_hi = upper_32_bits(dma_addr); 247362306a36Sopenharmony_ci frag++; 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci desc[frag].len_vlan = skb_headlen(skb) / 2; 247662306a36Sopenharmony_ci dma_addr = dma_map_single(&adapter->pdev->dev, 247762306a36Sopenharmony_ci skb->data + 247862306a36Sopenharmony_ci skb_headlen(skb) / 2, 247962306a36Sopenharmony_ci skb_headlen(skb) / 2, 248062306a36Sopenharmony_ci DMA_TO_DEVICE); 248162306a36Sopenharmony_ci desc[frag].addr_lo = lower_32_bits(dma_addr); 248262306a36Sopenharmony_ci desc[frag].addr_hi = upper_32_bits(dma_addr); 248362306a36Sopenharmony_ci frag++; 248462306a36Sopenharmony_ci } 248562306a36Sopenharmony_ci } else { 248662306a36Sopenharmony_ci desc[frag].len_vlan = skb_frag_size(&frags[i - 1]); 248762306a36Sopenharmony_ci dma_addr = skb_frag_dma_map(&adapter->pdev->dev, 248862306a36Sopenharmony_ci &frags[i - 1], 248962306a36Sopenharmony_ci 0, 249062306a36Sopenharmony_ci desc[frag].len_vlan, 249162306a36Sopenharmony_ci DMA_TO_DEVICE); 249262306a36Sopenharmony_ci desc[frag].addr_lo = lower_32_bits(dma_addr); 249362306a36Sopenharmony_ci desc[frag].addr_hi = upper_32_bits(dma_addr); 249462306a36Sopenharmony_ci frag++; 249562306a36Sopenharmony_ci } 249662306a36Sopenharmony_ci } 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci if (phydev && phydev->speed == SPEED_1000) { 249962306a36Sopenharmony_ci if (++tx_ring->since_irq == PARM_TX_NUM_BUFS_DEF) { 250062306a36Sopenharmony_ci /* Last element & Interrupt flag */ 250162306a36Sopenharmony_ci desc[frag - 1].flags = 250262306a36Sopenharmony_ci TXDESC_FLAG_INTPROC | TXDESC_FLAG_LASTPKT; 250362306a36Sopenharmony_ci tx_ring->since_irq = 0; 250462306a36Sopenharmony_ci } else { /* Last element */ 250562306a36Sopenharmony_ci desc[frag - 1].flags = TXDESC_FLAG_LASTPKT; 250662306a36Sopenharmony_ci } 250762306a36Sopenharmony_ci } else { 250862306a36Sopenharmony_ci desc[frag - 1].flags = 250962306a36Sopenharmony_ci TXDESC_FLAG_INTPROC | TXDESC_FLAG_LASTPKT; 251062306a36Sopenharmony_ci } 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci desc[0].flags |= TXDESC_FLAG_FIRSTPKT; 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci tcb->index_start = tx_ring->send_idx; 251562306a36Sopenharmony_ci tcb->stale = 0; 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci thiscopy = NUM_DESC_PER_RING_TX - INDEX10(tx_ring->send_idx); 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci if (thiscopy >= frag) { 252062306a36Sopenharmony_ci remainder = 0; 252162306a36Sopenharmony_ci thiscopy = frag; 252262306a36Sopenharmony_ci } else { 252362306a36Sopenharmony_ci remainder = frag - thiscopy; 252462306a36Sopenharmony_ci } 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci memcpy(tx_ring->tx_desc_ring + INDEX10(tx_ring->send_idx), 252762306a36Sopenharmony_ci desc, 252862306a36Sopenharmony_ci sizeof(struct tx_desc) * thiscopy); 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci add_10bit(&tx_ring->send_idx, thiscopy); 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci if (INDEX10(tx_ring->send_idx) == 0 || 253362306a36Sopenharmony_ci INDEX10(tx_ring->send_idx) == NUM_DESC_PER_RING_TX) { 253462306a36Sopenharmony_ci tx_ring->send_idx &= ~ET_DMA10_MASK; 253562306a36Sopenharmony_ci tx_ring->send_idx ^= ET_DMA10_WRAP; 253662306a36Sopenharmony_ci } 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci if (remainder) { 253962306a36Sopenharmony_ci memcpy(tx_ring->tx_desc_ring, 254062306a36Sopenharmony_ci desc + thiscopy, 254162306a36Sopenharmony_ci sizeof(struct tx_desc) * remainder); 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci add_10bit(&tx_ring->send_idx, remainder); 254462306a36Sopenharmony_ci } 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci if (INDEX10(tx_ring->send_idx) == 0) { 254762306a36Sopenharmony_ci if (tx_ring->send_idx) 254862306a36Sopenharmony_ci tcb->index = NUM_DESC_PER_RING_TX - 1; 254962306a36Sopenharmony_ci else 255062306a36Sopenharmony_ci tcb->index = ET_DMA10_WRAP|(NUM_DESC_PER_RING_TX - 1); 255162306a36Sopenharmony_ci } else { 255262306a36Sopenharmony_ci tcb->index = tx_ring->send_idx - 1; 255362306a36Sopenharmony_ci } 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci spin_lock(&adapter->tcb_send_qlock); 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci if (tx_ring->send_tail) 255862306a36Sopenharmony_ci tx_ring->send_tail->next = tcb; 255962306a36Sopenharmony_ci else 256062306a36Sopenharmony_ci tx_ring->send_head = tcb; 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci tx_ring->send_tail = tcb; 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci WARN_ON(tcb->next != NULL); 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci tx_ring->used++; 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci spin_unlock(&adapter->tcb_send_qlock); 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci /* Write the new write pointer back to the device. */ 257162306a36Sopenharmony_ci writel(tx_ring->send_idx, &adapter->regs->txdma.service_request); 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci /* For Gig only, we use Tx Interrupt coalescing. Enable the software 257462306a36Sopenharmony_ci * timer to wake us up if this packet isn't followed by N more. 257562306a36Sopenharmony_ci */ 257662306a36Sopenharmony_ci if (phydev && phydev->speed == SPEED_1000) { 257762306a36Sopenharmony_ci writel(PARM_TX_TIME_INT_DEF * NANO_IN_A_MICRO, 257862306a36Sopenharmony_ci &adapter->regs->global.watchdog_timer); 257962306a36Sopenharmony_ci } 258062306a36Sopenharmony_ci return 0; 258162306a36Sopenharmony_ci} 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_cistatic int send_packet(struct sk_buff *skb, struct et131x_adapter *adapter) 258462306a36Sopenharmony_ci{ 258562306a36Sopenharmony_ci int status; 258662306a36Sopenharmony_ci struct tcb *tcb; 258762306a36Sopenharmony_ci unsigned long flags; 258862306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci /* All packets must have at least a MAC address and a protocol type */ 259162306a36Sopenharmony_ci if (skb->len < ETH_HLEN) 259262306a36Sopenharmony_ci return -EIO; 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_ci spin_lock_irqsave(&adapter->tcb_ready_qlock, flags); 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci tcb = tx_ring->tcb_qhead; 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci if (tcb == NULL) { 259962306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tcb_ready_qlock, flags); 260062306a36Sopenharmony_ci return -ENOMEM; 260162306a36Sopenharmony_ci } 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci tx_ring->tcb_qhead = tcb->next; 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci if (tx_ring->tcb_qhead == NULL) 260662306a36Sopenharmony_ci tx_ring->tcb_qtail = NULL; 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tcb_ready_qlock, flags); 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci tcb->skb = skb; 261162306a36Sopenharmony_ci tcb->next = NULL; 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci status = nic_send_packet(adapter, tcb); 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci if (status != 0) { 261662306a36Sopenharmony_ci spin_lock_irqsave(&adapter->tcb_ready_qlock, flags); 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci if (tx_ring->tcb_qtail) 261962306a36Sopenharmony_ci tx_ring->tcb_qtail->next = tcb; 262062306a36Sopenharmony_ci else 262162306a36Sopenharmony_ci /* Apparently ready Q is empty. */ 262262306a36Sopenharmony_ci tx_ring->tcb_qhead = tcb; 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci tx_ring->tcb_qtail = tcb; 262562306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tcb_ready_qlock, flags); 262662306a36Sopenharmony_ci return status; 262762306a36Sopenharmony_ci } 262862306a36Sopenharmony_ci WARN_ON(tx_ring->used > NUM_TCB); 262962306a36Sopenharmony_ci return 0; 263062306a36Sopenharmony_ci} 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci/* free_send_packet - Recycle a struct tcb */ 263362306a36Sopenharmony_cistatic inline void free_send_packet(struct et131x_adapter *adapter, 263462306a36Sopenharmony_ci struct tcb *tcb) 263562306a36Sopenharmony_ci{ 263662306a36Sopenharmony_ci unsigned long flags; 263762306a36Sopenharmony_ci struct tx_desc *desc = NULL; 263862306a36Sopenharmony_ci struct net_device_stats *stats = &adapter->netdev->stats; 263962306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 264062306a36Sopenharmony_ci u64 dma_addr; 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_ci if (tcb->skb) { 264362306a36Sopenharmony_ci stats->tx_bytes += tcb->skb->len; 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci /* Iterate through the TX descriptors on the ring 264662306a36Sopenharmony_ci * corresponding to this packet and umap the fragments 264762306a36Sopenharmony_ci * they point to 264862306a36Sopenharmony_ci */ 264962306a36Sopenharmony_ci do { 265062306a36Sopenharmony_ci desc = tx_ring->tx_desc_ring + 265162306a36Sopenharmony_ci INDEX10(tcb->index_start); 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci dma_addr = desc->addr_lo; 265462306a36Sopenharmony_ci dma_addr |= (u64)desc->addr_hi << 32; 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci dma_unmap_single(&adapter->pdev->dev, 265762306a36Sopenharmony_ci dma_addr, 265862306a36Sopenharmony_ci desc->len_vlan, DMA_TO_DEVICE); 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci add_10bit(&tcb->index_start, 1); 266162306a36Sopenharmony_ci if (INDEX10(tcb->index_start) >= 266262306a36Sopenharmony_ci NUM_DESC_PER_RING_TX) { 266362306a36Sopenharmony_ci tcb->index_start &= ~ET_DMA10_MASK; 266462306a36Sopenharmony_ci tcb->index_start ^= ET_DMA10_WRAP; 266562306a36Sopenharmony_ci } 266662306a36Sopenharmony_ci } while (desc != tx_ring->tx_desc_ring + INDEX10(tcb->index)); 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci dev_kfree_skb_any(tcb->skb); 266962306a36Sopenharmony_ci } 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci memset(tcb, 0, sizeof(struct tcb)); 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci /* Add the TCB to the Ready Q */ 267462306a36Sopenharmony_ci spin_lock_irqsave(&adapter->tcb_ready_qlock, flags); 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci stats->tx_packets++; 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ci if (tx_ring->tcb_qtail) 267962306a36Sopenharmony_ci tx_ring->tcb_qtail->next = tcb; 268062306a36Sopenharmony_ci else /* Apparently ready Q is empty. */ 268162306a36Sopenharmony_ci tx_ring->tcb_qhead = tcb; 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci tx_ring->tcb_qtail = tcb; 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tcb_ready_qlock, flags); 268662306a36Sopenharmony_ci WARN_ON(tx_ring->used < 0); 268762306a36Sopenharmony_ci} 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci/* et131x_free_busy_send_packets - Free and complete the stopped active sends */ 269062306a36Sopenharmony_cistatic void et131x_free_busy_send_packets(struct et131x_adapter *adapter) 269162306a36Sopenharmony_ci{ 269262306a36Sopenharmony_ci struct tcb *tcb; 269362306a36Sopenharmony_ci unsigned long flags; 269462306a36Sopenharmony_ci u32 freed = 0; 269562306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci /* Any packets being sent? Check the first TCB on the send list */ 269862306a36Sopenharmony_ci spin_lock_irqsave(&adapter->tcb_send_qlock, flags); 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci tcb = tx_ring->send_head; 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci while (tcb != NULL && freed < NUM_TCB) { 270362306a36Sopenharmony_ci struct tcb *next = tcb->next; 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci tx_ring->send_head = next; 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci if (next == NULL) 270862306a36Sopenharmony_ci tx_ring->send_tail = NULL; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci tx_ring->used--; 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci freed++; 271562306a36Sopenharmony_ci free_send_packet(adapter, tcb); 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci spin_lock_irqsave(&adapter->tcb_send_qlock, flags); 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci tcb = tx_ring->send_head; 272062306a36Sopenharmony_ci } 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci WARN_ON(freed == NUM_TCB); 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci tx_ring->used = 0; 272762306a36Sopenharmony_ci} 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci/* et131x_handle_send_pkts 273062306a36Sopenharmony_ci * 273162306a36Sopenharmony_ci * Re-claim the send resources, complete sends and get more to send from 273262306a36Sopenharmony_ci * the send wait queue. 273362306a36Sopenharmony_ci */ 273462306a36Sopenharmony_cistatic void et131x_handle_send_pkts(struct et131x_adapter *adapter) 273562306a36Sopenharmony_ci{ 273662306a36Sopenharmony_ci unsigned long flags; 273762306a36Sopenharmony_ci u32 serviced; 273862306a36Sopenharmony_ci struct tcb *tcb; 273962306a36Sopenharmony_ci u32 index; 274062306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_ci serviced = readl(&adapter->regs->txdma.new_service_complete); 274362306a36Sopenharmony_ci index = INDEX10(serviced); 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci /* Has the ring wrapped? Process any descriptors that do not have 274662306a36Sopenharmony_ci * the same "wrap" indicator as the current completion indicator 274762306a36Sopenharmony_ci */ 274862306a36Sopenharmony_ci spin_lock_irqsave(&adapter->tcb_send_qlock, flags); 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci tcb = tx_ring->send_head; 275162306a36Sopenharmony_ci 275262306a36Sopenharmony_ci while (tcb && 275362306a36Sopenharmony_ci ((serviced ^ tcb->index) & ET_DMA10_WRAP) && 275462306a36Sopenharmony_ci index < INDEX10(tcb->index)) { 275562306a36Sopenharmony_ci tx_ring->used--; 275662306a36Sopenharmony_ci tx_ring->send_head = tcb->next; 275762306a36Sopenharmony_ci if (tcb->next == NULL) 275862306a36Sopenharmony_ci tx_ring->send_tail = NULL; 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); 276162306a36Sopenharmony_ci free_send_packet(adapter, tcb); 276262306a36Sopenharmony_ci spin_lock_irqsave(&adapter->tcb_send_qlock, flags); 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci /* Goto the next packet */ 276562306a36Sopenharmony_ci tcb = tx_ring->send_head; 276662306a36Sopenharmony_ci } 276762306a36Sopenharmony_ci while (tcb && 276862306a36Sopenharmony_ci !((serviced ^ tcb->index) & ET_DMA10_WRAP) && 276962306a36Sopenharmony_ci index > (tcb->index & ET_DMA10_MASK)) { 277062306a36Sopenharmony_ci tx_ring->used--; 277162306a36Sopenharmony_ci tx_ring->send_head = tcb->next; 277262306a36Sopenharmony_ci if (tcb->next == NULL) 277362306a36Sopenharmony_ci tx_ring->send_tail = NULL; 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); 277662306a36Sopenharmony_ci free_send_packet(adapter, tcb); 277762306a36Sopenharmony_ci spin_lock_irqsave(&adapter->tcb_send_qlock, flags); 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci /* Goto the next packet */ 278062306a36Sopenharmony_ci tcb = tx_ring->send_head; 278162306a36Sopenharmony_ci } 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci /* Wake up the queue when we hit a low-water mark */ 278462306a36Sopenharmony_ci if (tx_ring->used <= NUM_TCB / 3) 278562306a36Sopenharmony_ci netif_wake_queue(adapter->netdev); 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); 278862306a36Sopenharmony_ci} 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_cistatic int et131x_get_regs_len(struct net_device *netdev) 279162306a36Sopenharmony_ci{ 279262306a36Sopenharmony_ci#define ET131X_REGS_LEN 256 279362306a36Sopenharmony_ci return ET131X_REGS_LEN * sizeof(u32); 279462306a36Sopenharmony_ci} 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_cistatic void et131x_get_regs(struct net_device *netdev, 279762306a36Sopenharmony_ci struct ethtool_regs *regs, void *regs_data) 279862306a36Sopenharmony_ci{ 279962306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 280062306a36Sopenharmony_ci struct address_map __iomem *aregs = adapter->regs; 280162306a36Sopenharmony_ci u32 *regs_buff = regs_data; 280262306a36Sopenharmony_ci u32 num = 0; 280362306a36Sopenharmony_ci u16 tmp; 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci memset(regs_data, 0, et131x_get_regs_len(netdev)); 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci regs->version = (1 << 24) | (adapter->pdev->revision << 16) | 280862306a36Sopenharmony_ci adapter->pdev->device; 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_ci /* PHY regs */ 281162306a36Sopenharmony_ci et131x_mii_read(adapter, MII_BMCR, &tmp); 281262306a36Sopenharmony_ci regs_buff[num++] = tmp; 281362306a36Sopenharmony_ci et131x_mii_read(adapter, MII_BMSR, &tmp); 281462306a36Sopenharmony_ci regs_buff[num++] = tmp; 281562306a36Sopenharmony_ci et131x_mii_read(adapter, MII_PHYSID1, &tmp); 281662306a36Sopenharmony_ci regs_buff[num++] = tmp; 281762306a36Sopenharmony_ci et131x_mii_read(adapter, MII_PHYSID2, &tmp); 281862306a36Sopenharmony_ci regs_buff[num++] = tmp; 281962306a36Sopenharmony_ci et131x_mii_read(adapter, MII_ADVERTISE, &tmp); 282062306a36Sopenharmony_ci regs_buff[num++] = tmp; 282162306a36Sopenharmony_ci et131x_mii_read(adapter, MII_LPA, &tmp); 282262306a36Sopenharmony_ci regs_buff[num++] = tmp; 282362306a36Sopenharmony_ci et131x_mii_read(adapter, MII_EXPANSION, &tmp); 282462306a36Sopenharmony_ci regs_buff[num++] = tmp; 282562306a36Sopenharmony_ci /* Autoneg next page transmit reg */ 282662306a36Sopenharmony_ci et131x_mii_read(adapter, 0x07, &tmp); 282762306a36Sopenharmony_ci regs_buff[num++] = tmp; 282862306a36Sopenharmony_ci /* Link partner next page reg */ 282962306a36Sopenharmony_ci et131x_mii_read(adapter, 0x08, &tmp); 283062306a36Sopenharmony_ci regs_buff[num++] = tmp; 283162306a36Sopenharmony_ci et131x_mii_read(adapter, MII_CTRL1000, &tmp); 283262306a36Sopenharmony_ci regs_buff[num++] = tmp; 283362306a36Sopenharmony_ci et131x_mii_read(adapter, MII_STAT1000, &tmp); 283462306a36Sopenharmony_ci regs_buff[num++] = tmp; 283562306a36Sopenharmony_ci et131x_mii_read(adapter, 0x0b, &tmp); 283662306a36Sopenharmony_ci regs_buff[num++] = tmp; 283762306a36Sopenharmony_ci et131x_mii_read(adapter, 0x0c, &tmp); 283862306a36Sopenharmony_ci regs_buff[num++] = tmp; 283962306a36Sopenharmony_ci et131x_mii_read(adapter, MII_MMD_CTRL, &tmp); 284062306a36Sopenharmony_ci regs_buff[num++] = tmp; 284162306a36Sopenharmony_ci et131x_mii_read(adapter, MII_MMD_DATA, &tmp); 284262306a36Sopenharmony_ci regs_buff[num++] = tmp; 284362306a36Sopenharmony_ci et131x_mii_read(adapter, MII_ESTATUS, &tmp); 284462306a36Sopenharmony_ci regs_buff[num++] = tmp; 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_INDEX_REG, &tmp); 284762306a36Sopenharmony_ci regs_buff[num++] = tmp; 284862306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_DATA_REG, &tmp); 284962306a36Sopenharmony_ci regs_buff[num++] = tmp; 285062306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG, &tmp); 285162306a36Sopenharmony_ci regs_buff[num++] = tmp; 285262306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_LOOPBACK_CONTROL, &tmp); 285362306a36Sopenharmony_ci regs_buff[num++] = tmp; 285462306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_LOOPBACK_CONTROL + 1, &tmp); 285562306a36Sopenharmony_ci regs_buff[num++] = tmp; 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_REGISTER_MGMT_CONTROL, &tmp); 285862306a36Sopenharmony_ci regs_buff[num++] = tmp; 285962306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_CONFIG, &tmp); 286062306a36Sopenharmony_ci regs_buff[num++] = tmp; 286162306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_PHY_CONTROL, &tmp); 286262306a36Sopenharmony_ci regs_buff[num++] = tmp; 286362306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_INTERRUPT_MASK, &tmp); 286462306a36Sopenharmony_ci regs_buff[num++] = tmp; 286562306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_INTERRUPT_STATUS, &tmp); 286662306a36Sopenharmony_ci regs_buff[num++] = tmp; 286762306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_PHY_STATUS, &tmp); 286862306a36Sopenharmony_ci regs_buff[num++] = tmp; 286962306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_LED_1, &tmp); 287062306a36Sopenharmony_ci regs_buff[num++] = tmp; 287162306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_LED_2, &tmp); 287262306a36Sopenharmony_ci regs_buff[num++] = tmp; 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci /* Global regs */ 287562306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.txq_start_addr); 287662306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.txq_end_addr); 287762306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.rxq_start_addr); 287862306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.rxq_end_addr); 287962306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.pm_csr); 288062306a36Sopenharmony_ci regs_buff[num++] = adapter->stats.interrupt_status; 288162306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.int_mask); 288262306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.int_alias_clr_en); 288362306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.int_status_alias); 288462306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.sw_reset); 288562306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.slv_timer); 288662306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.msi_config); 288762306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.loopback); 288862306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->global.watchdog_timer); 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci /* TXDMA regs */ 289162306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.csr); 289262306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.pr_base_hi); 289362306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.pr_base_lo); 289462306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.pr_num_des); 289562306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.txq_wr_addr); 289662306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.txq_wr_addr_ext); 289762306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.txq_rd_addr); 289862306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.dma_wb_base_hi); 289962306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.dma_wb_base_lo); 290062306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.service_request); 290162306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.service_complete); 290262306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.cache_rd_index); 290362306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.cache_wr_index); 290462306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.tx_dma_error); 290562306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.desc_abort_cnt); 290662306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.payload_abort_cnt); 290762306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.writeback_abort_cnt); 290862306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.desc_timeout_cnt); 290962306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.payload_timeout_cnt); 291062306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.writeback_timeout_cnt); 291162306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.desc_error_cnt); 291262306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.payload_error_cnt); 291362306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.writeback_error_cnt); 291462306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.dropped_tlp_cnt); 291562306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.new_service_complete); 291662306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->txdma.ethernet_packet_cnt); 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci /* RXDMA regs */ 291962306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.csr); 292062306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.dma_wb_base_hi); 292162306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.dma_wb_base_lo); 292262306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.num_pkt_done); 292362306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.max_pkt_time); 292462306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.rxq_rd_addr); 292562306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.rxq_rd_addr_ext); 292662306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.rxq_wr_addr); 292762306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.psr_base_hi); 292862306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.psr_base_lo); 292962306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.psr_num_des); 293062306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.psr_avail_offset); 293162306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.psr_full_offset); 293262306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.psr_access_index); 293362306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.psr_min_des); 293462306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr0_base_lo); 293562306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr0_base_hi); 293662306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr0_num_des); 293762306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr0_avail_offset); 293862306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr0_full_offset); 293962306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr0_rd_index); 294062306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr0_min_des); 294162306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr1_base_lo); 294262306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr1_base_hi); 294362306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr1_num_des); 294462306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr1_avail_offset); 294562306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr1_full_offset); 294662306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr1_rd_index); 294762306a36Sopenharmony_ci regs_buff[num++] = readl(&aregs->rxdma.fbr1_min_des); 294862306a36Sopenharmony_ci} 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_cistatic void et131x_get_drvinfo(struct net_device *netdev, 295162306a36Sopenharmony_ci struct ethtool_drvinfo *info) 295262306a36Sopenharmony_ci{ 295362306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_ci strscpy(info->driver, DRIVER_NAME, sizeof(info->driver)); 295662306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(adapter->pdev), 295762306a36Sopenharmony_ci sizeof(info->bus_info)); 295862306a36Sopenharmony_ci} 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_cistatic const struct ethtool_ops et131x_ethtool_ops = { 296162306a36Sopenharmony_ci .get_drvinfo = et131x_get_drvinfo, 296262306a36Sopenharmony_ci .get_regs_len = et131x_get_regs_len, 296362306a36Sopenharmony_ci .get_regs = et131x_get_regs, 296462306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 296562306a36Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 296662306a36Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 296762306a36Sopenharmony_ci}; 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci/* et131x_hwaddr_init - set up the MAC Address */ 297062306a36Sopenharmony_cistatic void et131x_hwaddr_init(struct et131x_adapter *adapter) 297162306a36Sopenharmony_ci{ 297262306a36Sopenharmony_ci /* If have our default mac from init and no mac address from 297362306a36Sopenharmony_ci * EEPROM then we need to generate the last octet and set it on the 297462306a36Sopenharmony_ci * device 297562306a36Sopenharmony_ci */ 297662306a36Sopenharmony_ci if (is_zero_ether_addr(adapter->rom_addr)) { 297762306a36Sopenharmony_ci /* We need to randomly generate the last octet so we 297862306a36Sopenharmony_ci * decrease our chances of setting the mac address to 297962306a36Sopenharmony_ci * same as another one of our cards in the system 298062306a36Sopenharmony_ci */ 298162306a36Sopenharmony_ci get_random_bytes(&adapter->addr[5], 1); 298262306a36Sopenharmony_ci /* We have the default value in the register we are 298362306a36Sopenharmony_ci * working with so we need to copy the current 298462306a36Sopenharmony_ci * address into the permanent address 298562306a36Sopenharmony_ci */ 298662306a36Sopenharmony_ci ether_addr_copy(adapter->rom_addr, adapter->addr); 298762306a36Sopenharmony_ci } else { 298862306a36Sopenharmony_ci /* We do not have an override address, so set the 298962306a36Sopenharmony_ci * current address to the permanent address and add 299062306a36Sopenharmony_ci * it to the device 299162306a36Sopenharmony_ci */ 299262306a36Sopenharmony_ci ether_addr_copy(adapter->addr, adapter->rom_addr); 299362306a36Sopenharmony_ci } 299462306a36Sopenharmony_ci} 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_cistatic int et131x_pci_init(struct et131x_adapter *adapter, 299762306a36Sopenharmony_ci struct pci_dev *pdev) 299862306a36Sopenharmony_ci{ 299962306a36Sopenharmony_ci u16 max_payload; 300062306a36Sopenharmony_ci int i, rc; 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci rc = et131x_init_eeprom(adapter); 300362306a36Sopenharmony_ci if (rc < 0) 300462306a36Sopenharmony_ci goto out; 300562306a36Sopenharmony_ci 300662306a36Sopenharmony_ci if (!pci_is_pcie(pdev)) { 300762306a36Sopenharmony_ci dev_err(&pdev->dev, "Missing PCIe capabilities\n"); 300862306a36Sopenharmony_ci goto err_out; 300962306a36Sopenharmony_ci } 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_ci /* Program the Ack/Nak latency and replay timers */ 301262306a36Sopenharmony_ci max_payload = pdev->pcie_mpss; 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_ci if (max_payload < 2) { 301562306a36Sopenharmony_ci static const u16 acknak[2] = { 0x76, 0xD0 }; 301662306a36Sopenharmony_ci static const u16 replay[2] = { 0x1E0, 0x2ED }; 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci if (pci_write_config_word(pdev, ET1310_PCI_ACK_NACK, 301962306a36Sopenharmony_ci acknak[max_payload])) { 302062306a36Sopenharmony_ci dev_err(&pdev->dev, 302162306a36Sopenharmony_ci "Could not write PCI config space for ACK/NAK\n"); 302262306a36Sopenharmony_ci goto err_out; 302362306a36Sopenharmony_ci } 302462306a36Sopenharmony_ci if (pci_write_config_word(pdev, ET1310_PCI_REPLAY, 302562306a36Sopenharmony_ci replay[max_payload])) { 302662306a36Sopenharmony_ci dev_err(&pdev->dev, 302762306a36Sopenharmony_ci "Could not write PCI config space for Replay Timer\n"); 302862306a36Sopenharmony_ci goto err_out; 302962306a36Sopenharmony_ci } 303062306a36Sopenharmony_ci } 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci /* l0s and l1 latency timers. We are using default values. 303362306a36Sopenharmony_ci * Representing 001 for L0s and 010 for L1 303462306a36Sopenharmony_ci */ 303562306a36Sopenharmony_ci if (pci_write_config_byte(pdev, ET1310_PCI_L0L1LATENCY, 0x11)) { 303662306a36Sopenharmony_ci dev_err(&pdev->dev, 303762306a36Sopenharmony_ci "Could not write PCI config space for Latency Timers\n"); 303862306a36Sopenharmony_ci goto err_out; 303962306a36Sopenharmony_ci } 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_ci /* Change the max read size to 2k */ 304262306a36Sopenharmony_ci if (pcie_set_readrq(pdev, 2048)) { 304362306a36Sopenharmony_ci dev_err(&pdev->dev, 304462306a36Sopenharmony_ci "Couldn't change PCI config space for Max read size\n"); 304562306a36Sopenharmony_ci goto err_out; 304662306a36Sopenharmony_ci } 304762306a36Sopenharmony_ci 304862306a36Sopenharmony_ci /* Get MAC address from config space if an eeprom exists, otherwise 304962306a36Sopenharmony_ci * the MAC address there will not be valid 305062306a36Sopenharmony_ci */ 305162306a36Sopenharmony_ci if (!adapter->has_eeprom) { 305262306a36Sopenharmony_ci et131x_hwaddr_init(adapter); 305362306a36Sopenharmony_ci return 0; 305462306a36Sopenharmony_ci } 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) { 305762306a36Sopenharmony_ci if (pci_read_config_byte(pdev, ET1310_PCI_MAC_ADDRESS + i, 305862306a36Sopenharmony_ci adapter->rom_addr + i)) { 305962306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not read PCI config space for MAC address\n"); 306062306a36Sopenharmony_ci goto err_out; 306162306a36Sopenharmony_ci } 306262306a36Sopenharmony_ci } 306362306a36Sopenharmony_ci ether_addr_copy(adapter->addr, adapter->rom_addr); 306462306a36Sopenharmony_ciout: 306562306a36Sopenharmony_ci return rc; 306662306a36Sopenharmony_cierr_out: 306762306a36Sopenharmony_ci rc = -EIO; 306862306a36Sopenharmony_ci goto out; 306962306a36Sopenharmony_ci} 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci/* et131x_error_timer_handler 307262306a36Sopenharmony_ci * @data: timer-specific variable; here a pointer to our adapter structure 307362306a36Sopenharmony_ci * 307462306a36Sopenharmony_ci * The routine called when the error timer expires, to track the number of 307562306a36Sopenharmony_ci * recurring errors. 307662306a36Sopenharmony_ci */ 307762306a36Sopenharmony_cistatic void et131x_error_timer_handler(struct timer_list *t) 307862306a36Sopenharmony_ci{ 307962306a36Sopenharmony_ci struct et131x_adapter *adapter = from_timer(adapter, t, error_timer); 308062306a36Sopenharmony_ci struct phy_device *phydev = adapter->netdev->phydev; 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci if (et1310_in_phy_coma(adapter)) { 308362306a36Sopenharmony_ci /* Bring the device immediately out of coma, to 308462306a36Sopenharmony_ci * prevent it from sleeping indefinitely, this 308562306a36Sopenharmony_ci * mechanism could be improved! 308662306a36Sopenharmony_ci */ 308762306a36Sopenharmony_ci et1310_disable_phy_coma(adapter); 308862306a36Sopenharmony_ci adapter->boot_coma = 20; 308962306a36Sopenharmony_ci } else { 309062306a36Sopenharmony_ci et1310_update_macstat_host_counters(adapter); 309162306a36Sopenharmony_ci } 309262306a36Sopenharmony_ci 309362306a36Sopenharmony_ci if (!phydev->link && adapter->boot_coma < 11) 309462306a36Sopenharmony_ci adapter->boot_coma++; 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_ci if (adapter->boot_coma == 10) { 309762306a36Sopenharmony_ci if (!phydev->link) { 309862306a36Sopenharmony_ci if (!et1310_in_phy_coma(adapter)) { 309962306a36Sopenharmony_ci /* NOTE - This was originally a 'sync with 310062306a36Sopenharmony_ci * interrupt'. How to do that under Linux? 310162306a36Sopenharmony_ci */ 310262306a36Sopenharmony_ci et131x_enable_interrupts(adapter); 310362306a36Sopenharmony_ci et1310_enable_phy_coma(adapter); 310462306a36Sopenharmony_ci } 310562306a36Sopenharmony_ci } 310662306a36Sopenharmony_ci } 310762306a36Sopenharmony_ci 310862306a36Sopenharmony_ci /* This is a periodic timer, so reschedule */ 310962306a36Sopenharmony_ci mod_timer(&adapter->error_timer, jiffies + 311062306a36Sopenharmony_ci msecs_to_jiffies(TX_ERROR_PERIOD)); 311162306a36Sopenharmony_ci} 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_cistatic void et131x_adapter_memory_free(struct et131x_adapter *adapter) 311462306a36Sopenharmony_ci{ 311562306a36Sopenharmony_ci et131x_tx_dma_memory_free(adapter); 311662306a36Sopenharmony_ci et131x_rx_dma_memory_free(adapter); 311762306a36Sopenharmony_ci} 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_cistatic int et131x_adapter_memory_alloc(struct et131x_adapter *adapter) 312062306a36Sopenharmony_ci{ 312162306a36Sopenharmony_ci int status; 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci status = et131x_tx_dma_memory_alloc(adapter); 312462306a36Sopenharmony_ci if (status) { 312562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 312662306a36Sopenharmony_ci "et131x_tx_dma_memory_alloc FAILED\n"); 312762306a36Sopenharmony_ci et131x_tx_dma_memory_free(adapter); 312862306a36Sopenharmony_ci return status; 312962306a36Sopenharmony_ci } 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_ci status = et131x_rx_dma_memory_alloc(adapter); 313262306a36Sopenharmony_ci if (status) { 313362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 313462306a36Sopenharmony_ci "et131x_rx_dma_memory_alloc FAILED\n"); 313562306a36Sopenharmony_ci et131x_adapter_memory_free(adapter); 313662306a36Sopenharmony_ci return status; 313762306a36Sopenharmony_ci } 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci status = et131x_init_recv(adapter); 314062306a36Sopenharmony_ci if (status) { 314162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "et131x_init_recv FAILED\n"); 314262306a36Sopenharmony_ci et131x_adapter_memory_free(adapter); 314362306a36Sopenharmony_ci } 314462306a36Sopenharmony_ci return status; 314562306a36Sopenharmony_ci} 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_cistatic void et131x_adjust_link(struct net_device *netdev) 314862306a36Sopenharmony_ci{ 314962306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 315062306a36Sopenharmony_ci struct phy_device *phydev = netdev->phydev; 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_ci if (!phydev) 315362306a36Sopenharmony_ci return; 315462306a36Sopenharmony_ci if (phydev->link == adapter->link) 315562306a36Sopenharmony_ci return; 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_ci /* Check to see if we are in coma mode and if 315862306a36Sopenharmony_ci * so, disable it because we will not be able 315962306a36Sopenharmony_ci * to read PHY values until we are out. 316062306a36Sopenharmony_ci */ 316162306a36Sopenharmony_ci if (et1310_in_phy_coma(adapter)) 316262306a36Sopenharmony_ci et1310_disable_phy_coma(adapter); 316362306a36Sopenharmony_ci 316462306a36Sopenharmony_ci adapter->link = phydev->link; 316562306a36Sopenharmony_ci phy_print_status(phydev); 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci if (phydev->link) { 316862306a36Sopenharmony_ci adapter->boot_coma = 20; 316962306a36Sopenharmony_ci if (phydev->speed == SPEED_10) { 317062306a36Sopenharmony_ci u16 register18; 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG, 317362306a36Sopenharmony_ci ®ister18); 317462306a36Sopenharmony_ci et131x_mii_write(adapter, phydev->mdio.addr, 317562306a36Sopenharmony_ci PHY_MPHY_CONTROL_REG, 317662306a36Sopenharmony_ci register18 | 0x4); 317762306a36Sopenharmony_ci et131x_mii_write(adapter, phydev->mdio.addr, 317862306a36Sopenharmony_ci PHY_INDEX_REG, register18 | 0x8402); 317962306a36Sopenharmony_ci et131x_mii_write(adapter, phydev->mdio.addr, 318062306a36Sopenharmony_ci PHY_DATA_REG, register18 | 511); 318162306a36Sopenharmony_ci et131x_mii_write(adapter, phydev->mdio.addr, 318262306a36Sopenharmony_ci PHY_MPHY_CONTROL_REG, register18); 318362306a36Sopenharmony_ci } 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci et1310_config_flow_control(adapter); 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci if (phydev->speed == SPEED_1000 && 318862306a36Sopenharmony_ci adapter->registry_jumbo_packet > 2048) { 318962306a36Sopenharmony_ci u16 reg; 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_CONFIG, ®); 319262306a36Sopenharmony_ci reg &= ~ET_PHY_CONFIG_TX_FIFO_DEPTH; 319362306a36Sopenharmony_ci reg |= ET_PHY_CONFIG_FIFO_DEPTH_32; 319462306a36Sopenharmony_ci et131x_mii_write(adapter, phydev->mdio.addr, 319562306a36Sopenharmony_ci PHY_CONFIG, reg); 319662306a36Sopenharmony_ci } 319762306a36Sopenharmony_ci 319862306a36Sopenharmony_ci et131x_set_rx_dma_timer(adapter); 319962306a36Sopenharmony_ci et1310_config_mac_regs2(adapter); 320062306a36Sopenharmony_ci } else { 320162306a36Sopenharmony_ci adapter->boot_coma = 0; 320262306a36Sopenharmony_ci 320362306a36Sopenharmony_ci if (phydev->speed == SPEED_10) { 320462306a36Sopenharmony_ci u16 register18; 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG, 320762306a36Sopenharmony_ci ®ister18); 320862306a36Sopenharmony_ci et131x_mii_write(adapter, phydev->mdio.addr, 320962306a36Sopenharmony_ci PHY_MPHY_CONTROL_REG, 321062306a36Sopenharmony_ci register18 | 0x4); 321162306a36Sopenharmony_ci et131x_mii_write(adapter, phydev->mdio.addr, 321262306a36Sopenharmony_ci PHY_INDEX_REG, register18 | 0x8402); 321362306a36Sopenharmony_ci et131x_mii_write(adapter, phydev->mdio.addr, 321462306a36Sopenharmony_ci PHY_DATA_REG, register18 | 511); 321562306a36Sopenharmony_ci et131x_mii_write(adapter, phydev->mdio.addr, 321662306a36Sopenharmony_ci PHY_MPHY_CONTROL_REG, register18); 321762306a36Sopenharmony_ci } 321862306a36Sopenharmony_ci 321962306a36Sopenharmony_ci et131x_free_busy_send_packets(adapter); 322062306a36Sopenharmony_ci et131x_init_send(adapter); 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci /* Bring the device back to the state it was during 322362306a36Sopenharmony_ci * init prior to autonegotiation being complete. This 322462306a36Sopenharmony_ci * way, when we get the auto-neg complete interrupt, 322562306a36Sopenharmony_ci * we can complete init by calling config_mac_regs2. 322662306a36Sopenharmony_ci */ 322762306a36Sopenharmony_ci et131x_soft_reset(adapter); 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ci et131x_adapter_setup(adapter); 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci et131x_disable_txrx(netdev); 323262306a36Sopenharmony_ci et131x_enable_txrx(netdev); 323362306a36Sopenharmony_ci } 323462306a36Sopenharmony_ci} 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_cistatic int et131x_mii_probe(struct net_device *netdev) 323762306a36Sopenharmony_ci{ 323862306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 323962306a36Sopenharmony_ci struct phy_device *phydev = NULL; 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci phydev = phy_find_first(adapter->mii_bus); 324262306a36Sopenharmony_ci if (!phydev) { 324362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "no PHY found\n"); 324462306a36Sopenharmony_ci return -ENODEV; 324562306a36Sopenharmony_ci } 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_ci phydev = phy_connect(netdev, phydev_name(phydev), 324862306a36Sopenharmony_ci &et131x_adjust_link, PHY_INTERFACE_MODE_MII); 324962306a36Sopenharmony_ci 325062306a36Sopenharmony_ci if (IS_ERR(phydev)) { 325162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Could not attach to PHY\n"); 325262306a36Sopenharmony_ci return PTR_ERR(phydev); 325362306a36Sopenharmony_ci } 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci phy_set_max_speed(phydev, SPEED_100); 325662306a36Sopenharmony_ci 325762306a36Sopenharmony_ci if (adapter->pdev->device != ET131X_PCI_DEVICE_ID_FAST) 325862306a36Sopenharmony_ci phy_set_max_speed(phydev, SPEED_1000); 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci phydev->autoneg = AUTONEG_ENABLE; 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci phy_attached_info(phydev); 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ci return 0; 326562306a36Sopenharmony_ci} 326662306a36Sopenharmony_ci 326762306a36Sopenharmony_cistatic struct et131x_adapter *et131x_adapter_init(struct net_device *netdev, 326862306a36Sopenharmony_ci struct pci_dev *pdev) 326962306a36Sopenharmony_ci{ 327062306a36Sopenharmony_ci static const u8 default_mac[] = { 0x00, 0x05, 0x3d, 0x00, 0x02, 0x00 }; 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci struct et131x_adapter *adapter; 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ci adapter = netdev_priv(netdev); 327562306a36Sopenharmony_ci adapter->pdev = pci_dev_get(pdev); 327662306a36Sopenharmony_ci adapter->netdev = netdev; 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci spin_lock_init(&adapter->tcb_send_qlock); 327962306a36Sopenharmony_ci spin_lock_init(&adapter->tcb_ready_qlock); 328062306a36Sopenharmony_ci spin_lock_init(&adapter->rcv_lock); 328162306a36Sopenharmony_ci 328262306a36Sopenharmony_ci adapter->registry_jumbo_packet = 1514; /* 1514-9216 */ 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci ether_addr_copy(adapter->addr, default_mac); 328562306a36Sopenharmony_ci 328662306a36Sopenharmony_ci return adapter; 328762306a36Sopenharmony_ci} 328862306a36Sopenharmony_ci 328962306a36Sopenharmony_cistatic void et131x_pci_remove(struct pci_dev *pdev) 329062306a36Sopenharmony_ci{ 329162306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 329262306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 329362306a36Sopenharmony_ci 329462306a36Sopenharmony_ci unregister_netdev(netdev); 329562306a36Sopenharmony_ci netif_napi_del(&adapter->napi); 329662306a36Sopenharmony_ci phy_disconnect(netdev->phydev); 329762306a36Sopenharmony_ci mdiobus_unregister(adapter->mii_bus); 329862306a36Sopenharmony_ci mdiobus_free(adapter->mii_bus); 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci et131x_adapter_memory_free(adapter); 330162306a36Sopenharmony_ci iounmap(adapter->regs); 330262306a36Sopenharmony_ci pci_dev_put(pdev); 330362306a36Sopenharmony_ci 330462306a36Sopenharmony_ci free_netdev(netdev); 330562306a36Sopenharmony_ci pci_release_regions(pdev); 330662306a36Sopenharmony_ci pci_disable_device(pdev); 330762306a36Sopenharmony_ci} 330862306a36Sopenharmony_ci 330962306a36Sopenharmony_cistatic void et131x_up(struct net_device *netdev) 331062306a36Sopenharmony_ci{ 331162306a36Sopenharmony_ci et131x_enable_txrx(netdev); 331262306a36Sopenharmony_ci phy_start(netdev->phydev); 331362306a36Sopenharmony_ci} 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_cistatic void et131x_down(struct net_device *netdev) 331662306a36Sopenharmony_ci{ 331762306a36Sopenharmony_ci /* Save the timestamp for the TX watchdog, prevent a timeout */ 331862306a36Sopenharmony_ci netif_trans_update(netdev); 331962306a36Sopenharmony_ci 332062306a36Sopenharmony_ci phy_stop(netdev->phydev); 332162306a36Sopenharmony_ci et131x_disable_txrx(netdev); 332262306a36Sopenharmony_ci} 332362306a36Sopenharmony_ci 332462306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 332562306a36Sopenharmony_cistatic int et131x_suspend(struct device *dev) 332662306a36Sopenharmony_ci{ 332762306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 332862306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_ci if (netif_running(netdev)) { 333162306a36Sopenharmony_ci netif_device_detach(netdev); 333262306a36Sopenharmony_ci et131x_down(netdev); 333362306a36Sopenharmony_ci pci_save_state(pdev); 333462306a36Sopenharmony_ci } 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_ci return 0; 333762306a36Sopenharmony_ci} 333862306a36Sopenharmony_ci 333962306a36Sopenharmony_cistatic int et131x_resume(struct device *dev) 334062306a36Sopenharmony_ci{ 334162306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 334262306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 334362306a36Sopenharmony_ci 334462306a36Sopenharmony_ci if (netif_running(netdev)) { 334562306a36Sopenharmony_ci pci_restore_state(pdev); 334662306a36Sopenharmony_ci et131x_up(netdev); 334762306a36Sopenharmony_ci netif_device_attach(netdev); 334862306a36Sopenharmony_ci } 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci return 0; 335162306a36Sopenharmony_ci} 335262306a36Sopenharmony_ci#endif 335362306a36Sopenharmony_ci 335462306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(et131x_pm_ops, et131x_suspend, et131x_resume); 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_cistatic irqreturn_t et131x_isr(int irq, void *dev_id) 335762306a36Sopenharmony_ci{ 335862306a36Sopenharmony_ci bool handled = true; 335962306a36Sopenharmony_ci bool enable_interrupts = true; 336062306a36Sopenharmony_ci struct net_device *netdev = dev_id; 336162306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 336262306a36Sopenharmony_ci struct address_map __iomem *iomem = adapter->regs; 336362306a36Sopenharmony_ci struct rx_ring *rx_ring = &adapter->rx_ring; 336462306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 336562306a36Sopenharmony_ci u32 status; 336662306a36Sopenharmony_ci 336762306a36Sopenharmony_ci if (!netif_device_present(netdev)) { 336862306a36Sopenharmony_ci handled = false; 336962306a36Sopenharmony_ci enable_interrupts = false; 337062306a36Sopenharmony_ci goto out; 337162306a36Sopenharmony_ci } 337262306a36Sopenharmony_ci 337362306a36Sopenharmony_ci et131x_disable_interrupts(adapter); 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci status = readl(&adapter->regs->global.int_status); 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_ci if (adapter->flow == FLOW_TXONLY || adapter->flow == FLOW_BOTH) 337862306a36Sopenharmony_ci status &= ~INT_MASK_ENABLE; 337962306a36Sopenharmony_ci else 338062306a36Sopenharmony_ci status &= ~INT_MASK_ENABLE_NO_FLOW; 338162306a36Sopenharmony_ci 338262306a36Sopenharmony_ci /* Make sure this is our interrupt */ 338362306a36Sopenharmony_ci if (!status) { 338462306a36Sopenharmony_ci handled = false; 338562306a36Sopenharmony_ci et131x_enable_interrupts(adapter); 338662306a36Sopenharmony_ci goto out; 338762306a36Sopenharmony_ci } 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_ci /* This is our interrupt, so process accordingly */ 339062306a36Sopenharmony_ci if (status & ET_INTR_WATCHDOG) { 339162306a36Sopenharmony_ci struct tcb *tcb = tx_ring->send_head; 339262306a36Sopenharmony_ci 339362306a36Sopenharmony_ci if (tcb) 339462306a36Sopenharmony_ci if (++tcb->stale > 1) 339562306a36Sopenharmony_ci status |= ET_INTR_TXDMA_ISR; 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_ci if (rx_ring->unfinished_receives) 339862306a36Sopenharmony_ci status |= ET_INTR_RXDMA_XFR_DONE; 339962306a36Sopenharmony_ci else if (tcb == NULL) 340062306a36Sopenharmony_ci writel(0, &adapter->regs->global.watchdog_timer); 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_ci status &= ~ET_INTR_WATCHDOG; 340362306a36Sopenharmony_ci } 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci if (status & (ET_INTR_RXDMA_XFR_DONE | ET_INTR_TXDMA_ISR)) { 340662306a36Sopenharmony_ci enable_interrupts = false; 340762306a36Sopenharmony_ci napi_schedule(&adapter->napi); 340862306a36Sopenharmony_ci } 340962306a36Sopenharmony_ci 341062306a36Sopenharmony_ci status &= ~(ET_INTR_TXDMA_ISR | ET_INTR_RXDMA_XFR_DONE); 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_ci if (!status) 341362306a36Sopenharmony_ci goto out; 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci if (status & ET_INTR_TXDMA_ERR) { 341662306a36Sopenharmony_ci /* Following read also clears the register (COR) */ 341762306a36Sopenharmony_ci u32 txdma_err = readl(&iomem->txdma.tx_dma_error); 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, 342062306a36Sopenharmony_ci "TXDMA_ERR interrupt, error = %d\n", 342162306a36Sopenharmony_ci txdma_err); 342262306a36Sopenharmony_ci } 342362306a36Sopenharmony_ci 342462306a36Sopenharmony_ci if (status & (ET_INTR_RXDMA_FB_R0_LOW | ET_INTR_RXDMA_FB_R1_LOW)) { 342562306a36Sopenharmony_ci /* This indicates the number of unused buffers in RXDMA free 342662306a36Sopenharmony_ci * buffer ring 0 is <= the limit you programmed. Free buffer 342762306a36Sopenharmony_ci * resources need to be returned. Free buffers are consumed as 342862306a36Sopenharmony_ci * packets are passed from the network to the host. The host 342962306a36Sopenharmony_ci * becomes aware of the packets from the contents of the packet 343062306a36Sopenharmony_ci * status ring. This ring is queried when the packet done 343162306a36Sopenharmony_ci * interrupt occurs. Packets are then passed to the OS. When 343262306a36Sopenharmony_ci * the OS is done with the packets the resources can be 343362306a36Sopenharmony_ci * returned to the ET1310 for re-use. This interrupt is one 343462306a36Sopenharmony_ci * method of returning resources. 343562306a36Sopenharmony_ci */ 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci /* If the user has flow control on, then we will 343862306a36Sopenharmony_ci * send a pause packet, otherwise just exit 343962306a36Sopenharmony_ci */ 344062306a36Sopenharmony_ci if (adapter->flow == FLOW_TXONLY || adapter->flow == FLOW_BOTH) { 344162306a36Sopenharmony_ci /* Tell the device to send a pause packet via the back 344262306a36Sopenharmony_ci * pressure register (bp req and bp xon/xoff) 344362306a36Sopenharmony_ci */ 344462306a36Sopenharmony_ci if (!et1310_in_phy_coma(adapter)) 344562306a36Sopenharmony_ci writel(3, &iomem->txmac.bp_ctrl); 344662306a36Sopenharmony_ci } 344762306a36Sopenharmony_ci } 344862306a36Sopenharmony_ci 344962306a36Sopenharmony_ci /* Handle Packet Status Ring Low Interrupt */ 345062306a36Sopenharmony_ci if (status & ET_INTR_RXDMA_STAT_LOW) { 345162306a36Sopenharmony_ci /* Same idea as with the two Free Buffer Rings. Packets going 345262306a36Sopenharmony_ci * from the network to the host each consume a free buffer 345362306a36Sopenharmony_ci * resource and a packet status resource. These resources are 345462306a36Sopenharmony_ci * passed to the OS. When the OS is done with the resources, 345562306a36Sopenharmony_ci * they need to be returned to the ET1310. This is one method 345662306a36Sopenharmony_ci * of returning the resources. 345762306a36Sopenharmony_ci */ 345862306a36Sopenharmony_ci } 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci if (status & ET_INTR_RXDMA_ERR) { 346162306a36Sopenharmony_ci /* The rxdma_error interrupt is sent when a time-out on a 346262306a36Sopenharmony_ci * request issued by the JAGCore has occurred or a completion is 346362306a36Sopenharmony_ci * returned with an un-successful status. In both cases the 346462306a36Sopenharmony_ci * request is considered complete. The JAGCore will 346562306a36Sopenharmony_ci * automatically re-try the request in question. Normally 346662306a36Sopenharmony_ci * information on events like these are sent to the host using 346762306a36Sopenharmony_ci * the "Advanced Error Reporting" capability. This interrupt is 346862306a36Sopenharmony_ci * another way of getting similar information. The only thing 346962306a36Sopenharmony_ci * required is to clear the interrupt by reading the ISR in the 347062306a36Sopenharmony_ci * global resources. The JAGCore will do a re-try on the 347162306a36Sopenharmony_ci * request. Normally you should never see this interrupt. If 347262306a36Sopenharmony_ci * you start to see this interrupt occurring frequently then 347362306a36Sopenharmony_ci * something bad has occurred. A reset might be the thing to do. 347462306a36Sopenharmony_ci */ 347562306a36Sopenharmony_ci /* TRAP();*/ 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, "RxDMA_ERR interrupt, error %x\n", 347862306a36Sopenharmony_ci readl(&iomem->txmac.tx_test)); 347962306a36Sopenharmony_ci } 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_ci /* Handle the Wake on LAN Event */ 348262306a36Sopenharmony_ci if (status & ET_INTR_WOL) { 348362306a36Sopenharmony_ci /* This is a secondary interrupt for wake on LAN. The driver 348462306a36Sopenharmony_ci * should never see this, if it does, something serious is 348562306a36Sopenharmony_ci * wrong. 348662306a36Sopenharmony_ci */ 348762306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "WAKE_ON_LAN interrupt\n"); 348862306a36Sopenharmony_ci } 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci if (status & ET_INTR_TXMAC) { 349162306a36Sopenharmony_ci u32 err = readl(&iomem->txmac.err); 349262306a36Sopenharmony_ci 349362306a36Sopenharmony_ci /* When any of the errors occur and TXMAC generates an 349462306a36Sopenharmony_ci * interrupt to report these errors, it usually means that 349562306a36Sopenharmony_ci * TXMAC has detected an error in the data stream retrieved 349662306a36Sopenharmony_ci * from the on-chip Tx Q. All of these errors are catastrophic 349762306a36Sopenharmony_ci * and TXMAC won't be able to recover data when these errors 349862306a36Sopenharmony_ci * occur. In a nutshell, the whole Tx path will have to be reset 349962306a36Sopenharmony_ci * and re-configured afterwards. 350062306a36Sopenharmony_ci */ 350162306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, "TXMAC interrupt, error 0x%08x\n", 350262306a36Sopenharmony_ci err); 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci /* If we are debugging, we want to see this error, otherwise we 350562306a36Sopenharmony_ci * just want the device to be reset and continue 350662306a36Sopenharmony_ci */ 350762306a36Sopenharmony_ci } 350862306a36Sopenharmony_ci 350962306a36Sopenharmony_ci if (status & ET_INTR_RXMAC) { 351062306a36Sopenharmony_ci /* These interrupts are catastrophic to the device, what we need 351162306a36Sopenharmony_ci * to do is disable the interrupts and set the flag to cause us 351262306a36Sopenharmony_ci * to reset so we can solve this issue. 351362306a36Sopenharmony_ci */ 351462306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, 351562306a36Sopenharmony_ci "RXMAC interrupt, error 0x%08x. Requesting reset\n", 351662306a36Sopenharmony_ci readl(&iomem->rxmac.err_reg)); 351762306a36Sopenharmony_ci 351862306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, 351962306a36Sopenharmony_ci "Enable 0x%08x, Diag 0x%08x\n", 352062306a36Sopenharmony_ci readl(&iomem->rxmac.ctrl), 352162306a36Sopenharmony_ci readl(&iomem->rxmac.rxq_diag)); 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_ci /* If we are debugging, we want to see this error, otherwise we 352462306a36Sopenharmony_ci * just want the device to be reset and continue 352562306a36Sopenharmony_ci */ 352662306a36Sopenharmony_ci } 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci if (status & ET_INTR_MAC_STAT) { 352962306a36Sopenharmony_ci /* This means at least one of the un-masked counters in the 353062306a36Sopenharmony_ci * MAC_STAT block has rolled over. Use this to maintain the top, 353162306a36Sopenharmony_ci * software managed bits of the counter(s). 353262306a36Sopenharmony_ci */ 353362306a36Sopenharmony_ci et1310_handle_macstat_interrupt(adapter); 353462306a36Sopenharmony_ci } 353562306a36Sopenharmony_ci 353662306a36Sopenharmony_ci if (status & ET_INTR_SLV_TIMEOUT) { 353762306a36Sopenharmony_ci /* This means a timeout has occurred on a read or write request 353862306a36Sopenharmony_ci * to one of the JAGCore registers. The Global Resources block 353962306a36Sopenharmony_ci * has terminated the request and on a read request, returned a 354062306a36Sopenharmony_ci * "fake" value. The most likely reasons are: Bad Address or the 354162306a36Sopenharmony_ci * addressed module is in a power-down state and can't respond. 354262306a36Sopenharmony_ci */ 354362306a36Sopenharmony_ci } 354462306a36Sopenharmony_ci 354562306a36Sopenharmony_ciout: 354662306a36Sopenharmony_ci if (enable_interrupts) 354762306a36Sopenharmony_ci et131x_enable_interrupts(adapter); 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci return IRQ_RETVAL(handled); 355062306a36Sopenharmony_ci} 355162306a36Sopenharmony_ci 355262306a36Sopenharmony_cistatic int et131x_poll(struct napi_struct *napi, int budget) 355362306a36Sopenharmony_ci{ 355462306a36Sopenharmony_ci struct et131x_adapter *adapter = 355562306a36Sopenharmony_ci container_of(napi, struct et131x_adapter, napi); 355662306a36Sopenharmony_ci int work_done = et131x_handle_recv_pkts(adapter, budget); 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_ci et131x_handle_send_pkts(adapter); 355962306a36Sopenharmony_ci 356062306a36Sopenharmony_ci if (work_done < budget) { 356162306a36Sopenharmony_ci napi_complete_done(&adapter->napi, work_done); 356262306a36Sopenharmony_ci et131x_enable_interrupts(adapter); 356362306a36Sopenharmony_ci } 356462306a36Sopenharmony_ci 356562306a36Sopenharmony_ci return work_done; 356662306a36Sopenharmony_ci} 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci/* et131x_stats - Return the current device statistics */ 356962306a36Sopenharmony_cistatic struct net_device_stats *et131x_stats(struct net_device *netdev) 357062306a36Sopenharmony_ci{ 357162306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 357262306a36Sopenharmony_ci struct net_device_stats *stats = &adapter->netdev->stats; 357362306a36Sopenharmony_ci struct ce_stats *devstat = &adapter->stats; 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci stats->rx_errors = devstat->rx_length_errs + 357662306a36Sopenharmony_ci devstat->rx_align_errs + 357762306a36Sopenharmony_ci devstat->rx_crc_errs + 357862306a36Sopenharmony_ci devstat->rx_code_violations + 357962306a36Sopenharmony_ci devstat->rx_other_errs; 358062306a36Sopenharmony_ci stats->tx_errors = devstat->tx_max_pkt_errs; 358162306a36Sopenharmony_ci stats->multicast = devstat->multicast_pkts_rcvd; 358262306a36Sopenharmony_ci stats->collisions = devstat->tx_collisions; 358362306a36Sopenharmony_ci 358462306a36Sopenharmony_ci stats->rx_length_errors = devstat->rx_length_errs; 358562306a36Sopenharmony_ci stats->rx_over_errors = devstat->rx_overflows; 358662306a36Sopenharmony_ci stats->rx_crc_errors = devstat->rx_crc_errs; 358762306a36Sopenharmony_ci stats->rx_dropped = devstat->rcvd_pkts_dropped; 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_ci /* NOTE: Not used, can't find analogous statistics */ 359062306a36Sopenharmony_ci /* stats->rx_frame_errors = devstat->; */ 359162306a36Sopenharmony_ci /* stats->rx_fifo_errors = devstat->; */ 359262306a36Sopenharmony_ci /* stats->rx_missed_errors = devstat->; */ 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci /* stats->tx_aborted_errors = devstat->; */ 359562306a36Sopenharmony_ci /* stats->tx_carrier_errors = devstat->; */ 359662306a36Sopenharmony_ci /* stats->tx_fifo_errors = devstat->; */ 359762306a36Sopenharmony_ci /* stats->tx_heartbeat_errors = devstat->; */ 359862306a36Sopenharmony_ci /* stats->tx_window_errors = devstat->; */ 359962306a36Sopenharmony_ci return stats; 360062306a36Sopenharmony_ci} 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_cistatic int et131x_open(struct net_device *netdev) 360362306a36Sopenharmony_ci{ 360462306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 360562306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 360662306a36Sopenharmony_ci unsigned int irq = pdev->irq; 360762306a36Sopenharmony_ci int result; 360862306a36Sopenharmony_ci 360962306a36Sopenharmony_ci /* Start the timer to track NIC errors */ 361062306a36Sopenharmony_ci timer_setup(&adapter->error_timer, et131x_error_timer_handler, 0); 361162306a36Sopenharmony_ci adapter->error_timer.expires = jiffies + 361262306a36Sopenharmony_ci msecs_to_jiffies(TX_ERROR_PERIOD); 361362306a36Sopenharmony_ci add_timer(&adapter->error_timer); 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_ci result = request_irq(irq, et131x_isr, 361662306a36Sopenharmony_ci IRQF_SHARED, netdev->name, netdev); 361762306a36Sopenharmony_ci if (result) { 361862306a36Sopenharmony_ci dev_err(&pdev->dev, "could not register IRQ %d\n", irq); 361962306a36Sopenharmony_ci return result; 362062306a36Sopenharmony_ci } 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci adapter->flags |= FMP_ADAPTER_INTERRUPT_IN_USE; 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci napi_enable(&adapter->napi); 362562306a36Sopenharmony_ci 362662306a36Sopenharmony_ci et131x_up(netdev); 362762306a36Sopenharmony_ci 362862306a36Sopenharmony_ci return result; 362962306a36Sopenharmony_ci} 363062306a36Sopenharmony_ci 363162306a36Sopenharmony_cistatic int et131x_close(struct net_device *netdev) 363262306a36Sopenharmony_ci{ 363362306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci et131x_down(netdev); 363662306a36Sopenharmony_ci napi_disable(&adapter->napi); 363762306a36Sopenharmony_ci 363862306a36Sopenharmony_ci adapter->flags &= ~FMP_ADAPTER_INTERRUPT_IN_USE; 363962306a36Sopenharmony_ci free_irq(adapter->pdev->irq, netdev); 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_ci /* Stop the error timer */ 364262306a36Sopenharmony_ci return del_timer_sync(&adapter->error_timer); 364362306a36Sopenharmony_ci} 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci/* et131x_set_packet_filter - Configures the Rx Packet filtering */ 364662306a36Sopenharmony_cistatic int et131x_set_packet_filter(struct et131x_adapter *adapter) 364762306a36Sopenharmony_ci{ 364862306a36Sopenharmony_ci int filter = adapter->packet_filter; 364962306a36Sopenharmony_ci u32 ctrl; 365062306a36Sopenharmony_ci u32 pf_ctrl; 365162306a36Sopenharmony_ci 365262306a36Sopenharmony_ci ctrl = readl(&adapter->regs->rxmac.ctrl); 365362306a36Sopenharmony_ci pf_ctrl = readl(&adapter->regs->rxmac.pf_ctrl); 365462306a36Sopenharmony_ci 365562306a36Sopenharmony_ci /* Default to disabled packet filtering */ 365662306a36Sopenharmony_ci ctrl |= 0x04; 365762306a36Sopenharmony_ci 365862306a36Sopenharmony_ci /* Set us to be in promiscuous mode so we receive everything, this 365962306a36Sopenharmony_ci * is also true when we get a packet filter of 0 366062306a36Sopenharmony_ci */ 366162306a36Sopenharmony_ci if ((filter & ET131X_PACKET_TYPE_PROMISCUOUS) || filter == 0) 366262306a36Sopenharmony_ci pf_ctrl &= ~7; /* Clear filter bits */ 366362306a36Sopenharmony_ci else { 366462306a36Sopenharmony_ci /* Set us up with Multicast packet filtering. Three cases are 366562306a36Sopenharmony_ci * possible - (1) we have a multi-cast list, (2) we receive ALL 366662306a36Sopenharmony_ci * multicast entries or (3) we receive none. 366762306a36Sopenharmony_ci */ 366862306a36Sopenharmony_ci if (filter & ET131X_PACKET_TYPE_ALL_MULTICAST) 366962306a36Sopenharmony_ci pf_ctrl &= ~2; /* Multicast filter bit */ 367062306a36Sopenharmony_ci else { 367162306a36Sopenharmony_ci et1310_setup_device_for_multicast(adapter); 367262306a36Sopenharmony_ci pf_ctrl |= 2; 367362306a36Sopenharmony_ci ctrl &= ~0x04; 367462306a36Sopenharmony_ci } 367562306a36Sopenharmony_ci 367662306a36Sopenharmony_ci /* Set us up with Unicast packet filtering */ 367762306a36Sopenharmony_ci if (filter & ET131X_PACKET_TYPE_DIRECTED) { 367862306a36Sopenharmony_ci et1310_setup_device_for_unicast(adapter); 367962306a36Sopenharmony_ci pf_ctrl |= 4; 368062306a36Sopenharmony_ci ctrl &= ~0x04; 368162306a36Sopenharmony_ci } 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci /* Set us up with Broadcast packet filtering */ 368462306a36Sopenharmony_ci if (filter & ET131X_PACKET_TYPE_BROADCAST) { 368562306a36Sopenharmony_ci pf_ctrl |= 1; /* Broadcast filter bit */ 368662306a36Sopenharmony_ci ctrl &= ~0x04; 368762306a36Sopenharmony_ci } else { 368862306a36Sopenharmony_ci pf_ctrl &= ~1; 368962306a36Sopenharmony_ci } 369062306a36Sopenharmony_ci 369162306a36Sopenharmony_ci /* Setup the receive mac configuration registers - Packet 369262306a36Sopenharmony_ci * Filter control + the enable / disable for packet filter 369362306a36Sopenharmony_ci * in the control reg. 369462306a36Sopenharmony_ci */ 369562306a36Sopenharmony_ci writel(pf_ctrl, &adapter->regs->rxmac.pf_ctrl); 369662306a36Sopenharmony_ci writel(ctrl, &adapter->regs->rxmac.ctrl); 369762306a36Sopenharmony_ci } 369862306a36Sopenharmony_ci return 0; 369962306a36Sopenharmony_ci} 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_cistatic void et131x_multicast(struct net_device *netdev) 370262306a36Sopenharmony_ci{ 370362306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 370462306a36Sopenharmony_ci int packet_filter; 370562306a36Sopenharmony_ci struct netdev_hw_addr *ha; 370662306a36Sopenharmony_ci int i; 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci /* Before we modify the platform-independent filter flags, store them 370962306a36Sopenharmony_ci * locally. This allows us to determine if anything's changed and if 371062306a36Sopenharmony_ci * we even need to bother the hardware 371162306a36Sopenharmony_ci */ 371262306a36Sopenharmony_ci packet_filter = adapter->packet_filter; 371362306a36Sopenharmony_ci 371462306a36Sopenharmony_ci /* Clear the 'multicast' flag locally; because we only have a single 371562306a36Sopenharmony_ci * flag to check multicast, and multiple multicast addresses can be 371662306a36Sopenharmony_ci * set, this is the easiest way to determine if more than one 371762306a36Sopenharmony_ci * multicast address is being set. 371862306a36Sopenharmony_ci */ 371962306a36Sopenharmony_ci packet_filter &= ~ET131X_PACKET_TYPE_MULTICAST; 372062306a36Sopenharmony_ci 372162306a36Sopenharmony_ci /* Check the net_device flags and set the device independent flags 372262306a36Sopenharmony_ci * accordingly 372362306a36Sopenharmony_ci */ 372462306a36Sopenharmony_ci if (netdev->flags & IFF_PROMISC) 372562306a36Sopenharmony_ci adapter->packet_filter |= ET131X_PACKET_TYPE_PROMISCUOUS; 372662306a36Sopenharmony_ci else 372762306a36Sopenharmony_ci adapter->packet_filter &= ~ET131X_PACKET_TYPE_PROMISCUOUS; 372862306a36Sopenharmony_ci 372962306a36Sopenharmony_ci if ((netdev->flags & IFF_ALLMULTI) || 373062306a36Sopenharmony_ci (netdev_mc_count(netdev) > NIC_MAX_MCAST_LIST)) 373162306a36Sopenharmony_ci adapter->packet_filter |= ET131X_PACKET_TYPE_ALL_MULTICAST; 373262306a36Sopenharmony_ci 373362306a36Sopenharmony_ci if (netdev_mc_count(netdev) < 1) { 373462306a36Sopenharmony_ci adapter->packet_filter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST; 373562306a36Sopenharmony_ci adapter->packet_filter &= ~ET131X_PACKET_TYPE_MULTICAST; 373662306a36Sopenharmony_ci } else { 373762306a36Sopenharmony_ci adapter->packet_filter |= ET131X_PACKET_TYPE_MULTICAST; 373862306a36Sopenharmony_ci } 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci /* Set values in the private adapter struct */ 374162306a36Sopenharmony_ci i = 0; 374262306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) { 374362306a36Sopenharmony_ci if (i == NIC_MAX_MCAST_LIST) 374462306a36Sopenharmony_ci break; 374562306a36Sopenharmony_ci ether_addr_copy(adapter->multicast_list[i++], ha->addr); 374662306a36Sopenharmony_ci } 374762306a36Sopenharmony_ci adapter->multicast_addr_count = i; 374862306a36Sopenharmony_ci 374962306a36Sopenharmony_ci /* Are the new flags different from the previous ones? If not, then no 375062306a36Sopenharmony_ci * action is required 375162306a36Sopenharmony_ci * 375262306a36Sopenharmony_ci * NOTE - This block will always update the multicast_list with the 375362306a36Sopenharmony_ci * hardware, even if the addresses aren't the same. 375462306a36Sopenharmony_ci */ 375562306a36Sopenharmony_ci if (packet_filter != adapter->packet_filter) 375662306a36Sopenharmony_ci et131x_set_packet_filter(adapter); 375762306a36Sopenharmony_ci} 375862306a36Sopenharmony_ci 375962306a36Sopenharmony_cistatic netdev_tx_t et131x_tx(struct sk_buff *skb, struct net_device *netdev) 376062306a36Sopenharmony_ci{ 376162306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 376262306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_ci /* This driver does not support TSO, it is very unlikely 376562306a36Sopenharmony_ci * this condition is true. 376662306a36Sopenharmony_ci */ 376762306a36Sopenharmony_ci if (unlikely(skb_shinfo(skb)->nr_frags > MAX_TX_DESC_PER_PKT - 2)) { 376862306a36Sopenharmony_ci if (skb_linearize(skb)) 376962306a36Sopenharmony_ci goto drop_err; 377062306a36Sopenharmony_ci } 377162306a36Sopenharmony_ci /* stop the queue if it's getting full */ 377262306a36Sopenharmony_ci if (tx_ring->used >= NUM_TCB - 1 && !netif_queue_stopped(netdev)) 377362306a36Sopenharmony_ci netif_stop_queue(netdev); 377462306a36Sopenharmony_ci 377562306a36Sopenharmony_ci /* Save the timestamp for the TX timeout watchdog */ 377662306a36Sopenharmony_ci netif_trans_update(netdev); 377762306a36Sopenharmony_ci 377862306a36Sopenharmony_ci /* TCB is not available */ 377962306a36Sopenharmony_ci if (tx_ring->used >= NUM_TCB) 378062306a36Sopenharmony_ci goto drop_err; 378162306a36Sopenharmony_ci 378262306a36Sopenharmony_ci if ((adapter->flags & FMP_ADAPTER_FAIL_SEND_MASK) || 378362306a36Sopenharmony_ci !netif_carrier_ok(netdev)) 378462306a36Sopenharmony_ci goto drop_err; 378562306a36Sopenharmony_ci 378662306a36Sopenharmony_ci if (send_packet(skb, adapter)) 378762306a36Sopenharmony_ci goto drop_err; 378862306a36Sopenharmony_ci 378962306a36Sopenharmony_ci return NETDEV_TX_OK; 379062306a36Sopenharmony_ci 379162306a36Sopenharmony_cidrop_err: 379262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 379362306a36Sopenharmony_ci adapter->netdev->stats.tx_dropped++; 379462306a36Sopenharmony_ci return NETDEV_TX_OK; 379562306a36Sopenharmony_ci} 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_ci/* et131x_tx_timeout - Timeout handler 379862306a36Sopenharmony_ci * 379962306a36Sopenharmony_ci * The handler called when a Tx request times out. The timeout period is 380062306a36Sopenharmony_ci * specified by the 'tx_timeo" element in the net_device structure (see 380162306a36Sopenharmony_ci * et131x_alloc_device() to see how this value is set). 380262306a36Sopenharmony_ci */ 380362306a36Sopenharmony_cistatic void et131x_tx_timeout(struct net_device *netdev, unsigned int txqueue) 380462306a36Sopenharmony_ci{ 380562306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 380662306a36Sopenharmony_ci struct tx_ring *tx_ring = &adapter->tx_ring; 380762306a36Sopenharmony_ci struct tcb *tcb; 380862306a36Sopenharmony_ci unsigned long flags; 380962306a36Sopenharmony_ci 381062306a36Sopenharmony_ci /* If the device is closed, ignore the timeout */ 381162306a36Sopenharmony_ci if (!(adapter->flags & FMP_ADAPTER_INTERRUPT_IN_USE)) 381262306a36Sopenharmony_ci return; 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci /* Any nonrecoverable hardware error? 381562306a36Sopenharmony_ci * Checks adapter->flags for any failure in phy reading 381662306a36Sopenharmony_ci */ 381762306a36Sopenharmony_ci if (adapter->flags & FMP_ADAPTER_NON_RECOVER_ERROR) 381862306a36Sopenharmony_ci return; 381962306a36Sopenharmony_ci 382062306a36Sopenharmony_ci /* Hardware failure? */ 382162306a36Sopenharmony_ci if (adapter->flags & FMP_ADAPTER_HARDWARE_ERROR) { 382262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "hardware error - reset\n"); 382362306a36Sopenharmony_ci return; 382462306a36Sopenharmony_ci } 382562306a36Sopenharmony_ci 382662306a36Sopenharmony_ci /* Is send stuck? */ 382762306a36Sopenharmony_ci spin_lock_irqsave(&adapter->tcb_send_qlock, flags); 382862306a36Sopenharmony_ci tcb = tx_ring->send_head; 382962306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tcb_send_qlock, flags); 383062306a36Sopenharmony_ci 383162306a36Sopenharmony_ci if (tcb) { 383262306a36Sopenharmony_ci tcb->count++; 383362306a36Sopenharmony_ci 383462306a36Sopenharmony_ci if (tcb->count > NIC_SEND_HANG_THRESHOLD) { 383562306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, 383662306a36Sopenharmony_ci "Send stuck - reset. tcb->WrIndex %x\n", 383762306a36Sopenharmony_ci tcb->index); 383862306a36Sopenharmony_ci 383962306a36Sopenharmony_ci adapter->netdev->stats.tx_errors++; 384062306a36Sopenharmony_ci 384162306a36Sopenharmony_ci /* perform reset of tx/rx */ 384262306a36Sopenharmony_ci et131x_disable_txrx(netdev); 384362306a36Sopenharmony_ci et131x_enable_txrx(netdev); 384462306a36Sopenharmony_ci } 384562306a36Sopenharmony_ci } 384662306a36Sopenharmony_ci} 384762306a36Sopenharmony_ci 384862306a36Sopenharmony_cistatic int et131x_change_mtu(struct net_device *netdev, int new_mtu) 384962306a36Sopenharmony_ci{ 385062306a36Sopenharmony_ci int result = 0; 385162306a36Sopenharmony_ci struct et131x_adapter *adapter = netdev_priv(netdev); 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ci et131x_disable_txrx(netdev); 385462306a36Sopenharmony_ci 385562306a36Sopenharmony_ci netdev->mtu = new_mtu; 385662306a36Sopenharmony_ci 385762306a36Sopenharmony_ci et131x_adapter_memory_free(adapter); 385862306a36Sopenharmony_ci 385962306a36Sopenharmony_ci /* Set the config parameter for Jumbo Packet support */ 386062306a36Sopenharmony_ci adapter->registry_jumbo_packet = new_mtu + 14; 386162306a36Sopenharmony_ci et131x_soft_reset(adapter); 386262306a36Sopenharmony_ci 386362306a36Sopenharmony_ci result = et131x_adapter_memory_alloc(adapter); 386462306a36Sopenharmony_ci if (result != 0) { 386562306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, 386662306a36Sopenharmony_ci "Change MTU failed; couldn't re-alloc DMA memory\n"); 386762306a36Sopenharmony_ci return result; 386862306a36Sopenharmony_ci } 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci et131x_init_send(adapter); 387162306a36Sopenharmony_ci et131x_hwaddr_init(adapter); 387262306a36Sopenharmony_ci eth_hw_addr_set(netdev, adapter->addr); 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci /* Init the device with the new settings */ 387562306a36Sopenharmony_ci et131x_adapter_setup(adapter); 387662306a36Sopenharmony_ci et131x_enable_txrx(netdev); 387762306a36Sopenharmony_ci 387862306a36Sopenharmony_ci return result; 387962306a36Sopenharmony_ci} 388062306a36Sopenharmony_ci 388162306a36Sopenharmony_cistatic const struct net_device_ops et131x_netdev_ops = { 388262306a36Sopenharmony_ci .ndo_open = et131x_open, 388362306a36Sopenharmony_ci .ndo_stop = et131x_close, 388462306a36Sopenharmony_ci .ndo_start_xmit = et131x_tx, 388562306a36Sopenharmony_ci .ndo_set_rx_mode = et131x_multicast, 388662306a36Sopenharmony_ci .ndo_tx_timeout = et131x_tx_timeout, 388762306a36Sopenharmony_ci .ndo_change_mtu = et131x_change_mtu, 388862306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 388962306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 389062306a36Sopenharmony_ci .ndo_get_stats = et131x_stats, 389162306a36Sopenharmony_ci .ndo_eth_ioctl = phy_do_ioctl, 389262306a36Sopenharmony_ci}; 389362306a36Sopenharmony_ci 389462306a36Sopenharmony_cistatic int et131x_pci_setup(struct pci_dev *pdev, 389562306a36Sopenharmony_ci const struct pci_device_id *ent) 389662306a36Sopenharmony_ci{ 389762306a36Sopenharmony_ci struct net_device *netdev; 389862306a36Sopenharmony_ci struct et131x_adapter *adapter; 389962306a36Sopenharmony_ci int rc; 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ci rc = pci_enable_device(pdev); 390262306a36Sopenharmony_ci if (rc < 0) { 390362306a36Sopenharmony_ci dev_err(&pdev->dev, "pci_enable_device() failed\n"); 390462306a36Sopenharmony_ci goto out; 390562306a36Sopenharmony_ci } 390662306a36Sopenharmony_ci 390762306a36Sopenharmony_ci /* Perform some basic PCI checks */ 390862306a36Sopenharmony_ci if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 390962306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't find PCI device's base address\n"); 391062306a36Sopenharmony_ci rc = -ENODEV; 391162306a36Sopenharmony_ci goto err_disable; 391262306a36Sopenharmony_ci } 391362306a36Sopenharmony_ci 391462306a36Sopenharmony_ci rc = pci_request_regions(pdev, DRIVER_NAME); 391562306a36Sopenharmony_ci if (rc < 0) { 391662306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't get PCI resources\n"); 391762306a36Sopenharmony_ci goto err_disable; 391862306a36Sopenharmony_ci } 391962306a36Sopenharmony_ci 392062306a36Sopenharmony_ci pci_set_master(pdev); 392162306a36Sopenharmony_ci 392262306a36Sopenharmony_ci /* Check the DMA addressing support of this device */ 392362306a36Sopenharmony_ci rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 392462306a36Sopenharmony_ci if (rc) { 392562306a36Sopenharmony_ci dev_err(&pdev->dev, "No usable DMA addressing method\n"); 392662306a36Sopenharmony_ci goto err_release_res; 392762306a36Sopenharmony_ci } 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_ci netdev = alloc_etherdev(sizeof(struct et131x_adapter)); 393062306a36Sopenharmony_ci if (!netdev) { 393162306a36Sopenharmony_ci dev_err(&pdev->dev, "Couldn't alloc netdev struct\n"); 393262306a36Sopenharmony_ci rc = -ENOMEM; 393362306a36Sopenharmony_ci goto err_release_res; 393462306a36Sopenharmony_ci } 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci netdev->watchdog_timeo = ET131X_TX_TIMEOUT; 393762306a36Sopenharmony_ci netdev->netdev_ops = &et131x_netdev_ops; 393862306a36Sopenharmony_ci netdev->min_mtu = ET131X_MIN_MTU; 393962306a36Sopenharmony_ci netdev->max_mtu = ET131X_MAX_MTU; 394062306a36Sopenharmony_ci 394162306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 394262306a36Sopenharmony_ci netdev->ethtool_ops = &et131x_ethtool_ops; 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ci adapter = et131x_adapter_init(netdev, pdev); 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_ci rc = et131x_pci_init(adapter, pdev); 394762306a36Sopenharmony_ci if (rc < 0) 394862306a36Sopenharmony_ci goto err_free_dev; 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_ci /* Map the bus-relative registers to system virtual memory */ 395162306a36Sopenharmony_ci adapter->regs = pci_ioremap_bar(pdev, 0); 395262306a36Sopenharmony_ci if (!adapter->regs) { 395362306a36Sopenharmony_ci dev_err(&pdev->dev, "Cannot map device registers\n"); 395462306a36Sopenharmony_ci rc = -ENOMEM; 395562306a36Sopenharmony_ci goto err_free_dev; 395662306a36Sopenharmony_ci } 395762306a36Sopenharmony_ci 395862306a36Sopenharmony_ci /* If Phy COMA mode was enabled when we went down, disable it here. */ 395962306a36Sopenharmony_ci writel(ET_PMCSR_INIT, &adapter->regs->global.pm_csr); 396062306a36Sopenharmony_ci 396162306a36Sopenharmony_ci et131x_soft_reset(adapter); 396262306a36Sopenharmony_ci et131x_disable_interrupts(adapter); 396362306a36Sopenharmony_ci 396462306a36Sopenharmony_ci rc = et131x_adapter_memory_alloc(adapter); 396562306a36Sopenharmony_ci if (rc < 0) { 396662306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not alloc adapter memory (DMA)\n"); 396762306a36Sopenharmony_ci goto err_iounmap; 396862306a36Sopenharmony_ci } 396962306a36Sopenharmony_ci 397062306a36Sopenharmony_ci et131x_init_send(adapter); 397162306a36Sopenharmony_ci 397262306a36Sopenharmony_ci netif_napi_add(netdev, &adapter->napi, et131x_poll); 397362306a36Sopenharmony_ci 397462306a36Sopenharmony_ci eth_hw_addr_set(netdev, adapter->addr); 397562306a36Sopenharmony_ci 397662306a36Sopenharmony_ci rc = -ENOMEM; 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_ci adapter->mii_bus = mdiobus_alloc(); 397962306a36Sopenharmony_ci if (!adapter->mii_bus) { 398062306a36Sopenharmony_ci dev_err(&pdev->dev, "Alloc of mii_bus struct failed\n"); 398162306a36Sopenharmony_ci goto err_mem_free; 398262306a36Sopenharmony_ci } 398362306a36Sopenharmony_ci 398462306a36Sopenharmony_ci adapter->mii_bus->name = "et131x_eth_mii"; 398562306a36Sopenharmony_ci snprintf(adapter->mii_bus->id, MII_BUS_ID_SIZE, "%x", pci_dev_id(adapter->pdev)); 398662306a36Sopenharmony_ci adapter->mii_bus->priv = netdev; 398762306a36Sopenharmony_ci adapter->mii_bus->read = et131x_mdio_read; 398862306a36Sopenharmony_ci adapter->mii_bus->write = et131x_mdio_write; 398962306a36Sopenharmony_ci 399062306a36Sopenharmony_ci rc = mdiobus_register(adapter->mii_bus); 399162306a36Sopenharmony_ci if (rc < 0) { 399262306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register MII bus\n"); 399362306a36Sopenharmony_ci goto err_mdio_free; 399462306a36Sopenharmony_ci } 399562306a36Sopenharmony_ci 399662306a36Sopenharmony_ci rc = et131x_mii_probe(netdev); 399762306a36Sopenharmony_ci if (rc < 0) { 399862306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to probe MII bus\n"); 399962306a36Sopenharmony_ci goto err_mdio_unregister; 400062306a36Sopenharmony_ci } 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci et131x_adapter_setup(adapter); 400362306a36Sopenharmony_ci 400462306a36Sopenharmony_ci /* Init variable for counting how long we do not have link status */ 400562306a36Sopenharmony_ci adapter->boot_coma = 0; 400662306a36Sopenharmony_ci et1310_disable_phy_coma(adapter); 400762306a36Sopenharmony_ci 400862306a36Sopenharmony_ci /* We can enable interrupts now 400962306a36Sopenharmony_ci * 401062306a36Sopenharmony_ci * NOTE - Because registration of interrupt handler is done in the 401162306a36Sopenharmony_ci * device's open(), defer enabling device interrupts to that 401262306a36Sopenharmony_ci * point 401362306a36Sopenharmony_ci */ 401462306a36Sopenharmony_ci 401562306a36Sopenharmony_ci rc = register_netdev(netdev); 401662306a36Sopenharmony_ci if (rc < 0) { 401762306a36Sopenharmony_ci dev_err(&pdev->dev, "register_netdev() failed\n"); 401862306a36Sopenharmony_ci goto err_phy_disconnect; 401962306a36Sopenharmony_ci } 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci /* Register the net_device struct with the PCI subsystem. Save a copy 402262306a36Sopenharmony_ci * of the PCI config space for this device now that the device has 402362306a36Sopenharmony_ci * been initialized, just in case it needs to be quickly restored. 402462306a36Sopenharmony_ci */ 402562306a36Sopenharmony_ci pci_set_drvdata(pdev, netdev); 402662306a36Sopenharmony_ciout: 402762306a36Sopenharmony_ci return rc; 402862306a36Sopenharmony_ci 402962306a36Sopenharmony_cierr_phy_disconnect: 403062306a36Sopenharmony_ci phy_disconnect(netdev->phydev); 403162306a36Sopenharmony_cierr_mdio_unregister: 403262306a36Sopenharmony_ci mdiobus_unregister(adapter->mii_bus); 403362306a36Sopenharmony_cierr_mdio_free: 403462306a36Sopenharmony_ci mdiobus_free(adapter->mii_bus); 403562306a36Sopenharmony_cierr_mem_free: 403662306a36Sopenharmony_ci et131x_adapter_memory_free(adapter); 403762306a36Sopenharmony_cierr_iounmap: 403862306a36Sopenharmony_ci iounmap(adapter->regs); 403962306a36Sopenharmony_cierr_free_dev: 404062306a36Sopenharmony_ci pci_dev_put(pdev); 404162306a36Sopenharmony_ci free_netdev(netdev); 404262306a36Sopenharmony_cierr_release_res: 404362306a36Sopenharmony_ci pci_release_regions(pdev); 404462306a36Sopenharmony_cierr_disable: 404562306a36Sopenharmony_ci pci_disable_device(pdev); 404662306a36Sopenharmony_ci goto out; 404762306a36Sopenharmony_ci} 404862306a36Sopenharmony_ci 404962306a36Sopenharmony_cistatic const struct pci_device_id et131x_pci_table[] = { 405062306a36Sopenharmony_ci { PCI_VDEVICE(ATT, ET131X_PCI_DEVICE_ID_GIG), 0UL}, 405162306a36Sopenharmony_ci { PCI_VDEVICE(ATT, ET131X_PCI_DEVICE_ID_FAST), 0UL}, 405262306a36Sopenharmony_ci { 0,} 405362306a36Sopenharmony_ci}; 405462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, et131x_pci_table); 405562306a36Sopenharmony_ci 405662306a36Sopenharmony_cistatic struct pci_driver et131x_driver = { 405762306a36Sopenharmony_ci .name = DRIVER_NAME, 405862306a36Sopenharmony_ci .id_table = et131x_pci_table, 405962306a36Sopenharmony_ci .probe = et131x_pci_setup, 406062306a36Sopenharmony_ci .remove = et131x_pci_remove, 406162306a36Sopenharmony_ci .driver.pm = &et131x_pm_ops, 406262306a36Sopenharmony_ci}; 406362306a36Sopenharmony_ci 406462306a36Sopenharmony_cimodule_pci_driver(et131x_driver); 4065