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(®s->micr) & MICR_BUSY)
264cbe7d517SThomas Bogendoerfer ;
265cbe7d517SThomas Bogendoerfer writel((phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG,
266cbe7d517SThomas Bogendoerfer ®s->micr);
267cbe7d517SThomas Bogendoerfer while (readl(®s->micr) & MICR_BUSY)
268cbe7d517SThomas Bogendoerfer ;
2698862bf1eSJeff Kirsher
270cbe7d517SThomas Bogendoerfer return readl(®s->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(®s->micr) & MICR_BUSY)
279cbe7d517SThomas Bogendoerfer ;
280cbe7d517SThomas Bogendoerfer writel(data, ®s->midr_w);
281cbe7d517SThomas Bogendoerfer writel((phy << MICR_PHYADDR_SHIFT) | reg, ®s->micr);
282cbe7d517SThomas Bogendoerfer while (readl(®s->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(®s->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(®s->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(®s->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(®s->eisr);
539cbe7d517SThomas Bogendoerfer writel(eisr, ®s->eisr);
540cbe7d517SThomas Bogendoerfer readl(®s->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, ®s->etcsr);
5618862bf1eSJeff Kirsher ip->emcr |= EMCR_DUPLEX;
5628862bf1eSJeff Kirsher } else {
563cbe7d517SThomas Bogendoerfer writel(ETCSR_HD, ®s->etcsr);
5648862bf1eSJeff Kirsher ip->emcr &= ~EMCR_DUPLEX;
5658862bf1eSJeff Kirsher }
566cbe7d517SThomas Bogendoerfer writel(ip->emcr, ®s->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(®s->emcr) | (EMCR_BUFSIZ | EMCR_RAMPAR), ®s->emcr);
701cbe7d517SThomas Bogendoerfer readl(®s->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(®s->emcr) & ~EMCR_BUFSIZ, ®s->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, ®s->emcr); /* Reset */
724cbe7d517SThomas Bogendoerfer readl(®s->emcr); /* Flush WB */
7258862bf1eSJeff Kirsher udelay(4); /* Give it time ... */
726cbe7d517SThomas Bogendoerfer writel(0, ®s->emcr);
727cbe7d517SThomas Bogendoerfer readl(®s->emcr);
7288862bf1eSJeff Kirsher
7298862bf1eSJeff Kirsher /* Misc registers */
730ed870f6aSThomas Bogendoerfer writel(ERBAR_VAL, ®s->erbar);
731cbe7d517SThomas Bogendoerfer readl(®s->etcdc); /* Clear on read */
732cbe7d517SThomas Bogendoerfer writel(15, ®s->ercsr); /* RX low watermark */
733cbe7d517SThomas Bogendoerfer writel(0, ®s->ertr); /* Interrupt immediately */
7348862bf1eSJeff Kirsher __ioc3_set_mac_address(dev);
735cbe7d517SThomas Bogendoerfer writel(ip->ehar_h, ®s->ehar_h);
736cbe7d517SThomas Bogendoerfer writel(ip->ehar_l, ®s->ehar_l);
737cbe7d517SThomas Bogendoerfer writel(42, ®s->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, ®s->erbr_h);
748fcd0da5aSThomas Bogendoerfer writel(ring & 0xffffffff, ®s->erbr_l);
749fcd0da5aSThomas Bogendoerfer writel(ip->rx_ci << 3, ®s->ercir);
750fcd0da5aSThomas Bogendoerfer writel((ip->rx_pi << 3) | ERPIR_ARM, ®s->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, ®s->etbr_h);
758fcd0da5aSThomas Bogendoerfer writel(ring & 0xffffffff, ®s->etbr_l);
759fcd0da5aSThomas Bogendoerfer writel(ip->tx_pi << 7, ®s->etpir);
760fcd0da5aSThomas Bogendoerfer writel(ip->tx_ci << 7, ®s->etcir);
761fcd0da5aSThomas Bogendoerfer readl(®s->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, ®s->emcr);
766cbe7d517SThomas Bogendoerfer writel(EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO |
7678862bf1eSJeff Kirsher EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO |
768cbe7d517SThomas Bogendoerfer EISR_TXEXPLICIT | EISR_TXMEMERR, ®s->eier);
769cbe7d517SThomas Bogendoerfer readl(®s->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, ®s->emcr); /* Shutup */
777cbe7d517SThomas Bogendoerfer writel(0, ®s->eier); /* Disable interrupts */
778cbe7d517SThomas Bogendoerfer readl(®s->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, ®s->emcr);
1248cbe7d517SThomas Bogendoerfer readl(®s->emcr);
12498862bf1eSJeff Kirsher } else {
12508862bf1eSJeff Kirsher ip->emcr &= ~EMCR_PROMISC;
1251cbe7d517SThomas Bogendoerfer writel(ip->emcr, ®s->emcr); /* Clear promiscuous. */
1252cbe7d517SThomas Bogendoerfer readl(®s->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, ®s->ehar_h);
1270cbe7d517SThomas Bogendoerfer writel(ip->ehar_l, ®s->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