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