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