patch-2.3.43 linux/drivers/net/rtl8139.c
Next file: linux/drivers/net/setup.c
Previous file: linux/drivers/net/rcpci45.c
Back to the patch index
Back to the overall index
- Lines: 387
- Date:
Wed Feb 9 20:08:09 2000
- Orig file:
v2.3.42/linux/drivers/net/rtl8139.c
- Orig date:
Thu Nov 11 20:11:41 1999
diff -u --recursive --new-file v2.3.42/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c
@@ -165,11 +165,12 @@
const char *name;
u16 vendor_id, device_id, device_id_mask, flags;
int io_size;
- struct net_device *(*probe1)(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
+ struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
};
-static struct net_device * rtl8129_probe1(int pci_bus, int pci_devfn, long ioaddr,
- int irq, int chp_idx, int fnd_cnt);
+static struct net_device * rtl8129_probe1(struct pci_dev *pdev, int pci_bus,
+ int pci_devfn, long ioaddr,
+ int irq, int chp_idx, int fnd_cnt);
static struct pci_id_info pci_tbl[] =
{{ "RealTek RTL8129 Fast Ethernet",
@@ -249,10 +250,16 @@
{0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83}
};
+struct ring_info {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+};
+
struct rtl8129_private {
char devname[8]; /* Used only for kernel debugging. */
const char *product_name;
struct net_device *next_module;
+ struct pci_dev *pdev;
int chip_id;
int chip_revision;
unsigned char pci_bus, pci_devfn;
@@ -265,10 +272,12 @@
unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
unsigned int cur_tx, dirty_tx, tx_flag;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
- struct sk_buff* tx_skbuff[NUM_TX_DESC];
+ struct ring_info tx_info[NUM_TX_DESC];
unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
unsigned char *rx_ring;
unsigned char *tx_bufs; /* Tx bounce buffer region. */
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_bufs_dma;
char phys[4]; /* MII device addresses. */
char twistie, twist_cnt; /* Twister tune state. */
unsigned int tx_full:1; /* The Tx queue is full. */
@@ -328,6 +337,7 @@
return -ENODEV;
for (; pci_index < 0xff; pci_index++) {
+ struct pci_dev *pdev;
u16 vendor, device, pci_command, new_command;
int chip_idx, irq;
long ioaddr;
@@ -349,22 +359,9 @@
if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
continue;
- {
-#if defined(PCI_SUPPORT_VER2)
- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
- ioaddr = pdev->resource[0].start;
- irq = pdev->irq;
-#else
- u32 pci_ioaddr;
- u8 pci_irq_line;
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
- ioaddr = pci_ioaddr & ~3;
- irq = pci_irq_line;
-#endif
- }
+ pdev = pci_find_slot(pci_bus, pci_device_fn);
+ ioaddr = pdev->resource[0].start;
+ irq = pdev->irq;
if ((pci_tbl[chip_idx].flags & PCI_USES_IO) &&
check_region(ioaddr, pci_tbl[chip_idx].io_size))
@@ -382,7 +379,7 @@
PCI_COMMAND, new_command);
}
- dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found);
+ dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found);
if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
u8 pci_latency;
@@ -403,8 +400,9 @@
return cards_found ? 0 : -ENODEV;
}
-static struct net_device *rtl8129_probe1(int pci_bus, int pci_devfn, long ioaddr,
- int irq, int chip_idx, int found_cnt)
+static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus,
+ int pci_devfn, long ioaddr,
+ int irq, int chip_idx, int found_cnt)
{
static int did_version = 0; /* Already printed version info. */
struct rtl8129_private *tp;
@@ -449,6 +447,7 @@
tp->next_module = root_rtl8129_dev;
root_rtl8129_dev = dev;
+ tp->pdev = pdev;
tp->chip_id = chip_idx;
tp->pci_bus = pci_bus;
tp->pci_devfn = pci_devfn;
@@ -501,6 +500,8 @@
/* The Rtl8129-specific entries in the device structure. */
dev->open = &rtl8129_open;
dev->hard_start_xmit = &rtl8129_start_xmit;
+ dev->tx_timeout = &rtl8129_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
dev->stop = &rtl8129_close;
dev->get_stats = &rtl8129_get_stats;
dev->set_multicast_list = &set_rx_mode;
@@ -677,12 +678,22 @@
MOD_INC_USE_COUNT;
- tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL);
- tp->rx_ring = kmalloc(RX_BUF_LEN + 16, GFP_KERNEL);
+ tp->tx_bufs = pci_alloc_consistent(tp->pdev,
+ TX_BUF_SIZE * NUM_TX_DESC,
+ &tp->tx_bufs_dma);
+ tp->rx_ring = pci_alloc_consistent(tp->pdev,
+ RX_BUF_LEN + 16,
+ &tp->rx_ring_dma);
if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
free_irq(dev->irq, dev);
if (tp->tx_bufs)
- kfree(tp->tx_bufs);
+ pci_free_consistent(tp->pdev,
+ TX_BUF_SIZE * NUM_TX_DESC,
+ tp->tx_bufs, tp->tx_bufs_dma);
+ if (tp->rx_ring)
+ pci_free_consistent(tp->pdev,
+ RX_BUF_LEN + 16,
+ tp->rx_ring, tp->rx_ring_dma);
if (rtl8129_debug > 0)
printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n",
dev->name, RX_BUF_LEN);
@@ -725,7 +736,7 @@
outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
outb(0x00, ioaddr + Cfg9346);
- outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf);
+ outl(tp->rx_ring_dma, ioaddr + RxBuf);
/* Start the chip's Tx and Rx process. */
outl(0, ioaddr + RxMissed);
@@ -733,10 +744,6 @@
outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
/* Enable all known interrupts by setting the interrupt mask. */
outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
| TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
@@ -787,7 +794,8 @@
rtl8129_interrupt(dev->irq, dev, 0);
}
}
- if (dev->tbusy && jiffies - dev->trans_start >= 2*TX_TIMEOUT)
+ if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+ (jiffies - dev->trans_start) >= 2*TX_TIMEOUT)
rtl8129_tx_timeout(dev);
#if 0
@@ -902,26 +910,40 @@
{ /* Save the unsent Tx packets. */
struct sk_buff *saved_skb[NUM_TX_DESC], *skb;
int j;
- for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++)
- saved_skb[j] = tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC];
+ for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) {
+ struct ring_info *rp = &tp->tx_info[tp->dirty_tx % NUM_TX_DESC];
+
+ saved_skb[j] = rp->skb;
+ if (rp->mapping != 0) {
+ pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len);
+ rp->mapping = 0;
+ }
+ }
tp->dirty_tx = tp->cur_tx = 0;
for (i = 0; i < j; i++) {
- skb = tp->tx_skbuff[i] = saved_skb[i];
+ skb = tp->tx_info[i].skb = saved_skb[i];
if ((long)skb->data & 3) { /* Must use alignment buffer. */
memcpy(tp->tx_buf[i], skb->data, skb->len);
- outl(virt_to_bus(tp->tx_buf[i]), ioaddr + TxAddr0 + i*4);
- } else
- outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + i*4);
+ outl(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs),
+ ioaddr + TxAddr0 + i*4);
+ } else {
+ tp->tx_info[i].mapping =
+ pci_map_single(tp->pdev, skb->data, skb->len);
+ outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4);
+ }
/* Note: the chip doesn't have auto-pad! */
outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
ioaddr + TxStatus0 + i*4);
}
tp->cur_tx = i;
- while (i < NUM_TX_DESC)
- tp->tx_skbuff[i++] = 0;
+ while (i < NUM_TX_DESC) {
+ tp->tx_info[i].skb = NULL;
+ tp->tx_info[i].mapping = 0;
+ i++;
+ }
if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
- dev->tbusy = 0;
+ netif_wake_queue(dev);
tp->tx_full = 0;
} else {
tp->tx_full = 1;
@@ -949,8 +971,9 @@
tp->dirty_tx = tp->cur_tx = 0;
for (i = 0; i < NUM_TX_DESC; i++) {
- tp->tx_skbuff[i] = 0;
tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE];
+ tp->tx_info[i].skb = NULL;
+ tp->tx_info[i].mapping = 0;
}
}
@@ -961,29 +984,28 @@
long ioaddr = dev->base_addr;
int entry;
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- if (jiffies - dev->trans_start >= TX_TIMEOUT)
- rtl8129_tx_timeout(dev);
- return 1;
- }
+ netif_stop_queue(dev);
/* Calculate the next Tx descriptor entry. */
entry = tp->cur_tx % NUM_TX_DESC;
- tp->tx_skbuff[entry] = skb;
+ tp->tx_info[entry].skb = skb;
if ((long)skb->data & 3) { /* Must use alignment buffer. */
+ tp->tx_info[entry].mapping = 0;
memcpy(tp->tx_buf[entry], skb->data, skb->len);
- outl(virt_to_bus(tp->tx_buf[entry]), ioaddr + TxAddr0 + entry*4);
- } else
- outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + entry*4);
+ outl(tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs),
+ ioaddr + TxAddr0 + entry*4);
+ } else {
+ tp->tx_info[entry].mapping =
+ pci_map_single(tp->pdev, skb->data, skb->len);
+ outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4);
+ }
/* Note: the chip doesn't have auto-pad! */
outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
ioaddr + TxStatus0 + entry*4);
if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) { /* Typical path */
- clear_bit(0, (void*)&dev->tbusy);
+ netif_start_queue(dev);
} else {
tp->tx_full = 1;
}
@@ -1006,22 +1028,6 @@
int status, link_changed = 0;
long ioaddr = dev->base_addr;
-#if defined(__i386__)
- /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
- if (test_and_set_bit(0, (void*)&dev->interrupt)) {
- printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
- dev->name);
- dev->interrupt = 0; /* Avoid halting machine. */
- return;
- }
-#else
- if (dev->interrupt) {
- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
- return;
- }
- dev->interrupt = 1;
-#endif
-
do {
status = inw(ioaddr + IntrStatus);
/* Acknowledge all of the current interrupt sources ASAP, but
@@ -1082,14 +1088,20 @@
tp->stats.tx_packets++;
}
+ if (tp->tx_info[entry].mapping != 0) {
+ pci_unmap_single(tp->pdev,
+ tp->tx_info[entry].mapping,
+ tp->tx_info[entry].skb->len);
+ tp->tx_info[entry].mapping = 0;
+ }
+
/* Free the original skb. */
- dev_free_skb(tp->tx_skbuff[entry]);
- tp->tx_skbuff[entry] = 0;
+ dev_free_skb(tp->tx_info[entry].skb);
+ tp->tx_info[entry].skb = NULL;
if (tp->tx_full) {
- /* The ring is no longer full, clear tbusy. */
+ /* The ring is no longer full, wake the queue. */
tp->tx_full = 0;
- clear_bit(0, (void*)&dev->tbusy);
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
dirty_tx++;
}
@@ -1162,12 +1174,6 @@
if (rtl8129_debug > 3)
printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n",
dev->name, inl(ioaddr + IntrStatus));
-
-#if defined(__i386__)
- clear_bit(0, (void*)&dev->interrupt);
-#else
- dev->interrupt = 0;
-#endif
return;
}
@@ -1289,8 +1295,7 @@
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
int i;
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
if (rtl8129_debug > 1)
printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",
@@ -1311,12 +1316,23 @@
free_irq(dev->irq, dev);
for (i = 0; i < NUM_TX_DESC; i++) {
- if (tp->tx_skbuff[i])
- dev_free_skb(tp->tx_skbuff[i]);
- tp->tx_skbuff[i] = 0;
+ struct sk_buff *skb = tp->tx_info[i].skb;
+ dma_addr_t mapping = tp->tx_info[i].mapping;
+
+ if (skb) {
+ if (mapping)
+ pci_unmap_single(tp->pdev, mapping, skb->len);
+ dev_free_skb(skb);
+ }
+ tp->tx_info[i].skb = NULL;
+ tp->tx_info[i].mapping = 0;
}
- kfree(tp->rx_ring);
- kfree(tp->tx_bufs);
+ pci_free_consistent(tp->pdev, RX_BUF_LEN + 16,
+ tp->rx_ring, tp->rx_ring_dma);
+ pci_free_consistent(tp->pdev, TX_BUF_SIZE * NUM_TX_DESC,
+ tp->tx_bufs, tp->tx_bufs_dma);
+ tp->rx_ring = NULL;
+ tp->tx_bufs = NULL;
/* Green! Put the chip in low-power mode. */
outb(0xC0, ioaddr + Cfg9346);
@@ -1356,7 +1372,7 @@
struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
long ioaddr = dev->base_addr;
- if (dev->start) {
+ if (test_bit(LINK_STATE_START, &dev->state)) {
tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
outl(0, ioaddr + RxMissed);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)