#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if defined(CONFIG_SH_DREAMCAST)
#define RX_BUF_IDX 1 #else
#define RX_BUF_IDX 2 #endif
#define RX_BUF_LEN (8192
<< RX_BUF_IDX)
#define RX_BUF_PAD 16
#define RX_BUF_WRAP_PAD 2048
#if RX_BUF_LEN == 65536
#define RX_BUF_TOT_LEN RX_BUF_LEN
#else
#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD +
RX_BUF_WRAP_PAD)
#endif
typedef enum
{
RTL8139 =
0,
RTL8129,
} board_t;
static struct pci_device_id xc_id[] =
{
{0x10ec,
0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x10ec,
0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x1113,
0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x1500,
0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x4033,
0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x1186,
0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x1186,
0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x13d1,
0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x1259,
0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x1259,
0xa11e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x14ea,
0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x14ea,
0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x11db,
0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x1432,
0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x02ac,
0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x018a,
0x0106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x126c,
0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x1743,
0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x021b,
0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
#ifdef
CONFIG_SH_SECUREEDGE5410 {0x10ec,
0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
#endif
#ifdef CONFIG_8139TOO_8129
{0x10ec,
0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
#endif
{PCI_ANY_ID,
0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 },
{PCI_ANY_ID,
0x8139, 0x1186, 0x1300, 0, 0, RTL8139 },
{PCI_ANY_ID,
0x8139, 0x13d1, 0xab06, 0, 0, RTL8139 },
{0,}
};
MODULE_DEVICE_TABLE (pci,xc_id);
enum RTL8139_registers
{
MAC0 =
0, MAR0 =
8, TxStatus0 =
0x10, TxAddr0 =
0x20, RxBuf =
0x30, ChipCmd =
0x37,
RxBufPtr =
0x38,
IntrMask =
0x3C,
IntrStatus =
0x3E,
TxConfig =
0x40,
RxConfig =
0x44,
RxMissed =
0x4C,
Cfg9346 =
0x50,
Config1 =
0x52,
Config3 =
0x59,
Config4 =
0x5A,
HltClk =
0x5B,
MultiIntr =
0x5C, BasicModeCtrl = 0x62,
BasicModeStatus = 0x64,
NWayAdvert =
0x66,
NWayLPAR =
0x68,
NWayExpansion = 0x6A, CSCR =
0x74,
};
enum ChipCmdBits {
CmdReset =
0x10,
CmdRxEnb =
0x08,
CmdTxEnb =
0x04,
RxBufEmpty =
0x01,
};
enum IntrStatusBits
{
PCIErr =
0x8000,
PCSTimeout =
0x4000,
RxFIFOOver =
0x40,
RxUnderrun =
0x20,
RxOverflow =
0x10,
TxErr =
0x08,
TxOK =
0x04,
RxErr =
0x02,
RxOK =
0x01,
RxAckBits =
RxFIFOOver | RxOverflow | RxOK,
};
static const u16 xc_intr_mask =
PCIErr |
PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
TxErr | TxOK
| RxErr | RxOK;
static const u16 xc_norx_intr_mask =
PCIErr |
PCSTimeout | RxUnderrun | TxErr | TxOK | RxErr ;
enum Config1Bits {
Cfg1_PM_Enable = 0x01,
LWAKE =
0x10,
};
enum Config3Bits {
Cfg3_Magic = (1 << 5),
};
enum Config4Bits {
LWPTN = (1
<< 2),
};
enum Cfg9346Bits
{
Cfg9346_lock
= 0x00,
Cfg9346_Unlock = 0xC0,
};
enum TxStatusBits {
TxHostOwns =
0x2000,
TxUnderrun =
0x4000,
TxStatOK =
0x8000,
TxOutOfWindow = 0x20000000,
TxAborted =
0x40000000,
TxCarrierLost = 0x80000000,
};
enum rx_mode_bits
{
AcceptErr =
0x20,
AcceptRunt =
0x10,
AcceptBroadcast = 0x08,
AcceptMulticast = 0x04,
AcceptMyPhys
= 0x02,
AcceptAllPhys = 0x01,
};
typedef enum
{
CH_8139 =
0,
CH_8139_K,
CH_8139A,
CH_8139A_G,
CH_8139B,
CH_8130,
CH_8139C,
CH_8100,
CH_8100B_8139D,
CH_8101,
} chip_t;
enum chip_flags
{
HasHltClk =
(1 << 0),
HasLWake =
(1 << 1),
};
#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) /
(b30<<30 |
b29<<29 |
b28<<28 |
b27<<27 |
b26<<26 |
b23<<23 |
b22<<22)
#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1)
static const struct
{
const char
*name;
u32
version;
u32
flags;
} rtl_chip_info[] =
{
{
"RTL-8139",HW_REVID(1, 0, 0, 0, 0, 0, 0),HasHltClk,},
{ "RTL-8139
rev K",HW_REVID(1, 1, 0, 0, 0, 0, 0),HasHltClk,},
{
"RTL-8139A",HW_REVID(1, 1, 1, 0, 0, 0, 0),HasHltClk,},
{ "RTL-8139A
rev G",HW_REVID(1, 1, 1, 0, 0, 1, 0),HasHltClk,},
{
"RTL-8139B",HW_REVID(1, 1, 1, 1, 0, 0, 0),HasLWake,},
{
"RTL-8130",HW_REVID(1, 1, 1, 1, 1, 0, 0),HasLWake,},
{
"RTL-8139C",HW_REVID(1, 1, 1, 0, 1, 0, 0),HasLWake,},
{
"RTL-8100",HW_REVID(1, 1, 1, 1, 0, 1, 0),HasLWake,},
{
"RTL-8100B/8139D",HW_REVID(1, 1, 1, 0, 1, 0, 1),HasHltClk |
HasLWake,},
{
"RTL-8101", HW_REVID(1, 1, 1, 0, 1, 1, 1),HasLWake,},
};
struct xc_priv
{
void __iomem
*ioaddr;
spinlock_t
lock;
spinlock_t
rx_lock;
chip_t
chipset;
struct
napi_struct napi;
struct
pci_dev *pdev;
struct
net_device *dev;
struct
net_device_stats stats;
u32
rx_config;
unsigned
char *rx_bufs;
unsigned int
cur_rx;
dma_addr_t
rx_bufs_dma;
unsigned int
tx_flag;
unsigned
long cur_tx;
unsigned
long dirty_tx;
unsigned
char *tx_bufs;
unsigned
char *tx_buf[4];
dma_addr_t
tx_bufs_dma; u32
msg_enable;
unsigned int
default_port : 4; signed char
phys[4]; struct
mii_if_info mii; };
#if RX_BUF_IDX == 1
static const unsigned int xc_rx_config =
(1
<< 11) | (1
<< 7) | (7
<< 13) | (7
<< 8);
#elif RX_BUF_IDX == 2
static const unsigned int xc_rx_config =
(1
<< 12) | (1
<< 7) | (7
<< 13) | (7
<< 8);
#else
#error "Invalid configuration for 8139_RXBUF_IDX"
#endif
static char mii_2_8139_map[8] =
{
BasicModeCtrl,BasicModeStatus,0,0,
NWayAdvert,NWayLPAR,NWayExpansion,0
};
static void xc_check_media(struct net_device *dev, unsigned int
init_media)
{
struct
xc_priv *tp = netdev_priv(dev);
if
(tp->phys[0] >= 0)
mii_check_media(&tp->mii,
netif_msg_link(tp), init_media);
}
static int mdio_read (struct net_device *dev, int phy_id, int
location)
{
struct
xc_priv *tp = netdev_priv(dev);
void __iomem
*ioaddr = tp->ioaddr;
return
location < 8 &&
mii_2_8139_map[location] ?
ioread16(ioaddr+mii_2_8139_map[location]) : 0;
}
static void mdio_write(struct net_device *dev, int phy_id, int
location,int value)
{
struct
xc_priv *tp = netdev_priv(dev);
void __iomem
*ioaddr = tp->ioaddr;
if (location
< 8 &&
mii_2_8139_map[location])
{
if (location == 0)
{
iowrite8(Cfg9346_Unlock,ioaddr+Cfg9346);
iowrite16(value,ioaddr+BasicModeCtrl);
iowrite8(Cfg9346_lock,ioaddr+Cfg9346);
}
else
iowrite32(value,ioaddr+mii_2_8139_map[location]);
}
}
static u32 xc_get_link(struct net_device *dev)
{
struct
xc_priv *tp = netdev_priv(dev);
return
mii_link_ok(&tp->mii);
}
static int xc_get_settings(struct net_device *dev, struct
ethtool_cmd *cmd)
{
struct
xc_priv *tp = netdev_priv(dev);
spin_lock_irq(&tp->lock);
mii_ethtool_gset(&tp->mii,
cmd);
spin_unlock_irq(&tp->lock);
return
0;
}
static struct ethtool_ops xc_ethtool_ops =
{
.get_settings = xc_get_settings,
.get_link = xc_get_link,
};
static void __set_rx_mode (struct net_device *dev)
{(leave)
struct
xc_priv *tp = netdev_priv(dev);
void __iomem
*ioaddr = tp->ioaddr;
u32
mc_filter[2]; int i,
rx_mode;
u32
tmp;
struct
dev_mc_list *mclist;
rx_mode =
AcceptBroadcast | AcceptMyPhys;
mc_filter[1]
= mc_filter[0] = 0;
for (i = 0,
mclist = dev->mc_list; mclist
&& i <
dev->mc_count;
i++, mclist = mclist->next)
{
int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr)
>> 26;
mc_filter[bit_nr >> 5] |= 1
<< (bit_nr &
31);
rx_mode |= AcceptMulticast;
} tmp =
xc_rx_config | rx_mode;
if
(tp->rx_config != tmp)
{
iowrite32(tmp,ioaddr+RxConfig);
ioread32(ioaddr+RxConfig);
tp->rx_config = tmp;
}
iowrite32(mc_filter[0],ioaddr+MAR0 + 0);
iowrite32(mc_filter[1],ioaddr+MAR0 + 4);
}
static void xc_set_multicast_list(struct net_device *dev)
{
unsigned
long flags;
struct
xc_priv *tp = netdev_priv(dev);
spin_lock_irqsave (&tp->lock,
flags);
__set_rx_mode(dev);
spin_unlock_irqrestore (&tp->lock,
flags);
}
static void xc_reset(void __iomem *ioaddr)
{
int
i; iowrite8(CmdReset,ioaddr+ChipCmd); for (i =
1000; i > 0; i--)
{
barrier();
if ((ioread8(ioaddr+ChipCmd) & CmdReset) ==
0)
break;
udelay (10);
}
}
static void xc_cleanup_dev(struct net_device *dev)
{
struct
xc_priv *tp = netdev_priv(dev);
if
(tp->pdev == NULL || dev == NULL)
return;
if
(tp->ioaddr)
pci_iounmap(tp->pdev,tp->ioaddr);
pci_release_regions(tp->pdev);
free_netdev(dev);
pci_set_drvdata(tp->pdev,NULL);
}
static int xc_rx(struct net_device *dev, struct xc_priv *tp, int
budget)
{
u16
status;
struct
sk_buff *skb;
int
packet_size,data_size;
int
work_done = 0;
void __iomem
*ioaddr = tp->ioaddr;
unsigned
long cur_rx = tp->cur_rx;
while
(netif_running(dev) && work_done
< budget &&
((ioread8(ioaddr+ChipCmd) & RxBufEmpty) ==
0))
{
u32 tmp_size;
u32 offset = cur_rx % RX_BUF_LEN;
rmb();
tmp_size = le32_to_cpu(*(u32
*)(tp->rx_bufs+offset));
packet_size = tmp_size >> 16;
data_size = packet_size - 4;
skb = dev_alloc_skb(data_size + 2);
if (likely(skb))
{
skb->dev = dev;
skb_reserve(skb,2);
skb_copy_to_linear_data (skb,
&tp->rx_bufs[offset + 4],
data_size);
skb_put(skb,data_size);
skb->protocol = eth_type_trans (skb, dev);
dev->last_rx = jiffies;
tp->stats.rx_bytes += data_size;
tp->stats.rx_packets++;
netif_receive_skb (skb);
}
else
tp->stats.rx_dropped++;