jazzsonic.c revision d8865d5bb92d0d362ed6904cb248776d4da6efbb
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain * jazzsonic.c
3efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain *
4efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain * (C) 2005 Finn Thain
5efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain *
6efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain * Converted to DMA API, and (from the mac68k project) introduced
7efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain * dhd's support for 16-bit cards.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
106aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver is based on work from Andreas Busse, but most of
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the code is rewritten.
136aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A driver for the onboard Sonic ethernet controller on Mips Jazz
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * systems (Acer Pica-61, Mips Magnum 4000, Olivetti M700 and
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * perhaps others, too)
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
255a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
36d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
37efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain#include <linux/dma-mapping.h>
385a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/bootinfo.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/jazz.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/jazzdma.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char jazz_sonic_string[] = "jazzsonic";
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SONIC_MEM_SIZE	0x100
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sonic.h"
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Macros to access SONIC registers
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
56efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain#define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg))
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SONIC_WRITE(reg,val)						\
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo {									\
60efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	*((volatile unsigned int *)dev->base_addr+(reg)) = (val);		\
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
64efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain/* use 0 for production, 1 for verification, >1 for debug */
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SONIC_DEBUG
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int sonic_debug = SONIC_DEBUG;
676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#else
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int sonic_debug = 1;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We cannot use station (ethernet) address prefixes to detect the
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sonic controller since these are board manufacturer depended.
746aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * So we check for known Silicon Revision IDs instead.
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short known_revisions[] =
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x04,			/* Mips Magnum 4000 */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xffff			/* end of list */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
82f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thainstatic int jazzsonic_open(struct net_device* dev)
83f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain{
8462cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy	int retval;
8562cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy
86d8865d5bb92d0d362ed6904cb248776d4da6efbbMichael Opdenacker	retval = request_irq(dev->irq, sonic_interrupt, 0, "sonic", dev);
8762cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy	if (retval) {
8862cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
8962cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy				dev->name, dev->irq);
9062cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy		return retval;
91f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain	}
9262cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy
9362cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy	retval = sonic_open(dev);
9462cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy	if (retval)
9562cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy		free_irq(dev->irq, dev);
9662cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy	return retval;
97f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain}
98f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain
99f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thainstatic int jazzsonic_close(struct net_device* dev)
100f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain{
101f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain	int err;
102f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain	err = sonic_close(dev);
103f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain	free_irq(dev->irq, dev);
104f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain	return err;
105f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain}
106f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain
107502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalovstatic const struct net_device_ops sonic_netdev_ops = {
108502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_open		= jazzsonic_open,
109502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_stop		= jazzsonic_close,
110502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_start_xmit		= sonic_send_packet,
111502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_get_stats		= sonic_get_stats,
112afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= sonic_multicast_list,
113502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_tx_timeout		= sonic_tx_timeout,
114502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_change_mtu		= eth_change_mtu,
115502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_validate_addr	= eth_validate_addr,
116502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_set_mac_address	= eth_mac_addr,
117502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov};
118502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov
1196980cbe4a6dbb3d7871e99a3cbc74a572d14d327Bill Pembertonstatic int sonic_probe1(struct net_device *dev)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned version_printed;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int silicon_revision;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int val;
124efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	struct sonic_local *lp = netdev_priv(dev);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENODEV;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
128efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
130efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * get the Silicon Revision ID. If this is one of the known
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * one assume that we found a SONIC ethernet controller at
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the expected location.
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	silicon_revision = SONIC_READ(SONIC_SR);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sonic_debug > 1)
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision);
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = 0;
1418e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches	while (known_revisions[i] != 0xffff &&
1428e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches	       known_revisions[i] != silicon_revision)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i++;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (known_revisions[i] == 0xffff) {
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("SONIC ethernet controller not found (0x%4x)\n",
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       silicon_revision);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1506aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sonic_debug  &&  version_printed++ == 0)
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(version);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
154c23135573f37facd18edb2e8e8512c67928c54acKay Sievers	printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ",
155c23135573f37facd18edb2e8e8512c67928c54acKay Sievers	       dev_name(lp->device), dev->base_addr);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Put the sonic into software reset, then
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * retrieve and print the ethernet address.
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_CEP,0);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i<3; i++) {
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = SONIC_READ(SONIC_CAP0-i);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dev_addr[i*2] = val;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dev_addr[i*2+1] = val >> 8;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = -ENOMEM;
1706aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the device structure. */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
173efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->dma_bitmode = SONIC_BITMODE32;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
175efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	/* Allocate the entire chunk of memory for the descriptors.
176efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain           Note that this cannot cross a 64K boundary. */
177d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches	lp->descriptors = dma_alloc_coherent(lp->device,
178d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches					     SIZEOF_SONIC_DESC *
179d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches					     SONIC_BUS_SCALE(lp->dma_bitmode),
180d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches					     &lp->descriptors_laddr,
181d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches					     GFP_KERNEL);
182d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches	if (lp->descriptors == NULL)
183efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain		goto out;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
185efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	/* Now set up the pointers to point to the appropriate places */
186efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->cda = lp->descriptors;
187efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->tda = lp->cda + (SIZEOF_SONIC_CDA
188efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
189efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
190efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
191efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
192efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
193efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
194efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->cda_laddr = lp->descriptors_laddr;
195efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
196efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
197efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
198efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
199efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
200efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
201efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
202502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	dev->netdev_ops = &sonic_netdev_ops;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->watchdog_timeo = TX_TIMEOUT;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * clear tally counter
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_CRCT,0xffff);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_FAET,0xffff);
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_MPT,0xffff);
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
214c9145a2df072f75d97592ddac1624baeb7bad195Julia Lawall	release_mem_region(dev->base_addr, SONIC_MEM_SIZE);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Probe for a SONIC ethernet controller on a Mips Jazz board.
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Actually probing is superfluous but we're paranoid.
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2226980cbe4a6dbb3d7871e99a3cbc74a572d14d327Bill Pembertonstatic int jazz_sonic_probe(struct platform_device *pdev)
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sonic_local *lp;
226ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	struct resource *res;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
229ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
230ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	if (!res)
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
233efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	dev = alloc_etherdev(sizeof(struct sonic_local));
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
237efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp = netdev_priv(dev);
2383ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	lp->device = &pdev->dev;
2393ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	SET_NETDEV_DEV(dev, &pdev->dev);
2404564cba71637d3b4ea3730f5637b21a9eb3c8999Finn Thain	platform_set_drvdata(pdev, dev);
241efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netdev_boot_setup_check(dev);
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
244ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	dev->base_addr = res->start;
245ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	dev->irq = platform_get_irq(pdev, 0);
246ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	err = sonic_probe1(dev);
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_netdev(dev);
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out1;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
253e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg	printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq);
254efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1:
258c9145a2df072f75d97592ddac1624baeb7bad195Julia Lawall	release_mem_region(dev->base_addr, SONIC_MEM_SIZE);
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
265efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn ThainMODULE_DESCRIPTION("Jazz SONIC ethernet driver");
266efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thainmodule_param(sonic_debug, int, 0);
267efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn ThainMODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
26872abb46101fb5c47a9592914adb221b430ff26bdKay SieversMODULE_ALIAS("platform:jazzsonic");
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sonic.c"
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2726980cbe4a6dbb3d7871e99a3cbc74a572d14d327Bill Pembertonstatic int jazz_sonic_device_remove(struct platform_device *pdev)
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2743ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	struct net_device *dev = platform_get_drvdata(pdev);
275efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	struct sonic_local* lp = netdev_priv(dev);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
277d74472f0b2553e59eafb7feee0ff9558136a17e0Finn Thain	unregister_netdev(dev);
278efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
279efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                  lp->descriptors, lp->descriptors_laddr);
280c9145a2df072f75d97592ddac1624baeb7bad195Julia Lawall	release_mem_region(dev->base_addr, SONIC_MEM_SIZE);
281d74472f0b2553e59eafb7feee0ff9558136a17e0Finn Thain	free_netdev(dev);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2863ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver jazz_sonic_driver = {
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe	= jazz_sonic_probe,
2886980cbe4a6dbb3d7871e99a3cbc74a572d14d327Bill Pemberton	.remove	= jazz_sonic_device_remove,
2893ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver	= {
2903ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= jazz_sonic_string,
29172abb46101fb5c47a9592914adb221b430ff26bdKay Sievers		.owner	= THIS_MODULE,
2923ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
294efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
295db62f684deeb291ab2533b99843d5df9a36b1f19Axel Linmodule_platform_driver(jazz_sonic_driver);
296