11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Driver for the Macintosh 68K onboard MACE controller with PSC
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	driven DMA. The MACE driver code is derived from mace.c. The
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Mac68k theory of operation is courtesy of the MacBSD wizards.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This program is free software; you can redistribute it and/or
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	modify it under the terms of the GNU General Public License
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	as published by the Free Software Foundation; either version
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	2 of the License, or (at your option) any later version.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Copyright (C) 1996 Paul Mackerras.
12113aa838ec3a235d883f8357d31d90e16c47fc89Alan Cox *	Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver
158b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain *
168b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain *	Copyright (C) 2007 Finn Thain
178b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain *
188b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain *	Converted to DMA API, converted to unified driver model,
198b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain *	sync'd some routines with mace.c and fixed various bugs.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/crc32.h>
30bc63eb9c7ec0eb7b091db2d82d46d1e68ff9e231Akinobu Mita#include <linux/bitrev.h>
318b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#include <linux/dma-mapping.h>
328b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#include <linux/platform_device.h>
335a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
34ce43aa6c142d69820a267431ea342d1bd9f6d3ceFinn Thain#include <linux/interrupt.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/macints.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mac_psc.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/page.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "mace.h"
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
418b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic char mac_mace_string[] = "macmace";
428b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
438b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define N_TX_BUFF_ORDER	0
448b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define N_TX_RING	(1 << N_TX_BUFF_ORDER)
458b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define N_RX_BUFF_ORDER	3
468b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define N_RX_RING	(1 << N_RX_BUFF_ORDER)
478b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_TIMEOUT	HZ
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
508b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define MACE_BUFF_SIZE	0x800
518b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
528b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain/* Chip rev needs workaround on HW & multicast addr change */
538b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain#define BROKEN_ADDRCHG_REV	0x0941
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The MACE is simply wired down on a Mac68K box */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MACE_BASE	(void *)(0x50F1C000)
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MACE_PROM	(void *)(0x50F08001)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mace_data {
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct mace *mace;
628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	unsigned char *tx_ring;
638b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	dma_addr_t tx_ring_phys;
648b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	unsigned char *rx_ring;
658b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	dma_addr_t rx_ring_phys;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dma_intr;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rx_slot, rx_tail;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tx_slot, tx_sloti, tx_count;
698b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	int chipid;
708b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct device *device;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mace_frame {
748b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	u8	rcvcnt;
758b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	u8	pad1;
768b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	u8	rcvsts;
778b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	u8	pad2;
788b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	u8	rntpc;
798b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	u8	pad3;
808b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	u8	rcvcc;
818b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	u8	pad4;
828b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	u32	pad5;
838b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	u32	pad6;
846aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	u8	data[1];
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* And frame continues.. */
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PRIV_BYTES	sizeof(struct mace_data)
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_open(struct net_device *dev);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_close(struct net_device *dev);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_set_multicast(struct net_device *dev);
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_set_address(struct net_device *dev, void *addr);
958b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void mace_reset(struct net_device *dev);
967d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mace_interrupt(int irq, void *dev_id);
977d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mace_dma_intr(int irq, void *dev_id);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_tx_timeout(struct net_device *dev);
998b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void __mace_set_address(struct net_device *dev, void *addr);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Load a receive DMA channel with a base address and ring length
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_load_rxdma_base(struct net_device *dev, int set)
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1078b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CMD + set, 0x0100);
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CMD + set, 0x9800);
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mp->rx_tail = 0;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset the receive DMA subsystem
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_rxdma_reset(struct net_device *dev)
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct mace *mace = mp->mace;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 maccc = mace->maccc;
1256aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mace->maccc = maccc & ~ENRCV;
1276aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CTL, 0x8800);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mace_load_rxdma_base(dev, 0x00);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CTL, 0x0400);
1316aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CTL, 0x8800);
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mace_load_rxdma_base(dev, 0x10);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CTL, 0x0400);
1356aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mace->maccc = maccc;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mp->rx_slot = 0;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x9800);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x9800);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset the transmit DMA subsystem
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1466aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_txdma_reset(struct net_device *dev)
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1498b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct mace *mace = mp->mace;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 maccc;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETWR_CTL, 0x8800);
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	maccc = mace->maccc;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mace->maccc = maccc & ~ENXMT;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mp->tx_slot = mp->tx_sloti = 0;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mp->tx_count = N_TX_RING;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETWR_CTL, 0x0400);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mace->maccc = maccc;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable DMA
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_dma_off(struct net_device *dev)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CTL, 0x8800);
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CTL, 0x1000);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CMD + PSC_SET0, 0x1100);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CMD + PSC_SET1, 0x1100);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETWR_CTL, 0x8800);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETWR_CTL, 0x1000);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETWR_CMD + PSC_SET0, 0x1100);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETWR_CMD + PSC_SET1, 0x1100);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1820d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalovstatic const struct net_device_ops mace_netdev_ops = {
1830d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov	.ndo_open		= mace_open,
1840d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov	.ndo_stop		= mace_close,
1850d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov	.ndo_start_xmit		= mace_xmit_start,
1860d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov	.ndo_tx_timeout		= mace_tx_timeout,
187afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= mace_set_multicast,
1880d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov	.ndo_set_mac_address	= mace_set_address,
1890d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov	.ndo_change_mtu		= eth_change_mtu,
1900d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov	.ndo_validate_addr	= eth_validate_addr,
1910d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov};
1920d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Not really much of a probe. The hardware table tells us if this
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * model of Macintrash has a MACE (AV macintoshes)
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1976aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1988b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic int __devinit mace_probe(struct platform_device *pdev)
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int j;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mace_data *mp;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *addr;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char checksum = 0;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
2066aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = alloc_etherdev(PRIV_BYTES);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
2098b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		return -ENOMEM;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2118b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mp = netdev_priv(dev);
2128b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
2138b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mp->device = &pdev->dev;
2148b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	SET_NETDEV_DEV(dev, &pdev->dev);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->base_addr = (u32)MACE_BASE;
21743d620c82985b19008d87a437b4cf83f356264f7Joe Perches	mp->mace = MACE_BASE;
2186aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->irq = IRQ_MAC_MACE;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mp->dma_intr = IRQ_MAC_MACE_DMA;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mp->chipid = mp->mace->chipid_hi << 8 | mp->mace->chipid_lo;
2238b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The PROM contains 8 bytes which total 0xFF when XOR'd
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * together. Due to the usual peculiar apple brain damage
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the bytes are spaced out in a strange boundary and the
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * bits are reversed.
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	addr = (void *)MACE_PROM;
2326aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (j = 0; j < 6; ++j) {
234bc63eb9c7ec0eb7b091db2d82d46d1e68ff9e231Akinobu Mita		u8 v = bitrev8(addr[j<<4]);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		checksum ^= v;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dev_addr[j] = v;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (; j < 8; ++j) {
239bc63eb9c7ec0eb7b091db2d82d46d1e68ff9e231Akinobu Mita		checksum ^= bitrev8(addr[j<<4]);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2416aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (checksum != 0xFF) {
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_netdev(dev);
2448b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		return -ENODEV;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2470d3936a8b11b72e1387923342e33fdad553271d4Alexander Beregalov	dev->netdev_ops		= &mace_netdev_ops;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->watchdog_timeo	= TX_TIMEOUT;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
250e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg	printk(KERN_INFO "%s: 68K MACE, hardware address %pM\n",
251e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg	       dev->name, dev->dev_addr);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_netdev(dev);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!err)
2558b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		return 0;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
2588b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	return err;
2598b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain}
2608b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
2618b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain/*
2628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain * Reset the chip.
2638b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain */
2648b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
2658b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void mace_reset(struct net_device *dev)
2668b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain{
2678b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
2688b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	volatile struct mace *mb = mp->mace;
2698b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	int i;
2708b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
2718b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* soft-reset the chip */
2728b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	i = 200;
2738b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	while (--i) {
2748b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		mb->biucc = SWRST;
2758b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (mb->biucc & SWRST) {
2768b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			udelay(10);
2778b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			continue;
2788b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		}
2798b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		break;
2808b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	}
2818b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (!i) {
2828b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		printk(KERN_ERR "macmace: cannot reset chip!\n");
2838b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		return;
2848b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	}
2858b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
2868b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->maccc = 0;	/* turn off tx, rx */
2878b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->imr = 0xFF;	/* disable all intrs for now */
2888b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	i = mb->ir;
2898b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
2908b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->biucc = XMTSP_64;
2918b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->utr = RTRD;
2928b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->fifocc = XMTFW_8 | RCVFW_64 | XMTFWU | RCVFWU;
2938b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
2948b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */
2958b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->rcvfc = 0;
2968b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
2978b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* load up the hardware address */
2988b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	__mace_set_address(dev, dev->dev_addr);
2998b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
3008b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* clear the multicast filter */
3018b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (mp->chipid == BROKEN_ADDRCHG_REV)
3028b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		mb->iac = LOGADDR;
3038b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	else {
3048b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		mb->iac = ADDRCHG | LOGADDR;
3058b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		while ((mb->iac & ADDRCHG) != 0)
3068b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			;
3078b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	}
3088b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	for (i = 0; i < 8; ++i)
3098b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		mb->ladrf = 0;
3108b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
3118b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* done changing address */
3128b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (mp->chipid != BROKEN_ADDRCHG_REV)
3138b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		mb->iac = 0;
3148b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
3158b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->plscc = PORTSEL_AUI;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Load the address on a mace controller.
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void __mace_set_address(struct net_device *dev, void *addr)
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3248b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct mace *mb = mp->mace;
3268b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	unsigned char *p = addr;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3288b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
3298b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* load up the hardware address */
3308b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (mp->chipid == BROKEN_ADDRCHG_REV)
3318b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		mb->iac = PHYADDR;
3328b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	else {
3338b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		mb->iac = ADDRCHG | PHYADDR;
3348b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		while ((mb->iac & ADDRCHG) != 0)
3358b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			;
3368b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	}
3378b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	for (i = 0; i < 6; ++i)
3388b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		mb->padr = dev->dev_addr[i] = p[i];
3398b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (mp->chipid != BROKEN_ADDRCHG_REV)
3408b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		mb->iac = 0;
3418b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain}
3428b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
3438b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic int mace_set_address(struct net_device *dev, void *addr)
3448b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain{
3458b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
3468b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	volatile struct mace *mb = mp->mace;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 maccc;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_save(flags);
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	maccc = mb->maccc;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3548b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	__mace_set_address(dev, addr);
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb->maccc = maccc;
3578b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_restore(flags);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Open the Macintosh MACE. Most of this is playing with the DMA
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * engine. The ethernet chip is quite friendly.
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_open(struct net_device *dev)
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3708b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct mace *mb = mp->mace;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3738b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* reset the chip */
3748b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mace_reset(dev);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) {
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (request_irq(mp->dma_intr, mace_dma_intr, 0, dev->name, dev)) {
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "%s: can't get irq %d\n", dev->name, mp->dma_intr);
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_irq(dev->irq, dev);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Allocate the DMA ring buffers */
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3888b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mp->tx_ring = dma_alloc_coherent(mp->device,
3898b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			N_TX_RING * MACE_BUFF_SIZE,
3908b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			&mp->tx_ring_phys, GFP_KERNEL);
3918b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (mp->tx_ring == NULL) {
3928b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		printk(KERN_ERR "%s: unable to allocate DMA tx buffers\n", dev->name);
3938b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		goto out1;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3968b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mp->rx_ring = dma_alloc_coherent(mp->device,
3978b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			N_RX_RING * MACE_BUFF_SIZE,
3988b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			&mp->rx_ring_phys, GFP_KERNEL);
3998b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (mp->rx_ring == NULL) {
4008b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		printk(KERN_ERR "%s: unable to allocate DMA rx buffers\n", dev->name);
4018b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		goto out2;
4028b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	}
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mace_dma_off(dev);
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Not sure what these do */
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETWR_CTL, 0x9000);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CTL, 0x9000);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETWR_CTL, 0x0400);
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETRD_CTL, 0x0400);
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mace_rxdma_reset(dev);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mace_txdma_reset(dev);
4156aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4168b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* turn it on! */
4178b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->maccc = ENXMT | ENRCV;
4188b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* enable all interrupts except receive interrupts */
4198b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->imr = RCVINT;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4218b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
4228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainout2:
4238b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE,
4248b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	                  mp->tx_ring, mp->tx_ring_phys);
4258b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainout1:
4268b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	free_irq(dev->irq, dev);
4278b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	free_irq(mp->dma_intr, dev);
4288b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	return -ENOMEM;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Shut down the mace and its interrupt channel
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4346aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_close(struct net_device *dev)
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4378b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct mace *mb = mp->mace;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb->maccc = 0;		/* disable rx and tx	 */
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb->imr = 0xFF;		/* disable all irqs	 */
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mace_dma_off(dev);	/* disable rx and tx dma */
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Transmit a frame
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4506aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4538b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
4548b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	unsigned long flags;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4568b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* Stop the queue since there's only the one buffer */
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4588b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	local_irq_save(flags);
4598b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	netif_stop_queue(dev);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!mp->tx_count) {
4618b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		printk(KERN_ERR "macmace: tx queue running but no free buffers.\n");
4628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		local_irq_restore(flags);
4638b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		return NETDEV_TX_BUSY;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mp->tx_count--;
4668b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	local_irq_restore(flags);
4676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
46809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_packets++;
46909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_bytes += skb->len;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We need to copy into our xmit buffer to take care of alignment and caching issues */
472d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo	skb_copy_from_linear_data(skb, mp->tx_ring, skb->len);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* load the Tx DMA and fire it off */
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, (u32)  mp->tx_ring_phys);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mp->tx_slot ^= 0x10;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb(skb);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4848b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	return NETDEV_TX_OK;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_set_multicast(struct net_device *dev)
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4898b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct mace *mb = mp->mace;
491f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko	int i;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 crc;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 maccc;
4948b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	unsigned long flags;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4968b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	local_irq_save(flags);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	maccc = mb->maccc;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb->maccc &= ~PROM;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->flags & IFF_PROMISC) {
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mb->maccc |= PROM;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned char multicast_filter[8];
50422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko		struct netdev_hw_addr *ha;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev->flags & IFF_ALLMULTI) {
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < 8; i++) {
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				multicast_filter[i] = 0xFF;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < 8; i++)
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				multicast_filter[i] = 0;
51322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko			netdev_for_each_mc_addr(ha, dev) {
51422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko				crc = ether_crc_le(6, ha->addr);
515f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko				/* bit number in multicast_filter */
516f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko				i = crc >> 26;
517f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko				multicast_filter[i >> 3] |= 1 << (i & 7);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5218b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (mp->chipid == BROKEN_ADDRCHG_REV)
5228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			mb->iac = LOGADDR;
5238b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		else {
5248b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			mb->iac = ADDRCHG | LOGADDR;
5258b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			while ((mb->iac & ADDRCHG) != 0)
5268b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain				;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5288b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		for (i = 0; i < 8; ++i)
5298b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			mb->ladrf = multicast_filter[i];
5308b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (mp->chipid != BROKEN_ADDRCHG_REV)
5318b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			mb->iac = 0;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mb->maccc = maccc;
5358b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	local_irq_restore(flags);
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5383649ba001b5d037e2cead173b6cff54d32ef154aGeert Uytterhoevenstatic void mace_handle_misc_intrs(struct net_device *dev, int intr)
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5403649ba001b5d037e2cead173b6cff54d32ef154aGeert Uytterhoeven	struct mace_data *mp = netdev_priv(dev);
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct mace *mb = mp->mace;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int mace_babbles, mace_jabbers;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5448b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (intr & MPCO)
54509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_missed_errors += 256;
54609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.rx_missed_errors += mb->mpc;   /* reading clears it */
5478b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (intr & RNTPCO)
54809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_length_errors += 256;
54909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.rx_length_errors += mb->rntpc; /* reading clears it */
5508b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (intr & CERR)
55109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		++dev->stats.tx_heartbeat_errors;
5528b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (intr & BABBLE)
5538b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (mace_babbles++ < 4)
5548b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			printk(KERN_DEBUG "macmace: babbling transmitter\n");
5558b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (intr & JABBER)
5568b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (mace_jabbers++ < 4)
5578b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			printk(KERN_DEBUG "macmace: jabbering transceiver\n");
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5608b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic irqreturn_t mace_interrupt(int irq, void *dev_id)
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct net_device *dev = (struct net_device *) dev_id;
5638b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct mace *mb = mp->mace;
5658b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	int intr, fs;
566099575b6cb7eaf18211ba72de56264f67651b90bAlexey Dobriyan	unsigned long flags;
5676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5688b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* don't want the dma interrupt handler to fire */
5698b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	local_irq_save(flags);
5706aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
5718b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	intr = mb->ir; /* read interrupt register */
5723649ba001b5d037e2cead173b6cff54d32ef154aGeert Uytterhoeven	mace_handle_misc_intrs(dev, intr);
5738b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
5748b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (intr & XMTINT) {
5758b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		fs = mb->xmtfs;
5768b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if ((fs & XMTSV) == 0) {
5778b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			printk(KERN_ERR "macmace: xmtfs not valid! (fs=%x)\n", fs);
5788b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			mace_reset(dev);
5798b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			/*
5808b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			 * XXX mace likes to hang the machine after a xmtfs error.
5818b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			 * This is hard to reproduce, reseting *may* help
5828b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			 */
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5848b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		/* dma should have finished */
5858b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (!mp->tx_count) {
5868b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			printk(KERN_DEBUG "macmace: tx ring ran out? (fs=%x)\n", fs);
5878b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		}
5888b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		/* Update stats */
5898b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (fs & (UFLO|LCOL|LCAR|RTRY)) {
59009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			++dev->stats.tx_errors;
5918b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			if (fs & LCAR)
59209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				++dev->stats.tx_carrier_errors;
5938b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			else if (fs & (UFLO|LCOL|RTRY)) {
59409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik				++dev->stats.tx_aborted_errors;
5958b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain				if (mb->xmtfs & UFLO) {
5968b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain					printk(KERN_ERR "%s: DMA underrun.\n", dev->name);
59709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik					dev->stats.tx_fifo_errors++;
5988b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain					mace_txdma_reset(dev);
5998b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain				}
6008b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			}
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6026aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik	}
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6048b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (mp->tx_count)
6058b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		netif_wake_queue(dev);
6066aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6078b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	local_irq_restore(flags);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6098b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	return IRQ_HANDLED;
6108b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain}
6116aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6128b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void mace_tx_timeout(struct net_device *dev)
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6148b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	volatile struct mace *mb = mp->mace;
6168b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	unsigned long flags;
6176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6188b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	local_irq_save(flags);
6196aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6208b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* turn off both tx and rx and reset the chip */
6218b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->maccc = 0;
6228b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	printk(KERN_ERR "macmace: transmit timeout - resetting\n");
6238b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mace_txdma_reset(dev);
6248b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mace_reset(dev);
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6268b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* restart rx dma */
6278b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mace_rxdma_reset(dev);
6288b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
6298b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mp->tx_count = N_TX_RING;
6308b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	netif_wake_queue(dev);
6318b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
6328b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* turn it on! */
6338b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->maccc = ENXMT | ENRCV;
6348b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	/* enable all interrupts except receive interrupts */
6358b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	mb->imr = RCVINT;
6368b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
6378b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	local_irq_restore(flags);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle a newly arrived frame
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
6478b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	unsigned int frame_status = mf->rcvsts;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6498b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) {
65009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_errors++;
6518b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (frame_status & RS_OFLO) {
6528b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name);
65309f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			dev->stats.rx_fifo_errors++;
6548b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		}
6558b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (frame_status & RS_CLSN)
65609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			dev->stats.collisions++;
6578b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (frame_status & RS_FRAMERR)
65809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			dev->stats.rx_frame_errors++;
6598b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (frame_status & RS_FCSERR)
66009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			dev->stats.rx_crc_errors++;
6618b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	} else {
6628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 );
6636aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6641d266430546acf01438ae42d0a7370db4817e2adPradeep A Dalvi		skb = netdev_alloc_skb(dev, frame_length + 2);
6658b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		if (!skb) {
66609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik			dev->stats.rx_dropped++;
6678b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			return;
6688b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		}
6698b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		skb_reserve(skb, 2);
6708b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		memcpy(skb_put(skb, frame_length), mf->data, frame_length);
6718b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
6728b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		skb->protocol = eth_type_trans(skb, dev);
6738b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain		netif_rx(skb);
67409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_packets++;
67509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_bytes += frame_length;
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The PSC has passed us a DMA interrupt event.
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6826aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
6837d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t mace_dma_intr(int irq, void *dev_id)
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = (struct net_device *) dev_id;
6868b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int left, head;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 status;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 baka;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Not sure what this does */
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((baka = psc_read_long(PSC_MYSTERY)) != psc_read_long(PSC_MYSTERY));
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(baka & 0x60000000)) return IRQ_NONE;
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Process the read queue
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6996aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = psc_read_word(PSC_ENETRD_CTL);
7016aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & 0x2000) {
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mace_rxdma_reset(dev);
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (status & 0x0100) {
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x1100);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		left = psc_read_long(PSC_ENETRD_LEN + mp->rx_slot);
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		head = N_RX_RING - left;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Loop through the ring buffer and process new packages */
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (mp->rx_tail < head) {
7138b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain			mace_dma_rx_frame(dev, (struct mace_frame*) (mp->rx_ring
7148b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain				+ (mp->rx_tail * MACE_BUFF_SIZE)));
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mp->rx_tail++;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* If we're out of buffers in this ring then switch to */
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* the other set, otherwise just reactivate this one.  */
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!left) {
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mace_load_rxdma_base(dev, mp->rx_slot);
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mp->rx_slot ^= 0x10;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x9800);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7286aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Process the write queue
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = psc_read_word(PSC_ENETWR_CTL);
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & 0x2000) {
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mace_txdma_reset(dev);
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (status & 0x0100) {
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mp->tx_sloti ^= 0x10;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mp->tx_count++;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
7468b6aaab8c8bdbe011aac79af218dd1e657984babFinn ThainMODULE_DESCRIPTION("Macintosh MACE ethernet driver");
747eeb9c182a6ad8bc130377adb0a4cd7b95dd15f49Finn ThainMODULE_ALIAS("platform:macmace");
7488b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
7498b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic int __devexit mac_mace_device_remove (struct platform_device *pdev)
7508b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain{
7518b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct net_device *dev = platform_get_drvdata(pdev);
7528b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	struct mace_data *mp = netdev_priv(dev);
7538b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
7548b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	unregister_netdev(dev);
7558b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
7568b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	free_irq(dev->irq, dev);
7578b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	free_irq(IRQ_MAC_MACE_DMA, dev);
7588b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
7598b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	dma_free_coherent(mp->device, N_RX_RING * MACE_BUFF_SIZE,
7608b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	                  mp->rx_ring, mp->rx_ring_phys);
7618b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE,
7628b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	                  mp->tx_ring, mp->tx_ring_phys);
7638b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
7648b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	free_netdev(dev);
7658b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
7668b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	return 0;
7678b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain}
7688b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
7698b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic struct platform_driver mac_mace_driver = {
7708b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	.probe  = mace_probe,
7718b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	.remove = __devexit_p(mac_mace_device_remove),
7728b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	.driver	= {
773eeb9c182a6ad8bc130377adb0a4cd7b95dd15f49Finn Thain		.name	= mac_mace_string,
774eeb9c182a6ad8bc130377adb0a4cd7b95dd15f49Finn Thain		.owner	= THIS_MODULE,
7758b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	},
7768b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain};
7778b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
7788b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic int __init mac_mace_init_module(void)
7798b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain{
7800f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven	if (!MACH_IS_MAC)
7810f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven		return -ENODEV;
7820f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven
783eeb9c182a6ad8bc130377adb0a4cd7b95dd15f49Finn Thain	return platform_driver_register(&mac_mace_driver);
7848b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain}
7858b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
7868b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainstatic void __exit mac_mace_cleanup_module(void)
7878b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain{
7888b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain	platform_driver_unregister(&mac_mace_driver);
7898b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain}
7908b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thain
7918b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainmodule_init(mac_mace_init_module);
7928b6aaab8c8bdbe011aac79af218dd1e657984babFinn Thainmodule_exit(mac_mace_cleanup_module);
793