patch-2.3.99-pre2 linux/drivers/net/sis900.c
Next file: linux/drivers/net/sunhme.c
Previous file: linux/drivers/net/shaper.c
Back to the patch index
Back to the overall index
- Lines: 334
- Date:
Thu Mar 16 11:19:25 2000
- Orig file:
v2.3.99-pre1/linux/drivers/net/sis900.c
- Orig date:
Tue Mar 14 19:10:39 2000
diff -u --recursive --new-file v2.3.99-pre1/linux/drivers/net/sis900.c linux/drivers/net/sis900.c
@@ -52,34 +52,36 @@
#include "sis900.h"
static const char *version =
-"sis900.c: v1.06.04 02/11/2000\n";
+"sis900.c: v1.07 03/07/2000\n";
static int max_interrupt_work = 20;
+static int multicast_filter_limit = 128;
+
#define sis900_debug debug
static int sis900_debug = 0;
-static int multicast_filter_limit = 128;
-
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (4*HZ)
+/* SiS 900 is capable of 32 bits BM DMA */
+#define SIS900_DMA_MASK 0xffffffff
-struct mac_chip_info {
- const char *name;
- u16 vendor_id, device_id, flags;
- int io_size;
- struct net_device *(*probe) (struct mac_chip_info *mac, struct pci_dev * pci_dev,
- struct net_device * net_dev);
+static struct net_device * sis900_mac_probe (struct pci_dev * pci_dev,
+ char *card_name);
+enum {
+ SIS_900 = 0,
+ SIS_7018
};
-static struct net_device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev,
- struct net_device * net_dev);
-
-static struct mac_chip_info mac_chip_table[] = {
- { "SiS 900 PCI Fast Ethernet", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900,
- PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe},
- { "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016,
- PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe},
- {0,}, /* 0 terminated list. */
+static char * card_names[] = {
+ "SiS 900 PCI Fast Ethernet",
+ "SiS 7016 PCI Fast Ethernet"
+};
+static struct pci_device_id sis900_pci_tbl [] __initdata = {
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_900},
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7018}
};
+MODULE_DEVICE_TABLE (pci, sis900_pci_tbl);
static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex);
static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex);
@@ -111,24 +113,22 @@
} BufferDesc;
struct sis900_private {
- struct net_device *next_module;
struct net_device_stats stats;
struct pci_dev * pci_dev;
spinlock_t lock;
- struct mac_chip_info * mac;
struct mii_phy * mii;
unsigned int cur_phy;
struct timer_list timer; /* Link status detection timer. */
- unsigned int cur_rx, dirty_rx;
+ unsigned int cur_rx, dirty_rx;
unsigned int cur_tx, dirty_tx;
/* The saved address of a sent/receive-in-place packet buffer */
struct sk_buff *tx_skbuff[NUM_TX_DESC];
struct sk_buff *rx_skbuff[NUM_RX_DESC];
- BufferDesc tx_ring[NUM_TX_DESC];
+ BufferDesc tx_ring[NUM_TX_DESC];
BufferDesc rx_ring[NUM_RX_DESC];
unsigned int tx_full; /* The Tx queue is full. */
@@ -163,68 +163,47 @@
static void set_rx_mode(struct net_device *net_dev);
static void sis900_reset(struct net_device *net_dev);
-/* A list of all installed SiS900 devices, for removing the driver module. */
-static struct net_device *root_sis900_dev = NULL;
-
/* walk through every ethernet PCI devices to see if some of them are matched with our card list*/
-static int __init sis900_probe (void)
+static int __init sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
{
- int found = 0;
- struct pci_dev * pci_dev = NULL;
-
- while ((pci_dev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_dev)) != NULL) {
- /* pci_dev contains all ethernet devices */
- u32 pci_io_base;
- struct mac_chip_info * mac;
- struct net_device *net_dev = NULL;
-
- for (mac = mac_chip_table; mac->vendor_id; mac++) {
- /* try to match our card list */
- if (pci_dev->vendor == mac->vendor_id &&
- pci_dev->device == mac->device_id)
- break;
- }
-
- if (mac->vendor_id == 0)
- /* pci_dev does not match any of our cards */
- continue;
-
- /* now, pci_dev should be either 900 or 7016 */
- pci_io_base = pci_dev->resource[0].start;
- if ((mac->flags & PCI_COMMAND_IO ) &&
- check_region(pci_io_base, mac->io_size))
- continue;
-
- /* setup various bits in PCI command register */
- pci_enable_device (pci_dev);
- pci_set_master(pci_dev);
+ u32 pci_io_base;
- /* do the real low level jobs */
- net_dev = mac->probe(mac, pci_dev, net_dev);
-
- if (net_dev != NULL) {
- found++;
- }
- net_dev = NULL;
+ if (!pci_dma_supported(pci_dev, SIS900_DMA_MASK)) {
+ printk(KERN_ERR "sis900.c: architecture does not support "
+ "32bit PCI busmaster DMA\n");
+ return -ENODEV;
+ }
+
+ pci_io_base = pci_dev->resource[0].start;
+ if (check_region(pci_io_base, SIS900_TOTAL_SIZE)) {
+ printk(KERN_ERR "sis900.c: can't allocate I/O space at 0x%08x\n",
+ pci_io_base);
+ return -ENODEV;
}
- return found ? 0 : -ENODEV;
+
+ /* setup various bits in PCI command register */
+ pci_enable_device (pci_dev);
+ pci_set_master(pci_dev);
+
+ /* do the real low level jobs */
+ if (sis900_mac_probe(pci_dev, card_names[pci_id->driver_data]) == NULL)
+ return -1;
+
+ return 0;
}
-static struct net_device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev,
- struct net_device * net_dev)
+static struct net_device * __init sis900_mac_probe (struct pci_dev * pci_dev, char * card_name)
{
struct sis900_private *sis_priv;
long ioaddr = pci_dev->resource[0].start;
+ struct net_device *net_dev = NULL;
int irq = pci_dev->irq;
- static int did_version = 0;
u16 signature;
int i;
- if (did_version++ == 0)
- printk(KERN_INFO "%s", version);
-
if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
return NULL;
+
/* check to see if we have sane EEPROM */
signature = (u16) read_eeprom(ioaddr, EEPROMSignature);
if (signature == 0xffff || signature == 0x0000) {
@@ -233,8 +212,8 @@
return NULL;
}
- printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name,
- ioaddr, irq);
+ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name,
+ card_name, ioaddr, irq);
/* get MAC address from EEPROM */
for (i = 0; i < 3; i++)
@@ -252,23 +231,22 @@
memset(sis_priv, 0, sizeof(struct sis900_private));
/* We do a request_region() to register /proc/ioports info. */
- request_region(ioaddr, mac->io_size, net_dev->name);
+ request_region(ioaddr, SIS900_TOTAL_SIZE, net_dev->name);
net_dev->base_addr = ioaddr;
net_dev->irq = irq;
sis_priv->pci_dev = pci_dev;
- sis_priv->mac = mac;
spin_lock_init(&sis_priv->lock);
/* probe for mii transciver */
if (sis900_mii_probe(net_dev) == 0) {
unregister_netdev(net_dev);
kfree(sis_priv);
- release_region(ioaddr, mac->io_size);
+ release_region(ioaddr, SIS900_TOTAL_SIZE);
return NULL;
}
- sis_priv->next_module = root_sis900_dev;
- root_sis900_dev = net_dev;
+ pci_dev->driver_data = net_dev;
+ pci_dev->dma_mask = SIS900_DMA_MASK;
/* The SiS900-specific entries in the device structure. */
net_dev->open = &sis900_open;
@@ -283,7 +261,7 @@
return net_dev;
}
-static int sis900_mii_probe (struct net_device * net_dev)
+static int __init sis900_mii_probe (struct net_device * net_dev)
{
struct sis900_private * sis_priv = (struct sis900_private *)net_dev->priv;
int phy_addr;
@@ -966,21 +944,42 @@
net_dev->name);
break;
}
+
+ /* gvie the socket buffer to upper layers */
skb = sis_priv->rx_skbuff[entry];
- sis_priv->rx_skbuff[entry] = NULL;
- /* reset buffer descriptor state */
- sis_priv->rx_ring[entry].cmdsts = 0;
- sis_priv->rx_ring[entry].bufptr = 0;
-
skb_put(skb, rx_size);
skb->protocol = eth_type_trans(skb, net_dev);
netif_rx(skb);
-
+
+ /* some network statistics */
if ((rx_status & BCAST) == MCAST)
sis_priv->stats.multicast++;
net_dev->last_rx = jiffies;
sis_priv->stats.rx_bytes += rx_size;
sis_priv->stats.rx_packets++;
+
+ /* refill the Rx buffer, what if there is not enought memory for
+ new socket buffer ?? */
+ if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
+ /* not enough memory for skbuff, this makes a "hole"
+ on the buffer ring, it is not clear how the
+ hardware will react to this kind of degenerated
+ buffer */
+ printk(KERN_INFO "%s: Memory squeeze,"
+ "deferring packet.\n",
+ net_dev->name);
+ sis_priv->rx_skbuff[entry] = NULL;
+ /* reset buffer descriptor state */
+ sis_priv->rx_ring[entry].cmdsts = 0;
+ sis_priv->rx_ring[entry].bufptr = 0;
+ sis_priv->stats.rx_dropped++;
+ break;
+ }
+ skb->dev = net_dev;
+ sis_priv->rx_skbuff[entry] = skb;
+ sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
+ sis_priv->rx_ring[entry].bufptr = virt_to_bus(skb->tail);
+ sis_priv->dirty_rx++;
}
sis_priv->cur_rx++;
entry = sis_priv->cur_rx % NUM_RX_DESC;
@@ -1249,23 +1248,46 @@
outl(PESEL, ioaddr + cfg);
}
-static void __exit sis900_cleanup_module(void)
+static void __exit sis900_remove(struct pci_dev *pci_dev)
{
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_sis900_dev) {
- struct sis900_private *sis_priv =
- (struct sis900_private *)root_sis900_dev->priv;
- struct net_device *next_dev = sis_priv->next_module;
+ struct net_device *net_dev = pci_dev->driver_data;
+ struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
- unregister_netdev(root_sis900_dev);
- release_region(root_sis900_dev->base_addr,
- sis_priv->mac->io_size);
- kfree(sis_priv);
- kfree(root_sis900_dev);
+ unregister_netdev(net_dev);
+ release_region(net_dev->base_addr,
+ SIS900_TOTAL_SIZE);
+
+ kfree(sis_priv);
+ kfree(net_dev);
+}
- root_sis900_dev = next_dev;
+#define SIS900_MODULE_NAME "sis900"
+
+static struct pci_driver sis900_pci_driver = {
+ name: SIS900_MODULE_NAME,
+ id_table: sis900_pci_tbl,
+ probe: sis900_probe,
+ remove: sis900_remove,
+};
+
+static int __init sis900_init_module(void)
+{
+ if (!pci_present()) /* No PCI bus in this machine! */
+ return -ENODEV;
+
+ printk(KERN_INFO "%s", version);
+
+ if (!pci_register_driver(&sis900_pci_driver)) {
+ pci_unregister_driver(&sis900_pci_driver);
+ return -ENODEV;
}
+ return 0;
+}
+
+static void __exit sis900_cleanup_module(void)
+{
+ pci_unregister_driver(&sis900_pci_driver);
}
-module_init(sis900_probe);
+module_init(sis900_init_module);
module_exit(sis900_cleanup_module);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)