18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is (C) by the respective authors, and licensed under the GPL 58c2ecf20Sopenharmony_ci * License. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Written by Arjan van de Ven for Red Hat, Inc. 88c2ecf20Sopenharmony_ci * Based on work by Jeff Garzik, Doug Ledford and Donald Becker 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This software may be used and distributed according to the terms 118c2ecf20Sopenharmony_ci * of the GNU General Public License, incorporated herein by reference. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * $Id: xircom_cb.c,v 1.33 2001/03/19 14:02:07 arjanv Exp $ 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/string.h> 228c2ecf20Sopenharmony_ci#include <linux/errno.h> 238c2ecf20Sopenharmony_ci#include <linux/ioport.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 268c2ecf20Sopenharmony_ci#include <linux/pci.h> 278c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 288c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 298c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 308c2ecf20Sopenharmony_ci#include <linux/delay.h> 318c2ecf20Sopenharmony_ci#include <linux/bitops.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 348c2ecf20Sopenharmony_ci#include <asm/io.h> 358c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 368c2ecf20Sopenharmony_ci#include <asm/irq.h> 378c2ecf20Sopenharmony_ci#endif 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Xircom Cardbus ethernet driver"); 408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Arjan van de Ven <arjanv@redhat.com>"); 418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define xw32(reg, val) iowrite32(val, ioaddr + (reg)) 448c2ecf20Sopenharmony_ci#define xr32(reg) ioread32(ioaddr + (reg)) 458c2ecf20Sopenharmony_ci#define xr8(reg) ioread8(ioaddr + (reg)) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* IO registers on the card, offsets */ 488c2ecf20Sopenharmony_ci#define CSR0 0x00 498c2ecf20Sopenharmony_ci#define CSR1 0x08 508c2ecf20Sopenharmony_ci#define CSR2 0x10 518c2ecf20Sopenharmony_ci#define CSR3 0x18 528c2ecf20Sopenharmony_ci#define CSR4 0x20 538c2ecf20Sopenharmony_ci#define CSR5 0x28 548c2ecf20Sopenharmony_ci#define CSR6 0x30 558c2ecf20Sopenharmony_ci#define CSR7 0x38 568c2ecf20Sopenharmony_ci#define CSR8 0x40 578c2ecf20Sopenharmony_ci#define CSR9 0x48 588c2ecf20Sopenharmony_ci#define CSR10 0x50 598c2ecf20Sopenharmony_ci#define CSR11 0x58 608c2ecf20Sopenharmony_ci#define CSR12 0x60 618c2ecf20Sopenharmony_ci#define CSR13 0x68 628c2ecf20Sopenharmony_ci#define CSR14 0x70 638c2ecf20Sopenharmony_ci#define CSR15 0x78 648c2ecf20Sopenharmony_ci#define CSR16 0x80 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* PCI registers */ 678c2ecf20Sopenharmony_ci#define PCI_POWERMGMT 0x40 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* Offsets of the buffers within the descriptor pages, in bytes */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define NUMDESCRIPTORS 4 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistruct xircom_private { 778c2ecf20Sopenharmony_ci /* Send and receive buffers, kernel-addressable and dma addressable forms */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci __le32 *rx_buffer; 808c2ecf20Sopenharmony_ci __le32 *tx_buffer; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci dma_addr_t rx_dma_handle; 838c2ecf20Sopenharmony_ci dma_addr_t tx_dma_handle; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci struct sk_buff *tx_skb[4]; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci void __iomem *ioaddr; 888c2ecf20Sopenharmony_ci int open; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* transmit_used is the rotating counter that indicates which transmit 918c2ecf20Sopenharmony_ci descriptor has to be used next */ 928c2ecf20Sopenharmony_ci int transmit_used; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* Spinlock to serialize register operations. 958c2ecf20Sopenharmony_ci It must be helt while manipulating the following registers: 968c2ecf20Sopenharmony_ci CSR0, CSR6, CSR7, CSR9, CSR10, CSR15 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci spinlock_t lock; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1018c2ecf20Sopenharmony_ci struct net_device *dev; 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* Function prototypes */ 1068c2ecf20Sopenharmony_cistatic int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id); 1078c2ecf20Sopenharmony_cistatic void xircom_remove(struct pci_dev *pdev); 1088c2ecf20Sopenharmony_cistatic irqreturn_t xircom_interrupt(int irq, void *dev_instance); 1098c2ecf20Sopenharmony_cistatic netdev_tx_t xircom_start_xmit(struct sk_buff *skb, 1108c2ecf20Sopenharmony_ci struct net_device *dev); 1118c2ecf20Sopenharmony_cistatic int xircom_open(struct net_device *dev); 1128c2ecf20Sopenharmony_cistatic int xircom_close(struct net_device *dev); 1138c2ecf20Sopenharmony_cistatic void xircom_up(struct xircom_private *card); 1148c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 1158c2ecf20Sopenharmony_cistatic void xircom_poll_controller(struct net_device *dev); 1168c2ecf20Sopenharmony_ci#endif 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset); 1198c2ecf20Sopenharmony_cistatic void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset); 1208c2ecf20Sopenharmony_cistatic void read_mac_address(struct xircom_private *card); 1218c2ecf20Sopenharmony_cistatic void transceiver_voodoo(struct xircom_private *card); 1228c2ecf20Sopenharmony_cistatic void initialize_card(struct xircom_private *card); 1238c2ecf20Sopenharmony_cistatic void trigger_transmit(struct xircom_private *card); 1248c2ecf20Sopenharmony_cistatic void trigger_receive(struct xircom_private *card); 1258c2ecf20Sopenharmony_cistatic void setup_descriptors(struct xircom_private *card); 1268c2ecf20Sopenharmony_cistatic void remove_descriptors(struct xircom_private *card); 1278c2ecf20Sopenharmony_cistatic int link_status_changed(struct xircom_private *card); 1288c2ecf20Sopenharmony_cistatic void activate_receiver(struct xircom_private *card); 1298c2ecf20Sopenharmony_cistatic void deactivate_receiver(struct xircom_private *card); 1308c2ecf20Sopenharmony_cistatic void activate_transmitter(struct xircom_private *card); 1318c2ecf20Sopenharmony_cistatic void deactivate_transmitter(struct xircom_private *card); 1328c2ecf20Sopenharmony_cistatic void enable_transmit_interrupt(struct xircom_private *card); 1338c2ecf20Sopenharmony_cistatic void enable_receive_interrupt(struct xircom_private *card); 1348c2ecf20Sopenharmony_cistatic void enable_link_interrupt(struct xircom_private *card); 1358c2ecf20Sopenharmony_cistatic void disable_all_interrupts(struct xircom_private *card); 1368c2ecf20Sopenharmony_cistatic int link_status(struct xircom_private *card); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic const struct pci_device_id xircom_pci_table[] = { 1418c2ecf20Sopenharmony_ci { PCI_VDEVICE(XIRCOM, 0x0003), }, 1428c2ecf20Sopenharmony_ci {0,}, 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, xircom_pci_table); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic struct pci_driver xircom_ops = { 1478c2ecf20Sopenharmony_ci .name = "xircom_cb", 1488c2ecf20Sopenharmony_ci .id_table = xircom_pci_table, 1498c2ecf20Sopenharmony_ci .probe = xircom_probe, 1508c2ecf20Sopenharmony_ci .remove = xircom_remove, 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#if defined DEBUG && DEBUG > 1 1558c2ecf20Sopenharmony_cistatic void print_binary(unsigned int number) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci int i,i2; 1588c2ecf20Sopenharmony_ci char buffer[64]; 1598c2ecf20Sopenharmony_ci memset(buffer,0,64); 1608c2ecf20Sopenharmony_ci i2=0; 1618c2ecf20Sopenharmony_ci for (i=31;i>=0;i--) { 1628c2ecf20Sopenharmony_ci if (number & (1<<i)) 1638c2ecf20Sopenharmony_ci buffer[i2++]='1'; 1648c2ecf20Sopenharmony_ci else 1658c2ecf20Sopenharmony_ci buffer[i2++]='0'; 1668c2ecf20Sopenharmony_ci if ((i&3)==0) 1678c2ecf20Sopenharmony_ci buffer[i2++]=' '; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci pr_debug("%s\n",buffer); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci#endif 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic const struct net_device_ops netdev_ops = { 1748c2ecf20Sopenharmony_ci .ndo_open = xircom_open, 1758c2ecf20Sopenharmony_ci .ndo_stop = xircom_close, 1768c2ecf20Sopenharmony_ci .ndo_start_xmit = xircom_start_xmit, 1778c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 1788c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 1798c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 1808c2ecf20Sopenharmony_ci .ndo_poll_controller = xircom_poll_controller, 1818c2ecf20Sopenharmony_ci#endif 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* xircom_probe is the code that gets called on device insertion. 1858c2ecf20Sopenharmony_ci it sets up the hardware and registers the device to the networklayer. 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci TODO: Send 1 or 2 "dummy" packets here as the card seems to discard the 1888c2ecf20Sopenharmony_ci first two packets that get send, and pump hates that. 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_cistatic int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct device *d = &pdev->dev; 1948c2ecf20Sopenharmony_ci struct net_device *dev = NULL; 1958c2ecf20Sopenharmony_ci struct xircom_private *private; 1968c2ecf20Sopenharmony_ci unsigned long flags; 1978c2ecf20Sopenharmony_ci unsigned short tmp16; 1988c2ecf20Sopenharmony_ci int rc; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* First do the PCI initialisation */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 2038c2ecf20Sopenharmony_ci if (rc < 0) 2048c2ecf20Sopenharmony_ci goto out; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* disable all powermanagement */ 2078c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, PCI_POWERMGMT, 0x0000); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci pci_set_master(pdev); /* Why isn't this done by pci_enable_device ?*/ 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* clear PCI status, if any */ 2128c2ecf20Sopenharmony_ci pci_read_config_word (pdev,PCI_STATUS, &tmp16); 2138c2ecf20Sopenharmony_ci pci_write_config_word (pdev, PCI_STATUS,tmp16); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, "xircom_cb"); 2168c2ecf20Sopenharmony_ci if (rc < 0) { 2178c2ecf20Sopenharmony_ci pr_err("%s: failed to allocate io-region\n", __func__); 2188c2ecf20Sopenharmony_ci goto err_disable; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci rc = -ENOMEM; 2228c2ecf20Sopenharmony_ci /* 2238c2ecf20Sopenharmony_ci Before changing the hardware, allocate the memory. 2248c2ecf20Sopenharmony_ci This way, we can fail gracefully if not enough memory 2258c2ecf20Sopenharmony_ci is available. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_ci dev = alloc_etherdev(sizeof(struct xircom_private)); 2288c2ecf20Sopenharmony_ci if (!dev) 2298c2ecf20Sopenharmony_ci goto err_release; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci private = netdev_priv(dev); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* Allocate the send/receive buffers */ 2348c2ecf20Sopenharmony_ci private->rx_buffer = dma_alloc_coherent(d, 8192, 2358c2ecf20Sopenharmony_ci &private->rx_dma_handle, 2368c2ecf20Sopenharmony_ci GFP_KERNEL); 2378c2ecf20Sopenharmony_ci if (private->rx_buffer == NULL) 2388c2ecf20Sopenharmony_ci goto rx_buf_fail; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci private->tx_buffer = dma_alloc_coherent(d, 8192, 2418c2ecf20Sopenharmony_ci &private->tx_dma_handle, 2428c2ecf20Sopenharmony_ci GFP_KERNEL); 2438c2ecf20Sopenharmony_ci if (private->tx_buffer == NULL) 2448c2ecf20Sopenharmony_ci goto tx_buf_fail; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci private->dev = dev; 2508c2ecf20Sopenharmony_ci private->pdev = pdev; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* IO range. */ 2538c2ecf20Sopenharmony_ci private->ioaddr = pci_iomap(pdev, 0, 0); 2548c2ecf20Sopenharmony_ci if (!private->ioaddr) 2558c2ecf20Sopenharmony_ci goto reg_fail; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci spin_lock_init(&private->lock); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci initialize_card(private); 2608c2ecf20Sopenharmony_ci read_mac_address(private); 2618c2ecf20Sopenharmony_ci setup_descriptors(private); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci dev->netdev_ops = &netdev_ops; 2648c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, dev); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci rc = register_netdev(dev); 2678c2ecf20Sopenharmony_ci if (rc < 0) { 2688c2ecf20Sopenharmony_ci pr_err("%s: netdevice registration failed\n", __func__); 2698c2ecf20Sopenharmony_ci goto err_unmap; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci netdev_info(dev, "Xircom cardbus revision %i at irq %i\n", 2738c2ecf20Sopenharmony_ci pdev->revision, pdev->irq); 2748c2ecf20Sopenharmony_ci /* start the transmitter to get a heartbeat */ 2758c2ecf20Sopenharmony_ci /* TODO: send 2 dummy packets here */ 2768c2ecf20Sopenharmony_ci transceiver_voodoo(private); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci spin_lock_irqsave(&private->lock,flags); 2798c2ecf20Sopenharmony_ci activate_transmitter(private); 2808c2ecf20Sopenharmony_ci activate_receiver(private); 2818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&private->lock,flags); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci trigger_receive(private); 2848c2ecf20Sopenharmony_ciout: 2858c2ecf20Sopenharmony_ci return rc; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cierr_unmap: 2888c2ecf20Sopenharmony_ci pci_iounmap(pdev, private->ioaddr); 2898c2ecf20Sopenharmony_cireg_fail: 2908c2ecf20Sopenharmony_ci dma_free_coherent(d, 8192, private->tx_buffer, private->tx_dma_handle); 2918c2ecf20Sopenharmony_citx_buf_fail: 2928c2ecf20Sopenharmony_ci dma_free_coherent(d, 8192, private->rx_buffer, private->rx_dma_handle); 2938c2ecf20Sopenharmony_cirx_buf_fail: 2948c2ecf20Sopenharmony_ci free_netdev(dev); 2958c2ecf20Sopenharmony_cierr_release: 2968c2ecf20Sopenharmony_ci pci_release_regions(pdev); 2978c2ecf20Sopenharmony_cierr_disable: 2988c2ecf20Sopenharmony_ci pci_disable_device(pdev); 2998c2ecf20Sopenharmony_ci goto out; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/* 3048c2ecf20Sopenharmony_ci xircom_remove is called on module-unload or on device-eject. 3058c2ecf20Sopenharmony_ci it unregisters the irq, io-region and network device. 3068c2ecf20Sopenharmony_ci Interrupts and such are already stopped in the "ifconfig ethX down" 3078c2ecf20Sopenharmony_ci code. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_cistatic void xircom_remove(struct pci_dev *pdev) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 3128c2ecf20Sopenharmony_ci struct xircom_private *card = netdev_priv(dev); 3138c2ecf20Sopenharmony_ci struct device *d = &pdev->dev; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci unregister_netdev(dev); 3168c2ecf20Sopenharmony_ci pci_iounmap(pdev, card->ioaddr); 3178c2ecf20Sopenharmony_ci dma_free_coherent(d, 8192, card->tx_buffer, card->tx_dma_handle); 3188c2ecf20Sopenharmony_ci dma_free_coherent(d, 8192, card->rx_buffer, card->rx_dma_handle); 3198c2ecf20Sopenharmony_ci free_netdev(dev); 3208c2ecf20Sopenharmony_ci pci_release_regions(pdev); 3218c2ecf20Sopenharmony_ci pci_disable_device(pdev); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic irqreturn_t xircom_interrupt(int irq, void *dev_instance) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct net_device *dev = (struct net_device *) dev_instance; 3278c2ecf20Sopenharmony_ci struct xircom_private *card = netdev_priv(dev); 3288c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 3298c2ecf20Sopenharmony_ci unsigned int status; 3308c2ecf20Sopenharmony_ci int i; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci spin_lock(&card->lock); 3338c2ecf20Sopenharmony_ci status = xr32(CSR5); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci#if defined DEBUG && DEBUG > 1 3368c2ecf20Sopenharmony_ci print_binary(status); 3378c2ecf20Sopenharmony_ci pr_debug("tx status 0x%08x 0x%08x\n", 3388c2ecf20Sopenharmony_ci card->tx_buffer[0], card->tx_buffer[4]); 3398c2ecf20Sopenharmony_ci pr_debug("rx status 0x%08x 0x%08x\n", 3408c2ecf20Sopenharmony_ci card->rx_buffer[0], card->rx_buffer[4]); 3418c2ecf20Sopenharmony_ci#endif 3428c2ecf20Sopenharmony_ci /* Handle shared irq and hotplug */ 3438c2ecf20Sopenharmony_ci if (status == 0 || status == 0xffffffff) { 3448c2ecf20Sopenharmony_ci spin_unlock(&card->lock); 3458c2ecf20Sopenharmony_ci return IRQ_NONE; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (link_status_changed(card)) { 3498c2ecf20Sopenharmony_ci int newlink; 3508c2ecf20Sopenharmony_ci netdev_dbg(dev, "Link status has changed\n"); 3518c2ecf20Sopenharmony_ci newlink = link_status(card); 3528c2ecf20Sopenharmony_ci netdev_info(dev, "Link is %d mbit\n", newlink); 3538c2ecf20Sopenharmony_ci if (newlink) 3548c2ecf20Sopenharmony_ci netif_carrier_on(dev); 3558c2ecf20Sopenharmony_ci else 3568c2ecf20Sopenharmony_ci netif_carrier_off(dev); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Clear all remaining interrupts */ 3618c2ecf20Sopenharmony_ci status |= 0xffffffff; /* FIXME: make this clear only the 3628c2ecf20Sopenharmony_ci real existing bits */ 3638c2ecf20Sopenharmony_ci xw32(CSR5, status); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci for (i=0;i<NUMDESCRIPTORS;i++) 3678c2ecf20Sopenharmony_ci investigate_write_descriptor(dev,card,i,bufferoffsets[i]); 3688c2ecf20Sopenharmony_ci for (i=0;i<NUMDESCRIPTORS;i++) 3698c2ecf20Sopenharmony_ci investigate_read_descriptor(dev,card,i,bufferoffsets[i]); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci spin_unlock(&card->lock); 3728c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic netdev_tx_t xircom_start_xmit(struct sk_buff *skb, 3768c2ecf20Sopenharmony_ci struct net_device *dev) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct xircom_private *card; 3798c2ecf20Sopenharmony_ci unsigned long flags; 3808c2ecf20Sopenharmony_ci int nextdescriptor; 3818c2ecf20Sopenharmony_ci int desc; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci card = netdev_priv(dev); 3848c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->lock,flags); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* First see if we can free some descriptors */ 3878c2ecf20Sopenharmony_ci for (desc=0;desc<NUMDESCRIPTORS;desc++) 3888c2ecf20Sopenharmony_ci investigate_write_descriptor(dev,card,desc,bufferoffsets[desc]); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci nextdescriptor = (card->transmit_used +1) % (NUMDESCRIPTORS); 3928c2ecf20Sopenharmony_ci desc = card->transmit_used; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* only send the packet if the descriptor is free */ 3958c2ecf20Sopenharmony_ci if (card->tx_buffer[4*desc]==0) { 3968c2ecf20Sopenharmony_ci /* Copy the packet data; zero the memory first as the card 3978c2ecf20Sopenharmony_ci sometimes sends more than you ask it to. */ 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci memset(&card->tx_buffer[bufferoffsets[desc]/4],0,1536); 4008c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, 4018c2ecf20Sopenharmony_ci &(card->tx_buffer[bufferoffsets[desc] / 4]), 4028c2ecf20Sopenharmony_ci skb->len); 4038c2ecf20Sopenharmony_ci /* FIXME: The specification tells us that the length we send HAS to be a multiple of 4048c2ecf20Sopenharmony_ci 4 bytes. */ 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci card->tx_buffer[4*desc+1] = cpu_to_le32(skb->len); 4078c2ecf20Sopenharmony_ci if (desc == NUMDESCRIPTORS - 1) /* bit 25: last descriptor of the ring */ 4088c2ecf20Sopenharmony_ci card->tx_buffer[4*desc+1] |= cpu_to_le32(1<<25); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci card->tx_buffer[4*desc+1] |= cpu_to_le32(0xF0000000); 4118c2ecf20Sopenharmony_ci /* 0xF0... means want interrupts*/ 4128c2ecf20Sopenharmony_ci card->tx_skb[desc] = skb; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci wmb(); 4158c2ecf20Sopenharmony_ci /* This gives the descriptor to the card */ 4168c2ecf20Sopenharmony_ci card->tx_buffer[4*desc] = cpu_to_le32(0x80000000); 4178c2ecf20Sopenharmony_ci trigger_transmit(card); 4188c2ecf20Sopenharmony_ci if (card->tx_buffer[nextdescriptor*4] & cpu_to_le32(0x8000000)) { 4198c2ecf20Sopenharmony_ci /* next descriptor is occupied... */ 4208c2ecf20Sopenharmony_ci netif_stop_queue(dev); 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci card->transmit_used = nextdescriptor; 4238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->lock,flags); 4248c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Uh oh... no free descriptor... drop the packet */ 4288c2ecf20Sopenharmony_ci netif_stop_queue(dev); 4298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->lock,flags); 4308c2ecf20Sopenharmony_ci trigger_transmit(card); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic int xircom_open(struct net_device *dev) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci struct xircom_private *xp = netdev_priv(dev); 4418c2ecf20Sopenharmony_ci const int irq = xp->pdev->irq; 4428c2ecf20Sopenharmony_ci int retval; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci netdev_info(dev, "xircom cardbus adaptor found, using irq %i\n", irq); 4458c2ecf20Sopenharmony_ci retval = request_irq(irq, xircom_interrupt, IRQF_SHARED, dev->name, dev); 4468c2ecf20Sopenharmony_ci if (retval) 4478c2ecf20Sopenharmony_ci return retval; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci xircom_up(xp); 4508c2ecf20Sopenharmony_ci xp->open = 1; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic int xircom_close(struct net_device *dev) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct xircom_private *card; 4588c2ecf20Sopenharmony_ci unsigned long flags; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci card = netdev_priv(dev); 4618c2ecf20Sopenharmony_ci netif_stop_queue(dev); /* we don't want new packets */ 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->lock,flags); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci disable_all_interrupts(card); 4678c2ecf20Sopenharmony_ci#if 0 4688c2ecf20Sopenharmony_ci /* We can enable this again once we send dummy packets on ifconfig ethX up */ 4698c2ecf20Sopenharmony_ci deactivate_receiver(card); 4708c2ecf20Sopenharmony_ci deactivate_transmitter(card); 4718c2ecf20Sopenharmony_ci#endif 4728c2ecf20Sopenharmony_ci remove_descriptors(card); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->lock,flags); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci card->open = 0; 4778c2ecf20Sopenharmony_ci free_irq(card->pdev->irq, dev); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 4858c2ecf20Sopenharmony_cistatic void xircom_poll_controller(struct net_device *dev) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci struct xircom_private *xp = netdev_priv(dev); 4888c2ecf20Sopenharmony_ci const int irq = xp->pdev->irq; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci disable_irq(irq); 4918c2ecf20Sopenharmony_ci xircom_interrupt(irq, dev); 4928c2ecf20Sopenharmony_ci enable_irq(irq); 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci#endif 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic void initialize_card(struct xircom_private *card) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 5008c2ecf20Sopenharmony_ci unsigned long flags; 5018c2ecf20Sopenharmony_ci u32 val; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->lock, flags); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* First: reset the card */ 5068c2ecf20Sopenharmony_ci val = xr32(CSR0); 5078c2ecf20Sopenharmony_ci val |= 0x01; /* Software reset */ 5088c2ecf20Sopenharmony_ci xw32(CSR0, val); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci udelay(100); /* give the card some time to reset */ 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci val = xr32(CSR0); 5138c2ecf20Sopenharmony_ci val &= ~0x01; /* disable Software reset */ 5148c2ecf20Sopenharmony_ci xw32(CSR0, val); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci val = 0; /* Value 0x00 is a safe and conservative value 5188c2ecf20Sopenharmony_ci for the PCI configuration settings */ 5198c2ecf20Sopenharmony_ci xw32(CSR0, val); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci disable_all_interrupts(card); 5238c2ecf20Sopenharmony_ci deactivate_receiver(card); 5248c2ecf20Sopenharmony_ci deactivate_transmitter(card); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->lock, flags); 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci/* 5308c2ecf20Sopenharmony_citrigger_transmit causes the card to check for frames to be transmitted. 5318c2ecf20Sopenharmony_ciThis is accomplished by writing to the CSR1 port. The documentation 5328c2ecf20Sopenharmony_ciclaims that the act of writing is sufficient and that the value is 5338c2ecf20Sopenharmony_ciignored; I chose zero. 5348c2ecf20Sopenharmony_ci*/ 5358c2ecf20Sopenharmony_cistatic void trigger_transmit(struct xircom_private *card) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci xw32(CSR1, 0); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci/* 5438c2ecf20Sopenharmony_citrigger_receive causes the card to check for empty frames in the 5448c2ecf20Sopenharmony_cidescriptor list in which packets can be received. 5458c2ecf20Sopenharmony_ciThis is accomplished by writing to the CSR2 port. The documentation 5468c2ecf20Sopenharmony_ciclaims that the act of writing is sufficient and that the value is 5478c2ecf20Sopenharmony_ciignored; I chose zero. 5488c2ecf20Sopenharmony_ci*/ 5498c2ecf20Sopenharmony_cistatic void trigger_receive(struct xircom_private *card) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci xw32(CSR2, 0); 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci/* 5578c2ecf20Sopenharmony_cisetup_descriptors initializes the send and receive buffers to be valid 5588c2ecf20Sopenharmony_cidescriptors and programs the addresses into the card. 5598c2ecf20Sopenharmony_ci*/ 5608c2ecf20Sopenharmony_cistatic void setup_descriptors(struct xircom_private *card) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 5638c2ecf20Sopenharmony_ci u32 address; 5648c2ecf20Sopenharmony_ci int i; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci BUG_ON(card->rx_buffer == NULL); 5678c2ecf20Sopenharmony_ci BUG_ON(card->tx_buffer == NULL); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* Receive descriptors */ 5708c2ecf20Sopenharmony_ci memset(card->rx_buffer, 0, 128); /* clear the descriptors */ 5718c2ecf20Sopenharmony_ci for (i=0;i<NUMDESCRIPTORS;i++ ) { 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* Rx Descr0: It's empty, let the card own it, no errors -> 0x80000000 */ 5748c2ecf20Sopenharmony_ci card->rx_buffer[i*4 + 0] = cpu_to_le32(0x80000000); 5758c2ecf20Sopenharmony_ci /* Rx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */ 5768c2ecf20Sopenharmony_ci card->rx_buffer[i*4 + 1] = cpu_to_le32(1536); 5778c2ecf20Sopenharmony_ci if (i == NUMDESCRIPTORS - 1) /* bit 25 is "last descriptor" */ 5788c2ecf20Sopenharmony_ci card->rx_buffer[i*4 + 1] |= cpu_to_le32(1 << 25); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* Rx Descr2: address of the buffer 5818c2ecf20Sopenharmony_ci we store the buffer at the 2nd half of the page */ 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci address = card->rx_dma_handle; 5848c2ecf20Sopenharmony_ci card->rx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]); 5858c2ecf20Sopenharmony_ci /* Rx Desc3: address of 2nd buffer -> 0 */ 5868c2ecf20Sopenharmony_ci card->rx_buffer[i*4 + 3] = 0; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci wmb(); 5908c2ecf20Sopenharmony_ci /* Write the receive descriptor ring address to the card */ 5918c2ecf20Sopenharmony_ci address = card->rx_dma_handle; 5928c2ecf20Sopenharmony_ci xw32(CSR3, address); /* Receive descr list address */ 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* transmit descriptors */ 5968c2ecf20Sopenharmony_ci memset(card->tx_buffer, 0, 128); /* clear the descriptors */ 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci for (i=0;i<NUMDESCRIPTORS;i++ ) { 5998c2ecf20Sopenharmony_ci /* Tx Descr0: Empty, we own it, no errors -> 0x00000000 */ 6008c2ecf20Sopenharmony_ci card->tx_buffer[i*4 + 0] = 0x00000000; 6018c2ecf20Sopenharmony_ci /* Tx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */ 6028c2ecf20Sopenharmony_ci card->tx_buffer[i*4 + 1] = cpu_to_le32(1536); 6038c2ecf20Sopenharmony_ci if (i == NUMDESCRIPTORS - 1) /* bit 25 is "last descriptor" */ 6048c2ecf20Sopenharmony_ci card->tx_buffer[i*4 + 1] |= cpu_to_le32(1 << 25); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* Tx Descr2: address of the buffer 6078c2ecf20Sopenharmony_ci we store the buffer at the 2nd half of the page */ 6088c2ecf20Sopenharmony_ci address = card->tx_dma_handle; 6098c2ecf20Sopenharmony_ci card->tx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]); 6108c2ecf20Sopenharmony_ci /* Tx Desc3: address of 2nd buffer -> 0 */ 6118c2ecf20Sopenharmony_ci card->tx_buffer[i*4 + 3] = 0; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci wmb(); 6158c2ecf20Sopenharmony_ci /* wite the transmit descriptor ring to the card */ 6168c2ecf20Sopenharmony_ci address = card->tx_dma_handle; 6178c2ecf20Sopenharmony_ci xw32(CSR4, address); /* xmit descr list address */ 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci/* 6218c2ecf20Sopenharmony_ciremove_descriptors informs the card the descriptors are no longer 6228c2ecf20Sopenharmony_civalid by setting the address in the card to 0x00. 6238c2ecf20Sopenharmony_ci*/ 6248c2ecf20Sopenharmony_cistatic void remove_descriptors(struct xircom_private *card) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 6278c2ecf20Sopenharmony_ci unsigned int val; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci val = 0; 6308c2ecf20Sopenharmony_ci xw32(CSR3, val); /* Receive descriptor address */ 6318c2ecf20Sopenharmony_ci xw32(CSR4, val); /* Send descriptor address */ 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci/* 6358c2ecf20Sopenharmony_cilink_status_changed returns 1 if the card has indicated that 6368c2ecf20Sopenharmony_cithe link status has changed. The new link status has to be read from CSR12. 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ciThis function also clears the status-bit. 6398c2ecf20Sopenharmony_ci*/ 6408c2ecf20Sopenharmony_cistatic int link_status_changed(struct xircom_private *card) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 6438c2ecf20Sopenharmony_ci unsigned int val; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci val = xr32(CSR5); /* Status register */ 6468c2ecf20Sopenharmony_ci if (!(val & (1 << 27))) /* no change */ 6478c2ecf20Sopenharmony_ci return 0; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* clear the event by writing a 1 to the bit in the 6508c2ecf20Sopenharmony_ci status register. */ 6518c2ecf20Sopenharmony_ci val = (1 << 27); 6528c2ecf20Sopenharmony_ci xw32(CSR5, val); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci return 1; 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci/* 6598c2ecf20Sopenharmony_citransmit_active returns 1 if the transmitter on the card is 6608c2ecf20Sopenharmony_ciin a non-stopped state. 6618c2ecf20Sopenharmony_ci*/ 6628c2ecf20Sopenharmony_cistatic int transmit_active(struct xircom_private *card) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (!(xr32(CSR5) & (7 << 20))) /* transmitter disabled */ 6678c2ecf20Sopenharmony_ci return 0; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return 1; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci/* 6738c2ecf20Sopenharmony_cireceive_active returns 1 if the receiver on the card is 6748c2ecf20Sopenharmony_ciin a non-stopped state. 6758c2ecf20Sopenharmony_ci*/ 6768c2ecf20Sopenharmony_cistatic int receive_active(struct xircom_private *card) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (!(xr32(CSR5) & (7 << 17))) /* receiver disabled */ 6818c2ecf20Sopenharmony_ci return 0; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci return 1; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci/* 6878c2ecf20Sopenharmony_ciactivate_receiver enables the receiver on the card. 6888c2ecf20Sopenharmony_ciBefore being allowed to active the receiver, the receiver 6898c2ecf20Sopenharmony_cimust be completely de-activated. To achieve this, 6908c2ecf20Sopenharmony_cithis code actually disables the receiver first; then it waits for the 6918c2ecf20Sopenharmony_cireceiver to become inactive, then it activates the receiver and then 6928c2ecf20Sopenharmony_ciit waits for the receiver to be active. 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cimust be called with the lock held and interrupts disabled. 6958c2ecf20Sopenharmony_ci*/ 6968c2ecf20Sopenharmony_cistatic void activate_receiver(struct xircom_private *card) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 6998c2ecf20Sopenharmony_ci unsigned int val; 7008c2ecf20Sopenharmony_ci int counter; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci /* If the "active" bit is set and the receiver is already 7058c2ecf20Sopenharmony_ci active, no need to do the expensive thing */ 7068c2ecf20Sopenharmony_ci if ((val&2) && (receive_active(card))) 7078c2ecf20Sopenharmony_ci return; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci val = val & ~2; /* disable the receiver */ 7118c2ecf20Sopenharmony_ci xw32(CSR6, val); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci counter = 10; 7148c2ecf20Sopenharmony_ci while (counter > 0) { 7158c2ecf20Sopenharmony_ci if (!receive_active(card)) 7168c2ecf20Sopenharmony_ci break; 7178c2ecf20Sopenharmony_ci /* wait a while */ 7188c2ecf20Sopenharmony_ci udelay(50); 7198c2ecf20Sopenharmony_ci counter--; 7208c2ecf20Sopenharmony_ci if (counter <= 0) 7218c2ecf20Sopenharmony_ci netdev_err(card->dev, "Receiver failed to deactivate\n"); 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* enable the receiver */ 7258c2ecf20Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 7268c2ecf20Sopenharmony_ci val = val | 2; /* enable the receiver */ 7278c2ecf20Sopenharmony_ci xw32(CSR6, val); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci /* now wait for the card to activate again */ 7308c2ecf20Sopenharmony_ci counter = 10; 7318c2ecf20Sopenharmony_ci while (counter > 0) { 7328c2ecf20Sopenharmony_ci if (receive_active(card)) 7338c2ecf20Sopenharmony_ci break; 7348c2ecf20Sopenharmony_ci /* wait a while */ 7358c2ecf20Sopenharmony_ci udelay(50); 7368c2ecf20Sopenharmony_ci counter--; 7378c2ecf20Sopenharmony_ci if (counter <= 0) 7388c2ecf20Sopenharmony_ci netdev_err(card->dev, 7398c2ecf20Sopenharmony_ci "Receiver failed to re-activate\n"); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci/* 7448c2ecf20Sopenharmony_cideactivate_receiver disables the receiver on the card. 7458c2ecf20Sopenharmony_ciTo achieve this this code disables the receiver first; 7468c2ecf20Sopenharmony_cithen it waits for the receiver to become inactive. 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cimust be called with the lock held and interrupts disabled. 7498c2ecf20Sopenharmony_ci*/ 7508c2ecf20Sopenharmony_cistatic void deactivate_receiver(struct xircom_private *card) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 7538c2ecf20Sopenharmony_ci unsigned int val; 7548c2ecf20Sopenharmony_ci int counter; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 7578c2ecf20Sopenharmony_ci val = val & ~2; /* disable the receiver */ 7588c2ecf20Sopenharmony_ci xw32(CSR6, val); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci counter = 10; 7618c2ecf20Sopenharmony_ci while (counter > 0) { 7628c2ecf20Sopenharmony_ci if (!receive_active(card)) 7638c2ecf20Sopenharmony_ci break; 7648c2ecf20Sopenharmony_ci /* wait a while */ 7658c2ecf20Sopenharmony_ci udelay(50); 7668c2ecf20Sopenharmony_ci counter--; 7678c2ecf20Sopenharmony_ci if (counter <= 0) 7688c2ecf20Sopenharmony_ci netdev_err(card->dev, "Receiver failed to deactivate\n"); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci/* 7748c2ecf20Sopenharmony_ciactivate_transmitter enables the transmitter on the card. 7758c2ecf20Sopenharmony_ciBefore being allowed to active the transmitter, the transmitter 7768c2ecf20Sopenharmony_cimust be completely de-activated. To achieve this, 7778c2ecf20Sopenharmony_cithis code actually disables the transmitter first; then it waits for the 7788c2ecf20Sopenharmony_citransmitter to become inactive, then it activates the transmitter and then 7798c2ecf20Sopenharmony_ciit waits for the transmitter to be active again. 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cimust be called with the lock held and interrupts disabled. 7828c2ecf20Sopenharmony_ci*/ 7838c2ecf20Sopenharmony_cistatic void activate_transmitter(struct xircom_private *card) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 7868c2ecf20Sopenharmony_ci unsigned int val; 7878c2ecf20Sopenharmony_ci int counter; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* If the "active" bit is set and the receiver is already 7928c2ecf20Sopenharmony_ci active, no need to do the expensive thing */ 7938c2ecf20Sopenharmony_ci if ((val&(1<<13)) && (transmit_active(card))) 7948c2ecf20Sopenharmony_ci return; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci val = val & ~(1 << 13); /* disable the transmitter */ 7978c2ecf20Sopenharmony_ci xw32(CSR6, val); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci counter = 10; 8008c2ecf20Sopenharmony_ci while (counter > 0) { 8018c2ecf20Sopenharmony_ci if (!transmit_active(card)) 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci /* wait a while */ 8048c2ecf20Sopenharmony_ci udelay(50); 8058c2ecf20Sopenharmony_ci counter--; 8068c2ecf20Sopenharmony_ci if (counter <= 0) 8078c2ecf20Sopenharmony_ci netdev_err(card->dev, 8088c2ecf20Sopenharmony_ci "Transmitter failed to deactivate\n"); 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* enable the transmitter */ 8128c2ecf20Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 8138c2ecf20Sopenharmony_ci val = val | (1 << 13); /* enable the transmitter */ 8148c2ecf20Sopenharmony_ci xw32(CSR6, val); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* now wait for the card to activate again */ 8178c2ecf20Sopenharmony_ci counter = 10; 8188c2ecf20Sopenharmony_ci while (counter > 0) { 8198c2ecf20Sopenharmony_ci if (transmit_active(card)) 8208c2ecf20Sopenharmony_ci break; 8218c2ecf20Sopenharmony_ci /* wait a while */ 8228c2ecf20Sopenharmony_ci udelay(50); 8238c2ecf20Sopenharmony_ci counter--; 8248c2ecf20Sopenharmony_ci if (counter <= 0) 8258c2ecf20Sopenharmony_ci netdev_err(card->dev, 8268c2ecf20Sopenharmony_ci "Transmitter failed to re-activate\n"); 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci/* 8318c2ecf20Sopenharmony_cideactivate_transmitter disables the transmitter on the card. 8328c2ecf20Sopenharmony_ciTo achieve this this code disables the transmitter first; 8338c2ecf20Sopenharmony_cithen it waits for the transmitter to become inactive. 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cimust be called with the lock held and interrupts disabled. 8368c2ecf20Sopenharmony_ci*/ 8378c2ecf20Sopenharmony_cistatic void deactivate_transmitter(struct xircom_private *card) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 8408c2ecf20Sopenharmony_ci unsigned int val; 8418c2ecf20Sopenharmony_ci int counter; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci val = xr32(CSR6); /* Operation mode */ 8448c2ecf20Sopenharmony_ci val = val & ~2; /* disable the transmitter */ 8458c2ecf20Sopenharmony_ci xw32(CSR6, val); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci counter = 20; 8488c2ecf20Sopenharmony_ci while (counter > 0) { 8498c2ecf20Sopenharmony_ci if (!transmit_active(card)) 8508c2ecf20Sopenharmony_ci break; 8518c2ecf20Sopenharmony_ci /* wait a while */ 8528c2ecf20Sopenharmony_ci udelay(50); 8538c2ecf20Sopenharmony_ci counter--; 8548c2ecf20Sopenharmony_ci if (counter <= 0) 8558c2ecf20Sopenharmony_ci netdev_err(card->dev, 8568c2ecf20Sopenharmony_ci "Transmitter failed to deactivate\n"); 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci/* 8628c2ecf20Sopenharmony_cienable_transmit_interrupt enables the transmit interrupt 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cimust be called with the lock held and interrupts disabled. 8658c2ecf20Sopenharmony_ci*/ 8668c2ecf20Sopenharmony_cistatic void enable_transmit_interrupt(struct xircom_private *card) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 8698c2ecf20Sopenharmony_ci unsigned int val; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci val = xr32(CSR7); /* Interrupt enable register */ 8728c2ecf20Sopenharmony_ci val |= 1; /* enable the transmit interrupt */ 8738c2ecf20Sopenharmony_ci xw32(CSR7, val); 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci/* 8788c2ecf20Sopenharmony_cienable_receive_interrupt enables the receive interrupt 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cimust be called with the lock held and interrupts disabled. 8818c2ecf20Sopenharmony_ci*/ 8828c2ecf20Sopenharmony_cistatic void enable_receive_interrupt(struct xircom_private *card) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 8858c2ecf20Sopenharmony_ci unsigned int val; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci val = xr32(CSR7); /* Interrupt enable register */ 8888c2ecf20Sopenharmony_ci val = val | (1 << 6); /* enable the receive interrupt */ 8898c2ecf20Sopenharmony_ci xw32(CSR7, val); 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci/* 8938c2ecf20Sopenharmony_cienable_link_interrupt enables the link status change interrupt 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cimust be called with the lock held and interrupts disabled. 8968c2ecf20Sopenharmony_ci*/ 8978c2ecf20Sopenharmony_cistatic void enable_link_interrupt(struct xircom_private *card) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 9008c2ecf20Sopenharmony_ci unsigned int val; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci val = xr32(CSR7); /* Interrupt enable register */ 9038c2ecf20Sopenharmony_ci val = val | (1 << 27); /* enable the link status chage interrupt */ 9048c2ecf20Sopenharmony_ci xw32(CSR7, val); 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci/* 9108c2ecf20Sopenharmony_cidisable_all_interrupts disables all interrupts 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_cimust be called with the lock held and interrupts disabled. 9138c2ecf20Sopenharmony_ci*/ 9148c2ecf20Sopenharmony_cistatic void disable_all_interrupts(struct xircom_private *card) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci xw32(CSR7, 0); 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci/* 9228c2ecf20Sopenharmony_cienable_common_interrupts enables several weird interrupts 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cimust be called with the lock held and interrupts disabled. 9258c2ecf20Sopenharmony_ci*/ 9268c2ecf20Sopenharmony_cistatic void enable_common_interrupts(struct xircom_private *card) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 9298c2ecf20Sopenharmony_ci unsigned int val; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci val = xr32(CSR7); /* Interrupt enable register */ 9328c2ecf20Sopenharmony_ci val |= (1<<16); /* Normal Interrupt Summary */ 9338c2ecf20Sopenharmony_ci val |= (1<<15); /* Abnormal Interrupt Summary */ 9348c2ecf20Sopenharmony_ci val |= (1<<13); /* Fatal bus error */ 9358c2ecf20Sopenharmony_ci val |= (1<<8); /* Receive Process Stopped */ 9368c2ecf20Sopenharmony_ci val |= (1<<7); /* Receive Buffer Unavailable */ 9378c2ecf20Sopenharmony_ci val |= (1<<5); /* Transmit Underflow */ 9388c2ecf20Sopenharmony_ci val |= (1<<2); /* Transmit Buffer Unavailable */ 9398c2ecf20Sopenharmony_ci val |= (1<<1); /* Transmit Process Stopped */ 9408c2ecf20Sopenharmony_ci xw32(CSR7, val); 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci/* 9448c2ecf20Sopenharmony_cienable_promisc starts promisc mode 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cimust be called with the lock held and interrupts disabled. 9478c2ecf20Sopenharmony_ci*/ 9488c2ecf20Sopenharmony_cistatic int enable_promisc(struct xircom_private *card) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 9518c2ecf20Sopenharmony_ci unsigned int val; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci val = xr32(CSR6); 9548c2ecf20Sopenharmony_ci val = val | (1 << 6); 9558c2ecf20Sopenharmony_ci xw32(CSR6, val); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci return 1; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci/* 9648c2ecf20Sopenharmony_cilink_status() checks the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what. 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ciMust be called in locked state with interrupts disabled 9678c2ecf20Sopenharmony_ci*/ 9688c2ecf20Sopenharmony_cistatic int link_status(struct xircom_private *card) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 9718c2ecf20Sopenharmony_ci u8 val; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci val = xr8(CSR12); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* bit 2 is 0 for 10mbit link, 1 for not an 10mbit link */ 9768c2ecf20Sopenharmony_ci if (!(val & (1 << 2))) 9778c2ecf20Sopenharmony_ci return 10; 9788c2ecf20Sopenharmony_ci /* bit 1 is 0 for 100mbit link, 1 for not an 100mbit link */ 9798c2ecf20Sopenharmony_ci if (!(val & (1 << 1))) 9808c2ecf20Sopenharmony_ci return 100; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* If we get here -> no link at all */ 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci return 0; 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci/* 9928c2ecf20Sopenharmony_ci read_mac_address() reads the MAC address from the NIC and stores it in the "dev" structure. 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci This function will take the spinlock itself and can, as a result, not be called with the lock helt. 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_cistatic void read_mac_address(struct xircom_private *card) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 9998c2ecf20Sopenharmony_ci unsigned long flags; 10008c2ecf20Sopenharmony_ci u8 link; 10018c2ecf20Sopenharmony_ci int i; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->lock, flags); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci xw32(CSR9, 1 << 12); /* enable boot rom access */ 10068c2ecf20Sopenharmony_ci for (i = 0x100; i < 0x1f7; i += link + 2) { 10078c2ecf20Sopenharmony_ci u8 tuple, data_id, data_count; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci xw32(CSR10, i); 10108c2ecf20Sopenharmony_ci tuple = xr32(CSR9); 10118c2ecf20Sopenharmony_ci xw32(CSR10, i + 1); 10128c2ecf20Sopenharmony_ci link = xr32(CSR9); 10138c2ecf20Sopenharmony_ci xw32(CSR10, i + 2); 10148c2ecf20Sopenharmony_ci data_id = xr32(CSR9); 10158c2ecf20Sopenharmony_ci xw32(CSR10, i + 3); 10168c2ecf20Sopenharmony_ci data_count = xr32(CSR9); 10178c2ecf20Sopenharmony_ci if ((tuple == 0x22) && (data_id == 0x04) && (data_count == 0x06)) { 10188c2ecf20Sopenharmony_ci int j; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci for (j = 0; j < 6; j++) { 10218c2ecf20Sopenharmony_ci xw32(CSR10, i + j + 4); 10228c2ecf20Sopenharmony_ci card->dev->dev_addr[j] = xr32(CSR9) & 0xff; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci break; 10258c2ecf20Sopenharmony_ci } else if (link == 0) { 10268c2ecf20Sopenharmony_ci break; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->lock, flags); 10308c2ecf20Sopenharmony_ci pr_debug(" %pM\n", card->dev->dev_addr); 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci/* 10358c2ecf20Sopenharmony_ci transceiver_voodoo() enables the external UTP plug thingy. 10368c2ecf20Sopenharmony_ci it's called voodoo as I stole this code and cannot cross-reference 10378c2ecf20Sopenharmony_ci it with the specification. 10388c2ecf20Sopenharmony_ci */ 10398c2ecf20Sopenharmony_cistatic void transceiver_voodoo(struct xircom_private *card) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci void __iomem *ioaddr = card->ioaddr; 10428c2ecf20Sopenharmony_ci unsigned long flags; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci /* disable all powermanagement */ 10458c2ecf20Sopenharmony_ci pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci setup_descriptors(card); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->lock, flags); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci xw32(CSR15, 0x0008); 10528c2ecf20Sopenharmony_ci udelay(25); 10538c2ecf20Sopenharmony_ci xw32(CSR15, 0xa8050000); 10548c2ecf20Sopenharmony_ci udelay(25); 10558c2ecf20Sopenharmony_ci xw32(CSR15, 0xa00f0000); 10568c2ecf20Sopenharmony_ci udelay(25); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->lock, flags); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci netif_start_queue(card->dev); 10618c2ecf20Sopenharmony_ci} 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic void xircom_up(struct xircom_private *card) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci unsigned long flags; 10678c2ecf20Sopenharmony_ci int i; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* disable all powermanagement */ 10708c2ecf20Sopenharmony_ci pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci setup_descriptors(card); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->lock, flags); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci enable_link_interrupt(card); 10788c2ecf20Sopenharmony_ci enable_transmit_interrupt(card); 10798c2ecf20Sopenharmony_ci enable_receive_interrupt(card); 10808c2ecf20Sopenharmony_ci enable_common_interrupts(card); 10818c2ecf20Sopenharmony_ci enable_promisc(card); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* The card can have received packets already, read them away now */ 10848c2ecf20Sopenharmony_ci for (i=0;i<NUMDESCRIPTORS;i++) 10858c2ecf20Sopenharmony_ci investigate_read_descriptor(card->dev,card,i,bufferoffsets[i]); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->lock, flags); 10898c2ecf20Sopenharmony_ci trigger_receive(card); 10908c2ecf20Sopenharmony_ci trigger_transmit(card); 10918c2ecf20Sopenharmony_ci netif_start_queue(card->dev); 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci/* Bufferoffset is in BYTES */ 10958c2ecf20Sopenharmony_cistatic void 10968c2ecf20Sopenharmony_ciinvestigate_read_descriptor(struct net_device *dev, struct xircom_private *card, 10978c2ecf20Sopenharmony_ci int descnr, unsigned int bufferoffset) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci int status; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci status = le32_to_cpu(card->rx_buffer[4*descnr]); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (status > 0) { /* packet received */ 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci /* TODO: discard error packets */ 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci short pkt_len = ((status >> 16) & 0x7ff) - 4; 11088c2ecf20Sopenharmony_ci /* minus 4, we don't want the CRC */ 11098c2ecf20Sopenharmony_ci struct sk_buff *skb; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (pkt_len > 1518) { 11128c2ecf20Sopenharmony_ci netdev_err(dev, "Packet length %i is bogus\n", pkt_len); 11138c2ecf20Sopenharmony_ci pkt_len = 1518; 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(dev, pkt_len + 2); 11178c2ecf20Sopenharmony_ci if (skb == NULL) { 11188c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 11198c2ecf20Sopenharmony_ci goto out; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci skb_reserve(skb, 2); 11228c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, 11238c2ecf20Sopenharmony_ci &card->rx_buffer[bufferoffset / 4], 11248c2ecf20Sopenharmony_ci pkt_len); 11258c2ecf20Sopenharmony_ci skb_put(skb, pkt_len); 11268c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 11278c2ecf20Sopenharmony_ci netif_rx(skb); 11288c2ecf20Sopenharmony_ci dev->stats.rx_packets++; 11298c2ecf20Sopenharmony_ci dev->stats.rx_bytes += pkt_len; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ciout: 11328c2ecf20Sopenharmony_ci /* give the buffer back to the card */ 11338c2ecf20Sopenharmony_ci card->rx_buffer[4*descnr] = cpu_to_le32(0x80000000); 11348c2ecf20Sopenharmony_ci trigger_receive(card); 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci/* Bufferoffset is in BYTES */ 11408c2ecf20Sopenharmony_cistatic void 11418c2ecf20Sopenharmony_ciinvestigate_write_descriptor(struct net_device *dev, 11428c2ecf20Sopenharmony_ci struct xircom_private *card, 11438c2ecf20Sopenharmony_ci int descnr, unsigned int bufferoffset) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci int status; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci status = le32_to_cpu(card->tx_buffer[4*descnr]); 11488c2ecf20Sopenharmony_ci#if 0 11498c2ecf20Sopenharmony_ci if (status & 0x8000) { /* Major error */ 11508c2ecf20Sopenharmony_ci pr_err("Major transmit error status %x\n", status); 11518c2ecf20Sopenharmony_ci card->tx_buffer[4*descnr] = 0; 11528c2ecf20Sopenharmony_ci netif_wake_queue (dev); 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci#endif 11558c2ecf20Sopenharmony_ci if (status > 0) { /* bit 31 is 0 when done */ 11568c2ecf20Sopenharmony_ci if (card->tx_skb[descnr]!=NULL) { 11578c2ecf20Sopenharmony_ci dev->stats.tx_bytes += card->tx_skb[descnr]->len; 11588c2ecf20Sopenharmony_ci dev_kfree_skb_irq(card->tx_skb[descnr]); 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci card->tx_skb[descnr] = NULL; 11618c2ecf20Sopenharmony_ci /* Bit 8 in the status field is 1 if there was a collision */ 11628c2ecf20Sopenharmony_ci if (status & (1 << 8)) 11638c2ecf20Sopenharmony_ci dev->stats.collisions++; 11648c2ecf20Sopenharmony_ci card->tx_buffer[4*descnr] = 0; /* descriptor is free again */ 11658c2ecf20Sopenharmony_ci netif_wake_queue (dev); 11668c2ecf20Sopenharmony_ci dev->stats.tx_packets++; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cimodule_pci_driver(xircom_ops); 1171