18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Network device driver for the BMAC ethernet controller on
48c2ecf20Sopenharmony_ci * Apple Powermacs.  Assumes it's under a DBDMA controller.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 1998 Randy Gobbel.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * May 1999, Al Viro: proper release of /proc/net/bmac entry, switched to
98c2ecf20Sopenharmony_ci * dynamic procfs inode.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
158c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
168c2ecf20Sopenharmony_ci#include <linux/delay.h>
178c2ecf20Sopenharmony_ci#include <linux/string.h>
188c2ecf20Sopenharmony_ci#include <linux/timer.h>
198c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
208c2ecf20Sopenharmony_ci#include <linux/init.h>
218c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
228c2ecf20Sopenharmony_ci#include <linux/crc32.h>
238c2ecf20Sopenharmony_ci#include <linux/crc32poly.h>
248c2ecf20Sopenharmony_ci#include <linux/bitrev.h>
258c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
268c2ecf20Sopenharmony_ci#include <linux/slab.h>
278c2ecf20Sopenharmony_ci#include <linux/pgtable.h>
288c2ecf20Sopenharmony_ci#include <asm/prom.h>
298c2ecf20Sopenharmony_ci#include <asm/dbdma.h>
308c2ecf20Sopenharmony_ci#include <asm/io.h>
318c2ecf20Sopenharmony_ci#include <asm/page.h>
328c2ecf20Sopenharmony_ci#include <asm/machdep.h>
338c2ecf20Sopenharmony_ci#include <asm/pmac_feature.h>
348c2ecf20Sopenharmony_ci#include <asm/macio.h>
358c2ecf20Sopenharmony_ci#include <asm/irq.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include "bmac.h"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define trunc_page(x)	((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
408c2ecf20Sopenharmony_ci#define round_page(x)	trunc_page(((unsigned long)(x)) + ((unsigned long)(PAGE_SIZE - 1)))
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* switch to use multicast code lifted from sunhme driver */
438c2ecf20Sopenharmony_ci#define SUNHME_MULTICAST
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define N_RX_RING	64
468c2ecf20Sopenharmony_ci#define N_TX_RING	32
478c2ecf20Sopenharmony_ci#define MAX_TX_ACTIVE	1
488c2ecf20Sopenharmony_ci#define ETHERCRC	4
498c2ecf20Sopenharmony_ci#define ETHERMINPACKET	64
508c2ecf20Sopenharmony_ci#define ETHERMTU	1500
518c2ecf20Sopenharmony_ci#define RX_BUFLEN	(ETHERMTU + 14 + ETHERCRC + 2)
528c2ecf20Sopenharmony_ci#define TX_TIMEOUT	HZ	/* 1 second */
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* Bits in transmit DMA status */
558c2ecf20Sopenharmony_ci#define TX_DMA_ERR	0x80
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define XXDEBUG(args)
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistruct bmac_data {
608c2ecf20Sopenharmony_ci	/* volatile struct bmac *bmac; */
618c2ecf20Sopenharmony_ci	struct sk_buff_head *queue;
628c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *tx_dma;
638c2ecf20Sopenharmony_ci	int tx_dma_intr;
648c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *rx_dma;
658c2ecf20Sopenharmony_ci	int rx_dma_intr;
668c2ecf20Sopenharmony_ci	volatile struct dbdma_cmd *tx_cmds;	/* xmit dma command list */
678c2ecf20Sopenharmony_ci	volatile struct dbdma_cmd *rx_cmds;	/* recv dma command list */
688c2ecf20Sopenharmony_ci	struct macio_dev *mdev;
698c2ecf20Sopenharmony_ci	int is_bmac_plus;
708c2ecf20Sopenharmony_ci	struct sk_buff *rx_bufs[N_RX_RING];
718c2ecf20Sopenharmony_ci	int rx_fill;
728c2ecf20Sopenharmony_ci	int rx_empty;
738c2ecf20Sopenharmony_ci	struct sk_buff *tx_bufs[N_TX_RING];
748c2ecf20Sopenharmony_ci	int tx_fill;
758c2ecf20Sopenharmony_ci	int tx_empty;
768c2ecf20Sopenharmony_ci	unsigned char tx_fullup;
778c2ecf20Sopenharmony_ci	struct timer_list tx_timeout;
788c2ecf20Sopenharmony_ci	int timeout_active;
798c2ecf20Sopenharmony_ci	int sleeping;
808c2ecf20Sopenharmony_ci	int opened;
818c2ecf20Sopenharmony_ci	unsigned short hash_use_count[64];
828c2ecf20Sopenharmony_ci	unsigned short hash_table_mask[4];
838c2ecf20Sopenharmony_ci	spinlock_t lock;
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#if 0 /* Move that to ethtool */
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_citypedef struct bmac_reg_entry {
898c2ecf20Sopenharmony_ci	char *name;
908c2ecf20Sopenharmony_ci	unsigned short reg_offset;
918c2ecf20Sopenharmony_ci} bmac_reg_entry_t;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define N_REG_ENTRIES 31
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = {
968c2ecf20Sopenharmony_ci	{"MEMADD", MEMADD},
978c2ecf20Sopenharmony_ci	{"MEMDATAHI", MEMDATAHI},
988c2ecf20Sopenharmony_ci	{"MEMDATALO", MEMDATALO},
998c2ecf20Sopenharmony_ci	{"TXPNTR", TXPNTR},
1008c2ecf20Sopenharmony_ci	{"RXPNTR", RXPNTR},
1018c2ecf20Sopenharmony_ci	{"IPG1", IPG1},
1028c2ecf20Sopenharmony_ci	{"IPG2", IPG2},
1038c2ecf20Sopenharmony_ci	{"ALIMIT", ALIMIT},
1048c2ecf20Sopenharmony_ci	{"SLOT", SLOT},
1058c2ecf20Sopenharmony_ci	{"PALEN", PALEN},
1068c2ecf20Sopenharmony_ci	{"PAPAT", PAPAT},
1078c2ecf20Sopenharmony_ci	{"TXSFD", TXSFD},
1088c2ecf20Sopenharmony_ci	{"JAM", JAM},
1098c2ecf20Sopenharmony_ci	{"TXCFG", TXCFG},
1108c2ecf20Sopenharmony_ci	{"TXMAX", TXMAX},
1118c2ecf20Sopenharmony_ci	{"TXMIN", TXMIN},
1128c2ecf20Sopenharmony_ci	{"PAREG", PAREG},
1138c2ecf20Sopenharmony_ci	{"DCNT", DCNT},
1148c2ecf20Sopenharmony_ci	{"NCCNT", NCCNT},
1158c2ecf20Sopenharmony_ci	{"NTCNT", NTCNT},
1168c2ecf20Sopenharmony_ci	{"EXCNT", EXCNT},
1178c2ecf20Sopenharmony_ci	{"LTCNT", LTCNT},
1188c2ecf20Sopenharmony_ci	{"TXSM", TXSM},
1198c2ecf20Sopenharmony_ci	{"RXCFG", RXCFG},
1208c2ecf20Sopenharmony_ci	{"RXMAX", RXMAX},
1218c2ecf20Sopenharmony_ci	{"RXMIN", RXMIN},
1228c2ecf20Sopenharmony_ci	{"FRCNT", FRCNT},
1238c2ecf20Sopenharmony_ci	{"AECNT", AECNT},
1248c2ecf20Sopenharmony_ci	{"FECNT", FECNT},
1258c2ecf20Sopenharmony_ci	{"RXSM", RXSM},
1268c2ecf20Sopenharmony_ci	{"RXCV", RXCV}
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci#endif
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic unsigned char *bmac_emergency_rxbuf;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/*
1348c2ecf20Sopenharmony_ci * Number of bytes of private data per BMAC: allow enough for
1358c2ecf20Sopenharmony_ci * the rx and tx dma commands plus a branch dma command each,
1368c2ecf20Sopenharmony_ci * and another 16 bytes to allow us to align the dma command
1378c2ecf20Sopenharmony_ci * buffers on a 16 byte boundary.
1388c2ecf20Sopenharmony_ci */
1398c2ecf20Sopenharmony_ci#define PRIV_BYTES	(sizeof(struct bmac_data) \
1408c2ecf20Sopenharmony_ci	+ (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
1418c2ecf20Sopenharmony_ci	+ sizeof(struct sk_buff_head))
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int bmac_open(struct net_device *dev);
1448c2ecf20Sopenharmony_cistatic int bmac_close(struct net_device *dev);
1458c2ecf20Sopenharmony_cistatic int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
1468c2ecf20Sopenharmony_cistatic void bmac_set_multicast(struct net_device *dev);
1478c2ecf20Sopenharmony_cistatic void bmac_reset_and_enable(struct net_device *dev);
1488c2ecf20Sopenharmony_cistatic void bmac_start_chip(struct net_device *dev);
1498c2ecf20Sopenharmony_cistatic void bmac_init_chip(struct net_device *dev);
1508c2ecf20Sopenharmony_cistatic void bmac_init_registers(struct net_device *dev);
1518c2ecf20Sopenharmony_cistatic void bmac_enable_and_reset_chip(struct net_device *dev);
1528c2ecf20Sopenharmony_cistatic int bmac_set_address(struct net_device *dev, void *addr);
1538c2ecf20Sopenharmony_cistatic irqreturn_t bmac_misc_intr(int irq, void *dev_id);
1548c2ecf20Sopenharmony_cistatic irqreturn_t bmac_txdma_intr(int irq, void *dev_id);
1558c2ecf20Sopenharmony_cistatic irqreturn_t bmac_rxdma_intr(int irq, void *dev_id);
1568c2ecf20Sopenharmony_cistatic void bmac_set_timeout(struct net_device *dev);
1578c2ecf20Sopenharmony_cistatic void bmac_tx_timeout(struct timer_list *t);
1588c2ecf20Sopenharmony_cistatic netdev_tx_t bmac_output(struct sk_buff *skb, struct net_device *dev);
1598c2ecf20Sopenharmony_cistatic void bmac_start(struct net_device *dev);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci#define	DBDMA_SET(x)	( ((x) | (x) << 16) )
1628c2ecf20Sopenharmony_ci#define	DBDMA_CLEAR(x)	( (x) << 16)
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic inline void
1658c2ecf20Sopenharmony_cidbdma_st32(volatile __u32 __iomem *a, unsigned long x)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	__asm__ volatile( "stwbrx %0,0,%1" : : "r" (x), "r" (a) : "memory");
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic inline unsigned long
1718c2ecf20Sopenharmony_cidbdma_ld32(volatile __u32 __iomem *a)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	__u32 swap;
1748c2ecf20Sopenharmony_ci	__asm__ volatile ("lwbrx %0,0,%1" :  "=r" (swap) : "r" (a));
1758c2ecf20Sopenharmony_ci	return swap;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic void
1798c2ecf20Sopenharmony_cidbdma_continue(volatile struct dbdma_regs __iomem *dmap)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	dbdma_st32(&dmap->control,
1828c2ecf20Sopenharmony_ci		   DBDMA_SET(RUN|WAKE) | DBDMA_CLEAR(PAUSE|DEAD));
1838c2ecf20Sopenharmony_ci	eieio();
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic void
1878c2ecf20Sopenharmony_cidbdma_reset(volatile struct dbdma_regs __iomem *dmap)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	dbdma_st32(&dmap->control,
1908c2ecf20Sopenharmony_ci		   DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN));
1918c2ecf20Sopenharmony_ci	eieio();
1928c2ecf20Sopenharmony_ci	while (dbdma_ld32(&dmap->status) & RUN)
1938c2ecf20Sopenharmony_ci		eieio();
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic void
1978c2ecf20Sopenharmony_cidbdma_setcmd(volatile struct dbdma_cmd *cp,
1988c2ecf20Sopenharmony_ci	     unsigned short cmd, unsigned count, unsigned long addr,
1998c2ecf20Sopenharmony_ci	     unsigned long cmd_dep)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	out_le16(&cp->command, cmd);
2028c2ecf20Sopenharmony_ci	out_le16(&cp->req_count, count);
2038c2ecf20Sopenharmony_ci	out_le32(&cp->phy_addr, addr);
2048c2ecf20Sopenharmony_ci	out_le32(&cp->cmd_dep, cmd_dep);
2058c2ecf20Sopenharmony_ci	out_le16(&cp->xfer_status, 0);
2068c2ecf20Sopenharmony_ci	out_le16(&cp->res_count, 0);
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic inline
2108c2ecf20Sopenharmony_civoid bmwrite(struct net_device *dev, unsigned long reg_offset, unsigned data )
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	out_le16((void __iomem *)dev->base_addr + reg_offset, data);
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic inline
2178c2ecf20Sopenharmony_ciunsigned short bmread(struct net_device *dev, unsigned long reg_offset )
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	return in_le16((void __iomem *)dev->base_addr + reg_offset);
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic void
2238c2ecf20Sopenharmony_cibmac_enable_and_reset_chip(struct net_device *dev)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
2268c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
2278c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	if (rd)
2308c2ecf20Sopenharmony_ci		dbdma_reset(rd);
2318c2ecf20Sopenharmony_ci	if (td)
2328c2ecf20Sopenharmony_ci		dbdma_reset(td);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 1);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci#define MIFDELAY	udelay(10)
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic unsigned int
2408c2ecf20Sopenharmony_cibmac_mif_readbits(struct net_device *dev, int nb)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	unsigned int val = 0;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	while (--nb >= 0) {
2458c2ecf20Sopenharmony_ci		bmwrite(dev, MIFCSR, 0);
2468c2ecf20Sopenharmony_ci		MIFDELAY;
2478c2ecf20Sopenharmony_ci		if (bmread(dev, MIFCSR) & 8)
2488c2ecf20Sopenharmony_ci			val |= 1 << nb;
2498c2ecf20Sopenharmony_ci		bmwrite(dev, MIFCSR, 1);
2508c2ecf20Sopenharmony_ci		MIFDELAY;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci	bmwrite(dev, MIFCSR, 0);
2538c2ecf20Sopenharmony_ci	MIFDELAY;
2548c2ecf20Sopenharmony_ci	bmwrite(dev, MIFCSR, 1);
2558c2ecf20Sopenharmony_ci	MIFDELAY;
2568c2ecf20Sopenharmony_ci	return val;
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic void
2608c2ecf20Sopenharmony_cibmac_mif_writebits(struct net_device *dev, unsigned int val, int nb)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	int b;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	while (--nb >= 0) {
2658c2ecf20Sopenharmony_ci		b = (val & (1 << nb))? 6: 4;
2668c2ecf20Sopenharmony_ci		bmwrite(dev, MIFCSR, b);
2678c2ecf20Sopenharmony_ci		MIFDELAY;
2688c2ecf20Sopenharmony_ci		bmwrite(dev, MIFCSR, b|1);
2698c2ecf20Sopenharmony_ci		MIFDELAY;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic unsigned int
2748c2ecf20Sopenharmony_cibmac_mif_read(struct net_device *dev, unsigned int addr)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	unsigned int val;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	bmwrite(dev, MIFCSR, 4);
2798c2ecf20Sopenharmony_ci	MIFDELAY;
2808c2ecf20Sopenharmony_ci	bmac_mif_writebits(dev, ~0U, 32);
2818c2ecf20Sopenharmony_ci	bmac_mif_writebits(dev, 6, 4);
2828c2ecf20Sopenharmony_ci	bmac_mif_writebits(dev, addr, 10);
2838c2ecf20Sopenharmony_ci	bmwrite(dev, MIFCSR, 2);
2848c2ecf20Sopenharmony_ci	MIFDELAY;
2858c2ecf20Sopenharmony_ci	bmwrite(dev, MIFCSR, 1);
2868c2ecf20Sopenharmony_ci	MIFDELAY;
2878c2ecf20Sopenharmony_ci	val = bmac_mif_readbits(dev, 17);
2888c2ecf20Sopenharmony_ci	bmwrite(dev, MIFCSR, 4);
2898c2ecf20Sopenharmony_ci	MIFDELAY;
2908c2ecf20Sopenharmony_ci	return val;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic void
2948c2ecf20Sopenharmony_cibmac_mif_write(struct net_device *dev, unsigned int addr, unsigned int val)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	bmwrite(dev, MIFCSR, 4);
2978c2ecf20Sopenharmony_ci	MIFDELAY;
2988c2ecf20Sopenharmony_ci	bmac_mif_writebits(dev, ~0U, 32);
2998c2ecf20Sopenharmony_ci	bmac_mif_writebits(dev, 5, 4);
3008c2ecf20Sopenharmony_ci	bmac_mif_writebits(dev, addr, 10);
3018c2ecf20Sopenharmony_ci	bmac_mif_writebits(dev, 2, 2);
3028c2ecf20Sopenharmony_ci	bmac_mif_writebits(dev, val, 16);
3038c2ecf20Sopenharmony_ci	bmac_mif_writebits(dev, 3, 2);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic void
3078c2ecf20Sopenharmony_cibmac_init_registers(struct net_device *dev)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
3108c2ecf20Sopenharmony_ci	volatile unsigned short regValue;
3118c2ecf20Sopenharmony_ci	unsigned short *pWord16;
3128c2ecf20Sopenharmony_ci	int i;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* XXDEBUG(("bmac: enter init_registers\n")); */
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	bmwrite(dev, RXRST, RxResetValue);
3178c2ecf20Sopenharmony_ci	bmwrite(dev, TXRST, TxResetBit);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	i = 100;
3208c2ecf20Sopenharmony_ci	do {
3218c2ecf20Sopenharmony_ci		--i;
3228c2ecf20Sopenharmony_ci		udelay(10000);
3238c2ecf20Sopenharmony_ci		regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
3248c2ecf20Sopenharmony_ci	} while ((regValue & TxResetBit) && i > 0);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (!bp->is_bmac_plus) {
3278c2ecf20Sopenharmony_ci		regValue = bmread(dev, XCVRIF);
3288c2ecf20Sopenharmony_ci		regValue |= ClkBit | SerialMode | COLActiveLow;
3298c2ecf20Sopenharmony_ci		bmwrite(dev, XCVRIF, regValue);
3308c2ecf20Sopenharmony_ci		udelay(10000);
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	bmwrite(dev, RSEED, (unsigned short)0x1968);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	regValue = bmread(dev, XIFC);
3368c2ecf20Sopenharmony_ci	regValue |= TxOutputEnable;
3378c2ecf20Sopenharmony_ci	bmwrite(dev, XIFC, regValue);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	bmread(dev, PAREG);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	/* set collision counters to 0 */
3428c2ecf20Sopenharmony_ci	bmwrite(dev, NCCNT, 0);
3438c2ecf20Sopenharmony_ci	bmwrite(dev, NTCNT, 0);
3448c2ecf20Sopenharmony_ci	bmwrite(dev, EXCNT, 0);
3458c2ecf20Sopenharmony_ci	bmwrite(dev, LTCNT, 0);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* set rx counters to 0 */
3488c2ecf20Sopenharmony_ci	bmwrite(dev, FRCNT, 0);
3498c2ecf20Sopenharmony_ci	bmwrite(dev, LECNT, 0);
3508c2ecf20Sopenharmony_ci	bmwrite(dev, AECNT, 0);
3518c2ecf20Sopenharmony_ci	bmwrite(dev, FECNT, 0);
3528c2ecf20Sopenharmony_ci	bmwrite(dev, RXCV, 0);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/* set tx fifo information */
3558c2ecf20Sopenharmony_ci	bmwrite(dev, TXTH, 4);	/* 4 octets before tx starts */
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	bmwrite(dev, TXFIFOCSR, 0);	/* first disable txFIFO */
3588c2ecf20Sopenharmony_ci	bmwrite(dev, TXFIFOCSR, TxFIFOEnable );
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/* set rx fifo information */
3618c2ecf20Sopenharmony_ci	bmwrite(dev, RXFIFOCSR, 0);	/* first disable rxFIFO */
3628c2ecf20Sopenharmony_ci	bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	//bmwrite(dev, TXCFG, TxMACEnable);	       	/* TxNeverGiveUp maybe later */
3658c2ecf20Sopenharmony_ci	bmread(dev, STATUS);		/* read it just to clear it */
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	/* zero out the chip Hash Filter registers */
3688c2ecf20Sopenharmony_ci	for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
3698c2ecf20Sopenharmony_ci	bmwrite(dev, BHASH3, bp->hash_table_mask[0]); 	/* bits 15 - 0 */
3708c2ecf20Sopenharmony_ci	bmwrite(dev, BHASH2, bp->hash_table_mask[1]); 	/* bits 31 - 16 */
3718c2ecf20Sopenharmony_ci	bmwrite(dev, BHASH1, bp->hash_table_mask[2]); 	/* bits 47 - 32 */
3728c2ecf20Sopenharmony_ci	bmwrite(dev, BHASH0, bp->hash_table_mask[3]); 	/* bits 63 - 48 */
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	pWord16 = (unsigned short *)dev->dev_addr;
3758c2ecf20Sopenharmony_ci	bmwrite(dev, MADD0, *pWord16++);
3768c2ecf20Sopenharmony_ci	bmwrite(dev, MADD1, *pWord16++);
3778c2ecf20Sopenharmony_ci	bmwrite(dev, MADD2, *pWord16);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	bmwrite(dev, INTDISABLE, EnableNormal);
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci#if 0
3858c2ecf20Sopenharmony_cistatic void
3868c2ecf20Sopenharmony_cibmac_disable_interrupts(struct net_device *dev)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	bmwrite(dev, INTDISABLE, DisableAll);
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic void
3928c2ecf20Sopenharmony_cibmac_enable_interrupts(struct net_device *dev)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	bmwrite(dev, INTDISABLE, EnableNormal);
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci#endif
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic void
4008c2ecf20Sopenharmony_cibmac_start_chip(struct net_device *dev)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
4038c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
4048c2ecf20Sopenharmony_ci	unsigned short	oldConfig;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	/* enable rx dma channel */
4078c2ecf20Sopenharmony_ci	dbdma_continue(rd);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	oldConfig = bmread(dev, TXCFG);
4108c2ecf20Sopenharmony_ci	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/* turn on rx plus any other bits already on (promiscuous possibly) */
4138c2ecf20Sopenharmony_ci	oldConfig = bmread(dev, RXCFG);
4148c2ecf20Sopenharmony_ci	bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
4158c2ecf20Sopenharmony_ci	udelay(20000);
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic void
4198c2ecf20Sopenharmony_cibmac_init_phy(struct net_device *dev)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	unsigned int addr;
4228c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "phy registers:");
4258c2ecf20Sopenharmony_ci	for (addr = 0; addr < 32; ++addr) {
4268c2ecf20Sopenharmony_ci		if ((addr & 7) == 0)
4278c2ecf20Sopenharmony_ci			printk(KERN_DEBUG);
4288c2ecf20Sopenharmony_ci		printk(KERN_CONT " %.4x", bmac_mif_read(dev, addr));
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci	printk(KERN_CONT "\n");
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	if (bp->is_bmac_plus) {
4338c2ecf20Sopenharmony_ci		unsigned int capable, ctrl;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci		ctrl = bmac_mif_read(dev, 0);
4368c2ecf20Sopenharmony_ci		capable = ((bmac_mif_read(dev, 1) & 0xf800) >> 6) | 1;
4378c2ecf20Sopenharmony_ci		if (bmac_mif_read(dev, 4) != capable ||
4388c2ecf20Sopenharmony_ci		    (ctrl & 0x1000) == 0) {
4398c2ecf20Sopenharmony_ci			bmac_mif_write(dev, 4, capable);
4408c2ecf20Sopenharmony_ci			bmac_mif_write(dev, 0, 0x1200);
4418c2ecf20Sopenharmony_ci		} else
4428c2ecf20Sopenharmony_ci			bmac_mif_write(dev, 0, 0x1000);
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic void bmac_init_chip(struct net_device *dev)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	bmac_init_phy(dev);
4498c2ecf20Sopenharmony_ci	bmac_init_registers(dev);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
4538c2ecf20Sopenharmony_cistatic int bmac_suspend(struct macio_dev *mdev, pm_message_t state)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct net_device* dev = macio_get_drvdata(mdev);
4568c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
4578c2ecf20Sopenharmony_ci	unsigned long flags;
4588c2ecf20Sopenharmony_ci	unsigned short config;
4598c2ecf20Sopenharmony_ci	int i;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	netif_device_detach(dev);
4628c2ecf20Sopenharmony_ci	/* prolly should wait for dma to finish & turn off the chip */
4638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
4648c2ecf20Sopenharmony_ci	if (bp->timeout_active) {
4658c2ecf20Sopenharmony_ci		del_timer(&bp->tx_timeout);
4668c2ecf20Sopenharmony_ci		bp->timeout_active = 0;
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci	disable_irq(dev->irq);
4698c2ecf20Sopenharmony_ci	disable_irq(bp->tx_dma_intr);
4708c2ecf20Sopenharmony_ci	disable_irq(bp->rx_dma_intr);
4718c2ecf20Sopenharmony_ci	bp->sleeping = 1;
4728c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
4738c2ecf20Sopenharmony_ci	if (bp->opened) {
4748c2ecf20Sopenharmony_ci		volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
4758c2ecf20Sopenharmony_ci		volatile struct dbdma_regs __iomem *td = bp->tx_dma;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci		config = bmread(dev, RXCFG);
4788c2ecf20Sopenharmony_ci		bmwrite(dev, RXCFG, (config & ~RxMACEnable));
4798c2ecf20Sopenharmony_ci		config = bmread(dev, TXCFG);
4808c2ecf20Sopenharmony_ci       		bmwrite(dev, TXCFG, (config & ~TxMACEnable));
4818c2ecf20Sopenharmony_ci		bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
4828c2ecf20Sopenharmony_ci       		/* disable rx and tx dma */
4838c2ecf20Sopenharmony_ci		rd->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
4848c2ecf20Sopenharmony_ci		td->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
4858c2ecf20Sopenharmony_ci       		/* free some skb's */
4868c2ecf20Sopenharmony_ci       		for (i=0; i<N_RX_RING; i++) {
4878c2ecf20Sopenharmony_ci       			if (bp->rx_bufs[i] != NULL) {
4888c2ecf20Sopenharmony_ci       				dev_kfree_skb(bp->rx_bufs[i]);
4898c2ecf20Sopenharmony_ci       				bp->rx_bufs[i] = NULL;
4908c2ecf20Sopenharmony_ci       			}
4918c2ecf20Sopenharmony_ci       		}
4928c2ecf20Sopenharmony_ci       		for (i = 0; i<N_TX_RING; i++) {
4938c2ecf20Sopenharmony_ci			if (bp->tx_bufs[i] != NULL) {
4948c2ecf20Sopenharmony_ci		       		dev_kfree_skb(bp->tx_bufs[i]);
4958c2ecf20Sopenharmony_ci	       			bp->tx_bufs[i] = NULL;
4968c2ecf20Sopenharmony_ci		       	}
4978c2ecf20Sopenharmony_ci		}
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci       	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
5008c2ecf20Sopenharmony_ci	return 0;
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic int bmac_resume(struct macio_dev *mdev)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	struct net_device* dev = macio_get_drvdata(mdev);
5068c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	/* see if this is enough */
5098c2ecf20Sopenharmony_ci	if (bp->opened)
5108c2ecf20Sopenharmony_ci		bmac_reset_and_enable(dev);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	enable_irq(dev->irq);
5138c2ecf20Sopenharmony_ci       	enable_irq(bp->tx_dma_intr);
5148c2ecf20Sopenharmony_ci       	enable_irq(bp->rx_dma_intr);
5158c2ecf20Sopenharmony_ci       	netif_device_attach(dev);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	return 0;
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic int bmac_set_address(struct net_device *dev, void *addr)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
5248c2ecf20Sopenharmony_ci	unsigned char *p = addr;
5258c2ecf20Sopenharmony_ci	unsigned short *pWord16;
5268c2ecf20Sopenharmony_ci	unsigned long flags;
5278c2ecf20Sopenharmony_ci	int i;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	XXDEBUG(("bmac: enter set_address\n"));
5308c2ecf20Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	for (i = 0; i < 6; ++i) {
5338c2ecf20Sopenharmony_ci		dev->dev_addr[i] = p[i];
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci	/* load up the hardware address */
5368c2ecf20Sopenharmony_ci	pWord16  = (unsigned short *)dev->dev_addr;
5378c2ecf20Sopenharmony_ci	bmwrite(dev, MADD0, *pWord16++);
5388c2ecf20Sopenharmony_ci	bmwrite(dev, MADD1, *pWord16++);
5398c2ecf20Sopenharmony_ci	bmwrite(dev, MADD2, *pWord16);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
5428c2ecf20Sopenharmony_ci	XXDEBUG(("bmac: exit set_address\n"));
5438c2ecf20Sopenharmony_ci	return 0;
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic inline void bmac_set_timeout(struct net_device *dev)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
5498c2ecf20Sopenharmony_ci	unsigned long flags;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
5528c2ecf20Sopenharmony_ci	if (bp->timeout_active)
5538c2ecf20Sopenharmony_ci		del_timer(&bp->tx_timeout);
5548c2ecf20Sopenharmony_ci	bp->tx_timeout.expires = jiffies + TX_TIMEOUT;
5558c2ecf20Sopenharmony_ci	add_timer(&bp->tx_timeout);
5568c2ecf20Sopenharmony_ci	bp->timeout_active = 1;
5578c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic void
5618c2ecf20Sopenharmony_cibmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	void *vaddr;
5648c2ecf20Sopenharmony_ci	unsigned long baddr;
5658c2ecf20Sopenharmony_ci	unsigned long len;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	len = skb->len;
5688c2ecf20Sopenharmony_ci	vaddr = skb->data;
5698c2ecf20Sopenharmony_ci	baddr = virt_to_bus(vaddr);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	dbdma_setcmd(cp, (OUTPUT_LAST | INTR_ALWAYS | WAIT_IFCLR), len, baddr, 0);
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic void
5758c2ecf20Sopenharmony_cibmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	unsigned char *addr = skb? skb->data: bmac_emergency_rxbuf;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN,
5808c2ecf20Sopenharmony_ci		     virt_to_bus(addr), 0);
5818c2ecf20Sopenharmony_ci}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_cistatic void
5848c2ecf20Sopenharmony_cibmac_init_tx_ring(struct bmac_data *bp)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	memset((char *)bp->tx_cmds, 0, (N_TX_RING+1) * sizeof(struct dbdma_cmd));
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	bp->tx_empty = 0;
5918c2ecf20Sopenharmony_ci	bp->tx_fill = 0;
5928c2ecf20Sopenharmony_ci	bp->tx_fullup = 0;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	/* put a branch at the end of the tx command list */
5958c2ecf20Sopenharmony_ci	dbdma_setcmd(&bp->tx_cmds[N_TX_RING],
5968c2ecf20Sopenharmony_ci		     (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->tx_cmds));
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	/* reset tx dma */
5998c2ecf20Sopenharmony_ci	dbdma_reset(td);
6008c2ecf20Sopenharmony_ci	out_le32(&td->wait_sel, 0x00200020);
6018c2ecf20Sopenharmony_ci	out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds));
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic int
6058c2ecf20Sopenharmony_cibmac_init_rx_ring(struct net_device *dev)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
6088c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
6098c2ecf20Sopenharmony_ci	int i;
6108c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/* initialize list of sk_buffs for receiving and set up recv dma */
6138c2ecf20Sopenharmony_ci	memset((char *)bp->rx_cmds, 0,
6148c2ecf20Sopenharmony_ci	       (N_RX_RING + 1) * sizeof(struct dbdma_cmd));
6158c2ecf20Sopenharmony_ci	for (i = 0; i < N_RX_RING; i++) {
6168c2ecf20Sopenharmony_ci		if ((skb = bp->rx_bufs[i]) == NULL) {
6178c2ecf20Sopenharmony_ci			bp->rx_bufs[i] = skb = netdev_alloc_skb(dev, RX_BUFLEN + 2);
6188c2ecf20Sopenharmony_ci			if (skb != NULL)
6198c2ecf20Sopenharmony_ci				skb_reserve(skb, 2);
6208c2ecf20Sopenharmony_ci		}
6218c2ecf20Sopenharmony_ci		bmac_construct_rxbuff(skb, &bp->rx_cmds[i]);
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	bp->rx_empty = 0;
6258c2ecf20Sopenharmony_ci	bp->rx_fill = i;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	/* Put a branch back to the beginning of the receive command list */
6288c2ecf20Sopenharmony_ci	dbdma_setcmd(&bp->rx_cmds[N_RX_RING],
6298c2ecf20Sopenharmony_ci		     (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->rx_cmds));
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	/* start rx dma */
6328c2ecf20Sopenharmony_ci	dbdma_reset(rd);
6338c2ecf20Sopenharmony_ci	out_le32(&rd->cmdptr, virt_to_bus(bp->rx_cmds));
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	return 1;
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_cistatic int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
6428c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
6438c2ecf20Sopenharmony_ci	int i;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	/* see if there's a free slot in the tx ring */
6468c2ecf20Sopenharmony_ci	/* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */
6478c2ecf20Sopenharmony_ci	/* 	     bp->tx_empty, bp->tx_fill)); */
6488c2ecf20Sopenharmony_ci	i = bp->tx_fill + 1;
6498c2ecf20Sopenharmony_ci	if (i >= N_TX_RING)
6508c2ecf20Sopenharmony_ci		i = 0;
6518c2ecf20Sopenharmony_ci	if (i == bp->tx_empty) {
6528c2ecf20Sopenharmony_ci		netif_stop_queue(dev);
6538c2ecf20Sopenharmony_ci		bp->tx_fullup = 1;
6548c2ecf20Sopenharmony_ci		XXDEBUG(("bmac_transmit_packet: tx ring full\n"));
6558c2ecf20Sopenharmony_ci		return -1;		/* can't take it at the moment */
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	dbdma_setcmd(&bp->tx_cmds[i], DBDMA_STOP, 0, 0, 0);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill]);
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	bp->tx_bufs[bp->tx_fill] = skb;
6638c2ecf20Sopenharmony_ci	bp->tx_fill = i;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	dev->stats.tx_bytes += skb->len;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	dbdma_continue(td);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	return 0;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic int rxintcount;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cistatic irqreturn_t bmac_rxdma_intr(int irq, void *dev_id)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	struct net_device *dev = (struct net_device *) dev_id;
6778c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
6788c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
6798c2ecf20Sopenharmony_ci	volatile struct dbdma_cmd *cp;
6808c2ecf20Sopenharmony_ci	int i, nb, stat;
6818c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6828c2ecf20Sopenharmony_ci	unsigned int residual;
6838c2ecf20Sopenharmony_ci	int last;
6848c2ecf20Sopenharmony_ci	unsigned long flags;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	if (++rxintcount < 10) {
6898c2ecf20Sopenharmony_ci		XXDEBUG(("bmac_rxdma_intr\n"));
6908c2ecf20Sopenharmony_ci	}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	last = -1;
6938c2ecf20Sopenharmony_ci	i = bp->rx_empty;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	while (1) {
6968c2ecf20Sopenharmony_ci		cp = &bp->rx_cmds[i];
6978c2ecf20Sopenharmony_ci		stat = le16_to_cpu(cp->xfer_status);
6988c2ecf20Sopenharmony_ci		residual = le16_to_cpu(cp->res_count);
6998c2ecf20Sopenharmony_ci		if ((stat & ACTIVE) == 0)
7008c2ecf20Sopenharmony_ci			break;
7018c2ecf20Sopenharmony_ci		nb = RX_BUFLEN - residual - 2;
7028c2ecf20Sopenharmony_ci		if (nb < (ETHERMINPACKET - ETHERCRC)) {
7038c2ecf20Sopenharmony_ci			skb = NULL;
7048c2ecf20Sopenharmony_ci			dev->stats.rx_length_errors++;
7058c2ecf20Sopenharmony_ci			dev->stats.rx_errors++;
7068c2ecf20Sopenharmony_ci		} else {
7078c2ecf20Sopenharmony_ci			skb = bp->rx_bufs[i];
7088c2ecf20Sopenharmony_ci			bp->rx_bufs[i] = NULL;
7098c2ecf20Sopenharmony_ci		}
7108c2ecf20Sopenharmony_ci		if (skb != NULL) {
7118c2ecf20Sopenharmony_ci			nb -= ETHERCRC;
7128c2ecf20Sopenharmony_ci			skb_put(skb, nb);
7138c2ecf20Sopenharmony_ci			skb->protocol = eth_type_trans(skb, dev);
7148c2ecf20Sopenharmony_ci			netif_rx(skb);
7158c2ecf20Sopenharmony_ci			++dev->stats.rx_packets;
7168c2ecf20Sopenharmony_ci			dev->stats.rx_bytes += nb;
7178c2ecf20Sopenharmony_ci		} else {
7188c2ecf20Sopenharmony_ci			++dev->stats.rx_dropped;
7198c2ecf20Sopenharmony_ci		}
7208c2ecf20Sopenharmony_ci		if ((skb = bp->rx_bufs[i]) == NULL) {
7218c2ecf20Sopenharmony_ci			bp->rx_bufs[i] = skb = netdev_alloc_skb(dev, RX_BUFLEN + 2);
7228c2ecf20Sopenharmony_ci			if (skb != NULL)
7238c2ecf20Sopenharmony_ci				skb_reserve(bp->rx_bufs[i], 2);
7248c2ecf20Sopenharmony_ci		}
7258c2ecf20Sopenharmony_ci		bmac_construct_rxbuff(skb, &bp->rx_cmds[i]);
7268c2ecf20Sopenharmony_ci		cp->res_count = cpu_to_le16(0);
7278c2ecf20Sopenharmony_ci		cp->xfer_status = cpu_to_le16(0);
7288c2ecf20Sopenharmony_ci		last = i;
7298c2ecf20Sopenharmony_ci		if (++i >= N_RX_RING) i = 0;
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	if (last != -1) {
7338c2ecf20Sopenharmony_ci		bp->rx_fill = last;
7348c2ecf20Sopenharmony_ci		bp->rx_empty = i;
7358c2ecf20Sopenharmony_ci	}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	dbdma_continue(rd);
7388c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	if (rxintcount < 10) {
7418c2ecf20Sopenharmony_ci		XXDEBUG(("bmac_rxdma_intr done\n"));
7428c2ecf20Sopenharmony_ci	}
7438c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
7448c2ecf20Sopenharmony_ci}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_cistatic int txintcount;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_cistatic irqreturn_t bmac_txdma_intr(int irq, void *dev_id)
7498c2ecf20Sopenharmony_ci{
7508c2ecf20Sopenharmony_ci	struct net_device *dev = (struct net_device *) dev_id;
7518c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
7528c2ecf20Sopenharmony_ci	volatile struct dbdma_cmd *cp;
7538c2ecf20Sopenharmony_ci	int stat;
7548c2ecf20Sopenharmony_ci	unsigned long flags;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (txintcount++ < 10) {
7598c2ecf20Sopenharmony_ci		XXDEBUG(("bmac_txdma_intr\n"));
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/*     del_timer(&bp->tx_timeout); */
7638c2ecf20Sopenharmony_ci	/*     bp->timeout_active = 0; */
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	while (1) {
7668c2ecf20Sopenharmony_ci		cp = &bp->tx_cmds[bp->tx_empty];
7678c2ecf20Sopenharmony_ci		stat = le16_to_cpu(cp->xfer_status);
7688c2ecf20Sopenharmony_ci		if (txintcount < 10) {
7698c2ecf20Sopenharmony_ci			XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat));
7708c2ecf20Sopenharmony_ci		}
7718c2ecf20Sopenharmony_ci		if (!(stat & ACTIVE)) {
7728c2ecf20Sopenharmony_ci			/*
7738c2ecf20Sopenharmony_ci			 * status field might not have been filled by DBDMA
7748c2ecf20Sopenharmony_ci			 */
7758c2ecf20Sopenharmony_ci			if (cp == bus_to_virt(in_le32(&bp->tx_dma->cmdptr)))
7768c2ecf20Sopenharmony_ci				break;
7778c2ecf20Sopenharmony_ci		}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci		if (bp->tx_bufs[bp->tx_empty]) {
7808c2ecf20Sopenharmony_ci			++dev->stats.tx_packets;
7818c2ecf20Sopenharmony_ci			dev_consume_skb_irq(bp->tx_bufs[bp->tx_empty]);
7828c2ecf20Sopenharmony_ci		}
7838c2ecf20Sopenharmony_ci		bp->tx_bufs[bp->tx_empty] = NULL;
7848c2ecf20Sopenharmony_ci		bp->tx_fullup = 0;
7858c2ecf20Sopenharmony_ci		netif_wake_queue(dev);
7868c2ecf20Sopenharmony_ci		if (++bp->tx_empty >= N_TX_RING)
7878c2ecf20Sopenharmony_ci			bp->tx_empty = 0;
7888c2ecf20Sopenharmony_ci		if (bp->tx_empty == bp->tx_fill)
7898c2ecf20Sopenharmony_ci			break;
7908c2ecf20Sopenharmony_ci	}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	if (txintcount < 10) {
7958c2ecf20Sopenharmony_ci		XXDEBUG(("bmac_txdma_intr done->bmac_start\n"));
7968c2ecf20Sopenharmony_ci	}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	bmac_start(dev);
7998c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci#ifndef SUNHME_MULTICAST
8038c2ecf20Sopenharmony_ci/* Real fast bit-reversal algorithm, 6-bit values */
8048c2ecf20Sopenharmony_cistatic int reverse6[64] = {
8058c2ecf20Sopenharmony_ci	0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38,
8068c2ecf20Sopenharmony_ci	0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c,
8078c2ecf20Sopenharmony_ci	0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a,
8088c2ecf20Sopenharmony_ci	0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e,
8098c2ecf20Sopenharmony_ci	0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39,
8108c2ecf20Sopenharmony_ci	0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d,
8118c2ecf20Sopenharmony_ci	0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b,
8128c2ecf20Sopenharmony_ci	0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f
8138c2ecf20Sopenharmony_ci};
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_cistatic unsigned int
8168c2ecf20Sopenharmony_cicrc416(unsigned int curval, unsigned short nxtval)
8178c2ecf20Sopenharmony_ci{
8188c2ecf20Sopenharmony_ci	unsigned int counter, cur = curval, next = nxtval;
8198c2ecf20Sopenharmony_ci	int high_crc_set, low_data_set;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	/* Swap bytes */
8228c2ecf20Sopenharmony_ci	next = ((next & 0x00FF) << 8) | (next >> 8);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	/* Compute bit-by-bit */
8258c2ecf20Sopenharmony_ci	for (counter = 0; counter < 16; ++counter) {
8268c2ecf20Sopenharmony_ci		/* is high CRC bit set? */
8278c2ecf20Sopenharmony_ci		if ((cur & 0x80000000) == 0) high_crc_set = 0;
8288c2ecf20Sopenharmony_ci		else high_crc_set = 1;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci		cur = cur << 1;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci		if ((next & 0x0001) == 0) low_data_set = 0;
8338c2ecf20Sopenharmony_ci		else low_data_set = 1;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci		next = next >> 1;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci		/* do the XOR */
8388c2ecf20Sopenharmony_ci		if (high_crc_set ^ low_data_set) cur = cur ^ CRC32_POLY_BE;
8398c2ecf20Sopenharmony_ci	}
8408c2ecf20Sopenharmony_ci	return cur;
8418c2ecf20Sopenharmony_ci}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_cistatic unsigned int
8448c2ecf20Sopenharmony_cibmac_crc(unsigned short *address)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	unsigned int newcrc;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2]));
8498c2ecf20Sopenharmony_ci	newcrc = crc416(0xffffffff, *address);	/* address bits 47 - 32 */
8508c2ecf20Sopenharmony_ci	newcrc = crc416(newcrc, address[1]);	/* address bits 31 - 16 */
8518c2ecf20Sopenharmony_ci	newcrc = crc416(newcrc, address[2]);	/* address bits 15 - 0  */
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	return(newcrc);
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci/*
8578c2ecf20Sopenharmony_ci * Add requested mcast addr to BMac's hash table filter.
8588c2ecf20Sopenharmony_ci *
8598c2ecf20Sopenharmony_ci */
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_cistatic void
8628c2ecf20Sopenharmony_cibmac_addhash(struct bmac_data *bp, unsigned char *addr)
8638c2ecf20Sopenharmony_ci{
8648c2ecf20Sopenharmony_ci	unsigned int	 crc;
8658c2ecf20Sopenharmony_ci	unsigned short	 mask;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	if (!(*addr)) return;
8688c2ecf20Sopenharmony_ci	crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
8698c2ecf20Sopenharmony_ci	crc = reverse6[crc];	/* Hyperfast bit-reversing algorithm */
8708c2ecf20Sopenharmony_ci	if (bp->hash_use_count[crc]++) return; /* This bit is already set */
8718c2ecf20Sopenharmony_ci	mask = crc % 16;
8728c2ecf20Sopenharmony_ci	mask = (unsigned char)1 << mask;
8738c2ecf20Sopenharmony_ci	bp->hash_use_count[crc/16] |= mask;
8748c2ecf20Sopenharmony_ci}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_cistatic void
8778c2ecf20Sopenharmony_cibmac_removehash(struct bmac_data *bp, unsigned char *addr)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	unsigned int crc;
8808c2ecf20Sopenharmony_ci	unsigned char mask;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/* Now, delete the address from the filter copy, as indicated */
8838c2ecf20Sopenharmony_ci	crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
8848c2ecf20Sopenharmony_ci	crc = reverse6[crc];	/* Hyperfast bit-reversing algorithm */
8858c2ecf20Sopenharmony_ci	if (bp->hash_use_count[crc] == 0) return; /* That bit wasn't in use! */
8868c2ecf20Sopenharmony_ci	if (--bp->hash_use_count[crc]) return; /* That bit is still in use */
8878c2ecf20Sopenharmony_ci	mask = crc % 16;
8888c2ecf20Sopenharmony_ci	mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */
8898c2ecf20Sopenharmony_ci	bp->hash_table_mask[crc/16] &= mask;
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci/*
8938c2ecf20Sopenharmony_ci * Sync the adapter with the software copy of the multicast mask
8948c2ecf20Sopenharmony_ci *  (logical address filter).
8958c2ecf20Sopenharmony_ci */
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_cistatic void
8988c2ecf20Sopenharmony_cibmac_rx_off(struct net_device *dev)
8998c2ecf20Sopenharmony_ci{
9008c2ecf20Sopenharmony_ci	unsigned short rx_cfg;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	rx_cfg = bmread(dev, RXCFG);
9038c2ecf20Sopenharmony_ci	rx_cfg &= ~RxMACEnable;
9048c2ecf20Sopenharmony_ci	bmwrite(dev, RXCFG, rx_cfg);
9058c2ecf20Sopenharmony_ci	do {
9068c2ecf20Sopenharmony_ci		rx_cfg = bmread(dev, RXCFG);
9078c2ecf20Sopenharmony_ci	}  while (rx_cfg & RxMACEnable);
9088c2ecf20Sopenharmony_ci}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ciunsigned short
9118c2ecf20Sopenharmony_cibmac_rx_on(struct net_device *dev, int hash_enable, int promisc_enable)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	unsigned short rx_cfg;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	rx_cfg = bmread(dev, RXCFG);
9168c2ecf20Sopenharmony_ci	rx_cfg |= RxMACEnable;
9178c2ecf20Sopenharmony_ci	if (hash_enable) rx_cfg |= RxHashFilterEnable;
9188c2ecf20Sopenharmony_ci	else rx_cfg &= ~RxHashFilterEnable;
9198c2ecf20Sopenharmony_ci	if (promisc_enable) rx_cfg |= RxPromiscEnable;
9208c2ecf20Sopenharmony_ci	else rx_cfg &= ~RxPromiscEnable;
9218c2ecf20Sopenharmony_ci	bmwrite(dev, RXRST, RxResetValue);
9228c2ecf20Sopenharmony_ci	bmwrite(dev, RXFIFOCSR, 0);	/* first disable rxFIFO */
9238c2ecf20Sopenharmony_ci	bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
9248c2ecf20Sopenharmony_ci	bmwrite(dev, RXCFG, rx_cfg );
9258c2ecf20Sopenharmony_ci	return rx_cfg;
9268c2ecf20Sopenharmony_ci}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_cistatic void
9298c2ecf20Sopenharmony_cibmac_update_hash_table_mask(struct net_device *dev, struct bmac_data *bp)
9308c2ecf20Sopenharmony_ci{
9318c2ecf20Sopenharmony_ci	bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */
9328c2ecf20Sopenharmony_ci	bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */
9338c2ecf20Sopenharmony_ci	bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */
9348c2ecf20Sopenharmony_ci	bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci#if 0
9388c2ecf20Sopenharmony_cistatic void
9398c2ecf20Sopenharmony_cibmac_add_multi(struct net_device *dev,
9408c2ecf20Sopenharmony_ci	       struct bmac_data *bp, unsigned char *addr)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	/* XXDEBUG(("bmac: enter bmac_add_multi\n")); */
9438c2ecf20Sopenharmony_ci	bmac_addhash(bp, addr);
9448c2ecf20Sopenharmony_ci	bmac_rx_off(dev);
9458c2ecf20Sopenharmony_ci	bmac_update_hash_table_mask(dev, bp);
9468c2ecf20Sopenharmony_ci	bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
9478c2ecf20Sopenharmony_ci	/* XXDEBUG(("bmac: exit bmac_add_multi\n")); */
9488c2ecf20Sopenharmony_ci}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_cistatic void
9518c2ecf20Sopenharmony_cibmac_remove_multi(struct net_device *dev,
9528c2ecf20Sopenharmony_ci		  struct bmac_data *bp, unsigned char *addr)
9538c2ecf20Sopenharmony_ci{
9548c2ecf20Sopenharmony_ci	bmac_removehash(bp, addr);
9558c2ecf20Sopenharmony_ci	bmac_rx_off(dev);
9568c2ecf20Sopenharmony_ci	bmac_update_hash_table_mask(dev, bp);
9578c2ecf20Sopenharmony_ci	bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
9588c2ecf20Sopenharmony_ci}
9598c2ecf20Sopenharmony_ci#endif
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci/* Set or clear the multicast filter for this adaptor.
9628c2ecf20Sopenharmony_ci    num_addrs == -1	Promiscuous mode, receive all packets
9638c2ecf20Sopenharmony_ci    num_addrs == 0	Normal mode, clear multicast list
9648c2ecf20Sopenharmony_ci    num_addrs > 0	Multicast mode, receive normal and MC packets, and do
9658c2ecf20Sopenharmony_ci			best-effort filtering.
9668c2ecf20Sopenharmony_ci */
9678c2ecf20Sopenharmony_cistatic void bmac_set_multicast(struct net_device *dev)
9688c2ecf20Sopenharmony_ci{
9698c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha;
9708c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
9718c2ecf20Sopenharmony_ci	int num_addrs = netdev_mc_count(dev);
9728c2ecf20Sopenharmony_ci	unsigned short rx_cfg;
9738c2ecf20Sopenharmony_ci	int i;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	if (bp->sleeping)
9768c2ecf20Sopenharmony_ci		return;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs));
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) {
9818c2ecf20Sopenharmony_ci		for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff;
9828c2ecf20Sopenharmony_ci		bmac_update_hash_table_mask(dev, bp);
9838c2ecf20Sopenharmony_ci		rx_cfg = bmac_rx_on(dev, 1, 0);
9848c2ecf20Sopenharmony_ci		XXDEBUG(("bmac: all multi, rx_cfg=%#08x\n"));
9858c2ecf20Sopenharmony_ci	} else if ((dev->flags & IFF_PROMISC) || (num_addrs < 0)) {
9868c2ecf20Sopenharmony_ci		rx_cfg = bmread(dev, RXCFG);
9878c2ecf20Sopenharmony_ci		rx_cfg |= RxPromiscEnable;
9888c2ecf20Sopenharmony_ci		bmwrite(dev, RXCFG, rx_cfg);
9898c2ecf20Sopenharmony_ci		rx_cfg = bmac_rx_on(dev, 0, 1);
9908c2ecf20Sopenharmony_ci		XXDEBUG(("bmac: promisc mode enabled, rx_cfg=%#08x\n", rx_cfg));
9918c2ecf20Sopenharmony_ci	} else {
9928c2ecf20Sopenharmony_ci		for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
9938c2ecf20Sopenharmony_ci		for (i=0; i<64; i++) bp->hash_use_count[i] = 0;
9948c2ecf20Sopenharmony_ci		if (num_addrs == 0) {
9958c2ecf20Sopenharmony_ci			rx_cfg = bmac_rx_on(dev, 0, 0);
9968c2ecf20Sopenharmony_ci			XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg));
9978c2ecf20Sopenharmony_ci		} else {
9988c2ecf20Sopenharmony_ci			netdev_for_each_mc_addr(ha, dev)
9998c2ecf20Sopenharmony_ci				bmac_addhash(bp, ha->addr);
10008c2ecf20Sopenharmony_ci			bmac_update_hash_table_mask(dev, bp);
10018c2ecf20Sopenharmony_ci			rx_cfg = bmac_rx_on(dev, 1, 0);
10028c2ecf20Sopenharmony_ci			XXDEBUG(("bmac: multi enabled, rx_cfg=%#08x\n", rx_cfg));
10038c2ecf20Sopenharmony_ci		}
10048c2ecf20Sopenharmony_ci	}
10058c2ecf20Sopenharmony_ci	/* XXDEBUG(("bmac: exit bmac_set_multicast\n")); */
10068c2ecf20Sopenharmony_ci}
10078c2ecf20Sopenharmony_ci#else /* ifdef SUNHME_MULTICAST */
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci/* The version of set_multicast below was lifted from sunhme.c */
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_cistatic void bmac_set_multicast(struct net_device *dev)
10128c2ecf20Sopenharmony_ci{
10138c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha;
10148c2ecf20Sopenharmony_ci	unsigned short rx_cfg;
10158c2ecf20Sopenharmony_ci	u32 crc;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) {
10188c2ecf20Sopenharmony_ci		bmwrite(dev, BHASH0, 0xffff);
10198c2ecf20Sopenharmony_ci		bmwrite(dev, BHASH1, 0xffff);
10208c2ecf20Sopenharmony_ci		bmwrite(dev, BHASH2, 0xffff);
10218c2ecf20Sopenharmony_ci		bmwrite(dev, BHASH3, 0xffff);
10228c2ecf20Sopenharmony_ci	} else if(dev->flags & IFF_PROMISC) {
10238c2ecf20Sopenharmony_ci		rx_cfg = bmread(dev, RXCFG);
10248c2ecf20Sopenharmony_ci		rx_cfg |= RxPromiscEnable;
10258c2ecf20Sopenharmony_ci		bmwrite(dev, RXCFG, rx_cfg);
10268c2ecf20Sopenharmony_ci	} else {
10278c2ecf20Sopenharmony_ci		u16 hash_table[4] = { 0 };
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci		rx_cfg = bmread(dev, RXCFG);
10308c2ecf20Sopenharmony_ci		rx_cfg &= ~RxPromiscEnable;
10318c2ecf20Sopenharmony_ci		bmwrite(dev, RXCFG, rx_cfg);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
10348c2ecf20Sopenharmony_ci			crc = ether_crc_le(6, ha->addr);
10358c2ecf20Sopenharmony_ci			crc >>= 26;
10368c2ecf20Sopenharmony_ci			hash_table[crc >> 4] |= 1 << (crc & 0xf);
10378c2ecf20Sopenharmony_ci		}
10388c2ecf20Sopenharmony_ci		bmwrite(dev, BHASH0, hash_table[0]);
10398c2ecf20Sopenharmony_ci		bmwrite(dev, BHASH1, hash_table[1]);
10408c2ecf20Sopenharmony_ci		bmwrite(dev, BHASH2, hash_table[2]);
10418c2ecf20Sopenharmony_ci		bmwrite(dev, BHASH3, hash_table[3]);
10428c2ecf20Sopenharmony_ci	}
10438c2ecf20Sopenharmony_ci}
10448c2ecf20Sopenharmony_ci#endif /* SUNHME_MULTICAST */
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_cistatic int miscintcount;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_cistatic irqreturn_t bmac_misc_intr(int irq, void *dev_id)
10498c2ecf20Sopenharmony_ci{
10508c2ecf20Sopenharmony_ci	struct net_device *dev = (struct net_device *) dev_id;
10518c2ecf20Sopenharmony_ci	unsigned int status = bmread(dev, STATUS);
10528c2ecf20Sopenharmony_ci	if (miscintcount++ < 10) {
10538c2ecf20Sopenharmony_ci		XXDEBUG(("bmac_misc_intr\n"));
10548c2ecf20Sopenharmony_ci	}
10558c2ecf20Sopenharmony_ci	/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
10568c2ecf20Sopenharmony_ci	/*     bmac_txdma_intr_inner(irq, dev_id); */
10578c2ecf20Sopenharmony_ci	/*   if (status & FrameReceived) dev->stats.rx_dropped++; */
10588c2ecf20Sopenharmony_ci	if (status & RxErrorMask) dev->stats.rx_errors++;
10598c2ecf20Sopenharmony_ci	if (status & RxCRCCntExp) dev->stats.rx_crc_errors++;
10608c2ecf20Sopenharmony_ci	if (status & RxLenCntExp) dev->stats.rx_length_errors++;
10618c2ecf20Sopenharmony_ci	if (status & RxOverFlow) dev->stats.rx_over_errors++;
10628c2ecf20Sopenharmony_ci	if (status & RxAlignCntExp) dev->stats.rx_frame_errors++;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	/*   if (status & FrameSent) dev->stats.tx_dropped++; */
10658c2ecf20Sopenharmony_ci	if (status & TxErrorMask) dev->stats.tx_errors++;
10668c2ecf20Sopenharmony_ci	if (status & TxUnderrun) dev->stats.tx_fifo_errors++;
10678c2ecf20Sopenharmony_ci	if (status & TxNormalCollExp) dev->stats.collisions++;
10688c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
10698c2ecf20Sopenharmony_ci}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci/*
10728c2ecf20Sopenharmony_ci * Procedure for reading EEPROM
10738c2ecf20Sopenharmony_ci */
10748c2ecf20Sopenharmony_ci#define SROMAddressLength	5
10758c2ecf20Sopenharmony_ci#define DataInOn		0x0008
10768c2ecf20Sopenharmony_ci#define DataInOff		0x0000
10778c2ecf20Sopenharmony_ci#define Clk			0x0002
10788c2ecf20Sopenharmony_ci#define ChipSelect		0x0001
10798c2ecf20Sopenharmony_ci#define SDIShiftCount		3
10808c2ecf20Sopenharmony_ci#define SD0ShiftCount		2
10818c2ecf20Sopenharmony_ci#define	DelayValue		1000	/* number of microseconds */
10828c2ecf20Sopenharmony_ci#define SROMStartOffset		10	/* this is in words */
10838c2ecf20Sopenharmony_ci#define SROMReadCount		3	/* number of words to read from SROM */
10848c2ecf20Sopenharmony_ci#define SROMAddressBits		6
10858c2ecf20Sopenharmony_ci#define EnetAddressOffset	20
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_cistatic unsigned char
10888c2ecf20Sopenharmony_cibmac_clock_out_bit(struct net_device *dev)
10898c2ecf20Sopenharmony_ci{
10908c2ecf20Sopenharmony_ci	unsigned short         data;
10918c2ecf20Sopenharmony_ci	unsigned short         val;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	bmwrite(dev, SROMCSR, ChipSelect | Clk);
10948c2ecf20Sopenharmony_ci	udelay(DelayValue);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	data = bmread(dev, SROMCSR);
10978c2ecf20Sopenharmony_ci	udelay(DelayValue);
10988c2ecf20Sopenharmony_ci	val = (data >> SD0ShiftCount) & 1;
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	bmwrite(dev, SROMCSR, ChipSelect);
11018c2ecf20Sopenharmony_ci	udelay(DelayValue);
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	return val;
11048c2ecf20Sopenharmony_ci}
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_cistatic void
11078c2ecf20Sopenharmony_cibmac_clock_in_bit(struct net_device *dev, unsigned int val)
11088c2ecf20Sopenharmony_ci{
11098c2ecf20Sopenharmony_ci	unsigned short data;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	if (val != 0 && val != 1) return;
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	data = (val << SDIShiftCount);
11148c2ecf20Sopenharmony_ci	bmwrite(dev, SROMCSR, data | ChipSelect  );
11158c2ecf20Sopenharmony_ci	udelay(DelayValue);
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	bmwrite(dev, SROMCSR, data | ChipSelect | Clk );
11188c2ecf20Sopenharmony_ci	udelay(DelayValue);
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	bmwrite(dev, SROMCSR, data | ChipSelect);
11218c2ecf20Sopenharmony_ci	udelay(DelayValue);
11228c2ecf20Sopenharmony_ci}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_cistatic void
11258c2ecf20Sopenharmony_cireset_and_select_srom(struct net_device *dev)
11268c2ecf20Sopenharmony_ci{
11278c2ecf20Sopenharmony_ci	/* first reset */
11288c2ecf20Sopenharmony_ci	bmwrite(dev, SROMCSR, 0);
11298c2ecf20Sopenharmony_ci	udelay(DelayValue);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	/* send it the read command (110) */
11328c2ecf20Sopenharmony_ci	bmac_clock_in_bit(dev, 1);
11338c2ecf20Sopenharmony_ci	bmac_clock_in_bit(dev, 1);
11348c2ecf20Sopenharmony_ci	bmac_clock_in_bit(dev, 0);
11358c2ecf20Sopenharmony_ci}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_cistatic unsigned short
11388c2ecf20Sopenharmony_ciread_srom(struct net_device *dev, unsigned int addr, unsigned int addr_len)
11398c2ecf20Sopenharmony_ci{
11408c2ecf20Sopenharmony_ci	unsigned short data, val;
11418c2ecf20Sopenharmony_ci	int i;
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	/* send out the address we want to read from */
11448c2ecf20Sopenharmony_ci	for (i = 0; i < addr_len; i++)	{
11458c2ecf20Sopenharmony_ci		val = addr >> (addr_len-i-1);
11468c2ecf20Sopenharmony_ci		bmac_clock_in_bit(dev, val & 1);
11478c2ecf20Sopenharmony_ci	}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	/* Now read in the 16-bit data */
11508c2ecf20Sopenharmony_ci	data = 0;
11518c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)	{
11528c2ecf20Sopenharmony_ci		val = bmac_clock_out_bit(dev);
11538c2ecf20Sopenharmony_ci		data <<= 1;
11548c2ecf20Sopenharmony_ci		data |= val;
11558c2ecf20Sopenharmony_ci	}
11568c2ecf20Sopenharmony_ci	bmwrite(dev, SROMCSR, 0);
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	return data;
11598c2ecf20Sopenharmony_ci}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci/*
11628c2ecf20Sopenharmony_ci * It looks like Cogent and SMC use different methods for calculating
11638c2ecf20Sopenharmony_ci * checksums. What a pain..
11648c2ecf20Sopenharmony_ci */
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_cistatic int
11678c2ecf20Sopenharmony_cibmac_verify_checksum(struct net_device *dev)
11688c2ecf20Sopenharmony_ci{
11698c2ecf20Sopenharmony_ci	unsigned short data, storedCS;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	reset_and_select_srom(dev);
11728c2ecf20Sopenharmony_ci	data = read_srom(dev, 3, SROMAddressBits);
11738c2ecf20Sopenharmony_ci	storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00);
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	return 0;
11768c2ecf20Sopenharmony_ci}
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_cistatic void
11808c2ecf20Sopenharmony_cibmac_get_station_address(struct net_device *dev, unsigned char *ea)
11818c2ecf20Sopenharmony_ci{
11828c2ecf20Sopenharmony_ci	int i;
11838c2ecf20Sopenharmony_ci	unsigned short data;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++)
11868c2ecf20Sopenharmony_ci		{
11878c2ecf20Sopenharmony_ci			reset_and_select_srom(dev);
11888c2ecf20Sopenharmony_ci			data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
11898c2ecf20Sopenharmony_ci			ea[2*i]   = bitrev8(data & 0x0ff);
11908c2ecf20Sopenharmony_ci			ea[2*i+1] = bitrev8((data >> 8) & 0x0ff);
11918c2ecf20Sopenharmony_ci		}
11928c2ecf20Sopenharmony_ci}
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_cistatic void bmac_reset_and_enable(struct net_device *dev)
11958c2ecf20Sopenharmony_ci{
11968c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
11978c2ecf20Sopenharmony_ci	unsigned long flags;
11988c2ecf20Sopenharmony_ci	struct sk_buff *skb;
11998c2ecf20Sopenharmony_ci	unsigned char *data;
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
12028c2ecf20Sopenharmony_ci	bmac_enable_and_reset_chip(dev);
12038c2ecf20Sopenharmony_ci	bmac_init_tx_ring(bp);
12048c2ecf20Sopenharmony_ci	bmac_init_rx_ring(dev);
12058c2ecf20Sopenharmony_ci	bmac_init_chip(dev);
12068c2ecf20Sopenharmony_ci	bmac_start_chip(dev);
12078c2ecf20Sopenharmony_ci	bmwrite(dev, INTDISABLE, EnableNormal);
12088c2ecf20Sopenharmony_ci	bp->sleeping = 0;
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	/*
12118c2ecf20Sopenharmony_ci	 * It seems that the bmac can't receive until it's transmitted
12128c2ecf20Sopenharmony_ci	 * a packet.  So we give it a dummy packet to transmit.
12138c2ecf20Sopenharmony_ci	 */
12148c2ecf20Sopenharmony_ci	skb = netdev_alloc_skb(dev, ETHERMINPACKET);
12158c2ecf20Sopenharmony_ci	if (skb != NULL) {
12168c2ecf20Sopenharmony_ci		data = skb_put_zero(skb, ETHERMINPACKET);
12178c2ecf20Sopenharmony_ci		memcpy(data, dev->dev_addr, ETH_ALEN);
12188c2ecf20Sopenharmony_ci		memcpy(data + ETH_ALEN, dev->dev_addr, ETH_ALEN);
12198c2ecf20Sopenharmony_ci		bmac_transmit_packet(skb, dev);
12208c2ecf20Sopenharmony_ci	}
12218c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
12228c2ecf20Sopenharmony_ci}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_cistatic const struct ethtool_ops bmac_ethtool_ops = {
12258c2ecf20Sopenharmony_ci	.get_link		= ethtool_op_get_link,
12268c2ecf20Sopenharmony_ci};
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_cistatic const struct net_device_ops bmac_netdev_ops = {
12298c2ecf20Sopenharmony_ci	.ndo_open		= bmac_open,
12308c2ecf20Sopenharmony_ci	.ndo_stop		= bmac_close,
12318c2ecf20Sopenharmony_ci	.ndo_start_xmit		= bmac_output,
12328c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= bmac_set_multicast,
12338c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= bmac_set_address,
12348c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
12358c2ecf20Sopenharmony_ci};
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_cistatic int bmac_probe(struct macio_dev *mdev, const struct of_device_id *match)
12388c2ecf20Sopenharmony_ci{
12398c2ecf20Sopenharmony_ci	int j, rev, ret;
12408c2ecf20Sopenharmony_ci	struct bmac_data *bp;
12418c2ecf20Sopenharmony_ci	const unsigned char *prop_addr;
12428c2ecf20Sopenharmony_ci	unsigned char addr[6];
12438c2ecf20Sopenharmony_ci	struct net_device *dev;
12448c2ecf20Sopenharmony_ci	int is_bmac_plus = ((int)match->data) != 0;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
12478c2ecf20Sopenharmony_ci		printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
12488c2ecf20Sopenharmony_ci		return -ENODEV;
12498c2ecf20Sopenharmony_ci	}
12508c2ecf20Sopenharmony_ci	prop_addr = of_get_property(macio_get_of_node(mdev),
12518c2ecf20Sopenharmony_ci			"mac-address", NULL);
12528c2ecf20Sopenharmony_ci	if (prop_addr == NULL) {
12538c2ecf20Sopenharmony_ci		prop_addr = of_get_property(macio_get_of_node(mdev),
12548c2ecf20Sopenharmony_ci				"local-mac-address", NULL);
12558c2ecf20Sopenharmony_ci		if (prop_addr == NULL) {
12568c2ecf20Sopenharmony_ci			printk(KERN_ERR "BMAC: Can't get mac-address\n");
12578c2ecf20Sopenharmony_ci			return -ENODEV;
12588c2ecf20Sopenharmony_ci		}
12598c2ecf20Sopenharmony_ci	}
12608c2ecf20Sopenharmony_ci	memcpy(addr, prop_addr, sizeof(addr));
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	dev = alloc_etherdev(PRIV_BYTES);
12638c2ecf20Sopenharmony_ci	if (!dev)
12648c2ecf20Sopenharmony_ci		return -ENOMEM;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	bp = netdev_priv(dev);
12678c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
12688c2ecf20Sopenharmony_ci	macio_set_drvdata(mdev, dev);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	bp->mdev = mdev;
12718c2ecf20Sopenharmony_ci	spin_lock_init(&bp->lock);
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	if (macio_request_resources(mdev, "bmac")) {
12748c2ecf20Sopenharmony_ci		printk(KERN_ERR "BMAC: can't request IO resource !\n");
12758c2ecf20Sopenharmony_ci		goto out_free;
12768c2ecf20Sopenharmony_ci	}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	dev->base_addr = (unsigned long)
12798c2ecf20Sopenharmony_ci		ioremap(macio_resource_start(mdev, 0), macio_resource_len(mdev, 0));
12808c2ecf20Sopenharmony_ci	if (dev->base_addr == 0)
12818c2ecf20Sopenharmony_ci		goto out_release;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	dev->irq = macio_irq(mdev, 0);
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	bmac_enable_and_reset_chip(dev);
12868c2ecf20Sopenharmony_ci	bmwrite(dev, INTDISABLE, DisableAll);
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	rev = addr[0] == 0 && addr[1] == 0xA0;
12898c2ecf20Sopenharmony_ci	for (j = 0; j < 6; ++j)
12908c2ecf20Sopenharmony_ci		dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	/* Enable chip without interrupts for now */
12938c2ecf20Sopenharmony_ci	bmac_enable_and_reset_chip(dev);
12948c2ecf20Sopenharmony_ci	bmwrite(dev, INTDISABLE, DisableAll);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	dev->netdev_ops = &bmac_netdev_ops;
12978c2ecf20Sopenharmony_ci	dev->ethtool_ops = &bmac_ethtool_ops;
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	bmac_get_station_address(dev, addr);
13008c2ecf20Sopenharmony_ci	if (bmac_verify_checksum(dev) != 0)
13018c2ecf20Sopenharmony_ci		goto err_out_iounmap;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	bp->is_bmac_plus = is_bmac_plus;
13048c2ecf20Sopenharmony_ci	bp->tx_dma = ioremap(macio_resource_start(mdev, 1), macio_resource_len(mdev, 1));
13058c2ecf20Sopenharmony_ci	if (!bp->tx_dma)
13068c2ecf20Sopenharmony_ci		goto err_out_iounmap;
13078c2ecf20Sopenharmony_ci	bp->tx_dma_intr = macio_irq(mdev, 1);
13088c2ecf20Sopenharmony_ci	bp->rx_dma = ioremap(macio_resource_start(mdev, 2), macio_resource_len(mdev, 2));
13098c2ecf20Sopenharmony_ci	if (!bp->rx_dma)
13108c2ecf20Sopenharmony_ci		goto err_out_iounmap_tx;
13118c2ecf20Sopenharmony_ci	bp->rx_dma_intr = macio_irq(mdev, 2);
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
13148c2ecf20Sopenharmony_ci	bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);
13178c2ecf20Sopenharmony_ci	skb_queue_head_init(bp->queue);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	timer_setup(&bp->tx_timeout, bmac_tx_timeout, 0);
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	ret = request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev);
13228c2ecf20Sopenharmony_ci	if (ret) {
13238c2ecf20Sopenharmony_ci		printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
13248c2ecf20Sopenharmony_ci		goto err_out_iounmap_rx;
13258c2ecf20Sopenharmony_ci	}
13268c2ecf20Sopenharmony_ci	ret = request_irq(bp->tx_dma_intr, bmac_txdma_intr, 0, "BMAC-txdma", dev);
13278c2ecf20Sopenharmony_ci	if (ret) {
13288c2ecf20Sopenharmony_ci		printk(KERN_ERR "BMAC: can't get irq %d\n", bp->tx_dma_intr);
13298c2ecf20Sopenharmony_ci		goto err_out_irq0;
13308c2ecf20Sopenharmony_ci	}
13318c2ecf20Sopenharmony_ci	ret = request_irq(bp->rx_dma_intr, bmac_rxdma_intr, 0, "BMAC-rxdma", dev);
13328c2ecf20Sopenharmony_ci	if (ret) {
13338c2ecf20Sopenharmony_ci		printk(KERN_ERR "BMAC: can't get irq %d\n", bp->rx_dma_intr);
13348c2ecf20Sopenharmony_ci		goto err_out_irq1;
13358c2ecf20Sopenharmony_ci	}
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	/* Mask chip interrupts and disable chip, will be
13388c2ecf20Sopenharmony_ci	 * re-enabled on open()
13398c2ecf20Sopenharmony_ci	 */
13408c2ecf20Sopenharmony_ci	disable_irq(dev->irq);
13418c2ecf20Sopenharmony_ci	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	if (register_netdev(dev) != 0) {
13448c2ecf20Sopenharmony_ci		printk(KERN_ERR "BMAC: Ethernet registration failed\n");
13458c2ecf20Sopenharmony_ci		goto err_out_irq2;
13468c2ecf20Sopenharmony_ci	}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	printk(KERN_INFO "%s: BMAC%s at %pM",
13498c2ecf20Sopenharmony_ci	       dev->name, (is_bmac_plus ? "+" : ""), dev->dev_addr);
13508c2ecf20Sopenharmony_ci	XXDEBUG((", base_addr=%#0lx", dev->base_addr));
13518c2ecf20Sopenharmony_ci	printk("\n");
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	return 0;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_cierr_out_irq2:
13568c2ecf20Sopenharmony_ci	free_irq(bp->rx_dma_intr, dev);
13578c2ecf20Sopenharmony_cierr_out_irq1:
13588c2ecf20Sopenharmony_ci	free_irq(bp->tx_dma_intr, dev);
13598c2ecf20Sopenharmony_cierr_out_irq0:
13608c2ecf20Sopenharmony_ci	free_irq(dev->irq, dev);
13618c2ecf20Sopenharmony_cierr_out_iounmap_rx:
13628c2ecf20Sopenharmony_ci	iounmap(bp->rx_dma);
13638c2ecf20Sopenharmony_cierr_out_iounmap_tx:
13648c2ecf20Sopenharmony_ci	iounmap(bp->tx_dma);
13658c2ecf20Sopenharmony_cierr_out_iounmap:
13668c2ecf20Sopenharmony_ci	iounmap((void __iomem *)dev->base_addr);
13678c2ecf20Sopenharmony_ciout_release:
13688c2ecf20Sopenharmony_ci	macio_release_resources(mdev);
13698c2ecf20Sopenharmony_ciout_free:
13708c2ecf20Sopenharmony_ci	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
13718c2ecf20Sopenharmony_ci	free_netdev(dev);
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	return -ENODEV;
13748c2ecf20Sopenharmony_ci}
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_cistatic int bmac_open(struct net_device *dev)
13778c2ecf20Sopenharmony_ci{
13788c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
13798c2ecf20Sopenharmony_ci	/* XXDEBUG(("bmac: enter open\n")); */
13808c2ecf20Sopenharmony_ci	/* reset the chip */
13818c2ecf20Sopenharmony_ci	bp->opened = 1;
13828c2ecf20Sopenharmony_ci	bmac_reset_and_enable(dev);
13838c2ecf20Sopenharmony_ci	enable_irq(dev->irq);
13848c2ecf20Sopenharmony_ci	return 0;
13858c2ecf20Sopenharmony_ci}
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_cistatic int bmac_close(struct net_device *dev)
13888c2ecf20Sopenharmony_ci{
13898c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
13908c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
13918c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
13928c2ecf20Sopenharmony_ci	unsigned short config;
13938c2ecf20Sopenharmony_ci	int i;
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	bp->sleeping = 1;
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	/* disable rx and tx */
13988c2ecf20Sopenharmony_ci	config = bmread(dev, RXCFG);
13998c2ecf20Sopenharmony_ci	bmwrite(dev, RXCFG, (config & ~RxMACEnable));
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	config = bmread(dev, TXCFG);
14028c2ecf20Sopenharmony_ci	bmwrite(dev, TXCFG, (config & ~TxMACEnable));
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	/* disable rx and tx dma */
14078c2ecf20Sopenharmony_ci	rd->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
14088c2ecf20Sopenharmony_ci	td->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	/* free some skb's */
14118c2ecf20Sopenharmony_ci	XXDEBUG(("bmac: free rx bufs\n"));
14128c2ecf20Sopenharmony_ci	for (i=0; i<N_RX_RING; i++) {
14138c2ecf20Sopenharmony_ci		if (bp->rx_bufs[i] != NULL) {
14148c2ecf20Sopenharmony_ci			dev_kfree_skb(bp->rx_bufs[i]);
14158c2ecf20Sopenharmony_ci			bp->rx_bufs[i] = NULL;
14168c2ecf20Sopenharmony_ci		}
14178c2ecf20Sopenharmony_ci	}
14188c2ecf20Sopenharmony_ci	XXDEBUG(("bmac: free tx bufs\n"));
14198c2ecf20Sopenharmony_ci	for (i = 0; i<N_TX_RING; i++) {
14208c2ecf20Sopenharmony_ci		if (bp->tx_bufs[i] != NULL) {
14218c2ecf20Sopenharmony_ci			dev_kfree_skb(bp->tx_bufs[i]);
14228c2ecf20Sopenharmony_ci			bp->tx_bufs[i] = NULL;
14238c2ecf20Sopenharmony_ci		}
14248c2ecf20Sopenharmony_ci	}
14258c2ecf20Sopenharmony_ci	XXDEBUG(("bmac: all bufs freed\n"));
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	bp->opened = 0;
14288c2ecf20Sopenharmony_ci	disable_irq(dev->irq);
14298c2ecf20Sopenharmony_ci	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	return 0;
14328c2ecf20Sopenharmony_ci}
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_cistatic void
14358c2ecf20Sopenharmony_cibmac_start(struct net_device *dev)
14368c2ecf20Sopenharmony_ci{
14378c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
14388c2ecf20Sopenharmony_ci	int i;
14398c2ecf20Sopenharmony_ci	struct sk_buff *skb;
14408c2ecf20Sopenharmony_ci	unsigned long flags;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	if (bp->sleeping)
14438c2ecf20Sopenharmony_ci		return;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
14468c2ecf20Sopenharmony_ci	while (1) {
14478c2ecf20Sopenharmony_ci		i = bp->tx_fill + 1;
14488c2ecf20Sopenharmony_ci		if (i >= N_TX_RING)
14498c2ecf20Sopenharmony_ci			i = 0;
14508c2ecf20Sopenharmony_ci		if (i == bp->tx_empty)
14518c2ecf20Sopenharmony_ci			break;
14528c2ecf20Sopenharmony_ci		skb = skb_dequeue(bp->queue);
14538c2ecf20Sopenharmony_ci		if (skb == NULL)
14548c2ecf20Sopenharmony_ci			break;
14558c2ecf20Sopenharmony_ci		bmac_transmit_packet(skb, dev);
14568c2ecf20Sopenharmony_ci	}
14578c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
14588c2ecf20Sopenharmony_ci}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_cistatic netdev_tx_t
14618c2ecf20Sopenharmony_cibmac_output(struct sk_buff *skb, struct net_device *dev)
14628c2ecf20Sopenharmony_ci{
14638c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
14648c2ecf20Sopenharmony_ci	skb_queue_tail(bp->queue, skb);
14658c2ecf20Sopenharmony_ci	bmac_start(dev);
14668c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
14678c2ecf20Sopenharmony_ci}
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_cistatic void bmac_tx_timeout(struct timer_list *t)
14708c2ecf20Sopenharmony_ci{
14718c2ecf20Sopenharmony_ci	struct bmac_data *bp = from_timer(bp, t, tx_timeout);
14728c2ecf20Sopenharmony_ci	struct net_device *dev = macio_get_drvdata(bp->mdev);
14738c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
14748c2ecf20Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
14758c2ecf20Sopenharmony_ci	volatile struct dbdma_cmd *cp;
14768c2ecf20Sopenharmony_ci	unsigned long flags;
14778c2ecf20Sopenharmony_ci	unsigned short config, oldConfig;
14788c2ecf20Sopenharmony_ci	int i;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	XXDEBUG(("bmac: tx_timeout called\n"));
14818c2ecf20Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
14828c2ecf20Sopenharmony_ci	bp->timeout_active = 0;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	/* update various counters */
14858c2ecf20Sopenharmony_ci/*     	bmac_handle_misc_intrs(bp, 0); */
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	cp = &bp->tx_cmds[bp->tx_empty];
14888c2ecf20Sopenharmony_ci/*	XXDEBUG((KERN_DEBUG "bmac: tx dmastat=%x %x runt=%d pr=%x fs=%x fc=%x\n", */
14898c2ecf20Sopenharmony_ci/* 	   le32_to_cpu(td->status), le16_to_cpu(cp->xfer_status), bp->tx_bad_runt, */
14908c2ecf20Sopenharmony_ci/* 	   mb->pr, mb->xmtfs, mb->fifofc)); */
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	/* turn off both tx and rx and reset the chip */
14938c2ecf20Sopenharmony_ci	config = bmread(dev, RXCFG);
14948c2ecf20Sopenharmony_ci	bmwrite(dev, RXCFG, (config & ~RxMACEnable));
14958c2ecf20Sopenharmony_ci	config = bmread(dev, TXCFG);
14968c2ecf20Sopenharmony_ci	bmwrite(dev, TXCFG, (config & ~TxMACEnable));
14978c2ecf20Sopenharmony_ci	out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
14988c2ecf20Sopenharmony_ci	printk(KERN_ERR "bmac: transmit timeout - resetting\n");
14998c2ecf20Sopenharmony_ci	bmac_enable_and_reset_chip(dev);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	/* restart rx dma */
15028c2ecf20Sopenharmony_ci	cp = bus_to_virt(le32_to_cpu(rd->cmdptr));
15038c2ecf20Sopenharmony_ci	out_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
15048c2ecf20Sopenharmony_ci	out_le16(&cp->xfer_status, 0);
15058c2ecf20Sopenharmony_ci	out_le32(&rd->cmdptr, virt_to_bus(cp));
15068c2ecf20Sopenharmony_ci	out_le32(&rd->control, DBDMA_SET(RUN|WAKE));
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	/* fix up the transmit side */
15098c2ecf20Sopenharmony_ci	XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n",
15108c2ecf20Sopenharmony_ci		 bp->tx_empty, bp->tx_fill, bp->tx_fullup));
15118c2ecf20Sopenharmony_ci	i = bp->tx_empty;
15128c2ecf20Sopenharmony_ci	++dev->stats.tx_errors;
15138c2ecf20Sopenharmony_ci	if (i != bp->tx_fill) {
15148c2ecf20Sopenharmony_ci		dev_kfree_skb_irq(bp->tx_bufs[i]);
15158c2ecf20Sopenharmony_ci		bp->tx_bufs[i] = NULL;
15168c2ecf20Sopenharmony_ci		if (++i >= N_TX_RING) i = 0;
15178c2ecf20Sopenharmony_ci		bp->tx_empty = i;
15188c2ecf20Sopenharmony_ci	}
15198c2ecf20Sopenharmony_ci	bp->tx_fullup = 0;
15208c2ecf20Sopenharmony_ci	netif_wake_queue(dev);
15218c2ecf20Sopenharmony_ci	if (i != bp->tx_fill) {
15228c2ecf20Sopenharmony_ci		cp = &bp->tx_cmds[i];
15238c2ecf20Sopenharmony_ci		out_le16(&cp->xfer_status, 0);
15248c2ecf20Sopenharmony_ci		out_le16(&cp->command, OUTPUT_LAST);
15258c2ecf20Sopenharmony_ci		out_le32(&td->cmdptr, virt_to_bus(cp));
15268c2ecf20Sopenharmony_ci		out_le32(&td->control, DBDMA_SET(RUN));
15278c2ecf20Sopenharmony_ci		/* 	bmac_set_timeout(dev); */
15288c2ecf20Sopenharmony_ci		XXDEBUG((KERN_DEBUG "bmac: starting %d\n", i));
15298c2ecf20Sopenharmony_ci	}
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	/* turn it back on */
15328c2ecf20Sopenharmony_ci	oldConfig = bmread(dev, RXCFG);
15338c2ecf20Sopenharmony_ci	bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
15348c2ecf20Sopenharmony_ci	oldConfig = bmread(dev, TXCFG);
15358c2ecf20Sopenharmony_ci	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
15388c2ecf20Sopenharmony_ci}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci#if 0
15418c2ecf20Sopenharmony_cistatic void dump_dbdma(volatile struct dbdma_cmd *cp,int count)
15428c2ecf20Sopenharmony_ci{
15438c2ecf20Sopenharmony_ci	int i,*ip;
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	for (i=0;i< count;i++) {
15468c2ecf20Sopenharmony_ci		ip = (int*)(cp+i);
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci		printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n",
15498c2ecf20Sopenharmony_ci		       le32_to_cpup(ip+0),
15508c2ecf20Sopenharmony_ci		       le32_to_cpup(ip+1),
15518c2ecf20Sopenharmony_ci		       le32_to_cpup(ip+2),
15528c2ecf20Sopenharmony_ci		       le32_to_cpup(ip+3));
15538c2ecf20Sopenharmony_ci	}
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci}
15568c2ecf20Sopenharmony_ci#endif
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci#if 0
15598c2ecf20Sopenharmony_cistatic int
15608c2ecf20Sopenharmony_cibmac_proc_info(char *buffer, char **start, off_t offset, int length)
15618c2ecf20Sopenharmony_ci{
15628c2ecf20Sopenharmony_ci	int len = 0;
15638c2ecf20Sopenharmony_ci	off_t pos   = 0;
15648c2ecf20Sopenharmony_ci	off_t begin = 0;
15658c2ecf20Sopenharmony_ci	int i;
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	if (bmac_devs == NULL)
15688c2ecf20Sopenharmony_ci		return -ENOSYS;
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	len += sprintf(buffer, "BMAC counters & registers\n");
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	for (i = 0; i<N_REG_ENTRIES; i++) {
15738c2ecf20Sopenharmony_ci		len += sprintf(buffer + len, "%s: %#08x\n",
15748c2ecf20Sopenharmony_ci			       reg_entries[i].name,
15758c2ecf20Sopenharmony_ci			       bmread(bmac_devs, reg_entries[i].reg_offset));
15768c2ecf20Sopenharmony_ci		pos = begin + len;
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci		if (pos < offset) {
15798c2ecf20Sopenharmony_ci			len = 0;
15808c2ecf20Sopenharmony_ci			begin = pos;
15818c2ecf20Sopenharmony_ci		}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci		if (pos > offset+length) break;
15848c2ecf20Sopenharmony_ci	}
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	*start = buffer + (offset - begin);
15878c2ecf20Sopenharmony_ci	len -= (offset - begin);
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	if (len > length) len = length;
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	return len;
15928c2ecf20Sopenharmony_ci}
15938c2ecf20Sopenharmony_ci#endif
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_cistatic int bmac_remove(struct macio_dev *mdev)
15968c2ecf20Sopenharmony_ci{
15978c2ecf20Sopenharmony_ci	struct net_device *dev = macio_get_drvdata(mdev);
15988c2ecf20Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	unregister_netdev(dev);
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci       	free_irq(dev->irq, dev);
16038c2ecf20Sopenharmony_ci	free_irq(bp->tx_dma_intr, dev);
16048c2ecf20Sopenharmony_ci	free_irq(bp->rx_dma_intr, dev);
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	iounmap((void __iomem *)dev->base_addr);
16078c2ecf20Sopenharmony_ci	iounmap(bp->tx_dma);
16088c2ecf20Sopenharmony_ci	iounmap(bp->rx_dma);
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	macio_release_resources(mdev);
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	free_netdev(dev);
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci	return 0;
16158c2ecf20Sopenharmony_ci}
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_cistatic const struct of_device_id bmac_match[] =
16188c2ecf20Sopenharmony_ci{
16198c2ecf20Sopenharmony_ci	{
16208c2ecf20Sopenharmony_ci	.name 		= "bmac",
16218c2ecf20Sopenharmony_ci	.data		= (void *)0,
16228c2ecf20Sopenharmony_ci	},
16238c2ecf20Sopenharmony_ci	{
16248c2ecf20Sopenharmony_ci	.type		= "network",
16258c2ecf20Sopenharmony_ci	.compatible	= "bmac+",
16268c2ecf20Sopenharmony_ci	.data		= (void *)1,
16278c2ecf20Sopenharmony_ci	},
16288c2ecf20Sopenharmony_ci	{},
16298c2ecf20Sopenharmony_ci};
16308c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE (of, bmac_match);
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_cistatic struct macio_driver bmac_driver =
16338c2ecf20Sopenharmony_ci{
16348c2ecf20Sopenharmony_ci	.driver = {
16358c2ecf20Sopenharmony_ci		.name 		= "bmac",
16368c2ecf20Sopenharmony_ci		.owner		= THIS_MODULE,
16378c2ecf20Sopenharmony_ci		.of_match_table	= bmac_match,
16388c2ecf20Sopenharmony_ci	},
16398c2ecf20Sopenharmony_ci	.probe		= bmac_probe,
16408c2ecf20Sopenharmony_ci	.remove		= bmac_remove,
16418c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
16428c2ecf20Sopenharmony_ci	.suspend	= bmac_suspend,
16438c2ecf20Sopenharmony_ci	.resume		= bmac_resume,
16448c2ecf20Sopenharmony_ci#endif
16458c2ecf20Sopenharmony_ci};
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_cistatic int __init bmac_init(void)
16498c2ecf20Sopenharmony_ci{
16508c2ecf20Sopenharmony_ci	if (bmac_emergency_rxbuf == NULL) {
16518c2ecf20Sopenharmony_ci		bmac_emergency_rxbuf = kmalloc(RX_BUFLEN, GFP_KERNEL);
16528c2ecf20Sopenharmony_ci		if (bmac_emergency_rxbuf == NULL)
16538c2ecf20Sopenharmony_ci			return -ENOMEM;
16548c2ecf20Sopenharmony_ci	}
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	return macio_register_driver(&bmac_driver);
16578c2ecf20Sopenharmony_ci}
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_cistatic void __exit bmac_exit(void)
16608c2ecf20Sopenharmony_ci{
16618c2ecf20Sopenharmony_ci	macio_unregister_driver(&bmac_driver);
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	kfree(bmac_emergency_rxbuf);
16648c2ecf20Sopenharmony_ci	bmac_emergency_rxbuf = NULL;
16658c2ecf20Sopenharmony_ci}
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ciMODULE_AUTHOR("Randy Gobbel/Paul Mackerras");
16688c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");
16698c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_cimodule_init(bmac_init);
16728c2ecf20Sopenharmony_cimodule_exit(bmac_exit);
1673