jazzsonic.c revision d74472f0b2553e59eafb7feee0ff9558136a17e0
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>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.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>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/bootinfo.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.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 Torvaldsstatic struct platform_device *jazz_sonic_device;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SONIC_MEM_SIZE	0x100
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sonic.h"
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Macros to access SONIC registers
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
57efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain#define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg))
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SONIC_WRITE(reg,val)						\
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo {									\
61efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	*((volatile unsigned int *)dev->base_addr+(reg)) = (val);		\
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
65efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain/* use 0 for production, 1 for verification, >1 for debug */
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SONIC_DEBUG
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int sonic_debug = SONIC_DEBUG;
686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#else
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int sonic_debug = 1;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Base address and interrupt of the SONIC controller on JAZZ boards
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct {
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int port;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int irq;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}};
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We cannot use station (ethernet) address prefixes to detect the
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sonic controller since these are board manufacturer depended.
836aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * So we check for known Silicon Revision IDs instead.
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short known_revisions[] =
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x04,			/* Mips Magnum 4000 */
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xffff			/* end of list */
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thainstatic int __init sonic_probe1(struct net_device *dev)
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned version_printed;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int silicon_revision;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int val;
96efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	struct sonic_local *lp = netdev_priv(dev);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENODEV;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
100efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
102efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * get the Silicon Revision ID. If this is one of the known
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * one assume that we found a SONIC ethernet controller at
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the expected location.
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	silicon_revision = SONIC_READ(SONIC_SR);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sonic_debug > 1)
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = 0;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (known_revisions[i] != 0xffff
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       && known_revisions[i] != silicon_revision)
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i++;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (known_revisions[i] == 0xffff) {
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("SONIC ethernet controller not found (0x%4x)\n",
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       silicon_revision);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sonic_debug  &&  version_printed++ == 0)
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(version);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
126efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ", lp->device->bus_id, dev->base_addr);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Put the sonic into software reset, then
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * retrieve and print the ethernet address.
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_CEP,0);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i<3; i++) {
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = SONIC_READ(SONIC_CAP0-i);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dev_addr[i*2] = val;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->dev_addr[i*2+1] = val >> 8;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = -ENOMEM;
1416aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the device structure. */
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
144efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->dma_bitmode = SONIC_BITMODE32;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
146efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	/* Allocate the entire chunk of memory for the descriptors.
147efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain           Note that this cannot cross a 64K boundary. */
148efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	if ((lp->descriptors = dma_alloc_coherent(lp->device,
149efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain				SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
150efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain				&lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
151efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain		printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id);
152efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain		goto out;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
155efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	/* Now set up the pointers to point to the appropriate places */
156efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->cda = lp->descriptors;
157efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->tda = lp->cda + (SIZEOF_SONIC_CDA
158efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
159efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
160efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
161efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
162efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
163efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
164efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->cda_laddr = lp->descriptors_laddr;
165efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
166efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
167efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
168efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
169efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
170efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
171efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->open = sonic_open;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->stop = sonic_close;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->hard_start_xmit = sonic_send_packet;
175efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	dev->get_stats = sonic_get_stats;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->set_multicast_list = &sonic_multicast_list;
177efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	dev->tx_timeout = sonic_tx_timeout;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->watchdog_timeo = TX_TIMEOUT;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * clear tally counter
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_CRCT,0xffff);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_FAET,0xffff);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SONIC_WRITE(SONIC_MPT,0xffff);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
189efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	release_region(dev->base_addr, SONIC_MEM_SIZE);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Probe for a SONIC ethernet controller on a Mips Jazz board.
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Actually probing is superfluous but we're paranoid.
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1973ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int __init jazz_sonic_probe(struct platform_device *pdev)
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sonic_local *lp;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Don't probe if we're not running on a Jazz board.
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mips_machgroup != MACH_GROUP_JAZZ)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
210efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	dev = alloc_etherdev(sizeof(struct sonic_local));
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
214efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	lp = netdev_priv(dev);
2153ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	lp->device = &pdev->dev;
2163ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	SET_NETDEV_DEV(dev, &pdev->dev);
217efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain 	SET_MODULE_OWNER(dev);
218efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netdev_boot_setup_check(dev);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	if (dev->base_addr >= KSEG0) { /* Check a single specified location. */
222efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain		err = sonic_probe1(dev);
223efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	} else if (dev->base_addr != 0) { /* Don't probe at all. */
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENXIO;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; sonic_portlist[i].port; i++) {
227efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain			dev->base_addr = sonic_portlist[i].port;
228efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain			dev->irq = sonic_portlist[i].irq;
229efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain			if (sonic_probe1(dev) == 0)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!sonic_portlist[i].port)
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -ENODEV;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_netdev(dev);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out1;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	printk("%s: MAC ", dev->name);
242efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	for (i = 0; i < 6; i++) {
243efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain		printk("%2.2x", dev->dev_addr[i]);
244efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain		if (i < 5)
245efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain			printk(":");
246efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	}
247efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	printk(" IRQ %d\n", dev->irq);
248efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1:
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(dev->base_addr, SONIC_MEM_SIZE);
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
259efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn ThainMODULE_DESCRIPTION("Jazz SONIC ethernet driver");
260efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thainmodule_param(sonic_debug, int, 0);
261efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn ThainMODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631fb9df5d3069064c037c81c0ab8bf783ffa5e373Thomas Gleixner#define SONIC_IRQ_FLAG IRQF_DISABLED
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sonic.c"
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2673ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int __devexit jazz_sonic_device_remove (struct platform_device *pdev)
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2693ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	struct net_device *dev = platform_get_drvdata(pdev);
270efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	struct sonic_local* lp = netdev_priv(dev);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
272d74472f0b2553e59eafb7feee0ff9558136a17e0Finn Thain	unregister_netdev(dev);
273efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
274efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	                  lp->descriptors, lp->descriptors_laddr);
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region (dev->base_addr, SONIC_MEM_SIZE);
276d74472f0b2553e59eafb7feee0ff9558136a17e0Finn Thain	free_netdev(dev);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2813ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver jazz_sonic_driver = {
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe	= jazz_sonic_probe,
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.remove	= __devexit_p(jazz_sonic_device_remove),
2843ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver	= {
2853ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King		.name	= jazz_sonic_string,
2863ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
288efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init jazz_sonic_init_module(void)
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
291efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain	int err;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2933ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	if ((err = platform_driver_register(&jazz_sonic_driver))) {
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "Driver registration failed\n");
295efcce839360fb3a7b6dedeacaec80f68b0f2d052Finn Thain		return err;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29895cb5d954ee656a0b048ea2298188569e0759336Russell King	jazz_sonic_device = platform_device_alloc(jazz_sonic_string, 0);
29923c2a7b5dea983c7cee2813817409552f9714e95Ralf Baechle	if (!jazz_sonic_device)
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_unregister;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30295cb5d954ee656a0b048ea2298188569e0759336Russell King	if (platform_device_add(jazz_sonic_device)) {
30395cb5d954ee656a0b048ea2298188569e0759336Russell King		platform_device_put(jazz_sonic_device);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jazz_sonic_device = NULL;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_unregister:
310ee7ebdf40260c6c5586f20cda5d253bc988e7baaRalf Baechle	platform_driver_unregister(&jazz_sonic_driver);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOMEM;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit jazz_sonic_cleanup_module(void)
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3173ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_driver_unregister(&jazz_sonic_driver);
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (jazz_sonic_device) {
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		platform_device_unregister(jazz_sonic_device);
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		jazz_sonic_device = NULL;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(jazz_sonic_init_module);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(jazz_sonic_cleanup_module);
327