/*
* ipg.c: Device Driver for the IP1000 Gigabit Ethernet Adapter
*
* Copyright (C) 2003, 2007 IC Plus Corp
*
* Original Author:
*
* Craig Rich
* Sundance Technology, Inc.
* www.sundanceti.com
* craig_rich@sundanceti.com
*
* Current Maintainer:
*
* Sorbica Shieh.
* http://www.icplus.com.tw
* sorbica@icplus.com.tw
*
* Jesse Huang
* http://www.icplus.com.tw
* jesse@icplus.com.tw
*/
#include <linux/crc32.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/mutex.h>
#include <asm/div64.h>
#define IPG_RX_RING_BYTES (sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH)
#define IPG_TX_RING_BYTES (sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH)
#define IPG_RESET_MASK \
(IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET | IPG_AC_TX_RESET | \
IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \
IPG_AC_AUTO_INIT)
#define ipg_w32(val32, reg) iowrite32((val32), ioaddr + (reg))
#define ipg_w16(val16, reg) iowrite16((val16), ioaddr + (reg))
#define ipg_w8(val8, reg) iowrite8((val8), ioaddr + (reg))
#define ipg_r32(reg) ioread32(ioaddr + (reg))
#define ipg_r16(reg) ioread16(ioaddr + (reg))
#define ipg_r8(reg) ioread8(ioaddr + (reg))
enum {
netdev_io_size = 128
};
#include "ipg.h"
#define DRV_NAME "ipg"
MODULE_AUTHOR("IC Plus Corp. 2003");
MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver");
MODULE_LICENSE("GPL");
/*
* Defaults
*/
#define IPG_MAX_RXFRAME_SIZE 0x0600
#define IPG_RXFRAG_SIZE 0x0600
#define IPG_RXSUPPORT_SIZE 0x0600
#define IPG_IS_JUMBO false
/*
* Variable record -- index by leading revision/length
* Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN
*/
static unsigned short DefaultPhyParam[] = {
/* 11/12/03 IP1000A v1-3 rev=0x40 */
/*--------------------------------------------------------------------------
(0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2,
27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6,
31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7, 9, 0x0700,
--------------------------------------------------------------------------*/
/* 12/17/03 IP1000A v1-4 rev=0x40 */
(0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
0x0000,
30, 0x005e, 9, 0x0700,
/* 01/09/04 IP1000A v1-5 rev=0x41 */
(0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
0x0000,
30, 0x005e, 9, 0x0700,
0x0000
};
static const char *ipg_brand_name[] = {
"IC PLUS IP1000 1000/100/10 based NIC",
"Sundance Technology ST2021 based NIC",
"Tamarack Microelectronics TC9020/9021 based NIC",
"Tamarack Microelectronics TC9020/9021 based NIC",
"D-Link NIC IP1000A"
};
static DEFINE_PCI_DEVICE_TABLE(ipg_pci_tbl) = {
{ PCI_VDEVICE(SUNDANCE, 0x1023), 0 },
{ PCI_VDEVICE(SUNDANCE, 0x2021), 1 },
{ PCI_VDEVICE(SUNDANCE, 0x1021), 2 },
{ PCI_VDEVICE(DLINK, 0x9021), 3 },
{ PCI_VDEVICE(DLINK, 0x4020), 4 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, ipg_pci_tbl);
static inline void __iomem *ipg_ioaddr(struct net_device *dev)
{
struct ipg_nic_private *sp = netdev_priv(dev);
return sp->ioaddr;
}
#ifdef IPG_DEBUG
static void ipg_dump_rfdlist(struct net_device *dev)
{
struct ipg_nic_private *sp = netdev_priv(dev);
void __iomem *ioaddr = sp->ioaddr;
unsigned int i;
u32 offset;
IPG_DEBUG_MSG("_dump_rfdlist\n");
printk(KERN_INFO "rx_current = %2.2x\n", sp->rx_current);
printk(KERN_INFO "rx_dirty = %2.2x\n", sp->rx_dirty);
printk(KERN_INFO "RFDList start address = %16.16lx\n",
(unsigned long) sp->rxd_map);
printk(KERN_INFO "RFDListPtr register = %8.8x%8.8x\n",
ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0));
for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd;
printk(KERN_INFO "%2.2x %4.4x RFDNextPtr = %16.16lx\n", i,
offset, (unsigned long) sp->rxd[i].next_desc);
offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd;
printk(KERN_INFO "%2.2x %4.4x RFS = %16.16lx\n", i,
offset, (unsigned long) sp->rxd[i].rfs);
offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd;
printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i,
offset, (unsigned long) sp->rxd[i].frag_info);
}
}
static void ipg_dump_tfdlist(struct net_device *dev)
{
struct ipg_nic_private *sp = netdev_priv(dev);
void __iomem *ioaddr = sp->ioaddr;
unsigned int i;
u32 offset;
IPG_DEBUG_MSG("_dump_tfdlist\n");
printk(KERN_INFO "tx_current = %2.2x\n", sp->tx_current);
printk(KERN_INFO "tx_dirty = %2.2x\n", sp->tx_dirty);
printk(KERN_INFO "TFDList start address = %16.16lx\n",
(unsigned long) sp->txd_map);
printk(KERN_INFO "TFDListPtr register = %8.8x%8.8x\n",
ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0));
for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd;
|