david/ipxe
Archived
1
0
This repository has been archived on 2020-12-06. You can view files and clone it, but cannot push or open issues or pull requests.
ipxe/src/drivers/net/realtek.h
Michael Brown ccb6e5c627 [realtek] Clear bit 24 of RCR
On an Asus Z87-K motherboard with an onboard 8168 NIC, booting into
Windows 7 and then warm rebooting into iPXE results in a broken RX
datapath: packets can be transmitted successfully but garbage is
received.  A cold reboot clears the problem.

A dump of the PHY registers reveals only one difference: in the
failure case the bits ADVERTISE_PAUSE_CAP and ADVERTISE_PAUSE_ASYM are
cleared.  Explicitly setting these bits does not fix the problem.

A dump of the MAC registers reveals a few differences, of which the
most obvious culprit is the undocumented bit 24 of the Receive
Configuration Register (RCR), which is set in the failure case.
Explicitly clearing this bit does fix the problem.

Reported-by: Sebastian Nielsen <ipxe@sebbe.eu>
Reported-by: Oliver Rath <rath@mglug.de>
Debugged-by: Sebastian Nielsen <ipxe@sebbe.eu>
Tested-by: Sebastian Nielsen <ipxe@sebbe.eu>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2014-03-20 15:54:25 +00:00

308 lines
9.1 KiB
C

#ifndef _REALTEK_H
#define _REALTEK_H
/** @file
*
* Realtek 10/100/1000 network card driver
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/spi.h>
#include <ipxe/spi_bit.h>
#include <ipxe/nvo.h>
#include <ipxe/if_ether.h>
/** PCI memory BAR size */
#define RTL_BAR_SIZE 0x100
/** A packet descriptor */
struct realtek_descriptor {
/** Buffer size */
uint16_t length;
/** Flags */
uint16_t flags;
/** Reserved */
uint32_t reserved;
/** Buffer address */
uint64_t address;
} __attribute__ (( packed ));
/** Descriptor buffer size mask */
#define RTL_DESC_SIZE_MASK 0x3fff
/** Packet descriptor flags */
enum realtek_descriptor_flags {
/** Descriptor is owned by NIC */
RTL_DESC_OWN = 0x8000,
/** End of descriptor ring */
RTL_DESC_EOR = 0x4000,
/** First segment descriptor */
RTL_DESC_FS = 0x2000,
/** Last segment descriptor */
RTL_DESC_LS = 0x1000,
/** Receive error summary */
RTL_DESC_RES = 0x0020,
};
/** Descriptor ring alignment */
#define RTL_RING_ALIGN 256
/** A legacy mode receive packet header */
struct realtek_legacy_header {
/** Status */
uint16_t status;
/** Length */
uint16_t length;
/** Packet data */
uint8_t data[0];
} __attribute__ (( packed ));
/** Legacy mode status bits */
enum realtek_legacy_status {
/** Received OK */
RTL_STAT_ROK = 0x0001,
};
/** ID Register 0 (6 bytes) */
#define RTL_IDR0 0x00
/** Multicast Register 0 (dword) */
#define RTL_MAR0 0x08
/** Multicast Register 4 (dword) */
#define RTL_MAR4 0x0c
/** Transmit Status of Descriptor N (dword, 8139 only) */
#define RTL_TSD(n) ( 0x10 + 4 * (n) )
#define RTL_TSD_ERTXTH(x) ( (x) << 16 ) /**< Early TX threshold */
#define RTL_TSD_ERTXTH_DEFAULT RTL_TSD_ERTXTH ( 256 / 32 )
#define RTL_TSD_OWN 0x00002000UL /**< Ownership */
/** Transmit Start Address of Descriptor N (dword, 8139 only) */
#define RTL_TSAD(n) ( 0x20 + 4 * (n) )
/** Transmit Normal Priority Descriptors (qword) */
#define RTL_TNPDS 0x20
/** Number of transmit descriptors
*
* This is a hardware limit when using legacy mode.
*/
#define RTL_NUM_TX_DESC 4
/** Receive Buffer Start Address (dword, 8139 only) */
#define RTL_RBSTART 0x30
/** Receive buffer length */
#define RTL_RXBUF_LEN 8192
/** Receive buffer padding */
#define RTL_RXBUF_PAD 2038 /* Allow space for WRAP */
/** Receive buffer alignment */
#define RTL_RXBUF_ALIGN 16
/** Command Register (byte) */
#define RTL_CR 0x37
#define RTL_CR_RST 0x10 /**< Reset */
#define RTL_CR_RE 0x08 /**< Receiver Enable */
#define RTL_CR_TE 0x04 /**< Transmit Enable */
#define RTL_CR_BUFE 0x01 /**< Receive buffer empty */
/** Maximum time to wait for a reset, in milliseconds */
#define RTL_RESET_MAX_WAIT_MS 100
/** Current Address of Packet Read (word, 8139 only) */
#define RTL_CAPR 0x38
/** Transmit Priority Polling Register (byte, 8169 only) */
#define RTL_TPPOLL_8169 0x38
#define RTL_TPPOLL_NPQ 0x40 /**< Normal Priority Queue Polling */
/** Interrupt Mask Register (word) */
#define RTL_IMR 0x3c
#define RTL_IRQ_PUN_LINKCHG 0x0020 /**< Packet underrun / link change */
#define RTL_IRQ_TER 0x0008 /**< Transmit error */
#define RTL_IRQ_TOK 0x0004 /**< Transmit OK */
#define RTL_IRQ_RER 0x0002 /**< Receive error */
#define RTL_IRQ_ROK 0x0001 /**< Receive OK */
/** Interrupt Status Register (word) */
#define RTL_ISR 0x3e
/** Transmit (Tx) Configuration Register (dword) */
#define RTL_TCR 0x40
#define RTL_TCR_MXDMA(x) ( (x) << 8 ) /**< Max DMA burst size */
#define RTL_TCR_MXDMA_MASK RTL_TCR_MXDMA ( 0x7 )
#define RTL_TCR_MXDMA_DEFAULT RTL_TCR_MXDMA ( 0x7 /* Unlimited */ )
/** Receive (Rx) Configuration Register (dword) */
#define RTL_RCR 0x44
#define RTL_RCR_STOP_WORKING 0x01000000UL /**< Here be dragons */
#define RTL_RCR_RXFTH(x) ( (x) << 13 ) /**< Receive FIFO threshold */
#define RTL_RCR_RXFTH_MASK RTL_RCR_RXFTH ( 0x7 )
#define RTL_RCR_RXFTH_DEFAULT RTL_RCR_RXFTH ( 0x7 /* Whole packet */ )
#define RTL_RCR_RBLEN(x) ( (x) << 11 ) /**< Receive buffer length */
#define RTL_RCR_RBLEN_MASK RTL_RCR_RBLEN ( 0x3 )
#define RTL_RCR_RBLEN_DEFAULT RTL_RCR_RBLEN ( 0 /* 8kB */ )
#define RTL_RCR_MXDMA(x) ( (x) << 8 ) /**< Max DMA burst size */
#define RTL_RCR_MXDMA_MASK RTL_RCR_MXDMA ( 0x7 )
#define RTL_RCR_MXDMA_DEFAULT RTL_RCR_MXDMA ( 0x7 /* Unlimited */ )
#define RTL_RCR_WRAP 0x00000080UL /**< Overrun receive buffer */
#define RTL_RCR_9356SEL 0x00000040UL /**< EEPROM is a 93C56 */
#define RTL_RCR_AB 0x00000008UL /**< Accept broadcast packets */
#define RTL_RCR_AM 0x00000004UL /**< Accept multicast packets */
#define RTL_RCR_APM 0x00000002UL /**< Accept physical match */
#define RTL_RCR_AAP 0x00000001UL /**< Accept all packets */
/** 93C46 (93C56) Command Register (byte) */
#define RTL_9346CR 0x50
#define RTL_9346CR_EEM(x) ( (x) << 6 ) /**< Mode select */
#define RTL_9346CR_EEM_EEPROM RTL_9346CR_EEM ( 0x2 ) /**< EEPROM mode */
#define RTL_9346CR_EEM_NORMAL RTL_9346CR_EEM ( 0x0 ) /**< Normal mode */
#define RTL_9346CR_EECS 0x08 /**< Chip select */
#define RTL_9346CR_EESK 0x04 /**< Clock */
#define RTL_9346CR_EEDI 0x02 /**< Data in */
#define RTL_9346CR_EEDO 0x01 /**< Data out */
/** Word offset of ID code word within EEPROM */
#define RTL_EEPROM_ID ( 0x00 / 2 )
/** EEPROM code word magic value */
#define RTL_EEPROM_ID_MAGIC 0x8129
/** Word offset of MAC address within EEPROM */
#define RTL_EEPROM_MAC ( 0x0e / 2 )
/** Word offset of VPD / non-volatile options within EEPROM */
#define RTL_EEPROM_VPD ( 0x40 / 2 )
/** Length of VPD / non-volatile options within EEPROM */
#define RTL_EEPROM_VPD_LEN 0x40
/** Configuration Register 1 (byte) */
#define RTL_CONFIG1 0x52
#define RTL_CONFIG1_VPD 0x02 /**< Vital Product Data enabled */
/** Media Status Register (byte, 8139 only) */
#define RTL_MSR 0x58
#define RTL_MSR_TXFCE 0x80 /**< TX flow control enabled */
#define RTL_MSR_RXFCE 0x40 /**< RX flow control enabled */
#define RTL_MSR_AUX_STATUS 0x10 /**< Aux power present */
#define RTL_MSR_SPEED_10 0x08 /**< 10Mbps */
#define RTL_MSR_LINKB 0x04 /**< Inverse of link status */
#define RTL_MSR_TXPF 0x02 /**< TX pause flag */
#define RTL_MSR_RXPF 0x01 /**< RX pause flag */
/** PHY Access Register (dword, 8169 only) */
#define RTL_PHYAR 0x60
#define RTL_PHYAR_FLAG 0x80000000UL /**< Read/write flag */
/** Construct PHY Access Register value */
#define RTL_PHYAR_VALUE( flag, reg, data ) ( (flag) | ( (reg) << 16 ) | (data) )
/** Extract PHY Access Register data */
#define RTL_PHYAR_DATA( value ) ( (value) & 0xffff )
/** Maximum time to wait for PHY access, in microseconds */
#define RTL_MII_MAX_WAIT_US 500
/** PHY (GMII, MII, or TBI) Status Register (byte, 8169 only) */
#define RTL_PHYSTATUS 0x6c
#define RTL_PHYSTATUS_ENTBI 0x80 /**< TBI / GMII mode */
#define RTL_PHYSTATUS_TXFLOW 0x40 /**< TX flow control enabled */
#define RTL_PHYSTATUS_RXFLOW 0x20 /**< RX flow control enabled */
#define RTL_PHYSTATUS_1000MF 0x10 /**< 1000Mbps full-duplex */
#define RTL_PHYSTATUS_100M 0x08 /**< 100Mbps */
#define RTL_PHYSTATUS_10M 0x04 /**< 10Mbps */
#define RTL_PHYSTATUS_LINKSTS 0x02 /**< Link ok */
#define RTL_PHYSTATUS_FULLDUP 0x01 /**< Full duplex */
/** Transmit Priority Polling Register (byte, 8139C+ only) */
#define RTL_TPPOLL_8139CP 0xd9
/** RX Packet Maximum Size Register (word) */
#define RTL_RMS 0xda
/** C+ Command Register (word) */
#define RTL_CPCR 0xe0
#define RTL_CPCR_DAC 0x0010 /**< PCI Dual Address Cycle Enable */
#define RTL_CPCR_MULRW 0x0008 /**< PCI Multiple Read/Write Enable */
#define RTL_CPCR_CPRX 0x0002 /**< C+ receive enable */
#define RTL_CPCR_CPTX 0x0001 /**< C+ transmit enable */
/** Receive Descriptor Start Address Register (qword) */
#define RTL_RDSAR 0xe4
/** Number of receive descriptors */
#define RTL_NUM_RX_DESC 4
/** Receive buffer length */
#define RTL_RX_MAX_LEN \
( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ + 4 /* extra space */ )
/** A Realtek descriptor ring */
struct realtek_ring {
/** Descriptors */
struct realtek_descriptor *desc;
/** Producer index */
unsigned int prod;
/** Consumer index */
unsigned int cons;
/** Descriptor start address register */
unsigned int reg;
/** Length (in bytes) */
size_t len;
};
/**
* Initialise descriptor ring
*
* @v ring Descriptor ring
* @v count Number of descriptors
* @v reg Descriptor start address register
*/
static inline __attribute__ (( always_inline)) void
realtek_init_ring ( struct realtek_ring *ring, unsigned int count,
unsigned int reg ) {
ring->len = ( count * sizeof ( ring->desc[0] ) );
ring->reg = reg;
}
/** A Realtek network card */
struct realtek_nic {
/** Registers */
void *regs;
/** SPI bit-bashing interface */
struct spi_bit_basher spibit;
/** EEPROM */
struct spi_device eeprom;
/** Non-volatile options */
struct nvo_block nvo;
/** MII interface */
struct mii_interface mii;
/** Legacy datapath mode */
int legacy;
/** PHYAR and PHYSTATUS registers are present */
int have_phy_regs;
/** TPPoll register offset */
unsigned int tppoll;
/** Transmit descriptor ring */
struct realtek_ring tx;
/** Receive descriptor ring */
struct realtek_ring rx;
/** Receive I/O buffers */
struct io_buffer *rx_iobuf[RTL_NUM_RX_DESC];
/** Receive buffer (legacy mode) */
void *rx_buffer;
/** Offset within receive buffer (legacy mode) */
unsigned int rx_offset;
};
#endif /* _REALTEK_H */