176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2008 Marty Connor <mdc@etherboot.org>
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2008 Entity Cyber, Inc.
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * modify it under the terms of the GNU General Public License as
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * published by the Free Software Foundation; either version 2 of the
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * License, or any later version.
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is distributed in the hope that it will be useful, but
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WITHOUT ANY WARRANTY; without even the implied warranty of
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * General Public License for more details.
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * You should have received a copy of the GNU General Public License
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * along with this program; if not, write to the Free Software
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This driver is based on rtl8169 data sheets and work by:
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) a lot of people too. Please respect their work.
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2676d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER );
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h>
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h>
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdlib.h>
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <unistd.h>
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <assert.h>
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <byteswap.h>
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h>
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/ethernet.h>
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/if_ether.h>
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/io.h>
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/iobuf.h>
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/malloc.h>
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/netdevice.h>
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/pci.h>
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/timer.h>
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <mii.h>
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "r8169.h"
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*** Low level hardware routines ***/
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void mdio_write(void *ioaddr, int reg_addr, int value)
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "mdio_write\n" );
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff));
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 20; i > 0; i--) {
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/*
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * Check if the RTL8169 has completed writing to the specified
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * MII register.
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 */
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (!(RTL_R32(PHYAR) & 0x80000000))
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		udelay(25);
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int mdio_read(void *ioaddr, int reg_addr)
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i, value = -1;
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "mdio_read\n" );
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 20; i > 0; i--) {
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/*
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * Check if the RTL8169 has completed retrieving data from
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * the specified MII register.
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 */
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (RTL_R32(PHYAR) & 0x80000000) {
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			value = RTL_R32(PHYAR) & 0xffff;
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		udelay(25);
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return value;
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void mdio_patch(void *ioaddr, int reg_addr, int value)
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "mdio_patch\n" );
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value);
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_ephy_write(void *ioaddr, int reg_addr, int value)
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int i;
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_ephy_write\n" );
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		(reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < 100; i++) {
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG))
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		udelay(10);
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u16 rtl_ephy_read(void *ioaddr, int reg_addr)
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 value = 0xffff;
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int i;
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_ephy_read\n" );
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < 100; i++) {
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (RTL_R32(EPHYAR) & EPHYAR_FLAG) {
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK;
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		udelay(10);
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return value;
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_csi_write(void *ioaddr, int addr, int value)
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int i;
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_csi_write\n" );
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(CSIDR, value);
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < 100; i++) {
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (!(RTL_R32(CSIAR) & CSIAR_FLAG))
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		udelay(10);
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u32 rtl_csi_read(void *ioaddr, int addr)
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 value = ~0x00;
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int i;
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_csi_read\n" );
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < 100; i++) {
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (RTL_R32(CSIAR) & CSIAR_FLAG) {
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			value = RTL_R32(CSIDR);
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		udelay(10);
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return value;
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_irq_mask_and_ack(void *ioaddr)
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_irq_mask_and_ack\n" );
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(IntrMask, 0x0000);
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(IntrStatus, 0xffff);
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic unsigned int rtl8169_tbi_reset_pending(void *ioaddr)
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_tbi_reset_pending\n" );
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return RTL_R32(TBICSR) & TBIReset;
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic unsigned int rtl8169_xmii_reset_pending(void *ioaddr)
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_xmii_reset_pending\n" );
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic unsigned int rtl8169_tbi_link_ok(void *ioaddr)
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_tbi_link_ok\n" );
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return RTL_R32(TBICSR) & TBILinkOk;
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic unsigned int rtl8169_xmii_link_ok(void *ioaddr)
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_xmii_link_ok\n" );
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return RTL_R8(PHYstatus) & LinkStatus;
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_tbi_reset_enable(void *ioaddr)
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_tbi_reset_enable\n" );
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_xmii_reset_enable(void *ioaddr)
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int val;
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_xmii_reset_enable\n" );
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET;
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, MII_BMCR, val & 0xffff);
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rtl8169_set_speed_tbi(struct net_device *dev,
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				 u8 autoneg, u16 speed, u8 duplex)
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv(dev);
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int ret = 0;
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 reg;
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_set_speed_tbi\n" );
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = RTL_R32(TBICSR);
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (duplex == DUPLEX_FULL)) {
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else if (autoneg == AUTONEG_ENABLE)
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else {
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "incorrect speed setting refused in TBI mode\n" );
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ret = -EOPNOTSUPP;
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return ret;
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rtl8169_set_speed_xmii(struct net_device *dev,
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				  u8 autoneg, u16 speed, u8 duplex)
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv(dev);
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int auto_nego, giga_ctrl;
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_set_speed_xmii\n" );
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       ADVERTISE_100HALF | ADVERTISE_100FULL);
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (autoneg == AUTONEG_ENABLE) {
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      ADVERTISE_100HALF | ADVERTISE_100FULL);
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (speed == SPEED_10)
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL;
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		else if (speed == SPEED_100)
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL;
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		else if (speed == SPEED_1000)
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (duplex == DUPLEX_HALF)
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (duplex == DUPLEX_FULL)
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF);
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* This tweak comes straight from Realtek's driver. */
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		     (tp->mac_version == RTL_GIGA_MAC_VER_16))) {
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* The 8100e/8101e/8102e do Fast Ethernet only. */
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((tp->mac_version == RTL_GIGA_MAC_VER_07) ||
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_08) ||
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_09) ||
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_10) ||
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_13) ||
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_15) ||
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF))) {
30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			DBG ( "PHY does not support 1000Mbps.\n" );
30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/*
31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * Wake up the PHY.
31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 * Vendor specific (0x1f) and reserved (0x0e) MII registers.
31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 */
31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		mdio_write(ioaddr, 0x1f, 0x0000);
31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		mdio_write(ioaddr, 0x0e, 0x0000);
31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->phy_auto_nego_reg = auto_nego;
31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->phy_1000_ctrl_reg = giga_ctrl;
32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rtl8169_set_speed(struct net_device *dev,
32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			     u8 autoneg, u16 speed, u8 duplex)
32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv(dev);
33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int ret;
33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_set_speed\n" );
33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ret = tp->set_speed(dev, autoneg, speed, duplex);
33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return ret;
33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg,
34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				       int bitnum, int bitval)
34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int val;
34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_write_gmii_reg_bit\n" );
34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	val = mdio_read(ioaddr, reg);
34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	val = (bitval == 1) ?
34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		val | (bitval << bitnum) :  val & ~(0x0001 << bitnum);
35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, reg, val & 0xffff);
35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_get_mac_version(struct rtl8169_private *tp,
35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				    void *ioaddr)
35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/*
35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * The driver currently handles the 8168Bf and the 8168Be identically
35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * but they can be identified more specifically through the test below
35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * if needed:
36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 *
36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 *
36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * Same thing for the 8101Eb and the 8101Ec:
36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 *
36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	const struct {
36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		u32 mask;
36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		u32 val;
37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		int mac_version;
37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} mac_info[] = {
37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* 8168D family. */
37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7c800000, 0x28000000,	RTL_GIGA_MAC_VER_25 },
37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* 8168C family. */
37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x3ca00000,	RTL_GIGA_MAC_VER_24 },
37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x3c900000,	RTL_GIGA_MAC_VER_23 },
37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x3c800000,	RTL_GIGA_MAC_VER_18 },
37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7c800000, 0x3c800000,	RTL_GIGA_MAC_VER_24 },
38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x3c000000,	RTL_GIGA_MAC_VER_19 },
38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x3c200000,	RTL_GIGA_MAC_VER_20 },
38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x3c300000,	RTL_GIGA_MAC_VER_21 },
38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x3c400000,	RTL_GIGA_MAC_VER_22 },
38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7c800000, 0x3c000000,	RTL_GIGA_MAC_VER_22 },
38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* 8168B family. */
38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x38000000,	RTL_GIGA_MAC_VER_12 },
38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x38500000,	RTL_GIGA_MAC_VER_17 },
38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7c800000, 0x38000000,	RTL_GIGA_MAC_VER_17 },
39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7c800000, 0x30000000,	RTL_GIGA_MAC_VER_11 },
39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* 8101 family. */
39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x34a00000,	RTL_GIGA_MAC_VER_09 },
39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x24a00000,	RTL_GIGA_MAC_VER_09 },
39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x34900000,	RTL_GIGA_MAC_VER_08 },
39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x24900000,	RTL_GIGA_MAC_VER_08 },
39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x34800000,	RTL_GIGA_MAC_VER_07 },
39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x24800000,	RTL_GIGA_MAC_VER_07 },
39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x34000000,	RTL_GIGA_MAC_VER_13 },
40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x34300000,	RTL_GIGA_MAC_VER_10 },
40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7cf00000, 0x34200000,	RTL_GIGA_MAC_VER_16 },
40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7c800000, 0x34800000,	RTL_GIGA_MAC_VER_09 },
40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7c800000, 0x24800000,	RTL_GIGA_MAC_VER_09 },
40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7c800000, 0x34000000,	RTL_GIGA_MAC_VER_16 },
40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* FIXME: where did these entries come from ? -- FR */
40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0xfc800000, 0x38800000,	RTL_GIGA_MAC_VER_15 },
40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0xfc800000, 0x30800000,	RTL_GIGA_MAC_VER_14 },
40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* 8110 family. */
41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0xfc800000, 0x98000000,	RTL_GIGA_MAC_VER_06 },
41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0xfc800000, 0x18000000,	RTL_GIGA_MAC_VER_05 },
41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0xfc800000, 0x10000000,	RTL_GIGA_MAC_VER_04 },
41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0xfc800000, 0x04000000,	RTL_GIGA_MAC_VER_03 },
41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0xfc800000, 0x00800000,	RTL_GIGA_MAC_VER_02 },
41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0xfc800000, 0x00000000,	RTL_GIGA_MAC_VER_01 },
41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x00000000, 0x00000000,	RTL_GIGA_MAC_VER_01 }	/* Catch-all */
41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}, *p = mac_info;
41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 reg;
42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_get_mac_version\n" );
42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = RTL_R32(TxConfig);
42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	while ((reg & p->mask) != p->val)
42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		p++;
42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->mac_version = p->mac_version;
42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "tp->mac_version = %d\n", tp->mac_version );
42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (p->mask == 0x00000000) {
43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "unknown MAC (%08x)\n", reg );
43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct phy_reg {
43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 reg;
43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 val;
43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_phy_write(void *ioaddr, struct phy_reg *regs, int len)
44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_phy_write\n" );
44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	while (len-- > 0) {
44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		mdio_write(ioaddr, regs->reg, regs->val);
44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		regs++;
44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169s_hw_phy_config(void *ioaddr)
45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct {
45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		u16 regs[5]; /* Beware of bit-sign propagation */
45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} phy_magic[5] = { {
45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x0000,	//w 4 15 12 0
45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0x00a1,	//w 3 15 0 00a1
45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0x0008,	//w 2 15 0 0008
45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0x1020,	//w 1 15 0 1020
45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0x1000 } },{	//w 0 15 0 1000
46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x7000,	//w 4 15 12 7
46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xff41,	//w 3 15 0 ff41
46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xde60,	//w 2 15 0 de60
46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0x0140,	//w 1 15 0 0140
46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0x0077 } },{	//w 0 15 0 0077
46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0xa000,	//w 4 15 12 a
46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xdf01,	//w 3 15 0 df01
46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xdf20,	//w 2 15 0 df20
46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xff95,	//w 1 15 0 ff95
46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xfa00 } },{	//w 0 15 0 fa00
47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0xb000,	//w 4 15 12 b
47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xff41,	//w 3 15 0 ff41
47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xde20,	//w 2 15 0 de20
47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0x0140,	//w 1 15 0 0140
47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0x00bb } },{	//w 0 15 0 00bb
47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0xf000,	//w 4 15 12 f
47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xdf01,	//w 3 15 0 df01
47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xdf20,	//w 2 15 0 df20
47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xff95,	//w 1 15 0 ff95
47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		  0xbf00 }	//w 0 15 0 bf00
48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}, *p = phy_magic;
48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int i;
48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169s_hw_phy_config\n" );
48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, 0x1f, 0x0001);		//w 31 2 0 1
48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, 0x15, 0x1000);		//w 21 15 0 1000
48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, 0x18, 0x65c7);		//w 24 15 0 65c7
48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0);	//w 4 11 11 0
49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {
49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		int val, pos = 4;
49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);
49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		mdio_write(ioaddr, pos, val);
49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		while (--pos >= 0)
49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff);
49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1
49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0
50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169sb_hw_phy_config(void *ioaddr)
50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct phy_reg phy_reg_init[] = {
50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0002 },
50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x01, 0x90d0 },
50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 }
51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169sb_hw_phy_config\n" );
51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8168bb_hw_phy_config(void *ioaddr)
51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct phy_reg phy_reg_init[] = {
52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x10, 0xf41b },
52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 }
52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, 0x1f, 0x0001);
52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x16, 1 << 0);
52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8168bb_hw_phy_config\n" );
52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8168bef_hw_phy_config(void *ioaddr)
53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct phy_reg phy_reg_init[] = {
53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0001 },
53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x10, 0xf41b },
53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 }
53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8168bef_hw_phy_config\n" );
54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8168cp_1_hw_phy_config(void *ioaddr)
54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct phy_reg phy_reg_init[] = {
54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 },
54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1d, 0x0f00 },
55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0002 },
55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x0c, 0x1ec8 },
55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 }
55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8168cp_1_hw_phy_config\n" );
55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8168cp_2_hw_phy_config(void *ioaddr)
56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct phy_reg phy_reg_init[] = {
56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0001 },
56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1d, 0x3d98 },
56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 }
56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8168cp_2_hw_phy_config\n" );
56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, 0x1f, 0x0000);
57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x14, 1 << 5);
57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x0d, 1 << 5);
57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8168c_1_hw_phy_config(void *ioaddr)
57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct phy_reg phy_reg_init[] = {
58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0001 },
58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x12, 0x2300 },
58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0002 },
58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x00, 0x88d4 },
58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x01, 0x82b1 },
58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x03, 0x7002 },
58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x08, 0x9e30 },
58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x09, 0x01f0 },
58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x0a, 0x5500 },
58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x0c, 0x00c8 },
59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0003 },
59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x12, 0xc096 },
59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x16, 0x000a },
59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 },
59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 },
59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x09, 0x2000 },
59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x09, 0x0000 }
59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8168c_1_hw_phy_config\n" );
60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x14, 1 << 5);
60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x0d, 1 << 5);
60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, 0x1f, 0x0000);
60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8168c_2_hw_phy_config(void *ioaddr)
60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct phy_reg phy_reg_init[] = {
61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0001 },
61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x12, 0x2300 },
61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x03, 0x802f },
61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x02, 0x4f02 },
61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x01, 0x0409 },
61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x00, 0xf099 },
61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x04, 0x9800 },
61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x04, 0x9000 },
61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1d, 0x3d98 },
62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0002 },
62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x0c, 0x7eb8 },
62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x06, 0x0761 },
62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0003 },
62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x16, 0x0f0a },
62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 }
62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8168c_2_hw_phy_config\n" );
62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x16, 1 << 0);
63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x14, 1 << 5);
63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x0d, 1 << 5);
63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, 0x1f, 0x0000);
63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8168c_3_hw_phy_config(void *ioaddr)
63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct phy_reg phy_reg_init[] = {
64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0001 },
64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x12, 0x2300 },
64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1d, 0x3d98 },
64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0002 },
64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x0c, 0x7eb8 },
64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x06, 0x5461 },
64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0003 },
64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x16, 0x0f0a },
64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 }
65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8168c_3_hw_phy_config\n" );
65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x16, 1 << 0);
65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x14, 1 << 5);
65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x0d, 1 << 5);
65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, 0x1f, 0x0000);
66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8168c_4_hw_phy_config(void *ioaddr)
66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8168c_4_hw_phy_config\n" );
66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8168c_3_hw_phy_config(ioaddr);
66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8168d_hw_phy_config(void *ioaddr)
67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct phy_reg phy_reg_init_0[] = {
67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0001 },
67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x09, 0x2770 },
67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x08, 0x04d0 },
67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x0b, 0xad15 },
67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x0c, 0x5bf0 },
67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1c, 0xf101 },
67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0003 },
67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x14, 0x94d7 },
68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x12, 0xf4d6 },
68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x09, 0xca0f },
68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0002 },
68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x0b, 0x0b10 },
68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x0c, 0xd1f7 },
68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0002 },
68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x06, 0x5461 },
68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0002 },
68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x05, 0x6662 },
68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 },
69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x14, 0x0060 },
69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 },
69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x0d, 0xf8a0 },
69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0005 },
69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x05, 0xffc2 }
69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8168d_hw_phy_config\n" );
69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (mdio_read(ioaddr, 0x06) == 0xc400) {
70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		struct phy_reg phy_reg_init_1[] = {
70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x1f, 0x0005 },
70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x01, 0x0300 },
70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x1f, 0x0000 },
70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x11, 0x401c },
70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x16, 0x4100 },
70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x1f, 0x0005 },
70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x07, 0x0010 },
71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x05, 0x83dc },
71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0x087d },
71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x05, 0x8300 },
71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0x0101 },
71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0x05f8 },
71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0xf9fa },
71676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0xfbef },
71776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0x79e2 },
71876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0x835f },
71976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0xe0f8 },
72076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0x9ae1 },
72176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0xf89b },
72276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0xef31 },
72376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0x3b65 },
72476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0xaa07 },
72576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0x81e4 },
72676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0xf89a },
72776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0xe5f8 },
72876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0x9baf },
72976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0x06ae },
73076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x05, 0x83dc },
73176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			{ 0x06, 0x8300 },
73276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		};
73376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
73476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_phy_write(ioaddr, phy_reg_init_1,
73576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      ARRAY_SIZE(phy_reg_init_1));
73676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
73776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
73876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, 0x1f, 0x0000);
73976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
74076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
74176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8102e_hw_phy_config(void *ioaddr)
74276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
74376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct phy_reg phy_reg_init[] = {
74476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0003 },
74576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x08, 0x441d },
74676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x01, 0x9100 },
74776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x1f, 0x0000 }
74876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
74976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
75076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8102e_hw_phy_config\n" );
75176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
75276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_write(ioaddr, 0x1f, 0x0000);
75376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x11, 1 << 12);
75476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdio_patch(ioaddr, 0x19, 1 << 13);
75576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
75676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
75776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
75876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
75976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_phy_config(struct net_device *dev)
76076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
76176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv(dev);
76276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
76376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_phy_config\n" );
76576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "mac_version = 0x%02x\n", tp->mac_version );
76776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch (tp->mac_version) {
76976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_01:
77076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
77176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_02:
77276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_03:
77376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8169s_hw_phy_config(ioaddr);
77476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
77576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_04:
77676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8169sb_hw_phy_config(ioaddr);
77776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
77876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_07:
77976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_08:
78076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_09:
78176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8102e_hw_phy_config(ioaddr);
78276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
78376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_11:
78476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8168bb_hw_phy_config(ioaddr);
78576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
78676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_12:
78776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8168bef_hw_phy_config(ioaddr);
78876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
78976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_17:
79076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8168bef_hw_phy_config(ioaddr);
79176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
79276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_18:
79376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8168cp_1_hw_phy_config(ioaddr);
79476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
79576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_19:
79676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8168c_1_hw_phy_config(ioaddr);
79776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
79876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_20:
79976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8168c_2_hw_phy_config(ioaddr);
80076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
80176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_21:
80276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8168c_3_hw_phy_config(ioaddr);
80376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
80476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_22:
80576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8168c_4_hw_phy_config(ioaddr);
80676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
80776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_23:
80876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_24:
80976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8168cp_2_hw_phy_config(ioaddr);
81076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
81176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_25:
81276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8168d_hw_phy_config(ioaddr);
81376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
81476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	default:
81676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
81776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
81876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
81976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
82076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_phy_reset(struct net_device *dev __unused,
82176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      struct rtl8169_private *tp)
82276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
82376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
82476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int i;
82576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
82676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_phy_reset\n" );
82776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
82876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->phy_reset_enable(ioaddr);
82976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < 100; i++) {
83076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (!tp->phy_reset_pending(ioaddr))
83176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			return;
83276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		mdelay ( 1 );
83376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
83476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "PHY reset failed.\n" );
83576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
83676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
83776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
83876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
83976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
84076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
84176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_init_phy\n" );
84276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
84376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_hw_phy_config(dev);
84476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
84576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
84676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" );
84776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		RTL_W8(0x82, 0x01);
84876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
84976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
85076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
85176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
85276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
85376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
85476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
85576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
85676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" );
85776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		RTL_W8(0x82, 0x01);
85876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Set PHY Reg 0x0bh = 0x00h\n" );
85976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
86076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
86176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
86276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_phy_reset(dev, tp);
86376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
86476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/*
86576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * rtl8169_set_speed_xmii takes good care of the Fast Ethernet
86676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * only 8101. Don't panic.
86776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
86876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL);
86976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
87076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((RTL_R8(PHYstatus) & TBI_Enable))
87176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "TBI auto-negotiating\n" );
87276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
87376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
87476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const struct rtl_cfg_info {
87576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void (*hw_start)(struct net_device *);
87676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int region;
87776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int align;
87876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 intr_event;
87976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 napi_event;
88076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned features;
88176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} rtl_cfg_infos [] = {
88276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	[RTL_CFG_0] = {
88376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.hw_start	= rtl_hw_start_8169,
88476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.region		= 1,
88576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.align		= 0,
88676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.intr_event	= SYSErr | LinkChg | RxOverflow |
88776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
88876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.napi_event	= RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
88976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.features	= RTL_FEATURE_GMII
89076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	},
89176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	[RTL_CFG_1] = {
89276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.hw_start	= rtl_hw_start_8168,
89376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.region		= 2,
89476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.align		= 8,
89576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.intr_event	= SYSErr | LinkChg | RxOverflow |
89676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				  TxErr | TxOK | RxOK | RxErr,
89776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.napi_event	= TxErr | TxOK | RxOK | RxOverflow,
89876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.features	= RTL_FEATURE_GMII
89976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	},
90076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	[RTL_CFG_2] = {
90176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.hw_start	= rtl_hw_start_8101,
90276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.region		= 2,
90376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.align		= 8,
90476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.intr_event	= SYSErr | LinkChg | RxOverflow | PCSTimeout |
90576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				  RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
90676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.napi_event	= RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
90776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
90876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
90976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
91076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_hw_reset(void *ioaddr)
91176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
91276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_hw_reset\n" );
91376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
91476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Disable interrupts */
91576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_irq_mask_and_ack(ioaddr);
91676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
91776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Reset the chipset */
91876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(ChipCmd, CmdReset);
91976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
92076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* PCI commit */
92176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_R8(ChipCmd);
92276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
92376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
92476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
92576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
92676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
92776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 cfg = rtl8169_rx_config;
92876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
92976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_set_rx_tx_config_registers\n" );
93076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
93176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
93276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(RxConfig, cfg);
93376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
93476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Set DMA burst size and Interframe Gap Time */
93576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
93676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		(InterFrameGap << TxInterFrameGapShift));
93776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
93876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
93976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_soft_reset ( struct net_device *dev )
94076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
94176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv(dev);
94276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
94376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int i;
94476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
94576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_soft_reset\n" );
94676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
94776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Soft reset the chip. */
94876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(ChipCmd, CmdReset);
94976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
95076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Check that the chip has finished the reset. */
95176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < 100; i++) {
95276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
95376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
95476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		mdelay ( 1 );
95576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
95676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
95776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( i == 100 ) {
95876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Reset Failed! (> 100 iterations)\n" );
95976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
96076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
96176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
96276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start ( struct net_device *dev )
96376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
96476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv ( dev );
96576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
96676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start\n" );
96776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
96876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Soft reset NIC */
96976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_soft_reset ( dev );
97076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
97176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->hw_start ( dev );
97276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
97376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
97476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
97576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman					 void *ioaddr)
97676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
97776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_set_rx_tx_desc_registers\n" );
97876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
97976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/*
98076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
98176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * register to be written before TxDescAddrLow to work.
98276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * Switching from MMIO to I/O access fixes the issue as well.
98376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
98476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32 ( TxDescStartAddrHigh, 0 );
98576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32 ( TxDescStartAddrLow, virt_to_bus ( tp->tx_base ) );
98676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32 ( RxDescAddrHigh, 0 );
98776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32 ( RxDescAddrLow, virt_to_bus ( tp->rx_base ) );
98876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
98976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
99076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u16 rtl_rw_cpluscmd(void *ioaddr)
99176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
99276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 cmd;
99376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
99476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_rw_cpluscmd\n" );
99576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
99676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cmd = RTL_R16(CPlusCmd);
99776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(CPlusCmd, cmd);
99876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return cmd;
99976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
100076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
100176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_set_rx_max_size(void *ioaddr)
100276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
100376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_set_rx_max_size\n" );
100476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
100576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16 ( RxMaxSize, RX_BUF_SIZE );
100676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
100776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
100876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_set_magic_reg(void *ioaddr, unsigned mac_version)
100976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
101076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct {
101176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		u32 mac_version;
101276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		u32 clk;
101376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		u32 val;
101476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} cfg2_info [] = {
101576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
101676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
101776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
101876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
101976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}, *p = cfg2_info;
102076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int i;
102176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 clk;
102276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
102376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_set_magic_reg\n" );
102476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
102576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	clk = RTL_R8(Config2) & PCI_Clock_66MHz;
102676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
102776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ((p->mac_version == mac_version) && (p->clk == clk)) {
102876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			RTL_W32(0x7c, p->val);
102976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
103076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
103176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
103276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
103376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
103476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_set_rx_mode ( struct net_device *netdev )
103576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
103676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv ( netdev );
103776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
103876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 tmp;
103976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
104076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_set_rx_mode\n" );
104176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
104276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Accept all Multicast Packets */
104376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
104476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32 ( MAR0 + 0, 0xffffffff );
104576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32 ( MAR0 + 4, 0xffffffff );
104676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
104776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tmp = rtl8169_rx_config | AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
104876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	      ( RTL_R32 ( RxConfig ) & rtl_chip_info[tp->chipset].RxConfigMask );
104976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
105076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32 ( RxConfig, tmp );
105176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
105276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
105376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8169(struct net_device *dev)
105476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
105576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv(dev);
105676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
105776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct pci_device *pdev = tp->pci_dev;
105876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
105976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8169\n" );
106076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
106176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
106276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
106376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
106476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
106576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
106676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Cfg9346, Cfg9346_Unlock);
106776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
106876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
106976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
107076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
107176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_04))
107276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
107376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
107476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(EarlyTxThres, EarlyTxThld);
107576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
107676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_set_rx_max_size(ioaddr);
107776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
107876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
107976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
108076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
108176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_04))
108276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_set_rx_tx_config_registers(tp);
108376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
108476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
108576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
108676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
108776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
108876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Set MAC Reg C+CR Offset 0xE0. "
108976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			"Bit-3 and bit-14 MUST be 1\n" );
109076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->cp_cmd |= (1 << 14);
109176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
109276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
109376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(CPlusCmd, tp->cp_cmd);
109476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
109576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_set_magic_reg(ioaddr, tp->mac_version);
109676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
109776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/*
109876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * Undocumented corner. Supposedly:
109976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
110076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
110176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(IntrMitigate, 0x0000);
110276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
110376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_set_rx_tx_desc_registers(tp, ioaddr);
110476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
110576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
110676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
110776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
110876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
110976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
111076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_set_rx_tx_config_registers(tp);
111176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
111276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
111376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Cfg9346, Cfg9346_Lock);
111476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
111576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Initially a 10 us delay. Turned it into a PCI commit. - FR */
111676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_R8(IntrMask);
111776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
111876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(RxMissed, 0);
111976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
112076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_set_rx_mode(dev);
112176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
112276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* no early-rx interrupts */
112376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
112476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
112576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	//        RTL_W16(IntrMask, tp->intr_event);
112676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
112776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
112876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_tx_performance_tweak(struct pci_device *pdev, u16 force)
112976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
113076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct net_device *dev = pci_get_drvdata(pdev);
113176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv(dev);
113276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int cap = tp->pcie_cap;
113376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
113476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_tx_performance_tweak\n" );
113576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
113676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (cap) {
113776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		u16 ctl;
113876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
113976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
114076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
114176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
114276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
114376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
114476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
114576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_csi_access_enable(void *ioaddr)
114676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
114776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 csi;
114876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
114976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_csi_access_enable\n" );
115076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
115176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff;
115276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000);
115376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
115476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
115576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct ephy_info {
115676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int offset;
115776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 mask;
115876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 bits;
115976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
116076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
116176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_ephy_init(void *ioaddr, struct ephy_info *e, int len)
116276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
116376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 w;
116476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
116576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_ephy_init\n" );
116676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
116776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	while (len-- > 0) {
116876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits;
116976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_ephy_write(ioaddr, e->offset, w);
117076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		e++;
117176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
117276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
117376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
117476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_disable_clock_request(struct pci_device *pdev)
117576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
117676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct net_device *dev = pci_get_drvdata(pdev);
117776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv(dev);
117876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int cap = tp->pcie_cap;
117976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
118076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_disable_clock_request\n" );
118176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
118276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (cap) {
118376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		u16 ctl;
118476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
118576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
118676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
118776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
118876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
118976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
119076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
119176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define R8168_CPCMD_QUIRK_MASK (\
119276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	EnableBist | \
119376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Mac_dbgo_oe | \
119476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Force_half_dup | \
119576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Force_rxflow_en | \
119676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Force_txflow_en | \
119776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Cxpl_dbg_sel | \
119876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ASF | \
119976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PktCntrDisable | \
120076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Mac_dbgo_sel)
120176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
120276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8168bb(void *ioaddr, struct pci_device *pdev)
120376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
120476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8168bb\n" );
120576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
120676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
120776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
120876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
120976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
121076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_tx_performance_tweak(pdev,
121176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		(0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
121276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
121376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
121476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8168bef(void *ioaddr, struct pci_device *pdev)
121576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
121676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8168bef\n" );
121776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
121876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_hw_start_8168bb(ioaddr, pdev);
121976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
122076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(EarlyTxThres, EarlyTxThld);
122176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
122276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
122376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
122476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
122576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void __rtl_hw_start_8168cp(void *ioaddr, struct pci_device *pdev)
122676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
122776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "__rtl_hw_start_8168cp\n" );
122876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
122976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
123076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
123176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
123276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
123376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
123476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
123576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_disable_clock_request(pdev);
123676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
123776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
123876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
123976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
124076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8168cp_1(void *ioaddr, struct pci_device *pdev)
124176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
124276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	static struct ephy_info e_info_8168cp[] = {
124376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x01, 0,	0x0001 },
124476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x02, 0x0800,	0x1000 },
124576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x03, 0,	0x0042 },
124676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x06, 0x0080,	0x0000 },
124776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x07, 0,	0x2000 }
124876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
124976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
125076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8168cp_1\n" );
125176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
125276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_csi_access_enable(ioaddr);
125376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
125476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
125576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
125676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__rtl_hw_start_8168cp(ioaddr, pdev);
125776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
125876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
125976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8168cp_2(void *ioaddr, struct pci_device *pdev)
126076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
126176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8168cp_2\n" );
126276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
126376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_csi_access_enable(ioaddr);
126476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
126576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
126676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
126776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
126876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
126976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
127076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
127176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
127276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8168cp_3(void *ioaddr, struct pci_device *pdev)
127376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
127476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8168cp_3\n" );
127576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
127676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_csi_access_enable(ioaddr);
127776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
127876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
127976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
128076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Magic. */
128176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(DBG_REG, 0x20);
128276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
128376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(EarlyTxThres, EarlyTxThld);
128476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
128576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
128676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
128776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
128876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
128976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
129076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8168c_1(void *ioaddr, struct pci_device *pdev)
129176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
129276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	static struct ephy_info e_info_8168c_1[] = {
129376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x02, 0x0800,	0x1000 },
129476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x03, 0,	0x0002 },
129576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x06, 0x0080,	0x0000 }
129676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
129776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
129876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8168c_1\n" );
129976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
130076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_csi_access_enable(ioaddr);
130176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
130276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
130376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
130476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
130576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
130676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__rtl_hw_start_8168cp(ioaddr, pdev);
130776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
130876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
130976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8168c_2(void *ioaddr, struct pci_device *pdev)
131076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
131176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	static struct ephy_info e_info_8168c_2[] = {
131276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x01, 0,	0x0001 },
131376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x03, 0x0400,	0x0220 }
131476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
131576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
131676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8168c_2\n" );
131776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
131876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_csi_access_enable(ioaddr);
131976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
132076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
132176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
132276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__rtl_hw_start_8168cp(ioaddr, pdev);
132376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
132476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
132576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8168c_3(void *ioaddr, struct pci_device *pdev)
132676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
132776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8168c_3\n" );
132876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
132976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_hw_start_8168c_2(ioaddr, pdev);
133076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
133176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
133276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8168c_4(void *ioaddr, struct pci_device *pdev)
133376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
133476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8168c_4\n" );
133576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
133676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_csi_access_enable(ioaddr);
133776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
133876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__rtl_hw_start_8168cp(ioaddr, pdev);
133976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
134076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
134176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8168d(void *ioaddr, struct pci_device *pdev)
134276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
134376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8168d\n" );
134476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
134576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_csi_access_enable(ioaddr);
134676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
134776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_disable_clock_request(pdev);
134876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
134976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(EarlyTxThres, EarlyTxThld);
135076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
135176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
135276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
135376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
135476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
135576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
135676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8168(struct net_device *dev)
135776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
135876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv(dev);
135976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
136076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct pci_device *pdev = tp->pci_dev;
136176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
136276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8168\n" );
136376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
136476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Cfg9346, Cfg9346_Unlock);
136576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
136676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(EarlyTxThres, EarlyTxThld);
136776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
136876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_set_rx_max_size(ioaddr);
136976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
137076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
137176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
137276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(CPlusCmd, tp->cp_cmd);
137376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
137476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(IntrMitigate, 0x5151);
137576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
137676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Work around for RxFIFO overflow. */
137776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
137876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->intr_event |= RxFIFOOver | PCSTimeout;
137976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->intr_event &= ~RxOverflow;
138076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
138176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
138276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_set_rx_tx_desc_registers(tp, ioaddr);
138376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
138476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_set_rx_mode(dev);
138576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
138676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
138776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		(InterFrameGap << TxInterFrameGapShift));
138876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
138976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_R8(IntrMask);
139076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
139176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch (tp->mac_version) {
139276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_11:
139376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8168bb(ioaddr, pdev);
139476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
139576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
139676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_12:
139776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_17:
139876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8168bef(ioaddr, pdev);
139976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
140076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
140176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_18:
140276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8168cp_1(ioaddr, pdev);
140376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
140476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
140576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_19:
140676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8168c_1(ioaddr, pdev);
140776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
140876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
140976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_20:
141076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8168c_2(ioaddr, pdev);
141176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
141276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
141376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_21:
141476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8168c_3(ioaddr, pdev);
141576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
141676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
141776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_22:
141876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8168c_4(ioaddr, pdev);
141976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
142076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
142176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_23:
142276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8168cp_2(ioaddr, pdev);
142376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
142476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
142576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_24:
142676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8168cp_3(ioaddr, pdev);
142776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
142876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
142976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_25:
143076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8168d(ioaddr, pdev);
143176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
143276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
143376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	default:
143476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Unknown chipset (mac_version = %d).\n",
143576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		      tp->mac_version );
143676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
143776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
143876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
143976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
144076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
144176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Cfg9346, Cfg9346_Lock);
144276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
144376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
144476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
144576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	//        RTL_W16(IntrMask, tp->intr_event);
144676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
144776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
144876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define R810X_CPCMD_QUIRK_MASK (\
144976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	EnableBist | \
145076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Mac_dbgo_oe | \
145176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Force_half_dup | \
145276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Force_half_dup | \
145376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Force_txflow_en | \
145476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Cxpl_dbg_sel | \
145576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ASF | \
145676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PktCntrDisable | \
145776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCIDAC | \
145876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCIMulRW)
145976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
146076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8102e_1(void *ioaddr, struct pci_device *pdev)
146176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
146276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	static struct ephy_info e_info_8102e_1[] = {
146376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x01,	0, 0x6e65 },
146476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x02,	0, 0x091f },
146576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x03,	0, 0xc2f9 },
146676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x06,	0, 0xafb5 },
146776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x07,	0, 0x0e00 },
146876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x19,	0, 0xec80 },
146976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x01,	0, 0x2e65 },
147076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		{ 0x01,	0, 0x6e65 }
147176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	};
147276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u8 cfg1;
147376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
147476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8102e_1\n" );
147576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
147676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_csi_access_enable(ioaddr);
147776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
147876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(DBG_REG, FIX_NAK_1);
147976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
148076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
148176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
148276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Config1,
148376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
148476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
148576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
148676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cfg1 = RTL_R8(Config1);
148776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
148876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		RTL_W8(Config1, cfg1 & ~LEDS0);
148976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
149076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
149176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
149276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
149376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
149476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
149576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8102e_2(void *ioaddr, struct pci_device *pdev)
149676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
149776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8102e_2\n" );
149876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
149976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_csi_access_enable(ioaddr);
150076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
150176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
150276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
150376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
150476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
150576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
150676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
150776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
150876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
150976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8102e_3(void *ioaddr, struct pci_device *pdev)
151076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
151176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8102e_3\n" );
151276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
151376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_hw_start_8102e_2(ioaddr, pdev);
151476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
151576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_ephy_write(ioaddr, 0x03, 0xc2f9);
151676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
151776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
151876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl_hw_start_8101(struct net_device *dev)
151976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
152076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv(dev);
152176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
152276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct pci_device *pdev = tp->pci_dev;
152376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
152476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl_hw_start_8101\n" );
152576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
152676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
152776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
152876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		int cap = tp->pcie_cap;
152976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
153076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (cap) {
153176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL,
153276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman					      PCI_EXP_DEVCTL_NOSNOOP_EN);
153376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
153476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
153576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
153676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch (tp->mac_version) {
153776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_07:
153876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8102e_1(ioaddr, pdev);
153976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
154076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
154176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_08:
154276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8102e_3(ioaddr, pdev);
154376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
154476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
154576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL_GIGA_MAC_VER_09:
154676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl_hw_start_8102e_2(ioaddr, pdev);
154776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
154876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
154976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
155076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Cfg9346, Cfg9346_Unlock);
155176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
155276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(EarlyTxThres, EarlyTxThld);
155376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
155476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_set_rx_max_size(ioaddr);
155576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
155676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
155776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
155876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(CPlusCmd, tp->cp_cmd);
155976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
156076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(IntrMitigate, 0x0000);
156176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
156276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_set_rx_tx_desc_registers(tp, ioaddr);
156376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
156476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
156576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_set_rx_tx_config_registers(tp);
156676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
156776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(Cfg9346, Cfg9346_Lock);
156876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
156976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_R8(IntrMask);
157076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
157176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_set_rx_mode(dev);
157276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
157376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
157476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
157576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
157676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
157776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	//        RTL_W16(IntrMask, tp->intr_event);
157876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
157976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
158076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*** gPXE API Support Routines ***/
158176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
158276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
158376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * setup_tx_resources - allocate tx resources (descriptors)
158476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
158576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v tp	 Driver private storage
158676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
158776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc       Returns 0 on success, negative on failure
158876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman **/
158976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int
159076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_setup_tx_resources ( struct rtl8169_private *tp )
159176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
159276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_setup_tx_resources\n" );
159376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
159476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->tx_base = malloc_dma ( R8169_TX_RING_BYTES, TX_RING_ALIGN );
159576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
159676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! tp->tx_base ) {
159776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENOMEM;
159876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
159976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
160076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset ( tp->tx_base, 0, R8169_TX_RING_BYTES );
160176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
160276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "tp->tx_base      = %#08lx\n", virt_to_bus ( tp->tx_base ) );
160376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
160476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->tx_fill_ctr = 0;
160576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->tx_curr = 0;
160676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->tx_tail = 0;
160776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
160876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
160976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
161076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
161176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
161276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_process_tx_packets ( struct net_device *netdev )
161376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
161476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv ( netdev );
161576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
161676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint32_t tx_status;
161776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct TxDesc *tx_curr_desc;
161876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
161976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_process_tx_packets\n" );
162076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
162176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	while ( tp->tx_tail != tp->tx_curr ) {
162276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
162376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tx_curr_desc = tp->tx_base  + tp->tx_tail;
162476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
162576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tx_status = tx_curr_desc->opts1;
162676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
162776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG2 ( "Before DescOwn check tx_status: %#08x\n", tx_status );
162876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
162976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* if the packet at tx_tail is not owned by hardware it is for us */
163076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( tx_status & DescOwn )
163176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
163276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
163376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Transmitted packet.\n" );
163476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "tp->tx_fill_ctr     = %d\n", tp->tx_fill_ctr );
163576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "tp->tx_tail         = %d\n", tp->tx_tail );
163676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "tp->tx_curr         = %d\n", tp->tx_curr );
163776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "tx_status           = %d\n", tx_status );
163876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "tx_curr_desc        = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
163976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
164076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Pass packet to core for processing */
164176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		netdev_tx_complete ( netdev, tp->tx_iobuf[tp->tx_tail] );
164276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
164376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
164476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
164576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Decrement count of used descriptors */
164676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->tx_fill_ctr--;
164776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
164876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Increment sent packets index */
164976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->tx_tail = ( tp->tx_tail + 1 ) % NUM_TX_DESC;
165076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
165176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
165276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
165376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
165476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_free_tx_resources ( struct rtl8169_private *tp )
165576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
165676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_free_tx_resources\n" );
165776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
165876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	free_dma ( tp->tx_base, R8169_TX_RING_BYTES );
165976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
166076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
166176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
166276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_populate_rx_descriptor ( struct rtl8169_private *tp, struct RxDesc *rx_desc, uint32_t index )
166376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
166476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_populate_rx_descriptor\n" );
166576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
166676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "Populating rx descriptor %d\n", index );
166776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
166876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset ( rx_desc, 0, sizeof ( *rx_desc ) );
166976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
167076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rx_desc->addr_hi = 0;
167176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rx_desc->addr_lo = virt_to_bus ( tp->rx_iobuf[index]->data );
167276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rx_desc->opts2 = 0;
167376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rx_desc->opts1 = ( index == ( NUM_RX_DESC - 1 ) ? RingEnd : 0 ) |
167476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		RX_BUF_SIZE;
167576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rx_desc->opts1 |= DescOwn;
167676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
167776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
167876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
167976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Refill descriptor ring
168076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
168176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev		Net device
168276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
168376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_refill_rx_ring ( struct rtl8169_private *tp )
168476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
168576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct RxDesc *rx_curr_desc;
168676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
168776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
168876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_refill_rx_ring\n" );
168976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
169076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for ( i = 0; i < NUM_RX_DESC; i++ ) {
169176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
169276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rx_curr_desc = ( tp->rx_base ) + i;
169376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
169476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Don't touch descriptors owned by the NIC */
169576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( rx_curr_desc->opts1 & DescOwn )
169676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			continue;
169776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
169876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Don't touch descriptors with iobufs, they still need to be
169976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   processed by the poll routine */
170076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( tp->rx_iobuf[tp->rx_curr] != NULL )
170176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			continue;
170276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
170376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/** If we can't get an iobuf for this descriptor
170476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    try again later (next poll).
170576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 */
170676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( ! ( tp->rx_iobuf[i] = alloc_iob ( RX_BUF_SIZE ) ) ) {
170776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			DBG ( "Refill rx ring failed!!\n" );
170876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
170976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
171076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
171176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8169_populate_rx_descriptor ( tp, rx_curr_desc, i );
171276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
171376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
171476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
171576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
171676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * setup_rx_resources - allocate Rx resources (Descriptors)
171776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
171876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v tp:	 Driver private structure
171976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
172076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc       Returns 0 on success, negative on failure
172176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
172276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman **/
172376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int
172476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_setup_rx_resources ( struct rtl8169_private *tp )
172576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
172676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_setup_rx_resources\n" );
172776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
172876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->rx_base = malloc_dma ( R8169_RX_RING_BYTES, RX_RING_ALIGN );
172976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
173076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "tp->rx_base      = %#08lx\n", virt_to_bus ( tp->rx_base ) );
173176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
173276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! tp->rx_base ) {
173376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENOMEM;
173476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
173576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset ( tp->rx_base, 0, R8169_RX_RING_BYTES );
173676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
173776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_refill_rx_ring ( tp );
173876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
173976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->rx_curr = 0;
174076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
174176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
174276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
174376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
174476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
174576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_process_rx_packets ( struct net_device *netdev )
174676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
174776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv ( netdev );
174876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint32_t rx_status;
174976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t rx_len;
175076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct RxDesc *rx_curr_desc;
175176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
175276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
175376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_process_rx_packets\n" );
175476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
175576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for ( i = 0; i < NUM_RX_DESC; i++ ) {
175676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
175776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rx_curr_desc = tp->rx_base  + tp->rx_curr;
175876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
175976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rx_status = rx_curr_desc->opts1;
176076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
176176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG2 ( "Before DescOwn check rx_status: %#08x\n", rx_status );
176276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
176376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Hardware still owns the descriptor */
176476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( rx_status & DescOwn )
176576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
176676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
176776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* We own the descriptor, but it has not been refilled yet */
176876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( tp->rx_iobuf[tp->rx_curr] == NULL )
176976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
177076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
177176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rx_len = rx_status & 0x3fff;
177276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
177376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Received packet.\n" );
177476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "tp->rx_curr         = %d\n", tp->rx_curr );
177576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "rx_len              = %d\n", rx_len );
177676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "rx_status           = %#08x\n", rx_status );
177776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "rx_curr_desc        = %#08lx\n", virt_to_bus ( rx_curr_desc ) );
177876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
177976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( rx_status & RxRES ) {
178076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
178176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			netdev_rx_err ( netdev, tp->rx_iobuf[tp->rx_curr], -EINVAL );
178276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
178376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			DBG ( "rtl8169_poll: Corrupted packet received!\n"
178476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			       " rx_status: %#08x\n", rx_status );
178576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
178676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		} else 	{
178776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
178876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			/* Adjust size of the iobuf to reflect received data */
178976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			iob_put ( tp->rx_iobuf[tp->rx_curr], rx_len );
179076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
179176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			/* Add this packet to the receive queue.  */
179276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			netdev_rx ( netdev, tp->rx_iobuf[tp->rx_curr] );
179376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
179476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
179576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Invalidate this iobuf and descriptor */
179676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->rx_iobuf[tp->rx_curr] = NULL;
179776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
179876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
179976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Update pointer to next available rx descriptor */
180076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->rx_curr = ( tp->rx_curr + 1 ) % NUM_RX_DESC;
180176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
180276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_refill_rx_ring ( tp );
180376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
180476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
180576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
180676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_free_rx_resources ( struct rtl8169_private *tp )
180776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
180876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
180976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
181076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_free_rx_resources\n" );
181176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
181276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	free_dma ( tp->rx_base, R8169_RX_RING_BYTES );
181376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
181476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for ( i = 0; i < NUM_RX_DESC; i++ ) {
181576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		free_iob ( tp->rx_iobuf[i] );
181676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->rx_iobuf[i] = NULL;
181776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
181876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
181976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
182076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
182176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    FIXME: Because gPXE's pci_device_id structure does not contain a
182276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    field to contain arbitrary data, we need the following table to
182376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    associate PCI IDs with nic variants, because a lot of driver
182476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    routines depend on knowing which kind of variant they are dealing
182576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    with. --mdc
182676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman **/
182776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
182876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define _R(VENDOR,DEVICE,INDEX) \
182976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	{ .vendor = VENDOR, .device = DEVICE, .index = INDEX }
183076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
183176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const struct {
183276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t vendor;
183376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t device;
183476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int index;
183576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} nic_variant_table[] = {
183676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	_R(0x10ec, 0x8129, RTL_CFG_0),
183776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	_R(0x10ec, 0x8136, RTL_CFG_2),
183876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	_R(0x10ec, 0x8167, RTL_CFG_0),
183976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	_R(0x10ec, 0x8168, RTL_CFG_1),
184076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	_R(0x10ec, 0x8169, RTL_CFG_0),
184176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	_R(0x1186, 0x4300, RTL_CFG_0),
184276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	_R(0x1259, 0xc107, RTL_CFG_0),
184376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	_R(0x16ec, 0x0116, RTL_CFG_0),
184476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	_R(0x1737, 0x1032, RTL_CFG_0),
184576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	_R(0x0001, 0x8168, RTL_CFG_2),
184676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
184776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#undef _R
184876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
184976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int
185076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_get_nic_variant ( uint16_t vendor, uint16_t device )
185176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
185276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 i;
185376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
185476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_get_nic_variant\n" );
185576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
185676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < ARRAY_SIZE(nic_variant_table); i++) {
185776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( ( nic_variant_table[i].vendor == vendor ) &&
185876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		     ( nic_variant_table[i].device == device ) ) {
185976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			return ( nic_variant_table[i].index );
186076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
186176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
186276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "No matching NIC variant found!\n" );
186376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return ( RTL_CFG_0 );
186476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
186576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
186676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_irq_enable ( struct rtl8169_private *tp )
186776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
186876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
186976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
187076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_irq_enable\n" );
187176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
187276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16 ( IntrMask, tp->intr_event );
187376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
187476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
187576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8169_irq_disable ( struct rtl8169_private *tp )
187676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
187776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
187876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
187976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_irq_disable\n" );
188076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
188176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_irq_mask_and_ack ( ioaddr );
188276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
188376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
188476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*** gPXE Core API Routines ***/
188576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
188676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
188776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * open - Called when a network interface is made active
188876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
188976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev	network interface device structure
189076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc	Return status code, 0 on success, negative value on failure
189176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
189276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman **/
189376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int
189476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_open ( struct net_device *netdev )
189576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
189676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv ( netdev );
189776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
189876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int rc;
189976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
190076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_open\n" );
190176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
190276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* allocate transmit descriptors */
190376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rc = rtl8169_setup_tx_resources ( tp );
190476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( rc ) {
190576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Error setting up TX resources!\n" );
190676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_setup_tx;
190776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
190876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
190976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* allocate receive descriptors */
191076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rc = rtl8169_setup_rx_resources ( tp );
191176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( rc ) {
191276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Error setting up RX resources!\n" );
191376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_setup_rx;
191476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
191576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
191676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_hw_start ( netdev );
191776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
191876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "TxDescStartAddrHigh   = %#08lx\n", RTL_R32 ( TxDescStartAddrHigh ) );
191976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "TxDescStartAddrLow    = %#08lx\n", RTL_R32 ( TxDescStartAddrLow  ) );
192076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "RxDescAddrHigh        = %#08lx\n", RTL_R32 ( RxDescAddrHigh ) );
192176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "RxDescAddrLow         = %#08lx\n", RTL_R32 ( RxDescAddrLow  ) );
192276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
192376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
192476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
192576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_setup_rx:
192676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_free_tx_resources ( tp );
192776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_setup_tx:
192876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_hw_reset ( ioaddr );
192976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
193076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return rc;
193176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
193276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
193376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
193476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * transmit - Transmit a packet
193576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
193676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev	Network device
193776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v iobuf	I/O buffer
193876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
193976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc       Returns 0 on success, negative on failure
194076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
194176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int
194276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
194376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
194476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv ( netdev );
194576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
194676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint32_t tx_len = iob_len ( iobuf );
194776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
194876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct TxDesc *tx_curr_desc;
194976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
195076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ("rtl8169_transmit\n");
195176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
195276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( tp->tx_fill_ctr == NUM_TX_DESC ) {
195376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ("TX overflow\n");
195476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENOBUFS;
195576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
195676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
195776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/**
195876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 *  The rtl8169 family automatically pads short packets to a
195976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 *  minimum size, but if it did not, like some older cards,
196076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 *  we could do:
196176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 *  iob_pad ( iobuf, ETH_ZLEN );
196276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
196376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
196476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Save pointer to this iobuf we have been given to transmit so
196576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   we can pass it to netdev_tx_complete() later */
196676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->tx_iobuf[tp->tx_curr] = iobuf;
196776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
196876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tx_curr_desc = tp->tx_base + tp->tx_curr;
196976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
197076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "tp->tx_fill_ctr = %d\n", tp->tx_fill_ctr );
197176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "tp->tx_curr     = %d\n", tp->tx_curr );
197276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "tx_curr_desc    = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
197376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "iobuf->data     = %#08lx\n", virt_to_bus ( iobuf->data ) );
197476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "tx_len          = %d\n", tx_len );
197576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
197676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Configure current descriptor to transmit supplied packet */
197776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tx_curr_desc->addr_hi = 0;
197876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tx_curr_desc->addr_lo = virt_to_bus ( iobuf->data );
197976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tx_curr_desc->opts2 = 0;
198076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tx_curr_desc->opts1 = FirstFrag | LastFrag |
198176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		( tp->tx_curr == ( NUM_TX_DESC - 1 ) ? RingEnd : 0 ) |
198276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tx_len;
198376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
198476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Mark descriptor as owned by NIC */
198576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tx_curr_desc->opts1 |= DescOwn;
198676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
198776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "tx_curr_desc->opts1   = %#08x\n", tx_curr_desc->opts1 );
198876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "tx_curr_desc->opts2   = %#08x\n", tx_curr_desc->opts2 );
198976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "tx_curr_desc->addr_hi = %#08x\n", tx_curr_desc->addr_hi );
199076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "tx_curr_desc->addr_lo = %#08x\n", tx_curr_desc->addr_lo );
199176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
199276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W8 ( TxPoll, NPQ );	/* set polling bit */
199376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
199476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Point to next free descriptor */
199576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->tx_curr = ( tp->tx_curr + 1 ) % NUM_TX_DESC;
199676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
199776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Increment number of tx descriptors in use */
199876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->tx_fill_ctr++;
199976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
200076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
200176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
200276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
200376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
200476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * poll - Poll for received packets
200576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
200676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev	Network device
200776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
200876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
200976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_poll ( struct net_device *netdev )
201076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
201176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv ( netdev );
201276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
201376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
201476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t intr_status;
201576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uint16_t intr_mask;
201676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
201776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_poll\n" );
201876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
201976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	intr_status = RTL_R16 ( IntrStatus );
202076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	intr_mask   = RTL_R16 ( IntrMask );
202176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
202276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG2 ( "rtl8169_poll (before): intr_mask = %#04x  intr_status = %#04x\n",
202376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	      intr_mask, intr_status );
202476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
202576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_W16 ( IntrStatus, 0xffff );
202676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
202776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* hotplug / major error / no more work / shared irq */
202876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( intr_status == 0xffff )
202976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return;
203076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
203176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Process transmitted packets */
203276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_process_tx_packets ( netdev );
203376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
203476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Process received packets  */
203576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_process_rx_packets ( netdev );
203676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
203776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
203876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
203976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * close - Disable network interface
204076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
204176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev	network interface device structure
204276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
204376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman **/
204476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
204576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_close ( struct net_device *netdev )
204676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
204776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv ( netdev );
204876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
204976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
205076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "r8169_close\n" );
205176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
205276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_hw_reset ( ioaddr );
205376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
205476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_free_tx_resources ( tp );
205576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_free_rx_resources ( tp );
205676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
205776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
205876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
205976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * irq - enable or Disable interrupts
206076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
206176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev    network adapter
206276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v action    requested interrupt action
206376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
206476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman **/
206576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
206676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_irq ( struct net_device *netdev, int action )
206776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
206876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv ( netdev );
206976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
207076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_irq\n" );
207176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
207276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch ( action ) {
207376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case 0 :
207476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8169_irq_disable ( tp );
207576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
207676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	default :
207776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl8169_irq_enable ( tp );
207876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
207976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
208076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
208176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
208276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct net_device_operations rtl8169_operations = {
208376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.open           = rtl8169_open,
208476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.transmit       = rtl8169_transmit,
208576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.poll           = rtl8169_poll,
208676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.close          = rtl8169_close,
208776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.irq            = rtl8169_irq,
208876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
208976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
209076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
209176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * probe - Initial configuration of NIC
209276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
209376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v pci	PCI device
209476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v id	PCI IDs
209576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
209676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @ret rc	Return status code
209776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman **/
209876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int
209976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_probe ( struct pci_device *pdev, const struct pci_device_id *ent )
210076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
210176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i, rc;
210276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct net_device *netdev;
210376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp;
210476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr;
210576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
210676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/** FIXME: This lookup is necessary because gPXE does not have a "data"
210776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    element in the structure pci_device_id which can pass an arbitrary
210876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    piece of data to the driver.  It might be useful to add it. Then we
210976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    could just use ent->data instead of having to look up cfg_index.
211076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	**/
211176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int cfg_index = rtl8169_get_nic_variant ( ent->vendor, ent->device );
211276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	const struct rtl_cfg_info *cfg = rtl_cfg_infos + cfg_index;
211376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
211476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_probe\n" );
211576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
211676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "ent->vendor = %#04x, ent->device = %#04x\n", ent->vendor, ent->device );
211776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
211876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "cfg_index = %d\n", cfg_index );
211976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "cfg->intr_event = %#04x\n", cfg->intr_event );
212076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
212176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rc = -ENOMEM;
212276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
212376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Allocate net device ( also allocates memory for netdev->priv
212476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   and makes netdev-priv point to it )
212576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
212676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev = alloc_etherdev ( sizeof ( *tp ) );
212776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
212876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! netdev )
212976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_alloc_etherdev;
213076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
213176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Associate driver-specific network operations with
213276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   generic network device layer
213376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 */
213476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_init ( netdev, &rtl8169_operations );
213576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
213676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Associate this network device with the given PCI device */
213776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	pci_set_drvdata ( pdev, netdev );
213876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev->dev = &pdev->dev;
213976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
214076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Initialize driver private storage */
214176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp = netdev_priv ( netdev );
214276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset ( tp, 0, ( sizeof ( *tp ) ) );
214376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
214476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->pci_dev    = pdev;
214576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->irqno      = pdev->irq;
214676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->netdev     = netdev;
214776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->cfg_index  = cfg_index;
214876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->intr_event = cfg->intr_event;
214976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->cp_cmd     = PCIMulRW;
215076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
215176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->hw_start = cfg->hw_start;
215276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
215376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rc = -EIO;
215476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
215576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	adjust_pci_device ( pdev );
215676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
215776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* ioremap MMIO region */
215876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ioaddr = ioremap ( pdev->membase, R8169_REGS_SIZE );
215976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
216076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! ioaddr ) {
216176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "cannot remap MMIO\n" );
216276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rc = -EIO;
216376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_ioremap;
216476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
216576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
216676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->mmio_addr = ioaddr;
216776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
216876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->pcie_cap = pci_find_capability ( pdev, PCI_CAP_ID_EXP );
216976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( tp->pcie_cap ) {
217076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG (  "PCI Express capability\n" );
217176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
217276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG (  "No PCI Express capability\n" );
217376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
217476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
217576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Mask interrupts just in case */
217676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_irq_mask_and_ack ( ioaddr );
217776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
217876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Soft reset NIC */
217976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl_soft_reset ( netdev );
218076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
218176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Identify chip attached to board */
218276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_get_mac_version ( tp, ioaddr );
218376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
218476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for ( i = 0; (u32) i < ARRAY_SIZE ( rtl_chip_info ); i++ ) {
218576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ( tp->mac_version == rtl_chip_info[i].mac_version )
218676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
218776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
218876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( i == ARRAY_SIZE(rtl_chip_info ) ) {
218976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Unknown chip: assume array element #0, original RTL-8169 */
219076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG ( "Unknown chip version, assuming %s\n", rtl_chip_info[0].name );
219176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		i = 0;
219276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
219376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp->chipset = i;
219476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
219576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) &&
219676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (RTL_R8(PHYstatus) & TBI_Enable)) {
219776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->set_speed = rtl8169_set_speed_tbi;
219876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->phy_reset_enable = rtl8169_tbi_reset_enable;
219976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->phy_reset_pending = rtl8169_tbi_reset_pending;
220076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->link_ok = rtl8169_tbi_link_ok;
220176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
220276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
220376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
220476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->set_speed = rtl8169_set_speed_xmii;
220576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->phy_reset_enable = rtl8169_xmii_reset_enable;
220676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->phy_reset_pending = rtl8169_xmii_reset_pending;
220776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp->link_ok = rtl8169_xmii_link_ok;
220876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
220976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
221076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Get MAC address */
221176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for ( i = 0; i < MAC_ADDR_LEN; i++ )
221276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		netdev->hw_addr[i] = RTL_R8 ( MAC0 + i );
221376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
221476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "%s\n", eth_ntoa ( netdev->hw_addr ) );
221576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
221676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_init_phy ( netdev, tp );
221776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
221876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ( rc = register_netdev ( netdev ) ) != 0 )
221976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_register;
222076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
222176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Mark as link up; we don't yet handle link state */
222276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_link_up ( netdev );
222376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
222476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG ( "rtl8169_probe succeeded!\n" );
222576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
222676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* No errors, return success */
222776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
222876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
222976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Error return paths */
223076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_register:
223176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_ioremap:
223276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_put ( netdev );
223376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_alloc_etherdev:
223476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return rc;
223576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
223676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
223776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
223876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * remove - Device Removal Routine
223976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
224076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v pdev PCI device information struct
224176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
224276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman **/
224376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
224476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanrtl8169_remove ( struct pci_device *pdev )
224576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
224676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct net_device *netdev = pci_get_drvdata ( pdev );
224776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl8169_private *tp = netdev_priv ( netdev );
224876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	void *ioaddr = tp->mmio_addr;
224976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
225076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBGP ( "rtl8169_remove\n" );
225176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
225276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl8169_hw_reset ( ioaddr );
225376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
225476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unregister_netdev ( netdev );
225576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_nullify ( netdev );
225676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	netdev_put ( netdev );
225776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
225876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
225976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct pci_device_id rtl8169_nics[] = {
226076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCI_ROM(0x10ec, 0x8129, "rtl8169-0x8129", "rtl8169-0x8129", 0),
226176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCI_ROM(0x10ec, 0x8136, "rtl8169-0x8136", "rtl8169-0x8136", 0),
226276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCI_ROM(0x10ec, 0x8167, "rtl8169-0x8167", "rtl8169-0x8167", 0),
226376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCI_ROM(0x10ec, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168", 0),
226476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCI_ROM(0x10ec, 0x8169, "rtl8169-0x8169", "rtl8169-0x8169", 0),
226576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCI_ROM(0x1186, 0x4300, "rtl8169-0x4300", "rtl8169-0x4300", 0),
226676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCI_ROM(0x1259, 0xc107, "rtl8169-0xc107", "rtl8169-0xc107", 0),
226776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCI_ROM(0x16ec, 0x0116, "rtl8169-0x0116", "rtl8169-0x0116", 0),
226876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCI_ROM(0x1737, 0x1032, "rtl8169-0x1032", "rtl8169-0x1032", 0),
226976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	PCI_ROM(0x0001, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168", 0),
227076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
227176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
227276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct pci_driver rtl8169_driver __pci_driver = {
227376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  .ids = rtl8169_nics,
227476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  .id_count = ( sizeof ( rtl8169_nics ) / sizeof ( rtl8169_nics[0] ) ),
227576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  .probe = rtl8169_probe,
227676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  .remove = rtl8169_remove,
227776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
227876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
227976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
228076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Local variables:
228176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  c-basic-offset: 8
228276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  c-indent-level: 8
228376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  tab-width: 8
228476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * End:
228576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
2286