/*
* 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
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/crc32.h>
#include <linux/ethtool.h>
#include <linux/interrupt.h>
#include <linux/gfp.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 const 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 * const ipg_brand_name[] = {
"IC PLUS IP1000 1000/100/10 based NIC",
"Sundance Technology ST2021 based NIC",
"Tamarack Microelectronics TC9020/9021 based NIC",
"D-Link NIC IP1000A"
};
static const struct pci_device_id ipg_pci_tbl[] = {
{ PCI_VDEVICE(SUNDANCE, 0x1023), 0 },
{ PCI_VDEVICE(SUNDANCE, 0x2021), 1 },
{ PCI_VDEVICE(DLINK, 0x9021), 2 },
{ PCI_VDEVICE(DLINK, 0x4020), 3 },
{ 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");
netdev_info(dev, "rx_current = %02x\n", sp->rx_current);
netdev_info(dev, "rx_dirty = %02x\n", sp->rx_dirty);
netdev_info(dev, "RFDList start address = %016lx\n",
(unsigned long)sp->rxd_map);
netdev_info(dev, "RFDListPtr register = %08x%08x\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;
netdev_info(dev, "%02x %04x RFDNextPtr = %016lx\n",
i, offset, (unsigned long)sp->rxd[i].next_desc);
offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd;
netdev_info(dev, "%02x %04x RFS = %016lx\n",
i, offset, (unsigned long)sp->rxd[i].rfs);
offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd;
netdev_info(dev, "%02x %04x frag_info = %016lx\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");
netdev_info(dev, "tx_current = %02x\n", sp->tx_current);
netdev_info(dev, "tx_dirty = %02x\n", sp->tx_dirty);
netdev_info(dev, "TFDList start address = %016lx\n",
(unsigned long) sp->txd_map);
netdev_info(dev, "TFDListPtr register = %08x%08x\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;
netdev_info(dev, "%02x %04x TFDNextPtr = %016lx\n",
i, offset, (unsigned long)sp->txd[i].next_desc);
offset = (u32) &sp->txd[i].tfc - (u32) sp->txd;
netdev_info(dev, "%02x %04x TFC = %016lx\n",
i, offset, (unsigned long) sp->txd[i].tfc);
offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd;
netdev_info(dev, "%02x %04x frag_info = %016lx\n",
i, offset, (unsigned long) sp->txd[i].frag_info);
}
}
#endif
static void ipg_write_phy_ctl(void __iomem *ioaddr, u8 data)
{
ipg_w8(IPG_PC_RSVD_MASK & data, PHY_CTRL);
ndelay(IPG_PC_PHYCTRLWAIT_NS);
}
static void ipg_drive_phy_ctl_low_high(void __iomem *ioaddr, u8 data)
{
ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | data);
ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | data);
}
static void send_three_state(void __iomem *ioaddr, u8 phyctrlpolarity)
{
phyctrlpolarity |= (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR;
ipg_drive_phy_ctl_low_high(ioaddr, phyctrlpolarity);
}
static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity)
{
ipg_w8((IPG_PC_MGMTCLK_LO | (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR |
phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL);
}
static u16 read_phy_bit(void __iomem *ioaddr, u8 phyctrlpolarity)
{
u16 bit_data;
ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | phyctrlpolarity);
bit_data = ((ipg_r8(PHY_CTRL) & IPG_PC_MGMTDATA) >> 1) & 1;
ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | phyctrlpolarity);
return bit_data;
}
/*
* Read a register from the Physical Layer device located
* on the IPG NIC, using the IPG PHYCTRL register.
*/
static int mdio_read(struct net_device *dev, int phy_id, int phy_reg)
{
void __iomem *ioaddr = ipg_ioaddr(dev);
/*
* The GMII mangement frame structure for a read is as follows:
*
* |Preamble|st|op|phyad|regad|ta| data |idle|
* |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z |
*
* <32 1s> = 32 consecutive logic 1 values
* A = bit of Physical Layer device address (MSB first)
* R = bit of register address (MSB first)
* z = High impedance state
* D = bit of read data (MSB first)
*
* Transmission order is 'Preamble' field first, bits transmitted
* left to right (first to last).
*/
struct {
u32 field;
unsigned int len;
} p[] = {
{ GMII_PREAMBLE, 32 }, /* Preamble */
{ GMII_ST, 2 }, /* ST */
{ GMII_READ, 2 }, /* OP */
{ phy_id, 5 }, /* PHYAD */
{ phy_reg, 5 }, /* REGAD */
{ 0x0000, 2 }, /* TA */
{ 0x0000, 16 }, /* DATA */
{ 0x0000, 1 } /* IDLE */
};
unsigned int i, j;
u8 polarity, data;
polarity = ipg_r8(PHY_CTRL);
polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
/* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
for (j = 0; j < 5; j++) {
for (i = 0; i < p[j].len; i++) {
/* For each variable length field, the MSB must be
* transmitted first. Rotate through the field bits,
* starting with the MSB, and move each bit into the
* the 1st (2^1) bit position (this is the bit position
* corresponding to the MgmtData bit of the PhyCtrl
* register for the IPG).
*
* Example: ST = 01;
*
* First write a '0' to bi
评论0