|  | @@ -0,0 +1,779 @@
 | 
		
	
		
			
			|  | 1 | +/*
 | 
		
	
		
			
			|  | 2 | + * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
 | 
		
	
		
			
			|  | 3 | + *
 | 
		
	
		
			
			|  | 4 | + * (EEPROM code originally implemented for rtl8139.c)
 | 
		
	
		
			
			|  | 5 | + *
 | 
		
	
		
			
			|  | 6 | + * This program is free software; you can redistribute it and/or
 | 
		
	
		
			
			|  | 7 | + * modify it under the terms of the GNU General Public License as
 | 
		
	
		
			
			|  | 8 | + * published by the Free Software Foundation; either version 2 of the
 | 
		
	
		
			
			|  | 9 | + * License, or (at your option) any later version.
 | 
		
	
		
			
			|  | 10 | + *
 | 
		
	
		
			
			|  | 11 | + * This program is distributed in the hope that it will be useful, but
 | 
		
	
		
			
			|  | 12 | + * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
		
	
		
			
			|  | 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
		
	
		
			
			|  | 14 | + * General Public License for more details.
 | 
		
	
		
			
			|  | 15 | + *
 | 
		
	
		
			
			|  | 16 | + * You should have received a copy of the GNU General Public License
 | 
		
	
		
			
			|  | 17 | + * along with this program; if not, write to the Free Software
 | 
		
	
		
			
			|  | 18 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
		
	
		
			
			|  | 19 | + * 02110-1301, USA.
 | 
		
	
		
			
			|  | 20 | + */
 | 
		
	
		
			
			|  | 21 | +
 | 
		
	
		
			
			|  | 22 | +FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			|  | 23 | +
 | 
		
	
		
			
			|  | 24 | +#include <stdint.h>
 | 
		
	
		
			
			|  | 25 | +#include <string.h>
 | 
		
	
		
			
			|  | 26 | +#include <unistd.h>
 | 
		
	
		
			
			|  | 27 | +#include <errno.h>
 | 
		
	
		
			
			|  | 28 | +#include <byteswap.h>
 | 
		
	
		
			
			|  | 29 | +#include <ipxe/netdevice.h>
 | 
		
	
		
			
			|  | 30 | +#include <ipxe/ethernet.h>
 | 
		
	
		
			
			|  | 31 | +#include <ipxe/if_ether.h>
 | 
		
	
		
			
			|  | 32 | +#include <ipxe/iobuf.h>
 | 
		
	
		
			
			|  | 33 | +#include <ipxe/malloc.h>
 | 
		
	
		
			
			|  | 34 | +#include <ipxe/pci.h>
 | 
		
	
		
			
			|  | 35 | +#include <ipxe/nvs.h>
 | 
		
	
		
			
			|  | 36 | +#include <ipxe/threewire.h>
 | 
		
	
		
			
			|  | 37 | +#include <ipxe/bitbash.h>
 | 
		
	
		
			
			|  | 38 | +#include <ipxe/mii.h>
 | 
		
	
		
			
			|  | 39 | +#include "realtek.h"
 | 
		
	
		
			
			|  | 40 | +
 | 
		
	
		
			
			|  | 41 | +/** @file
 | 
		
	
		
			
			|  | 42 | + *
 | 
		
	
		
			
			|  | 43 | + * Realtek 10/100/1000 network card driver
 | 
		
	
		
			
			|  | 44 | + *
 | 
		
	
		
			
			|  | 45 | + * Based on the following datasheets:
 | 
		
	
		
			
			|  | 46 | + *
 | 
		
	
		
			
			|  | 47 | + *    http://www.datasheetarchive.com/dl/Datasheets-8/DSA-153536.pdf
 | 
		
	
		
			
			|  | 48 | + *    http://www.datasheetarchive.com/indexdl/Datasheet-028/DSA00494723.pdf
 | 
		
	
		
			
			|  | 49 | + */
 | 
		
	
		
			
			|  | 50 | +
 | 
		
	
		
			
			|  | 51 | +/******************************************************************************
 | 
		
	
		
			
			|  | 52 | + *
 | 
		
	
		
			
			|  | 53 | + * EEPROM interface
 | 
		
	
		
			
			|  | 54 | + *
 | 
		
	
		
			
			|  | 55 | + ******************************************************************************
 | 
		
	
		
			
			|  | 56 | + */
 | 
		
	
		
			
			|  | 57 | +
 | 
		
	
		
			
			|  | 58 | +/** Pin mapping for SPI bit-bashing interface */
 | 
		
	
		
			
			|  | 59 | +static const uint8_t realtek_eeprom_bits[] = {
 | 
		
	
		
			
			|  | 60 | +	[SPI_BIT_SCLK]	= RTL_9346CR_EESK,
 | 
		
	
		
			
			|  | 61 | +	[SPI_BIT_MOSI]	= RTL_9346CR_EEDI,
 | 
		
	
		
			
			|  | 62 | +	[SPI_BIT_MISO]	= RTL_9346CR_EEDO,
 | 
		
	
		
			
			|  | 63 | +	[SPI_BIT_SS(0)]	= ( RTL_9346CR_EECS | RTL_9346CR_EEM1 ),
 | 
		
	
		
			
			|  | 64 | +};
 | 
		
	
		
			
			|  | 65 | +
 | 
		
	
		
			
			|  | 66 | +/**
 | 
		
	
		
			
			|  | 67 | + * Read input bit
 | 
		
	
		
			
			|  | 68 | + *
 | 
		
	
		
			
			|  | 69 | + * @v basher		Bit-bashing interface
 | 
		
	
		
			
			|  | 70 | + * @v bit_id		Bit number
 | 
		
	
		
			
			|  | 71 | + * @ret zero		Input is a logic 0
 | 
		
	
		
			
			|  | 72 | + * @ret non-zero	Input is a logic 1
 | 
		
	
		
			
			|  | 73 | + */
 | 
		
	
		
			
			|  | 74 | +static int realtek_spi_read_bit ( struct bit_basher *basher,
 | 
		
	
		
			
			|  | 75 | +				  unsigned int bit_id ) {
 | 
		
	
		
			
			|  | 76 | +	struct realtek_nic *rtl = container_of ( basher, struct realtek_nic,
 | 
		
	
		
			
			|  | 77 | +						 spibit.basher );
 | 
		
	
		
			
			|  | 78 | +	uint8_t mask = realtek_eeprom_bits[bit_id];
 | 
		
	
		
			
			|  | 79 | +	uint8_t reg;
 | 
		
	
		
			
			|  | 80 | +
 | 
		
	
		
			
			|  | 81 | +	reg = readb ( rtl->regs + RTL_9346CR );
 | 
		
	
		
			
			|  | 82 | +	return ( reg & mask );
 | 
		
	
		
			
			|  | 83 | +}
 | 
		
	
		
			
			|  | 84 | +
 | 
		
	
		
			
			|  | 85 | +/**
 | 
		
	
		
			
			|  | 86 | + * Set/clear output bit
 | 
		
	
		
			
			|  | 87 | + *
 | 
		
	
		
			
			|  | 88 | + * @v basher		Bit-bashing interface
 | 
		
	
		
			
			|  | 89 | + * @v bit_id		Bit number
 | 
		
	
		
			
			|  | 90 | + * @v data		Value to write
 | 
		
	
		
			
			|  | 91 | + */
 | 
		
	
		
			
			|  | 92 | +static void realtek_spi_write_bit ( struct bit_basher *basher,
 | 
		
	
		
			
			|  | 93 | +				    unsigned int bit_id, unsigned long data ) {
 | 
		
	
		
			
			|  | 94 | +	struct realtek_nic *rtl = container_of ( basher, struct realtek_nic,
 | 
		
	
		
			
			|  | 95 | +						 spibit.basher );
 | 
		
	
		
			
			|  | 96 | +	uint8_t mask = realtek_eeprom_bits[bit_id];
 | 
		
	
		
			
			|  | 97 | +	uint8_t reg;
 | 
		
	
		
			
			|  | 98 | +
 | 
		
	
		
			
			|  | 99 | +	reg = readb ( rtl->regs + RTL_9346CR );
 | 
		
	
		
			
			|  | 100 | +	reg &= ~mask;
 | 
		
	
		
			
			|  | 101 | +	reg |= ( data & mask );
 | 
		
	
		
			
			|  | 102 | +	writeb ( reg, rtl->regs + RTL_9346CR );
 | 
		
	
		
			
			|  | 103 | +}
 | 
		
	
		
			
			|  | 104 | +
 | 
		
	
		
			
			|  | 105 | +/** SPI bit-bashing interface */
 | 
		
	
		
			
			|  | 106 | +static struct bit_basher_operations realtek_basher_ops = {
 | 
		
	
		
			
			|  | 107 | +	.read = realtek_spi_read_bit,
 | 
		
	
		
			
			|  | 108 | +	.write = realtek_spi_write_bit,
 | 
		
	
		
			
			|  | 109 | +};
 | 
		
	
		
			
			|  | 110 | +
 | 
		
	
		
			
			|  | 111 | +/**
 | 
		
	
		
			
			|  | 112 | + * Initialise EEPROM
 | 
		
	
		
			
			|  | 113 | + *
 | 
		
	
		
			
			|  | 114 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 115 | + */
 | 
		
	
		
			
			|  | 116 | +static void realtek_init_eeprom ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 117 | +	struct realtek_nic *rtl = netdev->priv;
 | 
		
	
		
			
			|  | 118 | +
 | 
		
	
		
			
			|  | 119 | +	/* Initialise SPI bit-bashing interface */
 | 
		
	
		
			
			|  | 120 | +	rtl->spibit.basher.op = &realtek_basher_ops;
 | 
		
	
		
			
			|  | 121 | +	rtl->spibit.bus.mode = SPI_MODE_THREEWIRE;
 | 
		
	
		
			
			|  | 122 | +	init_spi_bit_basher ( &rtl->spibit );
 | 
		
	
		
			
			|  | 123 | +
 | 
		
	
		
			
			|  | 124 | +	/* Detect EEPROM type and initialise three-wire device */
 | 
		
	
		
			
			|  | 125 | +	if ( readl ( rtl->regs + RTL_RCR ) & RTL_RCR_9356SEL ) {
 | 
		
	
		
			
			|  | 126 | +		DBGC ( rtl, "REALTEK %p EEPROM is a 93C56\n", rtl );
 | 
		
	
		
			
			|  | 127 | +		init_at93c56 ( &rtl->eeprom, 16 );
 | 
		
	
		
			
			|  | 128 | +	} else {
 | 
		
	
		
			
			|  | 129 | +		DBGC ( rtl, "REALTEK %p EEPROM is a 93C46\n", rtl );
 | 
		
	
		
			
			|  | 130 | +		init_at93c46 ( &rtl->eeprom, 16 );
 | 
		
	
		
			
			|  | 131 | +	}
 | 
		
	
		
			
			|  | 132 | +	rtl->eeprom.bus = &rtl->spibit.bus;
 | 
		
	
		
			
			|  | 133 | +
 | 
		
	
		
			
			|  | 134 | +	/* Initialise space for non-volatile options, if available
 | 
		
	
		
			
			|  | 135 | +	 *
 | 
		
	
		
			
			|  | 136 | +	 * We use offset 0x40 (i.e. address 0x20), length 0x40.  This
 | 
		
	
		
			
			|  | 137 | +	 * block is marked as VPD in the Realtek datasheets, so we use
 | 
		
	
		
			
			|  | 138 | +	 * it only if we detect that the card is not supporting VPD.
 | 
		
	
		
			
			|  | 139 | +	 */
 | 
		
	
		
			
			|  | 140 | +	if ( readb ( rtl->regs + RTL_CONFIG1 ) & RTL_CONFIG1_VPD ) {
 | 
		
	
		
			
			|  | 141 | +		DBGC ( rtl, "REALTEK %p EEPROM in use for VPD; cannot use "
 | 
		
	
		
			
			|  | 142 | +		       "for options\n", rtl );
 | 
		
	
		
			
			|  | 143 | +	} else {
 | 
		
	
		
			
			|  | 144 | +		nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, RTL_EEPROM_VPD,
 | 
		
	
		
			
			|  | 145 | +			   RTL_EEPROM_VPD_LEN, NULL, &netdev->refcnt );
 | 
		
	
		
			
			|  | 146 | +	}
 | 
		
	
		
			
			|  | 147 | +}
 | 
		
	
		
			
			|  | 148 | +
 | 
		
	
		
			
			|  | 149 | +/******************************************************************************
 | 
		
	
		
			
			|  | 150 | + *
 | 
		
	
		
			
			|  | 151 | + * MII interface
 | 
		
	
		
			
			|  | 152 | + *
 | 
		
	
		
			
			|  | 153 | + ******************************************************************************
 | 
		
	
		
			
			|  | 154 | + */
 | 
		
	
		
			
			|  | 155 | +
 | 
		
	
		
			
			|  | 156 | +/**
 | 
		
	
		
			
			|  | 157 | + * Read from MII register
 | 
		
	
		
			
			|  | 158 | + *
 | 
		
	
		
			
			|  | 159 | + * @v mii		MII interface
 | 
		
	
		
			
			|  | 160 | + * @v reg		Register address
 | 
		
	
		
			
			|  | 161 | + * @ret value		Data read, or negative error
 | 
		
	
		
			
			|  | 162 | + */
 | 
		
	
		
			
			|  | 163 | +static int realtek_mii_read ( struct mii_interface *mii, unsigned int reg ) {
 | 
		
	
		
			
			|  | 164 | +	struct realtek_nic *rtl = container_of ( mii, struct realtek_nic, mii );
 | 
		
	
		
			
			|  | 165 | +	unsigned int i;
 | 
		
	
		
			
			|  | 166 | +	uint32_t value;
 | 
		
	
		
			
			|  | 167 | +
 | 
		
	
		
			
			|  | 168 | +	/* Initiate read */
 | 
		
	
		
			
			|  | 169 | +	writel ( RTL_PHYAR_VALUE ( 0, reg, 0 ), rtl->regs + RTL_PHYAR );
 | 
		
	
		
			
			|  | 170 | +
 | 
		
	
		
			
			|  | 171 | +	/* Wait for read to complete */
 | 
		
	
		
			
			|  | 172 | +	for ( i = 0 ; i < RTL_MII_MAX_WAIT_US ; i++ ) {
 | 
		
	
		
			
			|  | 173 | +
 | 
		
	
		
			
			|  | 174 | +		/* If read is not complete, delay 1us and retry */
 | 
		
	
		
			
			|  | 175 | +		value = readl ( rtl->regs + RTL_PHYAR );
 | 
		
	
		
			
			|  | 176 | +		if ( ! ( value & RTL_PHYAR_FLAG ) ) {
 | 
		
	
		
			
			|  | 177 | +			udelay ( 1 );
 | 
		
	
		
			
			|  | 178 | +			continue;
 | 
		
	
		
			
			|  | 179 | +		}
 | 
		
	
		
			
			|  | 180 | +
 | 
		
	
		
			
			|  | 181 | +		/* Return register value */
 | 
		
	
		
			
			|  | 182 | +		return ( RTL_PHYAR_DATA ( value ) );
 | 
		
	
		
			
			|  | 183 | +	}
 | 
		
	
		
			
			|  | 184 | +
 | 
		
	
		
			
			|  | 185 | +	DBGC ( rtl, "REALTEK %p timed out waiting for MII read\n", rtl );
 | 
		
	
		
			
			|  | 186 | +	return -ETIMEDOUT;
 | 
		
	
		
			
			|  | 187 | +}
 | 
		
	
		
			
			|  | 188 | +
 | 
		
	
		
			
			|  | 189 | +/**
 | 
		
	
		
			
			|  | 190 | + * Write to MII register
 | 
		
	
		
			
			|  | 191 | + *
 | 
		
	
		
			
			|  | 192 | + * @v mii		MII interface
 | 
		
	
		
			
			|  | 193 | + * @v reg		Register address
 | 
		
	
		
			
			|  | 194 | + * @v data		Data to write
 | 
		
	
		
			
			|  | 195 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 196 | + */
 | 
		
	
		
			
			|  | 197 | +static int realtek_mii_write ( struct mii_interface *mii, unsigned int reg,
 | 
		
	
		
			
			|  | 198 | +			       unsigned int data) {
 | 
		
	
		
			
			|  | 199 | +	struct realtek_nic *rtl = container_of ( mii, struct realtek_nic, mii );
 | 
		
	
		
			
			|  | 200 | +	unsigned int i;
 | 
		
	
		
			
			|  | 201 | +
 | 
		
	
		
			
			|  | 202 | +	/* Initiate write */
 | 
		
	
		
			
			|  | 203 | +	writel ( RTL_PHYAR_VALUE ( RTL_PHYAR_FLAG, reg, data ),
 | 
		
	
		
			
			|  | 204 | +		 rtl->regs + RTL_PHYAR );
 | 
		
	
		
			
			|  | 205 | +
 | 
		
	
		
			
			|  | 206 | +	/* Wait for write to complete */
 | 
		
	
		
			
			|  | 207 | +	for ( i = 0 ; i < RTL_MII_MAX_WAIT_US ; i++ ) {
 | 
		
	
		
			
			|  | 208 | +
 | 
		
	
		
			
			|  | 209 | +		/* If write is not complete, delay 1us and retry */
 | 
		
	
		
			
			|  | 210 | +		if ( readl ( rtl->regs + RTL_PHYAR ) & RTL_PHYAR_FLAG ) {
 | 
		
	
		
			
			|  | 211 | +			udelay ( 1 );
 | 
		
	
		
			
			|  | 212 | +			continue;
 | 
		
	
		
			
			|  | 213 | +		}
 | 
		
	
		
			
			|  | 214 | +
 | 
		
	
		
			
			|  | 215 | +		return 0;
 | 
		
	
		
			
			|  | 216 | +	}
 | 
		
	
		
			
			|  | 217 | +
 | 
		
	
		
			
			|  | 218 | +	DBGC ( rtl, "REALTEK %p timed out waiting for MII write\n", rtl );
 | 
		
	
		
			
			|  | 219 | +	return -ETIMEDOUT;
 | 
		
	
		
			
			|  | 220 | +}
 | 
		
	
		
			
			|  | 221 | +
 | 
		
	
		
			
			|  | 222 | +/** Realtek MII operations */
 | 
		
	
		
			
			|  | 223 | +static struct mii_operations realtek_mii_operations = {
 | 
		
	
		
			
			|  | 224 | +	.read = realtek_mii_read,
 | 
		
	
		
			
			|  | 225 | +	.write = realtek_mii_write,
 | 
		
	
		
			
			|  | 226 | +};
 | 
		
	
		
			
			|  | 227 | +
 | 
		
	
		
			
			|  | 228 | +/******************************************************************************
 | 
		
	
		
			
			|  | 229 | + *
 | 
		
	
		
			
			|  | 230 | + * Device reset
 | 
		
	
		
			
			|  | 231 | + *
 | 
		
	
		
			
			|  | 232 | + ******************************************************************************
 | 
		
	
		
			
			|  | 233 | + */
 | 
		
	
		
			
			|  | 234 | +
 | 
		
	
		
			
			|  | 235 | +/**
 | 
		
	
		
			
			|  | 236 | + * Reset hardware
 | 
		
	
		
			
			|  | 237 | + *
 | 
		
	
		
			
			|  | 238 | + * @v rtl		Realtek device
 | 
		
	
		
			
			|  | 239 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 240 | + */
 | 
		
	
		
			
			|  | 241 | +static int realtek_reset ( struct realtek_nic *rtl ) {
 | 
		
	
		
			
			|  | 242 | +	unsigned int i;
 | 
		
	
		
			
			|  | 243 | +
 | 
		
	
		
			
			|  | 244 | +	/* Issue reset */
 | 
		
	
		
			
			|  | 245 | +	writeb ( RTL_CR_RST, rtl->regs + RTL_CR );
 | 
		
	
		
			
			|  | 246 | +
 | 
		
	
		
			
			|  | 247 | +	/* Wait for reset to complete */
 | 
		
	
		
			
			|  | 248 | +	for ( i = 0 ; i < RTL_RESET_MAX_WAIT_MS ; i++ ) {
 | 
		
	
		
			
			|  | 249 | +
 | 
		
	
		
			
			|  | 250 | +		/* If reset is not complete, delay 1ms and retry */
 | 
		
	
		
			
			|  | 251 | +		if ( readb ( rtl->regs + RTL_CR ) & RTL_CR_RST ) {
 | 
		
	
		
			
			|  | 252 | +			mdelay ( 1 );
 | 
		
	
		
			
			|  | 253 | +			continue;
 | 
		
	
		
			
			|  | 254 | +		}
 | 
		
	
		
			
			|  | 255 | +
 | 
		
	
		
			
			|  | 256 | +		/* Enable PCI Dual Address Cycle (for 64-bit systems) */
 | 
		
	
		
			
			|  | 257 | +		writew ( ( RTL_CPCR_DAC | RTL_CPCR_MULRW ),
 | 
		
	
		
			
			|  | 258 | +			 rtl->regs + RTL_CPCR );
 | 
		
	
		
			
			|  | 259 | +
 | 
		
	
		
			
			|  | 260 | +		return 0;
 | 
		
	
		
			
			|  | 261 | +	}
 | 
		
	
		
			
			|  | 262 | +
 | 
		
	
		
			
			|  | 263 | +	DBGC ( rtl, "REALTEK %p timed out waiting for reset\n", rtl );
 | 
		
	
		
			
			|  | 264 | +	return -ETIMEDOUT;
 | 
		
	
		
			
			|  | 265 | +}
 | 
		
	
		
			
			|  | 266 | +
 | 
		
	
		
			
			|  | 267 | +/******************************************************************************
 | 
		
	
		
			
			|  | 268 | + *
 | 
		
	
		
			
			|  | 269 | + * Link state
 | 
		
	
		
			
			|  | 270 | + *
 | 
		
	
		
			
			|  | 271 | + ******************************************************************************
 | 
		
	
		
			
			|  | 272 | + */
 | 
		
	
		
			
			|  | 273 | +
 | 
		
	
		
			
			|  | 274 | +/**
 | 
		
	
		
			
			|  | 275 | + * Check link state
 | 
		
	
		
			
			|  | 276 | + *
 | 
		
	
		
			
			|  | 277 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 278 | + */
 | 
		
	
		
			
			|  | 279 | +static void realtek_check_link ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 280 | +	struct realtek_nic *rtl = netdev->priv;
 | 
		
	
		
			
			|  | 281 | +
 | 
		
	
		
			
			|  | 282 | +	if ( readb ( rtl->regs + RTL_PHYSTATUS ) & RTL_PHYSTATUS_LINKSTS ) {
 | 
		
	
		
			
			|  | 283 | +		netdev_link_up ( netdev );
 | 
		
	
		
			
			|  | 284 | +	} else {
 | 
		
	
		
			
			|  | 285 | +		netdev_link_down ( netdev );
 | 
		
	
		
			
			|  | 286 | +	}
 | 
		
	
		
			
			|  | 287 | +}
 | 
		
	
		
			
			|  | 288 | +
 | 
		
	
		
			
			|  | 289 | +/******************************************************************************
 | 
		
	
		
			
			|  | 290 | + *
 | 
		
	
		
			
			|  | 291 | + * Network device interface
 | 
		
	
		
			
			|  | 292 | + *
 | 
		
	
		
			
			|  | 293 | + ******************************************************************************
 | 
		
	
		
			
			|  | 294 | + */
 | 
		
	
		
			
			|  | 295 | +
 | 
		
	
		
			
			|  | 296 | +/**
 | 
		
	
		
			
			|  | 297 | + * Create descriptor ring
 | 
		
	
		
			
			|  | 298 | + *
 | 
		
	
		
			
			|  | 299 | + * @v rtl		Realtek device
 | 
		
	
		
			
			|  | 300 | + * @v ring		Descriptor ring
 | 
		
	
		
			
			|  | 301 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 302 | + */
 | 
		
	
		
			
			|  | 303 | +static int realtek_create_ring ( struct realtek_nic *rtl,
 | 
		
	
		
			
			|  | 304 | +				 struct realtek_ring *ring ) {
 | 
		
	
		
			
			|  | 305 | +	physaddr_t address;
 | 
		
	
		
			
			|  | 306 | +
 | 
		
	
		
			
			|  | 307 | +	/* Allocate descriptor ring */
 | 
		
	
		
			
			|  | 308 | +	ring->desc = malloc_dma ( ring->len, RTL_RING_ALIGN );
 | 
		
	
		
			
			|  | 309 | +	if ( ! ring->desc )
 | 
		
	
		
			
			|  | 310 | +		return -ENOMEM;
 | 
		
	
		
			
			|  | 311 | +
 | 
		
	
		
			
			|  | 312 | +	/* Initialise descriptor ring */
 | 
		
	
		
			
			|  | 313 | +	memset ( ring->desc, 0, ring->len );
 | 
		
	
		
			
			|  | 314 | +
 | 
		
	
		
			
			|  | 315 | +	/* Program ring address */
 | 
		
	
		
			
			|  | 316 | +	address = virt_to_bus ( ring->desc );
 | 
		
	
		
			
			|  | 317 | +	writel ( ( address & 0xffffffffUL ), rtl->regs + ring->reg );
 | 
		
	
		
			
			|  | 318 | +	if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) {
 | 
		
	
		
			
			|  | 319 | +		writel ( ( ( ( uint64_t ) address ) >> 32 ),
 | 
		
	
		
			
			|  | 320 | +			 rtl->regs + ring->reg + 4 );
 | 
		
	
		
			
			|  | 321 | +	}
 | 
		
	
		
			
			|  | 322 | +	DBGC ( rtl, "REALTEK %p ring %02x is at [%08llx,%08llx)\n",
 | 
		
	
		
			
			|  | 323 | +	       rtl, ring->reg, ( ( unsigned long long ) address ),
 | 
		
	
		
			
			|  | 324 | +	       ( ( unsigned long long ) address + ring->len ) );
 | 
		
	
		
			
			|  | 325 | +
 | 
		
	
		
			
			|  | 326 | +	return 0;
 | 
		
	
		
			
			|  | 327 | +}
 | 
		
	
		
			
			|  | 328 | +
 | 
		
	
		
			
			|  | 329 | +/**
 | 
		
	
		
			
			|  | 330 | + * Destroy descriptor ring
 | 
		
	
		
			
			|  | 331 | + *
 | 
		
	
		
			
			|  | 332 | + * @v rtl		Realtek device
 | 
		
	
		
			
			|  | 333 | + * @v ring		Descriptor ring
 | 
		
	
		
			
			|  | 334 | + */
 | 
		
	
		
			
			|  | 335 | +static void realtek_destroy_ring ( struct realtek_nic *rtl,
 | 
		
	
		
			
			|  | 336 | +				   struct realtek_ring *ring ) {
 | 
		
	
		
			
			|  | 337 | +
 | 
		
	
		
			
			|  | 338 | +	/* Clear ring address */
 | 
		
	
		
			
			|  | 339 | +	writel ( 0, rtl->regs + ring->reg );
 | 
		
	
		
			
			|  | 340 | +	writel ( 0, rtl->regs + ring->reg + 4 );
 | 
		
	
		
			
			|  | 341 | +
 | 
		
	
		
			
			|  | 342 | +	/* Free descriptor ring */
 | 
		
	
		
			
			|  | 343 | +	free_dma ( ring->desc, ring->len );
 | 
		
	
		
			
			|  | 344 | +	ring->desc = NULL;
 | 
		
	
		
			
			|  | 345 | +	ring->prod = 0;
 | 
		
	
		
			
			|  | 346 | +	ring->cons = 0;
 | 
		
	
		
			
			|  | 347 | +}
 | 
		
	
		
			
			|  | 348 | +
 | 
		
	
		
			
			|  | 349 | +/**
 | 
		
	
		
			
			|  | 350 | + * Refill receive descriptor ring
 | 
		
	
		
			
			|  | 351 | + *
 | 
		
	
		
			
			|  | 352 | + * @v rtl		Realtek device
 | 
		
	
		
			
			|  | 353 | + */
 | 
		
	
		
			
			|  | 354 | +static void realtek_refill_rx ( struct realtek_nic *rtl ) {
 | 
		
	
		
			
			|  | 355 | +	struct realtek_descriptor *rx;
 | 
		
	
		
			
			|  | 356 | +	struct io_buffer *iobuf;
 | 
		
	
		
			
			|  | 357 | +	unsigned int rx_idx;
 | 
		
	
		
			
			|  | 358 | +	physaddr_t address;
 | 
		
	
		
			
			|  | 359 | +	int is_last;
 | 
		
	
		
			
			|  | 360 | +
 | 
		
	
		
			
			|  | 361 | +	while ( ( rtl->rx.prod - rtl->rx.cons ) < RTL_NUM_RX_DESC ) {
 | 
		
	
		
			
			|  | 362 | +
 | 
		
	
		
			
			|  | 363 | +		/* Allocate I/O buffer */
 | 
		
	
		
			
			|  | 364 | +		iobuf = alloc_iob ( RTL_RX_MAX_LEN );
 | 
		
	
		
			
			|  | 365 | +		if ( ! iobuf ) {
 | 
		
	
		
			
			|  | 366 | +			/* Wait for next refill */
 | 
		
	
		
			
			|  | 367 | +			return;
 | 
		
	
		
			
			|  | 368 | +		}
 | 
		
	
		
			
			|  | 369 | +
 | 
		
	
		
			
			|  | 370 | +		/* Get next receive descriptor */
 | 
		
	
		
			
			|  | 371 | +		rx_idx = ( rtl->rx.prod++ % RTL_NUM_RX_DESC );
 | 
		
	
		
			
			|  | 372 | +		is_last = ( rx_idx == ( RTL_NUM_RX_DESC - 1 ) );
 | 
		
	
		
			
			|  | 373 | +		rx = &rtl->rx.desc[rx_idx];
 | 
		
	
		
			
			|  | 374 | +
 | 
		
	
		
			
			|  | 375 | +		/* Populate receive descriptor */
 | 
		
	
		
			
			|  | 376 | +		address = virt_to_bus ( iobuf->data );
 | 
		
	
		
			
			|  | 377 | +		rx->address = cpu_to_le64 ( address );
 | 
		
	
		
			
			|  | 378 | +		rx->length = RTL_RX_MAX_LEN;
 | 
		
	
		
			
			|  | 379 | +		wmb();
 | 
		
	
		
			
			|  | 380 | +		rx->flags = ( cpu_to_le16 ( RTL_DESC_OWN ) |
 | 
		
	
		
			
			|  | 381 | +			      ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) );
 | 
		
	
		
			
			|  | 382 | +		wmb();
 | 
		
	
		
			
			|  | 383 | +
 | 
		
	
		
			
			|  | 384 | +		/* Record I/O buffer */
 | 
		
	
		
			
			|  | 385 | +		assert ( rtl->rx_iobuf[rx_idx] == NULL );
 | 
		
	
		
			
			|  | 386 | +		rtl->rx_iobuf[rx_idx] = iobuf;
 | 
		
	
		
			
			|  | 387 | +
 | 
		
	
		
			
			|  | 388 | +		DBGC2 ( rtl, "REALTEK %p RX %d is [%llx,%llx)\n", rtl, rx_idx,
 | 
		
	
		
			
			|  | 389 | +			( ( unsigned long long ) address ),
 | 
		
	
		
			
			|  | 390 | +			( ( unsigned long long ) address + RTL_RX_MAX_LEN ) );
 | 
		
	
		
			
			|  | 391 | +	}
 | 
		
	
		
			
			|  | 392 | +}
 | 
		
	
		
			
			|  | 393 | +
 | 
		
	
		
			
			|  | 394 | +/**
 | 
		
	
		
			
			|  | 395 | + * Open network device
 | 
		
	
		
			
			|  | 396 | + *
 | 
		
	
		
			
			|  | 397 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 398 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 399 | + */
 | 
		
	
		
			
			|  | 400 | +static int realtek_open ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 401 | +	struct realtek_nic *rtl = netdev->priv;
 | 
		
	
		
			
			|  | 402 | +	uint32_t rcr;
 | 
		
	
		
			
			|  | 403 | +	int rc;
 | 
		
	
		
			
			|  | 404 | +
 | 
		
	
		
			
			|  | 405 | +	/* Create transmit descriptor ring */
 | 
		
	
		
			
			|  | 406 | +	if ( ( rc = realtek_create_ring ( rtl, &rtl->tx ) ) != 0 )
 | 
		
	
		
			
			|  | 407 | +		goto err_create_tx;
 | 
		
	
		
			
			|  | 408 | +
 | 
		
	
		
			
			|  | 409 | +	/* Create receive descriptor ring */
 | 
		
	
		
			
			|  | 410 | +	if ( ( rc = realtek_create_ring ( rtl, &rtl->rx ) ) != 0 )
 | 
		
	
		
			
			|  | 411 | +		goto err_create_rx;
 | 
		
	
		
			
			|  | 412 | +
 | 
		
	
		
			
			|  | 413 | +	/* Configure MTU */
 | 
		
	
		
			
			|  | 414 | +	writew ( RTL_RX_MAX_LEN, rtl->regs + RTL_RMS );
 | 
		
	
		
			
			|  | 415 | +
 | 
		
	
		
			
			|  | 416 | +	/* Accept all packets */
 | 
		
	
		
			
			|  | 417 | +	writel ( 0xffffffffUL, rtl->regs + RTL_MAR0 );
 | 
		
	
		
			
			|  | 418 | +	writel ( 0xffffffffUL, rtl->regs + RTL_MAR4 );
 | 
		
	
		
			
			|  | 419 | +	rcr = readl ( rtl->regs + RTL_RCR );
 | 
		
	
		
			
			|  | 420 | +	writel ( ( rcr | RTL_RCR_AB | RTL_RCR_AM | RTL_RCR_APM | RTL_RCR_AAP ),
 | 
		
	
		
			
			|  | 421 | +		 rtl->regs + RTL_RCR );
 | 
		
	
		
			
			|  | 422 | +
 | 
		
	
		
			
			|  | 423 | +	/* Fill receive ring */
 | 
		
	
		
			
			|  | 424 | +	realtek_refill_rx ( rtl );
 | 
		
	
		
			
			|  | 425 | +
 | 
		
	
		
			
			|  | 426 | +	/* Enable transmitter and receiver */
 | 
		
	
		
			
			|  | 427 | +	writeb ( ( RTL_CR_TE | RTL_CR_RE ), rtl->regs + RTL_CR );
 | 
		
	
		
			
			|  | 428 | +
 | 
		
	
		
			
			|  | 429 | +	return 0;
 | 
		
	
		
			
			|  | 430 | +
 | 
		
	
		
			
			|  | 431 | +	realtek_destroy_ring ( rtl, &rtl->rx );
 | 
		
	
		
			
			|  | 432 | + err_create_rx:
 | 
		
	
		
			
			|  | 433 | +	realtek_destroy_ring ( rtl, &rtl->tx );
 | 
		
	
		
			
			|  | 434 | + err_create_tx:
 | 
		
	
		
			
			|  | 435 | +	return rc;
 | 
		
	
		
			
			|  | 436 | +}
 | 
		
	
		
			
			|  | 437 | +
 | 
		
	
		
			
			|  | 438 | +/**
 | 
		
	
		
			
			|  | 439 | + * Close network device
 | 
		
	
		
			
			|  | 440 | + *
 | 
		
	
		
			
			|  | 441 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 442 | + */
 | 
		
	
		
			
			|  | 443 | +static void realtek_close ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 444 | +	struct realtek_nic *rtl = netdev->priv;
 | 
		
	
		
			
			|  | 445 | +	unsigned int i;
 | 
		
	
		
			
			|  | 446 | +
 | 
		
	
		
			
			|  | 447 | +	/* Disable receiver and transmitter */
 | 
		
	
		
			
			|  | 448 | +	writeb ( 0, rtl->regs + RTL_CR );
 | 
		
	
		
			
			|  | 449 | +
 | 
		
	
		
			
			|  | 450 | +	/* Destroy receive descriptor ring */
 | 
		
	
		
			
			|  | 451 | +	realtek_destroy_ring ( rtl, &rtl->rx );
 | 
		
	
		
			
			|  | 452 | +
 | 
		
	
		
			
			|  | 453 | +	/* Discard any unused receive buffers */
 | 
		
	
		
			
			|  | 454 | +	for ( i = 0 ; i < RTL_NUM_RX_DESC ; i++ ) {
 | 
		
	
		
			
			|  | 455 | +		if ( rtl->rx_iobuf[i] )
 | 
		
	
		
			
			|  | 456 | +			free_iob ( rtl->rx_iobuf[i] );
 | 
		
	
		
			
			|  | 457 | +		rtl->rx_iobuf[i] = NULL;
 | 
		
	
		
			
			|  | 458 | +	}
 | 
		
	
		
			
			|  | 459 | +
 | 
		
	
		
			
			|  | 460 | +	/* Destroy transmit descriptor ring */
 | 
		
	
		
			
			|  | 461 | +	realtek_destroy_ring ( rtl, &rtl->tx );
 | 
		
	
		
			
			|  | 462 | +}
 | 
		
	
		
			
			|  | 463 | +
 | 
		
	
		
			
			|  | 464 | +/**
 | 
		
	
		
			
			|  | 465 | + * Transmit packet
 | 
		
	
		
			
			|  | 466 | + *
 | 
		
	
		
			
			|  | 467 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 468 | + * @v iobuf		I/O buffer
 | 
		
	
		
			
			|  | 469 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 470 | + */
 | 
		
	
		
			
			|  | 471 | +static int realtek_transmit ( struct net_device *netdev,
 | 
		
	
		
			
			|  | 472 | +			      struct io_buffer *iobuf ) {
 | 
		
	
		
			
			|  | 473 | +	struct realtek_nic *rtl = netdev->priv;
 | 
		
	
		
			
			|  | 474 | +	struct realtek_descriptor *tx;
 | 
		
	
		
			
			|  | 475 | +	unsigned int tx_idx;
 | 
		
	
		
			
			|  | 476 | +	physaddr_t address;
 | 
		
	
		
			
			|  | 477 | +	int is_last;
 | 
		
	
		
			
			|  | 478 | +
 | 
		
	
		
			
			|  | 479 | +	/* Get next transmit descriptor */
 | 
		
	
		
			
			|  | 480 | +	if ( ( rtl->tx.prod - rtl->tx.cons ) >= RTL_NUM_TX_DESC ) {
 | 
		
	
		
			
			|  | 481 | +		DBGC ( rtl, "REALTEK %p out of transmit descriptors\n", rtl );
 | 
		
	
		
			
			|  | 482 | +		return -ENOBUFS;
 | 
		
	
		
			
			|  | 483 | +	}
 | 
		
	
		
			
			|  | 484 | +	tx_idx = ( rtl->tx.prod++ % RTL_NUM_TX_DESC );
 | 
		
	
		
			
			|  | 485 | +	is_last = ( tx_idx == ( RTL_NUM_TX_DESC - 1 ) );
 | 
		
	
		
			
			|  | 486 | +	tx = &rtl->tx.desc[tx_idx];
 | 
		
	
		
			
			|  | 487 | +
 | 
		
	
		
			
			|  | 488 | +	/* Populate transmit descriptor */
 | 
		
	
		
			
			|  | 489 | +	address = virt_to_bus ( iobuf->data );
 | 
		
	
		
			
			|  | 490 | +	tx->address = cpu_to_le64 ( address );
 | 
		
	
		
			
			|  | 491 | +	tx->length = cpu_to_le16 ( iob_len ( iobuf ) );
 | 
		
	
		
			
			|  | 492 | +	wmb();
 | 
		
	
		
			
			|  | 493 | +	tx->flags = ( cpu_to_le16 ( RTL_DESC_OWN | RTL_DESC_FS | RTL_DESC_LS ) |
 | 
		
	
		
			
			|  | 494 | +		      ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) );
 | 
		
	
		
			
			|  | 495 | +	wmb();
 | 
		
	
		
			
			|  | 496 | +
 | 
		
	
		
			
			|  | 497 | +	/* Notify card that there are packets ready to transmit */
 | 
		
	
		
			
			|  | 498 | +	writeb ( RTL_TPPOLL_NPQ, rtl->regs + RTL_TPPOLL );
 | 
		
	
		
			
			|  | 499 | +
 | 
		
	
		
			
			|  | 500 | +	DBGC2 ( rtl, "REALTEK %p TX %d is [%llx,%llx)\n", rtl, tx_idx,
 | 
		
	
		
			
			|  | 501 | +		( ( unsigned long long ) address ),
 | 
		
	
		
			
			|  | 502 | +		( ( unsigned long long ) address + iob_len ( iobuf ) ) );
 | 
		
	
		
			
			|  | 503 | +
 | 
		
	
		
			
			|  | 504 | +	return 0;
 | 
		
	
		
			
			|  | 505 | +}
 | 
		
	
		
			
			|  | 506 | +
 | 
		
	
		
			
			|  | 507 | +/**
 | 
		
	
		
			
			|  | 508 | + * Poll for completed packets
 | 
		
	
		
			
			|  | 509 | + *
 | 
		
	
		
			
			|  | 510 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 511 | + */
 | 
		
	
		
			
			|  | 512 | +static void realtek_poll_tx ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 513 | +	struct realtek_nic *rtl = netdev->priv;
 | 
		
	
		
			
			|  | 514 | +	struct realtek_descriptor *tx;
 | 
		
	
		
			
			|  | 515 | +	unsigned int tx_idx;
 | 
		
	
		
			
			|  | 516 | +
 | 
		
	
		
			
			|  | 517 | +	/* Check for completed packets */
 | 
		
	
		
			
			|  | 518 | +	while ( rtl->tx.cons != rtl->tx.prod ) {
 | 
		
	
		
			
			|  | 519 | +
 | 
		
	
		
			
			|  | 520 | +		/* Get next transmit descriptor */
 | 
		
	
		
			
			|  | 521 | +		tx_idx = ( rtl->tx.cons % RTL_NUM_TX_DESC );
 | 
		
	
		
			
			|  | 522 | +		tx = &rtl->tx.desc[tx_idx];
 | 
		
	
		
			
			|  | 523 | +
 | 
		
	
		
			
			|  | 524 | +		/* Stop if descriptor is still in use */
 | 
		
	
		
			
			|  | 525 | +		if ( tx->flags & cpu_to_le16 ( RTL_DESC_OWN ) )
 | 
		
	
		
			
			|  | 526 | +			return;
 | 
		
	
		
			
			|  | 527 | +
 | 
		
	
		
			
			|  | 528 | +		DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx );
 | 
		
	
		
			
			|  | 529 | +
 | 
		
	
		
			
			|  | 530 | +		/* Complete TX descriptor */
 | 
		
	
		
			
			|  | 531 | +		netdev_tx_complete_next ( netdev );
 | 
		
	
		
			
			|  | 532 | +		rtl->tx.cons++;
 | 
		
	
		
			
			|  | 533 | +	}
 | 
		
	
		
			
			|  | 534 | +}
 | 
		
	
		
			
			|  | 535 | +
 | 
		
	
		
			
			|  | 536 | +/**
 | 
		
	
		
			
			|  | 537 | + * Poll for received packets
 | 
		
	
		
			
			|  | 538 | + *
 | 
		
	
		
			
			|  | 539 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 540 | + */
 | 
		
	
		
			
			|  | 541 | +static void realtek_poll_rx ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 542 | +	struct realtek_nic *rtl = netdev->priv;
 | 
		
	
		
			
			|  | 543 | +	struct realtek_descriptor *rx;
 | 
		
	
		
			
			|  | 544 | +	struct io_buffer *iobuf;
 | 
		
	
		
			
			|  | 545 | +	unsigned int rx_idx;
 | 
		
	
		
			
			|  | 546 | +	size_t len;
 | 
		
	
		
			
			|  | 547 | +
 | 
		
	
		
			
			|  | 548 | +	/* Check for received packets */
 | 
		
	
		
			
			|  | 549 | +	while ( rtl->rx.cons != rtl->rx.prod ) {
 | 
		
	
		
			
			|  | 550 | +
 | 
		
	
		
			
			|  | 551 | +		/* Get next receive descriptor */
 | 
		
	
		
			
			|  | 552 | +		rx_idx = ( rtl->rx.cons % RTL_NUM_RX_DESC );
 | 
		
	
		
			
			|  | 553 | +		rx = &rtl->rx.desc[rx_idx];
 | 
		
	
		
			
			|  | 554 | +
 | 
		
	
		
			
			|  | 555 | +		/* Stop if descriptor is still in use */
 | 
		
	
		
			
			|  | 556 | +		if ( rx->flags & cpu_to_le16 ( RTL_DESC_OWN ) )
 | 
		
	
		
			
			|  | 557 | +			return;
 | 
		
	
		
			
			|  | 558 | +
 | 
		
	
		
			
			|  | 559 | +		/* Populate I/O buffer */
 | 
		
	
		
			
			|  | 560 | +		iobuf = rtl->rx_iobuf[rx_idx];
 | 
		
	
		
			
			|  | 561 | +		rtl->rx_iobuf[rx_idx] = NULL;
 | 
		
	
		
			
			|  | 562 | +		len = ( le16_to_cpu ( rx->length ) & RTL_DESC_SIZE_MASK );
 | 
		
	
		
			
			|  | 563 | +		iob_put ( iobuf, ( len - 4 /* strip CRC */ ) );
 | 
		
	
		
			
			|  | 564 | +
 | 
		
	
		
			
			|  | 565 | +		DBGC2 ( rtl, "REALTEK %p RX %d complete (length %zd)\n",
 | 
		
	
		
			
			|  | 566 | +			rtl, rx_idx, len );
 | 
		
	
		
			
			|  | 567 | +
 | 
		
	
		
			
			|  | 568 | +		/* Hand off to network stack */
 | 
		
	
		
			
			|  | 569 | +		if ( rx->flags & cpu_to_le16 ( RTL_DESC_RES ) ) {
 | 
		
	
		
			
			|  | 570 | +			netdev_rx_err ( netdev, iobuf, -EIO );
 | 
		
	
		
			
			|  | 571 | +		} else {
 | 
		
	
		
			
			|  | 572 | +			netdev_rx ( netdev, iobuf );
 | 
		
	
		
			
			|  | 573 | +		}
 | 
		
	
		
			
			|  | 574 | +		rtl->rx.cons++;
 | 
		
	
		
			
			|  | 575 | +	}
 | 
		
	
		
			
			|  | 576 | +}
 | 
		
	
		
			
			|  | 577 | +
 | 
		
	
		
			
			|  | 578 | +/**
 | 
		
	
		
			
			|  | 579 | + * Poll for completed and received packets
 | 
		
	
		
			
			|  | 580 | + *
 | 
		
	
		
			
			|  | 581 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 582 | + */
 | 
		
	
		
			
			|  | 583 | +static void realtek_poll ( struct net_device *netdev ) {
 | 
		
	
		
			
			|  | 584 | +	struct realtek_nic *rtl = netdev->priv;
 | 
		
	
		
			
			|  | 585 | +	uint16_t isr;
 | 
		
	
		
			
			|  | 586 | +
 | 
		
	
		
			
			|  | 587 | +	/* Check for and acknowledge interrupts */
 | 
		
	
		
			
			|  | 588 | +	isr = readw ( rtl->regs + RTL_ISR );
 | 
		
	
		
			
			|  | 589 | +	if ( ! isr )
 | 
		
	
		
			
			|  | 590 | +		return;
 | 
		
	
		
			
			|  | 591 | +	writew ( isr, rtl->regs + RTL_ISR );
 | 
		
	
		
			
			|  | 592 | +
 | 
		
	
		
			
			|  | 593 | +	/* Poll for TX completions, if applicable */
 | 
		
	
		
			
			|  | 594 | +	if ( isr & ( RTL_IRQ_TER | RTL_IRQ_TOK ) )
 | 
		
	
		
			
			|  | 595 | +		realtek_poll_tx ( netdev );
 | 
		
	
		
			
			|  | 596 | +
 | 
		
	
		
			
			|  | 597 | +	/* Poll for RX completionsm, if applicable */
 | 
		
	
		
			
			|  | 598 | +	if ( isr & ( RTL_IRQ_RER | RTL_IRQ_ROK ) )
 | 
		
	
		
			
			|  | 599 | +		realtek_poll_rx ( netdev );
 | 
		
	
		
			
			|  | 600 | +
 | 
		
	
		
			
			|  | 601 | +	/* Check link state, if applicable */
 | 
		
	
		
			
			|  | 602 | +	if ( isr & RTL_IRQ_PUN_LINKCHG )
 | 
		
	
		
			
			|  | 603 | +		realtek_check_link ( netdev );
 | 
		
	
		
			
			|  | 604 | +
 | 
		
	
		
			
			|  | 605 | +	/* Refill RX ring */
 | 
		
	
		
			
			|  | 606 | +	realtek_refill_rx ( rtl );
 | 
		
	
		
			
			|  | 607 | +}
 | 
		
	
		
			
			|  | 608 | +
 | 
		
	
		
			
			|  | 609 | +/**
 | 
		
	
		
			
			|  | 610 | + * Enable or disable interrupts
 | 
		
	
		
			
			|  | 611 | + *
 | 
		
	
		
			
			|  | 612 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 613 | + * @v enable		Interrupts should be enabled
 | 
		
	
		
			
			|  | 614 | + */
 | 
		
	
		
			
			|  | 615 | +static void realtek_irq ( struct net_device *netdev, int enable ) {
 | 
		
	
		
			
			|  | 616 | +	struct realtek_nic *rtl = netdev->priv;
 | 
		
	
		
			
			|  | 617 | +	uint16_t imr;
 | 
		
	
		
			
			|  | 618 | +
 | 
		
	
		
			
			|  | 619 | +	/* Set interrupt mask */
 | 
		
	
		
			
			|  | 620 | +	imr = ( enable ? ( RTL_IRQ_PUN_LINKCHG | RTL_IRQ_TER | RTL_IRQ_TOK |
 | 
		
	
		
			
			|  | 621 | +			   RTL_IRQ_RER | RTL_IRQ_ROK ) : 0 );
 | 
		
	
		
			
			|  | 622 | +	writew ( imr, rtl->regs + RTL_IMR );
 | 
		
	
		
			
			|  | 623 | +}
 | 
		
	
		
			
			|  | 624 | +
 | 
		
	
		
			
			|  | 625 | +/** Realtek network device operations */
 | 
		
	
		
			
			|  | 626 | +static struct net_device_operations realtek_operations = {
 | 
		
	
		
			
			|  | 627 | +	.open		= realtek_open,
 | 
		
	
		
			
			|  | 628 | +	.close		= realtek_close,
 | 
		
	
		
			
			|  | 629 | +	.transmit	= realtek_transmit,
 | 
		
	
		
			
			|  | 630 | +	.poll		= realtek_poll,
 | 
		
	
		
			
			|  | 631 | +	.irq		= realtek_irq,
 | 
		
	
		
			
			|  | 632 | +};
 | 
		
	
		
			
			|  | 633 | +
 | 
		
	
		
			
			|  | 634 | +/******************************************************************************
 | 
		
	
		
			
			|  | 635 | + *
 | 
		
	
		
			
			|  | 636 | + * PCI interface
 | 
		
	
		
			
			|  | 637 | + *
 | 
		
	
		
			
			|  | 638 | + ******************************************************************************
 | 
		
	
		
			
			|  | 639 | + */
 | 
		
	
		
			
			|  | 640 | +
 | 
		
	
		
			
			|  | 641 | +/**
 | 
		
	
		
			
			|  | 642 | + * Probe PCI device
 | 
		
	
		
			
			|  | 643 | + *
 | 
		
	
		
			
			|  | 644 | + * @v pci		PCI device
 | 
		
	
		
			
			|  | 645 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 646 | + */
 | 
		
	
		
			
			|  | 647 | +static int realtek_probe ( struct pci_device *pci ) {
 | 
		
	
		
			
			|  | 648 | +	struct net_device *netdev;
 | 
		
	
		
			
			|  | 649 | +	struct realtek_nic *rtl;
 | 
		
	
		
			
			|  | 650 | +	unsigned int i;
 | 
		
	
		
			
			|  | 651 | +	int rc;
 | 
		
	
		
			
			|  | 652 | +
 | 
		
	
		
			
			|  | 653 | +	/* Allocate and initialise net device */
 | 
		
	
		
			
			|  | 654 | +	netdev = alloc_etherdev ( sizeof ( *rtl ) );
 | 
		
	
		
			
			|  | 655 | +	if ( ! netdev ) {
 | 
		
	
		
			
			|  | 656 | +		rc = -ENOMEM;
 | 
		
	
		
			
			|  | 657 | +		goto err_alloc;
 | 
		
	
		
			
			|  | 658 | +	}
 | 
		
	
		
			
			|  | 659 | +	netdev_init ( netdev, &realtek_operations );
 | 
		
	
		
			
			|  | 660 | +	rtl = netdev->priv;
 | 
		
	
		
			
			|  | 661 | +	pci_set_drvdata ( pci, netdev );
 | 
		
	
		
			
			|  | 662 | +	netdev->dev = &pci->dev;
 | 
		
	
		
			
			|  | 663 | +	memset ( rtl, 0, sizeof ( *rtl ) );
 | 
		
	
		
			
			|  | 664 | +	realtek_init_ring ( &rtl->tx, RTL_NUM_TX_DESC, RTL_TNPDS );
 | 
		
	
		
			
			|  | 665 | +	realtek_init_ring ( &rtl->rx, RTL_NUM_RX_DESC, RTL_RDSAR );
 | 
		
	
		
			
			|  | 666 | +
 | 
		
	
		
			
			|  | 667 | +	/* Fix up PCI device */
 | 
		
	
		
			
			|  | 668 | +	adjust_pci_device ( pci );
 | 
		
	
		
			
			|  | 669 | +
 | 
		
	
		
			
			|  | 670 | +	/* Map registers */
 | 
		
	
		
			
			|  | 671 | +	rtl->regs = ioremap ( pci->membase, RTL_BAR_SIZE );
 | 
		
	
		
			
			|  | 672 | +
 | 
		
	
		
			
			|  | 673 | +	/* Reset the NIC */
 | 
		
	
		
			
			|  | 674 | +	if ( ( rc = realtek_reset ( rtl ) ) != 0 )
 | 
		
	
		
			
			|  | 675 | +		goto err_reset;
 | 
		
	
		
			
			|  | 676 | +
 | 
		
	
		
			
			|  | 677 | +	/* Initialise EEPROM */
 | 
		
	
		
			
			|  | 678 | +	realtek_init_eeprom ( netdev );
 | 
		
	
		
			
			|  | 679 | +
 | 
		
	
		
			
			|  | 680 | +	/* Read MAC address from EEPROM */
 | 
		
	
		
			
			|  | 681 | +	if ( ( rc = nvs_read ( &rtl->eeprom.nvs, RTL_EEPROM_MAC,
 | 
		
	
		
			
			|  | 682 | +			       netdev->hw_addr, ETH_ALEN ) ) != 0 ) {
 | 
		
	
		
			
			|  | 683 | +		DBGC ( rtl, "REALTEK %p could not read MAC address: %s\n",
 | 
		
	
		
			
			|  | 684 | +		       rtl, strerror ( rc ) );
 | 
		
	
		
			
			|  | 685 | +		goto err_nvs_read;
 | 
		
	
		
			
			|  | 686 | +	}
 | 
		
	
		
			
			|  | 687 | +
 | 
		
	
		
			
			|  | 688 | +	/* The EEPROM may not be present for onboard NICs.  Fall back
 | 
		
	
		
			
			|  | 689 | +	 * to reading the current ID register value, which will
 | 
		
	
		
			
			|  | 690 | +	 * hopefully have been programmed by the platform firmware.
 | 
		
	
		
			
			|  | 691 | +	 */
 | 
		
	
		
			
			|  | 692 | +	if ( ! is_valid_ether_addr ( netdev->hw_addr ) ) {
 | 
		
	
		
			
			|  | 693 | +		DBGC ( rtl, "REALTEK %p seems to have no EEPROM\n", rtl );
 | 
		
	
		
			
			|  | 694 | +		for ( i = 0 ; i < ETH_ALEN ; i++ )
 | 
		
	
		
			
			|  | 695 | +			netdev->hw_addr[i] = readb ( rtl->regs + RTL_IDR0 + i );
 | 
		
	
		
			
			|  | 696 | +	}
 | 
		
	
		
			
			|  | 697 | +
 | 
		
	
		
			
			|  | 698 | +	/* Initialise and reset MII interface */
 | 
		
	
		
			
			|  | 699 | +	mii_init ( &rtl->mii, &realtek_mii_operations );
 | 
		
	
		
			
			|  | 700 | +	if ( ( rc = mii_reset ( &rtl->mii ) ) != 0 ) {
 | 
		
	
		
			
			|  | 701 | +		DBGC ( rtl, "REALTEK %p could not reset MII: %s\n",
 | 
		
	
		
			
			|  | 702 | +		       rtl, strerror ( rc ) );
 | 
		
	
		
			
			|  | 703 | +		goto err_mii_reset;
 | 
		
	
		
			
			|  | 704 | +	}
 | 
		
	
		
			
			|  | 705 | +
 | 
		
	
		
			
			|  | 706 | +	/* Register network device */
 | 
		
	
		
			
			|  | 707 | +	if ( ( rc = register_netdev ( netdev ) ) != 0 )
 | 
		
	
		
			
			|  | 708 | +		goto err_register_netdev;
 | 
		
	
		
			
			|  | 709 | +
 | 
		
	
		
			
			|  | 710 | +	/* Set initial link state */
 | 
		
	
		
			
			|  | 711 | +	realtek_check_link ( netdev );
 | 
		
	
		
			
			|  | 712 | +
 | 
		
	
		
			
			|  | 713 | +	/* Register non-volatile options, if applicable */
 | 
		
	
		
			
			|  | 714 | +	if ( rtl->nvo.nvs ) {
 | 
		
	
		
			
			|  | 715 | +		if ( ( rc = register_nvo ( &rtl->nvo,
 | 
		
	
		
			
			|  | 716 | +					   netdev_settings ( netdev ) ) ) != 0)
 | 
		
	
		
			
			|  | 717 | +			goto err_register_nvo;
 | 
		
	
		
			
			|  | 718 | +	}
 | 
		
	
		
			
			|  | 719 | +
 | 
		
	
		
			
			|  | 720 | +	return 0;
 | 
		
	
		
			
			|  | 721 | +
 | 
		
	
		
			
			|  | 722 | + err_register_nvo:
 | 
		
	
		
			
			|  | 723 | +	unregister_netdev ( netdev );
 | 
		
	
		
			
			|  | 724 | + err_register_netdev:
 | 
		
	
		
			
			|  | 725 | + err_mii_reset:
 | 
		
	
		
			
			|  | 726 | + err_nvs_read:
 | 
		
	
		
			
			|  | 727 | +	realtek_reset ( rtl );
 | 
		
	
		
			
			|  | 728 | + err_reset:
 | 
		
	
		
			
			|  | 729 | +	netdev_nullify ( netdev );
 | 
		
	
		
			
			|  | 730 | +	netdev_put ( netdev );
 | 
		
	
		
			
			|  | 731 | + err_alloc:
 | 
		
	
		
			
			|  | 732 | +	return rc;
 | 
		
	
		
			
			|  | 733 | +}
 | 
		
	
		
			
			|  | 734 | +
 | 
		
	
		
			
			|  | 735 | +/**
 | 
		
	
		
			
			|  | 736 | + * Remove PCI device
 | 
		
	
		
			
			|  | 737 | + *
 | 
		
	
		
			
			|  | 738 | + * @v pci		PCI device
 | 
		
	
		
			
			|  | 739 | + */
 | 
		
	
		
			
			|  | 740 | +static void realtek_remove ( struct pci_device *pci ) {
 | 
		
	
		
			
			|  | 741 | +	struct net_device *netdev = pci_get_drvdata ( pci );
 | 
		
	
		
			
			|  | 742 | +	struct realtek_nic *rtl = netdev->priv;
 | 
		
	
		
			
			|  | 743 | +
 | 
		
	
		
			
			|  | 744 | +	/* Unregister non-volatile options, if applicable */
 | 
		
	
		
			
			|  | 745 | +	if ( rtl->nvo.nvs )
 | 
		
	
		
			
			|  | 746 | +		unregister_nvo ( &rtl->nvo );
 | 
		
	
		
			
			|  | 747 | +
 | 
		
	
		
			
			|  | 748 | +	/* Unregister network device */
 | 
		
	
		
			
			|  | 749 | +	unregister_netdev ( netdev );
 | 
		
	
		
			
			|  | 750 | +
 | 
		
	
		
			
			|  | 751 | +	/* Reset card */
 | 
		
	
		
			
			|  | 752 | +	realtek_reset ( rtl );
 | 
		
	
		
			
			|  | 753 | +
 | 
		
	
		
			
			|  | 754 | +	/* Free network device */
 | 
		
	
		
			
			|  | 755 | +	netdev_nullify ( netdev );
 | 
		
	
		
			
			|  | 756 | +	netdev_put ( netdev );
 | 
		
	
		
			
			|  | 757 | +}
 | 
		
	
		
			
			|  | 758 | +
 | 
		
	
		
			
			|  | 759 | +/** Realtek PCI device IDs */
 | 
		
	
		
			
			|  | 760 | +static struct pci_device_id realtek_nics[] = {
 | 
		
	
		
			
			|  | 761 | +	PCI_ROM ( 0x10ec, 0x8129, "r8129",	"RTL-8129", 0 ),
 | 
		
	
		
			
			|  | 762 | +	PCI_ROM ( 0x10ec, 0x8136, "r8136",	"RTL8101E/RTL8102E", 0 ),
 | 
		
	
		
			
			|  | 763 | +	PCI_ROM ( 0x10ec, 0x8167, "r8167",	"RTL-8110SC/8169SC", 0 ),
 | 
		
	
		
			
			|  | 764 | +	PCI_ROM ( 0x10ec, 0x8168, "r8168",	"RTL8111/8168B", 0 ),
 | 
		
	
		
			
			|  | 765 | +	PCI_ROM ( 0x10ec, 0x8169, "r8169",	"RTL-8169", 0 ),
 | 
		
	
		
			
			|  | 766 | +	PCI_ROM ( 0x1186, 0x4300, "dge528t",	"DGE-528T", 0 ),
 | 
		
	
		
			
			|  | 767 | +	PCI_ROM ( 0x1259, 0xc107, "allied8169",	"Allied Telesyn 8169", 0 ),
 | 
		
	
		
			
			|  | 768 | +	PCI_ROM ( 0x16ec, 0x0116, "usr997902",	"USR997902", 0 ),
 | 
		
	
		
			
			|  | 769 | +	PCI_ROM ( 0x1737, 0x1032, "linksys8169","Linksys 8169", 0 ),
 | 
		
	
		
			
			|  | 770 | +	PCI_ROM ( 0x0001, 0x8168, "clone8169",	"Cloned 8169", 0 ),
 | 
		
	
		
			
			|  | 771 | +};
 | 
		
	
		
			
			|  | 772 | +
 | 
		
	
		
			
			|  | 773 | +/** Realtek PCI driver */
 | 
		
	
		
			
			|  | 774 | +struct pci_driver realtek_driver __pci_driver = {
 | 
		
	
		
			
			|  | 775 | +	.ids = realtek_nics,
 | 
		
	
		
			
			|  | 776 | +	.id_count = ( sizeof ( realtek_nics ) / sizeof ( realtek_nics[0] ) ),
 | 
		
	
		
			
			|  | 777 | +	.probe = realtek_probe,
 | 
		
	
		
			
			|  | 778 | +	.remove = realtek_remove,
 | 
		
	
		
			
			|  | 779 | +};
 |