patch-2.3.99-pre1 linux/drivers/net/dmfe.c
Next file: linux/drivers/net/eexpress.c
Previous file: linux/drivers/net/dgrs.c
Back to the patch index
Back to the overall index
- Lines: 1224
- Date:
Sun Mar 12 19:27:22 2000
- Orig file:
v2.3.51/linux/drivers/net/dmfe.c
- Orig date:
Sat Feb 12 11:22:10 2000
diff -u --recursive --new-file v2.3.51/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c
@@ -1,15 +1,26 @@
/*
- dmfe.c: Version 1.26
+ dmfe.c: Version 1.28 01/18/2000
- A Davicom DM9102 fast ethernet driver for Linux.
+ A Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux.
+ Copyright (C) 1997 Sten Wang
+
+ 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.
- 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, version 1.
Compiler command:
"gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall
- -Wstrict-prototypes -O6 -c dmfe.c"
+ -Wstrict-prototypes -O6 -c dmfe.c"
+ OR
+ "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net -Wall
+ -Wstrict-prototypes -O6 -c dmfe.c"
The following steps teach you how to active DM9102 board:
1. Used the upper compiler command to compile dmfe.c
@@ -25,7 +36,7 @@
"route add -net 172.22.3.0 eth0"
5. Well done. Your DM9102 adapter actived now.
- Author: Sten Wang, E-mail: sten_wang@davicom.com.tw
+ Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw
Date: 10/28,1998
@@ -44,6 +55,9 @@
Check and fix on 64bit and big endian boxes.
Sort out the PCI latency.
+ (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
+
+ Cleaned up for kernel merge by Alan Cox (alan@redhat.com)
*/
#include <linux/module.h>
@@ -60,38 +74,41 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/version.h>
-
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
#include <linux/delay.h>
+
#include <asm/processor.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
/* Board/System/Debug information/definition ---------------- */
+#define PCI_DM9132_ID 0x91321282 /* Davicom DM9132 ID */
#define PCI_DM9102_ID 0x91021282 /* Davicom DM9102 ID */
#define PCI_DM9100_ID 0x91001282 /* Davicom DM9100 ID */
#define DMFE_SUCC 0
#define DM9102_IO_SIZE 0x80
-#define TX_FREE_DESC_CNT 0x1 /* Tx packet count */
+#define DM9102A_IO_SIZE 0x100
+#define TX_FREE_DESC_CNT 0xc /* Tx packet count */
+#define TX_MAX_SEND_CNT 0x1 /* Maximum tx packet per time */
#define TX_DESC_CNT 0x10 /* Allocated Tx descriptors */
#define RX_DESC_CNT 0x10 /* Allocated Rx descriptors */
#define DESC_ALL_CNT TX_DESC_CNT+RX_DESC_CNT
#define TX_BUF_ALLOC 0x600
#define RX_ALLOC_SIZE 0x620
#define DM910X_RESET 1
-#define CR6_DEFAULT 0x002c0000 /* SF, MII, HD */
+#define CR6_DEFAULT 0x00280000 /* SF, HD */
#define CR7_DEFAULT 0x1a2cd
#define CR15_DEFAULT 0x06 /* TxJabber RxWatchdog */
#define TDES0_ERR_MASK 0x4302 /* TXJT, LC, EC, FUE */
#define MAX_PACKET_SIZE 1514
#define DMFE_MAX_MULTICAST 14
-#define RX_MAX_TRAFFIC 0x5000
+#define RX_MAX_TRAFFIC 0x14000
#define MAX_CHECK_PACKET 0x8000
#define DMFE_10MHF 0
@@ -100,8 +117,8 @@
#define DMFE_100MFD 5
#define DMFE_AUTO 8
-#define DMFE_TIMER_WUT jiffies+HZ*1 /* timer wakeup time : 1 second */
-#define DMFE_TX_TIMEOUT HZ*2 /* tx packet time-out time */
+#define DMFE_TIMER_WUT jiffies+(HZ*2)/2 /* timer wakeup time : 1 second */
+#define DMFE_TX_TIMEOUT HZ*1.5 /* tx packet time-out time 1.5 s" */
#define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk("DBUG: %s %x\n", msg, vaule)
@@ -109,7 +126,7 @@
#define DELAY_1US udelay(1) /* udelay scale 1 usec */
-#define SHOW_MEDIA_TYPE(mode) printk("\n<WARN> Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
+#define SHOW_MEDIA_TYPE(mode) printk(KERN_WARNING "dmfe: Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
/* CR9 definition: SROM/MII */
@@ -125,6 +142,9 @@
#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US;
+#define CHK_IO_SIZE(pci_id, dev_rev) ( (pci_id==PCI_DM9132_ID) || (dev_rev >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE
+
+
/* Structure/enum declaration ------------------------------- */
struct tx_desc {
u32 tdes0, tdes1, tdes2, tdes3;
@@ -149,13 +169,14 @@
struct pci_dev *net_dev; /* PCI device */
- u32 ioaddr; /* I/O base address */
+ unsigned long ioaddr; /* I/O base address */
+ u32 cr0_data;
u32 cr5_data;
u32 cr6_data;
u32 cr7_data;
u32 cr15_data;
-
-/* descriptor pointer */
+
+ /* descriptor pointer */
unsigned char *buf_pool_ptr; /* Tx buffer pool memory */
unsigned char *buf_pool_start; /* Tx buffer pool align dword */
unsigned char *desc_pool_ptr; /* descriptor pool memory */
@@ -166,9 +187,12 @@
struct rx_desc *rx_insert_ptr;
struct rx_desc *rx_ready_ptr; /* packet come pointer */
u32 tx_packet_cnt; /* transmitted packet count */
+ u32 tx_queue_cnt; /* wait to send packet count */
u32 rx_avail_cnt; /* available rx descriptor count */
u32 interval_rx_cnt; /* rx packet count a callback time */
+ u16 phy_id2; /* Phyxcer ID2 */
+
u8 media_mode; /* user specify media mode */
u8 op_mode; /* real work media mode */
u8 phy_addr;
@@ -190,14 +214,14 @@
enum dmfe_CR6_bits {
CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80, CR6_FDM = 0x200,
- CR6_TXSC = 0x2000, CR6_STI = 0x100000, CR6_SFT = 0x200000, CR6_RXA = 0x40000000
+ CR6_TXSC = 0x2000, CR6_STI = 0x100000, CR6_SFT = 0x200000, CR6_RXA = 0x40000000,
+ CR6_NO_PURGE = 0x20000000
};
/* Global variable declaration ----------------------------- */
-
static int dmfe_debug = 0;
static unsigned char dmfe_media_mode = 8;
-static struct net_device *dmfe_root_dev = NULL; /* First device */
+static struct net_device *dmfe_root_dev = NULL; /* First device */
static u32 dmfe_cr6_user_set = 0;
/* For module input parameter */
@@ -206,7 +230,7 @@
static unsigned char mode = 8;
static u8 chkmode = 1;
-unsigned long CrcTable[256] =
+static unsigned long CrcTable[256] =
{
0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
@@ -275,7 +299,7 @@
};
/* function declaration ------------------------------------- */
-static int dmfe_reg_board(void);
+static int dmfe_probe(void);
static int dmfe_open(struct net_device *);
static int dmfe_start_xmit(struct sk_buff *, struct net_device *);
static int dmfe_stop(struct net_device *);
@@ -288,11 +312,11 @@
static void allocated_rx_buffer(struct dmfe_board_info *);
static void update_cr6(u32, u32);
static void send_filter_frame(struct net_device *, int);
-static u16 phy_read(u32, u8, u8);
-static void phy_write(u32, u8, u8, u16);
+static void dm9132_id_table(struct net_device *, int);
+static u16 phy_read(u32, u8, u8, u32);
+static void phy_write(u32, u8, u8, u16, u32);
static void phy_write_1bit(u32, u32);
static u16 phy_read_1bit(u32);
-static void parser_ctrl_info(struct dmfe_board_info *);
static void dmfe_sense_speed(struct dmfe_board_info *);
static void dmfe_process_mode(struct dmfe_board_info *);
static void dmfe_timer(unsigned long);
@@ -301,7 +325,7 @@
static void dmfe_dynamic_reset(struct net_device *);
static void dmfe_free_rxbuffer(struct dmfe_board_info *);
static void dmfe_init_dm910x(struct net_device *);
-static unsigned long cal_CRC(unsigned char *, unsigned int);
+static unsigned long cal_CRC(unsigned char *, unsigned int, u8);
/* DM910X network board routine ---------------------------- */
@@ -309,9 +333,9 @@
* Search DM910X board, allocate space and register it
*/
-static int __init dmfe_reg_board(void)
+static int __init dmfe_probe(void)
{
- u32 pci_iobase;
+ unsigned long pci_iobase;
u16 dm9102_count = 0;
u8 pci_irqline;
static int index = 0; /* For multiple call */
@@ -320,7 +344,7 @@
struct pci_dev *net_dev = NULL;
struct net_device *dev;
- DMFE_DBUG(0, "dmfe_reg_board()", 0);
+ DMFE_DBUG(0, "dmfe_probe()", 0);
if (!pci_present())
return -ENODEV;
@@ -329,20 +353,18 @@
while ((net_dev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, net_dev)))
{
u32 pci_id;
+ u32 dev_rev;
index++;
if (pci_read_config_dword(net_dev, PCI_VENDOR_ID, &pci_id) != DMFE_SUCC)
continue;
- if (pci_id != PCI_DM9102_ID)
+ if ((pci_id != PCI_DM9102_ID) && (pci_id != PCI_DM9132_ID))
continue;
pci_iobase = net_dev->resource[0].start;
pci_irqline = net_dev->irq;
- if (check_region(pci_iobase, DM9102_IO_SIZE)) /* IO range check */
- continue;
-
/* Enable Master/IO access, Disable memory access */
pci_enable_device (net_dev);
@@ -355,7 +377,19 @@
pci_write_config_byte(net_dev, PCI_LATENCY_TIMER, 0x80);
- /* IO range and interrupt check */
+ /* Read Chip revesion */
+ pci_read_config_dword(net_dev, PCI_REVISION_ID, &dev_rev);
+
+ /* IO range check */
+ if (check_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev))) {
+ printk(KERN_ERR "dmfe: I/O conflict : IO=%lx Range=%x\n", pci_iobase, CHK_IO_SIZE(pci_id, dev_rev));
+ continue;
+ }
+ /* Interrupt check */
+ if (pci_irqline == 0) {
+ printk(KERN_ERR "dmfe: Interrupt wrong : IRQ=%d\n", pci_irqline);
+ continue;
+ }
/* Found DM9102 card and PCI resource allocated OK */
dm9102_count++; /* Found a DM9102 card */
@@ -373,7 +407,7 @@
db->chip_id = pci_id; /* keep Chip vandor/Device ID */
db->ioaddr = pci_iobase;
- pci_read_config_dword(net_dev, 8, &db->chip_revesion);
+ db->chip_revesion = dev_rev;
db->net_dev = net_dev;
@@ -386,7 +420,7 @@
dev->set_multicast_list = &dmfe_set_filter_mode;
dev->do_ioctl = &dmfe_do_ioctl;
- request_region(pci_iobase, DM9102_IO_SIZE, dev->name);
+ request_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev), dev->name);
/* read 64 word srom data */
for (i = 0; i < 64; i++)
@@ -422,20 +456,17 @@
db->desc_pool_ptr = kmalloc(sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, GFP_KERNEL | GFP_DMA);
if (db->desc_pool_ptr == NULL)
return -ENOMEM;
-
if ((u32) db->desc_pool_ptr & 0x1f)
db->first_tx_desc = (struct tx_desc *) (((u32) db->desc_pool_ptr & ~0x1f) + 0x20);
else
db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
/* Allocated Tx buffer memory */
-
db->buf_pool_ptr = kmalloc(TX_BUF_ALLOC * TX_DESC_CNT + 4, GFP_KERNEL | GFP_DMA);
if (db->buf_pool_ptr == NULL) {
kfree(db->desc_pool_ptr);
return -ENOMEM;
}
-
if ((u32) db->buf_pool_ptr & 0x3)
db->buf_pool_start = (char *) (((u32) db->buf_pool_ptr & ~0x3) + 0x4);
else
@@ -444,16 +475,21 @@
/* system variable init */
db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set;
db->tx_packet_cnt = 0;
+ db->tx_queue_cnt = 0;
db->rx_avail_cnt = 0;
db->link_failed = 0;
db->wait_reset = 0;
db->in_reset_state = 0;
db->rx_error_cnt = 0;
- if (chkmode && (db->chip_revesion < 0x02000030)) {
- db->dm910x_chk_mode = 1; /* Enter the check mode */
- } else {
+ if (!chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revesion >= 0x02000030)) {
+ //db->cr6_data &= ~CR6_SFT; /* Used Tx threshold */
+ //db->cr6_data |= CR6_NO_PURGE; /* No purge if rx unavailable */
+ db->cr0_data = 0xc00000; /* TX/RX desc burst mode */
db->dm910x_chk_mode = 4; /* Enter the normal mode */
+ } else {
+ db->cr0_data = 0;
+ db->dm910x_chk_mode = 1; /* Enter the check mode */
}
/* Initilize DM910X board */
@@ -474,14 +510,12 @@
return 0;
}
-/*
- * Initialize DM910X board
- * Reset DM910X board
- * Initialize TX/Rx descriptor chain structure
- * Send the set-up frame
- * Enable Tx/Rx machine
+/* Initilize DM910X board
+ Reset DM910X board
+ Initilize TX/Rx descriptor chain structure
+ Send the set-up frame
+ Enable Tx/Rx machine
*/
-
static void dmfe_init_dm910x(struct net_device *dev)
{
struct dmfe_board_info *db = dev->priv;
@@ -490,16 +524,18 @@
DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
/* Reset DM910x board : need 32 PCI clock to complete */
- outl(DM910X_RESET, ioaddr + DCR0);
+ outl(DM910X_RESET, ioaddr + DCR0); /* RESET MAC */
DELAY_5US;
- outl(0, ioaddr + DCR0);
+ outl(db->cr0_data, ioaddr + DCR0);
outl(0x180, ioaddr + DCR12); /* Let bit 7 output port */
- outl(0x80, ioaddr + DCR12); /* Reset DM9102 phyxcer */
+ outl(0x80, ioaddr + DCR12); /* RESET DM9102 phyxcer */
outl(0x0, ioaddr + DCR12); /* Clear RESET signal */
- /* Parser control information: Phy addr */
- parser_ctrl_info(db);
+ /* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
+ db->phy_addr = 1;
+
+ /* Media Mode Check */
db->media_mode = dmfe_media_mode;
if (db->media_mode & DMFE_AUTO)
dmfe_sense_speed(db);
@@ -514,7 +550,10 @@
update_cr6(db->cr6_data, ioaddr);
/* Send setup frame */
- send_filter_frame(dev, 0);
+ if (db->chip_id == PCI_DM9132_ID)
+ dm9132_id_table(dev, dev->mc_count); /* DM9132 */
+ else
+ send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */
/* Init CR5/CR7, interrupt active bit */
outl(0xffffffff, ioaddr + DCR5); /* clear all CR5 status */
@@ -533,10 +572,9 @@
/*
- * Hardware start transmission.
- * Send a packet to media from the upper layer.
+ Hardware start transmission.
+ Send a packet to media from the upper layer.
*/
-
static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct dmfe_board_info *db = dev->priv;
@@ -561,25 +599,24 @@
txptr = db->tx_insert_ptr;
memcpy((char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len);
txptr->tdes1 = 0xe1000000 | skb->len;
- txptr->tdes0 = 0x80000000; /* set owner bit to DM910X */
/* Point to next transmit free descriptor */
db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;
- /* transmit counter increase 1 */
- db->tx_packet_cnt++;
- db->stats.tx_packets++;
-
- /* issue Tx polling command */
- outl(0x1, dev->base_addr + DCR1);
+ /* Transmit Packet Process */
+ if (db->tx_packet_cnt < TX_MAX_SEND_CNT) {
+ txptr->tdes0 = 0x80000000; /* set owner bit to DM910X */
+ db->tx_packet_cnt++; /* Ready to send count */
+ outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling comand */
+ } else {
+ db->tx_queue_cnt++; /* queue the tx packet */
+ outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling comand */
+ }
/* Tx resource check */
if (db->tx_packet_cnt < TX_FREE_DESC_CNT)
netif_wake_queue(dev);
- /* Set transmit time stamp */
- dev->trans_start = jiffies; /* saved the time stamp */
-
/* free this SKB */
dev_kfree_skb(skb);
return 0;
@@ -622,8 +659,8 @@
}
/*
- * DM9102 insterrupt handler
- * receive the packet to upper layer, free the transmitted packet
+ DM9102 insterrupt handler
+ receive the packet to upper layer, free the transmitted packet
*/
static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -637,7 +674,6 @@
DMFE_DBUG(1, "dmfe_interrupt() without device arg", 0);
return;
}
-
/* A real interrupt coming */
db = (struct dmfe_board_info *) dev->priv;
ioaddr = dev->base_addr;
@@ -667,15 +703,35 @@
/* printk("tdes0=%x\n", txptr->tdes0); */
if (txptr->tdes0 & 0x80000000)
break;
+ db->stats.tx_packets++;
+
if ((txptr->tdes0 & TDES0_ERR_MASK) && (txptr->tdes0 != 0x7fffffff)) {
/* printk("tdes0=%x\n", txptr->tdes0); */
db->stats.tx_errors++;
}
+ /* Transmit statistic counter */
+ if (txptr->tdes0 != 0x7fffffff) {
+ /* printk("tdes0=%x\n", txptr->tdes0); */
+ db->stats.collisions += (txptr->tdes0 >> 3) & 0xf;
+ db->stats.tx_bytes += txptr->tdes1 & 0x7ff;
+ if (txptr->tdes0 & TDES0_ERR_MASK)
+ db->stats.tx_errors++;
+ }
txptr = (struct tx_desc *) txptr->next_tx_desc;
db->tx_packet_cnt--;
}
+ /* Update TX remove pointer to next */
db->tx_remove_ptr = (struct tx_desc *) txptr;
+ /* Send the Tx packet in queue */
+ if ((db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt) {
+ txptr->tdes0 = 0x80000000; /* set owner bit to DM910X */
+ db->tx_packet_cnt++; /* Ready to send count */
+ outl(0x1, ioaddr + DCR1); /* Issue Tx polling command */
+ dev->trans_start = jiffies; /* saved the time stamp */
+ db->tx_queue_cnt--;
+ }
+ /* Resource available check */
if (db->tx_packet_cnt < TX_FREE_DESC_CNT)
netif_wake_queue(dev);
@@ -695,7 +751,6 @@
}
/* Restore CR7 to enable interrupt mask */
-
if (db->interval_rx_cnt > RX_MAX_TRAFFIC)
db->cr7_data = 0x1a28d;
else
@@ -704,9 +759,8 @@
}
/*
- * Receive the come packet and pass to upper layer
+ Receive the come packet and pass to upper layer
*/
-
static void dmfe_rx_packet(struct net_device *dev, struct dmfe_board_info *db)
{
struct rx_desc *rxptr;
@@ -727,11 +781,11 @@
/* reused this SKB */
DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0);
dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);
- db->rx_error_cnt++;
+ /* db->rx_error_cnt++; */
} else {
+ /* A packet with First/Last flag */
rxlen = ((rxptr->rdes0 >> 16) & 0x3fff) - 4; /* skip CRC */
- /* A packet with First/Last flag */
if (rxptr->rdes0 & 0x8000) { /* error summary bit check */
/* This is a error packet */
/* printk("rdes0 error : %x \n", rxptr->rdes0); */
@@ -748,7 +802,7 @@
skb = (struct sk_buff *) rxptr->rx_skb_ptr;
/* Received Packet CRC check need or not */
- if ((db->dm910x_chk_mode & 1) && (cal_CRC(skb->tail, rxlen) != (*(unsigned long *) (skb->tail + rxlen)))) {
+ if ((db->dm910x_chk_mode & 1) && (cal_CRC(skb->tail, rxlen, 1) != (*(unsigned long *) (skb->tail + rxlen)))) {
/* Found a error received packet */
dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);
db->dm910x_chk_mode = 3;
@@ -758,11 +812,12 @@
skb_put(skb, rxlen);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb); /* Send to upper layer */
- /* skb->ip_summed = CHECKSUM_UNNECESSARY; */
dev->last_rx = jiffies;
db->stats.rx_packets++;
+ db->stats.rx_bytes += rxlen;
}
} else {
+ /* Reuse SKB buffer when the packet is error */
DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0);
dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr);
}
@@ -772,12 +827,12 @@
}
db->rx_ready_ptr = rxptr;
+
}
/*
- * Get statistics from driver.
+ Get statistics from driver.
*/
-
static struct enet_statistics *dmfe_get_stats(struct net_device *dev)
{
struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
@@ -787,9 +842,8 @@
}
/*
- * Set DM910X multicast address
+ Set DM910X multicast address
*/
-
static void dmfe_set_filter_mode(struct net_device *dev)
{
struct dmfe_board_info *db = dev->priv;
@@ -809,13 +863,15 @@
return;
}
DMFE_DBUG(0, "Set multicast address", dev->mc_count);
- send_filter_frame(dev, dev->mc_count);
+ if (db->chip_id == PCI_DM9132_ID)
+ dm9132_id_table(dev, dev->mc_count); /* DM9132 */
+ else
+ send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */
}
/*
- * Process the upper socket ioctl command
+ Process the upper socket ioctl command
*/
-
static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
@@ -823,10 +879,9 @@
}
/*
- * A periodic timer routine
- * Dynamic media sense, allocated Rx buffer...
+ A periodic timer routine
+ Dynamic media sense, allocated Rx buffer...
*/
-
static void dmfe_timer(unsigned long data)
{
u32 tmp_cr8;
@@ -861,18 +916,26 @@
if (db->wait_reset | (db->tx_packet_cnt &&
((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT)) | (db->rx_error_cnt > 3)) {
- /* printk("wait_reset %x, tx cnt %x, rx err %x, time %x\n", db->wait_reset, db->tx_packet_cnt, db->rx_error_cnt, jiffies-dev->trans_start); */
+ /*
+ printk("wait_reset %x, tx cnt %x, rx err %x, time %x\n", db->wait_reset, db->tx_packet_cnt, db->rx_error_cnt, jiffies-dev->trans_start);
+ */
DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx moniotr step1", db->tx_packet_cnt);
dmfe_dynamic_reset(dev);
db->timer.expires = DMFE_TIMER_WUT;
add_timer(&db->timer);
return;
}
- db->rx_error_cnt = 0; /* Clear previous counter */
+ db->rx_error_cnt = 0; /* Clear previos counter */
/* Link status check, Dynamic media type change */
- tmp_cr12 = inb(db->ioaddr + DCR12);
- if (db->chip_revesion == 0x02000030) {
+ if (db->chip_id == PCI_DM9132_ID)
+ tmp_cr12 = inb(db->ioaddr + DCR9 + 3); /* DM9132 */
+ else
+ tmp_cr12 = inb(db->ioaddr + DCR12); /* DM9102/DM9102A */
+
+ if (((db->chip_id == PCI_DM9102_ID) && (db->chip_revesion == 0x02000030)) ||
+ ((db->chip_id == PCI_DM9132_ID) && (db->chip_revesion == 0x02000010))) {
+ /* DM9102A Chip */
if (tmp_cr12 & 2)
tmp_cr12 = 0x0; /* Link failed */
else
@@ -882,10 +945,26 @@
/* Link Failed */
DMFE_DBUG(0, "Link Failed", tmp_cr12);
db->link_failed = 1;
- phy_write(db->ioaddr, db->phy_addr, 0, 0x8000); /* reset Phy controller */
+ phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id); /* reset Phy */
+
+ /* 10/100M link failed, used 1M Home-Net */
+ db->cr6_data |= 0x00040000; /* CR6 bit18 = 1, select Home-Net */
+ db->cr6_data &= ~0x00000200; /* CR6 bit9 =0, half duplex mode */
+ update_cr6(db->cr6_data, db->ioaddr);
+
+ /* For DM9801 : PHY ID1 0181h, PHY ID2 B900h */
+ db->phy_id2 = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
+ if (db->phy_id2 == 0xb900)
+ phy_write(db->ioaddr, db->phy_addr, 25, 0x7e08, db->chip_id);
} else if ((tmp_cr12 & 0x3) && db->link_failed) {
DMFE_DBUG(0, "Link link OK", tmp_cr12);
db->link_failed = 0;
+
+ /* CR6 bit18=0, select 10/100M */
+ db->cr6_data &= ~0x00040000;
+ update_cr6(db->cr6_data, db->ioaddr);
+
+ /* Auto Sense Speed */
if (db->media_mode & DMFE_AUTO)
dmfe_sense_speed(db);
dmfe_process_mode(db);
@@ -902,13 +981,12 @@
}
/*
- * Dynamic reset the DM910X board
- * Stop DM910X board
- * Free Tx/Rx allocated memory
- * Reset DM910X board
- * Re-initilize DM910X board
+ Dynamic reset the DM910X board
+ Stop DM910X board
+ Free Tx/Rx allocated memory
+ Reset DM910X board
+ Re-initilize DM910X board
*/
-
static void dmfe_dynamic_reset(struct net_device *dev)
{
struct dmfe_board_info *db = dev->priv;
@@ -929,6 +1007,7 @@
/* system variable init */
db->tx_packet_cnt = 0;
+ db->tx_queue_cnt = 0;
db->rx_avail_cnt = 0;
db->link_failed = 0;
db->wait_reset = 0;
@@ -945,9 +1024,8 @@
}
/*
- * Free all allocated rx buffer
+ free all allocated rx buffer
*/
-
static void dmfe_free_rxbuffer(struct dmfe_board_info *db)
{
DMFE_DBUG(0, "dmfe_free_rxbuffer()", 0);
@@ -961,9 +1039,8 @@
}
/*
- * Reused the SK buffer
+ Reused the SK buffer
*/
-
static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff *skb)
{
struct rx_desc *rxptr = db->rx_insert_ptr;
@@ -979,10 +1056,9 @@
}
/*
- * Initialize transmit/Receive descriptor
- * Using Chain structure, and allocated Tx/Rx buffer
+ Initialize transmit/Receive descriptor
+ Using Chain structure, and allocated Tx/Rx buffer
*/
-
static void dmfe_descriptor_init(struct dmfe_board_info *db, u32 ioaddr)
{
struct tx_desc *tmp_tx;
@@ -1033,10 +1109,9 @@
}
/*
- * Update CR6 vaule
- * Firstly stop DM910X , then written value and start
+ Update CR6 vaule
+ Firstly stop DM910X , then written value and start
*/
-
static void update_cr6(u32 cr6_data, u32 ioaddr)
{
u32 cr6_tmp;
@@ -1049,11 +1124,50 @@
/* printk("CR6 update %x ", cr6_tmp); */
}
-/*
- * Send a setup frame
- * This setup frame initilize DM910X addres filter mode
+/* Send a setup frame for DM9132
+ This setup frame initilize DM910X addres filter mode
+ */
+static void dm9132_id_table(struct net_device *dev, int mc_cnt)
+{
+ struct dev_mc_list *mcptr;
+ u16 *addrptr;
+ u32 ioaddr = dev->base_addr + 0xc0; /* ID Table */
+ u32 hash_val;
+ u16 i, hash_table[4];
+
+ DMFE_DBUG(0, "dm9132_id_table()", 0);
+
+ /* Node address */
+ addrptr = (u16 *) dev->dev_addr;
+ outw(addrptr[0], ioaddr);
+ ioaddr += 4;
+ outw(addrptr[1], ioaddr);
+ ioaddr += 4;
+ outw(addrptr[2], ioaddr);
+ ioaddr += 4;
+
+ /* Clear Hash Table */
+ for (i = 0; i < 4; i++)
+ hash_table[i] = 0x0;
+
+ /* broadcast address */
+ hash_table[3] = 0x8000;
+
+ /* the multicast address in Hash Table : 64 bits */
+ for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
+ hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f;
+ hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
+ }
+
+ /* Write the hash table to MAC MD table */
+ for (i = 0; i < 4; i++, ioaddr += 4) {
+ outw(hash_table[i], ioaddr);
+ }
+}
+
+/* Send a setup frame for DM9102/DM9102A
+ This setup frame initilize DM910X addres filter mode
*/
-
static void send_filter_frame(struct net_device *dev, int mc_cnt)
{
struct dmfe_board_info *db = dev->priv;
@@ -1068,17 +1182,17 @@
txptr = db->tx_insert_ptr;
suptr = (u32 *) txptr->tx_buf_ptr;
- /* broadcast address */
- *suptr++ = 0xffff;
- *suptr++ = 0xffff;
- *suptr++ = 0xffff;
-
/* Node address */
addrptr = (u16 *) dev->dev_addr;
*suptr++ = addrptr[0];
*suptr++ = addrptr[1];
*suptr++ = addrptr[2];
+ /* broadcast address */
+ *suptr++ = 0xffff;
+ *suptr++ = 0xffff;
+ *suptr++ = 0xffff;
+
/* fit the multicast address */
for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
addrptr = (u16 *) mcptr->dmi_addr;
@@ -1092,19 +1206,21 @@
*suptr++ = 0xffff;
*suptr++ = 0xffff;
}
-
/* prepare the setup frame */
- db->tx_packet_cnt++;
- netif_stop_queue(dev);
- txptr->tdes1 = 0x890000c0;
- txptr->tdes0 = 0x80000000;
db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc;
-
- update_cr6(db->cr6_data | 0x2000, dev->base_addr);
- outl(0x1, dev->base_addr + DCR1);
- update_cr6(db->cr6_data, dev->base_addr);
- dev->trans_start = jiffies;
-
+ txptr->tdes1 = 0x890000c0;
+ /* Resource Check and Send the setup packet */
+ if (!db->tx_packet_cnt) {
+ /* Resource Empty */
+ db->tx_packet_cnt++;
+ txptr->tdes0 = 0x80000000;
+ update_cr6(db->cr6_data | 0x2000, dev->base_addr);
+ outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling command */
+ update_cr6(db->cr6_data, dev->base_addr);
+ } else {
+ /* Put into TX queue */
+ db->tx_queue_cnt++;
+ }
}
/*
@@ -1132,9 +1248,8 @@
}
/*
- * Read one word data from the serial ROM
+ Read one word data from the serial ROM
*/
-
static u16 read_srom_word(long ioaddr, int offset)
{
int i;
@@ -1170,35 +1285,6 @@
}
/*
- * Parser Control media block to get Phy address
- */
-
-static void parser_ctrl_info(struct dmfe_board_info *db)
-{
- int i;
- char *sdata = db->srom;
- unsigned char count;
-
- /* point to info leaf0 */
- count = *(sdata + 33);
-
- /* Point to First media block */
- sdata += 34;
- for (i = 0; i < count; i++) {
- if (*(sdata + 1) == 1) {
- db->phy_addr = *(sdata + 2);
- break;
- }
- sdata += ((unsigned char) *(sdata) & 0x7f) + 1;
- }
-
- if (i >= count) {
- printk("Can't found Control Block\n");
- db->phy_addr = 1;
- }
-}
-
-/*
* Auto sense the media mode
*/
@@ -1209,13 +1295,16 @@
for (i = 1000; i; i--) {
DELAY_5US;
- phy_mode = phy_read(db->ioaddr, db->phy_addr, 1);
+ phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
if ((phy_mode & 0x24) == 0x24)
break;
}
if (i) {
- phy_mode = phy_read(db->ioaddr, db->phy_addr, 17) & 0xf000;
+ if (db->chip_id == PCI_DM9132_ID) /* DM9132 */
+ phy_mode = phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) & 0xf000;
+ else /* DM9102/DM9102A */
+ phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000;
/* printk("Phy_mode %x ",phy_mode); */
switch (phy_mode) {
case 0x1000:
@@ -1231,23 +1320,22 @@
db->op_mode = DMFE_100MFD;
break;
default:
- db->op_mode = DMFE_100MHF;
- DMFE_DBUG(1, "Media Type error, phy reg17", phy_mode);
+ db->op_mode = DMFE_10MHF;
+ DMFE_DBUG(0, "Media Type error, phy reg17", phy_mode);
break;
}
} else {
- db->op_mode = DMFE_100MHF;
+ db->op_mode = DMFE_10MHF;
DMFE_DBUG(0, "Link Failed :", phy_mode);
}
}
/*
- * Process op-mode
- * AUTO mode : PHY controller in Auto-negotiation Mode
- * Force mode: PHY controller in force mode with HUB
- * N-way force capability with SWITCH
+ Process op-mode
+ AUTO mode : PHY controller in Auto-negotiation Mode
+ Force mode: PHY controller in force mode with HUB
+ N-way force capability with SWITCH
*/
-
static void dmfe_process_mode(struct dmfe_board_info *db)
{
u16 phy_reg;
@@ -1259,11 +1347,11 @@
if (!(db->media_mode & DMFE_AUTO)) { /* Force Mode Check */
/* User force the media type */
- phy_reg = phy_read(db->ioaddr, db->phy_addr, 5);
+ phy_reg = phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id);
/* printk("Nway phy_reg5 %x ",phy_reg); */
if (phy_reg & 0x1) {
/* parter own the N-Way capability */
- phy_reg = phy_read(db->ioaddr, db->phy_addr, 4) & ~0x1e0;
+ phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x1e0;
switch (db->op_mode) {
case DMFE_10MHF:
phy_reg |= 0x20;
@@ -1278,7 +1366,7 @@
phy_reg |= 0x100;
break;
}
- phy_write(db->ioaddr, db->phy_addr, 4, phy_reg);
+ phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
} else {
/* parter without the N-Way capability */
switch (db->op_mode) {
@@ -1295,95 +1383,109 @@
phy_reg = 0x2100;
break;
}
- phy_write(db->ioaddr, db->phy_addr, 0, phy_reg);
+ phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
}
}
}
/*
- * Write a word to Phy register
+ Write a word to Phy register
*/
-
-static void phy_write(u32 iobase, u8 phy_addr, u8 offset, u16 phy_data)
+static void phy_write(u32 iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id)
{
u16 i;
- u32 ioaddr = iobase + DCR9;
+ u32 ioaddr;
- /* Send 33 synchronization clock to Phy controller */
- for (i = 0; i < 35; i++)
- phy_write_1bit(ioaddr, PHY_DATA_1);
+ if (chip_id == PCI_DM9132_ID) {
+ ioaddr = iobase + 0x80 + offset * 4;
+ outw(phy_data, ioaddr);
+ } else {
+ /* DM9102/DM9102A Chip */
+ ioaddr = iobase + DCR9;
- /* Send start command(01) to Phy */
- phy_write_1bit(ioaddr, PHY_DATA_0);
- phy_write_1bit(ioaddr, PHY_DATA_1);
+ /* Send 33 synchronization clock to Phy controller */
+ for (i = 0; i < 35; i++)
+ phy_write_1bit(ioaddr, PHY_DATA_1);
- /* Send write command(01) to Phy */
- phy_write_1bit(ioaddr, PHY_DATA_0);
- phy_write_1bit(ioaddr, PHY_DATA_1);
+ /* Send start command(01) to Phy */
+ phy_write_1bit(ioaddr, PHY_DATA_0);
+ phy_write_1bit(ioaddr, PHY_DATA_1);
- /* Send Phy addres */
- for (i = 0x10; i > 0; i = i >> 1)
- phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
+ /* Send write command(01) to Phy */
+ phy_write_1bit(ioaddr, PHY_DATA_0);
+ phy_write_1bit(ioaddr, PHY_DATA_1);
- /* Send register addres */
- for (i = 0x10; i > 0; i = i >> 1)
- phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
+ /* Send Phy addres */
+ for (i = 0x10; i > 0; i = i >> 1)
+ phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
+
+ /* Send register addres */
+ for (i = 0x10; i > 0; i = i >> 1)
+ phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
- /* written trasnition */
- phy_write_1bit(ioaddr, PHY_DATA_1);
- phy_write_1bit(ioaddr, PHY_DATA_0);
+ /* written trasnition */
+ phy_write_1bit(ioaddr, PHY_DATA_1);
+ phy_write_1bit(ioaddr, PHY_DATA_0);
- /* Write a word data to PHY controller */
- for (i = 0x8000; i > 0; i >>= 1)
- phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
+ /* Write a word data to PHY controller */
+ for (i = 0x8000; i > 0; i >>= 1)
+ phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
+ }
}
/*
- * Read a word data from phy register
+ Read a word data from phy register
*/
-
-static u16 phy_read(u32 iobase, u8 phy_addr, u8 offset)
+static u16 phy_read(u32 iobase, u8 phy_addr, u8 offset, u32 chip_id)
{
int i;
u16 phy_data;
- u32 ioaddr = iobase + DCR9;
+ u32 ioaddr;
- /* Send 33 synchronization clock to Phy controller */
- for (i = 0; i < 35; i++)
+ if (chip_id == PCI_DM9132_ID) {
+ /* DM9132 Chip */
+ ioaddr = iobase + 0x80 + offset * 4;
+ phy_data = inw(ioaddr);
+ } else {
+ /* DM9102/DM9102A Chip */
+
+ ioaddr = iobase + DCR9;
+ /* Send 33 synchronization clock to Phy controller */
+ for (i = 0; i < 35; i++)
+ phy_write_1bit(ioaddr, PHY_DATA_1);
+
+ /* Send start command(01) to Phy */
+ phy_write_1bit(ioaddr, PHY_DATA_0);
phy_write_1bit(ioaddr, PHY_DATA_1);
- /* Send start command(01) to Phy */
- phy_write_1bit(ioaddr, PHY_DATA_0);
- phy_write_1bit(ioaddr, PHY_DATA_1);
-
- /* Send read command(10) to Phy */
- phy_write_1bit(ioaddr, PHY_DATA_1);
- phy_write_1bit(ioaddr, PHY_DATA_0);
-
- /* Send Phy addres */
- for (i = 0x10; i > 0; i = i >> 1)
- phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
-
- /* Send register addres */
- for (i = 0x10; i > 0; i = i >> 1)
- phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
-
- /* Skip transition state */
- phy_read_1bit(ioaddr);
-
- /* read 16bit data */
- for (phy_data = 0, i = 0; i < 16; i++) {
- phy_data <<= 1;
- phy_data |= phy_read_1bit(ioaddr);
+ /* Send read command(10) to Phy */
+ phy_write_1bit(ioaddr, PHY_DATA_1);
+ phy_write_1bit(ioaddr, PHY_DATA_0);
+
+ /* Send Phy addres */
+ for (i = 0x10; i > 0; i = i >> 1)
+ phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
+
+ /* Send register addres */
+ for (i = 0x10; i > 0; i = i >> 1)
+ phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
+
+ /* Skip transition state */
+ phy_read_1bit(ioaddr);
+
+ /* read 16bit data */
+ for (phy_data = 0, i = 0; i < 16; i++) {
+ phy_data <<= 1;
+ phy_data |= phy_read_1bit(ioaddr);
+ }
}
return phy_data;
}
/*
- * Write one bit data to Phy Controller
+ Write one bit data to Phy Controller
*/
-
static void phy_write_1bit(u32 ioaddr, u32 phy_data)
{
outl(phy_data, ioaddr); /* MII Clock Low */
@@ -1395,9 +1497,8 @@
}
/*
- * Read one bit phy data from PHY controller
+ Read one bit phy data from PHY controller
*/
-
static u16 phy_read_1bit(u32 ioaddr)
{
u16 phy_data;
@@ -1412,10 +1513,11 @@
}
/*
- * Calculate the CRC valude of the Rx packet
+ Calculate the CRC valude of the Rx packet
+ flag = 1 : return the reverse CRC (for the received packet CRC)
+ 0 : return the normal CRC (for Hash Table index)
*/
-
-static unsigned long cal_CRC(unsigned char *Data, unsigned int Len)
+unsigned long cal_CRC(unsigned char *Data, unsigned int Len, u8 flag)
{
unsigned long Crc = 0xffffffff;
@@ -1423,8 +1525,10 @@
Crc = CrcTable[(Crc ^ *Data++) & 0xFF] ^ (Crc >> 8);
}
- return ~Crc;
-
+ if (flag)
+ return ~Crc;
+ else
+ return Crc;
}
@@ -1461,7 +1565,7 @@
break;
}
- return dmfe_reg_board(); /* search board and register */
+ return dmfe_probe(); /* search board and register */
}
/*
@@ -1473,14 +1577,16 @@
static void __exit dmfe_cleanup_module(void)
{
struct net_device *next_dev;
+ struct dmfe_board_info *db;
DMFE_DBUG(0, "clean_module()", 0);
while (dmfe_root_dev) {
- next_dev = ((struct dmfe_board_info *) dmfe_root_dev->priv)->next_dev;
+ db = dmfe_root_dev->priv;
+ next_dev = db->next_dev;
unregister_netdev(dmfe_root_dev);
- release_region(dmfe_root_dev->base_addr, DM9102_IO_SIZE);
- kfree(dmfe_root_dev->priv); /* free board information */
+ release_region(dmfe_root_dev->base_addr, CHK_IO_SIZE(db->chip_id, db->chip_revesion));
+ kfree(db); /* free board information */
kfree(dmfe_root_dev); /* free device structure */
dmfe_root_dev = next_dev;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)