11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
479add6277396b91c638f16eb2f1338badc47760dJustin P. Mattock * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6a4d4d5181d043ea835c15da6c85a5bbecbaded6eRalf Baechle
7a4d4d5181d043ea835c15da6c85a5bbecbaded6eRalf Baechle#undef DEBUG
8a4d4d5181d043ea835c15da6c85a5bbecbaded6eRalf Baechle
9b7f080cfe223b3b7424872639d153695615a9255Alexey Dobriyan#include <linux/dma-mapping.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
125a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
20df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle#include <linux/platform_device.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sgi/hpc3.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sgi/ip22.h>
26df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle#include <asm/sgi/seeq.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sgiseeq.h"
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *sgiseeqstr = "SGI Seeq8003";
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If you want speed, you do something silly, it always has worked for me.  So,
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with that in mind, I've decided to make this driver look completely like a
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stupid Lance from a driver architecture perspective.  Only difference is that
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * here our "ring buffer" looks and acts like a real Lance one does but is
3725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * laid out like how the HPC DMA and the Seeq want it to.  You'd be surprised
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * how a stupid idea like this can pay off in performance, not to mention
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * making this driver 2,000 times easier to write. ;-)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Tune these if we tend to run out often etc. */
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SEEQ_RX_BUFFERS  16
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SEEQ_TX_BUFFERS  16
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_BUF_SZ       1584
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NEXT_RX(i)  (((i) + 1) & (SEEQ_RX_BUFFERS - 1))
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NEXT_TX(i)  (((i) + 1) & (SEEQ_TX_BUFFERS - 1))
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PREV_RX(i)  (((i) - 1) & (SEEQ_RX_BUFFERS - 1))
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PREV_TX(i)  (((i) - 1) & (SEEQ_TX_BUFFERS - 1))
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_BUFFS_AVAIL(sp) ((sp->tx_old <= sp->tx_new) ? \
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    sp->tx_old + (SEEQ_TX_BUFFERS - 1) - sp->tx_new : \
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    sp->tx_old - sp->tx_new - 1)
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer#define VIRT_TO_DMA(sp, v) ((sp)->srings_dma +                                 \
5843831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				  (dma_addr_t)((unsigned long)(v) -            \
5943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					       (unsigned long)((sp)->rx_desc)))
6043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer
6143831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer/* Copy frames shorter than rx_copybreak, otherwise pass on up in
6243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
6343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer */
6443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerferstatic int rx_copybreak = 100;
6543831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer
6643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer#define PAD_SIZE    (128 - sizeof(struct hpc_dma_desc) - sizeof(void *))
6743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sgiseeq_rx_desc {
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct hpc_dma_desc rdma;
7043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	u8 padding[PAD_SIZE];
7143831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	struct sk_buff *skb;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sgiseeq_tx_desc {
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct hpc_dma_desc tdma;
7643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	u8 padding[PAD_SIZE];
7743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	struct sk_buff *skb;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Warning: This structure is laid out in a certain way because HPC dma
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *          descriptors must be 8-byte aligned.  So don't touch this without
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *          some care.
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sgiseeq_init_block { /* Note the name ;-) */
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_rx_desc rxvector[SEEQ_RX_BUFFERS];
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_tx_desc txvector[SEEQ_TX_BUFFERS];
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sgiseeq_private {
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_init_block *srings;
9299cd149efe824cf27c5d34506002a0fbfa831c0fRalf Baechle	dma_addr_t srings_dma;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Ptrs to the descriptors in uncached space. */
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_rx_desc *rx_desc;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_tx_desc *tx_desc;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *name;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hpc3_ethregs *hregs;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_regs *sregs;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Ring entry counters. */
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int rx_new, tx_new;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int rx_old, tx_old;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int is_edlc;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char control;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char mode;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t tx_lock;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11349b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerferstatic inline void dma_sync_desc_cpu(struct net_device *dev, void *addr)
11449b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer{
11549b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc),
11649b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		       DMA_FROM_DEVICE);
11749b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer}
11849b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer
11949b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerferstatic inline void dma_sync_desc_dev(struct net_device *dev, void *addr)
12049b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer{
12149b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc),
12249b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		       DMA_TO_DEVICE);
12349b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer}
12449b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void hpc3_eth_reset(struct hpc3_ethregs *hregs)
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
127302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf Baechle	hregs->reset = HPC3_ERST_CRESET | HPC3_ERST_CLRIRQ;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(20);
129302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf Baechle	hregs->reset = 0;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void reset_hpc3_and_seeq(struct hpc3_ethregs *hregs,
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       struct sgiseeq_regs *sregs)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hregs->rx_ctrl = hregs->tx_ctrl = 0;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hpc3_eth_reset(hregs);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RSTAT_GO_BITS (SEEQ_RCMD_IGOOD | SEEQ_RCMD_IEOF | SEEQ_RCMD_ISHORT | \
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       SEEQ_RCMD_IDRIB | SEEQ_RCMD_ICRC)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void seeq_go(struct sgiseeq_private *sp,
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   struct hpc3_ethregs *hregs,
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   struct sgiseeq_regs *sregs)
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sregs->rstat = sp->mode | RSTAT_GO_BITS;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hregs->rx_ctrl = HPC3_ERXCTRL_ACTIVE;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __sgiseeq_set_mac_address(struct net_device *dev)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_private *sp = netdev_priv(dev);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_regs *sregs = sp->sregs;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sregs->tstat = SEEQ_TCMD_RB0;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 6; i++)
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sregs->rw.eth_addr[i] = dev->dev_addr[i];
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sgiseeq_set_mac_address(struct net_device *dev, void *addr)
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_private *sp = netdev_priv(dev);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sockaddr *sa = addr;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&sp->tx_lock);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__sgiseeq_set_mac_address(dev);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&sp->tx_lock);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TCNTINFO_INIT (HPCDMA_EOX | HPCDMA_ETXD)
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RCNTCFG_INIT  (HPCDMA_OWN | HPCDMA_EORP | HPCDMA_XIE)
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RCNTINFO_INIT (RCNTCFG_INIT | (PKT_BUF_SZ & HPCDMA_BCNT))
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int seeq_init_ring(struct net_device *dev)
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_private *sp = netdev_priv(dev);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->rx_new = sp->tx_new = 0;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->rx_old = sp->tx_old = 0;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__sgiseeq_set_mac_address(dev);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup tx ring. */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0; i < SEEQ_TX_BUFFERS; i++) {
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sp->tx_desc[i].tdma.cntinfo = TCNTINFO_INIT;
19349b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		dma_sync_desc_dev(dev, &sp->tx_desc[i]);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* And now the rx ring. */
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < SEEQ_RX_BUFFERS; i++) {
198a24a789cc6b0a736759bd221b0a32f9a240c2f6eThomas Bogendoerfer		if (!sp->rx_desc[i].skb) {
19943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			dma_addr_t dma_addr;
20043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			struct sk_buff *skb = netdev_alloc_skb(dev, PKT_BUF_SZ);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			if (skb == NULL)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
20443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			skb_reserve(skb, 2);
20543831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			dma_addr = dma_map_single(dev->dev.parent,
20643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer						  skb->data - 2,
20743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer						  PKT_BUF_SZ, DMA_FROM_DEVICE);
20843831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			sp->rx_desc[i].skb = skb;
20943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			sp->rx_desc[i].rdma.pbuf = dma_addr;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sp->rx_desc[i].rdma.cntinfo = RCNTINFO_INIT;
21249b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		dma_sync_desc_dev(dev, &sp->rx_desc[i]);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->rx_desc[i - 1].rdma.cntinfo |= HPCDMA_EOR;
21549b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_sync_desc_dev(dev, &sp->rx_desc[i - 1]);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerferstatic void seeq_purge_ring(struct net_device *dev)
22043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer{
22143831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	struct sgiseeq_private *sp = netdev_priv(dev);
22243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	int i;
22343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer
22443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	/* clear tx ring. */
22543831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	for (i = 0; i < SEEQ_TX_BUFFERS; i++) {
22643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		if (sp->tx_desc[i].skb) {
22743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			dev_kfree_skb(sp->tx_desc[i].skb);
22843831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			sp->tx_desc[i].skb = NULL;
22943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		}
23043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	}
23143831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer
23243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	/* And now the rx ring. */
23343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	for (i = 0; i < SEEQ_RX_BUFFERS; i++) {
23443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		if (sp->rx_desc[i].skb) {
23543831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			dev_kfree_skb(sp->rx_desc[i].skb);
23643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			sp->rx_desc[i].skb = NULL;
23743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		}
23843831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	}
23943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer}
24043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sgiseeq_private *gpriv;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *gdev;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
245a4d4d5181d043ea835c15da6c85a5bbecbaded6eRalf Baechlestatic void sgiseeq_dump_rings(void)
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int once;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_rx_desc *r = gpriv->rx_desc;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_tx_desc *t = gpriv->tx_desc;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hpc3_ethregs *hregs = gpriv->hregs;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (once)
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	once++;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("RING DUMP:\n");
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < SEEQ_RX_BUFFERS; i++) {
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("RX [%d]: @(%p) [%08x,%08x,%08x] ",
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       i, (&r[i]), r[i].rdma.pbuf, r[i].rdma.cntinfo,
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       r[i].rdma.pnext);
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i += 1;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("-- [%d]: @(%p) [%08x,%08x,%08x]\n",
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       i, (&r[i]), r[i].rdma.pbuf, r[i].rdma.cntinfo,
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       r[i].rdma.pnext);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < SEEQ_TX_BUFFERS; i++) {
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("TX [%d]: @(%p) [%08x,%08x,%08x] ",
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       i, (&t[i]), t[i].tdma.pbuf, t[i].tdma.cntinfo,
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       t[i].tdma.pnext);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i += 1;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("-- [%d]: @(%p) [%08x,%08x,%08x]\n",
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       i, (&t[i]), t[i].tdma.pbuf, t[i].tdma.cntinfo,
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       t[i].tdma.pnext);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("INFO: [rx_new = %d rx_old=%d] [tx_new = %d tx_old = %d]\n",
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       gpriv->rx_new, gpriv->rx_old, gpriv->tx_new, gpriv->tx_old);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("RREGS: rx_cbptr[%08x] rx_ndptr[%08x] rx_ctrl[%08x]\n",
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       hregs->rx_cbptr, hregs->rx_ndptr, hregs->rx_ctrl);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("TREGS: tx_cbptr[%08x] tx_ndptr[%08x] tx_ctrl[%08x]\n",
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       hregs->tx_cbptr, hregs->tx_ndptr, hregs->tx_ctrl);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TSTAT_INIT_SEEQ (SEEQ_TCMD_IPT|SEEQ_TCMD_I16|SEEQ_TCMD_IC|SEEQ_TCMD_IUF)
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TSTAT_INIT_EDLC ((TSTAT_INIT_SEEQ) | SEEQ_TCMD_RB2)
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     struct sgiseeq_regs *sregs)
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hpc3_ethregs *hregs = sp->hregs;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reset_hpc3_and_seeq(hregs, sregs);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = seeq_init_ring(dev);
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup to field the proper interrupt types. */
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sp->is_edlc) {
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sregs->tstat = TSTAT_INIT_EDLC;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sregs->rw.wregs.control = sp->control;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sregs->rw.wregs.frame_gap = 0;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sregs->tstat = TSTAT_INIT_SEEQ;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	hregs->rx_ndptr = VIRT_TO_DMA(sp, sp->rx_desc);
30843831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	hregs->tx_ndptr = VIRT_TO_DMA(sp, sp->tx_desc);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seeq_go(sp, hregs, sregs);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzikstatic void record_rx_errors(struct net_device *dev, unsigned char status)
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & SEEQ_RSTAT_OVERF ||
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    status & SEEQ_RSTAT_SFRAME)
31809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_over_errors++;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & SEEQ_RSTAT_CERROR)
32009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_crc_errors++;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & SEEQ_RSTAT_DERROR)
32209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_frame_errors++;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & SEEQ_RSTAT_REOF)
32409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_errors++;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void rx_maybe_restart(struct sgiseeq_private *sp,
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    struct hpc3_ethregs *hregs,
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    struct sgiseeq_regs *sregs)
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(hregs->rx_ctrl & HPC3_ERXCTRL_ACTIVE)) {
33243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		hregs->rx_ndptr = VIRT_TO_DMA(sp, sp->rx_desc + sp->rx_new);
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seeq_go(sp, hregs, sregs);
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp,
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct hpc3_ethregs *hregs,
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct sgiseeq_regs *sregs)
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_rx_desc *rd;
342a4d4d5181d043ea835c15da6c85a5bbecbaded6eRalf Baechle	struct sk_buff *skb = NULL;
34343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	struct sk_buff *newskb;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char pkt_status;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len = 0;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int orig_end = PREV_RX(sp->rx_new);
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Service every received packet. */
34943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	rd = &sp->rx_desc[sp->rx_new];
35049b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_sync_desc_cpu(dev, rd);
35143831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	while (!(rd->rdma.cntinfo & HPCDMA_OWN)) {
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3;
35343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		dma_unmap_single(dev->dev.parent, rd->rdma.pbuf,
35443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				 PKT_BUF_SZ, DMA_FROM_DEVICE);
35543831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		pkt_status = rd->skb->data[len];
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pkt_status & SEEQ_RSTAT_FIG) {
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Packet is OK. */
35843831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			/* We don't want to receive our own packets */
35943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			if (memcmp(rd->skb->data + 6, dev->dev_addr, ETH_ALEN)) {
36043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				if (len > rx_copybreak) {
36143831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					skb = rd->skb;
36243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					newskb = netdev_alloc_skb(dev, PKT_BUF_SZ);
36343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					if (!newskb) {
36443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer						newskb = skb;
36543831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer						skb = NULL;
36643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer						goto memory_squeeze;
36743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					}
36843831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					skb_reserve(newskb, 2);
36943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				} else {
37089d71a66c40d629e3b1285def543ab1425558cd5Eric Dumazet					skb = netdev_alloc_skb_ip_align(dev, len);
37189d71a66c40d629e3b1285def543ab1425558cd5Eric Dumazet					if (skb)
37243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer						skb_copy_to_linear_data(skb, rd->skb->data, len);
37389d71a66c40d629e3b1285def543ab1425558cd5Eric Dumazet
37443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					newskb = rd->skb;
37543831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				}
37643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfermemory_squeeze:
37743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				if (skb) {
37843831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					skb_put(skb, len);
37943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					skb->protocol = eth_type_trans(skb, dev);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					netif_rx(skb);
38109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					dev->stats.rx_packets++;
38209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					dev->stats.rx_bytes += len;
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
38443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
38543831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer						dev->name);
38643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					dev->stats.rx_dropped++;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
38943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				/* Silently drop my own packets */
39043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				newskb = rd->skb;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
39309f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			record_rx_errors(dev, pkt_status);
39443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			newskb = rd->skb;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
39643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		rd->skb = newskb;
39743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		rd->rdma.pbuf = dma_map_single(dev->dev.parent,
39843831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					       newskb->data - 2,
39943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer					       PKT_BUF_SZ, DMA_FROM_DEVICE);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Return the entry to the ring pool. */
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rd->rdma.cntinfo = RCNTINFO_INIT;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sp->rx_new = NEXT_RX(sp->rx_new);
40449b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		dma_sync_desc_dev(dev, rd);
40543831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		rd = &sp->rx_desc[sp->rx_new];
40649b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		dma_sync_desc_cpu(dev, rd);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
40849b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_sync_desc_cpu(dev, &sp->rx_desc[orig_end]);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->rx_desc[orig_end].rdma.cntinfo &= ~(HPCDMA_EOR);
41049b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_sync_desc_dev(dev, &sp->rx_desc[orig_end]);
41149b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_sync_desc_cpu(dev, &sp->rx_desc[PREV_RX(sp->rx_new)]);
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->rx_desc[PREV_RX(sp->rx_new)].rdma.cntinfo |= HPCDMA_EOR;
41349b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_sync_desc_dev(dev, &sp->rx_desc[PREV_RX(sp->rx_new)]);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rx_maybe_restart(sp, hregs, sregs);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void tx_maybe_reset_collisions(struct sgiseeq_private *sp,
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     struct sgiseeq_regs *sregs)
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sp->is_edlc) {
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sregs->rw.wregs.control = sp->control & ~(SEEQ_CTRL_XCNT);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sregs->rw.wregs.control = sp->control;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerferstatic inline void kick_tx(struct net_device *dev,
42743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			   struct sgiseeq_private *sp,
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   struct hpc3_ethregs *hregs)
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
43043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	struct sgiseeq_tx_desc *td;
43143831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	int i = sp->tx_old;
43243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If the HPC aint doin nothin, and there are more packets
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * with ETXD cleared and XIU set we must make very certain
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * that we restart the HPC else we risk locking up the
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * adapter.  The following code is only safe iff the HPCDMA
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * is not active!
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
43943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	td = &sp->tx_desc[i];
44049b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_sync_desc_cpu(dev, td);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) ==
44243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	      (HPCDMA_XIU | HPCDMA_ETXD)) {
44343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		i = NEXT_TX(i);
44443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		td = &sp->tx_desc[i];
44549b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		dma_sync_desc_cpu(dev, td);
44643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	}
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (td->tdma.cntinfo & HPCDMA_XIU) {
44843831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		hregs->tx_ndptr = VIRT_TO_DMA(sp, td);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp,
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct hpc3_ethregs *hregs,
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct sgiseeq_regs *sregs)
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_tx_desc *td;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long status = hregs->tx_ctrl;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int j;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tx_maybe_reset_collisions(sp, sregs);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(status & (HPC3_ETXCTRL_ACTIVE | SEEQ_TSTAT_PTRANS))) {
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Oops, HPC detected some sort of error. */
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & SEEQ_TSTAT_R16)
46609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			dev->stats.tx_aborted_errors++;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & SEEQ_TSTAT_UFLOW)
46809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			dev->stats.tx_fifo_errors++;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & SEEQ_TSTAT_LCLS)
47009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			dev->stats.collisions++;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Ack 'em... */
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (j = sp->tx_old; j != sp->tx_new; j = NEXT_TX(j)) {
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		td = &sp->tx_desc[j];
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47749b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		dma_sync_desc_cpu(dev, td);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(td->tdma.cntinfo & (HPCDMA_XIU)))
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(td->tdma.cntinfo & (HPCDMA_ETXD))) {
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!(status & HPC3_ETXCTRL_ACTIVE)) {
48243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				hregs->tx_ndptr = VIRT_TO_DMA(sp, td);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
48709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.tx_packets++;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sp->tx_old = NEXT_TX(sp->tx_old);
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		td->tdma.cntinfo |= HPCDMA_EOX;
49143831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		if (td->skb) {
49243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			dev_kfree_skb_any(td->skb);
49343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			td->skb = NULL;
49443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		}
49549b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		dma_sync_desc_dev(dev, td);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4997d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t sgiseeq_interrupt(int irq, void *dev_id)
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = (struct net_device *) dev_id;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_private *sp = netdev_priv(dev);
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hpc3_ethregs *hregs = sp->hregs;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_regs *sregs = sp->sregs;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&sp->tx_lock);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Ack the IRQ and set software state. */
509302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf Baechle	hregs->reset = HPC3_ERST_CLRIRQ;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Always check for received packets. */
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sgiseeq_rx(dev, sp, hregs, sregs);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Only check for tx acks if we have something queued. */
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sp->tx_old != sp->tx_new)
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sgiseeq_tx(dev, sp, hregs, sregs);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((TX_BUFFS_AVAIL(sp) > 0) && netif_queue_stopped(dev)) {
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_wake_queue(dev);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&sp->tx_lock);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sgiseeq_open(struct net_device *dev)
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_private *sp = netdev_priv(dev);
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_regs *sregs = sp->sregs;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int irq = dev->irq;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (request_irq(irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) {
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Seeq8003: Can't get irq %d\n", dev->irq);
53506d6e6d2e4ef61172f342fddeea5cfa465d81578Nicolas Kaiser		return -EAGAIN;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = init_seeq(dev, sp, sregs);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_free_irq;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_start_queue(dev);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_free_irq:
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(irq, dev);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sgiseeq_close(struct net_device *dev)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_private *sp = netdev_priv(dev);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_regs *sregs = sp->sregs;
5562891439e7378e35534d7eb32f77671dc4d61db4cRalf Baechle	unsigned int irq = dev->irq;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Shutdown the Seeq. */
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reset_hpc3_and_seeq(sp->hregs, sregs);
5622891439e7378e35534d7eb32f77671dc4d61db4cRalf Baechle	free_irq(irq, dev);
56343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	seeq_purge_ring(dev);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int sgiseeq_reset(struct net_device *dev)
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_private *sp = netdev_priv(dev);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_regs *sregs = sp->sregs;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = init_seeq(dev, sp, sregs);
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet	dev->trans_start = jiffies; /* prevent tx timeout */
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_wake_queue(dev);
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_private *sp = netdev_priv(dev);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hpc3_ethregs *hregs = sp->hregs;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_tx_desc *td;
59043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	int len, entry;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&sp->tx_lock, flags);
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup... */
59543831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	len = skb->len;
59643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	if (len < ETH_ZLEN) {
597ce6fbdefb68d46db88170494b277551f955b48e2Julia Lawall		if (skb_padto(skb, ETH_ZLEN)) {
598ce6fbdefb68d46db88170494b277551f955b48e2Julia Lawall			spin_unlock_irqrestore(&sp->tx_lock, flags);
5996ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy			return NETDEV_TX_OK;
600ce6fbdefb68d46db88170494b277551f955b48e2Julia Lawall		}
60143831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		len = ETH_ZLEN;
60243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	}
60343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer
60409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_bytes += len;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry = sp->tx_new;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	td = &sp->tx_desc[entry];
60749b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_sync_desc_cpu(dev, td);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Create entry.  There are so many races with adding a new
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * descriptor to the chain:
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * 1) Assume that the HPC is off processing a DMA chain while
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *    we are changing all of the following.
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * 2) Do no allow the HPC to look at a new descriptor until
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *    we have completely set up it's state.  This means, do
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *    not clear HPCDMA_EOX in the current last descritptor
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *    until the one we are adding looks consistent and could
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *    be processes right now.
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * 3) The tx interrupt code must notice when we've added a new
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *    entry and the HPC got to the end of the chain before we
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *    added this new entry and restarted it.
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
62243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	td->skb = skb;
62343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	td->tdma.pbuf = dma_map_single(dev->dev.parent, skb->data,
62443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				       len, DMA_TO_DEVICE);
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	td->tdma.cntinfo = (len & HPCDMA_BCNT) |
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	                   HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX;
62749b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_sync_desc_dev(dev, td);
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sp->tx_old != sp->tx_new) {
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sgiseeq_tx_desc *backend;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		backend = &sp->tx_desc[PREV_TX(sp->tx_new)];
63249b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		dma_sync_desc_cpu(dev, backend);
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		backend->tdma.cntinfo &= ~HPCDMA_EOX;
63449b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		dma_sync_desc_dev(dev, backend);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Maybe kick the HPC back into motion. */
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(hregs->tx_ctrl & HPC3_ETXCTRL_ACTIVE))
64043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		kick_tx(dev, sp, hregs);
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!TX_BUFFS_AVAIL(sp))
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_stop_queue(dev);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&sp->tx_lock, flags);
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6466ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void timeout(struct net_device *dev)
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_NOTICE "%s: transmit timed out, resetting\n", dev->name);
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sgiseeq_reset(dev);
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6541ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet	dev->trans_start = jiffies; /* prevent tx timeout */
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_wake_queue(dev);
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sgiseeq_set_multicast(struct net_device *dev)
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6608f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct sgiseeq_private *sp = netdev_priv(dev);
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char oldmode = sp->mode;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(dev->flags & IFF_PROMISC)
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sp->mode = SEEQ_RCMD_RANY;
6654cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko	else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev))
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sp->mode = SEEQ_RCMD_RBMCAST;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sp->mode = SEEQ_RCMD_RBCAST;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* XXX I know this sucks, but is there a better way to reprogram
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * XXX the receiver? At least, this shouldn't happen too often.
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (oldmode != sp->mode)
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sgiseeq_reset(dev);
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67843831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerferstatic inline void setup_tx_ring(struct net_device *dev,
67943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				 struct sgiseeq_tx_desc *buf,
68043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				 int nbufs)
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
68243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	struct sgiseeq_private *sp = netdev_priv(dev);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (i < (nbufs - 1)) {
68643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		buf[i].tdma.pnext = VIRT_TO_DMA(sp, buf + i + 1);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[i].tdma.pbuf = 0;
68849b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		dma_sync_desc_dev(dev, &buf[i]);
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i++;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
69143831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	buf[i].tdma.pnext = VIRT_TO_DMA(sp, buf);
69249b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_sync_desc_dev(dev, &buf[i]);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69543831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerferstatic inline void setup_rx_ring(struct net_device *dev,
69643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				 struct sgiseeq_rx_desc *buf,
69743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer				 int nbufs)
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
69943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	struct sgiseeq_private *sp = netdev_priv(dev);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 0;
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (i < (nbufs - 1)) {
70343831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer		buf[i].rdma.pnext = VIRT_TO_DMA(sp, buf + i + 1);
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf[i].rdma.pbuf = 0;
70549b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer		dma_sync_desc_dev(dev, &buf[i]);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i++;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[i].rdma.pbuf = 0;
70943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	buf[i].rdma.pnext = VIRT_TO_DMA(sp, buf);
71049b11bc3d43eb287fc9d78e1a892e97288980d49Thomas Bogendoerfer	dma_sync_desc_dev(dev, &buf[i]);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7138c2c6be186097aafd8f8a17927203b457545cc69Alexander Beregalovstatic const struct net_device_ops sgiseeq_netdev_ops = {
7148c2c6be186097aafd8f8a17927203b457545cc69Alexander Beregalov	.ndo_open		= sgiseeq_open,
7158c2c6be186097aafd8f8a17927203b457545cc69Alexander Beregalov	.ndo_stop		= sgiseeq_close,
7168c2c6be186097aafd8f8a17927203b457545cc69Alexander Beregalov	.ndo_start_xmit		= sgiseeq_start_xmit,
7178c2c6be186097aafd8f8a17927203b457545cc69Alexander Beregalov	.ndo_tx_timeout		= timeout,
718afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= sgiseeq_set_multicast,
7198c2c6be186097aafd8f8a17927203b457545cc69Alexander Beregalov	.ndo_set_mac_address	= sgiseeq_set_mac_address,
7208c2c6be186097aafd8f8a17927203b457545cc69Alexander Beregalov	.ndo_change_mtu		= eth_change_mtu,
7218c2c6be186097aafd8f8a17927203b457545cc69Alexander Beregalov	.ndo_validate_addr	= eth_validate_addr,
7228c2c6be186097aafd8f8a17927203b457545cc69Alexander Beregalov};
7238c2c6be186097aafd8f8a17927203b457545cc69Alexander Beregalov
724a65a688182cd7f5b69bd6dd9022be96ea771642cUwe Kleine-Königstatic int __devinit sgiseeq_probe(struct platform_device *pdev)
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
726df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	struct sgiseeq_platform_data *pd = pdev->dev.platform_data;
727df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	struct hpc3_regs *hpcregs = pd->hpc;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_init_block *sr;
729df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	unsigned int irq = pd->irq;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sgiseeq_private *sp;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
73243831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	int err;
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = alloc_etherdev(sizeof (struct sgiseeq_private));
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev) {
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
739df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle
740df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	platform_set_drvdata(pdev, dev);
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp = netdev_priv(dev);
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make private data page aligned */
74443831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	sr = dma_alloc_noncoherent(&pdev->dev, sizeof(*sp->srings),
74599cd149efe824cf27c5d34506002a0fbfa831c0fRalf Baechle				&sp->srings_dma, GFP_KERNEL);
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sr) {
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n");
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out_free_dev;
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->srings = sr;
75299cd149efe824cf27c5d34506002a0fbfa831c0fRalf Baechle	sp->rx_desc = sp->srings->rxvector;
75399cd149efe824cf27c5d34506002a0fbfa831c0fRalf Baechle	sp->tx_desc = sp->srings->txvector;
75499cd149efe824cf27c5d34506002a0fbfa831c0fRalf Baechle
75599cd149efe824cf27c5d34506002a0fbfa831c0fRalf Baechle	/* A couple calculations now, saves many cycles later. */
75643831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	setup_rx_ring(dev, sp->rx_desc, SEEQ_RX_BUFFERS);
75743831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	setup_tx_ring(dev, sp->tx_desc, SEEQ_TX_BUFFERS);
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
759df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	memcpy(dev->dev_addr, pd->mac, ETH_ALEN);
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gpriv = sp;
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gdev = dev;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
765302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf Baechle	sp->sregs = (struct sgiseeq_regs *) &hpcregs->eth_ext[0];
766302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf Baechle	sp->hregs = &hpcregs->ethregs;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->name = sgiseeqstr;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->mode = SEEQ_RCMD_RBCAST;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
770302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf Baechle	/* Setup PIO and DMA transfer timing */
771302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf Baechle	sp->hregs->pconfig = 0x161;
772302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf Baechle	sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
773302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf Baechle			     HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
774302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf Baechle
77578ee5b3cc88297bb98843c24b231e99f3f2886a0Ladislav Michl	/* Setup PIO and DMA transfer timing */
77678ee5b3cc88297bb98843c24b231e99f3f2886a0Ladislav Michl	sp->hregs->pconfig = 0x161;
77778ee5b3cc88297bb98843c24b231e99f3f2886a0Ladislav Michl	sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
77878ee5b3cc88297bb98843c24b231e99f3f2886a0Ladislav Michl			     HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
77978ee5b3cc88297bb98843c24b231e99f3f2886a0Ladislav Michl
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset the chip. */
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hpc3_eth_reset(sp->hregs);
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sp->is_edlc = !(sp->sregs->rw.rregs.collision_tx[0] & 0xff);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sp->is_edlc)
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sp->control = SEEQ_CTRL_XCNT | SEEQ_CTRL_ACCNT |
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT |
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      SEEQ_CTRL_ENCARR;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7898c2c6be186097aafd8f8a17927203b457545cc69Alexander Beregalov	dev->netdev_ops		= &sgiseeq_netdev_ops;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->watchdog_timeo	= (200 * HZ) / 1000;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->irq		= irq;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (register_netdev(dev)) {
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Sgiseeq: Cannot register net device, "
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "aborting.\n");
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENODEV;
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out_free_page;
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
800e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg	printk(KERN_INFO "%s: %s %pM\n", dev->name, sgiseeqstr, dev->dev_addr);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out_free_page:
8052891439e7378e35534d7eb32f77671dc4d61db4cRalf Baechle	free_page((unsigned long) sp->srings);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out_free_dev:
8078d879de89807d82bc4cc3e9d73609b874fa9458cKulikov Vasiliy	free_netdev(dev);
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
813e3efb05468128e834cf17d492822333c6e189ae4Ralf Baechlestatic int __exit sgiseeq_remove(struct platform_device *pdev)
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
815df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	struct net_device *dev = platform_get_drvdata(pdev);
816df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	struct sgiseeq_private *sp = netdev_priv(dev);
81778ee5b3cc88297bb98843c24b231e99f3f2886a0Ladislav Michl
818df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	unregister_netdev(dev);
81943831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer	dma_free_noncoherent(&pdev->dev, sizeof(*sp->srings), sp->srings,
82043831b1581031991357385dd6c0762c06a3a62abThomas Bogendoerfer			     sp->srings_dma);
821df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	free_netdev(dev);
822df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	platform_set_drvdata(pdev, NULL);
823e3efb05468128e834cf17d492822333c6e189ae4Ralf Baechle
824e3efb05468128e834cf17d492822333c6e189ae4Ralf Baechle	return 0;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
827df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechlestatic struct platform_driver sgiseeq_driver = {
828df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	.probe	= sgiseeq_probe,
829fb74c2fcac05fced50cd11b8e8dcecede1d4d880Uwe Kleine-König	.remove	= __exit_p(sgiseeq_remove),
830df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	.driver = {
83172abb46101fb5c47a9592914adb221b430ff26bdKay Sievers		.name	= "sgiseeq",
83272abb46101fb5c47a9592914adb221b430ff26bdKay Sievers		.owner	= THIS_MODULE,
833df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle	}
834df9f54084f1faf611cedd846d38b0631f9d4e9a5Ralf Baechle};
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
836db62f684deeb291ab2533b99843d5df9a36b1f19Axel Linmodule_platform_driver(sgiseeq_driver);
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
838302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf BaechleMODULE_DESCRIPTION("SGI Seeq 8003 driver");
839302a5c4b3d4d6aff7772a4b3431bb772586e6011Ralf BaechleMODULE_AUTHOR("Linux/MIPS Mailing List <linux-mips@linux-mips.org>");
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
84172abb46101fb5c47a9592914adb221b430ff26bdKay SieversMODULE_ALIAS("platform:sgiseeq");
842