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/ioport.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
35d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
36efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain#include <linux/dma-mapping.h>
375a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/bootinfo.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/jazz.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/jazzdma.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char jazz_sonic_string[] = "jazzsonic";
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SONIC_MEM_SIZE	0x100
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sonic.h"
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Macros to access SONIC registers
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
55efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain#define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg))
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SONIC_WRITE(reg,val)						\
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo {									\
59efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	*((volatile unsigned int *)dev->base_addr+(reg)) = (val);		\
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
63efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain/* use 0 for production, 1 for verification, >1 for debug */
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SONIC_DEBUG
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int sonic_debug = SONIC_DEBUG;
666aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#else
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int sonic_debug = 1;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We cannot use station (ethernet) address prefixes to detect the
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sonic controller since these are board manufacturer depended.
736aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * So we check for known Silicon Revision IDs instead.
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short known_revisions[] =
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x04,			/* Mips Magnum 4000 */
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xffff			/* end of list */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thainstatic int jazzsonic_open(struct net_device* dev)
82f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain{
8362cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy	int retval;
8462cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy
85d8865d5bb92d0d362ed6904cb248776d4da6efbbMichael Opdenacker	retval = request_irq(dev->irq, sonic_interrupt, 0, "sonic", dev);
8662cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy	if (retval) {
8762cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
8862cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy				dev->name, dev->irq);
8962cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy		return retval;
90f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain	}
9162cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy
9262cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy	retval = sonic_open(dev);
9362cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy	if (retval)
9462cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy		free_irq(dev->irq, dev);
9562cd69a10683bd17a2454213b8c36a4399c533abKulikov Vasiliy	return retval;
96f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain}
97f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain
98f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thainstatic int jazzsonic_close(struct net_device* dev)
99f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain{
100f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain	int err;
101f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain	err = sonic_close(dev);
102f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain	free_irq(dev->irq, dev);
103f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain	return err;
104f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain}
105f4d86754f956ab5ea73aa91759a0d89a2f0e3f2aFinn Thain
106502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalovstatic const struct net_device_ops sonic_netdev_ops = {
107502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_open		= jazzsonic_open,
108502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_stop		= jazzsonic_close,
109502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_start_xmit		= sonic_send_packet,
110502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_get_stats		= sonic_get_stats,
111afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= sonic_multicast_list,
112502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_tx_timeout		= sonic_tx_timeout,
113502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_change_mtu		= eth_change_mtu,
114502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_validate_addr	= eth_validate_addr,
115502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	.ndo_set_mac_address	= eth_mac_addr,
116502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov};
117502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov
1186980cbe4a6dbb3d7871e99a3cbc74a572d14d327Bill Pembertonstatic int sonic_probe1(struct net_device *dev)
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned version_printed;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int silicon_revision;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int val;
123efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	struct sonic_local *lp = netdev_priv(dev);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENODEV;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
127efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
129efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * get the Silicon Revision ID. If this is one of the known
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * one assume that we found a SONIC ethernet controller at
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the expected location.
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	silicon_revision = SONIC_READ(SONIC_SR);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sonic_debug > 1)
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = 0;
1408e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches	while (known_revisions[i] != 0xffff &&
1418e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches	       known_revisions[i] != silicon_revision)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i++;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (known_revisions[i] == 0xffff) {
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("SONIC ethernet controller not found (0x%4x)\n",
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       silicon_revision);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1496aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sonic_debug  &&  version_printed++ == 0)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(version);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
153c23135573f37facd18edb2e8e8512c67928c54acKay Sievers	printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ",
154c23135573f37facd18edb2e8e8512c67928c54acKay Sievers	       dev_name(lp->device), dev->base_addr);
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Put the sonic into software reset, then
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * retrieve and print the ethernet address.
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_CEP,0);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i<3; i++) {
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = SONIC_READ(SONIC_CAP0-i);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dev_addr[i*2] = val;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dev_addr[i*2+1] = val >> 8;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = -ENOMEM;
1696aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the device structure. */
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
172efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->dma_bitmode = SONIC_BITMODE32;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
174efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	/* Allocate the entire chunk of memory for the descriptors.
175efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain           Note that this cannot cross a 64K boundary. */
176d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches	lp->descriptors = dma_alloc_coherent(lp->device,
177d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches					     SIZEOF_SONIC_DESC *
178d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches					     SONIC_BUS_SCALE(lp->dma_bitmode),
179d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches					     &lp->descriptors_laddr,
180d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches					     GFP_KERNEL);
181d0320f750093d012d3ed69fc1e8b385f654523d5Joe Perches	if (lp->descriptors == NULL)
182efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain		goto out;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
184efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	/* Now set up the pointers to point to the appropriate places */
185efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->cda = lp->descriptors;
186efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->tda = lp->cda + (SIZEOF_SONIC_CDA
187efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
188efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
189efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
190efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
191efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
192efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
193efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->cda_laddr = lp->descriptors_laddr;
194efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
195efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
196efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
197efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
198efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
199efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
200efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
201502a326f833927a84a8de29f5fb638aa9da15f4bAlexander Beregalov	dev->netdev_ops = &sonic_netdev_ops;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->watchdog_timeo = TX_TIMEOUT;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * clear tally counter
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_CRCT,0xffff);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_FAET,0xffff);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_MPT,0xffff);
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
213c9145a2df072f75d97592ddac1624baeb7bad195Julia Lawall	release_mem_region(dev->base_addr, SONIC_MEM_SIZE);
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Probe for a SONIC ethernet controller on a Mips Jazz board.
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Actually probing is superfluous but we're paranoid.
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2216980cbe4a6dbb3d7871e99a3cbc74a572d14d327Bill Pembertonstatic int jazz_sonic_probe(struct platform_device *pdev)
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sonic_local *lp;
225ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	struct resource *res;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
228ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
229ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	if (!res)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
232efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	dev = alloc_etherdev(sizeof(struct sonic_local));
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
236efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp = netdev_priv(dev);
2373ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	lp->device = &pdev->dev;
2383ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	SET_NETDEV_DEV(dev, &pdev->dev);
2394564cba71637d3b4ea3730f5637b21a9eb3c8999Finn Thain	platform_set_drvdata(pdev, dev);
240efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netdev_boot_setup_check(dev);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
243ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	dev->base_addr = res->start;
244ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	dev->irq = platform_get_irq(pdev, 0);
245ed9f0e0bf3ceb44334ca9b70779a50b2e79b7f97Thomas Bogendoerfer	err = sonic_probe1(dev);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_netdev(dev);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out1;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
252e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg	printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq);
253efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1:
257c9145a2df072f75d97592ddac1624baeb7bad195Julia Lawall	release_mem_region(dev->base_addr, SONIC_MEM_SIZE);
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
264efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn ThainMODULE_DESCRIPTION("Jazz SONIC ethernet driver");
265efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thainmodule_param(sonic_debug, int, 0);
266efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn ThainMODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
26772abb46101fb5c47a9592914adb221b430ff26bdKay SieversMODULE_ALIAS("platform:jazzsonic");
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sonic.c"
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2716980cbe4a6dbb3d7871e99a3cbc74a572d14d327Bill Pembertonstatic int jazz_sonic_device_remove(struct platform_device *pdev)
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2733ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	struct net_device *dev = platform_get_drvdata(pdev);
274efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	struct sonic_local* lp = netdev_priv(dev);
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
276d74472f0b2553e59eafb7feee0ff9558136a17e0Finn Thain	unregister_netdev(dev);
277efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
278efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                  lp->descriptors, lp->descriptors_laddr);
279c9145a2df072f75d97592ddac1624baeb7bad195Julia Lawall	release_mem_region(dev->base_addr, SONIC_MEM_SIZE);
280d74472f0b2553e59eafb7feee0ff9558136a17e0Finn Thain	free_netdev(dev);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2853ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver jazz_sonic_driver = {
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe	= jazz_sonic_probe,
2876980cbe4a6dbb3d7871e99a3cbc74a572d14d327Bill Pemberton	.remove	= jazz_sonic_device_remove,
2883ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver	= {
2893ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= jazz_sonic_string,
29072abb46101fb5c47a9592914adb221b430ff26bdKay Sievers		.owner	= THIS_MODULE,
2913ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
293efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
294db62f684deeb291ab2533b99843d5df9a36b1f19Axel Linmodule_platform_driver(jazz_sonic_driver);
295