📄 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/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 <linux/bitops.h>#include <asm/uaccess.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 irqreturn_t 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);#ifdef CONFIG_NET_POLL_CONTROLLERstatic void xircom_poll_controller(struct net_device *dev);#endifstatic 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 transceiver_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[] = { {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 = xircom_remove, .suspend =NULL, .resume =NULL};#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 void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ struct xircom_private *private = netdev_priv(dev); strcpy(info->driver, "xircom_cb"); strcpy(info->bus_info, pci_name(private->pdev));}static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo,};/* 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. */ dev = alloc_etherdev(sizeof(struct xircom_private)); if (!dev) { printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n"); goto device_fail; } private = netdev_priv(dev); /* 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"); goto rx_buf_fail; } 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"); goto tx_buf_fail; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); private->dev = dev; private->pdev = pdev; private->io_port = pci_resource_start(pdev, 0); spin_lock_init(&private->lock); 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;#ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = &xircom_poll_controller;#endif SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); pci_set_drvdata(pdev, dev); if (register_netdev(dev)) { printk(KERN_ERR "xircom_probe: netdevice registration failed.\n"); goto reg_fail; } printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq); /* start the transmitter to get a heartbeat */ /* TODO: send 2 dummy packets here */ transceiver_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;reg_fail: kfree(private->tx_buffer);tx_buf_fail: kfree(private->rx_buffer);rx_buf_fail: free_netdev(dev);device_fail: return -ENODEV;}/* 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 = netdev_priv(dev); enter("xircom_remove"); pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle); pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle); release_region(dev->base_addr, 128); unregister_netdev(dev); free_netdev(dev); pci_set_drvdata(pdev, NULL); leave("xircom_remove");} static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_instance; struct xircom_private *card = netdev_priv(dev); unsigned int status; int i; enter("xircom_interrupt\n"); spin_lock(&card->lock); status = inl(card->io_port+CSR5);#ifdef 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 /* Handle shared irq and hotplug */ if (status == 0 || status == 0xffffffff) { spin_unlock(&card->lock); return IRQ_NONE; } 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"); return IRQ_HANDLED;}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 = netdev_priv(dev); 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 */ card->tx_buffer[4*desc+1] |= 0xF0000000; /* 0xF0... means want interrupts*/ card->tx_skb[desc] = skb; wmb(); /* This gives the descriptor to the card */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -