162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is (C) by the respective authors, and licensed under the GPL 562306a36Sopenharmony_ci * License. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Written by Arjan van de Ven for Red Hat, Inc. 862306a36Sopenharmony_ci * Based on work by Jeff Garzik, Doug Ledford and Donald Becker 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This software may be used and distributed according to the terms 1162306a36Sopenharmony_ci * of the GNU General Public License, incorporated herein by reference. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * $Id: xircom_cb.c,v 1.33 2001/03/19 14:02:07 arjanv Exp $ 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/string.h> 2262306a36Sopenharmony_ci#include <linux/errno.h> 2362306a36Sopenharmony_ci#include <linux/ioport.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/interrupt.h> 2662306a36Sopenharmony_ci#include <linux/pci.h> 2762306a36Sopenharmony_ci#include <linux/netdevice.h> 2862306a36Sopenharmony_ci#include <linux/etherdevice.h> 2962306a36Sopenharmony_ci#include <linux/skbuff.h> 3062306a36Sopenharmony_ci#include <linux/delay.h> 3162306a36Sopenharmony_ci#include <linux/bitops.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/uaccess.h> 3462306a36Sopenharmony_ci#include <asm/io.h> 3562306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 3662306a36Sopenharmony_ci#include <asm/irq.h> 3762306a36Sopenharmony_ci#endif 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciMODULE_DESCRIPTION("Xircom Cardbus ethernet driver"); 4062306a36Sopenharmony_ciMODULE_AUTHOR("Arjan van de Ven <arjanv@redhat.com>"); 4162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define xw32(reg, val) iowrite32(val, ioaddr + (reg)) 4462306a36Sopenharmony_ci#define xr32(reg) ioread32(ioaddr + (reg)) 4562306a36Sopenharmony_ci#define xr8(reg) ioread8(ioaddr + (reg)) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* IO registers on the card, offsets */ 4862306a36Sopenharmony_ci#define CSR0 0x00 4962306a36Sopenharmony_ci#define CSR1 0x08 5062306a36Sopenharmony_ci#define CSR2 0x10 5162306a36Sopenharmony_ci#define CSR3 0x18 5262306a36Sopenharmony_ci#define CSR4 0x20 5362306a36Sopenharmony_ci#define CSR5 0x28 5462306a36Sopenharmony_ci#define CSR6 0x30 5562306a36Sopenharmony_ci#define CSR7 0x38 5662306a36Sopenharmony_ci#define CSR8 0x40 5762306a36Sopenharmony_ci#define CSR9 0x48 5862306a36Sopenharmony_ci#define CSR10 0x50 5962306a36Sopenharmony_ci#define CSR11 0x58 6062306a36Sopenharmony_ci#define CSR12 0x60 6162306a36Sopenharmony_ci#define CSR13 0x68 6262306a36Sopenharmony_ci#define CSR14 0x70 6362306a36Sopenharmony_ci#define CSR15 0x78 6462306a36Sopenharmony_ci#define CSR16 0x80 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* PCI registers */ 6762306a36Sopenharmony_ci#define PCI_POWERMGMT 0x40 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* Offsets of the buffers within the descriptor pages, in bytes */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define NUMDESCRIPTORS 4 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistruct xircom_private { 7762306a36Sopenharmony_ci /* Send and receive buffers, kernel-addressable and dma addressable forms */ 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci __le32 *rx_buffer; 8062306a36Sopenharmony_ci __le32 *tx_buffer; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci dma_addr_t rx_dma_handle; 8362306a36Sopenharmony_ci dma_addr_t tx_dma_handle; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci struct sk_buff *tx_skb[4]; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci void __iomem *ioaddr; 8862306a36Sopenharmony_ci int open; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* transmit_used is the rotating counter that indicates which transmit 9162306a36Sopenharmony_ci descriptor has to be used next */ 9262306a36Sopenharmony_ci int transmit_used; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* Spinlock to serialize register operations. 9562306a36Sopenharmony_ci It must be helt while manipulating the following registers: 9662306a36Sopenharmony_ci CSR0, CSR6, CSR7, CSR9, CSR10, CSR15 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci spinlock_t lock; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci struct pci_dev *pdev; 10162306a36Sopenharmony_ci struct net_device *dev; 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* Function prototypes */ 10662306a36Sopenharmony_cistatic int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id); 10762306a36Sopenharmony_cistatic void xircom_remove(struct pci_dev *pdev); 10862306a36Sopenharmony_cistatic irqreturn_t xircom_interrupt(int irq, void *dev_instance); 10962306a36Sopenharmony_cistatic netdev_tx_t xircom_start_xmit(struct sk_buff *skb, 11062306a36Sopenharmony_ci struct net_device *dev); 11162306a36Sopenharmony_cistatic int xircom_open(struct net_device *dev); 11262306a36Sopenharmony_cistatic int xircom_close(struct net_device *dev); 11362306a36Sopenharmony_cistatic void xircom_up(struct xircom_private *card); 11462306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 11562306a36Sopenharmony_cistatic void xircom_poll_controller(struct net_device *dev); 11662306a36Sopenharmony_ci#endif 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset); 11962306a36Sopenharmony_cistatic void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset); 12062306a36Sopenharmony_cistatic void read_mac_address(struct xircom_private *card); 12162306a36Sopenharmony_cistatic void transceiver_voodoo(struct xircom_private *card); 12262306a36Sopenharmony_cistatic void initialize_card(struct xircom_private *card); 12362306a36Sopenharmony_cistatic void trigger_transmit(struct xircom_private *card); 12462306a36Sopenharmony_cistatic void trigger_receive(struct xircom_private *card); 12562306a36Sopenharmony_cistatic void setup_descriptors(struct xircom_private *card); 12662306a36Sopenharmony_cistatic void remove_descriptors(struct xircom_private *card); 12762306a36Sopenharmony_cistatic int link_status_changed(struct xircom_private *card); 12862306a36Sopenharmony_cistatic void activate_receiver(struct xircom_private *card); 12962306a36Sopenharmony_cistatic void deactivate_receiver(struct xircom_private *card); 13062306a36Sopenharmony_cistatic void activate_transmitter(struct xircom_private *card); 13162306a36Sopenharmony_cistatic void deactivate_transmitter(struct xircom_private *card); 13262306a36Sopenharmony_cistatic void enable_transmit_interrupt(struct xircom_private *card); 13362306a36Sopenharmony_cistatic void enable_receive_interrupt(struct xircom_private *card); 13462306a36Sopenharmony_cistatic void enable_link_interrupt(struct xircom_private *card); 13562306a36Sopenharmony_cistatic void disable_all_interrupts(struct xircom_private *card); 13662306a36Sopenharmony_cistatic int link_status(struct xircom_private *card); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic const struct pci_device_id xircom_pci_table[] = { 14162306a36Sopenharmony_ci { PCI_VDEVICE(XIRCOM, 0x0003), }, 14262306a36Sopenharmony_ci {0,}, 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, xircom_pci_table); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic struct pci_driver xircom_ops = { 14762306a36Sopenharmony_ci .name = "xircom_cb", 14862306a36Sopenharmony_ci .id_table = xircom_pci_table, 14962306a36Sopenharmony_ci .probe = xircom_probe, 15062306a36Sopenharmony_ci .remove = xircom_remove, 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#if defined DEBUG && DEBUG > 1 15562306a36Sopenharmony_cistatic void print_binary(unsigned int number) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci int i,i2; 15862306a36Sopenharmony_ci char buffer[64]; 15962306a36Sopenharmony_ci memset(buffer,0,64); 16062306a36Sopenharmony_ci i2=0; 16162306a36Sopenharmony_ci for (i=31;i>=0;i--) { 16262306a36Sopenharmony_ci if (number & (1<<i)) 16362306a36Sopenharmony_ci buffer[i2++]='1'; 16462306a36Sopenharmony_ci else 16562306a36Sopenharmony_ci buffer[i2++]='0'; 16662306a36Sopenharmony_ci if ((i&3)==0) 16762306a36Sopenharmony_ci buffer[i2++]=' '; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci pr_debug("%s\n",buffer); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci#endif 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic const struct net_device_ops netdev_ops = { 17462306a36Sopenharmony_ci .ndo_open = xircom_open, 17562306a36Sopenharmony_ci .ndo_stop = xircom_close, 17662306a36Sopenharmony_ci .ndo_start_xmit = xircom_start_xmit, 17762306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 17862306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 17962306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 18062306a36Sopenharmony_ci .ndo_poll_controller = xircom_poll_controller, 18162306a36Sopenharmony_ci#endif 18262306a36Sopenharmony_ci}; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* xircom_probe is the code that gets called on device insertion. 18562306a36Sopenharmony_ci it sets up the hardware and registers the device to the networklayer. 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci TODO: Send 1 or 2 "dummy" packets here as the card seems to discard the 18862306a36Sopenharmony_ci first two packets that get send, and pump hates that. 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_cistatic int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct device *d = &pdev->dev; 19462306a36Sopenharmony_ci struct net_device *dev = NULL; 19562306a36Sopenharmony_ci struct xircom_private *private; 19662306a36Sopenharmony_ci unsigned long flags; 19762306a36Sopenharmony_ci unsigned short tmp16; 19862306a36Sopenharmony_ci int rc; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* First do the PCI initialisation */ 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci rc = pci_enable_device(pdev); 20362306a36Sopenharmony_ci if (rc < 0) 20462306a36Sopenharmony_ci goto out; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* disable all powermanagement */ 20762306a36Sopenharmony_ci pci_write_config_dword(pdev, PCI_POWERMGMT, 0x0000); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci pci_set_master(pdev); /* Why isn't this done by pci_enable_device ?*/ 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* clear PCI status, if any */ 21262306a36Sopenharmony_ci pci_read_config_word (pdev,PCI_STATUS, &tmp16); 21362306a36Sopenharmony_ci pci_write_config_word (pdev, PCI_STATUS,tmp16); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci rc = pci_request_regions(pdev, "xircom_cb"); 21662306a36Sopenharmony_ci if (rc < 0) { 21762306a36Sopenharmony_ci pr_err("%s: failed to allocate io-region\n", __func__); 21862306a36Sopenharmony_ci goto err_disable; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci rc = -ENOMEM; 22262306a36Sopenharmony_ci /* 22362306a36Sopenharmony_ci Before changing the hardware, allocate the memory. 22462306a36Sopenharmony_ci This way, we can fail gracefully if not enough memory 22562306a36Sopenharmony_ci is available. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci dev = alloc_etherdev(sizeof(struct xircom_private)); 22862306a36Sopenharmony_ci if (!dev) 22962306a36Sopenharmony_ci goto err_release; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci private = netdev_priv(dev); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Allocate the send/receive buffers */ 23462306a36Sopenharmony_ci private->rx_buffer = dma_alloc_coherent(d, 8192, 23562306a36Sopenharmony_ci &private->rx_dma_handle, 23662306a36Sopenharmony_ci GFP_KERNEL); 23762306a36Sopenharmony_ci if (private->rx_buffer == NULL) 23862306a36Sopenharmony_ci goto rx_buf_fail; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci private->tx_buffer = dma_alloc_coherent(d, 8192, 24162306a36Sopenharmony_ci &private->tx_dma_handle, 24262306a36Sopenharmony_ci GFP_KERNEL); 24362306a36Sopenharmony_ci if (private->tx_buffer == NULL) 24462306a36Sopenharmony_ci goto tx_buf_fail; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci private->dev = dev; 25062306a36Sopenharmony_ci private->pdev = pdev; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* IO range. */ 25362306a36Sopenharmony_ci private->ioaddr = pci_iomap(pdev, 0, 0); 25462306a36Sopenharmony_ci if (!private->ioaddr) 25562306a36Sopenharmony_ci goto reg_fail; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci spin_lock_init(&private->lock); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci initialize_card(private); 26062306a36Sopenharmony_ci read_mac_address(private); 26162306a36Sopenharmony_ci setup_descriptors(private); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci dev->netdev_ops = &netdev_ops; 26462306a36Sopenharmony_ci pci_set_drvdata(pdev, dev); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci rc = register_netdev(dev); 26762306a36Sopenharmony_ci if (rc < 0) { 26862306a36Sopenharmony_ci pr_err("%s: netdevice registration failed\n", __func__); 26962306a36Sopenharmony_ci goto err_unmap; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci netdev_info(dev, "Xircom cardbus revision %i at irq %i\n", 27362306a36Sopenharmony_ci pdev->revision, pdev->irq); 27462306a36Sopenharmony_ci /* start the transmitter to get a heartbeat */ 27562306a36Sopenharmony_ci /* TODO: send 2 dummy packets here */ 27662306a36Sopenharmony_ci transceiver_voodoo(private); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci spin_lock_irqsave(&private->lock,flags); 27962306a36Sopenharmony_ci activate_transmitter(private); 28062306a36Sopenharmony_ci activate_receiver(private); 28162306a36Sopenharmony_ci spin_unlock_irqrestore(&private->lock,flags); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci trigger_receive(private); 28462306a36Sopenharmony_ciout: 28562306a36Sopenharmony_ci return rc; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cierr_unmap: 28862306a36Sopenharmony_ci pci_iounmap(pdev, private->ioaddr); 28962306a36Sopenharmony_cireg_fail: 29062306a36Sopenharmony_ci dma_free_coherent(d, 8192, private->tx_buffer, private->tx_dma_handle); 29162306a36Sopenharmony_citx_buf_fail: 29262306a36Sopenharmony_ci dma_free_coherent(d, 8192, private->rx_buffer, private->rx_dma_handle); 29362306a36Sopenharmony_cirx_buf_fail: 29462306a36Sopenharmony_ci free_netdev(dev); 29562306a36Sopenharmony_cierr_release: 29662306a36Sopenharmony_ci pci_release_regions(pdev); 29762306a36Sopenharmony_cierr_disable: 29862306a36Sopenharmony_ci pci_disable_device(pdev); 29962306a36Sopenharmony_ci goto out; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/* 30462306a36Sopenharmony_ci xircom_remove is called on module-unload or on device-eject. 30562306a36Sopenharmony_ci it unregisters the irq, io-region and network device. 30662306a36Sopenharmony_ci Interrupts and such are already stopped in the "ifconfig ethX down" 30762306a36Sopenharmony_ci code. 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_cistatic void xircom_remove(struct pci_dev *pdev) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 31262306a36Sopenharmony_ci struct xircom_private *card = netdev_priv(dev); 31362306a36Sopenharmony_ci struct device *d = &pdev->dev; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci unregister_netdev(dev); 31662306a36Sopenharmony_ci pci_iounmap(pdev, card->ioaddr); 31762306a36Sopenharmony_ci dma_free_coherent(d, 8192, card->tx_buffer, card->tx_dma_handle); 31862306a36Sopenharmony_ci dma_free_coherent(d, 8192, card->rx_buffer, card->rx_dma_handle); 31962306a36Sopenharmony_ci free_netdev(dev); 32062306a36Sopenharmony_ci pci_release_regions(pdev); 32162306a36Sopenharmony_ci pci_disable_device(pdev); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic irqreturn_t xircom_interrupt(int irq, void *dev_instance) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct net_device *dev = (struct net_device *) dev_instance; 32762306a36Sopenharmony_ci struct xircom_private *card = netdev_priv(dev); 32862306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 32962306a36Sopenharmony_ci unsigned int status; 33062306a36Sopenharmony_ci int i; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci spin_lock(&card->lock); 33362306a36Sopenharmony_ci status = xr32(CSR5); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci#if defined DEBUG && DEBUG > 1 33662306a36Sopenharmony_ci print_binary(status); 33762306a36Sopenharmony_ci pr_debug("tx status 0x%08x 0x%08x\n", 33862306a36Sopenharmony_ci card->tx_buffer[0], card->tx_buffer[4]); 33962306a36Sopenharmony_ci pr_debug("rx status 0x%08x 0x%08x\n", 34062306a36Sopenharmony_ci card->rx_buffer[0], card->rx_buffer[4]); 34162306a36Sopenharmony_ci#endif 34262306a36Sopenharmony_ci /* Handle shared irq and hotplug */ 34362306a36Sopenharmony_ci if (status == 0 || status == 0xffffffff) { 34462306a36Sopenharmony_ci spin_unlock(&card->lock); 34562306a36Sopenharmony_ci return IRQ_NONE; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (link_status_changed(card)) { 34962306a36Sopenharmony_ci int newlink; 35062306a36Sopenharmony_ci netdev_dbg(dev, "Link status has changed\n"); 35162306a36Sopenharmony_ci newlink = link_status(card); 35262306a36Sopenharmony_ci netdev_info(dev, "Link is %d mbit\n", newlink); 35362306a36Sopenharmony_ci if (newlink) 35462306a36Sopenharmony_ci netif_carrier_on(dev); 35562306a36Sopenharmony_ci else 35662306a36Sopenharmony_ci netif_carrier_off(dev); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* Clear all remaining interrupts */ 36162306a36Sopenharmony_ci status |= 0xffffffff; /* FIXME: make this clear only the 36262306a36Sopenharmony_ci real existing bits */ 36362306a36Sopenharmony_ci xw32(CSR5, status); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci for (i=0;i<NUMDESCRIPTORS;i++) 36762306a36Sopenharmony_ci investigate_write_descriptor(dev,card,i,bufferoffsets[i]); 36862306a36Sopenharmony_ci for (i=0;i<NUMDESCRIPTORS;i++) 36962306a36Sopenharmony_ci investigate_read_descriptor(dev,card,i,bufferoffsets[i]); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci spin_unlock(&card->lock); 37262306a36Sopenharmony_ci return IRQ_HANDLED; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic netdev_tx_t xircom_start_xmit(struct sk_buff *skb, 37662306a36Sopenharmony_ci struct net_device *dev) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct xircom_private *card; 37962306a36Sopenharmony_ci unsigned long flags; 38062306a36Sopenharmony_ci int nextdescriptor; 38162306a36Sopenharmony_ci int desc; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci card = netdev_priv(dev); 38462306a36Sopenharmony_ci spin_lock_irqsave(&card->lock,flags); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* First see if we can free some descriptors */ 38762306a36Sopenharmony_ci for (desc=0;desc<NUMDESCRIPTORS;desc++) 38862306a36Sopenharmony_ci investigate_write_descriptor(dev,card,desc,bufferoffsets[desc]); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci nextdescriptor = (card->transmit_used +1) % (NUMDESCRIPTORS); 39262306a36Sopenharmony_ci desc = card->transmit_used; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* only send the packet if the descriptor is free */ 39562306a36Sopenharmony_ci if (card->tx_buffer[4*desc]==0) { 39662306a36Sopenharmony_ci /* Copy the packet data; zero the memory first as the card 39762306a36Sopenharmony_ci sometimes sends more than you ask it to. */ 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci memset(&card->tx_buffer[bufferoffsets[desc]/4],0,1536); 40062306a36Sopenharmony_ci skb_copy_from_linear_data(skb, 40162306a36Sopenharmony_ci &(card->tx_buffer[bufferoffsets[desc] / 4]), 40262306a36Sopenharmony_ci skb->len); 40362306a36Sopenharmony_ci /* FIXME: The specification tells us that the length we send HAS to be a multiple of 40462306a36Sopenharmony_ci 4 bytes. */ 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci card->tx_buffer[4*desc+1] = cpu_to_le32(skb->len); 40762306a36Sopenharmony_ci if (desc == NUMDESCRIPTORS - 1) /* bit 25: last descriptor of the ring */ 40862306a36Sopenharmony_ci card->tx_buffer[4*desc+1] |= cpu_to_le32(1<<25); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci card->tx_buffer[4*desc+1] |= cpu_to_le32(0xF0000000); 41162306a36Sopenharmony_ci /* 0xF0... means want interrupts*/ 41262306a36Sopenharmony_ci card->tx_skb[desc] = skb; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci wmb(); 41562306a36Sopenharmony_ci /* This gives the descriptor to the card */ 41662306a36Sopenharmony_ci card->tx_buffer[4*desc] = cpu_to_le32(0x80000000); 41762306a36Sopenharmony_ci trigger_transmit(card); 41862306a36Sopenharmony_ci if (card->tx_buffer[nextdescriptor*4] & cpu_to_le32(0x8000000)) { 41962306a36Sopenharmony_ci /* next descriptor is occupied... */ 42062306a36Sopenharmony_ci netif_stop_queue(dev); 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci card->transmit_used = nextdescriptor; 42362306a36Sopenharmony_ci spin_unlock_irqrestore(&card->lock,flags); 42462306a36Sopenharmony_ci return NETDEV_TX_OK; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* Uh oh... no free descriptor... drop the packet */ 42862306a36Sopenharmony_ci netif_stop_queue(dev); 42962306a36Sopenharmony_ci spin_unlock_irqrestore(&card->lock,flags); 43062306a36Sopenharmony_ci trigger_transmit(card); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return NETDEV_TX_BUSY; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int xircom_open(struct net_device *dev) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct xircom_private *xp = netdev_priv(dev); 44162306a36Sopenharmony_ci const int irq = xp->pdev->irq; 44262306a36Sopenharmony_ci int retval; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci netdev_info(dev, "xircom cardbus adaptor found, using irq %i\n", irq); 44562306a36Sopenharmony_ci retval = request_irq(irq, xircom_interrupt, IRQF_SHARED, dev->name, dev); 44662306a36Sopenharmony_ci if (retval) 44762306a36Sopenharmony_ci return retval; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci xircom_up(xp); 45062306a36Sopenharmony_ci xp->open = 1; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic int xircom_close(struct net_device *dev) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct xircom_private *card; 45862306a36Sopenharmony_ci unsigned long flags; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci card = netdev_priv(dev); 46162306a36Sopenharmony_ci netif_stop_queue(dev); /* we don't want new packets */ 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci spin_lock_irqsave(&card->lock,flags); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci disable_all_interrupts(card); 46762306a36Sopenharmony_ci#if 0 46862306a36Sopenharmony_ci /* We can enable this again once we send dummy packets on ifconfig ethX up */ 46962306a36Sopenharmony_ci deactivate_receiver(card); 47062306a36Sopenharmony_ci deactivate_transmitter(card); 47162306a36Sopenharmony_ci#endif 47262306a36Sopenharmony_ci remove_descriptors(card); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci spin_unlock_irqrestore(&card->lock,flags); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci card->open = 0; 47762306a36Sopenharmony_ci free_irq(card->pdev->irq, dev); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 48562306a36Sopenharmony_cistatic void xircom_poll_controller(struct net_device *dev) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct xircom_private *xp = netdev_priv(dev); 48862306a36Sopenharmony_ci const int irq = xp->pdev->irq; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci disable_irq(irq); 49162306a36Sopenharmony_ci xircom_interrupt(irq, dev); 49262306a36Sopenharmony_ci enable_irq(irq); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci#endif 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic void initialize_card(struct xircom_private *card) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 50062306a36Sopenharmony_ci unsigned long flags; 50162306a36Sopenharmony_ci u32 val; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci spin_lock_irqsave(&card->lock, flags); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* First: reset the card */ 50662306a36Sopenharmony_ci val = xr32(CSR0); 50762306a36Sopenharmony_ci val |= 0x01; /* Software reset */ 50862306a36Sopenharmony_ci xw32(CSR0, val); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci udelay(100); /* give the card some time to reset */ 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci val = xr32(CSR0); 51362306a36Sopenharmony_ci val &= ~0x01; /* disable Software reset */ 51462306a36Sopenharmony_ci xw32(CSR0, val); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci val = 0; /* Value 0x00 is a safe and conservative value 51862306a36Sopenharmony_ci for the PCI configuration settings */ 51962306a36Sopenharmony_ci xw32(CSR0, val); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci disable_all_interrupts(card); 52362306a36Sopenharmony_ci deactivate_receiver(card); 52462306a36Sopenharmony_ci deactivate_transmitter(card); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci spin_unlock_irqrestore(&card->lock, flags); 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci/* 53062306a36Sopenharmony_citrigger_transmit causes the card to check for frames to be transmitted. 53162306a36Sopenharmony_ciThis is accomplished by writing to the CSR1 port. The documentation 53262306a36Sopenharmony_ciclaims that the act of writing is sufficient and that the value is 53362306a36Sopenharmony_ciignored; I chose zero. 53462306a36Sopenharmony_ci*/ 53562306a36Sopenharmony_cistatic void trigger_transmit(struct xircom_private *card) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci xw32(CSR1, 0); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/* 54362306a36Sopenharmony_citrigger_receive causes the card to check for empty frames in the 54462306a36Sopenharmony_cidescriptor list in which packets can be received. 54562306a36Sopenharmony_ciThis is accomplished by writing to the CSR2 port. The documentation 54662306a36Sopenharmony_ciclaims that the act of writing is sufficient and that the value is 54762306a36Sopenharmony_ciignored; I chose zero. 54862306a36Sopenharmony_ci*/ 54962306a36Sopenharmony_cistatic void trigger_receive(struct xircom_private *card) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci xw32(CSR2, 0); 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci/* 55762306a36Sopenharmony_cisetup_descriptors initializes the send and receive buffers to be valid 55862306a36Sopenharmony_cidescriptors and programs the addresses into the card. 55962306a36Sopenharmony_ci*/ 56062306a36Sopenharmony_cistatic void setup_descriptors(struct xircom_private *card) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 56362306a36Sopenharmony_ci u32 address; 56462306a36Sopenharmony_ci int i; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci BUG_ON(card->rx_buffer == NULL); 56762306a36Sopenharmony_ci BUG_ON(card->tx_buffer == NULL); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* Receive descriptors */ 57062306a36Sopenharmony_ci memset(card->rx_buffer, 0, 128); /* clear the descriptors */ 57162306a36Sopenharmony_ci for (i=0;i<NUMDESCRIPTORS;i++ ) { 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* Rx Descr0: It's empty, let the card own it, no errors -> 0x80000000 */ 57462306a36Sopenharmony_ci card->rx_buffer[i*4 + 0] = cpu_to_le32(0x80000000); 57562306a36Sopenharmony_ci /* Rx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */ 57662306a36Sopenharmony_ci card->rx_buffer[i*4 + 1] = cpu_to_le32(1536); 57762306a36Sopenharmony_ci if (i == NUMDESCRIPTORS - 1) /* bit 25 is "last descriptor" */ 57862306a36Sopenharmony_ci card->rx_buffer[i*4 + 1] |= cpu_to_le32(1 << 25); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* Rx Descr2: address of the buffer 58162306a36Sopenharmony_ci we store the buffer at the 2nd half of the page */ 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci address = card->rx_dma_handle; 58462306a36Sopenharmony_ci card->rx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]); 58562306a36Sopenharmony_ci /* Rx Desc3: address of 2nd buffer -> 0 */ 58662306a36Sopenharmony_ci card->rx_buffer[i*4 + 3] = 0; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci wmb(); 59062306a36Sopenharmony_ci /* Write the receive descriptor ring address to the card */ 59162306a36Sopenharmony_ci address = card->rx_dma_handle; 59262306a36Sopenharmony_ci xw32(CSR3, address); /* Receive descr list address */ 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* transmit descriptors */ 59662306a36Sopenharmony_ci memset(card->tx_buffer, 0, 128); /* clear the descriptors */ 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci for (i=0;i<NUMDESCRIPTORS;i++ ) { 59962306a36Sopenharmony_ci /* Tx Descr0: Empty, we own it, no errors -> 0x00000000 */ 60062306a36Sopenharmony_ci card->tx_buffer[i*4 + 0] = 0x00000000; 60162306a36Sopenharmony_ci /* Tx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */ 60262306a36Sopenharmony_ci card->tx_buffer[i*4 + 1] = cpu_to_le32(1536); 60362306a36Sopenharmony_ci if (i == NUMDESCRIPTORS - 1) /* bit 25 is "last descriptor" */ 60462306a36Sopenharmony_ci card->tx_buffer[i*4 + 1] |= cpu_to_le32(1 << 25); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci /* Tx Descr2: address of the buffer 60762306a36Sopenharmony_ci we store the buffer at the 2nd half of the page */ 60862306a36Sopenharmony_ci address = card->tx_dma_handle; 60962306a36Sopenharmony_ci card->tx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]); 61062306a36Sopenharmony_ci /* Tx Desc3: address of 2nd buffer -> 0 */ 61162306a36Sopenharmony_ci card->tx_buffer[i*4 + 3] = 0; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci wmb(); 61562306a36Sopenharmony_ci /* wite the transmit descriptor ring to the card */ 61662306a36Sopenharmony_ci address = card->tx_dma_handle; 61762306a36Sopenharmony_ci xw32(CSR4, address); /* xmit descr list address */ 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci/* 62162306a36Sopenharmony_ciremove_descriptors informs the card the descriptors are no longer 62262306a36Sopenharmony_civalid by setting the address in the card to 0x00. 62362306a36Sopenharmony_ci*/ 62462306a36Sopenharmony_cistatic void remove_descriptors(struct xircom_private *card) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 62762306a36Sopenharmony_ci unsigned int val; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci val = 0; 63062306a36Sopenharmony_ci xw32(CSR3, val); /* Receive descriptor address */ 63162306a36Sopenharmony_ci xw32(CSR4, val); /* Send descriptor address */ 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci/* 63562306a36Sopenharmony_cilink_status_changed returns 1 if the card has indicated that 63662306a36Sopenharmony_cithe link status has changed. The new link status has to be read from CSR12. 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ciThis function also clears the status-bit. 63962306a36Sopenharmony_ci*/ 64062306a36Sopenharmony_cistatic int link_status_changed(struct xircom_private *card) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 64362306a36Sopenharmony_ci unsigned int val; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci val = xr32(CSR5); /* Status register */ 64662306a36Sopenharmony_ci if (!(val & (1 << 27))) /* no change */ 64762306a36Sopenharmony_ci return 0; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* clear the event by writing a 1 to the bit in the 65062306a36Sopenharmony_ci status register. */ 65162306a36Sopenharmony_ci val = (1 << 27); 65262306a36Sopenharmony_ci xw32(CSR5, val); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci return 1; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci/* 65962306a36Sopenharmony_citransmit_active returns 1 if the transmitter on the card is 66062306a36Sopenharmony_ciin a non-stopped state. 66162306a36Sopenharmony_ci*/ 66262306a36Sopenharmony_cistatic int transmit_active(struct xircom_private *card) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (!(xr32(CSR5) & (7 << 20))) /* transmitter disabled */ 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci return 1; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci/* 67362306a36Sopenharmony_cireceive_active returns 1 if the receiver on the card is 67462306a36Sopenharmony_ciin a non-stopped state. 67562306a36Sopenharmony_ci*/ 67662306a36Sopenharmony_cistatic int receive_active(struct xircom_private *card) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (!(xr32(CSR5) & (7 << 17))) /* receiver disabled */ 68162306a36Sopenharmony_ci return 0; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return 1; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci/* 68762306a36Sopenharmony_ciactivate_receiver enables the receiver on the card. 68862306a36Sopenharmony_ciBefore being allowed to active the receiver, the receiver 68962306a36Sopenharmony_cimust be completely de-activated. To achieve this, 69062306a36Sopenharmony_cithis code actually disables the receiver first; then it waits for the 69162306a36Sopenharmony_cireceiver to become inactive, then it activates the receiver and then 69262306a36Sopenharmony_ciit waits for the receiver to be active. 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cimust be called with the lock held and interrupts disabled. 69562306a36Sopenharmony_ci*/ 69662306a36Sopenharmony_cistatic void activate_receiver(struct xircom_private *card) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 69962306a36Sopenharmony_ci unsigned int val; 70062306a36Sopenharmony_ci int counter; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci /* If the "active" bit is set and the receiver is already 70562306a36Sopenharmony_ci active, no need to do the expensive thing */ 70662306a36Sopenharmony_ci if ((val&2) && (receive_active(card))) 70762306a36Sopenharmony_ci return; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci val = val & ~2; /* disable the receiver */ 71162306a36Sopenharmony_ci xw32(CSR6, val); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci counter = 10; 71462306a36Sopenharmony_ci while (counter > 0) { 71562306a36Sopenharmony_ci if (!receive_active(card)) 71662306a36Sopenharmony_ci break; 71762306a36Sopenharmony_ci /* wait a while */ 71862306a36Sopenharmony_ci udelay(50); 71962306a36Sopenharmony_ci counter--; 72062306a36Sopenharmony_ci if (counter <= 0) 72162306a36Sopenharmony_ci netdev_err(card->dev, "Receiver failed to deactivate\n"); 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* enable the receiver */ 72562306a36Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 72662306a36Sopenharmony_ci val = val | 2; /* enable the receiver */ 72762306a36Sopenharmony_ci xw32(CSR6, val); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* now wait for the card to activate again */ 73062306a36Sopenharmony_ci counter = 10; 73162306a36Sopenharmony_ci while (counter > 0) { 73262306a36Sopenharmony_ci if (receive_active(card)) 73362306a36Sopenharmony_ci break; 73462306a36Sopenharmony_ci /* wait a while */ 73562306a36Sopenharmony_ci udelay(50); 73662306a36Sopenharmony_ci counter--; 73762306a36Sopenharmony_ci if (counter <= 0) 73862306a36Sopenharmony_ci netdev_err(card->dev, 73962306a36Sopenharmony_ci "Receiver failed to re-activate\n"); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci/* 74462306a36Sopenharmony_cideactivate_receiver disables the receiver on the card. 74562306a36Sopenharmony_ciTo achieve this this code disables the receiver first; 74662306a36Sopenharmony_cithen it waits for the receiver to become inactive. 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cimust be called with the lock held and interrupts disabled. 74962306a36Sopenharmony_ci*/ 75062306a36Sopenharmony_cistatic void deactivate_receiver(struct xircom_private *card) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 75362306a36Sopenharmony_ci unsigned int val; 75462306a36Sopenharmony_ci int counter; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 75762306a36Sopenharmony_ci val = val & ~2; /* disable the receiver */ 75862306a36Sopenharmony_ci xw32(CSR6, val); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci counter = 10; 76162306a36Sopenharmony_ci while (counter > 0) { 76262306a36Sopenharmony_ci if (!receive_active(card)) 76362306a36Sopenharmony_ci break; 76462306a36Sopenharmony_ci /* wait a while */ 76562306a36Sopenharmony_ci udelay(50); 76662306a36Sopenharmony_ci counter--; 76762306a36Sopenharmony_ci if (counter <= 0) 76862306a36Sopenharmony_ci netdev_err(card->dev, "Receiver failed to deactivate\n"); 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci/* 77462306a36Sopenharmony_ciactivate_transmitter enables the transmitter on the card. 77562306a36Sopenharmony_ciBefore being allowed to active the transmitter, the transmitter 77662306a36Sopenharmony_cimust be completely de-activated. To achieve this, 77762306a36Sopenharmony_cithis code actually disables the transmitter first; then it waits for the 77862306a36Sopenharmony_citransmitter to become inactive, then it activates the transmitter and then 77962306a36Sopenharmony_ciit waits for the transmitter to be active again. 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cimust be called with the lock held and interrupts disabled. 78262306a36Sopenharmony_ci*/ 78362306a36Sopenharmony_cistatic void activate_transmitter(struct xircom_private *card) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 78662306a36Sopenharmony_ci unsigned int val; 78762306a36Sopenharmony_ci int counter; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci /* If the "active" bit is set and the receiver is already 79262306a36Sopenharmony_ci active, no need to do the expensive thing */ 79362306a36Sopenharmony_ci if ((val&(1<<13)) && (transmit_active(card))) 79462306a36Sopenharmony_ci return; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci val = val & ~(1 << 13); /* disable the transmitter */ 79762306a36Sopenharmony_ci xw32(CSR6, val); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci counter = 10; 80062306a36Sopenharmony_ci while (counter > 0) { 80162306a36Sopenharmony_ci if (!transmit_active(card)) 80262306a36Sopenharmony_ci break; 80362306a36Sopenharmony_ci /* wait a while */ 80462306a36Sopenharmony_ci udelay(50); 80562306a36Sopenharmony_ci counter--; 80662306a36Sopenharmony_ci if (counter <= 0) 80762306a36Sopenharmony_ci netdev_err(card->dev, 80862306a36Sopenharmony_ci "Transmitter failed to deactivate\n"); 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* enable the transmitter */ 81262306a36Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 81362306a36Sopenharmony_ci val = val | (1 << 13); /* enable the transmitter */ 81462306a36Sopenharmony_ci xw32(CSR6, val); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* now wait for the card to activate again */ 81762306a36Sopenharmony_ci counter = 10; 81862306a36Sopenharmony_ci while (counter > 0) { 81962306a36Sopenharmony_ci if (transmit_active(card)) 82062306a36Sopenharmony_ci break; 82162306a36Sopenharmony_ci /* wait a while */ 82262306a36Sopenharmony_ci udelay(50); 82362306a36Sopenharmony_ci counter--; 82462306a36Sopenharmony_ci if (counter <= 0) 82562306a36Sopenharmony_ci netdev_err(card->dev, 82662306a36Sopenharmony_ci "Transmitter failed to re-activate\n"); 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci/* 83162306a36Sopenharmony_cideactivate_transmitter disables the transmitter on the card. 83262306a36Sopenharmony_ciTo achieve this this code disables the transmitter first; 83362306a36Sopenharmony_cithen it waits for the transmitter to become inactive. 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_cimust be called with the lock held and interrupts disabled. 83662306a36Sopenharmony_ci*/ 83762306a36Sopenharmony_cistatic void deactivate_transmitter(struct xircom_private *card) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 84062306a36Sopenharmony_ci unsigned int val; 84162306a36Sopenharmony_ci int counter; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 84462306a36Sopenharmony_ci val = val & ~2; /* disable the transmitter */ 84562306a36Sopenharmony_ci xw32(CSR6, val); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci counter = 20; 84862306a36Sopenharmony_ci while (counter > 0) { 84962306a36Sopenharmony_ci if (!transmit_active(card)) 85062306a36Sopenharmony_ci break; 85162306a36Sopenharmony_ci /* wait a while */ 85262306a36Sopenharmony_ci udelay(50); 85362306a36Sopenharmony_ci counter--; 85462306a36Sopenharmony_ci if (counter <= 0) 85562306a36Sopenharmony_ci netdev_err(card->dev, 85662306a36Sopenharmony_ci "Transmitter failed to deactivate\n"); 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci/* 86262306a36Sopenharmony_cienable_transmit_interrupt enables the transmit interrupt 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cimust be called with the lock held and interrupts disabled. 86562306a36Sopenharmony_ci*/ 86662306a36Sopenharmony_cistatic void enable_transmit_interrupt(struct xircom_private *card) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 86962306a36Sopenharmony_ci unsigned int val; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci val = xr32(CSR7); /* Interrupt enable register */ 87262306a36Sopenharmony_ci val |= 1; /* enable the transmit interrupt */ 87362306a36Sopenharmony_ci xw32(CSR7, val); 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci/* 87862306a36Sopenharmony_cienable_receive_interrupt enables the receive interrupt 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cimust be called with the lock held and interrupts disabled. 88162306a36Sopenharmony_ci*/ 88262306a36Sopenharmony_cistatic void enable_receive_interrupt(struct xircom_private *card) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 88562306a36Sopenharmony_ci unsigned int val; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci val = xr32(CSR7); /* Interrupt enable register */ 88862306a36Sopenharmony_ci val = val | (1 << 6); /* enable the receive interrupt */ 88962306a36Sopenharmony_ci xw32(CSR7, val); 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci/* 89362306a36Sopenharmony_cienable_link_interrupt enables the link status change interrupt 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cimust be called with the lock held and interrupts disabled. 89662306a36Sopenharmony_ci*/ 89762306a36Sopenharmony_cistatic void enable_link_interrupt(struct xircom_private *card) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 90062306a36Sopenharmony_ci unsigned int val; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci val = xr32(CSR7); /* Interrupt enable register */ 90362306a36Sopenharmony_ci val = val | (1 << 27); /* enable the link status chage interrupt */ 90462306a36Sopenharmony_ci xw32(CSR7, val); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci/* 91062306a36Sopenharmony_cidisable_all_interrupts disables all interrupts 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_cimust be called with the lock held and interrupts disabled. 91362306a36Sopenharmony_ci*/ 91462306a36Sopenharmony_cistatic void disable_all_interrupts(struct xircom_private *card) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci xw32(CSR7, 0); 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci/* 92262306a36Sopenharmony_cienable_common_interrupts enables several weird interrupts 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cimust be called with the lock held and interrupts disabled. 92562306a36Sopenharmony_ci*/ 92662306a36Sopenharmony_cistatic void enable_common_interrupts(struct xircom_private *card) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 92962306a36Sopenharmony_ci unsigned int val; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci val = xr32(CSR7); /* Interrupt enable register */ 93262306a36Sopenharmony_ci val |= (1<<16); /* Normal Interrupt Summary */ 93362306a36Sopenharmony_ci val |= (1<<15); /* Abnormal Interrupt Summary */ 93462306a36Sopenharmony_ci val |= (1<<13); /* Fatal bus error */ 93562306a36Sopenharmony_ci val |= (1<<8); /* Receive Process Stopped */ 93662306a36Sopenharmony_ci val |= (1<<7); /* Receive Buffer Unavailable */ 93762306a36Sopenharmony_ci val |= (1<<5); /* Transmit Underflow */ 93862306a36Sopenharmony_ci val |= (1<<2); /* Transmit Buffer Unavailable */ 93962306a36Sopenharmony_ci val |= (1<<1); /* Transmit Process Stopped */ 94062306a36Sopenharmony_ci xw32(CSR7, val); 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci/* 94462306a36Sopenharmony_cienable_promisc starts promisc mode 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_cimust be called with the lock held and interrupts disabled. 94762306a36Sopenharmony_ci*/ 94862306a36Sopenharmony_cistatic int enable_promisc(struct xircom_private *card) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 95162306a36Sopenharmony_ci unsigned int val; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci val = xr32(CSR6); 95462306a36Sopenharmony_ci val = val | (1 << 6); 95562306a36Sopenharmony_ci xw32(CSR6, val); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci return 1; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci/* 96462306a36Sopenharmony_cilink_status() checks the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what. 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ciMust be called in locked state with interrupts disabled 96762306a36Sopenharmony_ci*/ 96862306a36Sopenharmony_cistatic int link_status(struct xircom_private *card) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 97162306a36Sopenharmony_ci u8 val; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci val = xr8(CSR12); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci /* bit 2 is 0 for 10mbit link, 1 for not an 10mbit link */ 97662306a36Sopenharmony_ci if (!(val & (1 << 2))) 97762306a36Sopenharmony_ci return 10; 97862306a36Sopenharmony_ci /* bit 1 is 0 for 100mbit link, 1 for not an 100mbit link */ 97962306a36Sopenharmony_ci if (!(val & (1 << 1))) 98062306a36Sopenharmony_ci return 100; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* If we get here -> no link at all */ 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci return 0; 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci/* 99262306a36Sopenharmony_ci read_mac_address() reads the MAC address from the NIC and stores it in the "dev" structure. 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci This function will take the spinlock itself and can, as a result, not be called with the lock helt. 99562306a36Sopenharmony_ci */ 99662306a36Sopenharmony_cistatic void read_mac_address(struct xircom_private *card) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 99962306a36Sopenharmony_ci unsigned long flags; 100062306a36Sopenharmony_ci u8 link; 100162306a36Sopenharmony_ci int i; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci spin_lock_irqsave(&card->lock, flags); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci xw32(CSR9, 1 << 12); /* enable boot rom access */ 100662306a36Sopenharmony_ci for (i = 0x100; i < 0x1f7; i += link + 2) { 100762306a36Sopenharmony_ci u8 tuple, data_id, data_count; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci xw32(CSR10, i); 101062306a36Sopenharmony_ci tuple = xr32(CSR9); 101162306a36Sopenharmony_ci xw32(CSR10, i + 1); 101262306a36Sopenharmony_ci link = xr32(CSR9); 101362306a36Sopenharmony_ci xw32(CSR10, i + 2); 101462306a36Sopenharmony_ci data_id = xr32(CSR9); 101562306a36Sopenharmony_ci xw32(CSR10, i + 3); 101662306a36Sopenharmony_ci data_count = xr32(CSR9); 101762306a36Sopenharmony_ci if ((tuple == 0x22) && (data_id == 0x04) && (data_count == 0x06)) { 101862306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 101962306a36Sopenharmony_ci int j; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci for (j = 0; j < 6; j++) { 102262306a36Sopenharmony_ci xw32(CSR10, i + j + 4); 102362306a36Sopenharmony_ci addr[j] = xr32(CSR9) & 0xff; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci eth_hw_addr_set(card->dev, addr); 102662306a36Sopenharmony_ci break; 102762306a36Sopenharmony_ci } else if (link == 0) { 102862306a36Sopenharmony_ci break; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci spin_unlock_irqrestore(&card->lock, flags); 103262306a36Sopenharmony_ci pr_debug(" %pM\n", card->dev->dev_addr); 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci/* 103762306a36Sopenharmony_ci transceiver_voodoo() enables the external UTP plug thingy. 103862306a36Sopenharmony_ci it's called voodoo as I stole this code and cannot cross-reference 103962306a36Sopenharmony_ci it with the specification. 104062306a36Sopenharmony_ci */ 104162306a36Sopenharmony_cistatic void transceiver_voodoo(struct xircom_private *card) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 104462306a36Sopenharmony_ci unsigned long flags; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* disable all powermanagement */ 104762306a36Sopenharmony_ci pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci setup_descriptors(card); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci spin_lock_irqsave(&card->lock, flags); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci xw32(CSR15, 0x0008); 105462306a36Sopenharmony_ci udelay(25); 105562306a36Sopenharmony_ci xw32(CSR15, 0xa8050000); 105662306a36Sopenharmony_ci udelay(25); 105762306a36Sopenharmony_ci xw32(CSR15, 0xa00f0000); 105862306a36Sopenharmony_ci udelay(25); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci spin_unlock_irqrestore(&card->lock, flags); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci netif_start_queue(card->dev); 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic void xircom_up(struct xircom_private *card) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci unsigned long flags; 106962306a36Sopenharmony_ci int i; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci /* disable all powermanagement */ 107262306a36Sopenharmony_ci pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci setup_descriptors(card); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci spin_lock_irqsave(&card->lock, flags); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci enable_link_interrupt(card); 108062306a36Sopenharmony_ci enable_transmit_interrupt(card); 108162306a36Sopenharmony_ci enable_receive_interrupt(card); 108262306a36Sopenharmony_ci enable_common_interrupts(card); 108362306a36Sopenharmony_ci enable_promisc(card); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* The card can have received packets already, read them away now */ 108662306a36Sopenharmony_ci for (i=0;i<NUMDESCRIPTORS;i++) 108762306a36Sopenharmony_ci investigate_read_descriptor(card->dev,card,i,bufferoffsets[i]); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci spin_unlock_irqrestore(&card->lock, flags); 109162306a36Sopenharmony_ci trigger_receive(card); 109262306a36Sopenharmony_ci trigger_transmit(card); 109362306a36Sopenharmony_ci netif_start_queue(card->dev); 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci/* Bufferoffset is in BYTES */ 109762306a36Sopenharmony_cistatic void 109862306a36Sopenharmony_ciinvestigate_read_descriptor(struct net_device *dev, struct xircom_private *card, 109962306a36Sopenharmony_ci int descnr, unsigned int bufferoffset) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci int status; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci status = le32_to_cpu(card->rx_buffer[4*descnr]); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (status > 0) { /* packet received */ 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci /* TODO: discard error packets */ 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci short pkt_len = ((status >> 16) & 0x7ff) - 4; 111062306a36Sopenharmony_ci /* minus 4, we don't want the CRC */ 111162306a36Sopenharmony_ci struct sk_buff *skb; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci if (pkt_len > 1518) { 111462306a36Sopenharmony_ci netdev_err(dev, "Packet length %i is bogus\n", pkt_len); 111562306a36Sopenharmony_ci pkt_len = 1518; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci skb = netdev_alloc_skb(dev, pkt_len + 2); 111962306a36Sopenharmony_ci if (skb == NULL) { 112062306a36Sopenharmony_ci dev->stats.rx_dropped++; 112162306a36Sopenharmony_ci goto out; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci skb_reserve(skb, 2); 112462306a36Sopenharmony_ci skb_copy_to_linear_data(skb, 112562306a36Sopenharmony_ci &card->rx_buffer[bufferoffset / 4], 112662306a36Sopenharmony_ci pkt_len); 112762306a36Sopenharmony_ci skb_put(skb, pkt_len); 112862306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 112962306a36Sopenharmony_ci netif_rx(skb); 113062306a36Sopenharmony_ci dev->stats.rx_packets++; 113162306a36Sopenharmony_ci dev->stats.rx_bytes += pkt_len; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ciout: 113462306a36Sopenharmony_ci /* give the buffer back to the card */ 113562306a36Sopenharmony_ci card->rx_buffer[4*descnr] = cpu_to_le32(0x80000000); 113662306a36Sopenharmony_ci trigger_receive(card); 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci/* Bufferoffset is in BYTES */ 114262306a36Sopenharmony_cistatic void 114362306a36Sopenharmony_ciinvestigate_write_descriptor(struct net_device *dev, 114462306a36Sopenharmony_ci struct xircom_private *card, 114562306a36Sopenharmony_ci int descnr, unsigned int bufferoffset) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci int status; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci status = le32_to_cpu(card->tx_buffer[4*descnr]); 115062306a36Sopenharmony_ci#if 0 115162306a36Sopenharmony_ci if (status & 0x8000) { /* Major error */ 115262306a36Sopenharmony_ci pr_err("Major transmit error status %x\n", status); 115362306a36Sopenharmony_ci card->tx_buffer[4*descnr] = 0; 115462306a36Sopenharmony_ci netif_wake_queue (dev); 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci#endif 115762306a36Sopenharmony_ci if (status > 0) { /* bit 31 is 0 when done */ 115862306a36Sopenharmony_ci if (card->tx_skb[descnr]!=NULL) { 115962306a36Sopenharmony_ci dev->stats.tx_bytes += card->tx_skb[descnr]->len; 116062306a36Sopenharmony_ci dev_kfree_skb_irq(card->tx_skb[descnr]); 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci card->tx_skb[descnr] = NULL; 116362306a36Sopenharmony_ci /* Bit 8 in the status field is 1 if there was a collision */ 116462306a36Sopenharmony_ci if (status & (1 << 8)) 116562306a36Sopenharmony_ci dev->stats.collisions++; 116662306a36Sopenharmony_ci card->tx_buffer[4*descnr] = 0; /* descriptor is free again */ 116762306a36Sopenharmony_ci netif_wake_queue (dev); 116862306a36Sopenharmony_ci dev->stats.tx_packets++; 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cimodule_pci_driver(xircom_ops); 1173