1c1b6a3d8SThomas Bogendoerfer // SPDX-License-Identifier: GPL-2.0
2c1b6a3d8SThomas Bogendoerfer /* Driver for SGI's IOC3 based Ethernet cards as found in the PCI card.
38862bf1eSJeff Kirsher  *
48862bf1eSJeff Kirsher  * Copyright (C) 1999, 2000, 01, 03, 06 Ralf Baechle
58862bf1eSJeff Kirsher  * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc.
68862bf1eSJeff Kirsher  *
78862bf1eSJeff Kirsher  * References:
88862bf1eSJeff Kirsher  *  o IOC3 ASIC specification 4.51, 1996-04-18
98862bf1eSJeff Kirsher  *  o IEEE 802.3 specification, 2000 edition
108862bf1eSJeff Kirsher  *  o DP38840A Specification, National Semiconductor, March 1997
118862bf1eSJeff Kirsher  *
128862bf1eSJeff Kirsher  * To do:
138862bf1eSJeff Kirsher  *
148862bf1eSJeff Kirsher  *  o Use prefetching for large packets.  What is a good lower limit for
158862bf1eSJeff Kirsher  *    prefetching?
168862bf1eSJeff Kirsher  *  o Use hardware checksums.
178862bf1eSJeff Kirsher  *  o Which PHYs might possibly be attached to the IOC3 in real live,
188862bf1eSJeff Kirsher  *    which workarounds are required for them?  Do we ever have Lucent's?
198862bf1eSJeff Kirsher  *  o For the 2.5 branch kill the mii-tool ioctls.
208862bf1eSJeff Kirsher  */
218862bf1eSJeff Kirsher 
228862bf1eSJeff Kirsher #define IOC3_NAME	"ioc3-eth"
238862bf1eSJeff Kirsher #define IOC3_VERSION	"2.6.3-4"
248862bf1eSJeff Kirsher 
258862bf1eSJeff Kirsher #include <linux/delay.h>
268862bf1eSJeff Kirsher #include <linux/kernel.h>
278862bf1eSJeff Kirsher #include <linux/mm.h>
288862bf1eSJeff Kirsher #include <linux/errno.h>
298862bf1eSJeff Kirsher #include <linux/module.h>
300ce5ebd2SThomas Bogendoerfer #include <linux/init.h>
310ce5ebd2SThomas Bogendoerfer #include <linux/crc16.h>
328862bf1eSJeff Kirsher #include <linux/crc32.h>
338862bf1eSJeff Kirsher #include <linux/mii.h>
348862bf1eSJeff Kirsher #include <linux/in.h>
35c1b6a3d8SThomas Bogendoerfer #include <linux/io.h>
368862bf1eSJeff Kirsher #include <linux/ip.h>
378862bf1eSJeff Kirsher #include <linux/tcp.h>
388862bf1eSJeff Kirsher #include <linux/udp.h>
398862bf1eSJeff Kirsher #include <linux/gfp.h>
408862bf1eSJeff Kirsher #include <linux/netdevice.h>
418862bf1eSJeff Kirsher #include <linux/etherdevice.h>
428862bf1eSJeff Kirsher #include <linux/ethtool.h>
438862bf1eSJeff Kirsher #include <linux/skbuff.h>
444dd14747SChristoph Hellwig #include <linux/dma-mapping.h>
450ce5ebd2SThomas Bogendoerfer #include <linux/platform_device.h>
460ce5ebd2SThomas Bogendoerfer #include <linux/nvmem-consumer.h>
47ed870f6aSThomas Bogendoerfer 
488862bf1eSJeff Kirsher #include <net/ip.h>
498862bf1eSJeff Kirsher 
508862bf1eSJeff Kirsher #include <asm/sn/ioc3.h>
518862bf1eSJeff Kirsher #include <asm/pci/bridge.h>
528862bf1eSJeff Kirsher 
530ce5ebd2SThomas Bogendoerfer #define CRC16_INIT	0
540ce5ebd2SThomas Bogendoerfer #define CRC16_VALID	0xb001
550ce5ebd2SThomas Bogendoerfer 
56141a7dbbSThomas Bogendoerfer /* Number of RX buffers.  This is tunable in the range of 16 <= x < 512.
57141a7dbbSThomas Bogendoerfer  * The value must be a power of two.
588862bf1eSJeff Kirsher  */
598862bf1eSJeff Kirsher #define RX_BUFFS		64
60141a7dbbSThomas Bogendoerfer #define RX_RING_ENTRIES		512		/* fixed in hardware */
61141a7dbbSThomas Bogendoerfer #define RX_RING_MASK		(RX_RING_ENTRIES - 1)
62ed870f6aSThomas Bogendoerfer #define RX_RING_SIZE		(RX_RING_ENTRIES * sizeof(u64))
63141a7dbbSThomas Bogendoerfer 
64141a7dbbSThomas Bogendoerfer /* 128 TX buffers (not tunable) */
65141a7dbbSThomas Bogendoerfer #define TX_RING_ENTRIES		128
66141a7dbbSThomas Bogendoerfer #define TX_RING_MASK		(TX_RING_ENTRIES - 1)
67ed870f6aSThomas Bogendoerfer #define TX_RING_SIZE		(TX_RING_ENTRIES * sizeof(struct ioc3_etxd))
688862bf1eSJeff Kirsher 
69850d2fedSThomas Bogendoerfer /* IOC3 does dma transfers in 128 byte blocks */
70850d2fedSThomas Bogendoerfer #define IOC3_DMA_XFER_LEN	128UL
71850d2fedSThomas Bogendoerfer 
72850d2fedSThomas Bogendoerfer /* Every RX buffer starts with 8 byte descriptor data */
73850d2fedSThomas Bogendoerfer #define RX_OFFSET		(sizeof(struct ioc3_erxbuf) + NET_IP_ALIGN)
74850d2fedSThomas Bogendoerfer #define RX_BUF_SIZE		(13 * IOC3_DMA_XFER_LEN)
75850d2fedSThomas Bogendoerfer 
763498cb27SThomas Bogendoerfer #define ETCSR_FD   ((21 << ETCSR_IPGR2_SHIFT) | (21 << ETCSR_IPGR1_SHIFT) | 21)
773498cb27SThomas Bogendoerfer #define ETCSR_HD   ((17 << ETCSR_IPGR2_SHIFT) | (11 << ETCSR_IPGR1_SHIFT) | 21)
788862bf1eSJeff Kirsher 
798862bf1eSJeff Kirsher /* Private per NIC data of the driver.  */
808862bf1eSJeff Kirsher struct ioc3_private {
81cbe7d517SThomas Bogendoerfer 	struct ioc3_ethregs *regs;
82ed870f6aSThomas Bogendoerfer 	struct device *dma_dev;
83cbe7d517SThomas Bogendoerfer 	u32 *ssram;
848862bf1eSJeff Kirsher 	unsigned long *rxr;		/* pointer to receiver ring */
85369a782aSThomas Bogendoerfer 	void *tx_ring;
868862bf1eSJeff Kirsher 	struct ioc3_etxd *txr;
87ed870f6aSThomas Bogendoerfer 	dma_addr_t rxr_dma;
88ed870f6aSThomas Bogendoerfer 	dma_addr_t txr_dma;
89141a7dbbSThomas Bogendoerfer 	struct sk_buff *rx_skbs[RX_RING_ENTRIES];
90141a7dbbSThomas Bogendoerfer 	struct sk_buff *tx_skbs[TX_RING_ENTRIES];
918862bf1eSJeff Kirsher 	int rx_ci;			/* RX consumer index */
928862bf1eSJeff Kirsher 	int rx_pi;			/* RX producer index */
938862bf1eSJeff Kirsher 	int tx_ci;			/* TX consumer index */
948862bf1eSJeff Kirsher 	int tx_pi;			/* TX producer index */
958862bf1eSJeff Kirsher 	int txqlen;
968862bf1eSJeff Kirsher 	u32 emcr, ehar_h, ehar_l;
978862bf1eSJeff Kirsher 	spinlock_t ioc3_lock;
988862bf1eSJeff Kirsher 	struct mii_if_info mii;
998862bf1eSJeff Kirsher 
1008862bf1eSJeff Kirsher 	/* Members used by autonegotiation  */
1018862bf1eSJeff Kirsher 	struct timer_list ioc3_timer;
1028862bf1eSJeff Kirsher };
1038862bf1eSJeff Kirsher 
1048862bf1eSJeff Kirsher static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
1058862bf1eSJeff Kirsher static void ioc3_set_multicast_list(struct net_device *dev);
10628d304efSYueHaibing static netdev_tx_t ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev);
1070290bd29SMichael S. Tsirkin static void ioc3_timeout(struct net_device *dev, unsigned int txqueue);
1088862bf1eSJeff Kirsher static inline unsigned int ioc3_hash(const unsigned char *addr);
109fcd0da5aSThomas Bogendoerfer static void ioc3_start(struct ioc3_private *ip);
1108862bf1eSJeff Kirsher static inline void ioc3_stop(struct ioc3_private *ip);
1118862bf1eSJeff Kirsher static void ioc3_init(struct net_device *dev);
112850d2fedSThomas Bogendoerfer static int ioc3_alloc_rx_bufs(struct net_device *dev);
11319a957b6SThomas Bogendoerfer static void ioc3_free_rx_bufs(struct ioc3_private *ip);
11419a957b6SThomas Bogendoerfer static inline void ioc3_clean_tx_ring(struct ioc3_private *ip);
1158862bf1eSJeff Kirsher 
1168862bf1eSJeff Kirsher static const struct ethtool_ops ioc3_ethtool_ops;
1178862bf1eSJeff Kirsher 
aligned_rx_skb_addr(unsigned long addr)1188862bf1eSJeff Kirsher static inline unsigned long aligned_rx_skb_addr(unsigned long addr)
1198862bf1eSJeff Kirsher {
120850d2fedSThomas Bogendoerfer 	return (~addr + 1) & (IOC3_DMA_XFER_LEN - 1UL);
1218862bf1eSJeff Kirsher }
1228862bf1eSJeff Kirsher 
ioc3_alloc_skb(struct ioc3_private * ip,struct sk_buff ** skb,struct ioc3_erxbuf ** rxb,dma_addr_t * rxb_dma)123ed870f6aSThomas Bogendoerfer static inline int ioc3_alloc_skb(struct ioc3_private *ip, struct sk_buff **skb,
124ed870f6aSThomas Bogendoerfer 				 struct ioc3_erxbuf **rxb, dma_addr_t *rxb_dma)
1258862bf1eSJeff Kirsher {
126850d2fedSThomas Bogendoerfer 	struct sk_buff *new_skb;
127ed870f6aSThomas Bogendoerfer 	dma_addr_t d;
128850d2fedSThomas Bogendoerfer 	int offset;
1298862bf1eSJeff Kirsher 
130850d2fedSThomas Bogendoerfer 	new_skb = alloc_skb(RX_BUF_SIZE + IOC3_DMA_XFER_LEN - 1, GFP_ATOMIC);
131850d2fedSThomas Bogendoerfer 	if (!new_skb)
132850d2fedSThomas Bogendoerfer 		return -ENOMEM;
133c1b6a3d8SThomas Bogendoerfer 
134850d2fedSThomas Bogendoerfer 	/* ensure buffer is aligned to IOC3_DMA_XFER_LEN */
135850d2fedSThomas Bogendoerfer 	offset = aligned_rx_skb_addr((unsigned long)new_skb->data);
1368862bf1eSJeff Kirsher 	if (offset)
137850d2fedSThomas Bogendoerfer 		skb_reserve(new_skb, offset);
1388862bf1eSJeff Kirsher 
139ed870f6aSThomas Bogendoerfer 	d = dma_map_single(ip->dma_dev, new_skb->data,
140ed870f6aSThomas Bogendoerfer 			   RX_BUF_SIZE, DMA_FROM_DEVICE);
141ed870f6aSThomas Bogendoerfer 
142ed870f6aSThomas Bogendoerfer 	if (dma_mapping_error(ip->dma_dev, d)) {
143ed870f6aSThomas Bogendoerfer 		dev_kfree_skb_any(new_skb);
144ed870f6aSThomas Bogendoerfer 		return -ENOMEM;
145ed870f6aSThomas Bogendoerfer 	}
146ed870f6aSThomas Bogendoerfer 	*rxb_dma = d;
147850d2fedSThomas Bogendoerfer 	*rxb = (struct ioc3_erxbuf *)new_skb->data;
148850d2fedSThomas Bogendoerfer 	skb_reserve(new_skb, RX_OFFSET);
149850d2fedSThomas Bogendoerfer 	*skb = new_skb;
150850d2fedSThomas Bogendoerfer 
151850d2fedSThomas Bogendoerfer 	return 0;
1528862bf1eSJeff Kirsher }
1538862bf1eSJeff Kirsher 
154ed870f6aSThomas Bogendoerfer #ifdef CONFIG_PCI_XTALK_BRIDGE
ioc3_map(dma_addr_t addr,unsigned long attr)155ed870f6aSThomas Bogendoerfer static inline unsigned long ioc3_map(dma_addr_t addr, unsigned long attr)
1568862bf1eSJeff Kirsher {
157ed870f6aSThomas Bogendoerfer 	return (addr & ~PCI64_ATTR_BAR) | attr;
1588862bf1eSJeff Kirsher }
159ed870f6aSThomas Bogendoerfer 
160ed870f6aSThomas Bogendoerfer #define ERBAR_VAL	(ERBAR_BARRIER_BIT << ERBAR_RXBARR_SHIFT)
161ed870f6aSThomas Bogendoerfer #else
ioc3_map(dma_addr_t addr,unsigned long attr)162ed870f6aSThomas Bogendoerfer static inline unsigned long ioc3_map(dma_addr_t addr, unsigned long attr)
163ed870f6aSThomas Bogendoerfer {
164ed870f6aSThomas Bogendoerfer 	return addr;
165ed870f6aSThomas Bogendoerfer }
166ed870f6aSThomas Bogendoerfer 
167ed870f6aSThomas Bogendoerfer #define ERBAR_VAL	0
168ed870f6aSThomas Bogendoerfer #endif
169ed870f6aSThomas Bogendoerfer 
ioc3eth_nvmem_match(struct device * dev,const void * data)1700ce5ebd2SThomas Bogendoerfer static int ioc3eth_nvmem_match(struct device *dev, const void *data)
1718862bf1eSJeff Kirsher {
1720ce5ebd2SThomas Bogendoerfer 	const char *name = dev_name(dev);
1730ce5ebd2SThomas Bogendoerfer 	const char *prefix = data;
1740ce5ebd2SThomas Bogendoerfer 	int prefix_len;
1758862bf1eSJeff Kirsher 
1760ce5ebd2SThomas Bogendoerfer 	prefix_len = strlen(prefix);
1770ce5ebd2SThomas Bogendoerfer 	if (strlen(name) < (prefix_len + 3))
1788862bf1eSJeff Kirsher 		return 0;
1798862bf1eSJeff Kirsher 
1800ce5ebd2SThomas Bogendoerfer 	if (memcmp(prefix, name, prefix_len) != 0)
1810ce5ebd2SThomas Bogendoerfer 		return 0;
1828862bf1eSJeff Kirsher 
1830ce5ebd2SThomas Bogendoerfer 	/* found nvmem device which is attached to our ioc3
1840ce5ebd2SThomas Bogendoerfer 	 * now check for one wire family code 09, 89 and 91
1850ce5ebd2SThomas Bogendoerfer 	 */
1860ce5ebd2SThomas Bogendoerfer 	if (memcmp(name + prefix_len, "09-", 3) == 0)
1870ce5ebd2SThomas Bogendoerfer 		return 1;
1880ce5ebd2SThomas Bogendoerfer 	if (memcmp(name + prefix_len, "89-", 3) == 0)
1890ce5ebd2SThomas Bogendoerfer 		return 1;
1900ce5ebd2SThomas Bogendoerfer 	if (memcmp(name + prefix_len, "91-", 3) == 0)
1910ce5ebd2SThomas Bogendoerfer 		return 1;
1928862bf1eSJeff Kirsher 
1938862bf1eSJeff Kirsher 	return 0;
1948862bf1eSJeff Kirsher }
1958862bf1eSJeff Kirsher 
ioc3eth_get_mac_addr(struct resource * res,u8 mac_addr[6])1960ce5ebd2SThomas Bogendoerfer static int ioc3eth_get_mac_addr(struct resource *res, u8 mac_addr[6])
1978862bf1eSJeff Kirsher {
1980ce5ebd2SThomas Bogendoerfer 	struct nvmem_device *nvmem;
1990ce5ebd2SThomas Bogendoerfer 	char prefix[24];
2000ce5ebd2SThomas Bogendoerfer 	u8 prom[16];
2010ce5ebd2SThomas Bogendoerfer 	int ret;
2028862bf1eSJeff Kirsher 	int i;
2038862bf1eSJeff Kirsher 
2040ce5ebd2SThomas Bogendoerfer 	snprintf(prefix, sizeof(prefix), "ioc3-%012llx-",
2050ce5ebd2SThomas Bogendoerfer 		 res->start & ~0xffff);
2068862bf1eSJeff Kirsher 
2070ce5ebd2SThomas Bogendoerfer 	nvmem = nvmem_device_find(prefix, ioc3eth_nvmem_match);
2080ce5ebd2SThomas Bogendoerfer 	if (IS_ERR(nvmem))
2090ce5ebd2SThomas Bogendoerfer 		return PTR_ERR(nvmem);
2108862bf1eSJeff Kirsher 
2110ce5ebd2SThomas Bogendoerfer 	ret = nvmem_device_read(nvmem, 0, 16, prom);
2120ce5ebd2SThomas Bogendoerfer 	nvmem_device_put(nvmem);
2130ce5ebd2SThomas Bogendoerfer 	if (ret < 0)
2140ce5ebd2SThomas Bogendoerfer 		return ret;
2158862bf1eSJeff Kirsher 
2160ce5ebd2SThomas Bogendoerfer 	/* check, if content is valid */
2170ce5ebd2SThomas Bogendoerfer 	if (prom[0] != 0x0a ||
2180ce5ebd2SThomas Bogendoerfer 	    crc16(CRC16_INIT, prom, 13) != CRC16_VALID)
2190ce5ebd2SThomas Bogendoerfer 		return -EINVAL;
2208862bf1eSJeff Kirsher 
2210ce5ebd2SThomas Bogendoerfer 	for (i = 0; i < 6; i++)
2220ce5ebd2SThomas Bogendoerfer 		mac_addr[i] = prom[10 - i];
2238862bf1eSJeff Kirsher 
2240ce5ebd2SThomas Bogendoerfer 	return 0;
2258862bf1eSJeff Kirsher }
2268862bf1eSJeff Kirsher 
__ioc3_set_mac_address(struct net_device * dev)2278862bf1eSJeff Kirsher static void __ioc3_set_mac_address(struct net_device *dev)
2288862bf1eSJeff Kirsher {
2298862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
2308862bf1eSJeff Kirsher 
231cbe7d517SThomas Bogendoerfer 	writel((dev->dev_addr[5] <<  8) |
232cbe7d517SThomas Bogendoerfer 	       dev->dev_addr[4],
233cbe7d517SThomas Bogendoerfer 	       &ip->regs->emar_h);
234cbe7d517SThomas Bogendoerfer 	writel((dev->dev_addr[3] << 24) |
235cbe7d517SThomas Bogendoerfer 	       (dev->dev_addr[2] << 16) |
236cbe7d517SThomas Bogendoerfer 	       (dev->dev_addr[1] <<  8) |
237cbe7d517SThomas Bogendoerfer 	       dev->dev_addr[0],
238cbe7d517SThomas Bogendoerfer 	       &ip->regs->emar_l);
2398862bf1eSJeff Kirsher }
2408862bf1eSJeff Kirsher 
ioc3_set_mac_address(struct net_device * dev,void * addr)2418862bf1eSJeff Kirsher static int ioc3_set_mac_address(struct net_device *dev, void *addr)
2428862bf1eSJeff Kirsher {
2438862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
2448862bf1eSJeff Kirsher 	struct sockaddr *sa = addr;
2458862bf1eSJeff Kirsher 
246a05e4c0aSJakub Kicinski 	eth_hw_addr_set(dev, sa->sa_data);
2478862bf1eSJeff Kirsher 
2488862bf1eSJeff Kirsher 	spin_lock_irq(&ip->ioc3_lock);
2498862bf1eSJeff Kirsher 	__ioc3_set_mac_address(dev);
2508862bf1eSJeff Kirsher 	spin_unlock_irq(&ip->ioc3_lock);
2518862bf1eSJeff Kirsher 
2528862bf1eSJeff Kirsher 	return 0;
2538862bf1eSJeff Kirsher }
2548862bf1eSJeff Kirsher 
255c1b6a3d8SThomas Bogendoerfer /* Caller must hold the ioc3_lock ever for MII readers.  This is also
2568862bf1eSJeff Kirsher  * used to protect the transmitter side but it's low contention.
2578862bf1eSJeff Kirsher  */
ioc3_mdio_read(struct net_device * dev,int phy,int reg)2588862bf1eSJeff Kirsher static int ioc3_mdio_read(struct net_device *dev, int phy, int reg)
2598862bf1eSJeff Kirsher {
2608862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
261cbe7d517SThomas Bogendoerfer 	struct ioc3_ethregs *regs = ip->regs;
2628862bf1eSJeff Kirsher 
263cbe7d517SThomas Bogendoerfer 	while (readl(&regs->micr) & MICR_BUSY)
264cbe7d517SThomas Bogendoerfer 		;
265cbe7d517SThomas Bogendoerfer 	writel((phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG,
266cbe7d517SThomas Bogendoerfer 	       &regs->micr);
267cbe7d517SThomas Bogendoerfer 	while (readl(&regs->micr) & MICR_BUSY)
268cbe7d517SThomas Bogendoerfer 		;
2698862bf1eSJeff Kirsher 
270cbe7d517SThomas Bogendoerfer 	return readl(&regs->midr_r) & MIDR_DATA_MASK;
2718862bf1eSJeff Kirsher }
2728862bf1eSJeff Kirsher 
ioc3_mdio_write(struct net_device * dev,int phy,int reg,int data)2738862bf1eSJeff Kirsher static void ioc3_mdio_write(struct net_device *dev, int phy, int reg, int data)
2748862bf1eSJeff Kirsher {
2758862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
276cbe7d517SThomas Bogendoerfer 	struct ioc3_ethregs *regs = ip->regs;
2778862bf1eSJeff Kirsher 
278cbe7d517SThomas Bogendoerfer 	while (readl(&regs->micr) & MICR_BUSY)
279cbe7d517SThomas Bogendoerfer 		;
280cbe7d517SThomas Bogendoerfer 	writel(data, &regs->midr_w);
281cbe7d517SThomas Bogendoerfer 	writel((phy << MICR_PHYADDR_SHIFT) | reg, &regs->micr);
282cbe7d517SThomas Bogendoerfer 	while (readl(&regs->micr) & MICR_BUSY)
283cbe7d517SThomas Bogendoerfer 		;
2848862bf1eSJeff Kirsher }
2858862bf1eSJeff Kirsher 
2868862bf1eSJeff Kirsher static int ioc3_mii_init(struct ioc3_private *ip);
2878862bf1eSJeff Kirsher 
ioc3_get_stats(struct net_device * dev)2888862bf1eSJeff Kirsher static struct net_device_stats *ioc3_get_stats(struct net_device *dev)
2898862bf1eSJeff Kirsher {
2908862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
291cbe7d517SThomas Bogendoerfer 	struct ioc3_ethregs *regs = ip->regs;
2928862bf1eSJeff Kirsher 
293cbe7d517SThomas Bogendoerfer 	dev->stats.collisions += readl(&regs->etcdc) & ETCDC_COLLCNT_MASK;
2948862bf1eSJeff Kirsher 	return &dev->stats;
2958862bf1eSJeff Kirsher }
2968862bf1eSJeff Kirsher 
ioc3_tcpudp_checksum(struct sk_buff * skb,u32 hwsum,int len)297c1b6a3d8SThomas Bogendoerfer static void ioc3_tcpudp_checksum(struct sk_buff *skb, u32 hwsum, int len)
2988862bf1eSJeff Kirsher {
2998862bf1eSJeff Kirsher 	struct ethhdr *eh = eth_hdr(skb);
3008862bf1eSJeff Kirsher 	unsigned int proto;
3018862bf1eSJeff Kirsher 	unsigned char *cp;
302c1b6a3d8SThomas Bogendoerfer 	struct iphdr *ih;
303c1b6a3d8SThomas Bogendoerfer 	u32 csum, ehsum;
304c1b6a3d8SThomas Bogendoerfer 	u16 *ew;
3058862bf1eSJeff Kirsher 
306c1b6a3d8SThomas Bogendoerfer 	/* Did hardware handle the checksum at all?  The cases we can handle
3078862bf1eSJeff Kirsher 	 * are:
3088862bf1eSJeff Kirsher 	 *
3098862bf1eSJeff Kirsher 	 * - TCP and UDP checksums of IPv4 only.
3108862bf1eSJeff Kirsher 	 * - IPv6 would be doable but we keep that for later ...
3118862bf1eSJeff Kirsher 	 * - Only unfragmented packets.  Did somebody already tell you
3128862bf1eSJeff Kirsher 	 *   fragmentation is evil?
3138862bf1eSJeff Kirsher 	 * - don't care about packet size.  Worst case when processing a
3148862bf1eSJeff Kirsher 	 *   malformed packet we'll try to access the packet at ip header +
3158862bf1eSJeff Kirsher 	 *   64 bytes which is still inside the skb.  Even in the unlikely
3168862bf1eSJeff Kirsher 	 *   case where the checksum is right the higher layers will still
3178862bf1eSJeff Kirsher 	 *   drop the packet as appropriate.
3188862bf1eSJeff Kirsher 	 */
3198862bf1eSJeff Kirsher 	if (eh->h_proto != htons(ETH_P_IP))
3208862bf1eSJeff Kirsher 		return;
3218862bf1eSJeff Kirsher 
3228862bf1eSJeff Kirsher 	ih = (struct iphdr *)((char *)eh + ETH_HLEN);
3238862bf1eSJeff Kirsher 	if (ip_is_fragment(ih))
3248862bf1eSJeff Kirsher 		return;
3258862bf1eSJeff Kirsher 
3268862bf1eSJeff Kirsher 	proto = ih->protocol;
3278862bf1eSJeff Kirsher 	if (proto != IPPROTO_TCP && proto != IPPROTO_UDP)
3288862bf1eSJeff Kirsher 		return;
3298862bf1eSJeff Kirsher 
3308862bf1eSJeff Kirsher 	/* Same as tx - compute csum of pseudo header  */
3318862bf1eSJeff Kirsher 	csum = hwsum +
3328862bf1eSJeff Kirsher 	       (ih->tot_len - (ih->ihl << 2)) +
333c1b6a3d8SThomas Bogendoerfer 	       htons((u16)ih->protocol) +
3348862bf1eSJeff Kirsher 	       (ih->saddr >> 16) + (ih->saddr & 0xffff) +
3358862bf1eSJeff Kirsher 	       (ih->daddr >> 16) + (ih->daddr & 0xffff);
3368862bf1eSJeff Kirsher 
3378862bf1eSJeff Kirsher 	/* Sum up ethernet dest addr, src addr and protocol  */
338c1b6a3d8SThomas Bogendoerfer 	ew = (u16 *)eh;
3398862bf1eSJeff Kirsher 	ehsum = ew[0] + ew[1] + ew[2] + ew[3] + ew[4] + ew[5] + ew[6];
3408862bf1eSJeff Kirsher 
3418862bf1eSJeff Kirsher 	ehsum = (ehsum & 0xffff) + (ehsum >> 16);
3428862bf1eSJeff Kirsher 	ehsum = (ehsum & 0xffff) + (ehsum >> 16);
3438862bf1eSJeff Kirsher 
3448862bf1eSJeff Kirsher 	csum += 0xffff ^ ehsum;
3458862bf1eSJeff Kirsher 
3468862bf1eSJeff Kirsher 	/* In the next step we also subtract the 1's complement
347c1b6a3d8SThomas Bogendoerfer 	 * checksum of the trailing ethernet CRC.
348c1b6a3d8SThomas Bogendoerfer 	 */
3498862bf1eSJeff Kirsher 	cp = (char *)eh + len;	/* points at trailing CRC */
3508862bf1eSJeff Kirsher 	if (len & 1) {
351c1b6a3d8SThomas Bogendoerfer 		csum += 0xffff ^ (u16)((cp[1] << 8) | cp[0]);
352c1b6a3d8SThomas Bogendoerfer 		csum += 0xffff ^ (u16)((cp[3] << 8) | cp[2]);
3538862bf1eSJeff Kirsher 	} else {
354c1b6a3d8SThomas Bogendoerfer 		csum += 0xffff ^ (u16)((cp[0] << 8) | cp[1]);
355c1b6a3d8SThomas Bogendoerfer 		csum += 0xffff ^ (u16)((cp[2] << 8) | cp[3]);
3568862bf1eSJeff Kirsher 	}
3578862bf1eSJeff Kirsher 
3588862bf1eSJeff Kirsher 	csum = (csum & 0xffff) + (csum >> 16);
3598862bf1eSJeff Kirsher 	csum = (csum & 0xffff) + (csum >> 16);
3608862bf1eSJeff Kirsher 
3618862bf1eSJeff Kirsher 	if (csum == 0xffff)
3628862bf1eSJeff Kirsher 		skb->ip_summed = CHECKSUM_UNNECESSARY;
3638862bf1eSJeff Kirsher }
3648862bf1eSJeff Kirsher 
ioc3_rx(struct net_device * dev)3658862bf1eSJeff Kirsher static inline void ioc3_rx(struct net_device *dev)
3668862bf1eSJeff Kirsher {
3678862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
3688862bf1eSJeff Kirsher 	struct sk_buff *skb, *new_skb;
3698862bf1eSJeff Kirsher 	int rx_entry, n_entry, len;
3708862bf1eSJeff Kirsher 	struct ioc3_erxbuf *rxb;
3718862bf1eSJeff Kirsher 	unsigned long *rxr;
372ed870f6aSThomas Bogendoerfer 	dma_addr_t d;
3738862bf1eSJeff Kirsher 	u32 w0, err;
3748862bf1eSJeff Kirsher 
37564699336SJoe Perches 	rxr = ip->rxr;		/* Ring base */
3768862bf1eSJeff Kirsher 	rx_entry = ip->rx_ci;				/* RX consume index */
3778862bf1eSJeff Kirsher 	n_entry = ip->rx_pi;
3788862bf1eSJeff Kirsher 
3798862bf1eSJeff Kirsher 	skb = ip->rx_skbs[rx_entry];
3808862bf1eSJeff Kirsher 	rxb = (struct ioc3_erxbuf *)(skb->data - RX_OFFSET);
3818862bf1eSJeff Kirsher 	w0 = be32_to_cpu(rxb->w0);
3828862bf1eSJeff Kirsher 
3838862bf1eSJeff Kirsher 	while (w0 & ERXBUF_V) {
3848862bf1eSJeff Kirsher 		err = be32_to_cpu(rxb->err);		/* It's valid ...  */
3858862bf1eSJeff Kirsher 		if (err & ERXBUF_GOODPKT) {
3868862bf1eSJeff Kirsher 			len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4;
387850d2fedSThomas Bogendoerfer 			skb_put(skb, len);
3888862bf1eSJeff Kirsher 			skb->protocol = eth_type_trans(skb, dev);
3898862bf1eSJeff Kirsher 
390ed870f6aSThomas Bogendoerfer 			if (ioc3_alloc_skb(ip, &new_skb, &rxb, &d)) {
3918862bf1eSJeff Kirsher 				/* Ouch, drop packet and just recycle packet
392c1b6a3d8SThomas Bogendoerfer 				 * to keep the ring filled.
393c1b6a3d8SThomas Bogendoerfer 				 */
3948862bf1eSJeff Kirsher 				dev->stats.rx_dropped++;
3958862bf1eSJeff Kirsher 				new_skb = skb;
396ed870f6aSThomas Bogendoerfer 				d = rxr[rx_entry];
3978862bf1eSJeff Kirsher 				goto next;
3988862bf1eSJeff Kirsher 			}
3998862bf1eSJeff Kirsher 
4008862bf1eSJeff Kirsher 			if (likely(dev->features & NETIF_F_RXCSUM))
4018862bf1eSJeff Kirsher 				ioc3_tcpudp_checksum(skb,
402c1b6a3d8SThomas Bogendoerfer 						     w0 & ERXBUF_IPCKSUM_MASK,
403c1b6a3d8SThomas Bogendoerfer 						     len);
4048862bf1eSJeff Kirsher 
405ed870f6aSThomas Bogendoerfer 			dma_unmap_single(ip->dma_dev, rxr[rx_entry],
406ed870f6aSThomas Bogendoerfer 					 RX_BUF_SIZE, DMA_FROM_DEVICE);
407ed870f6aSThomas Bogendoerfer 
4088862bf1eSJeff Kirsher 			netif_rx(skb);
4098862bf1eSJeff Kirsher 
4108862bf1eSJeff Kirsher 			ip->rx_skbs[rx_entry] = NULL;	/* Poison  */
4118862bf1eSJeff Kirsher 
4128862bf1eSJeff Kirsher 			dev->stats.rx_packets++;		/* Statistics */
4138862bf1eSJeff Kirsher 			dev->stats.rx_bytes += len;
4148862bf1eSJeff Kirsher 		} else {
4158862bf1eSJeff Kirsher 			/* The frame is invalid and the skb never
416c1b6a3d8SThomas Bogendoerfer 			 * reached the network layer so we can just
417c1b6a3d8SThomas Bogendoerfer 			 * recycle it.
418c1b6a3d8SThomas Bogendoerfer 			 */
4198862bf1eSJeff Kirsher 			new_skb = skb;
420ed870f6aSThomas Bogendoerfer 			d = rxr[rx_entry];
4218862bf1eSJeff Kirsher 			dev->stats.rx_errors++;
4228862bf1eSJeff Kirsher 		}
4238862bf1eSJeff Kirsher 		if (err & ERXBUF_CRCERR)	/* Statistics */
4248862bf1eSJeff Kirsher 			dev->stats.rx_crc_errors++;
4258862bf1eSJeff Kirsher 		if (err & ERXBUF_FRAMERR)
4268862bf1eSJeff Kirsher 			dev->stats.rx_frame_errors++;
427ed870f6aSThomas Bogendoerfer 
4288862bf1eSJeff Kirsher next:
4298862bf1eSJeff Kirsher 		ip->rx_skbs[n_entry] = new_skb;
430ed870f6aSThomas Bogendoerfer 		rxr[n_entry] = cpu_to_be64(ioc3_map(d, PCI64_ATTR_BAR));
4318862bf1eSJeff Kirsher 		rxb->w0 = 0;				/* Clear valid flag */
432141a7dbbSThomas Bogendoerfer 		n_entry = (n_entry + 1) & RX_RING_MASK;	/* Update erpir */
4338862bf1eSJeff Kirsher 
4348862bf1eSJeff Kirsher 		/* Now go on to the next ring entry.  */
435141a7dbbSThomas Bogendoerfer 		rx_entry = (rx_entry + 1) & RX_RING_MASK;
4368862bf1eSJeff Kirsher 		skb = ip->rx_skbs[rx_entry];
4378862bf1eSJeff Kirsher 		rxb = (struct ioc3_erxbuf *)(skb->data - RX_OFFSET);
4388862bf1eSJeff Kirsher 		w0 = be32_to_cpu(rxb->w0);
4398862bf1eSJeff Kirsher 	}
440cbe7d517SThomas Bogendoerfer 	writel((n_entry << 3) | ERPIR_ARM, &ip->regs->erpir);
4418862bf1eSJeff Kirsher 	ip->rx_pi = n_entry;
4428862bf1eSJeff Kirsher 	ip->rx_ci = rx_entry;
4438862bf1eSJeff Kirsher }
4448862bf1eSJeff Kirsher 
ioc3_tx(struct net_device * dev)4458862bf1eSJeff Kirsher static inline void ioc3_tx(struct net_device *dev)
4468862bf1eSJeff Kirsher {
4478862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
448cbe7d517SThomas Bogendoerfer 	struct ioc3_ethregs *regs = ip->regs;
4498862bf1eSJeff Kirsher 	unsigned long packets, bytes;
4508862bf1eSJeff Kirsher 	int tx_entry, o_entry;
4518862bf1eSJeff Kirsher 	struct sk_buff *skb;
4528862bf1eSJeff Kirsher 	u32 etcir;
4538862bf1eSJeff Kirsher 
4548862bf1eSJeff Kirsher 	spin_lock(&ip->ioc3_lock);
455cbe7d517SThomas Bogendoerfer 	etcir = readl(&regs->etcir);
4568862bf1eSJeff Kirsher 
457141a7dbbSThomas Bogendoerfer 	tx_entry = (etcir >> 7) & TX_RING_MASK;
4588862bf1eSJeff Kirsher 	o_entry = ip->tx_ci;
4598862bf1eSJeff Kirsher 	packets = 0;
4608862bf1eSJeff Kirsher 	bytes = 0;
4618862bf1eSJeff Kirsher 
4628862bf1eSJeff Kirsher 	while (o_entry != tx_entry) {
4638862bf1eSJeff Kirsher 		packets++;
4648862bf1eSJeff Kirsher 		skb = ip->tx_skbs[o_entry];
4658862bf1eSJeff Kirsher 		bytes += skb->len;
466d1a096c2SYang Wei 		dev_consume_skb_irq(skb);
4678862bf1eSJeff Kirsher 		ip->tx_skbs[o_entry] = NULL;
4688862bf1eSJeff Kirsher 
469141a7dbbSThomas Bogendoerfer 		o_entry = (o_entry + 1) & TX_RING_MASK;	/* Next */
4708862bf1eSJeff Kirsher 
471cbe7d517SThomas Bogendoerfer 		etcir = readl(&regs->etcir);		/* More pkts sent?  */
472141a7dbbSThomas Bogendoerfer 		tx_entry = (etcir >> 7) & TX_RING_MASK;
4738862bf1eSJeff Kirsher 	}
4748862bf1eSJeff Kirsher 
4758862bf1eSJeff Kirsher 	dev->stats.tx_packets += packets;
4768862bf1eSJeff Kirsher 	dev->stats.tx_bytes += bytes;
4778862bf1eSJeff Kirsher 	ip->txqlen -= packets;
4788862bf1eSJeff Kirsher 
479141a7dbbSThomas Bogendoerfer 	if (netif_queue_stopped(dev) && ip->txqlen < TX_RING_ENTRIES)
4808862bf1eSJeff Kirsher 		netif_wake_queue(dev);
4818862bf1eSJeff Kirsher 
4828862bf1eSJeff Kirsher 	ip->tx_ci = o_entry;
4838862bf1eSJeff Kirsher 	spin_unlock(&ip->ioc3_lock);
4848862bf1eSJeff Kirsher }
4858862bf1eSJeff Kirsher 
486c1b6a3d8SThomas Bogendoerfer /* Deal with fatal IOC3 errors.  This condition might be caused by a hard or
4878862bf1eSJeff Kirsher  * software problems, so we should try to recover
4888862bf1eSJeff Kirsher  * more gracefully if this ever happens.  In theory we might be flooded
4898862bf1eSJeff Kirsher  * with such error interrupts if something really goes wrong, so we might
4908862bf1eSJeff Kirsher  * also consider to take the interface down.
4918862bf1eSJeff Kirsher  */
ioc3_error(struct net_device * dev,u32 eisr)4928862bf1eSJeff Kirsher static void ioc3_error(struct net_device *dev, u32 eisr)
4938862bf1eSJeff Kirsher {
4948862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
4958862bf1eSJeff Kirsher 
4968862bf1eSJeff Kirsher 	spin_lock(&ip->ioc3_lock);
4978862bf1eSJeff Kirsher 
4988862bf1eSJeff Kirsher 	if (eisr & EISR_RXOFLO)
499c1b6a3d8SThomas Bogendoerfer 		net_err_ratelimited("%s: RX overflow.\n", dev->name);
5008862bf1eSJeff Kirsher 	if (eisr & EISR_RXBUFOFLO)
501c1b6a3d8SThomas Bogendoerfer 		net_err_ratelimited("%s: RX buffer overflow.\n", dev->name);
5028862bf1eSJeff Kirsher 	if (eisr & EISR_RXMEMERR)
503c1b6a3d8SThomas Bogendoerfer 		net_err_ratelimited("%s: RX PCI error.\n", dev->name);
5048862bf1eSJeff Kirsher 	if (eisr & EISR_RXPARERR)
505c1b6a3d8SThomas Bogendoerfer 		net_err_ratelimited("%s: RX SSRAM parity error.\n", dev->name);
5068862bf1eSJeff Kirsher 	if (eisr & EISR_TXBUFUFLO)
507c1b6a3d8SThomas Bogendoerfer 		net_err_ratelimited("%s: TX buffer underflow.\n", dev->name);
5088862bf1eSJeff Kirsher 	if (eisr & EISR_TXMEMERR)
509c1b6a3d8SThomas Bogendoerfer 		net_err_ratelimited("%s: TX PCI error.\n", dev->name);
5108862bf1eSJeff Kirsher 
5118862bf1eSJeff Kirsher 	ioc3_stop(ip);
51219a957b6SThomas Bogendoerfer 	ioc3_free_rx_bufs(ip);
51319a957b6SThomas Bogendoerfer 	ioc3_clean_tx_ring(ip);
51419a957b6SThomas Bogendoerfer 
5158862bf1eSJeff Kirsher 	ioc3_init(dev);
516850d2fedSThomas Bogendoerfer 	if (ioc3_alloc_rx_bufs(dev)) {
517850d2fedSThomas Bogendoerfer 		netdev_err(dev, "%s: rx buffer allocation failed\n", __func__);
518850d2fedSThomas Bogendoerfer 		spin_unlock(&ip->ioc3_lock);
519850d2fedSThomas Bogendoerfer 		return;
520850d2fedSThomas Bogendoerfer 	}
521fcd0da5aSThomas Bogendoerfer 	ioc3_start(ip);
5228862bf1eSJeff Kirsher 	ioc3_mii_init(ip);
5238862bf1eSJeff Kirsher 
5248862bf1eSJeff Kirsher 	netif_wake_queue(dev);
5258862bf1eSJeff Kirsher 
5268862bf1eSJeff Kirsher 	spin_unlock(&ip->ioc3_lock);
5278862bf1eSJeff Kirsher }
5288862bf1eSJeff Kirsher 
5298862bf1eSJeff Kirsher /* The interrupt handler does all of the Rx thread work and cleans up
530c1b6a3d8SThomas Bogendoerfer  * after the Tx thread.
531c1b6a3d8SThomas Bogendoerfer  */
ioc3_interrupt(int irq,void * dev_id)532cbe7d517SThomas Bogendoerfer static irqreturn_t ioc3_interrupt(int irq, void *dev_id)
5338862bf1eSJeff Kirsher {
534cbe7d517SThomas Bogendoerfer 	struct ioc3_private *ip = netdev_priv(dev_id);
535cbe7d517SThomas Bogendoerfer 	struct ioc3_ethregs *regs = ip->regs;
5368862bf1eSJeff Kirsher 	u32 eisr;
5378862bf1eSJeff Kirsher 
538cbe7d517SThomas Bogendoerfer 	eisr = readl(&regs->eisr);
539cbe7d517SThomas Bogendoerfer 	writel(eisr, &regs->eisr);
540cbe7d517SThomas Bogendoerfer 	readl(&regs->eisr);				/* Flush */
5418862bf1eSJeff Kirsher 
5428862bf1eSJeff Kirsher 	if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR |
5438862bf1eSJeff Kirsher 		    EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXMEMERR))
544cbe7d517SThomas Bogendoerfer 		ioc3_error(dev_id, eisr);
5458862bf1eSJeff Kirsher 	if (eisr & EISR_RXTIMERINT)
546cbe7d517SThomas Bogendoerfer 		ioc3_rx(dev_id);
5478862bf1eSJeff Kirsher 	if (eisr & EISR_TXEXPLICIT)
548cbe7d517SThomas Bogendoerfer 		ioc3_tx(dev_id);
5498862bf1eSJeff Kirsher 
5508862bf1eSJeff Kirsher 	return IRQ_HANDLED;
5518862bf1eSJeff Kirsher }
5528862bf1eSJeff Kirsher 
ioc3_setup_duplex(struct ioc3_private * ip)5538862bf1eSJeff Kirsher static inline void ioc3_setup_duplex(struct ioc3_private *ip)
5548862bf1eSJeff Kirsher {
555cbe7d517SThomas Bogendoerfer 	struct ioc3_ethregs *regs = ip->regs;
5568862bf1eSJeff Kirsher 
557d1c94542SThomas Bogendoerfer 	spin_lock_irq(&ip->ioc3_lock);
558d1c94542SThomas Bogendoerfer 
5598862bf1eSJeff Kirsher 	if (ip->mii.full_duplex) {
560cbe7d517SThomas Bogendoerfer 		writel(ETCSR_FD, &regs->etcsr);
5618862bf1eSJeff Kirsher 		ip->emcr |= EMCR_DUPLEX;
5628862bf1eSJeff Kirsher 	} else {
563cbe7d517SThomas Bogendoerfer 		writel(ETCSR_HD, &regs->etcsr);
5648862bf1eSJeff Kirsher 		ip->emcr &= ~EMCR_DUPLEX;
5658862bf1eSJeff Kirsher 	}
566cbe7d517SThomas Bogendoerfer 	writel(ip->emcr, &regs->emcr);
567d1c94542SThomas Bogendoerfer 
568d1c94542SThomas Bogendoerfer 	spin_unlock_irq(&ip->ioc3_lock);
5698862bf1eSJeff Kirsher }
5708862bf1eSJeff Kirsher 
ioc3_timer(struct timer_list * t)571dfc57004SKees Cook static void ioc3_timer(struct timer_list *t)
5728862bf1eSJeff Kirsher {
573dfc57004SKees Cook 	struct ioc3_private *ip = from_timer(ip, t, ioc3_timer);
5748862bf1eSJeff Kirsher 
5758862bf1eSJeff Kirsher 	/* Print the link status if it has changed */
5768862bf1eSJeff Kirsher 	mii_check_media(&ip->mii, 1, 0);
5778862bf1eSJeff Kirsher 	ioc3_setup_duplex(ip);
5788862bf1eSJeff Kirsher 
5798862bf1eSJeff Kirsher 	ip->ioc3_timer.expires = jiffies + ((12 * HZ) / 10); /* 1.2s */
5808862bf1eSJeff Kirsher 	add_timer(&ip->ioc3_timer);
5818862bf1eSJeff Kirsher }
5828862bf1eSJeff Kirsher 
583c1b6a3d8SThomas Bogendoerfer /* Try to find a PHY.  There is no apparent relation between the MII addresses
5848862bf1eSJeff Kirsher  * in the SGI documentation and what we find in reality, so we simply probe
58534a568a2SThomas Bogendoerfer  * for the PHY.
5868862bf1eSJeff Kirsher  */
ioc3_mii_init(struct ioc3_private * ip)5878862bf1eSJeff Kirsher static int ioc3_mii_init(struct ioc3_private *ip)
5888862bf1eSJeff Kirsher {
5898862bf1eSJeff Kirsher 	u16 word;
59034a568a2SThomas Bogendoerfer 	int i;
5918862bf1eSJeff Kirsher 
5928862bf1eSJeff Kirsher 	for (i = 0; i < 32; i++) {
5930ce5ebd2SThomas Bogendoerfer 		word = ioc3_mdio_read(ip->mii.dev, i, MII_PHYSID1);
5948862bf1eSJeff Kirsher 
5958862bf1eSJeff Kirsher 		if (word != 0xffff && word != 0x0000) {
5968862bf1eSJeff Kirsher 			ip->mii.phy_id = i;
59734a568a2SThomas Bogendoerfer 			return 0;
59834a568a2SThomas Bogendoerfer 		}
59934a568a2SThomas Bogendoerfer 	}
60034a568a2SThomas Bogendoerfer 	ip->mii.phy_id = -1;
60134a568a2SThomas Bogendoerfer 	return -ENODEV;
6028862bf1eSJeff Kirsher }
6038862bf1eSJeff Kirsher 
ioc3_mii_start(struct ioc3_private * ip)6048862bf1eSJeff Kirsher static void ioc3_mii_start(struct ioc3_private *ip)
6058862bf1eSJeff Kirsher {
6068862bf1eSJeff Kirsher 	ip->ioc3_timer.expires = jiffies + (12 * HZ) / 10;  /* 1.2 sec. */
6078862bf1eSJeff Kirsher 	add_timer(&ip->ioc3_timer);
6088862bf1eSJeff Kirsher }
6098862bf1eSJeff Kirsher 
ioc3_tx_unmap(struct ioc3_private * ip,int entry)610ed870f6aSThomas Bogendoerfer static inline void ioc3_tx_unmap(struct ioc3_private *ip, int entry)
611ed870f6aSThomas Bogendoerfer {
612ed870f6aSThomas Bogendoerfer 	struct ioc3_etxd *desc;
613ed870f6aSThomas Bogendoerfer 	u32 cmd, bufcnt, len;
614ed870f6aSThomas Bogendoerfer 
615ed870f6aSThomas Bogendoerfer 	desc = &ip->txr[entry];
616ed870f6aSThomas Bogendoerfer 	cmd = be32_to_cpu(desc->cmd);
617ed870f6aSThomas Bogendoerfer 	bufcnt = be32_to_cpu(desc->bufcnt);
618ed870f6aSThomas Bogendoerfer 	if (cmd & ETXD_B1V) {
619ed870f6aSThomas Bogendoerfer 		len = (bufcnt & ETXD_B1CNT_MASK) >> ETXD_B1CNT_SHIFT;
620ed870f6aSThomas Bogendoerfer 		dma_unmap_single(ip->dma_dev, be64_to_cpu(desc->p1),
621ed870f6aSThomas Bogendoerfer 				 len, DMA_TO_DEVICE);
622ed870f6aSThomas Bogendoerfer 	}
623ed870f6aSThomas Bogendoerfer 	if (cmd & ETXD_B2V) {
624ed870f6aSThomas Bogendoerfer 		len = (bufcnt & ETXD_B2CNT_MASK) >> ETXD_B2CNT_SHIFT;
625ed870f6aSThomas Bogendoerfer 		dma_unmap_single(ip->dma_dev, be64_to_cpu(desc->p2),
626ed870f6aSThomas Bogendoerfer 				 len, DMA_TO_DEVICE);
627ed870f6aSThomas Bogendoerfer 	}
628ed870f6aSThomas Bogendoerfer }
629ed870f6aSThomas Bogendoerfer 
ioc3_clean_tx_ring(struct ioc3_private * ip)6308862bf1eSJeff Kirsher static inline void ioc3_clean_tx_ring(struct ioc3_private *ip)
6318862bf1eSJeff Kirsher {
6328862bf1eSJeff Kirsher 	struct sk_buff *skb;
6338862bf1eSJeff Kirsher 	int i;
6348862bf1eSJeff Kirsher 
635141a7dbbSThomas Bogendoerfer 	for (i = 0; i < TX_RING_ENTRIES; i++) {
6368862bf1eSJeff Kirsher 		skb = ip->tx_skbs[i];
6378862bf1eSJeff Kirsher 		if (skb) {
638ed870f6aSThomas Bogendoerfer 			ioc3_tx_unmap(ip, i);
6398862bf1eSJeff Kirsher 			ip->tx_skbs[i] = NULL;
6408862bf1eSJeff Kirsher 			dev_kfree_skb_any(skb);
6418862bf1eSJeff Kirsher 		}
6428862bf1eSJeff Kirsher 		ip->txr[i].cmd = 0;
6438862bf1eSJeff Kirsher 	}
6448862bf1eSJeff Kirsher 	ip->tx_pi = 0;
6458862bf1eSJeff Kirsher 	ip->tx_ci = 0;
6468862bf1eSJeff Kirsher }
6478862bf1eSJeff Kirsher 
ioc3_free_rx_bufs(struct ioc3_private * ip)6489c328b05SThomas Bogendoerfer static void ioc3_free_rx_bufs(struct ioc3_private *ip)
6498862bf1eSJeff Kirsher {
6508862bf1eSJeff Kirsher 	int rx_entry, n_entry;
651ed870f6aSThomas Bogendoerfer 	struct sk_buff *skb;
6528862bf1eSJeff Kirsher 
6538862bf1eSJeff Kirsher 	n_entry = ip->rx_ci;
6548862bf1eSJeff Kirsher 	rx_entry = ip->rx_pi;
6558862bf1eSJeff Kirsher 
6568862bf1eSJeff Kirsher 	while (n_entry != rx_entry) {
657ed870f6aSThomas Bogendoerfer 		skb = ip->rx_skbs[n_entry];
658ed870f6aSThomas Bogendoerfer 		if (skb) {
659ed870f6aSThomas Bogendoerfer 			dma_unmap_single(ip->dma_dev,
660ed870f6aSThomas Bogendoerfer 					 be64_to_cpu(ip->rxr[n_entry]),
661ed870f6aSThomas Bogendoerfer 					 RX_BUF_SIZE, DMA_FROM_DEVICE);
662ed870f6aSThomas Bogendoerfer 			dev_kfree_skb_any(skb);
663ed870f6aSThomas Bogendoerfer 		}
664141a7dbbSThomas Bogendoerfer 		n_entry = (n_entry + 1) & RX_RING_MASK;
6658862bf1eSJeff Kirsher 	}
6668862bf1eSJeff Kirsher }
6678862bf1eSJeff Kirsher 
ioc3_alloc_rx_bufs(struct net_device * dev)668850d2fedSThomas Bogendoerfer static int ioc3_alloc_rx_bufs(struct net_device *dev)
6698862bf1eSJeff Kirsher {
6708862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
6718862bf1eSJeff Kirsher 	struct ioc3_erxbuf *rxb;
672ed870f6aSThomas Bogendoerfer 	dma_addr_t d;
6738862bf1eSJeff Kirsher 	int i;
6748862bf1eSJeff Kirsher 
6758862bf1eSJeff Kirsher 	/* Now the rx buffers.  The RX ring may be larger but
676c1b6a3d8SThomas Bogendoerfer 	 * we only allocate 16 buffers for now.  Need to tune
677c1b6a3d8SThomas Bogendoerfer 	 * this for performance and memory later.
678c1b6a3d8SThomas Bogendoerfer 	 */
6798862bf1eSJeff Kirsher 	for (i = 0; i < RX_BUFFS; i++) {
680ed870f6aSThomas Bogendoerfer 		if (ioc3_alloc_skb(ip, &ip->rx_skbs[i], &rxb, &d))
681850d2fedSThomas Bogendoerfer 			return -ENOMEM;
6828862bf1eSJeff Kirsher 
683489467e5SThomas Bogendoerfer 		rxb->w0 = 0;	/* Clear valid flag */
684ed870f6aSThomas Bogendoerfer 		ip->rxr[i] = cpu_to_be64(ioc3_map(d, PCI64_ATTR_BAR));
6858862bf1eSJeff Kirsher 	}
6868862bf1eSJeff Kirsher 	ip->rx_ci = 0;
6878862bf1eSJeff Kirsher 	ip->rx_pi = RX_BUFFS;
688850d2fedSThomas Bogendoerfer 
689850d2fedSThomas Bogendoerfer 	return 0;
6908862bf1eSJeff Kirsher }
6918862bf1eSJeff Kirsher 
ioc3_ssram_disc(struct ioc3_private * ip)6928862bf1eSJeff Kirsher static inline void ioc3_ssram_disc(struct ioc3_private *ip)
6938862bf1eSJeff Kirsher {
694cbe7d517SThomas Bogendoerfer 	struct ioc3_ethregs *regs = ip->regs;
695cbe7d517SThomas Bogendoerfer 	u32 *ssram0 = &ip->ssram[0x0000];
696cbe7d517SThomas Bogendoerfer 	u32 *ssram1 = &ip->ssram[0x4000];
697cbe7d517SThomas Bogendoerfer 	u32 pattern = 0x5555;
6988862bf1eSJeff Kirsher 
6998862bf1eSJeff Kirsher 	/* Assume the larger size SSRAM and enable parity checking */
700cbe7d517SThomas Bogendoerfer 	writel(readl(&regs->emcr) | (EMCR_BUFSIZ | EMCR_RAMPAR), &regs->emcr);
701cbe7d517SThomas Bogendoerfer 	readl(&regs->emcr); /* Flush */
7028862bf1eSJeff Kirsher 
703cbe7d517SThomas Bogendoerfer 	writel(pattern, ssram0);
704cbe7d517SThomas Bogendoerfer 	writel(~pattern & IOC3_SSRAM_DM, ssram1);
7058862bf1eSJeff Kirsher 
706cbe7d517SThomas Bogendoerfer 	if ((readl(ssram0) & IOC3_SSRAM_DM) != pattern ||
707cbe7d517SThomas Bogendoerfer 	    (readl(ssram1) & IOC3_SSRAM_DM) != (~pattern & IOC3_SSRAM_DM)) {
7088862bf1eSJeff Kirsher 		/* set ssram size to 64 KB */
709cbe7d517SThomas Bogendoerfer 		ip->emcr |= EMCR_RAMPAR;
710cbe7d517SThomas Bogendoerfer 		writel(readl(&regs->emcr) & ~EMCR_BUFSIZ, &regs->emcr);
711cbe7d517SThomas Bogendoerfer 	} else {
712cbe7d517SThomas Bogendoerfer 		ip->emcr |= EMCR_BUFSIZ | EMCR_RAMPAR;
713cbe7d517SThomas Bogendoerfer 	}
7148862bf1eSJeff Kirsher }
7158862bf1eSJeff Kirsher 
ioc3_init(struct net_device * dev)7168862bf1eSJeff Kirsher static void ioc3_init(struct net_device *dev)
7178862bf1eSJeff Kirsher {
7188862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
719cbe7d517SThomas Bogendoerfer 	struct ioc3_ethregs *regs = ip->regs;
7208862bf1eSJeff Kirsher 
7218862bf1eSJeff Kirsher 	del_timer_sync(&ip->ioc3_timer);	/* Kill if running	*/
7228862bf1eSJeff Kirsher 
723cbe7d517SThomas Bogendoerfer 	writel(EMCR_RST, &regs->emcr);		/* Reset		*/
724cbe7d517SThomas Bogendoerfer 	readl(&regs->emcr);			/* Flush WB		*/
7258862bf1eSJeff Kirsher 	udelay(4);				/* Give it time ...	*/
726cbe7d517SThomas Bogendoerfer 	writel(0, &regs->emcr);
727cbe7d517SThomas Bogendoerfer 	readl(&regs->emcr);
7288862bf1eSJeff Kirsher 
7298862bf1eSJeff Kirsher 	/* Misc registers  */
730ed870f6aSThomas Bogendoerfer 	writel(ERBAR_VAL, &regs->erbar);
731cbe7d517SThomas Bogendoerfer 	readl(&regs->etcdc);			/* Clear on read */
732cbe7d517SThomas Bogendoerfer 	writel(15, &regs->ercsr);		/* RX low watermark  */
733cbe7d517SThomas Bogendoerfer 	writel(0, &regs->ertr);			/* Interrupt immediately */
7348862bf1eSJeff Kirsher 	__ioc3_set_mac_address(dev);
735cbe7d517SThomas Bogendoerfer 	writel(ip->ehar_h, &regs->ehar_h);
736cbe7d517SThomas Bogendoerfer 	writel(ip->ehar_l, &regs->ehar_l);
737cbe7d517SThomas Bogendoerfer 	writel(42, &regs->ersr);		/* XXX should be random */
738fcd0da5aSThomas Bogendoerfer }
739fcd0da5aSThomas Bogendoerfer 
ioc3_start(struct ioc3_private * ip)740fcd0da5aSThomas Bogendoerfer static void ioc3_start(struct ioc3_private *ip)
741fcd0da5aSThomas Bogendoerfer {
742fcd0da5aSThomas Bogendoerfer 	struct ioc3_ethregs *regs = ip->regs;
743fcd0da5aSThomas Bogendoerfer 	unsigned long ring;
744fcd0da5aSThomas Bogendoerfer 
745fcd0da5aSThomas Bogendoerfer 	/* Now the rx ring base, consume & produce registers.  */
746ed870f6aSThomas Bogendoerfer 	ring = ioc3_map(ip->rxr_dma, PCI64_ATTR_PREC);
747fcd0da5aSThomas Bogendoerfer 	writel(ring >> 32, &regs->erbr_h);
748fcd0da5aSThomas Bogendoerfer 	writel(ring & 0xffffffff, &regs->erbr_l);
749fcd0da5aSThomas Bogendoerfer 	writel(ip->rx_ci << 3, &regs->ercir);
750fcd0da5aSThomas Bogendoerfer 	writel((ip->rx_pi << 3) | ERPIR_ARM, &regs->erpir);
751fcd0da5aSThomas Bogendoerfer 
752ed870f6aSThomas Bogendoerfer 	ring = ioc3_map(ip->txr_dma, PCI64_ATTR_PREC);
753fcd0da5aSThomas Bogendoerfer 
754fcd0da5aSThomas Bogendoerfer 	ip->txqlen = 0;					/* nothing queued  */
755fcd0da5aSThomas Bogendoerfer 
756fcd0da5aSThomas Bogendoerfer 	/* Now the tx ring base, consume & produce registers.  */
757fcd0da5aSThomas Bogendoerfer 	writel(ring >> 32, &regs->etbr_h);
758fcd0da5aSThomas Bogendoerfer 	writel(ring & 0xffffffff, &regs->etbr_l);
759fcd0da5aSThomas Bogendoerfer 	writel(ip->tx_pi << 7, &regs->etpir);
760fcd0da5aSThomas Bogendoerfer 	writel(ip->tx_ci << 7, &regs->etcir);
761fcd0da5aSThomas Bogendoerfer 	readl(&regs->etcir);				/* Flush */
7628862bf1eSJeff Kirsher 
7638862bf1eSJeff Kirsher 	ip->emcr |= ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | EMCR_TXDMAEN |
7648862bf1eSJeff Kirsher 		    EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN | EMCR_PADEN;
765cbe7d517SThomas Bogendoerfer 	writel(ip->emcr, &regs->emcr);
766cbe7d517SThomas Bogendoerfer 	writel(EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO |
7678862bf1eSJeff Kirsher 	       EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO |
768cbe7d517SThomas Bogendoerfer 	       EISR_TXEXPLICIT | EISR_TXMEMERR, &regs->eier);
769cbe7d517SThomas Bogendoerfer 	readl(&regs->eier);
7708862bf1eSJeff Kirsher }
7718862bf1eSJeff Kirsher 
ioc3_stop(struct ioc3_private * ip)7728862bf1eSJeff Kirsher static inline void ioc3_stop(struct ioc3_private *ip)
7738862bf1eSJeff Kirsher {
774cbe7d517SThomas Bogendoerfer 	struct ioc3_ethregs *regs = ip->regs;
7758862bf1eSJeff Kirsher 
776cbe7d517SThomas Bogendoerfer 	writel(0, &regs->emcr);			/* Shutup */
777cbe7d517SThomas Bogendoerfer 	writel(0, &regs->eier);			/* Disable interrupts */
778cbe7d517SThomas Bogendoerfer 	readl(&regs->eier);			/* Flush */
7798862bf1eSJeff Kirsher }
7808862bf1eSJeff Kirsher 
ioc3_open(struct net_device * dev)7818862bf1eSJeff Kirsher static int ioc3_open(struct net_device *dev)
7828862bf1eSJeff Kirsher {
7838862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
7848862bf1eSJeff Kirsher 
7858862bf1eSJeff Kirsher 	ip->ehar_h = 0;
7868862bf1eSJeff Kirsher 	ip->ehar_l = 0;
78719a957b6SThomas Bogendoerfer 
7888862bf1eSJeff Kirsher 	ioc3_init(dev);
789850d2fedSThomas Bogendoerfer 	if (ioc3_alloc_rx_bufs(dev)) {
790850d2fedSThomas Bogendoerfer 		netdev_err(dev, "%s: rx buffer allocation failed\n", __func__);
791850d2fedSThomas Bogendoerfer 		return -ENOMEM;
792850d2fedSThomas Bogendoerfer 	}
793fcd0da5aSThomas Bogendoerfer 	ioc3_start(ip);
7948862bf1eSJeff Kirsher 	ioc3_mii_start(ip);
7958862bf1eSJeff Kirsher 
7968862bf1eSJeff Kirsher 	netif_start_queue(dev);
7978862bf1eSJeff Kirsher 	return 0;
7988862bf1eSJeff Kirsher }
7998862bf1eSJeff Kirsher 
ioc3_close(struct net_device * dev)8008862bf1eSJeff Kirsher static int ioc3_close(struct net_device *dev)
8018862bf1eSJeff Kirsher {
8028862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
8038862bf1eSJeff Kirsher 
8048862bf1eSJeff Kirsher 	del_timer_sync(&ip->ioc3_timer);
8058862bf1eSJeff Kirsher 
8068862bf1eSJeff Kirsher 	netif_stop_queue(dev);
8078862bf1eSJeff Kirsher 
8088862bf1eSJeff Kirsher 	ioc3_stop(ip);
8098862bf1eSJeff Kirsher 
8109c328b05SThomas Bogendoerfer 	ioc3_free_rx_bufs(ip);
8119c328b05SThomas Bogendoerfer 	ioc3_clean_tx_ring(ip);
8129c328b05SThomas Bogendoerfer 
8138862bf1eSJeff Kirsher 	return 0;
8148862bf1eSJeff Kirsher }
8158862bf1eSJeff Kirsher 
8168862bf1eSJeff Kirsher static const struct net_device_ops ioc3_netdev_ops = {
8178862bf1eSJeff Kirsher 	.ndo_open		= ioc3_open,
8188862bf1eSJeff Kirsher 	.ndo_stop		= ioc3_close,
8198862bf1eSJeff Kirsher 	.ndo_start_xmit		= ioc3_start_xmit,
8208862bf1eSJeff Kirsher 	.ndo_tx_timeout		= ioc3_timeout,
8218862bf1eSJeff Kirsher 	.ndo_get_stats		= ioc3_get_stats,
822afc4b13dSJiri Pirko 	.ndo_set_rx_mode	= ioc3_set_multicast_list,
823a7605370SArnd Bergmann 	.ndo_eth_ioctl		= ioc3_ioctl,
8248862bf1eSJeff Kirsher 	.ndo_validate_addr	= eth_validate_addr,
8258862bf1eSJeff Kirsher 	.ndo_set_mac_address	= ioc3_set_mac_address,
8268862bf1eSJeff Kirsher };
8278862bf1eSJeff Kirsher 
ioc3eth_probe(struct platform_device * pdev)8280ce5ebd2SThomas Bogendoerfer static int ioc3eth_probe(struct platform_device *pdev)
8298862bf1eSJeff Kirsher {
8300ce5ebd2SThomas Bogendoerfer 	u32 sw_physid1, sw_physid2, vendor, model, rev;
8318862bf1eSJeff Kirsher 	struct ioc3_private *ip;
8320ce5ebd2SThomas Bogendoerfer 	struct net_device *dev;
8330ce5ebd2SThomas Bogendoerfer 	struct resource *regs;
8340ce5ebd2SThomas Bogendoerfer 	u8 mac_addr[6];
835051a07ecSChristoph Hellwig 	int err;
8368862bf1eSJeff Kirsher 
8370ce5ebd2SThomas Bogendoerfer 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
838db8f7be1SYang Yingliang 	if (!regs) {
839db8f7be1SYang Yingliang 		dev_err(&pdev->dev, "Invalid resource\n");
840db8f7be1SYang Yingliang 		return -EINVAL;
841db8f7be1SYang Yingliang 	}
8420ce5ebd2SThomas Bogendoerfer 	/* get mac addr from one wire prom */
8430ce5ebd2SThomas Bogendoerfer 	if (ioc3eth_get_mac_addr(regs, mac_addr))
8440ce5ebd2SThomas Bogendoerfer 		return -EPROBE_DEFER; /* not available yet */
8458862bf1eSJeff Kirsher 
8468862bf1eSJeff Kirsher 	dev = alloc_etherdev(sizeof(struct ioc3_private));
8470ce5ebd2SThomas Bogendoerfer 	if (!dev)
8480ce5ebd2SThomas Bogendoerfer 		return -ENOMEM;
8498862bf1eSJeff Kirsher 
8508862bf1eSJeff Kirsher 	SET_NETDEV_DEV(dev, &pdev->dev);
8518862bf1eSJeff Kirsher 
8528862bf1eSJeff Kirsher 	ip = netdev_priv(dev);
8530ce5ebd2SThomas Bogendoerfer 	ip->dma_dev = pdev->dev.parent;
8540ce5ebd2SThomas Bogendoerfer 	ip->regs = devm_platform_ioremap_resource(pdev, 0);
855a7654211STang Bin 	if (IS_ERR(ip->regs)) {
856a7654211STang Bin 		err = PTR_ERR(ip->regs);
8570ce5ebd2SThomas Bogendoerfer 		goto out_free;
8588862bf1eSJeff Kirsher 	}
8598862bf1eSJeff Kirsher 
8600ce5ebd2SThomas Bogendoerfer 	ip->ssram = devm_platform_ioremap_resource(pdev, 1);
861a7654211STang Bin 	if (IS_ERR(ip->ssram)) {
862a7654211STang Bin 		err = PTR_ERR(ip->ssram);
8630ce5ebd2SThomas Bogendoerfer 		goto out_free;
8640ce5ebd2SThomas Bogendoerfer 	}
8650ce5ebd2SThomas Bogendoerfer 
8660ce5ebd2SThomas Bogendoerfer 	dev->irq = platform_get_irq(pdev, 0);
8670ce5ebd2SThomas Bogendoerfer 	if (dev->irq < 0) {
8680ce5ebd2SThomas Bogendoerfer 		err = dev->irq;
8690ce5ebd2SThomas Bogendoerfer 		goto out_free;
8700ce5ebd2SThomas Bogendoerfer 	}
8710ce5ebd2SThomas Bogendoerfer 
8720ce5ebd2SThomas Bogendoerfer 	if (devm_request_irq(&pdev->dev, dev->irq, ioc3_interrupt,
8730ce5ebd2SThomas Bogendoerfer 			     IRQF_SHARED, "ioc3-eth", dev)) {
8740ce5ebd2SThomas Bogendoerfer 		dev_err(&pdev->dev, "Can't get irq %d\n", dev->irq);
8750ce5ebd2SThomas Bogendoerfer 		err = -ENODEV;
8760ce5ebd2SThomas Bogendoerfer 		goto out_free;
8770ce5ebd2SThomas Bogendoerfer 	}
8788862bf1eSJeff Kirsher 
8798862bf1eSJeff Kirsher 	spin_lock_init(&ip->ioc3_lock);
880dfc57004SKees Cook 	timer_setup(&ip->ioc3_timer, ioc3_timer, 0);
8818862bf1eSJeff Kirsher 
8828862bf1eSJeff Kirsher 	ioc3_stop(ip);
883c7b57274SThomas Bogendoerfer 
884c7b57274SThomas Bogendoerfer 	/* Allocate rx ring.  4kb = 512 entries, must be 4kb aligned */
8854dd14747SChristoph Hellwig 	ip->rxr = dma_alloc_coherent(ip->dma_dev, RX_RING_SIZE, &ip->rxr_dma,
88659511bcfSChristoph Hellwig 				     GFP_KERNEL);
887c7b57274SThomas Bogendoerfer 	if (!ip->rxr) {
888c7b57274SThomas Bogendoerfer 		pr_err("ioc3-eth: rx ring allocation failed\n");
889c7b57274SThomas Bogendoerfer 		err = -ENOMEM;
890c7b57274SThomas Bogendoerfer 		goto out_stop;
891c7b57274SThomas Bogendoerfer 	}
892c7b57274SThomas Bogendoerfer 
893c7b57274SThomas Bogendoerfer 	/* Allocate tx rings.  16kb = 128 bufs, must be 16kb aligned  */
894369a782aSThomas Bogendoerfer 	ip->tx_ring = dma_alloc_coherent(ip->dma_dev, TX_RING_SIZE + SZ_16K - 1,
895369a782aSThomas Bogendoerfer 					 &ip->txr_dma, GFP_KERNEL);
896369a782aSThomas Bogendoerfer 	if (!ip->tx_ring) {
897c7b57274SThomas Bogendoerfer 		pr_err("ioc3-eth: tx ring allocation failed\n");
898c7b57274SThomas Bogendoerfer 		err = -ENOMEM;
899c7b57274SThomas Bogendoerfer 		goto out_stop;
900c7b57274SThomas Bogendoerfer 	}
901369a782aSThomas Bogendoerfer 	/* Align TX ring */
902369a782aSThomas Bogendoerfer 	ip->txr = PTR_ALIGN(ip->tx_ring, SZ_16K);
903369a782aSThomas Bogendoerfer 	ip->txr_dma = ALIGN(ip->txr_dma, SZ_16K);
904c7b57274SThomas Bogendoerfer 
9058862bf1eSJeff Kirsher 	ioc3_init(dev);
9068862bf1eSJeff Kirsher 
9078862bf1eSJeff Kirsher 	ip->mii.phy_id_mask = 0x1f;
9088862bf1eSJeff Kirsher 	ip->mii.reg_num_mask = 0x1f;
9098862bf1eSJeff Kirsher 	ip->mii.dev = dev;
9108862bf1eSJeff Kirsher 	ip->mii.mdio_read = ioc3_mdio_read;
9118862bf1eSJeff Kirsher 	ip->mii.mdio_write = ioc3_mdio_write;
9128862bf1eSJeff Kirsher 
9138862bf1eSJeff Kirsher 	ioc3_mii_init(ip);
9148862bf1eSJeff Kirsher 
9158862bf1eSJeff Kirsher 	if (ip->mii.phy_id == -1) {
9160ce5ebd2SThomas Bogendoerfer 		netdev_err(dev, "Didn't find a PHY, goodbye.\n");
9178862bf1eSJeff Kirsher 		err = -ENODEV;
9188862bf1eSJeff Kirsher 		goto out_stop;
9198862bf1eSJeff Kirsher 	}
9208862bf1eSJeff Kirsher 
9218862bf1eSJeff Kirsher 	ioc3_mii_start(ip);
9228862bf1eSJeff Kirsher 	ioc3_ssram_disc(ip);
923a96d317fSJakub Kicinski 	eth_hw_addr_set(dev, mac_addr);
9248862bf1eSJeff Kirsher 
9258862bf1eSJeff Kirsher 	/* The IOC3-specific entries in the device structure. */
9268862bf1eSJeff Kirsher 	dev->watchdog_timeo	= 5 * HZ;
9278862bf1eSJeff Kirsher 	dev->netdev_ops		= &ioc3_netdev_ops;
9288862bf1eSJeff Kirsher 	dev->ethtool_ops	= &ioc3_ethtool_ops;
9298862bf1eSJeff Kirsher 	dev->hw_features	= NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
9307ca2c4c2SChristoph Hellwig 	dev->features		= NETIF_F_IP_CSUM | NETIF_F_HIGHDMA;
9318862bf1eSJeff Kirsher 
9328862bf1eSJeff Kirsher 	sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1);
9338862bf1eSJeff Kirsher 	sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2);
9348862bf1eSJeff Kirsher 
9358862bf1eSJeff Kirsher 	err = register_netdev(dev);
9368862bf1eSJeff Kirsher 	if (err)
9378862bf1eSJeff Kirsher 		goto out_stop;
9388862bf1eSJeff Kirsher 
9398862bf1eSJeff Kirsher 	mii_check_media(&ip->mii, 1, 1);
9408862bf1eSJeff Kirsher 	ioc3_setup_duplex(ip);
9418862bf1eSJeff Kirsher 
9428862bf1eSJeff Kirsher 	vendor = (sw_physid1 << 12) | (sw_physid2 >> 4);
9438862bf1eSJeff Kirsher 	model  = (sw_physid2 >> 4) & 0x3f;
9448862bf1eSJeff Kirsher 	rev    = sw_physid2 & 0xf;
945c1b6a3d8SThomas Bogendoerfer 	netdev_info(dev, "Using PHY %d, vendor 0x%x, model %d, rev %d.\n",
946c1b6a3d8SThomas Bogendoerfer 		    ip->mii.phy_id, vendor, model, rev);
947c1b6a3d8SThomas Bogendoerfer 	netdev_info(dev, "IOC3 SSRAM has %d kbyte.\n",
9488862bf1eSJeff Kirsher 		    ip->emcr & EMCR_BUFSIZ ? 128 : 64);
9498862bf1eSJeff Kirsher 
9508862bf1eSJeff Kirsher 	return 0;
9518862bf1eSJeff Kirsher 
9528862bf1eSJeff Kirsher out_stop:
9538862bf1eSJeff Kirsher 	del_timer_sync(&ip->ioc3_timer);
954c7b57274SThomas Bogendoerfer 	if (ip->rxr)
9554dd14747SChristoph Hellwig 		dma_free_coherent(ip->dma_dev, RX_RING_SIZE, ip->rxr,
9564dd14747SChristoph Hellwig 				  ip->rxr_dma);
957369a782aSThomas Bogendoerfer 	if (ip->tx_ring)
958edab74e9SChristophe JAILLET 		dma_free_coherent(ip->dma_dev, TX_RING_SIZE + SZ_16K - 1, ip->tx_ring,
9594dd14747SChristoph Hellwig 				  ip->txr_dma);
9608862bf1eSJeff Kirsher out_free:
9618862bf1eSJeff Kirsher 	free_netdev(dev);
9628862bf1eSJeff Kirsher 	return err;
9638862bf1eSJeff Kirsher }
9648862bf1eSJeff Kirsher 
ioc3eth_remove(struct platform_device * pdev)9650ce5ebd2SThomas Bogendoerfer static int ioc3eth_remove(struct platform_device *pdev)
9668862bf1eSJeff Kirsher {
9670ce5ebd2SThomas Bogendoerfer 	struct net_device *dev = platform_get_drvdata(pdev);
9688862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
9698862bf1eSJeff Kirsher 
9704dd14747SChristoph Hellwig 	dma_free_coherent(ip->dma_dev, RX_RING_SIZE, ip->rxr, ip->rxr_dma);
971edab74e9SChristophe JAILLET 	dma_free_coherent(ip->dma_dev, TX_RING_SIZE + SZ_16K - 1, ip->tx_ring, ip->txr_dma);
972c7b57274SThomas Bogendoerfer 
9738862bf1eSJeff Kirsher 	unregister_netdev(dev);
9748862bf1eSJeff Kirsher 	del_timer_sync(&ip->ioc3_timer);
9758862bf1eSJeff Kirsher 	free_netdev(dev);
9760ce5ebd2SThomas Bogendoerfer 
9770ce5ebd2SThomas Bogendoerfer 	return 0;
9788862bf1eSJeff Kirsher }
9798862bf1eSJeff Kirsher 
9808862bf1eSJeff Kirsher 
ioc3_start_xmit(struct sk_buff * skb,struct net_device * dev)98128d304efSYueHaibing static netdev_tx_t ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
9828862bf1eSJeff Kirsher {
9838862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
9848862bf1eSJeff Kirsher 	struct ioc3_etxd *desc;
985cbe7d517SThomas Bogendoerfer 	unsigned long data;
986cbe7d517SThomas Bogendoerfer 	unsigned int len;
9878862bf1eSJeff Kirsher 	int produce;
988c1b6a3d8SThomas Bogendoerfer 	u32 w0 = 0;
9898862bf1eSJeff Kirsher 
990c1b6a3d8SThomas Bogendoerfer 	/* IOC3 has a fairly simple minded checksumming hardware which simply
9918862bf1eSJeff Kirsher 	 * adds up the 1's complement checksum for the entire packet and
9928862bf1eSJeff Kirsher 	 * inserts it at an offset which can be specified in the descriptor
9938862bf1eSJeff Kirsher 	 * into the transmit packet.  This means we have to compensate for the
9948862bf1eSJeff Kirsher 	 * MAC header which should not be summed and the TCP/UDP pseudo headers
9958862bf1eSJeff Kirsher 	 * manually.
9968862bf1eSJeff Kirsher 	 */
9978862bf1eSJeff Kirsher 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
9988862bf1eSJeff Kirsher 		const struct iphdr *ih = ip_hdr(skb);
9998862bf1eSJeff Kirsher 		const int proto = ntohs(ih->protocol);
10008862bf1eSJeff Kirsher 		unsigned int csoff;
1001c1b6a3d8SThomas Bogendoerfer 		u32 csum, ehsum;
1002c1b6a3d8SThomas Bogendoerfer 		u16 *eh;
10038862bf1eSJeff Kirsher 
10048862bf1eSJeff Kirsher 		/* The MAC header.  skb->mac seem the logic approach
1005c1b6a3d8SThomas Bogendoerfer 		 * to find the MAC header - except it's a NULL pointer ...
1006c1b6a3d8SThomas Bogendoerfer 		 */
1007c1b6a3d8SThomas Bogendoerfer 		eh = (u16 *)skb->data;
10088862bf1eSJeff Kirsher 
10098862bf1eSJeff Kirsher 		/* Sum up dest addr, src addr and protocol  */
10108862bf1eSJeff Kirsher 		ehsum = eh[0] + eh[1] + eh[2] + eh[3] + eh[4] + eh[5] + eh[6];
10118862bf1eSJeff Kirsher 
10128862bf1eSJeff Kirsher 		/* Skip IP header; it's sum is always zero and was
1013c1b6a3d8SThomas Bogendoerfer 		 * already filled in by ip_output.c
1014c1b6a3d8SThomas Bogendoerfer 		 */
10158862bf1eSJeff Kirsher 		csum = csum_tcpudp_nofold(ih->saddr, ih->daddr,
10168862bf1eSJeff Kirsher 					  ih->tot_len - (ih->ihl << 2),
10178dff19a6SThomas Bogendoerfer 					  proto, csum_fold(ehsum));
10188862bf1eSJeff Kirsher 
10198862bf1eSJeff Kirsher 		csum = (csum & 0xffff) + (csum >> 16);	/* Fold again */
10208862bf1eSJeff Kirsher 		csum = (csum & 0xffff) + (csum >> 16);
10218862bf1eSJeff Kirsher 
10228862bf1eSJeff Kirsher 		csoff = ETH_HLEN + (ih->ihl << 2);
10238862bf1eSJeff Kirsher 		if (proto == IPPROTO_UDP) {
10248862bf1eSJeff Kirsher 			csoff += offsetof(struct udphdr, check);
10258862bf1eSJeff Kirsher 			udp_hdr(skb)->check = csum;
10268862bf1eSJeff Kirsher 		}
10278862bf1eSJeff Kirsher 		if (proto == IPPROTO_TCP) {
10288862bf1eSJeff Kirsher 			csoff += offsetof(struct tcphdr, check);
10298862bf1eSJeff Kirsher 			tcp_hdr(skb)->check = csum;
10308862bf1eSJeff Kirsher 		}
10318862bf1eSJeff Kirsher 
10328862bf1eSJeff Kirsher 		w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT);
10338862bf1eSJeff Kirsher 	}
10348862bf1eSJeff Kirsher 
10358862bf1eSJeff Kirsher 	spin_lock_irq(&ip->ioc3_lock);
10368862bf1eSJeff Kirsher 
10378862bf1eSJeff Kirsher 	data = (unsigned long)skb->data;
10388862bf1eSJeff Kirsher 	len = skb->len;
10398862bf1eSJeff Kirsher 
10408862bf1eSJeff Kirsher 	produce = ip->tx_pi;
10418862bf1eSJeff Kirsher 	desc = &ip->txr[produce];
10428862bf1eSJeff Kirsher 
10438862bf1eSJeff Kirsher 	if (len <= 104) {
10448862bf1eSJeff Kirsher 		/* Short packet, let's copy it directly into the ring.  */
10458862bf1eSJeff Kirsher 		skb_copy_from_linear_data(skb, desc->data, skb->len);
10468862bf1eSJeff Kirsher 		if (len < ETH_ZLEN) {
10478862bf1eSJeff Kirsher 			/* Very short packet, pad with zeros at the end. */
10488862bf1eSJeff Kirsher 			memset(desc->data + len, 0, ETH_ZLEN - len);
10498862bf1eSJeff Kirsher 			len = ETH_ZLEN;
10508862bf1eSJeff Kirsher 		}
10518862bf1eSJeff Kirsher 		desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_D0V | w0);
10528862bf1eSJeff Kirsher 		desc->bufcnt = cpu_to_be32(len);
10538862bf1eSJeff Kirsher 	} else if ((data ^ (data + len - 1)) & 0x4000) {
10548862bf1eSJeff Kirsher 		unsigned long b2 = (data | 0x3fffUL) + 1UL;
10558862bf1eSJeff Kirsher 		unsigned long s1 = b2 - data;
10568862bf1eSJeff Kirsher 		unsigned long s2 = data + len - b2;
1057ed870f6aSThomas Bogendoerfer 		dma_addr_t d1, d2;
10588862bf1eSJeff Kirsher 
10598862bf1eSJeff Kirsher 		desc->cmd    = cpu_to_be32(len | ETXD_INTWHENDONE |
10608862bf1eSJeff Kirsher 					   ETXD_B1V | ETXD_B2V | w0);
10618862bf1eSJeff Kirsher 		desc->bufcnt = cpu_to_be32((s1 << ETXD_B1CNT_SHIFT) |
10628862bf1eSJeff Kirsher 					   (s2 << ETXD_B2CNT_SHIFT));
1063ed870f6aSThomas Bogendoerfer 		d1 = dma_map_single(ip->dma_dev, skb->data, s1, DMA_TO_DEVICE);
1064ed870f6aSThomas Bogendoerfer 		if (dma_mapping_error(ip->dma_dev, d1))
1065ed870f6aSThomas Bogendoerfer 			goto drop_packet;
1066ed870f6aSThomas Bogendoerfer 		d2 = dma_map_single(ip->dma_dev, (void *)b2, s1, DMA_TO_DEVICE);
1067ed870f6aSThomas Bogendoerfer 		if (dma_mapping_error(ip->dma_dev, d2)) {
1068ed870f6aSThomas Bogendoerfer 			dma_unmap_single(ip->dma_dev, d1, len, DMA_TO_DEVICE);
1069ed870f6aSThomas Bogendoerfer 			goto drop_packet;
1070ed870f6aSThomas Bogendoerfer 		}
1071ed870f6aSThomas Bogendoerfer 		desc->p1     = cpu_to_be64(ioc3_map(d1, PCI64_ATTR_PREF));
1072ed870f6aSThomas Bogendoerfer 		desc->p2     = cpu_to_be64(ioc3_map(d2, PCI64_ATTR_PREF));
10738862bf1eSJeff Kirsher 	} else {
1074ed870f6aSThomas Bogendoerfer 		dma_addr_t d;
1075ed870f6aSThomas Bogendoerfer 
10768862bf1eSJeff Kirsher 		/* Normal sized packet that doesn't cross a page boundary. */
10778862bf1eSJeff Kirsher 		desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_B1V | w0);
10788862bf1eSJeff Kirsher 		desc->bufcnt = cpu_to_be32(len << ETXD_B1CNT_SHIFT);
1079ed870f6aSThomas Bogendoerfer 		d = dma_map_single(ip->dma_dev, skb->data, len, DMA_TO_DEVICE);
1080ed870f6aSThomas Bogendoerfer 		if (dma_mapping_error(ip->dma_dev, d))
1081ed870f6aSThomas Bogendoerfer 			goto drop_packet;
1082ed870f6aSThomas Bogendoerfer 		desc->p1     = cpu_to_be64(ioc3_map(d, PCI64_ATTR_PREF));
10838862bf1eSJeff Kirsher 	}
10848862bf1eSJeff Kirsher 
1085c1b6a3d8SThomas Bogendoerfer 	mb(); /* make sure all descriptor changes are visible */
10868862bf1eSJeff Kirsher 
10878862bf1eSJeff Kirsher 	ip->tx_skbs[produce] = skb;			/* Remember skb */
1088141a7dbbSThomas Bogendoerfer 	produce = (produce + 1) & TX_RING_MASK;
10898862bf1eSJeff Kirsher 	ip->tx_pi = produce;
1090cbe7d517SThomas Bogendoerfer 	writel(produce << 7, &ip->regs->etpir);		/* Fire ... */
10918862bf1eSJeff Kirsher 
10928862bf1eSJeff Kirsher 	ip->txqlen++;
10938862bf1eSJeff Kirsher 
1094141a7dbbSThomas Bogendoerfer 	if (ip->txqlen >= (TX_RING_ENTRIES - 1))
10958862bf1eSJeff Kirsher 		netif_stop_queue(dev);
10968862bf1eSJeff Kirsher 
10978862bf1eSJeff Kirsher 	spin_unlock_irq(&ip->ioc3_lock);
10988862bf1eSJeff Kirsher 
10998862bf1eSJeff Kirsher 	return NETDEV_TX_OK;
1100ed870f6aSThomas Bogendoerfer 
1101ed870f6aSThomas Bogendoerfer drop_packet:
1102ed870f6aSThomas Bogendoerfer 	dev_kfree_skb_any(skb);
1103ed870f6aSThomas Bogendoerfer 	dev->stats.tx_dropped++;
1104ed870f6aSThomas Bogendoerfer 
1105ed870f6aSThomas Bogendoerfer 	spin_unlock_irq(&ip->ioc3_lock);
1106ed870f6aSThomas Bogendoerfer 
1107ed870f6aSThomas Bogendoerfer 	return NETDEV_TX_OK;
11088862bf1eSJeff Kirsher }
11098862bf1eSJeff Kirsher 
ioc3_timeout(struct net_device * dev,unsigned int txqueue)11100290bd29SMichael S. Tsirkin static void ioc3_timeout(struct net_device *dev, unsigned int txqueue)
11118862bf1eSJeff Kirsher {
11128862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
11138862bf1eSJeff Kirsher 
1114c1b6a3d8SThomas Bogendoerfer 	netdev_err(dev, "transmit timed out, resetting\n");
11158862bf1eSJeff Kirsher 
11168862bf1eSJeff Kirsher 	spin_lock_irq(&ip->ioc3_lock);
11178862bf1eSJeff Kirsher 
11188862bf1eSJeff Kirsher 	ioc3_stop(ip);
111919a957b6SThomas Bogendoerfer 	ioc3_free_rx_bufs(ip);
112019a957b6SThomas Bogendoerfer 	ioc3_clean_tx_ring(ip);
112119a957b6SThomas Bogendoerfer 
11228862bf1eSJeff Kirsher 	ioc3_init(dev);
1123850d2fedSThomas Bogendoerfer 	if (ioc3_alloc_rx_bufs(dev)) {
1124850d2fedSThomas Bogendoerfer 		netdev_err(dev, "%s: rx buffer allocation failed\n", __func__);
1125850d2fedSThomas Bogendoerfer 		spin_unlock_irq(&ip->ioc3_lock);
1126850d2fedSThomas Bogendoerfer 		return;
1127850d2fedSThomas Bogendoerfer 	}
1128fcd0da5aSThomas Bogendoerfer 	ioc3_start(ip);
11298862bf1eSJeff Kirsher 	ioc3_mii_init(ip);
11308862bf1eSJeff Kirsher 	ioc3_mii_start(ip);
11318862bf1eSJeff Kirsher 
11328862bf1eSJeff Kirsher 	spin_unlock_irq(&ip->ioc3_lock);
11338862bf1eSJeff Kirsher 
11348862bf1eSJeff Kirsher 	netif_wake_queue(dev);
11358862bf1eSJeff Kirsher }
11368862bf1eSJeff Kirsher 
1137c1b6a3d8SThomas Bogendoerfer /* Given a multicast ethernet address, this routine calculates the
11388862bf1eSJeff Kirsher  * address's bit index in the logical address filter mask
11398862bf1eSJeff Kirsher  */
ioc3_hash(const unsigned char * addr)11408862bf1eSJeff Kirsher static inline unsigned int ioc3_hash(const unsigned char *addr)
11418862bf1eSJeff Kirsher {
11428862bf1eSJeff Kirsher 	unsigned int temp = 0;
11438862bf1eSJeff Kirsher 	int bits;
1144c1b6a3d8SThomas Bogendoerfer 	u32 crc;
11458862bf1eSJeff Kirsher 
11468862bf1eSJeff Kirsher 	crc = ether_crc_le(ETH_ALEN, addr);
11478862bf1eSJeff Kirsher 
11488862bf1eSJeff Kirsher 	crc &= 0x3f;    /* bit reverse lowest 6 bits for hash index */
11498862bf1eSJeff Kirsher 	for (bits = 6; --bits >= 0; ) {
11508862bf1eSJeff Kirsher 		temp <<= 1;
11518862bf1eSJeff Kirsher 		temp |= (crc & 0x1);
11528862bf1eSJeff Kirsher 		crc >>= 1;
11538862bf1eSJeff Kirsher 	}
11548862bf1eSJeff Kirsher 
11558862bf1eSJeff Kirsher 	return temp;
11568862bf1eSJeff Kirsher }
11578862bf1eSJeff Kirsher 
ioc3_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)11588862bf1eSJeff Kirsher static void ioc3_get_drvinfo(struct net_device *dev,
11598862bf1eSJeff Kirsher 			     struct ethtool_drvinfo *info)
11608862bf1eSJeff Kirsher {
1161*f029c781SWolfram Sang 	strscpy(info->driver, IOC3_NAME, sizeof(info->driver));
1162*f029c781SWolfram Sang 	strscpy(info->version, IOC3_VERSION, sizeof(info->version));
1163*f029c781SWolfram Sang 	strscpy(info->bus_info, pci_name(to_pci_dev(dev->dev.parent)),
11640ce5ebd2SThomas Bogendoerfer 		sizeof(info->bus_info));
11658862bf1eSJeff Kirsher }
11668862bf1eSJeff Kirsher 
ioc3_get_link_ksettings(struct net_device * dev,struct ethtool_link_ksettings * cmd)1167b61a26f8SPhilippe Reynes static int ioc3_get_link_ksettings(struct net_device *dev,
1168b61a26f8SPhilippe Reynes 				   struct ethtool_link_ksettings *cmd)
11698862bf1eSJeff Kirsher {
11708862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
11718862bf1eSJeff Kirsher 
11728862bf1eSJeff Kirsher 	spin_lock_irq(&ip->ioc3_lock);
117382c01a84Syuval.shaia@oracle.com 	mii_ethtool_get_link_ksettings(&ip->mii, cmd);
11748862bf1eSJeff Kirsher 	spin_unlock_irq(&ip->ioc3_lock);
11758862bf1eSJeff Kirsher 
117682c01a84Syuval.shaia@oracle.com 	return 0;
11778862bf1eSJeff Kirsher }
11788862bf1eSJeff Kirsher 
ioc3_set_link_ksettings(struct net_device * dev,const struct ethtool_link_ksettings * cmd)1179b61a26f8SPhilippe Reynes static int ioc3_set_link_ksettings(struct net_device *dev,
1180b61a26f8SPhilippe Reynes 				   const struct ethtool_link_ksettings *cmd)
11818862bf1eSJeff Kirsher {
11828862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
11838862bf1eSJeff Kirsher 	int rc;
11848862bf1eSJeff Kirsher 
11858862bf1eSJeff Kirsher 	spin_lock_irq(&ip->ioc3_lock);
1186b61a26f8SPhilippe Reynes 	rc = mii_ethtool_set_link_ksettings(&ip->mii, cmd);
11878862bf1eSJeff Kirsher 	spin_unlock_irq(&ip->ioc3_lock);
11888862bf1eSJeff Kirsher 
11898862bf1eSJeff Kirsher 	return rc;
11908862bf1eSJeff Kirsher }
11918862bf1eSJeff Kirsher 
ioc3_nway_reset(struct net_device * dev)11928862bf1eSJeff Kirsher static int ioc3_nway_reset(struct net_device *dev)
11938862bf1eSJeff Kirsher {
11948862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
11958862bf1eSJeff Kirsher 	int rc;
11968862bf1eSJeff Kirsher 
11978862bf1eSJeff Kirsher 	spin_lock_irq(&ip->ioc3_lock);
11988862bf1eSJeff Kirsher 	rc = mii_nway_restart(&ip->mii);
11998862bf1eSJeff Kirsher 	spin_unlock_irq(&ip->ioc3_lock);
12008862bf1eSJeff Kirsher 
12018862bf1eSJeff Kirsher 	return rc;
12028862bf1eSJeff Kirsher }
12038862bf1eSJeff Kirsher 
ioc3_get_link(struct net_device * dev)12048862bf1eSJeff Kirsher static u32 ioc3_get_link(struct net_device *dev)
12058862bf1eSJeff Kirsher {
12068862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
12078862bf1eSJeff Kirsher 	int rc;
12088862bf1eSJeff Kirsher 
12098862bf1eSJeff Kirsher 	spin_lock_irq(&ip->ioc3_lock);
12108862bf1eSJeff Kirsher 	rc = mii_link_ok(&ip->mii);
12118862bf1eSJeff Kirsher 	spin_unlock_irq(&ip->ioc3_lock);
12128862bf1eSJeff Kirsher 
12138862bf1eSJeff Kirsher 	return rc;
12148862bf1eSJeff Kirsher }
12158862bf1eSJeff Kirsher 
12168862bf1eSJeff Kirsher static const struct ethtool_ops ioc3_ethtool_ops = {
12178862bf1eSJeff Kirsher 	.get_drvinfo		= ioc3_get_drvinfo,
12188862bf1eSJeff Kirsher 	.nway_reset		= ioc3_nway_reset,
12198862bf1eSJeff Kirsher 	.get_link		= ioc3_get_link,
1220b61a26f8SPhilippe Reynes 	.get_link_ksettings	= ioc3_get_link_ksettings,
1221b61a26f8SPhilippe Reynes 	.set_link_ksettings	= ioc3_set_link_ksettings,
12228862bf1eSJeff Kirsher };
12238862bf1eSJeff Kirsher 
ioc3_ioctl(struct net_device * dev,struct ifreq * rq,int cmd)12248862bf1eSJeff Kirsher static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
12258862bf1eSJeff Kirsher {
12268862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
12278862bf1eSJeff Kirsher 	int rc;
12288862bf1eSJeff Kirsher 
12298862bf1eSJeff Kirsher 	spin_lock_irq(&ip->ioc3_lock);
12308862bf1eSJeff Kirsher 	rc = generic_mii_ioctl(&ip->mii, if_mii(rq), cmd, NULL);
12318862bf1eSJeff Kirsher 	spin_unlock_irq(&ip->ioc3_lock);
12328862bf1eSJeff Kirsher 
12338862bf1eSJeff Kirsher 	return rc;
12348862bf1eSJeff Kirsher }
12358862bf1eSJeff Kirsher 
ioc3_set_multicast_list(struct net_device * dev)12368862bf1eSJeff Kirsher static void ioc3_set_multicast_list(struct net_device *dev)
12378862bf1eSJeff Kirsher {
12388862bf1eSJeff Kirsher 	struct ioc3_private *ip = netdev_priv(dev);
1239cbe7d517SThomas Bogendoerfer 	struct ioc3_ethregs *regs = ip->regs;
1240cbe7d517SThomas Bogendoerfer 	struct netdev_hw_addr *ha;
12418862bf1eSJeff Kirsher 	u64 ehar = 0;
12428862bf1eSJeff Kirsher 
1243d1c94542SThomas Bogendoerfer 	spin_lock_irq(&ip->ioc3_lock);
1244d1c94542SThomas Bogendoerfer 
12458862bf1eSJeff Kirsher 	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous.  */
12468862bf1eSJeff Kirsher 		ip->emcr |= EMCR_PROMISC;
1247cbe7d517SThomas Bogendoerfer 		writel(ip->emcr, &regs->emcr);
1248cbe7d517SThomas Bogendoerfer 		readl(&regs->emcr);
12498862bf1eSJeff Kirsher 	} else {
12508862bf1eSJeff Kirsher 		ip->emcr &= ~EMCR_PROMISC;
1251cbe7d517SThomas Bogendoerfer 		writel(ip->emcr, &regs->emcr);		/* Clear promiscuous. */
1252cbe7d517SThomas Bogendoerfer 		readl(&regs->emcr);
12538862bf1eSJeff Kirsher 
12548862bf1eSJeff Kirsher 		if ((dev->flags & IFF_ALLMULTI) ||
12558862bf1eSJeff Kirsher 		    (netdev_mc_count(dev) > 64)) {
12568862bf1eSJeff Kirsher 			/* Too many for hashing to make sense or we want all
1257c1b6a3d8SThomas Bogendoerfer 			 * multicast packets anyway,  so skip computing all the
1258c1b6a3d8SThomas Bogendoerfer 			 * hashes and just accept all packets.
1259c1b6a3d8SThomas Bogendoerfer 			 */
12608862bf1eSJeff Kirsher 			ip->ehar_h = 0xffffffff;
12618862bf1eSJeff Kirsher 			ip->ehar_l = 0xffffffff;
12628862bf1eSJeff Kirsher 		} else {
12638862bf1eSJeff Kirsher 			netdev_for_each_mc_addr(ha, dev) {
12648862bf1eSJeff Kirsher 				ehar |= (1UL << ioc3_hash(ha->addr));
12658862bf1eSJeff Kirsher 			}
12668862bf1eSJeff Kirsher 			ip->ehar_h = ehar >> 32;
12678862bf1eSJeff Kirsher 			ip->ehar_l = ehar & 0xffffffff;
12688862bf1eSJeff Kirsher 		}
1269cbe7d517SThomas Bogendoerfer 		writel(ip->ehar_h, &regs->ehar_h);
1270cbe7d517SThomas Bogendoerfer 		writel(ip->ehar_l, &regs->ehar_l);
12718862bf1eSJeff Kirsher 	}
12728862bf1eSJeff Kirsher 
1273d1c94542SThomas Bogendoerfer 	spin_unlock_irq(&ip->ioc3_lock);
12748862bf1eSJeff Kirsher }
12758862bf1eSJeff Kirsher 
12760ce5ebd2SThomas Bogendoerfer static struct platform_driver ioc3eth_driver = {
12770ce5ebd2SThomas Bogendoerfer 	.probe  = ioc3eth_probe,
12780ce5ebd2SThomas Bogendoerfer 	.remove = ioc3eth_remove,
12790ce5ebd2SThomas Bogendoerfer 	.driver = {
12800ce5ebd2SThomas Bogendoerfer 		.name = "ioc3-eth",
12810ce5ebd2SThomas Bogendoerfer 	}
12820ce5ebd2SThomas Bogendoerfer };
12830ce5ebd2SThomas Bogendoerfer 
12840ce5ebd2SThomas Bogendoerfer module_platform_driver(ioc3eth_driver);
12850ce5ebd2SThomas Bogendoerfer 
12868862bf1eSJeff Kirsher MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
12878862bf1eSJeff Kirsher MODULE_DESCRIPTION("SGI IOC3 Ethernet driver");
12888862bf1eSJeff Kirsher MODULE_LICENSE("GPL");
1289