📄 xircom_cb.c
字号:
/* * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards * * This software is Copyright 2001 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, Donald Becker and Ion Badulescu * * 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.11 2001/06/05 09:50:57 fenrus Exp $ */#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/delay.h>#include <asm/io.h>#ifdef DEBUG#define enter() printk("Enter: %s, %s line %i\n",__FUNCTION__,__FILE__,__LINE__)#define leave() printk("Leave: %s, %s line %i\n",__FUNCTION__,__FILE__,__LINE__)#else#define enter() do {} while (0)#define leave() 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 4#define RXTXBUFSIZE 8192#define MAX_PACKETSIZE 1536#define DescOwnedCard 0x80000000#define DescOwnedDriver 0x00000000#define PromiscBit (1<<6)#define CollisionBit (1<<8)#define TxActiveBit (1<<13)#define RxActiveBit (1<<1)#define LastDescBit (1<<25)#define LinkStatusBit (1<<27)#define PowerMgmtBits ( (1<<31)|(1<<30) )static const unsigned int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144};/* note: this struct is assumed to be packed as this is the "hardware" layout */struct descriptor { u32 status; u32 control; u32 address1; u32 address2;};struct xircom_private { /* Send and receive buffers, kernel-addressable and dma addressable forms */ unsigned char *rx_buffer; unsigned char *tx_buffer; struct descriptor *rx_desc; struct descriptor *tx_desc; dma_addr_t rx_dma_handle; dma_addr_t tx_dma_handle; struct sk_buff *tx_skb[NUMDESCRIPTORS]; unsigned long io_port; /* transmit_used is the rotating counter that indicates which transmit descriptor has to be used next */ unsigned 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_rx_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset);static unsigned int investigate_tx_descriptor(struct net_device *dev, struct xircom_private *card, unsigned 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 inline void trigger_transmit(struct xircom_private *card);static inline void trigger_receive(struct xircom_private *card);static void setup_descriptors(struct xircom_private *card);static inline void remove_descriptors(struct xircom_private *card);static inline unsigned 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 inline unsigned int link_status(struct xircom_private *card);static int mdio_read(struct xircom_private *card, int phy_id, int location);static void mdio_write(struct xircom_private *card, int phy_id, int location, int value);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);}#endif/* 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; u8 chip_rev; unsigned long flags; u32 tmp32; u16 tmp16; int ret; enter(); /* First do the PCI initialisation */ ret = pci_enable_device(pdev); if (ret) return ret; /* disable all powermanagement */ pci_read_config_dword(pdev, PCI_POWERMGMT,&tmp32); tmp32 &= ~PowerMgmtBits; pci_write_config_dword(pdev, PCI_POWERMGMT, tmp32); pci_set_master(pdev); /* 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; } dev = init_etherdev(dev, sizeof(*private)); if (dev == NULL) { printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n"); return -ENODEV; } SET_MODULE_OWNER(dev); private = dev->priv; if (private==NULL) { printk(KERN_ERR "xircom_probe: failed to allocate private device struct\n"); return -ENODEV; } /* Allocate the send/receive buffers */ private->rx_buffer = pci_alloc_consistent(pdev,RXTXBUFSIZE,&private->rx_dma_handle); if (private->rx_buffer == NULL) { printk(KERN_ERR "xircom_probe: no memory for rx buffer \n"); kfree(private); return -ENODEV; } /* the descriptors are stored in the first bytes of the rx_buffer, hence the ugly cast */ private->rx_desc = (struct descriptor *)private->rx_buffer; private->tx_buffer = pci_alloc_consistent(pdev,RXTXBUFSIZE,&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; } /* the descriptors are stored in the first bytes of the tx_buffer, hence the ugly cast */ private->tx_desc = (struct descriptor *)private->tx_buffer; 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; pci_set_drvdata(pdev,dev); /* start the transmitter to get a heartbeat; don't do that when there already is one though; Cisco's really don't like that. */ if (!link_status(private)) tranceiver_voodoo(private); spin_lock_irqsave(&private->lock,flags); activate_transmitter(private); activate_receiver(private); spin_unlock_irqrestore(&private->lock,flags); /* TODO: send 2 dummy packets here */ trigger_receive(private); leave(); 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(); card=dev->priv; if (card->rx_buffer!=NULL) pci_free_consistent(pdev,RXTXBUFSIZE,card->rx_buffer,card->rx_dma_handle); card->rx_buffer = NULL; card->rx_desc = NULL; if (card->tx_buffer!=NULL) pci_free_consistent(pdev,RXTXBUFSIZE,card->tx_buffer,card->tx_dma_handle); card->tx_buffer = NULL; card->tx_desc = NULL; release_region(dev->base_addr, 128); unregister_netdev(dev); kfree(dev); pci_set_drvdata(pdev,NULL); leave();} static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs){ struct net_device *dev = dev_instance; struct xircom_private *card = dev->priv; u32 status; unsigned int xmit_free_count; unsigned int i; enter(); spin_lock(&card->lock); status = inl(card->io_port+CSR5); if (status==0xffffffff) {/* card has been ejected / powered down */ spin_unlock(&card->lock); return; } /* Todo: check if there were any events at all; to speed up returning if we're on a shared interrupt */ if (link_status_changed(card)) { int newlink; printk(KERN_DEBUG "xircom_cb: Link status has changed \n"); newlink = link_status(card); if (newlink) { printk(KERN_INFO "xircom_cb: Link is %i mbit \n",newlink); netif_carrier_on(dev); } else { printk(KERN_INFO "xircom_cb: Link is absent \n"); netif_carrier_off(dev); } } /* Clear all remaining interrupt events */ status |= 0xffffffff; /* FIXME: make this clear only the real existing bits */ outl(status,card->io_port+CSR5); xmit_free_count = 0; for (i=0;i<NUMDESCRIPTORS;i++) xmit_free_count += investigate_tx_descriptor(dev,card,i,bufferoffsets[i]); for (i=0;i<NUMDESCRIPTORS;i++) investigate_rx_descriptor(dev,card,i,bufferoffsets[i]); if (xmit_free_count) netif_start_queue(dev); spin_unlock(&card->lock); leave();}static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct xircom_private *card; unsigned long flags; unsigned int nextdescriptor; unsigned int desc; enter(); card = (struct xircom_private*)dev->priv; spin_lock_irqsave(&card->lock,flags); nextdescriptor = (card->transmit_used +1) % (NUMDESCRIPTORS); desc = card->transmit_used; /* only send the packet if the descriptor is free */ if (card->tx_desc[desc].status==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]],0,MAX_PACKETSIZE); memcpy(&(card->tx_buffer[bufferoffsets[desc]]),skb->data,skb->len); /* FIXME: The specification tells us that the length we send HAS to be a multiple of 4 bytes. */ card->tx_desc[desc].control = skb->len; if (desc == NUMDESCRIPTORS-1) card->tx_desc[desc].control |= LastDescBit; /* bit 25: last descriptor of the ring */ card->tx_desc[desc].control |= 0xF0000000; /* 0xF0... means want interrupts*/ card->tx_skb[desc] = skb; wmb(); /* This gives the descriptor to the card */ card->tx_desc[desc].status = DescOwnedCard; trigger_transmit(card); if (((int)card->tx_desc[nextdescriptor].status)<0) { /* next descriptor is occupied... */ netif_stop_queue(dev); } card->transmit_used = nextdescriptor; spin_unlock_irqrestore(&card->lock,flags); leave(); return 0; } /* Uh oh... no free descriptor... drop the packet */ /* This should not happen in theory...*/ netif_stop_queue(dev); spin_unlock_irqrestore(&card->lock,flags); trigger_transmit(card); leave(); return -EIO;}static int xircom_open(struct net_device *dev){ struct xircom_private *xp = (struct xircom_private *) dev->priv; int retval; enter(); printk(KERN_INFO "Xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq); retval = request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev); if (retval) { printk(KERN_ERR "xircom_cb: Unable to aquire IRQ %i, aborting.\n",dev->irq); leave(); return retval;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -