jazzsonic.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 307 行
C
307 行
/* * sonic.c * * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de) * * This driver is based on work from Andreas Busse, but most of * the code is rewritten. * * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de) * * A driver for the onboard Sonic ethernet controller on Mips Jazz * systems (Acer Pica-61, Mips Magnum 4000, Olivetti M700 and * perhaps others, too) */#include <linux/kernel.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <asm/bootinfo.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/pgtable.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/jazz.h>#include <asm/jazzdma.h>#define DRV_NAME "jazzsonic"#define SREGS_PAD(n) u16 n;#include "sonic.h"/* * Macros to access SONIC registers */#define SONIC_READ(reg) (*((volatile unsigned int *)base_addr+reg))#define SONIC_WRITE(reg,val) \do { \ *((volatile unsigned int *)base_addr+reg) = val; \}/* use 0 for production, 1 for verification, >2 for debug */#ifdef SONIC_DEBUGstatic unsigned int sonic_debug = SONIC_DEBUG;#else static unsigned int sonic_debug = 1;#endif/* * Base address and interrupt of the SONIC controller on JAZZ boards */static struct { unsigned int port; unsigned int irq;} sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}};/* * We cannot use station (ethernet) address prefixes to detect the * sonic controller since these are board manufacturer depended. * So we check for known Silicon Revision IDs instead. */static unsigned short known_revisions[] ={ 0x04, /* Mips Magnum 4000 */ 0xffff /* end of list */};/* Index to functions, as function prototypes. */static int sonic_probe1(struct net_device *dev, unsigned int base_addr, unsigned int irq);/* * Probe for a SONIC ethernet controller on a Mips Jazz board. * Actually probing is superfluous but we're paranoid. */struct net_device * __init sonic_probe(int unit){ struct net_device *dev; struct sonic_local *lp; unsigned int base_addr; int err = 0; int i; /* * Don't probe if we're not running on a Jazz board. */ if (mips_machgroup != MACH_GROUP_JAZZ) return ERR_PTR(-ENODEV); dev = alloc_etherdev(0); if (!dev) return ERR_PTR(-ENOMEM); sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); base_addr = dev->base_addr; if (base_addr >= KSEG0) { /* Check a single specified location. */ err = sonic_probe1(dev, base_addr, dev->irq); } else if (base_addr != 0) { /* Don't probe at all. */ err = -ENXIO; } else { for (i = 0; sonic_portlist[i].port; i++) { int io = sonic_portlist[i].port; if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0) break; } if (!sonic_portlist[i].port) err = -ENODEV; } if (err) goto out; err = register_netdev(dev); if (err) goto out1; return dev;out1: lp = dev->priv; vdma_free(lp->rba_laddr); kfree(lp->rba); vdma_free(lp->cda_laddr); kfree(lp); release_region(dev->base_addr, 0x100);out: free_netdev(dev); return ERR_PTR(err);}static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr, unsigned int irq){ static unsigned version_printed; unsigned int silicon_revision; unsigned int val; struct sonic_local *lp; int err = -ENODEV; int i; if (!request_region(base_addr, 0x100, DRV_NAME)) return -EBUSY; /* * get the Silicon Revision ID. If this is one of the known * one assume that we found a SONIC ethernet controller at * the expected location. */ silicon_revision = SONIC_READ(SONIC_SR); if (sonic_debug > 1) printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision); i = 0; while (known_revisions[i] != 0xffff && known_revisions[i] != silicon_revision) i++; if (known_revisions[i] == 0xffff) { printk("SONIC ethernet controller not found (0x%4x)\n", silicon_revision); goto out; } if (sonic_debug && version_printed++ == 0) printk(version); printk("%s: Sonic ethernet found at 0x%08lx, ", dev->name, base_addr); /* Fill in the 'dev' fields. */ dev->base_addr = base_addr; dev->irq = irq; /* * Put the sonic into software reset, then * retrieve and print the ethernet address. */ SONIC_WRITE(SONIC_CMD,SONIC_CR_RST); SONIC_WRITE(SONIC_CEP,0); for (i=0; i<3; i++) { val = SONIC_READ(SONIC_CAP0-i); dev->dev_addr[i*2] = val; dev->dev_addr[i*2+1] = val >> 8; } printk("HW Address "); for (i = 0; i < 6; i++) { printk("%2.2x", dev->dev_addr[i]); if (i<5) printk(":"); } printk(" IRQ %d\n", irq); err = -ENOMEM; /* Initialize the device structure. */ if (dev->priv == NULL) { /* * the memory be located in the same 64kb segment */ lp = NULL; i = 0; do { lp = kmalloc(sizeof(*lp), GFP_KERNEL); if ((unsigned long) lp >> 16 != ((unsigned long)lp + sizeof(*lp) ) >> 16) { /* FIXME, free the memory later */ kfree(lp); lp = NULL; } } while (lp == NULL && i++ < 20); if (lp == NULL) { printk("%s: couldn't allocate memory for descriptors\n", dev->name); goto out; } memset(lp, 0, sizeof(struct sonic_local)); /* get the virtual dma address */ lp->cda_laddr = vdma_alloc(PHYSADDR(lp),sizeof(*lp)); if (lp->cda_laddr == ~0UL) { printk("%s: couldn't get DMA page entry for " "descriptors\n", dev->name); goto out1; } lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda); lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda); lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra); /* allocate receive buffer area */ /* FIXME, maybe we should use skbs */ lp->rba = kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL); if (!lp->rba) { printk("%s: couldn't allocate receive buffers\n", dev->name); goto out2; } /* get virtual dma address */ lp->rba_laddr = vdma_alloc(PHYSADDR(lp->rba), SONIC_NUM_RRS * SONIC_RBSIZE); if (lp->rba_laddr == ~0UL) { printk("%s: couldn't get DMA page entry for receive " "buffers\n",dev->name); goto out3; } /* now convert pointer to KSEG1 pointer */ lp->rba = (char *)KSEG1ADDR(lp->rba); flush_cache_all(); dev->priv = (struct sonic_local *)KSEG1ADDR(lp); } lp = (struct sonic_local *)dev->priv; dev->open = sonic_open; dev->stop = sonic_close; dev->hard_start_xmit = sonic_send_packet; dev->get_stats = sonic_get_stats; dev->set_multicast_list = &sonic_multicast_list; dev->watchdog_timeo = TX_TIMEOUT; /* * clear tally counter */ SONIC_WRITE(SONIC_CRCT,0xffff); SONIC_WRITE(SONIC_FAET,0xffff); SONIC_WRITE(SONIC_MPT,0xffff); return 0;out3: kfree(lp->rba);out2: vdma_free(lp->cda_laddr);out1: kfree(lp);out: release_region(base_addr, 0x100); return err;}/* * SONIC uses a normal IRQ */#define sonic_request_irq request_irq#define sonic_free_irq free_irq#define sonic_chiptomem(x) KSEG1ADDR(vdma_log2phys(x))#include "sonic.c"
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?