📄 xircom_cb.c
字号:
/* * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards * * This software is (C) by the respective authors, and licensed under the GPL * License. * * Written by Arjan van de Ven for Red Hat, Inc. * Based on work by Jeff Garzik, Doug Ledford and Donald Becker * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * * $Id: xircom_cb.c,v 1.33 2001/03/19 14:02:07 arjanv Exp $ */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/ethtool.h>#include <asm/uaccess.h>#include <asm/bitops.h>#include <asm/io.h>#ifdef DEBUG#define enter(x) printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__)#define leave(x) printk("Leave: %s, %s line %i\n",x,__FILE__,__LINE__)#else#define enter(x) do {} while (0)#define leave(x) do {} while (0)#endifMODULE_DESCRIPTION("Xircom Cardbus ethernet driver");MODULE_AUTHOR("Arjan van de Ven <arjanv@redhat.com>");MODULE_LICENSE("GPL");/* IO registers on the card, offsets */#define CSR0 0x00#define CSR1 0x08#define CSR2 0x10#define CSR3 0x18#define CSR4 0x20#define CSR5 0x28#define CSR6 0x30#define CSR7 0x38#define CSR8 0x40#define CSR9 0x48#define CSR10 0x50#define CSR11 0x58#define CSR12 0x60#define CSR13 0x68#define CSR14 0x70#define CSR15 0x78#define CSR16 0x80/* PCI registers */#define PCI_POWERMGMT 0x40/* Offsets of the buffers within the descriptor pages, in bytes */#define NUMDESCRIPTORS 4static int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144};struct xircom_private { /* Send and receive buffers, kernel-addressable and dma addressable forms */ unsigned int *rx_buffer; unsigned int *tx_buffer; dma_addr_t rx_dma_handle; dma_addr_t tx_dma_handle; struct sk_buff *tx_skb[4]; unsigned long io_port; int open; /* transmit_used is the rotating counter that indicates which transmit descriptor has to be used next */ int transmit_used; /* Spinlock to serialize register operations. It must be helt while manipulating the following registers: CSR0, CSR6, CSR7, CSR9, CSR10, CSR15 */ spinlock_t lock; struct pci_dev *pdev; struct net_device *dev; struct net_device_stats stats;};/* Function prototypes */static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id);static void xircom_remove(struct pci_dev *pdev);static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev);static int xircom_open(struct net_device *dev);static int xircom_close(struct net_device *dev);static void xircom_up(struct xircom_private *card);static struct net_device_stats *xircom_get_stats(struct net_device *dev);static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset);static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset);static void read_mac_address(struct xircom_private *card);static void tranceiver_voodoo(struct xircom_private *card);static void initialize_card(struct xircom_private *card);static void trigger_transmit(struct xircom_private *card);static void trigger_receive(struct xircom_private *card);static void setup_descriptors(struct xircom_private *card);static void remove_descriptors(struct xircom_private *card);static int link_status_changed(struct xircom_private *card);static void activate_receiver(struct xircom_private *card);static void deactivate_receiver(struct xircom_private *card);static void activate_transmitter(struct xircom_private *card);static void deactivate_transmitter(struct xircom_private *card);static void enable_transmit_interrupt(struct xircom_private *card);static void enable_receive_interrupt(struct xircom_private *card);static void enable_link_interrupt(struct xircom_private *card);static void disable_all_interrupts(struct xircom_private *card);static int link_status(struct xircom_private *card);static struct pci_device_id xircom_pci_table[] __devinitdata = { {0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID,}, {0,},};MODULE_DEVICE_TABLE(pci, xircom_pci_table);static struct pci_driver xircom_ops = { name: "xircom_cb", id_table: xircom_pci_table, probe: xircom_probe, remove: __devexit_p(xircom_remove),};#ifdef DEBUGstatic void print_binary(unsigned int number){ int i,i2; char buffer[64]; memset(buffer,0,64); i2=0; for (i=31;i>=0;i--) { if (number & (1<<i)) buffer[i2++]='1'; else buffer[i2++]='0'; if ((i&3)==0) buffer[i2++]=' '; } printk("%s\n",buffer);}#endifstatic int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr){ u32 ethcmd; if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) return -EFAULT; switch (ethcmd) { case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; strncpy(info.driver, "xircom_cb", sizeof(info.driver)-1); if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; return 0; } } return -EOPNOTSUPP;}static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); default: return -EOPNOTSUPP; }}/* xircom_probe is the code that gets called on device insertion. it sets up the hardware and registers the device to the networklayer. TODO: Send 1 or 2 "dummy" packets here as the card seems to discard the first two packets that get send, and pump hates that. */static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id){ struct net_device *dev = NULL; struct xircom_private *private; unsigned char chip_rev; unsigned long flags; unsigned short tmp16; enter("xircom_probe"); /* First do the PCI initialisation */ if (pci_enable_device(pdev)) return -ENODEV; /* disable all powermanagement */ pci_write_config_dword(pdev, PCI_POWERMGMT, 0x0000); pci_set_master(pdev); /* Why isn't this done by pci_enable_device ?*/ /* clear PCI status, if any */ pci_read_config_word (pdev,PCI_STATUS, &tmp16); pci_write_config_word (pdev, PCI_STATUS,tmp16); pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev); if (!request_region(pci_resource_start(pdev, 0), 128, "xircom_cb")) { printk(KERN_ERR "xircom_probe: failed to allocate io-region\n"); return -ENODEV; } /* Before changing the hardware, allocate the memory. This way, we can fail gracefully if not enough memory is available. */ private = kmalloc(sizeof(*private),GFP_KERNEL); memset(private, 0, sizeof(struct xircom_private)); /* Allocate the send/receive buffers */ private->rx_buffer = pci_alloc_consistent(pdev,8192,&private->rx_dma_handle); if (private->rx_buffer == NULL) { printk(KERN_ERR "xircom_probe: no memory for rx buffer \n"); kfree(private); return -ENODEV; } private->tx_buffer = pci_alloc_consistent(pdev,8192,&private->tx_dma_handle); if (private->tx_buffer == NULL) { printk(KERN_ERR "xircom_probe: no memory for tx buffer \n"); kfree(private->rx_buffer); kfree(private); return -ENODEV; } dev = init_etherdev(dev, 0); if (dev == NULL) { printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n"); kfree(private->rx_buffer); kfree(private->tx_buffer); kfree(private); return -ENODEV; } SET_MODULE_OWNER(dev); printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq); private->dev = dev; private->pdev = pdev; private->io_port = pci_resource_start(pdev, 0); private->lock = SPIN_LOCK_UNLOCKED; dev->irq = pdev->irq; dev->base_addr = private->io_port; initialize_card(private); read_mac_address(private); setup_descriptors(private); dev->open = &xircom_open; dev->hard_start_xmit = &xircom_start_xmit; dev->stop = &xircom_close; dev->get_stats = &xircom_get_stats; dev->priv = private; dev->do_ioctl = &private_ioctl; pci_set_drvdata(pdev, dev); /* start the transmitter to get a heartbeat */ /* TODO: send 2 dummy packets here */ tranceiver_voodoo(private); spin_lock_irqsave(&private->lock,flags); activate_transmitter(private); activate_receiver(private); spin_unlock_irqrestore(&private->lock,flags); trigger_receive(private); leave("xircom_probe"); return 0;}/* xircom_remove is called on module-unload or on device-eject. it unregisters the irq, io-region and network device. Interrupts and such are already stopped in the "ifconfig ethX down" code. */static void __devexit xircom_remove(struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *card; enter("xircom_remove"); if (dev!=NULL) { card=dev->priv; if (card!=NULL) { if (card->rx_buffer!=NULL) pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle); card->rx_buffer = NULL; if (card->tx_buffer!=NULL) pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle); card->tx_buffer = NULL; } kfree(card); } release_region(dev->base_addr, 128); unregister_netdev(dev); kfree(dev); leave("xircom_remove");} static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_instance; struct xircom_private *card = (struct xircom_private *) dev->priv; unsigned int status; int i; enter("xircom_interrupt\n"); spin_lock(&card->lock); status = inl(card->io_port+CSR5);#if DEBUG print_binary(status); printk("tx status 0x%08x 0x%08x \n",card->tx_buffer[0],card->tx_buffer[4]); printk("rx status 0x%08x 0x%08x \n",card->rx_buffer[0],card->rx_buffer[4]);#endif if (link_status_changed(card)) { int newlink; printk(KERN_DEBUG "xircom_cb: Link status has changed \n"); newlink = link_status(card); printk(KERN_INFO "xircom_cb: Link is %i mbit \n",newlink); if (newlink) netif_carrier_on(dev); else netif_carrier_off(dev); } /* Clear all remaining interrupts */ status |= 0xffffffff; /* FIXME: make this clear only the real existing bits */ outl(status,card->io_port+CSR5); for (i=0;i<NUMDESCRIPTORS;i++) investigate_write_descriptor(dev,card,i,bufferoffsets[i]); for (i=0;i<NUMDESCRIPTORS;i++) investigate_read_descriptor(dev,card,i,bufferoffsets[i]); spin_unlock(&card->lock); leave("xircom_interrupt");}static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct xircom_private *card; unsigned long flags; int nextdescriptor; int desc; enter("xircom_start_xmit"); card = (struct xircom_private*)dev->priv; spin_lock_irqsave(&card->lock,flags); /* First see if we can free some descriptors */ for (desc=0;desc<NUMDESCRIPTORS;desc++) investigate_write_descriptor(dev,card,desc,bufferoffsets[desc]); nextdescriptor = (card->transmit_used +1) % (NUMDESCRIPTORS); desc = card->transmit_used; /* only send the packet if the descriptor is free */ if (card->tx_buffer[4*desc]==0) { /* Copy the packet data; zero the memory first as the card sometimes sends more than you ask it to. */ memset(&card->tx_buffer[bufferoffsets[desc]/4],0,1536); memcpy(&(card->tx_buffer[bufferoffsets[desc]/4]),skb->data,skb->len); /* FIXME: The specification tells us that the length we send HAS to be a multiple of 4 bytes. */ card->tx_buffer[4*desc+1] = skb->len; if (desc == NUMDESCRIPTORS-1) card->tx_buffer[4*desc+1] |= (1<<25); /* bit 25: last descriptor of the ring */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -