162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Network device driver for the BMAC ethernet controller on
462306a36Sopenharmony_ci * Apple Powermacs.  Assumes it's under a DBDMA controller.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 1998 Randy Gobbel.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * May 1999, Al Viro: proper release of /proc/net/bmac entry, switched to
962306a36Sopenharmony_ci * dynamic procfs inode.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/netdevice.h>
1562306a36Sopenharmony_ci#include <linux/etherdevice.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/string.h>
1862306a36Sopenharmony_ci#include <linux/timer.h>
1962306a36Sopenharmony_ci#include <linux/proc_fs.h>
2062306a36Sopenharmony_ci#include <linux/init.h>
2162306a36Sopenharmony_ci#include <linux/spinlock.h>
2262306a36Sopenharmony_ci#include <linux/crc32.h>
2362306a36Sopenharmony_ci#include <linux/crc32poly.h>
2462306a36Sopenharmony_ci#include <linux/bitrev.h>
2562306a36Sopenharmony_ci#include <linux/ethtool.h>
2662306a36Sopenharmony_ci#include <linux/slab.h>
2762306a36Sopenharmony_ci#include <linux/pgtable.h>
2862306a36Sopenharmony_ci#include <asm/dbdma.h>
2962306a36Sopenharmony_ci#include <asm/io.h>
3062306a36Sopenharmony_ci#include <asm/page.h>
3162306a36Sopenharmony_ci#include <asm/machdep.h>
3262306a36Sopenharmony_ci#include <asm/pmac_feature.h>
3362306a36Sopenharmony_ci#include <asm/macio.h>
3462306a36Sopenharmony_ci#include <asm/irq.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include "bmac.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define trunc_page(x)	((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
3962306a36Sopenharmony_ci#define round_page(x)	trunc_page(((unsigned long)(x)) + ((unsigned long)(PAGE_SIZE - 1)))
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* switch to use multicast code lifted from sunhme driver */
4262306a36Sopenharmony_ci#define SUNHME_MULTICAST
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define N_RX_RING	64
4562306a36Sopenharmony_ci#define N_TX_RING	32
4662306a36Sopenharmony_ci#define MAX_TX_ACTIVE	1
4762306a36Sopenharmony_ci#define ETHERCRC	4
4862306a36Sopenharmony_ci#define ETHERMINPACKET	64
4962306a36Sopenharmony_ci#define ETHERMTU	1500
5062306a36Sopenharmony_ci#define RX_BUFLEN	(ETHERMTU + 14 + ETHERCRC + 2)
5162306a36Sopenharmony_ci#define TX_TIMEOUT	HZ	/* 1 second */
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Bits in transmit DMA status */
5462306a36Sopenharmony_ci#define TX_DMA_ERR	0x80
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define XXDEBUG(args)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistruct bmac_data {
5962306a36Sopenharmony_ci	/* volatile struct bmac *bmac; */
6062306a36Sopenharmony_ci	struct sk_buff_head *queue;
6162306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *tx_dma;
6262306a36Sopenharmony_ci	int tx_dma_intr;
6362306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *rx_dma;
6462306a36Sopenharmony_ci	int rx_dma_intr;
6562306a36Sopenharmony_ci	volatile struct dbdma_cmd *tx_cmds;	/* xmit dma command list */
6662306a36Sopenharmony_ci	volatile struct dbdma_cmd *rx_cmds;	/* recv dma command list */
6762306a36Sopenharmony_ci	struct macio_dev *mdev;
6862306a36Sopenharmony_ci	int is_bmac_plus;
6962306a36Sopenharmony_ci	struct sk_buff *rx_bufs[N_RX_RING];
7062306a36Sopenharmony_ci	int rx_fill;
7162306a36Sopenharmony_ci	int rx_empty;
7262306a36Sopenharmony_ci	struct sk_buff *tx_bufs[N_TX_RING];
7362306a36Sopenharmony_ci	int tx_fill;
7462306a36Sopenharmony_ci	int tx_empty;
7562306a36Sopenharmony_ci	unsigned char tx_fullup;
7662306a36Sopenharmony_ci	struct timer_list tx_timeout;
7762306a36Sopenharmony_ci	int timeout_active;
7862306a36Sopenharmony_ci	int sleeping;
7962306a36Sopenharmony_ci	int opened;
8062306a36Sopenharmony_ci	unsigned short hash_use_count[64];
8162306a36Sopenharmony_ci	unsigned short hash_table_mask[4];
8262306a36Sopenharmony_ci	spinlock_t lock;
8362306a36Sopenharmony_ci};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#if 0 /* Move that to ethtool */
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_citypedef struct bmac_reg_entry {
8862306a36Sopenharmony_ci	char *name;
8962306a36Sopenharmony_ci	unsigned short reg_offset;
9062306a36Sopenharmony_ci} bmac_reg_entry_t;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define N_REG_ENTRIES 31
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = {
9562306a36Sopenharmony_ci	{"MEMADD", MEMADD},
9662306a36Sopenharmony_ci	{"MEMDATAHI", MEMDATAHI},
9762306a36Sopenharmony_ci	{"MEMDATALO", MEMDATALO},
9862306a36Sopenharmony_ci	{"TXPNTR", TXPNTR},
9962306a36Sopenharmony_ci	{"RXPNTR", RXPNTR},
10062306a36Sopenharmony_ci	{"IPG1", IPG1},
10162306a36Sopenharmony_ci	{"IPG2", IPG2},
10262306a36Sopenharmony_ci	{"ALIMIT", ALIMIT},
10362306a36Sopenharmony_ci	{"SLOT", SLOT},
10462306a36Sopenharmony_ci	{"PALEN", PALEN},
10562306a36Sopenharmony_ci	{"PAPAT", PAPAT},
10662306a36Sopenharmony_ci	{"TXSFD", TXSFD},
10762306a36Sopenharmony_ci	{"JAM", JAM},
10862306a36Sopenharmony_ci	{"TXCFG", TXCFG},
10962306a36Sopenharmony_ci	{"TXMAX", TXMAX},
11062306a36Sopenharmony_ci	{"TXMIN", TXMIN},
11162306a36Sopenharmony_ci	{"PAREG", PAREG},
11262306a36Sopenharmony_ci	{"DCNT", DCNT},
11362306a36Sopenharmony_ci	{"NCCNT", NCCNT},
11462306a36Sopenharmony_ci	{"NTCNT", NTCNT},
11562306a36Sopenharmony_ci	{"EXCNT", EXCNT},
11662306a36Sopenharmony_ci	{"LTCNT", LTCNT},
11762306a36Sopenharmony_ci	{"TXSM", TXSM},
11862306a36Sopenharmony_ci	{"RXCFG", RXCFG},
11962306a36Sopenharmony_ci	{"RXMAX", RXMAX},
12062306a36Sopenharmony_ci	{"RXMIN", RXMIN},
12162306a36Sopenharmony_ci	{"FRCNT", FRCNT},
12262306a36Sopenharmony_ci	{"AECNT", AECNT},
12362306a36Sopenharmony_ci	{"FECNT", FECNT},
12462306a36Sopenharmony_ci	{"RXSM", RXSM},
12562306a36Sopenharmony_ci	{"RXCV", RXCV}
12662306a36Sopenharmony_ci};
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#endif
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic unsigned char *bmac_emergency_rxbuf;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/*
13362306a36Sopenharmony_ci * Number of bytes of private data per BMAC: allow enough for
13462306a36Sopenharmony_ci * the rx and tx dma commands plus a branch dma command each,
13562306a36Sopenharmony_ci * and another 16 bytes to allow us to align the dma command
13662306a36Sopenharmony_ci * buffers on a 16 byte boundary.
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_ci#define PRIV_BYTES	(sizeof(struct bmac_data) \
13962306a36Sopenharmony_ci	+ (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
14062306a36Sopenharmony_ci	+ sizeof(struct sk_buff_head))
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int bmac_open(struct net_device *dev);
14362306a36Sopenharmony_cistatic int bmac_close(struct net_device *dev);
14462306a36Sopenharmony_cistatic int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
14562306a36Sopenharmony_cistatic void bmac_set_multicast(struct net_device *dev);
14662306a36Sopenharmony_cistatic void bmac_reset_and_enable(struct net_device *dev);
14762306a36Sopenharmony_cistatic void bmac_start_chip(struct net_device *dev);
14862306a36Sopenharmony_cistatic void bmac_init_chip(struct net_device *dev);
14962306a36Sopenharmony_cistatic void bmac_init_registers(struct net_device *dev);
15062306a36Sopenharmony_cistatic void bmac_enable_and_reset_chip(struct net_device *dev);
15162306a36Sopenharmony_cistatic int bmac_set_address(struct net_device *dev, void *addr);
15262306a36Sopenharmony_cistatic irqreturn_t bmac_misc_intr(int irq, void *dev_id);
15362306a36Sopenharmony_cistatic irqreturn_t bmac_txdma_intr(int irq, void *dev_id);
15462306a36Sopenharmony_cistatic irqreturn_t bmac_rxdma_intr(int irq, void *dev_id);
15562306a36Sopenharmony_cistatic void bmac_set_timeout(struct net_device *dev);
15662306a36Sopenharmony_cistatic void bmac_tx_timeout(struct timer_list *t);
15762306a36Sopenharmony_cistatic netdev_tx_t bmac_output(struct sk_buff *skb, struct net_device *dev);
15862306a36Sopenharmony_cistatic void bmac_start(struct net_device *dev);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci#define	DBDMA_SET(x)	( ((x) | (x) << 16) )
16162306a36Sopenharmony_ci#define	DBDMA_CLEAR(x)	( (x) << 16)
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic inline void
16462306a36Sopenharmony_cidbdma_st32(volatile __u32 __iomem *a, unsigned long x)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	__asm__ volatile( "stwbrx %0,0,%1" : : "r" (x), "r" (a) : "memory");
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic inline unsigned long
17062306a36Sopenharmony_cidbdma_ld32(volatile __u32 __iomem *a)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	__u32 swap;
17362306a36Sopenharmony_ci	__asm__ volatile ("lwbrx %0,0,%1" :  "=r" (swap) : "r" (a));
17462306a36Sopenharmony_ci	return swap;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void
17862306a36Sopenharmony_cidbdma_continue(volatile struct dbdma_regs __iomem *dmap)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	dbdma_st32(&dmap->control,
18162306a36Sopenharmony_ci		   DBDMA_SET(RUN|WAKE) | DBDMA_CLEAR(PAUSE|DEAD));
18262306a36Sopenharmony_ci	eieio();
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic void
18662306a36Sopenharmony_cidbdma_reset(volatile struct dbdma_regs __iomem *dmap)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	dbdma_st32(&dmap->control,
18962306a36Sopenharmony_ci		   DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN));
19062306a36Sopenharmony_ci	eieio();
19162306a36Sopenharmony_ci	while (dbdma_ld32(&dmap->status) & RUN)
19262306a36Sopenharmony_ci		eieio();
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic void
19662306a36Sopenharmony_cidbdma_setcmd(volatile struct dbdma_cmd *cp,
19762306a36Sopenharmony_ci	     unsigned short cmd, unsigned count, unsigned long addr,
19862306a36Sopenharmony_ci	     unsigned long cmd_dep)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	out_le16(&cp->command, cmd);
20162306a36Sopenharmony_ci	out_le16(&cp->req_count, count);
20262306a36Sopenharmony_ci	out_le32(&cp->phy_addr, addr);
20362306a36Sopenharmony_ci	out_le32(&cp->cmd_dep, cmd_dep);
20462306a36Sopenharmony_ci	out_le16(&cp->xfer_status, 0);
20562306a36Sopenharmony_ci	out_le16(&cp->res_count, 0);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic inline
20962306a36Sopenharmony_civoid bmwrite(struct net_device *dev, unsigned long reg_offset, unsigned data )
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	out_le16((void __iomem *)dev->base_addr + reg_offset, data);
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic inline
21662306a36Sopenharmony_ciunsigned short bmread(struct net_device *dev, unsigned long reg_offset )
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	return in_le16((void __iomem *)dev->base_addr + reg_offset);
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic void
22262306a36Sopenharmony_cibmac_enable_and_reset_chip(struct net_device *dev)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
22562306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
22662306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (rd)
22962306a36Sopenharmony_ci		dbdma_reset(rd);
23062306a36Sopenharmony_ci	if (td)
23162306a36Sopenharmony_ci		dbdma_reset(td);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 1);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci#define MIFDELAY	udelay(10)
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic unsigned int
23962306a36Sopenharmony_cibmac_mif_readbits(struct net_device *dev, int nb)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	unsigned int val = 0;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	while (--nb >= 0) {
24462306a36Sopenharmony_ci		bmwrite(dev, MIFCSR, 0);
24562306a36Sopenharmony_ci		MIFDELAY;
24662306a36Sopenharmony_ci		if (bmread(dev, MIFCSR) & 8)
24762306a36Sopenharmony_ci			val |= 1 << nb;
24862306a36Sopenharmony_ci		bmwrite(dev, MIFCSR, 1);
24962306a36Sopenharmony_ci		MIFDELAY;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci	bmwrite(dev, MIFCSR, 0);
25262306a36Sopenharmony_ci	MIFDELAY;
25362306a36Sopenharmony_ci	bmwrite(dev, MIFCSR, 1);
25462306a36Sopenharmony_ci	MIFDELAY;
25562306a36Sopenharmony_ci	return val;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic void
25962306a36Sopenharmony_cibmac_mif_writebits(struct net_device *dev, unsigned int val, int nb)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	int b;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	while (--nb >= 0) {
26462306a36Sopenharmony_ci		b = (val & (1 << nb))? 6: 4;
26562306a36Sopenharmony_ci		bmwrite(dev, MIFCSR, b);
26662306a36Sopenharmony_ci		MIFDELAY;
26762306a36Sopenharmony_ci		bmwrite(dev, MIFCSR, b|1);
26862306a36Sopenharmony_ci		MIFDELAY;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic unsigned int
27362306a36Sopenharmony_cibmac_mif_read(struct net_device *dev, unsigned int addr)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	unsigned int val;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	bmwrite(dev, MIFCSR, 4);
27862306a36Sopenharmony_ci	MIFDELAY;
27962306a36Sopenharmony_ci	bmac_mif_writebits(dev, ~0U, 32);
28062306a36Sopenharmony_ci	bmac_mif_writebits(dev, 6, 4);
28162306a36Sopenharmony_ci	bmac_mif_writebits(dev, addr, 10);
28262306a36Sopenharmony_ci	bmwrite(dev, MIFCSR, 2);
28362306a36Sopenharmony_ci	MIFDELAY;
28462306a36Sopenharmony_ci	bmwrite(dev, MIFCSR, 1);
28562306a36Sopenharmony_ci	MIFDELAY;
28662306a36Sopenharmony_ci	val = bmac_mif_readbits(dev, 17);
28762306a36Sopenharmony_ci	bmwrite(dev, MIFCSR, 4);
28862306a36Sopenharmony_ci	MIFDELAY;
28962306a36Sopenharmony_ci	return val;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic void
29362306a36Sopenharmony_cibmac_mif_write(struct net_device *dev, unsigned int addr, unsigned int val)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	bmwrite(dev, MIFCSR, 4);
29662306a36Sopenharmony_ci	MIFDELAY;
29762306a36Sopenharmony_ci	bmac_mif_writebits(dev, ~0U, 32);
29862306a36Sopenharmony_ci	bmac_mif_writebits(dev, 5, 4);
29962306a36Sopenharmony_ci	bmac_mif_writebits(dev, addr, 10);
30062306a36Sopenharmony_ci	bmac_mif_writebits(dev, 2, 2);
30162306a36Sopenharmony_ci	bmac_mif_writebits(dev, val, 16);
30262306a36Sopenharmony_ci	bmac_mif_writebits(dev, 3, 2);
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic void
30662306a36Sopenharmony_cibmac_init_registers(struct net_device *dev)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
30962306a36Sopenharmony_ci	volatile unsigned short regValue;
31062306a36Sopenharmony_ci	const unsigned short *pWord16;
31162306a36Sopenharmony_ci	int i;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* XXDEBUG(("bmac: enter init_registers\n")); */
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	bmwrite(dev, RXRST, RxResetValue);
31662306a36Sopenharmony_ci	bmwrite(dev, TXRST, TxResetBit);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	i = 100;
31962306a36Sopenharmony_ci	do {
32062306a36Sopenharmony_ci		--i;
32162306a36Sopenharmony_ci		udelay(10000);
32262306a36Sopenharmony_ci		regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
32362306a36Sopenharmony_ci	} while ((regValue & TxResetBit) && i > 0);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (!bp->is_bmac_plus) {
32662306a36Sopenharmony_ci		regValue = bmread(dev, XCVRIF);
32762306a36Sopenharmony_ci		regValue |= ClkBit | SerialMode | COLActiveLow;
32862306a36Sopenharmony_ci		bmwrite(dev, XCVRIF, regValue);
32962306a36Sopenharmony_ci		udelay(10000);
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	bmwrite(dev, RSEED, (unsigned short)0x1968);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	regValue = bmread(dev, XIFC);
33562306a36Sopenharmony_ci	regValue |= TxOutputEnable;
33662306a36Sopenharmony_ci	bmwrite(dev, XIFC, regValue);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	bmread(dev, PAREG);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* set collision counters to 0 */
34162306a36Sopenharmony_ci	bmwrite(dev, NCCNT, 0);
34262306a36Sopenharmony_ci	bmwrite(dev, NTCNT, 0);
34362306a36Sopenharmony_ci	bmwrite(dev, EXCNT, 0);
34462306a36Sopenharmony_ci	bmwrite(dev, LTCNT, 0);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	/* set rx counters to 0 */
34762306a36Sopenharmony_ci	bmwrite(dev, FRCNT, 0);
34862306a36Sopenharmony_ci	bmwrite(dev, LECNT, 0);
34962306a36Sopenharmony_ci	bmwrite(dev, AECNT, 0);
35062306a36Sopenharmony_ci	bmwrite(dev, FECNT, 0);
35162306a36Sopenharmony_ci	bmwrite(dev, RXCV, 0);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* set tx fifo information */
35462306a36Sopenharmony_ci	bmwrite(dev, TXTH, 4);	/* 4 octets before tx starts */
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	bmwrite(dev, TXFIFOCSR, 0);	/* first disable txFIFO */
35762306a36Sopenharmony_ci	bmwrite(dev, TXFIFOCSR, TxFIFOEnable );
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/* set rx fifo information */
36062306a36Sopenharmony_ci	bmwrite(dev, RXFIFOCSR, 0);	/* first disable rxFIFO */
36162306a36Sopenharmony_ci	bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	//bmwrite(dev, TXCFG, TxMACEnable);	       	/* TxNeverGiveUp maybe later */
36462306a36Sopenharmony_ci	bmread(dev, STATUS);		/* read it just to clear it */
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* zero out the chip Hash Filter registers */
36762306a36Sopenharmony_ci	for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
36862306a36Sopenharmony_ci	bmwrite(dev, BHASH3, bp->hash_table_mask[0]); 	/* bits 15 - 0 */
36962306a36Sopenharmony_ci	bmwrite(dev, BHASH2, bp->hash_table_mask[1]); 	/* bits 31 - 16 */
37062306a36Sopenharmony_ci	bmwrite(dev, BHASH1, bp->hash_table_mask[2]); 	/* bits 47 - 32 */
37162306a36Sopenharmony_ci	bmwrite(dev, BHASH0, bp->hash_table_mask[3]); 	/* bits 63 - 48 */
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	pWord16 = (const unsigned short *)dev->dev_addr;
37462306a36Sopenharmony_ci	bmwrite(dev, MADD0, *pWord16++);
37562306a36Sopenharmony_ci	bmwrite(dev, MADD1, *pWord16++);
37662306a36Sopenharmony_ci	bmwrite(dev, MADD2, *pWord16);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	bmwrite(dev, INTDISABLE, EnableNormal);
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci#if 0
38462306a36Sopenharmony_cistatic void
38562306a36Sopenharmony_cibmac_disable_interrupts(struct net_device *dev)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	bmwrite(dev, INTDISABLE, DisableAll);
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic void
39162306a36Sopenharmony_cibmac_enable_interrupts(struct net_device *dev)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	bmwrite(dev, INTDISABLE, EnableNormal);
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci#endif
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic void
39962306a36Sopenharmony_cibmac_start_chip(struct net_device *dev)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
40262306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
40362306a36Sopenharmony_ci	unsigned short	oldConfig;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* enable rx dma channel */
40662306a36Sopenharmony_ci	dbdma_continue(rd);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	oldConfig = bmread(dev, TXCFG);
40962306a36Sopenharmony_ci	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* turn on rx plus any other bits already on (promiscuous possibly) */
41262306a36Sopenharmony_ci	oldConfig = bmread(dev, RXCFG);
41362306a36Sopenharmony_ci	bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
41462306a36Sopenharmony_ci	udelay(20000);
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic void
41862306a36Sopenharmony_cibmac_init_phy(struct net_device *dev)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	unsigned int addr;
42162306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	printk(KERN_DEBUG "phy registers:");
42462306a36Sopenharmony_ci	for (addr = 0; addr < 32; ++addr) {
42562306a36Sopenharmony_ci		if ((addr & 7) == 0)
42662306a36Sopenharmony_ci			printk(KERN_DEBUG);
42762306a36Sopenharmony_ci		printk(KERN_CONT " %.4x", bmac_mif_read(dev, addr));
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci	printk(KERN_CONT "\n");
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	if (bp->is_bmac_plus) {
43262306a36Sopenharmony_ci		unsigned int capable, ctrl;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		ctrl = bmac_mif_read(dev, 0);
43562306a36Sopenharmony_ci		capable = ((bmac_mif_read(dev, 1) & 0xf800) >> 6) | 1;
43662306a36Sopenharmony_ci		if (bmac_mif_read(dev, 4) != capable ||
43762306a36Sopenharmony_ci		    (ctrl & 0x1000) == 0) {
43862306a36Sopenharmony_ci			bmac_mif_write(dev, 4, capable);
43962306a36Sopenharmony_ci			bmac_mif_write(dev, 0, 0x1200);
44062306a36Sopenharmony_ci		} else
44162306a36Sopenharmony_ci			bmac_mif_write(dev, 0, 0x1000);
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic void bmac_init_chip(struct net_device *dev)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	bmac_init_phy(dev);
44862306a36Sopenharmony_ci	bmac_init_registers(dev);
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci#ifdef CONFIG_PM
45262306a36Sopenharmony_cistatic int bmac_suspend(struct macio_dev *mdev, pm_message_t state)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct net_device* dev = macio_get_drvdata(mdev);
45562306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
45662306a36Sopenharmony_ci	unsigned long flags;
45762306a36Sopenharmony_ci	unsigned short config;
45862306a36Sopenharmony_ci	int i;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	netif_device_detach(dev);
46162306a36Sopenharmony_ci	/* prolly should wait for dma to finish & turn off the chip */
46262306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
46362306a36Sopenharmony_ci	if (bp->timeout_active) {
46462306a36Sopenharmony_ci		del_timer(&bp->tx_timeout);
46562306a36Sopenharmony_ci		bp->timeout_active = 0;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci	disable_irq(dev->irq);
46862306a36Sopenharmony_ci	disable_irq(bp->tx_dma_intr);
46962306a36Sopenharmony_ci	disable_irq(bp->rx_dma_intr);
47062306a36Sopenharmony_ci	bp->sleeping = 1;
47162306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
47262306a36Sopenharmony_ci	if (bp->opened) {
47362306a36Sopenharmony_ci		volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
47462306a36Sopenharmony_ci		volatile struct dbdma_regs __iomem *td = bp->tx_dma;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci		config = bmread(dev, RXCFG);
47762306a36Sopenharmony_ci		bmwrite(dev, RXCFG, (config & ~RxMACEnable));
47862306a36Sopenharmony_ci		config = bmread(dev, TXCFG);
47962306a36Sopenharmony_ci		bmwrite(dev, TXCFG, (config & ~TxMACEnable));
48062306a36Sopenharmony_ci		bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
48162306a36Sopenharmony_ci		/* disable rx and tx dma */
48262306a36Sopenharmony_ci		rd->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
48362306a36Sopenharmony_ci		td->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
48462306a36Sopenharmony_ci		/* free some skb's */
48562306a36Sopenharmony_ci		for (i=0; i<N_RX_RING; i++) {
48662306a36Sopenharmony_ci			if (bp->rx_bufs[i] != NULL) {
48762306a36Sopenharmony_ci				dev_kfree_skb(bp->rx_bufs[i]);
48862306a36Sopenharmony_ci				bp->rx_bufs[i] = NULL;
48962306a36Sopenharmony_ci			}
49062306a36Sopenharmony_ci		}
49162306a36Sopenharmony_ci		for (i = 0; i<N_TX_RING; i++) {
49262306a36Sopenharmony_ci			if (bp->tx_bufs[i] != NULL) {
49362306a36Sopenharmony_ci		       		dev_kfree_skb(bp->tx_bufs[i]);
49462306a36Sopenharmony_ci	       			bp->tx_bufs[i] = NULL;
49562306a36Sopenharmony_ci		       	}
49662306a36Sopenharmony_ci		}
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
49962306a36Sopenharmony_ci	return 0;
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic int bmac_resume(struct macio_dev *mdev)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	struct net_device* dev = macio_get_drvdata(mdev);
50562306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/* see if this is enough */
50862306a36Sopenharmony_ci	if (bp->opened)
50962306a36Sopenharmony_ci		bmac_reset_and_enable(dev);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	enable_irq(dev->irq);
51262306a36Sopenharmony_ci	enable_irq(bp->tx_dma_intr);
51362306a36Sopenharmony_ci	enable_irq(bp->rx_dma_intr);
51462306a36Sopenharmony_ci	netif_device_attach(dev);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	return 0;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci#endif /* CONFIG_PM */
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic int bmac_set_address(struct net_device *dev, void *addr)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
52362306a36Sopenharmony_ci	const unsigned short *pWord16;
52462306a36Sopenharmony_ci	unsigned long flags;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	XXDEBUG(("bmac: enter set_address\n"));
52762306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	eth_hw_addr_set(dev, addr);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* load up the hardware address */
53262306a36Sopenharmony_ci	pWord16  = (const unsigned short *)dev->dev_addr;
53362306a36Sopenharmony_ci	bmwrite(dev, MADD0, *pWord16++);
53462306a36Sopenharmony_ci	bmwrite(dev, MADD1, *pWord16++);
53562306a36Sopenharmony_ci	bmwrite(dev, MADD2, *pWord16);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
53862306a36Sopenharmony_ci	XXDEBUG(("bmac: exit set_address\n"));
53962306a36Sopenharmony_ci	return 0;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic inline void bmac_set_timeout(struct net_device *dev)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
54562306a36Sopenharmony_ci	unsigned long flags;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
54862306a36Sopenharmony_ci	if (bp->timeout_active)
54962306a36Sopenharmony_ci		del_timer(&bp->tx_timeout);
55062306a36Sopenharmony_ci	bp->tx_timeout.expires = jiffies + TX_TIMEOUT;
55162306a36Sopenharmony_ci	add_timer(&bp->tx_timeout);
55262306a36Sopenharmony_ci	bp->timeout_active = 1;
55362306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic void
55762306a36Sopenharmony_cibmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	void *vaddr;
56062306a36Sopenharmony_ci	unsigned long baddr;
56162306a36Sopenharmony_ci	unsigned long len;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	len = skb->len;
56462306a36Sopenharmony_ci	vaddr = skb->data;
56562306a36Sopenharmony_ci	baddr = virt_to_bus(vaddr);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	dbdma_setcmd(cp, (OUTPUT_LAST | INTR_ALWAYS | WAIT_IFCLR), len, baddr, 0);
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic void
57162306a36Sopenharmony_cibmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	unsigned char *addr = skb? skb->data: bmac_emergency_rxbuf;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN,
57662306a36Sopenharmony_ci		     virt_to_bus(addr), 0);
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cistatic void
58062306a36Sopenharmony_cibmac_init_tx_ring(struct bmac_data *bp)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	memset((char *)bp->tx_cmds, 0, (N_TX_RING+1) * sizeof(struct dbdma_cmd));
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	bp->tx_empty = 0;
58762306a36Sopenharmony_ci	bp->tx_fill = 0;
58862306a36Sopenharmony_ci	bp->tx_fullup = 0;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	/* put a branch at the end of the tx command list */
59162306a36Sopenharmony_ci	dbdma_setcmd(&bp->tx_cmds[N_TX_RING],
59262306a36Sopenharmony_ci		     (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->tx_cmds));
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/* reset tx dma */
59562306a36Sopenharmony_ci	dbdma_reset(td);
59662306a36Sopenharmony_ci	out_le32(&td->wait_sel, 0x00200020);
59762306a36Sopenharmony_ci	out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds));
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic int
60162306a36Sopenharmony_cibmac_init_rx_ring(struct net_device *dev)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
60462306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
60562306a36Sopenharmony_ci	int i;
60662306a36Sopenharmony_ci	struct sk_buff *skb;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/* initialize list of sk_buffs for receiving and set up recv dma */
60962306a36Sopenharmony_ci	memset((char *)bp->rx_cmds, 0,
61062306a36Sopenharmony_ci	       (N_RX_RING + 1) * sizeof(struct dbdma_cmd));
61162306a36Sopenharmony_ci	for (i = 0; i < N_RX_RING; i++) {
61262306a36Sopenharmony_ci		if ((skb = bp->rx_bufs[i]) == NULL) {
61362306a36Sopenharmony_ci			bp->rx_bufs[i] = skb = netdev_alloc_skb(dev, RX_BUFLEN + 2);
61462306a36Sopenharmony_ci			if (skb != NULL)
61562306a36Sopenharmony_ci				skb_reserve(skb, 2);
61662306a36Sopenharmony_ci		}
61762306a36Sopenharmony_ci		bmac_construct_rxbuff(skb, &bp->rx_cmds[i]);
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	bp->rx_empty = 0;
62162306a36Sopenharmony_ci	bp->rx_fill = i;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	/* Put a branch back to the beginning of the receive command list */
62462306a36Sopenharmony_ci	dbdma_setcmd(&bp->rx_cmds[N_RX_RING],
62562306a36Sopenharmony_ci		     (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->rx_cmds));
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	/* start rx dma */
62862306a36Sopenharmony_ci	dbdma_reset(rd);
62962306a36Sopenharmony_ci	out_le32(&rd->cmdptr, virt_to_bus(bp->rx_cmds));
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return 1;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
63862306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
63962306a36Sopenharmony_ci	int i;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	/* see if there's a free slot in the tx ring */
64262306a36Sopenharmony_ci	/* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */
64362306a36Sopenharmony_ci	/* 	     bp->tx_empty, bp->tx_fill)); */
64462306a36Sopenharmony_ci	i = bp->tx_fill + 1;
64562306a36Sopenharmony_ci	if (i >= N_TX_RING)
64662306a36Sopenharmony_ci		i = 0;
64762306a36Sopenharmony_ci	if (i == bp->tx_empty) {
64862306a36Sopenharmony_ci		netif_stop_queue(dev);
64962306a36Sopenharmony_ci		bp->tx_fullup = 1;
65062306a36Sopenharmony_ci		XXDEBUG(("bmac_transmit_packet: tx ring full\n"));
65162306a36Sopenharmony_ci		return -1;		/* can't take it at the moment */
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	dbdma_setcmd(&bp->tx_cmds[i], DBDMA_STOP, 0, 0, 0);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill]);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	bp->tx_bufs[bp->tx_fill] = skb;
65962306a36Sopenharmony_ci	bp->tx_fill = i;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	dev->stats.tx_bytes += skb->len;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	dbdma_continue(td);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	return 0;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic int rxintcount;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic irqreturn_t bmac_rxdma_intr(int irq, void *dev_id)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	struct net_device *dev = (struct net_device *) dev_id;
67362306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
67462306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
67562306a36Sopenharmony_ci	volatile struct dbdma_cmd *cp;
67662306a36Sopenharmony_ci	int i, nb, stat;
67762306a36Sopenharmony_ci	struct sk_buff *skb;
67862306a36Sopenharmony_ci	unsigned int residual;
67962306a36Sopenharmony_ci	int last;
68062306a36Sopenharmony_ci	unsigned long flags;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	if (++rxintcount < 10) {
68562306a36Sopenharmony_ci		XXDEBUG(("bmac_rxdma_intr\n"));
68662306a36Sopenharmony_ci	}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	last = -1;
68962306a36Sopenharmony_ci	i = bp->rx_empty;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	while (1) {
69262306a36Sopenharmony_ci		cp = &bp->rx_cmds[i];
69362306a36Sopenharmony_ci		stat = le16_to_cpu(cp->xfer_status);
69462306a36Sopenharmony_ci		residual = le16_to_cpu(cp->res_count);
69562306a36Sopenharmony_ci		if ((stat & ACTIVE) == 0)
69662306a36Sopenharmony_ci			break;
69762306a36Sopenharmony_ci		nb = RX_BUFLEN - residual - 2;
69862306a36Sopenharmony_ci		if (nb < (ETHERMINPACKET - ETHERCRC)) {
69962306a36Sopenharmony_ci			skb = NULL;
70062306a36Sopenharmony_ci			dev->stats.rx_length_errors++;
70162306a36Sopenharmony_ci			dev->stats.rx_errors++;
70262306a36Sopenharmony_ci		} else {
70362306a36Sopenharmony_ci			skb = bp->rx_bufs[i];
70462306a36Sopenharmony_ci			bp->rx_bufs[i] = NULL;
70562306a36Sopenharmony_ci		}
70662306a36Sopenharmony_ci		if (skb != NULL) {
70762306a36Sopenharmony_ci			nb -= ETHERCRC;
70862306a36Sopenharmony_ci			skb_put(skb, nb);
70962306a36Sopenharmony_ci			skb->protocol = eth_type_trans(skb, dev);
71062306a36Sopenharmony_ci			netif_rx(skb);
71162306a36Sopenharmony_ci			++dev->stats.rx_packets;
71262306a36Sopenharmony_ci			dev->stats.rx_bytes += nb;
71362306a36Sopenharmony_ci		} else {
71462306a36Sopenharmony_ci			++dev->stats.rx_dropped;
71562306a36Sopenharmony_ci		}
71662306a36Sopenharmony_ci		if ((skb = bp->rx_bufs[i]) == NULL) {
71762306a36Sopenharmony_ci			bp->rx_bufs[i] = skb = netdev_alloc_skb(dev, RX_BUFLEN + 2);
71862306a36Sopenharmony_ci			if (skb != NULL)
71962306a36Sopenharmony_ci				skb_reserve(bp->rx_bufs[i], 2);
72062306a36Sopenharmony_ci		}
72162306a36Sopenharmony_ci		bmac_construct_rxbuff(skb, &bp->rx_cmds[i]);
72262306a36Sopenharmony_ci		cp->res_count = cpu_to_le16(0);
72362306a36Sopenharmony_ci		cp->xfer_status = cpu_to_le16(0);
72462306a36Sopenharmony_ci		last = i;
72562306a36Sopenharmony_ci		if (++i >= N_RX_RING) i = 0;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (last != -1) {
72962306a36Sopenharmony_ci		bp->rx_fill = last;
73062306a36Sopenharmony_ci		bp->rx_empty = i;
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	dbdma_continue(rd);
73462306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (rxintcount < 10) {
73762306a36Sopenharmony_ci		XXDEBUG(("bmac_rxdma_intr done\n"));
73862306a36Sopenharmony_ci	}
73962306a36Sopenharmony_ci	return IRQ_HANDLED;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic int txintcount;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_cistatic irqreturn_t bmac_txdma_intr(int irq, void *dev_id)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	struct net_device *dev = (struct net_device *) dev_id;
74762306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
74862306a36Sopenharmony_ci	volatile struct dbdma_cmd *cp;
74962306a36Sopenharmony_ci	int stat;
75062306a36Sopenharmony_ci	unsigned long flags;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	if (txintcount++ < 10) {
75562306a36Sopenharmony_ci		XXDEBUG(("bmac_txdma_intr\n"));
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/*     del_timer(&bp->tx_timeout); */
75962306a36Sopenharmony_ci	/*     bp->timeout_active = 0; */
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	while (1) {
76262306a36Sopenharmony_ci		cp = &bp->tx_cmds[bp->tx_empty];
76362306a36Sopenharmony_ci		stat = le16_to_cpu(cp->xfer_status);
76462306a36Sopenharmony_ci		if (txintcount < 10) {
76562306a36Sopenharmony_ci			XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat));
76662306a36Sopenharmony_ci		}
76762306a36Sopenharmony_ci		if (!(stat & ACTIVE)) {
76862306a36Sopenharmony_ci			/*
76962306a36Sopenharmony_ci			 * status field might not have been filled by DBDMA
77062306a36Sopenharmony_ci			 */
77162306a36Sopenharmony_ci			if (cp == bus_to_virt(in_le32(&bp->tx_dma->cmdptr)))
77262306a36Sopenharmony_ci				break;
77362306a36Sopenharmony_ci		}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci		if (bp->tx_bufs[bp->tx_empty]) {
77662306a36Sopenharmony_ci			++dev->stats.tx_packets;
77762306a36Sopenharmony_ci			dev_consume_skb_irq(bp->tx_bufs[bp->tx_empty]);
77862306a36Sopenharmony_ci		}
77962306a36Sopenharmony_ci		bp->tx_bufs[bp->tx_empty] = NULL;
78062306a36Sopenharmony_ci		bp->tx_fullup = 0;
78162306a36Sopenharmony_ci		netif_wake_queue(dev);
78262306a36Sopenharmony_ci		if (++bp->tx_empty >= N_TX_RING)
78362306a36Sopenharmony_ci			bp->tx_empty = 0;
78462306a36Sopenharmony_ci		if (bp->tx_empty == bp->tx_fill)
78562306a36Sopenharmony_ci			break;
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	if (txintcount < 10) {
79162306a36Sopenharmony_ci		XXDEBUG(("bmac_txdma_intr done->bmac_start\n"));
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	bmac_start(dev);
79562306a36Sopenharmony_ci	return IRQ_HANDLED;
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci#ifndef SUNHME_MULTICAST
79962306a36Sopenharmony_ci/* Real fast bit-reversal algorithm, 6-bit values */
80062306a36Sopenharmony_cistatic int reverse6[64] = {
80162306a36Sopenharmony_ci	0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38,
80262306a36Sopenharmony_ci	0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c,
80362306a36Sopenharmony_ci	0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a,
80462306a36Sopenharmony_ci	0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e,
80562306a36Sopenharmony_ci	0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39,
80662306a36Sopenharmony_ci	0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d,
80762306a36Sopenharmony_ci	0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b,
80862306a36Sopenharmony_ci	0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f
80962306a36Sopenharmony_ci};
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_cistatic unsigned int
81262306a36Sopenharmony_cicrc416(unsigned int curval, unsigned short nxtval)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	unsigned int counter, cur = curval, next = nxtval;
81562306a36Sopenharmony_ci	int high_crc_set, low_data_set;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/* Swap bytes */
81862306a36Sopenharmony_ci	next = ((next & 0x00FF) << 8) | (next >> 8);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* Compute bit-by-bit */
82162306a36Sopenharmony_ci	for (counter = 0; counter < 16; ++counter) {
82262306a36Sopenharmony_ci		/* is high CRC bit set? */
82362306a36Sopenharmony_ci		if ((cur & 0x80000000) == 0) high_crc_set = 0;
82462306a36Sopenharmony_ci		else high_crc_set = 1;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci		cur = cur << 1;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci		if ((next & 0x0001) == 0) low_data_set = 0;
82962306a36Sopenharmony_ci		else low_data_set = 1;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci		next = next >> 1;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci		/* do the XOR */
83462306a36Sopenharmony_ci		if (high_crc_set ^ low_data_set) cur = cur ^ CRC32_POLY_BE;
83562306a36Sopenharmony_ci	}
83662306a36Sopenharmony_ci	return cur;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic unsigned int
84062306a36Sopenharmony_cibmac_crc(unsigned short *address)
84162306a36Sopenharmony_ci{
84262306a36Sopenharmony_ci	unsigned int newcrc;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2]));
84562306a36Sopenharmony_ci	newcrc = crc416(0xffffffff, *address);	/* address bits 47 - 32 */
84662306a36Sopenharmony_ci	newcrc = crc416(newcrc, address[1]);	/* address bits 31 - 16 */
84762306a36Sopenharmony_ci	newcrc = crc416(newcrc, address[2]);	/* address bits 15 - 0  */
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	return(newcrc);
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci/*
85362306a36Sopenharmony_ci * Add requested mcast addr to BMac's hash table filter.
85462306a36Sopenharmony_ci *
85562306a36Sopenharmony_ci */
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistatic void
85862306a36Sopenharmony_cibmac_addhash(struct bmac_data *bp, unsigned char *addr)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	unsigned int	 crc;
86162306a36Sopenharmony_ci	unsigned short	 mask;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	if (!(*addr)) return;
86462306a36Sopenharmony_ci	crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
86562306a36Sopenharmony_ci	crc = reverse6[crc];	/* Hyperfast bit-reversing algorithm */
86662306a36Sopenharmony_ci	if (bp->hash_use_count[crc]++) return; /* This bit is already set */
86762306a36Sopenharmony_ci	mask = crc % 16;
86862306a36Sopenharmony_ci	mask = (unsigned char)1 << mask;
86962306a36Sopenharmony_ci	bp->hash_use_count[crc/16] |= mask;
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_cistatic void
87362306a36Sopenharmony_cibmac_removehash(struct bmac_data *bp, unsigned char *addr)
87462306a36Sopenharmony_ci{
87562306a36Sopenharmony_ci	unsigned int crc;
87662306a36Sopenharmony_ci	unsigned char mask;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/* Now, delete the address from the filter copy, as indicated */
87962306a36Sopenharmony_ci	crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
88062306a36Sopenharmony_ci	crc = reverse6[crc];	/* Hyperfast bit-reversing algorithm */
88162306a36Sopenharmony_ci	if (bp->hash_use_count[crc] == 0) return; /* That bit wasn't in use! */
88262306a36Sopenharmony_ci	if (--bp->hash_use_count[crc]) return; /* That bit is still in use */
88362306a36Sopenharmony_ci	mask = crc % 16;
88462306a36Sopenharmony_ci	mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */
88562306a36Sopenharmony_ci	bp->hash_table_mask[crc/16] &= mask;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci/*
88962306a36Sopenharmony_ci * Sync the adapter with the software copy of the multicast mask
89062306a36Sopenharmony_ci *  (logical address filter).
89162306a36Sopenharmony_ci */
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cistatic void
89462306a36Sopenharmony_cibmac_rx_off(struct net_device *dev)
89562306a36Sopenharmony_ci{
89662306a36Sopenharmony_ci	unsigned short rx_cfg;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	rx_cfg = bmread(dev, RXCFG);
89962306a36Sopenharmony_ci	rx_cfg &= ~RxMACEnable;
90062306a36Sopenharmony_ci	bmwrite(dev, RXCFG, rx_cfg);
90162306a36Sopenharmony_ci	do {
90262306a36Sopenharmony_ci		rx_cfg = bmread(dev, RXCFG);
90362306a36Sopenharmony_ci	}  while (rx_cfg & RxMACEnable);
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ciunsigned short
90762306a36Sopenharmony_cibmac_rx_on(struct net_device *dev, int hash_enable, int promisc_enable)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	unsigned short rx_cfg;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	rx_cfg = bmread(dev, RXCFG);
91262306a36Sopenharmony_ci	rx_cfg |= RxMACEnable;
91362306a36Sopenharmony_ci	if (hash_enable) rx_cfg |= RxHashFilterEnable;
91462306a36Sopenharmony_ci	else rx_cfg &= ~RxHashFilterEnable;
91562306a36Sopenharmony_ci	if (promisc_enable) rx_cfg |= RxPromiscEnable;
91662306a36Sopenharmony_ci	else rx_cfg &= ~RxPromiscEnable;
91762306a36Sopenharmony_ci	bmwrite(dev, RXRST, RxResetValue);
91862306a36Sopenharmony_ci	bmwrite(dev, RXFIFOCSR, 0);	/* first disable rxFIFO */
91962306a36Sopenharmony_ci	bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
92062306a36Sopenharmony_ci	bmwrite(dev, RXCFG, rx_cfg );
92162306a36Sopenharmony_ci	return rx_cfg;
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic void
92562306a36Sopenharmony_cibmac_update_hash_table_mask(struct net_device *dev, struct bmac_data *bp)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */
92862306a36Sopenharmony_ci	bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */
92962306a36Sopenharmony_ci	bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */
93062306a36Sopenharmony_ci	bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci#if 0
93462306a36Sopenharmony_cistatic void
93562306a36Sopenharmony_cibmac_add_multi(struct net_device *dev,
93662306a36Sopenharmony_ci	       struct bmac_data *bp, unsigned char *addr)
93762306a36Sopenharmony_ci{
93862306a36Sopenharmony_ci	/* XXDEBUG(("bmac: enter bmac_add_multi\n")); */
93962306a36Sopenharmony_ci	bmac_addhash(bp, addr);
94062306a36Sopenharmony_ci	bmac_rx_off(dev);
94162306a36Sopenharmony_ci	bmac_update_hash_table_mask(dev, bp);
94262306a36Sopenharmony_ci	bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
94362306a36Sopenharmony_ci	/* XXDEBUG(("bmac: exit bmac_add_multi\n")); */
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistatic void
94762306a36Sopenharmony_cibmac_remove_multi(struct net_device *dev,
94862306a36Sopenharmony_ci		  struct bmac_data *bp, unsigned char *addr)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	bmac_removehash(bp, addr);
95162306a36Sopenharmony_ci	bmac_rx_off(dev);
95262306a36Sopenharmony_ci	bmac_update_hash_table_mask(dev, bp);
95362306a36Sopenharmony_ci	bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci#endif
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci/* Set or clear the multicast filter for this adaptor.
95862306a36Sopenharmony_ci    num_addrs == -1	Promiscuous mode, receive all packets
95962306a36Sopenharmony_ci    num_addrs == 0	Normal mode, clear multicast list
96062306a36Sopenharmony_ci    num_addrs > 0	Multicast mode, receive normal and MC packets, and do
96162306a36Sopenharmony_ci			best-effort filtering.
96262306a36Sopenharmony_ci */
96362306a36Sopenharmony_cistatic void bmac_set_multicast(struct net_device *dev)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
96662306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
96762306a36Sopenharmony_ci	int num_addrs = netdev_mc_count(dev);
96862306a36Sopenharmony_ci	unsigned short rx_cfg;
96962306a36Sopenharmony_ci	int i;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	if (bp->sleeping)
97262306a36Sopenharmony_ci		return;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs));
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) {
97762306a36Sopenharmony_ci		for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff;
97862306a36Sopenharmony_ci		bmac_update_hash_table_mask(dev, bp);
97962306a36Sopenharmony_ci		rx_cfg = bmac_rx_on(dev, 1, 0);
98062306a36Sopenharmony_ci		XXDEBUG(("bmac: all multi, rx_cfg=%#08x\n"));
98162306a36Sopenharmony_ci	} else if ((dev->flags & IFF_PROMISC) || (num_addrs < 0)) {
98262306a36Sopenharmony_ci		rx_cfg = bmread(dev, RXCFG);
98362306a36Sopenharmony_ci		rx_cfg |= RxPromiscEnable;
98462306a36Sopenharmony_ci		bmwrite(dev, RXCFG, rx_cfg);
98562306a36Sopenharmony_ci		rx_cfg = bmac_rx_on(dev, 0, 1);
98662306a36Sopenharmony_ci		XXDEBUG(("bmac: promisc mode enabled, rx_cfg=%#08x\n", rx_cfg));
98762306a36Sopenharmony_ci	} else {
98862306a36Sopenharmony_ci		for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
98962306a36Sopenharmony_ci		for (i=0; i<64; i++) bp->hash_use_count[i] = 0;
99062306a36Sopenharmony_ci		if (num_addrs == 0) {
99162306a36Sopenharmony_ci			rx_cfg = bmac_rx_on(dev, 0, 0);
99262306a36Sopenharmony_ci			XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg));
99362306a36Sopenharmony_ci		} else {
99462306a36Sopenharmony_ci			netdev_for_each_mc_addr(ha, dev)
99562306a36Sopenharmony_ci				bmac_addhash(bp, ha->addr);
99662306a36Sopenharmony_ci			bmac_update_hash_table_mask(dev, bp);
99762306a36Sopenharmony_ci			rx_cfg = bmac_rx_on(dev, 1, 0);
99862306a36Sopenharmony_ci			XXDEBUG(("bmac: multi enabled, rx_cfg=%#08x\n", rx_cfg));
99962306a36Sopenharmony_ci		}
100062306a36Sopenharmony_ci	}
100162306a36Sopenharmony_ci	/* XXDEBUG(("bmac: exit bmac_set_multicast\n")); */
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci#else /* ifdef SUNHME_MULTICAST */
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci/* The version of set_multicast below was lifted from sunhme.c */
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_cistatic void bmac_set_multicast(struct net_device *dev)
100862306a36Sopenharmony_ci{
100962306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
101062306a36Sopenharmony_ci	unsigned short rx_cfg;
101162306a36Sopenharmony_ci	u32 crc;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) {
101462306a36Sopenharmony_ci		bmwrite(dev, BHASH0, 0xffff);
101562306a36Sopenharmony_ci		bmwrite(dev, BHASH1, 0xffff);
101662306a36Sopenharmony_ci		bmwrite(dev, BHASH2, 0xffff);
101762306a36Sopenharmony_ci		bmwrite(dev, BHASH3, 0xffff);
101862306a36Sopenharmony_ci	} else if(dev->flags & IFF_PROMISC) {
101962306a36Sopenharmony_ci		rx_cfg = bmread(dev, RXCFG);
102062306a36Sopenharmony_ci		rx_cfg |= RxPromiscEnable;
102162306a36Sopenharmony_ci		bmwrite(dev, RXCFG, rx_cfg);
102262306a36Sopenharmony_ci	} else {
102362306a36Sopenharmony_ci		u16 hash_table[4] = { 0 };
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci		rx_cfg = bmread(dev, RXCFG);
102662306a36Sopenharmony_ci		rx_cfg &= ~RxPromiscEnable;
102762306a36Sopenharmony_ci		bmwrite(dev, RXCFG, rx_cfg);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
103062306a36Sopenharmony_ci			crc = ether_crc_le(6, ha->addr);
103162306a36Sopenharmony_ci			crc >>= 26;
103262306a36Sopenharmony_ci			hash_table[crc >> 4] |= 1 << (crc & 0xf);
103362306a36Sopenharmony_ci		}
103462306a36Sopenharmony_ci		bmwrite(dev, BHASH0, hash_table[0]);
103562306a36Sopenharmony_ci		bmwrite(dev, BHASH1, hash_table[1]);
103662306a36Sopenharmony_ci		bmwrite(dev, BHASH2, hash_table[2]);
103762306a36Sopenharmony_ci		bmwrite(dev, BHASH3, hash_table[3]);
103862306a36Sopenharmony_ci	}
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ci#endif /* SUNHME_MULTICAST */
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_cistatic int miscintcount;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_cistatic irqreturn_t bmac_misc_intr(int irq, void *dev_id)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	struct net_device *dev = (struct net_device *) dev_id;
104762306a36Sopenharmony_ci	unsigned int status = bmread(dev, STATUS);
104862306a36Sopenharmony_ci	if (miscintcount++ < 10) {
104962306a36Sopenharmony_ci		XXDEBUG(("bmac_misc_intr\n"));
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci	/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
105262306a36Sopenharmony_ci	/*     bmac_txdma_intr_inner(irq, dev_id); */
105362306a36Sopenharmony_ci	/*   if (status & FrameReceived) dev->stats.rx_dropped++; */
105462306a36Sopenharmony_ci	if (status & RxErrorMask) dev->stats.rx_errors++;
105562306a36Sopenharmony_ci	if (status & RxCRCCntExp) dev->stats.rx_crc_errors++;
105662306a36Sopenharmony_ci	if (status & RxLenCntExp) dev->stats.rx_length_errors++;
105762306a36Sopenharmony_ci	if (status & RxOverFlow) dev->stats.rx_over_errors++;
105862306a36Sopenharmony_ci	if (status & RxAlignCntExp) dev->stats.rx_frame_errors++;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	/*   if (status & FrameSent) dev->stats.tx_dropped++; */
106162306a36Sopenharmony_ci	if (status & TxErrorMask) dev->stats.tx_errors++;
106262306a36Sopenharmony_ci	if (status & TxUnderrun) dev->stats.tx_fifo_errors++;
106362306a36Sopenharmony_ci	if (status & TxNormalCollExp) dev->stats.collisions++;
106462306a36Sopenharmony_ci	return IRQ_HANDLED;
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci/*
106862306a36Sopenharmony_ci * Procedure for reading EEPROM
106962306a36Sopenharmony_ci */
107062306a36Sopenharmony_ci#define SROMAddressLength	5
107162306a36Sopenharmony_ci#define DataInOn		0x0008
107262306a36Sopenharmony_ci#define DataInOff		0x0000
107362306a36Sopenharmony_ci#define Clk			0x0002
107462306a36Sopenharmony_ci#define ChipSelect		0x0001
107562306a36Sopenharmony_ci#define SDIShiftCount		3
107662306a36Sopenharmony_ci#define SD0ShiftCount		2
107762306a36Sopenharmony_ci#define	DelayValue		1000	/* number of microseconds */
107862306a36Sopenharmony_ci#define SROMStartOffset		10	/* this is in words */
107962306a36Sopenharmony_ci#define SROMReadCount		3	/* number of words to read from SROM */
108062306a36Sopenharmony_ci#define SROMAddressBits		6
108162306a36Sopenharmony_ci#define EnetAddressOffset	20
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_cistatic unsigned char
108462306a36Sopenharmony_cibmac_clock_out_bit(struct net_device *dev)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	unsigned short         data;
108762306a36Sopenharmony_ci	unsigned short         val;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	bmwrite(dev, SROMCSR, ChipSelect | Clk);
109062306a36Sopenharmony_ci	udelay(DelayValue);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	data = bmread(dev, SROMCSR);
109362306a36Sopenharmony_ci	udelay(DelayValue);
109462306a36Sopenharmony_ci	val = (data >> SD0ShiftCount) & 1;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	bmwrite(dev, SROMCSR, ChipSelect);
109762306a36Sopenharmony_ci	udelay(DelayValue);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	return val;
110062306a36Sopenharmony_ci}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_cistatic void
110362306a36Sopenharmony_cibmac_clock_in_bit(struct net_device *dev, unsigned int val)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	unsigned short data;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	if (val != 0 && val != 1) return;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	data = (val << SDIShiftCount);
111062306a36Sopenharmony_ci	bmwrite(dev, SROMCSR, data | ChipSelect  );
111162306a36Sopenharmony_ci	udelay(DelayValue);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	bmwrite(dev, SROMCSR, data | ChipSelect | Clk );
111462306a36Sopenharmony_ci	udelay(DelayValue);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	bmwrite(dev, SROMCSR, data | ChipSelect);
111762306a36Sopenharmony_ci	udelay(DelayValue);
111862306a36Sopenharmony_ci}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_cistatic void
112162306a36Sopenharmony_cireset_and_select_srom(struct net_device *dev)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	/* first reset */
112462306a36Sopenharmony_ci	bmwrite(dev, SROMCSR, 0);
112562306a36Sopenharmony_ci	udelay(DelayValue);
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	/* send it the read command (110) */
112862306a36Sopenharmony_ci	bmac_clock_in_bit(dev, 1);
112962306a36Sopenharmony_ci	bmac_clock_in_bit(dev, 1);
113062306a36Sopenharmony_ci	bmac_clock_in_bit(dev, 0);
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic unsigned short
113462306a36Sopenharmony_ciread_srom(struct net_device *dev, unsigned int addr, unsigned int addr_len)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	unsigned short data, val;
113762306a36Sopenharmony_ci	int i;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	/* send out the address we want to read from */
114062306a36Sopenharmony_ci	for (i = 0; i < addr_len; i++)	{
114162306a36Sopenharmony_ci		val = addr >> (addr_len-i-1);
114262306a36Sopenharmony_ci		bmac_clock_in_bit(dev, val & 1);
114362306a36Sopenharmony_ci	}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	/* Now read in the 16-bit data */
114662306a36Sopenharmony_ci	data = 0;
114762306a36Sopenharmony_ci	for (i = 0; i < 16; i++)	{
114862306a36Sopenharmony_ci		val = bmac_clock_out_bit(dev);
114962306a36Sopenharmony_ci		data <<= 1;
115062306a36Sopenharmony_ci		data |= val;
115162306a36Sopenharmony_ci	}
115262306a36Sopenharmony_ci	bmwrite(dev, SROMCSR, 0);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	return data;
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci/*
115862306a36Sopenharmony_ci * It looks like Cogent and SMC use different methods for calculating
115962306a36Sopenharmony_ci * checksums. What a pain..
116062306a36Sopenharmony_ci */
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_cistatic int
116362306a36Sopenharmony_cibmac_verify_checksum(struct net_device *dev)
116462306a36Sopenharmony_ci{
116562306a36Sopenharmony_ci	unsigned short data, storedCS;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	reset_and_select_srom(dev);
116862306a36Sopenharmony_ci	data = read_srom(dev, 3, SROMAddressBits);
116962306a36Sopenharmony_ci	storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	return 0;
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_cistatic void
117662306a36Sopenharmony_cibmac_get_station_address(struct net_device *dev, unsigned char *ea)
117762306a36Sopenharmony_ci{
117862306a36Sopenharmony_ci	int i;
117962306a36Sopenharmony_ci	unsigned short data;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	for (i = 0; i < 3; i++)
118262306a36Sopenharmony_ci		{
118362306a36Sopenharmony_ci			reset_and_select_srom(dev);
118462306a36Sopenharmony_ci			data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
118562306a36Sopenharmony_ci			ea[2*i]   = bitrev8(data & 0x0ff);
118662306a36Sopenharmony_ci			ea[2*i+1] = bitrev8((data >> 8) & 0x0ff);
118762306a36Sopenharmony_ci		}
118862306a36Sopenharmony_ci}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_cistatic void bmac_reset_and_enable(struct net_device *dev)
119162306a36Sopenharmony_ci{
119262306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
119362306a36Sopenharmony_ci	unsigned long flags;
119462306a36Sopenharmony_ci	struct sk_buff *skb;
119562306a36Sopenharmony_ci	unsigned char *data;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
119862306a36Sopenharmony_ci	bmac_enable_and_reset_chip(dev);
119962306a36Sopenharmony_ci	bmac_init_tx_ring(bp);
120062306a36Sopenharmony_ci	bmac_init_rx_ring(dev);
120162306a36Sopenharmony_ci	bmac_init_chip(dev);
120262306a36Sopenharmony_ci	bmac_start_chip(dev);
120362306a36Sopenharmony_ci	bmwrite(dev, INTDISABLE, EnableNormal);
120462306a36Sopenharmony_ci	bp->sleeping = 0;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	/*
120762306a36Sopenharmony_ci	 * It seems that the bmac can't receive until it's transmitted
120862306a36Sopenharmony_ci	 * a packet.  So we give it a dummy packet to transmit.
120962306a36Sopenharmony_ci	 */
121062306a36Sopenharmony_ci	skb = netdev_alloc_skb(dev, ETHERMINPACKET);
121162306a36Sopenharmony_ci	if (skb != NULL) {
121262306a36Sopenharmony_ci		data = skb_put_zero(skb, ETHERMINPACKET);
121362306a36Sopenharmony_ci		memcpy(data, dev->dev_addr, ETH_ALEN);
121462306a36Sopenharmony_ci		memcpy(data + ETH_ALEN, dev->dev_addr, ETH_ALEN);
121562306a36Sopenharmony_ci		bmac_transmit_packet(skb, dev);
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_cistatic const struct ethtool_ops bmac_ethtool_ops = {
122162306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
122262306a36Sopenharmony_ci};
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_cistatic const struct net_device_ops bmac_netdev_ops = {
122562306a36Sopenharmony_ci	.ndo_open		= bmac_open,
122662306a36Sopenharmony_ci	.ndo_stop		= bmac_close,
122762306a36Sopenharmony_ci	.ndo_start_xmit		= bmac_output,
122862306a36Sopenharmony_ci	.ndo_set_rx_mode	= bmac_set_multicast,
122962306a36Sopenharmony_ci	.ndo_set_mac_address	= bmac_set_address,
123062306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
123162306a36Sopenharmony_ci};
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_cistatic int bmac_probe(struct macio_dev *mdev, const struct of_device_id *match)
123462306a36Sopenharmony_ci{
123562306a36Sopenharmony_ci	int j, rev, ret;
123662306a36Sopenharmony_ci	struct bmac_data *bp;
123762306a36Sopenharmony_ci	const unsigned char *prop_addr;
123862306a36Sopenharmony_ci	unsigned char addr[6];
123962306a36Sopenharmony_ci	u8 macaddr[6];
124062306a36Sopenharmony_ci	struct net_device *dev;
124162306a36Sopenharmony_ci	int is_bmac_plus = ((int)match->data) != 0;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
124462306a36Sopenharmony_ci		printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
124562306a36Sopenharmony_ci		return -ENODEV;
124662306a36Sopenharmony_ci	}
124762306a36Sopenharmony_ci	prop_addr = of_get_property(macio_get_of_node(mdev),
124862306a36Sopenharmony_ci			"mac-address", NULL);
124962306a36Sopenharmony_ci	if (prop_addr == NULL) {
125062306a36Sopenharmony_ci		prop_addr = of_get_property(macio_get_of_node(mdev),
125162306a36Sopenharmony_ci				"local-mac-address", NULL);
125262306a36Sopenharmony_ci		if (prop_addr == NULL) {
125362306a36Sopenharmony_ci			printk(KERN_ERR "BMAC: Can't get mac-address\n");
125462306a36Sopenharmony_ci			return -ENODEV;
125562306a36Sopenharmony_ci		}
125662306a36Sopenharmony_ci	}
125762306a36Sopenharmony_ci	memcpy(addr, prop_addr, sizeof(addr));
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	dev = alloc_etherdev(PRIV_BYTES);
126062306a36Sopenharmony_ci	if (!dev)
126162306a36Sopenharmony_ci		return -ENOMEM;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	bp = netdev_priv(dev);
126462306a36Sopenharmony_ci	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
126562306a36Sopenharmony_ci	macio_set_drvdata(mdev, dev);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	bp->mdev = mdev;
126862306a36Sopenharmony_ci	spin_lock_init(&bp->lock);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	if (macio_request_resources(mdev, "bmac")) {
127162306a36Sopenharmony_ci		printk(KERN_ERR "BMAC: can't request IO resource !\n");
127262306a36Sopenharmony_ci		goto out_free;
127362306a36Sopenharmony_ci	}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	dev->base_addr = (unsigned long)
127662306a36Sopenharmony_ci		ioremap(macio_resource_start(mdev, 0), macio_resource_len(mdev, 0));
127762306a36Sopenharmony_ci	if (dev->base_addr == 0)
127862306a36Sopenharmony_ci		goto out_release;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	dev->irq = macio_irq(mdev, 0);
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	bmac_enable_and_reset_chip(dev);
128362306a36Sopenharmony_ci	bmwrite(dev, INTDISABLE, DisableAll);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	rev = addr[0] == 0 && addr[1] == 0xA0;
128662306a36Sopenharmony_ci	for (j = 0; j < 6; ++j)
128762306a36Sopenharmony_ci		macaddr[j] = rev ? bitrev8(addr[j]): addr[j];
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	eth_hw_addr_set(dev, macaddr);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	/* Enable chip without interrupts for now */
129262306a36Sopenharmony_ci	bmac_enable_and_reset_chip(dev);
129362306a36Sopenharmony_ci	bmwrite(dev, INTDISABLE, DisableAll);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	dev->netdev_ops = &bmac_netdev_ops;
129662306a36Sopenharmony_ci	dev->ethtool_ops = &bmac_ethtool_ops;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	bmac_get_station_address(dev, addr);
129962306a36Sopenharmony_ci	if (bmac_verify_checksum(dev) != 0)
130062306a36Sopenharmony_ci		goto err_out_iounmap;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	bp->is_bmac_plus = is_bmac_plus;
130362306a36Sopenharmony_ci	bp->tx_dma = ioremap(macio_resource_start(mdev, 1), macio_resource_len(mdev, 1));
130462306a36Sopenharmony_ci	if (!bp->tx_dma)
130562306a36Sopenharmony_ci		goto err_out_iounmap;
130662306a36Sopenharmony_ci	bp->tx_dma_intr = macio_irq(mdev, 1);
130762306a36Sopenharmony_ci	bp->rx_dma = ioremap(macio_resource_start(mdev, 2), macio_resource_len(mdev, 2));
130862306a36Sopenharmony_ci	if (!bp->rx_dma)
130962306a36Sopenharmony_ci		goto err_out_iounmap_tx;
131062306a36Sopenharmony_ci	bp->rx_dma_intr = macio_irq(mdev, 2);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
131362306a36Sopenharmony_ci	bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);
131662306a36Sopenharmony_ci	skb_queue_head_init(bp->queue);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	timer_setup(&bp->tx_timeout, bmac_tx_timeout, 0);
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	ret = request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev);
132162306a36Sopenharmony_ci	if (ret) {
132262306a36Sopenharmony_ci		printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
132362306a36Sopenharmony_ci		goto err_out_iounmap_rx;
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci	ret = request_irq(bp->tx_dma_intr, bmac_txdma_intr, 0, "BMAC-txdma", dev);
132662306a36Sopenharmony_ci	if (ret) {
132762306a36Sopenharmony_ci		printk(KERN_ERR "BMAC: can't get irq %d\n", bp->tx_dma_intr);
132862306a36Sopenharmony_ci		goto err_out_irq0;
132962306a36Sopenharmony_ci	}
133062306a36Sopenharmony_ci	ret = request_irq(bp->rx_dma_intr, bmac_rxdma_intr, 0, "BMAC-rxdma", dev);
133162306a36Sopenharmony_ci	if (ret) {
133262306a36Sopenharmony_ci		printk(KERN_ERR "BMAC: can't get irq %d\n", bp->rx_dma_intr);
133362306a36Sopenharmony_ci		goto err_out_irq1;
133462306a36Sopenharmony_ci	}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	/* Mask chip interrupts and disable chip, will be
133762306a36Sopenharmony_ci	 * re-enabled on open()
133862306a36Sopenharmony_ci	 */
133962306a36Sopenharmony_ci	disable_irq(dev->irq);
134062306a36Sopenharmony_ci	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	if (register_netdev(dev) != 0) {
134362306a36Sopenharmony_ci		printk(KERN_ERR "BMAC: Ethernet registration failed\n");
134462306a36Sopenharmony_ci		goto err_out_irq2;
134562306a36Sopenharmony_ci	}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	printk(KERN_INFO "%s: BMAC%s at %pM",
134862306a36Sopenharmony_ci	       dev->name, (is_bmac_plus ? "+" : ""), dev->dev_addr);
134962306a36Sopenharmony_ci	XXDEBUG((", base_addr=%#0lx", dev->base_addr));
135062306a36Sopenharmony_ci	printk("\n");
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	return 0;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_cierr_out_irq2:
135562306a36Sopenharmony_ci	free_irq(bp->rx_dma_intr, dev);
135662306a36Sopenharmony_cierr_out_irq1:
135762306a36Sopenharmony_ci	free_irq(bp->tx_dma_intr, dev);
135862306a36Sopenharmony_cierr_out_irq0:
135962306a36Sopenharmony_ci	free_irq(dev->irq, dev);
136062306a36Sopenharmony_cierr_out_iounmap_rx:
136162306a36Sopenharmony_ci	iounmap(bp->rx_dma);
136262306a36Sopenharmony_cierr_out_iounmap_tx:
136362306a36Sopenharmony_ci	iounmap(bp->tx_dma);
136462306a36Sopenharmony_cierr_out_iounmap:
136562306a36Sopenharmony_ci	iounmap((void __iomem *)dev->base_addr);
136662306a36Sopenharmony_ciout_release:
136762306a36Sopenharmony_ci	macio_release_resources(mdev);
136862306a36Sopenharmony_ciout_free:
136962306a36Sopenharmony_ci	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
137062306a36Sopenharmony_ci	free_netdev(dev);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	return -ENODEV;
137362306a36Sopenharmony_ci}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_cistatic int bmac_open(struct net_device *dev)
137662306a36Sopenharmony_ci{
137762306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
137862306a36Sopenharmony_ci	/* XXDEBUG(("bmac: enter open\n")); */
137962306a36Sopenharmony_ci	/* reset the chip */
138062306a36Sopenharmony_ci	bp->opened = 1;
138162306a36Sopenharmony_ci	bmac_reset_and_enable(dev);
138262306a36Sopenharmony_ci	enable_irq(dev->irq);
138362306a36Sopenharmony_ci	return 0;
138462306a36Sopenharmony_ci}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_cistatic int bmac_close(struct net_device *dev)
138762306a36Sopenharmony_ci{
138862306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
138962306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
139062306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
139162306a36Sopenharmony_ci	unsigned short config;
139262306a36Sopenharmony_ci	int i;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	bp->sleeping = 1;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	/* disable rx and tx */
139762306a36Sopenharmony_ci	config = bmread(dev, RXCFG);
139862306a36Sopenharmony_ci	bmwrite(dev, RXCFG, (config & ~RxMACEnable));
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	config = bmread(dev, TXCFG);
140162306a36Sopenharmony_ci	bmwrite(dev, TXCFG, (config & ~TxMACEnable));
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	/* disable rx and tx dma */
140662306a36Sopenharmony_ci	rd->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
140762306a36Sopenharmony_ci	td->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	/* free some skb's */
141062306a36Sopenharmony_ci	XXDEBUG(("bmac: free rx bufs\n"));
141162306a36Sopenharmony_ci	for (i=0; i<N_RX_RING; i++) {
141262306a36Sopenharmony_ci		if (bp->rx_bufs[i] != NULL) {
141362306a36Sopenharmony_ci			dev_kfree_skb(bp->rx_bufs[i]);
141462306a36Sopenharmony_ci			bp->rx_bufs[i] = NULL;
141562306a36Sopenharmony_ci		}
141662306a36Sopenharmony_ci	}
141762306a36Sopenharmony_ci	XXDEBUG(("bmac: free tx bufs\n"));
141862306a36Sopenharmony_ci	for (i = 0; i<N_TX_RING; i++) {
141962306a36Sopenharmony_ci		if (bp->tx_bufs[i] != NULL) {
142062306a36Sopenharmony_ci			dev_kfree_skb(bp->tx_bufs[i]);
142162306a36Sopenharmony_ci			bp->tx_bufs[i] = NULL;
142262306a36Sopenharmony_ci		}
142362306a36Sopenharmony_ci	}
142462306a36Sopenharmony_ci	XXDEBUG(("bmac: all bufs freed\n"));
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	bp->opened = 0;
142762306a36Sopenharmony_ci	disable_irq(dev->irq);
142862306a36Sopenharmony_ci	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	return 0;
143162306a36Sopenharmony_ci}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_cistatic void
143462306a36Sopenharmony_cibmac_start(struct net_device *dev)
143562306a36Sopenharmony_ci{
143662306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
143762306a36Sopenharmony_ci	int i;
143862306a36Sopenharmony_ci	struct sk_buff *skb;
143962306a36Sopenharmony_ci	unsigned long flags;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	if (bp->sleeping)
144262306a36Sopenharmony_ci		return;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
144562306a36Sopenharmony_ci	while (1) {
144662306a36Sopenharmony_ci		i = bp->tx_fill + 1;
144762306a36Sopenharmony_ci		if (i >= N_TX_RING)
144862306a36Sopenharmony_ci			i = 0;
144962306a36Sopenharmony_ci		if (i == bp->tx_empty)
145062306a36Sopenharmony_ci			break;
145162306a36Sopenharmony_ci		skb = skb_dequeue(bp->queue);
145262306a36Sopenharmony_ci		if (skb == NULL)
145362306a36Sopenharmony_ci			break;
145462306a36Sopenharmony_ci		bmac_transmit_packet(skb, dev);
145562306a36Sopenharmony_ci	}
145662306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_cistatic netdev_tx_t
146062306a36Sopenharmony_cibmac_output(struct sk_buff *skb, struct net_device *dev)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
146362306a36Sopenharmony_ci	skb_queue_tail(bp->queue, skb);
146462306a36Sopenharmony_ci	bmac_start(dev);
146562306a36Sopenharmony_ci	return NETDEV_TX_OK;
146662306a36Sopenharmony_ci}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_cistatic void bmac_tx_timeout(struct timer_list *t)
146962306a36Sopenharmony_ci{
147062306a36Sopenharmony_ci	struct bmac_data *bp = from_timer(bp, t, tx_timeout);
147162306a36Sopenharmony_ci	struct net_device *dev = macio_get_drvdata(bp->mdev);
147262306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *td = bp->tx_dma;
147362306a36Sopenharmony_ci	volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
147462306a36Sopenharmony_ci	volatile struct dbdma_cmd *cp;
147562306a36Sopenharmony_ci	unsigned long flags;
147662306a36Sopenharmony_ci	unsigned short config, oldConfig;
147762306a36Sopenharmony_ci	int i;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	XXDEBUG(("bmac: tx_timeout called\n"));
148062306a36Sopenharmony_ci	spin_lock_irqsave(&bp->lock, flags);
148162306a36Sopenharmony_ci	bp->timeout_active = 0;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	/* update various counters */
148462306a36Sopenharmony_ci/*     	bmac_handle_misc_intrs(bp, 0); */
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	cp = &bp->tx_cmds[bp->tx_empty];
148762306a36Sopenharmony_ci/*	XXDEBUG((KERN_DEBUG "bmac: tx dmastat=%x %x runt=%d pr=%x fs=%x fc=%x\n", */
148862306a36Sopenharmony_ci/* 	   le32_to_cpu(td->status), le16_to_cpu(cp->xfer_status), bp->tx_bad_runt, */
148962306a36Sopenharmony_ci/* 	   mb->pr, mb->xmtfs, mb->fifofc)); */
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	/* turn off both tx and rx and reset the chip */
149262306a36Sopenharmony_ci	config = bmread(dev, RXCFG);
149362306a36Sopenharmony_ci	bmwrite(dev, RXCFG, (config & ~RxMACEnable));
149462306a36Sopenharmony_ci	config = bmread(dev, TXCFG);
149562306a36Sopenharmony_ci	bmwrite(dev, TXCFG, (config & ~TxMACEnable));
149662306a36Sopenharmony_ci	out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
149762306a36Sopenharmony_ci	printk(KERN_ERR "bmac: transmit timeout - resetting\n");
149862306a36Sopenharmony_ci	bmac_enable_and_reset_chip(dev);
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	/* restart rx dma */
150162306a36Sopenharmony_ci	cp = bus_to_virt(le32_to_cpu(rd->cmdptr));
150262306a36Sopenharmony_ci	out_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
150362306a36Sopenharmony_ci	out_le16(&cp->xfer_status, 0);
150462306a36Sopenharmony_ci	out_le32(&rd->cmdptr, virt_to_bus(cp));
150562306a36Sopenharmony_ci	out_le32(&rd->control, DBDMA_SET(RUN|WAKE));
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	/* fix up the transmit side */
150862306a36Sopenharmony_ci	XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n",
150962306a36Sopenharmony_ci		 bp->tx_empty, bp->tx_fill, bp->tx_fullup));
151062306a36Sopenharmony_ci	i = bp->tx_empty;
151162306a36Sopenharmony_ci	++dev->stats.tx_errors;
151262306a36Sopenharmony_ci	if (i != bp->tx_fill) {
151362306a36Sopenharmony_ci		dev_kfree_skb_irq(bp->tx_bufs[i]);
151462306a36Sopenharmony_ci		bp->tx_bufs[i] = NULL;
151562306a36Sopenharmony_ci		if (++i >= N_TX_RING) i = 0;
151662306a36Sopenharmony_ci		bp->tx_empty = i;
151762306a36Sopenharmony_ci	}
151862306a36Sopenharmony_ci	bp->tx_fullup = 0;
151962306a36Sopenharmony_ci	netif_wake_queue(dev);
152062306a36Sopenharmony_ci	if (i != bp->tx_fill) {
152162306a36Sopenharmony_ci		cp = &bp->tx_cmds[i];
152262306a36Sopenharmony_ci		out_le16(&cp->xfer_status, 0);
152362306a36Sopenharmony_ci		out_le16(&cp->command, OUTPUT_LAST);
152462306a36Sopenharmony_ci		out_le32(&td->cmdptr, virt_to_bus(cp));
152562306a36Sopenharmony_ci		out_le32(&td->control, DBDMA_SET(RUN));
152662306a36Sopenharmony_ci		/* 	bmac_set_timeout(dev); */
152762306a36Sopenharmony_ci		XXDEBUG((KERN_DEBUG "bmac: starting %d\n", i));
152862306a36Sopenharmony_ci	}
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	/* turn it back on */
153162306a36Sopenharmony_ci	oldConfig = bmread(dev, RXCFG);
153262306a36Sopenharmony_ci	bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
153362306a36Sopenharmony_ci	oldConfig = bmread(dev, TXCFG);
153462306a36Sopenharmony_ci	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	spin_unlock_irqrestore(&bp->lock, flags);
153762306a36Sopenharmony_ci}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci#if 0
154062306a36Sopenharmony_cistatic void dump_dbdma(volatile struct dbdma_cmd *cp,int count)
154162306a36Sopenharmony_ci{
154262306a36Sopenharmony_ci	int i,*ip;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	for (i=0;i< count;i++) {
154562306a36Sopenharmony_ci		ip = (int*)(cp+i);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci		printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n",
154862306a36Sopenharmony_ci		       le32_to_cpup(ip+0),
154962306a36Sopenharmony_ci		       le32_to_cpup(ip+1),
155062306a36Sopenharmony_ci		       le32_to_cpup(ip+2),
155162306a36Sopenharmony_ci		       le32_to_cpup(ip+3));
155262306a36Sopenharmony_ci	}
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci}
155562306a36Sopenharmony_ci#endif
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci#if 0
155862306a36Sopenharmony_cistatic int
155962306a36Sopenharmony_cibmac_proc_info(char *buffer, char **start, off_t offset, int length)
156062306a36Sopenharmony_ci{
156162306a36Sopenharmony_ci	int len = 0;
156262306a36Sopenharmony_ci	off_t pos   = 0;
156362306a36Sopenharmony_ci	off_t begin = 0;
156462306a36Sopenharmony_ci	int i;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	if (bmac_devs == NULL)
156762306a36Sopenharmony_ci		return -ENOSYS;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	len += sprintf(buffer, "BMAC counters & registers\n");
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	for (i = 0; i<N_REG_ENTRIES; i++) {
157262306a36Sopenharmony_ci		len += sprintf(buffer + len, "%s: %#08x\n",
157362306a36Sopenharmony_ci			       reg_entries[i].name,
157462306a36Sopenharmony_ci			       bmread(bmac_devs, reg_entries[i].reg_offset));
157562306a36Sopenharmony_ci		pos = begin + len;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci		if (pos < offset) {
157862306a36Sopenharmony_ci			len = 0;
157962306a36Sopenharmony_ci			begin = pos;
158062306a36Sopenharmony_ci		}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci		if (pos > offset+length) break;
158362306a36Sopenharmony_ci	}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	*start = buffer + (offset - begin);
158662306a36Sopenharmony_ci	len -= (offset - begin);
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	if (len > length) len = length;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	return len;
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci#endif
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_cistatic int bmac_remove(struct macio_dev *mdev)
159562306a36Sopenharmony_ci{
159662306a36Sopenharmony_ci	struct net_device *dev = macio_get_drvdata(mdev);
159762306a36Sopenharmony_ci	struct bmac_data *bp = netdev_priv(dev);
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	unregister_netdev(dev);
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	free_irq(dev->irq, dev);
160262306a36Sopenharmony_ci	free_irq(bp->tx_dma_intr, dev);
160362306a36Sopenharmony_ci	free_irq(bp->rx_dma_intr, dev);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	iounmap((void __iomem *)dev->base_addr);
160662306a36Sopenharmony_ci	iounmap(bp->tx_dma);
160762306a36Sopenharmony_ci	iounmap(bp->rx_dma);
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	macio_release_resources(mdev);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	free_netdev(dev);
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	return 0;
161462306a36Sopenharmony_ci}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_cistatic const struct of_device_id bmac_match[] =
161762306a36Sopenharmony_ci{
161862306a36Sopenharmony_ci	{
161962306a36Sopenharmony_ci	.name 		= "bmac",
162062306a36Sopenharmony_ci	.data		= (void *)0,
162162306a36Sopenharmony_ci	},
162262306a36Sopenharmony_ci	{
162362306a36Sopenharmony_ci	.type		= "network",
162462306a36Sopenharmony_ci	.compatible	= "bmac+",
162562306a36Sopenharmony_ci	.data		= (void *)1,
162662306a36Sopenharmony_ci	},
162762306a36Sopenharmony_ci	{},
162862306a36Sopenharmony_ci};
162962306a36Sopenharmony_ciMODULE_DEVICE_TABLE (of, bmac_match);
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_cistatic struct macio_driver bmac_driver =
163262306a36Sopenharmony_ci{
163362306a36Sopenharmony_ci	.driver = {
163462306a36Sopenharmony_ci		.name 		= "bmac",
163562306a36Sopenharmony_ci		.owner		= THIS_MODULE,
163662306a36Sopenharmony_ci		.of_match_table	= bmac_match,
163762306a36Sopenharmony_ci	},
163862306a36Sopenharmony_ci	.probe		= bmac_probe,
163962306a36Sopenharmony_ci	.remove		= bmac_remove,
164062306a36Sopenharmony_ci#ifdef CONFIG_PM
164162306a36Sopenharmony_ci	.suspend	= bmac_suspend,
164262306a36Sopenharmony_ci	.resume		= bmac_resume,
164362306a36Sopenharmony_ci#endif
164462306a36Sopenharmony_ci};
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_cistatic int __init bmac_init(void)
164862306a36Sopenharmony_ci{
164962306a36Sopenharmony_ci	if (bmac_emergency_rxbuf == NULL) {
165062306a36Sopenharmony_ci		bmac_emergency_rxbuf = kmalloc(RX_BUFLEN, GFP_KERNEL);
165162306a36Sopenharmony_ci		if (bmac_emergency_rxbuf == NULL)
165262306a36Sopenharmony_ci			return -ENOMEM;
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	return macio_register_driver(&bmac_driver);
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_cistatic void __exit bmac_exit(void)
165962306a36Sopenharmony_ci{
166062306a36Sopenharmony_ci	macio_unregister_driver(&bmac_driver);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	kfree(bmac_emergency_rxbuf);
166362306a36Sopenharmony_ci	bmac_emergency_rxbuf = NULL;
166462306a36Sopenharmony_ci}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ciMODULE_AUTHOR("Randy Gobbel/Paul Mackerras");
166762306a36Sopenharmony_ciMODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");
166862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_cimodule_init(bmac_init);
167162306a36Sopenharmony_cimodule_exit(bmac_exit);
1672