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