patch-2.4.0-test12 linux/drivers/net/ioc3-eth.c
Next file: linux/drivers/net/irda/irtty.c
Previous file: linux/drivers/net/ibmlana.c
Back to the patch index
Back to the overall index
- Lines: 343
- Date:
Tue Nov 28 21:42:04 2000
- Orig file:
v2.4.0-test11/linux/drivers/net/ioc3-eth.c
- Orig date:
Sun Oct 8 10:50:19 2000
diff -u --recursive --new-file v2.4.0-test11/linux/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c
@@ -69,7 +69,7 @@
#include <asm/pci/bridge.h>
/* 32 RX buffers. This is tunable in the range of 16 <= x < 512. */
-#define RX_BUFFS 32
+#define RX_BUFFS 64
/* Private ioctls that de facto are well known and used for examply
by mii-tool. */
@@ -96,6 +96,7 @@
int tx_pi; /* TX producer index */
int txqlen;
u32 emcr, ehar_h, ehar_l;
+ struct timer_list negtimer;
spinlock_t ioc3_lock;
};
@@ -104,7 +105,7 @@
static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void ioc3_timeout(struct net_device *dev);
static inline unsigned int ioc3_hash(const unsigned char *addr);
-static void ioc3_stop(struct net_device *dev);
+static inline void ioc3_stop(struct net_device *dev);
static void ioc3_init(struct net_device *dev);
static const char ioc3_str[] = "IOC3 Ethernet";
@@ -381,17 +382,20 @@
ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG;
while (ioc3->micr & MICR_BUSY);
- return ioc3->midr & MIDR_DATA_MASK;
+ return ioc3->midr_r & MIDR_DATA_MASK;
}
static void mii_write(struct ioc3 *ioc3, int phy, int reg, u16 data)
{
while (ioc3->micr & MICR_BUSY);
- ioc3->midr = data;
+ ioc3->midr_w = data;
ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg;
while (ioc3->micr & MICR_BUSY);
}
+static int ioc3_mii_init(struct net_device *dev, struct ioc3_private *ip,
+ struct ioc3 *ioc3);
+
static struct net_device_stats *ioc3_get_stats(struct net_device *dev)
{
struct ioc3_private *ip = (struct ioc3_private *) dev->priv;
@@ -426,6 +430,8 @@
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
+ ip->rx_skbs[rx_entry] = NULL; /* Poison */
+
new_skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
if (!new_skb) {
/* Ouch, drop packet and just recycle packet
@@ -545,6 +551,7 @@
ioc3_stop(dev);
ioc3_init(dev);
+ ioc3_mii_init(dev, ip, ioc3);
dev->trans_start = jiffies;
netif_wake_queue(dev);
@@ -563,6 +570,7 @@
u32 eisr;
eisr = ioc3->eisr & enabled;
+
while (eisr) {
ioc3->eisr = eisr;
ioc3->eisr; /* Flush */
@@ -579,46 +587,43 @@
}
}
-/* One day this will do the autonegotiation. */
-int ioc3_mii_init(struct net_device *dev, struct ioc3_private *ip,
- struct ioc3 *ioc3)
+static void negotiate(unsigned long data)
{
- u16 word, mii0, mii_status, mii2, mii3, mii4;
- u32 vendor, model, rev;
+ struct net_device *dev = (struct net_device *) data;
+ struct ioc3_private *ip = (struct ioc3_private *) dev->priv;
+ struct ioc3 *ioc3 = ip->regs;
+
+ mod_timer(&ip->negtimer, jiffies + 20 * HZ);
+}
+
+static int ioc3_mii_init(struct net_device *dev, struct ioc3_private *ip,
+ struct ioc3 *ioc3)
+{
+ u16 word, mii0;
int i, phy;
spin_lock_irq(&ip->ioc3_lock);
phy = -1;
for (i = 0; i < 32; i++) {
word = mii_read(ioc3, i, 2);
- if ((word != 0xffff) & (word != 0x0000)) {
+ if ((word != 0xffff) && (word != 0x0000)) {
phy = i;
break; /* Found a PHY */
}
}
if (phy == -1) {
spin_unlock_irq(&ip->ioc3_lock);
- printk("Didn't find a PHY, goodbye.\n");
return -ENODEV;
}
ip->phy = phy;
- mii0 = mii_read(ioc3, phy, 0);
- mii_status = mii_read(ioc3, phy, 1);
- mii2 = mii_read(ioc3, phy, 2);
- mii3 = mii_read(ioc3, phy, 3);
- mii4 = mii_read(ioc3, phy, 4);
- vendor = (mii2 << 12) | (mii3 >> 4);
- model = (mii3 >> 4) & 0x3f;
- rev = mii3 & 0xf;
- printk("Ok, using PHY %d, vendor 0x%x, model %d, rev %d.\n",
- phy, vendor, model, rev);
- printk(KERN_INFO "%s: MII transceiver found at MDIO address "
- "%d, config %4.4x status %4.4x.\n",
- dev->name, phy, mii0, mii_status);
-
/* Autonegotiate 100mbit and fullduplex. */
- mii_write(ioc3, phy, 0, mii0 | 0x3100);
+ mii0 = mii_read(ioc3, ip->phy, 0);
+ mii_write(ioc3, ip->phy, 0, mii0 | 0x3100);
+
+ ip->negtimer.function = &negotiate;
+ ip->negtimer.data = (unsigned long) dev;
+ mod_timer(&ip->negtimer, jiffies); /* Run it now */
spin_unlock_irq(&ip->ioc3_lock);
@@ -670,22 +675,26 @@
struct sk_buff *skb;
int rx_entry, n_entry;
- ioc3_clean_tx_ring(ip);
- ip->txr = NULL;
- free_pages((unsigned long)ip->txr, 2);
-
- n_entry = ip->rx_ci;
- rx_entry = ip->rx_pi;
+ if (ip->txr) {
+ ioc3_clean_tx_ring(ip);
+ free_pages((unsigned long)ip->txr, 2);
+ ip->txr = NULL;
+ }
+
+ if (ip->rxr) {
+ n_entry = ip->rx_ci;
+ rx_entry = ip->rx_pi;
+
+ while (n_entry != rx_entry) {
+ skb = ip->rx_skbs[n_entry];
+ if (skb)
+ dev_kfree_skb_any(skb);
- while (n_entry != rx_entry) {
- skb = ip->rx_skbs[n_entry];
- if (skb)
- dev_kfree_skb_any(skb);
-
- n_entry = (n_entry + 1) & 511;
+ n_entry = (n_entry + 1) & 511;
+ }
+ free_page((unsigned long)ip->rxr);
+ ip->rxr = NULL;
}
- free_page((unsigned long)ip->rxr);
- ip->rxr = NULL;
}
static void
@@ -698,7 +707,7 @@
if (ip->rxr == NULL) {
/* Allocate and initialize rx ring. 4kb = 512 entries */
- ip->rxr = (unsigned long *) get_free_page(GFP_KERNEL);
+ ip->rxr = (unsigned long *) get_free_page(GFP_KERNEL|GFP_ATOMIC);
rxr = (unsigned long *) ip->rxr;
/* Now the rx buffers. The RX ring may be larger but
@@ -707,7 +716,7 @@
for (i = 0; i < RX_BUFFS; i++) {
struct sk_buff *skb;
- skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, 0);
+ skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
if (!skb) {
show_free_areas();
continue;
@@ -729,7 +738,7 @@
if (ip->txr == NULL) {
/* Allocate and initialize tx rings. 16kb = 128 bufs. */
- ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2);
+ ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL|GFP_ATOMIC, 2);
ip->tx_pi = 0;
ip->tx_ci = 0;
}
@@ -741,6 +750,7 @@
{
unsigned long ring;
+ ioc3_free_rings(ip);
ioc3_alloc_rings(dev, ip, ioc3);
ioc3_clean_rx_ring(ip);
@@ -824,7 +834,7 @@
ioc3->eier;
}
-static void ioc3_stop(struct net_device *dev)
+static inline void ioc3_stop(struct net_device *dev)
{
struct ioc3_private *ip = dev->priv;
struct ioc3 *ioc3 = ip->regs;
@@ -863,6 +873,7 @@
{
struct ioc3_private *ip = dev->priv;
+ del_timer(&ip->negtimer);
netif_stop_queue(dev);
ioc3_stop(dev); /* Flush */
@@ -875,14 +886,23 @@
return 0;
}
-static void ioc3_pci_init(struct pci_dev *pdev)
+static int ioc3_pci_init(struct pci_dev *pdev)
{
+ u16 mii0, mii_status, mii2, mii3, mii4;
struct net_device *dev = NULL; // XXX
struct ioc3_private *ip;
struct ioc3 *ioc3;
unsigned long ioc3_base, ioc3_size;
+ u32 vendor, model, rev;
+ int phy;
+
+ dev = init_etherdev(0, sizeof(struct ioc3_private));
+
+ if (!dev)
+ return -ENOMEM;
- dev = init_etherdev(dev, 0);
+ ip = dev->priv;
+ memset(ip, 0, sizeof(*ip));
/*
* This probably needs to be register_netdevice, or call
@@ -891,9 +911,6 @@
*/
netif_device_attach(dev);
- ip = (struct ioc3_private *) kmalloc(sizeof(*ip), GFP_KERNEL);
- memset(ip, 0, sizeof(*ip));
- dev->priv = ip;
dev->irq = pdev->irq;
ioc3_base = pdev->resource[0].start;
@@ -906,12 +923,38 @@
ioc3_stop(dev);
ip->emcr = 0;
ioc3_init(dev);
+
+ init_timer(&ip->negtimer);
ioc3_mii_init(dev, ip, ioc3);
+ phy = ip->phy;
+ if (phy == -1) {
+ printk(KERN_CRIT"%s: Didn't find a PHY, goodbye.\n", dev->name);
+ ioc3_stop(dev);
+ free_irq(dev->irq, dev);
+ ioc3_free_rings(ip);
+
+ return -ENODEV;
+ }
+
+ mii0 = mii_read(ioc3, phy, 0);
+ mii_status = mii_read(ioc3, phy, 1);
+ mii2 = mii_read(ioc3, phy, 2);
+ mii3 = mii_read(ioc3, phy, 3);
+ mii4 = mii_read(ioc3, phy, 4);
+ vendor = (mii2 << 12) | (mii3 >> 4);
+ model = (mii3 >> 4) & 0x3f;
+ rev = mii3 & 0xf;
+ printk(KERN_INFO"Using PHY %d, vendor 0x%x, model %d, rev %d.\n",
+ phy, vendor, model, rev);
+ printk(KERN_INFO "%s: MII transceiver found at MDIO address "
+ "%d, config %4.4x status %4.4x.\n",
+ dev->name, phy, mii0, mii_status);
+
ioc3_ssram_disc(ip);
printk("IOC3 SSRAM has %d kbyte.\n", ip->emcr & EMCR_BUFSIZ ? 128 : 64);
- ioc3_get_eaddr(dev, ioc3);
+ ioc3_get_eaddr(dev, ioc3);
/* The IOC3-specific entries in the device structure. */
dev->open = ioc3_open;
@@ -922,6 +965,8 @@
dev->get_stats = ioc3_get_stats;
dev->do_ioctl = ioc3_ioctl;
dev->set_multicast_list = ioc3_set_multicast_list;
+
+ return 0;
}
static int __init ioc3_probe(void)
@@ -938,7 +983,8 @@
while ((pdev = pci_find_device(PCI_VENDOR_ID_SGI,
PCI_DEVICE_ID_SGI_IOC3, pdev))) {
- ioc3_pci_init(pdev);
+ if (ioc3_pci_init(pdev))
+ return -ENOMEM;
cards++;
}
}
@@ -1018,10 +1064,14 @@
static void ioc3_timeout(struct net_device *dev)
{
+ struct ioc3_private *ip = dev->priv;
+ struct ioc3 *ioc3 = ip->regs;
+
printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
ioc3_stop(dev);
ioc3_init(dev);
+ ioc3_mii_init(dev, ip, ioc3);
dev->trans_start = jiffies;
netif_wake_queue(dev);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)