Skip to content
Snippets Groups Projects
amd8111e.c 51.6 KiB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed

/* Advanced  Micro Devices Inc. AMD8111E Linux Network Driver
 * Copyright (C) 2004 Advanced Micro Devices
 *
Linus Torvalds's avatar
Linus Torvalds committed
 *
 * Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com> [ 8139cp.c,tg3.c ]
 * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)[ tg3.c]
 * Copyright 1996-1999 Thomas Bogendoerfer [ pcnet32.c ]
 * Derived from the lance driver written 1993,1994,1995 by Donald Becker.
 * Copyright 1993 United States Government as represented by the
 *	Director, National Security Agency.[ pcnet32.c ]
 * Carsten Langgaard, carstenl@mips.com [ pcnet32.c ]
 * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
 *
Linus Torvalds's avatar
Linus Torvalds committed
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
Linus Torvalds's avatar
Linus Torvalds committed
 * USA
Linus Torvalds's avatar
Linus Torvalds committed
Module Name:

	amd8111e.c

Abstract:

 	 AMD8111 based 10/100 Ethernet Controller Driver.
Linus Torvalds's avatar
Linus Torvalds committed

Environment:

	Kernel Mode

Revision History:
 	3.0.0
	   Initial Revision.
	3.0.1
	 1. Dynamic interrupt coalescing.
	 2. Removed prev_stats.
	 3. MII support.
	 4. Dynamic IPG support
	3.0.2  05/29/2003
	 1. Bug fix: Fixed failure to send jumbo packets larger than 4k.
	 2. Bug fix: Fixed VLAN support failure.
	 3. Bug fix: Fixed receive interrupt coalescing bug.
	 4. Dynamic IPG support is disabled by default.
	3.0.3 06/05/2003
	 1. Bug fix: Fixed failure to close the interface if SMP is enabled.
	3.0.4 12/09/2003
	 1. Added set_mac_address routine for bonding driver support.
	 2. Tested the driver for bonding support
	 3. Bug fix: Fixed mismach in actual receive buffer lenth and lenth
Linus Torvalds's avatar
Linus Torvalds committed
	    indicated to the h/w.
	 4. Modified amd8111e_rx() routine to receive all the received packets
Linus Torvalds's avatar
Linus Torvalds committed
	    in the first interrupt.
	 5. Bug fix: Corrected  rx_errors  reported in get_stats() function.
	3.0.5 03/22/2004
	 1. Added NAPI support
Linus Torvalds's avatar
Linus Torvalds committed

*/


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/if_vlan.h>
#include <linux/ctype.h>
Linus Torvalds's avatar
Linus Torvalds committed
#include <linux/crc32.h>
Linus Torvalds's avatar
Linus Torvalds committed

#include <asm/system.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>

#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define AMD8111E_VLAN_TAG_USED 1
#else
#define AMD8111E_VLAN_TAG_USED 0
#endif

#include "amd8111e.h"
#define MODULE_NAME	"amd8111e"
#define MODULE_VERS	"3.0.7"
Linus Torvalds's avatar
Linus Torvalds committed
MODULE_AUTHOR("Advanced Micro Devices, Inc.");
MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version "MODULE_VERS);
Linus Torvalds's avatar
Linus Torvalds committed
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl);
module_param_array(speed_duplex, int, NULL, 0);
MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotiate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex");
Linus Torvalds's avatar
Linus Torvalds committed
module_param_array(coalesce, bool, NULL, 0);
MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0: Disable");
module_param_array(dynamic_ipg, bool, NULL, 0);
MODULE_PARM_DESC(dynamic_ipg, "Enable or Disable dynamic IPG, 1: Enable, 0: Disable");

static DEFINE_PCI_DEVICE_TABLE(amd8111e_pci_tbl) = {
Linus Torvalds's avatar
Linus Torvalds committed
	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD8111E_7462,
	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
	{ 0, }

};
Linus Torvalds's avatar
Linus Torvalds committed
This function will read the PHY registers.
*/
static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val)
{
	void __iomem *mmio = lp->mmio;
	unsigned int reg_val;
	unsigned int repeat= REPEAT_CNT;

	reg_val = readl(mmio + PHY_ACCESS);
	while (reg_val & PHY_CMD_ACTIVE)
		reg_val = readl( mmio + PHY_ACCESS );

	writel( PHY_RD_CMD | ((phy_id & 0x1f) << 21) |
			   ((reg & 0x1f) << 16),  mmio +PHY_ACCESS);
	do{
		reg_val = readl(mmio + PHY_ACCESS);
		udelay(30);  /* It takes 30 us to read/write data */
	} while (--repeat && (reg_val & PHY_CMD_ACTIVE));
	if(reg_val & PHY_RD_ERR)
		goto err_phy_read;
Linus Torvalds's avatar
Linus Torvalds committed
	*val = reg_val & 0xffff;
	return 0;
err_phy_read:
Linus Torvalds's avatar
Linus Torvalds committed
	*val = 0;
	return -EINVAL;
/*
This function will write into PHY registers.
Linus Torvalds's avatar
Linus Torvalds committed
*/
static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val)
{
	unsigned int repeat = REPEAT_CNT;
Linus Torvalds's avatar
Linus Torvalds committed
	void __iomem *mmio = lp->mmio;
	unsigned int reg_val;

	reg_val = readl(mmio + PHY_ACCESS);
	while (reg_val & PHY_CMD_ACTIVE)
		reg_val = readl( mmio + PHY_ACCESS );

	writel( PHY_WR_CMD | ((phy_id & 0x1f) << 21) |
			   ((reg & 0x1f) << 16)|val, mmio + PHY_ACCESS);

	do{
		reg_val = readl(mmio + PHY_ACCESS);
		udelay(30);  /* It takes 30 us to read/write the data */
	} while (--repeat && (reg_val & PHY_CMD_ACTIVE));
Linus Torvalds's avatar
Linus Torvalds committed
	if(reg_val & PHY_RD_ERR)
		goto err_phy_write;
Linus Torvalds's avatar
Linus Torvalds committed
	return 0;

err_phy_write:
Linus Torvalds's avatar
Linus Torvalds committed
	return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
}
Linus Torvalds's avatar
Linus Torvalds committed
This is the mii register read function provided to the mii interface.
Linus Torvalds's avatar
Linus Torvalds committed
static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num)
{
	struct amd8111e_priv* lp = netdev_priv(dev);
	unsigned int reg_val;

	amd8111e_read_phy(lp,phy_id,reg_num,&reg_val);
	return reg_val;
Linus Torvalds's avatar
Linus Torvalds committed
This is the mii register write function provided to the mii interface.
Linus Torvalds's avatar
Linus Torvalds committed
static void amd8111e_mdio_write(struct net_device * dev, int phy_id, int reg_num, int val)
{
Loading
Loading full blame...