*sonic/natsemi/ns83829: Move the National Semi-conductor drivers

Move the National Semi-conductor drivers into drivers/net/ethernet/natsemi/
and make the necessary Kconfig and Makefile changes.  Also moved the 8390
(National Semi-conductor) devices as a sub-menu of National Semi-conductor
devices.

- moved the ibmlana driver as well into this directory since it is a
  "SONIC" driver

CC: Alfred Arnold <alfred.arnold@lancom.de>
CC: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
CC: Harald Welte <laforge@gnumonks.org>
CC: Tim Hockin <thockin@hockin.org>
CC: <linux-ns83820@kvack.org>
CC: Kevin Chea <kchea@yahoo.com>
CC: Marc Gauthier <marc@linux-xtensa.org>
CC: Chris Zankel <chris@zankel.net>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Acked-by: Marc Gauthier <marc@tensilica.com>
This commit is contained in:
Jeff Kirsher
2011-05-18 05:14:22 -07:00
parent 8fb6b09081
commit d9fb9f3842
17 changed files with 101 additions and 75 deletions

View File

@@ -4,9 +4,10 @@
config NET_VENDOR_8390
bool "National Semi-conductor 8390 devices"
depends on AMIGA_PCMCIA || PCI || SUPERH || ISA || MCA || EISA || \
MAC || M32R || MACH_TX49XX || MCA_LEGACY || H8300 || \
ARM || MIPS || ZORRO || PCMCIA || EXPERIMENTAL
depends on NET_VENDOR_NATSEMI && (AMIGA_PCMCIA || PCI || SUPERH || \
ISA || MCA || EISA || MAC || M32R || MACH_TX49XX || \
MCA_LEGACY || H8300 || ARM || MIPS || ZORRO || PCMCIA || \
EXPERIMENTAL)
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from

View File

@@ -12,7 +12,6 @@ menuconfig ETHERNET
if ETHERNET
source "drivers/net/ethernet/3com/Kconfig"
source "drivers/net/ethernet/8390/Kconfig"
source "drivers/net/ethernet/amd/Kconfig"
source "drivers/net/ethernet/apple/Kconfig"
source "drivers/net/ethernet/broadcom/Kconfig"
@@ -26,6 +25,8 @@ source "drivers/net/ethernet/intel/Kconfig"
source "drivers/net/ethernet/i825xx/Kconfig"
source "drivers/net/ethernet/mellanox/Kconfig"
source "drivers/net/ethernet/myricom/Kconfig"
source "drivers/net/ethernet/natsemi/Kconfig"
source "drivers/net/ethernet/8390/Kconfig"
source "drivers/net/ethernet/pasemi/Kconfig"
source "drivers/net/ethernet/qlogic/Kconfig"
source "drivers/net/ethernet/racal/Kconfig"

View File

@@ -17,6 +17,7 @@ obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/
obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/
obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/
obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/
obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
obj-$(CONFIG_NET_VENDOR_RACAL) += racal/

View File

@@ -0,0 +1,82 @@
#
# National Semi-conductor device configuration
#
config NET_VENDOR_NATSEMI
bool "National Semi-conductor devices"
depends on MCA || MAC || MACH_JAZZ || PCI || XTENSA_PLATFORM_XT2000
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about National Semi-conductor devices. If you say Y,
you will be asked for your specific card in the following questions.
if NET_VENDOR_NATSEMI
config IBMLANA
tristate "IBM LAN Adapter/A support"
depends on MCA
---help---
This is a Micro Channel Ethernet adapter. You need to set
CONFIG_MCA to use this driver. It is both available as an in-kernel
driver and as a module.
To compile this driver as a module, choose M here. The only
currently supported card is the IBM LAN Adapter/A for Ethernet. It
will both support 16K and 32K memory windows, however a 32K window
gives a better security against packet losses. Usage of multiple
boards with this driver should be possible, but has not been tested
up to now due to lack of hardware.
config MACSONIC
tristate "Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)"
depends on MAC
---help---
Support for NatSemi SONIC based Ethernet devices. This includes
the onboard Ethernet in many Quadras as well as some LC-PDS,
a few Nubus and all known Comm Slot Ethernet cards. If you have
one of these say Y and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. This module will
be called macsonic.
config MIPS_JAZZ_SONIC
tristate "MIPS JAZZ onboard SONIC Ethernet support"
depends on MACH_JAZZ
---help---
This is the driver for the onboard card of MIPS Magnum 4000,
Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
config NATSEMI
tristate "National Semiconductor DP8381x series PCI Ethernet support"
depends on PCI
select CRC32
---help---
This driver is for the National Semiconductor DP83810 series,
which is used in cards from PureData, NetGear, Linksys
and others, including the 83815 chip.
More specific information and updates are available from
<http://www.scyld.com/network/natsemi.html>.
config NS83820
tristate "National Semiconductor DP83820 support"
depends on PCI
---help---
This is a driver for the National Semiconductor DP83820 series
of gigabit ethernet MACs. Cards using this chipset include
the D-Link DGE-500T, PureData's PDP8023Z-TG, SMC's SMC9462TX,
SOHO-GA2000T, SOHO-GA2500T. The driver supports the use of
zero copy.
config XTENSA_XT2000_SONIC
tristate "Xtensa XT2000 onboard SONIC Ethernet support"
depends on XTENSA_PLATFORM_XT2000
---help---
This is the driver for the onboard card of the Xtensa XT2000 board.
endif # NET_VENDOR_NATSEMI

View File

@@ -0,0 +1,10 @@
#
# Makefile for the National Semi-conductor Sonic devices.
#
obj-$(CONFIG_IBMLANA) += ibmlana.o
obj-$(CONFIG_MACSONIC) += macsonic.o
obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
obj-$(CONFIG_NATSEMI) += natsemi.o
obj-$(CONFIG_NS83820) += ns83820.o
obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,278 @@
#ifndef _IBM_LANA_INCLUDE_
#define _IBM_LANA_INCLUDE_
#ifdef _IBM_LANA_DRIVER_
/* maximum packet size */
#define PKTSIZE 1524
/* number of transmit buffers */
#define TXBUFCNT 4
/* Adapter ID's */
#define IBM_LANA_ID 0xffe0
/* media enumeration - defined in a way that it fits onto the LAN/A's
POS registers... */
typedef enum {
Media_10BaseT, Media_10Base5,
Media_Unknown, Media_10Base2, Media_Count
} ibmlana_medium;
/* private structure */
typedef struct {
unsigned int slot; /* MCA-Slot-# */
int realirq; /* memorizes actual IRQ, even when
currently not allocated */
ibmlana_medium medium; /* physical cannector */
u32 tdastart, txbufstart, /* addresses */
rrastart, rxbufstart, rdastart, rxbufcnt, txusedcnt;
int nextrxdescr, /* next rx descriptor to be used */
lastrxdescr, /* last free rx descriptor */
nexttxdescr, /* last tx descriptor to be used */
currtxdescr, /* tx descriptor currently tx'ed */
txused[TXBUFCNT]; /* busy flags */
void __iomem *base;
spinlock_t lock;
} ibmlana_priv;
/* this card uses quite a lot of I/O ports...luckily the MCA bus decodes
a full 64K I/O range... */
#define IBM_LANA_IORANGE 0xa0
/* Command Register: */
#define SONIC_CMDREG 0x00
#define CMDREG_HTX 0x0001 /* halt transmission */
#define CMDREG_TXP 0x0002 /* start transmission */
#define CMDREG_RXDIS 0x0004 /* disable receiver */
#define CMDREG_RXEN 0x0008 /* enable receiver */
#define CMDREG_STP 0x0010 /* stop timer */
#define CMDREG_ST 0x0020 /* start timer */
#define CMDREG_RST 0x0080 /* software reset */
#define CMDREG_RRRA 0x0100 /* force SONIC to read first RRA */
#define CMDREG_LCAM 0x0200 /* force SONIC to read CAM descrs */
/* Data Configuration Register */
#define SONIC_DCREG 0x02
#define DCREG_EXBUS 0x8000 /* Extended Bus Mode */
#define DCREG_LBR 0x2000 /* Latched Bus Retry */
#define DCREG_PO1 0x1000 /* Programmable Outputs */
#define DCREG_PO0 0x0800
#define DCREG_SBUS 0x0400 /* Synchronous Bus Mode */
#define DCREG_USR1 0x0200 /* User Definable Pins */
#define DCREG_USR0 0x0100
#define DCREG_WC0 0x0000 /* 0..3 Wait States */
#define DCREG_WC1 0x0040
#define DCREG_WC2 0x0080
#define DCREG_WC3 0x00c0
#define DCREG_DW16 0x0000 /* 16 bit Bus Mode */
#define DCREG_DW32 0x0020 /* 32 bit Bus Mode */
#define DCREG_BMS 0x0010 /* Block Mode Select */
#define DCREG_RFT4 0x0000 /* 4/8/16/24 bytes RX Threshold */
#define DCREG_RFT8 0x0004
#define DCREG_RFT16 0x0008
#define DCREG_RFT24 0x000c
#define DCREG_TFT8 0x0000 /* 8/16/24/28 bytes TX Threshold */
#define DCREG_TFT16 0x0001
#define DCREG_TFT24 0x0002
#define DCREG_TFT28 0x0003
/* Receive Control Register */
#define SONIC_RCREG 0x04
#define RCREG_ERR 0x8000 /* accept damaged and collided pkts */
#define RCREG_RNT 0x4000 /* accept packets that are < 64 */
#define RCREG_BRD 0x2000 /* accept broadcasts */
#define RCREG_PRO 0x1000 /* promiscuous mode */
#define RCREG_AMC 0x0800 /* accept all multicasts */
#define RCREG_LB_NONE 0x0000 /* no loopback */
#define RCREG_LB_MAC 0x0200 /* MAC loopback */
#define RCREG_LB_ENDEC 0x0400 /* ENDEC loopback */
#define RCREG_LB_XVR 0x0600 /* Transceiver loopback */
#define RCREG_MC 0x0100 /* Multicast received */
#define RCREG_BC 0x0080 /* Broadcast received */
#define RCREG_LPKT 0x0040 /* last packet in RBA */
#define RCREG_CRS 0x0020 /* carrier sense present */
#define RCREG_COL 0x0010 /* recv'd packet with collision */
#define RCREG_CRCR 0x0008 /* recv'd packet with CRC error */
#define RCREG_FAER 0x0004 /* recv'd packet with inv. framing */
#define RCREG_LBK 0x0002 /* recv'd loopback packet */
#define RCREG_PRX 0x0001 /* recv'd packet is OK */
/* Transmit Control Register */
#define SONIC_TCREG 0x06
#define TCREG_PINT 0x8000 /* generate interrupt after TDA read */
#define TCREG_POWC 0x4000 /* timer start out of window detect */
#define TCREG_CRCI 0x2000 /* inhibit CRC generation */
#define TCREG_EXDIS 0x1000 /* disable excessive deferral timer */
#define TCREG_EXD 0x0400 /* excessive deferral occurred */
#define TCREG_DEF 0x0200 /* single deferral occurred */
#define TCREG_NCRS 0x0100 /* no carrier detected */
#define TCREG_CRSL 0x0080 /* carrier lost */
#define TCREG_EXC 0x0040 /* excessive collisions occurred */
#define TCREG_OWC 0x0020 /* out of window collision occurred */
#define TCREG_PMB 0x0008 /* packet monitored bad */
#define TCREG_FU 0x0004 /* FIFO underrun */
#define TCREG_BCM 0x0002 /* byte count mismatch of fragments */
#define TCREG_PTX 0x0001 /* packet transmitted OK */
/* Interrupt Mask Register */
#define SONIC_IMREG 0x08
#define IMREG_BREN 0x4000 /* interrupt when bus retry occurred */
#define IMREG_HBLEN 0x2000 /* interrupt when heartbeat lost */
#define IMREG_LCDEN 0x1000 /* interrupt when CAM loaded */
#define IMREG_PINTEN 0x0800 /* interrupt when PINT in TDA set */
#define IMREG_PRXEN 0x0400 /* interrupt when packet received */
#define IMREG_PTXEN 0x0200 /* interrupt when packet was sent */
#define IMREG_TXEREN 0x0100 /* interrupt when send failed */
#define IMREG_TCEN 0x0080 /* interrupt when timer completed */
#define IMREG_RDEEN 0x0040 /* interrupt when RDA exhausted */
#define IMREG_RBEEN 0x0020 /* interrupt when RBA exhausted */
#define IMREG_RBAEEN 0x0010 /* interrupt when RBA too short */
#define IMREG_CRCEN 0x0008 /* interrupt when CRC counter rolls */
#define IMREG_FAEEN 0x0004 /* interrupt when FAE counter rolls */
#define IMREG_MPEN 0x0002 /* interrupt when MP counter rolls */
#define IMREG_RFOEN 0x0001 /* interrupt when Rx FIFO overflows */
/* Interrupt Status Register */
#define SONIC_ISREG 0x0a
#define ISREG_BR 0x4000 /* bus retry occurred */
#define ISREG_HBL 0x2000 /* heartbeat lost */
#define ISREG_LCD 0x1000 /* CAM loaded */
#define ISREG_PINT 0x0800 /* PINT in TDA set */
#define ISREG_PKTRX 0x0400 /* packet received */
#define ISREG_TXDN 0x0200 /* packet was sent */
#define ISREG_TXER 0x0100 /* send failed */
#define ISREG_TC 0x0080 /* timer completed */
#define ISREG_RDE 0x0040 /* RDA exhausted */
#define ISREG_RBE 0x0020 /* RBA exhausted */
#define ISREG_RBAE 0x0010 /* RBA too short for received frame */
#define ISREG_CRC 0x0008 /* CRC counter rolls over */
#define ISREG_FAE 0x0004 /* FAE counter rolls over */
#define ISREG_MP 0x0002 /* MP counter rolls over */
#define ISREG_RFO 0x0001 /* Rx FIFO overflows */
#define SONIC_UTDA 0x0c /* current transmit descr address */
#define SONIC_CTDA 0x0e
#define SONIC_URDA 0x1a /* current receive descr address */
#define SONIC_CRDA 0x1c
#define SONIC_CRBA0 0x1e /* current receive buffer address */
#define SONIC_CRBA1 0x20
#define SONIC_RBWC0 0x22 /* word count in receive buffer */
#define SONIC_RBWC1 0x24
#define SONIC_EOBC 0x26 /* minimum space to be free in RBA */
#define SONIC_URRA 0x28 /* upper address of CDA & Recv Area */
#define SONIC_RSA 0x2a /* start of receive resource area */
#define SONIC_REA 0x2c /* end of receive resource area */
#define SONIC_RRP 0x2e /* resource read pointer */
#define SONIC_RWP 0x30 /* resource write pointer */
#define SONIC_CAMEPTR 0x42 /* CAM entry pointer */
#define SONIC_CAMADDR2 0x44 /* CAM address ports */
#define SONIC_CAMADDR1 0x46
#define SONIC_CAMADDR0 0x48
#define SONIC_CAMPTR 0x4c /* lower address of CDA */
#define SONIC_CAMCNT 0x4e /* # of CAM descriptors to load */
/* Data Configuration Register 2 */
#define SONIC_DCREG2 0x7e
#define DCREG2_EXPO3 0x8000 /* extended programmable outputs */
#define DCREG2_EXPO2 0x4000
#define DCREG2_EXPO1 0x2000
#define DCREG2_EXPO0 0x1000
#define DCREG2_HD 0x0800 /* heartbeat disable */
#define DCREG2_JD 0x0200 /* jabber timer disable */
#define DCREG2_AUTO 0x0100 /* enable AUI/TP auto selection */
#define DCREG2_XWRAP 0x0040 /* TP transceiver loopback */
#define DCREG2_PH 0x0010 /* HOLD request timing */
#define DCREG2_PCM 0x0004 /* packet compress when matched */
#define DCREG2_PCNM 0x0002 /* packet compress when not matched */
#define DCREG2_RJCM 0x0001 /* inverse packet match via CAM */
/* Board Control Register: Enable RAM, Interrupts... */
#define BCMREG 0x80
#define BCMREG_RAMEN 0x80 /* switch over to RAM */
#define BCMREG_IPEND 0x40 /* interrupt pending ? */
#define BCMREG_RESET 0x08 /* reset board */
#define BCMREG_16BIT 0x04 /* adapter in 16-bit slot */
#define BCMREG_RAMWIN 0x02 /* enable RAM window */
#define BCMREG_IEN 0x01 /* interrupt enable */
/* MAC Address PROM */
#define MACADDRPROM 0x92
/* structure of a CAM entry */
typedef struct {
u32 index; /* pointer into CAM area */
u32 addr0; /* address part (bits 0..15 used) */
u32 addr1;
u32 addr2;
} camentry_t;
/* structure of a receive resource */
typedef struct {
u32 startlo; /* start address (bits 0..15 used) */
u32 starthi;
u32 cntlo; /* size in 16-bit quantities */
u32 cnthi;
} rra_t;
/* structure of a receive descriptor */
typedef struct {
u32 status; /* packet status */
u32 length; /* length in bytes */
u32 startlo; /* start address */
u32 starthi;
u32 seqno; /* frame sequence */
u32 link; /* pointer to next descriptor */
/* bit 0 = EOL */
u32 inuse; /* !=0 --> free for SONIC to write */
} rda_t;
/* structure of a transmit descriptor */
typedef struct {
u32 status; /* transmit status */
u32 config; /* value for TCR */
u32 length; /* total length */
u32 fragcount; /* number of fragments */
u32 startlo; /* start address of fragment */
u32 starthi;
u32 fraglength; /* length of this fragment */
/* more address/length triplets may */
/* follow here */
u32 link; /* pointer to next descriptor */
/* bit 0 = EOL */
} tda_t;
#endif /* _IBM_LANA_DRIVER_ */
#endif /* _IBM_LANA_INCLUDE_ */

View File

@@ -0,0 +1,308 @@
/*
* jazzsonic.c
*
* (C) 2005 Finn Thain
*
* Converted to DMA API, and (from the mac68k project) introduced
* dhd's support for 16-bit cards.
*
* (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/module.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/gfp.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/in.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 <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/jazz.h>
#include <asm/jazzdma.h>
static char jazz_sonic_string[] = "jazzsonic";
#define SONIC_MEM_SIZE 0x100
#include "sonic.h"
/*
* Macros to access SONIC registers
*/
#define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg))
#define SONIC_WRITE(reg,val) \
do { \
*((volatile unsigned int *)dev->base_addr+(reg)) = (val); \
} while (0)
/* use 0 for production, 1 for verification, >1 for debug */
#ifdef SONIC_DEBUG
static unsigned int sonic_debug = SONIC_DEBUG;
#else
static unsigned int sonic_debug = 1;
#endif
/*
* 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 */
};
static int jazzsonic_open(struct net_device* dev)
{
int retval;
retval = request_irq(dev->irq, sonic_interrupt, IRQF_DISABLED,
"sonic", dev);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
dev->name, dev->irq);
return retval;
}
retval = sonic_open(dev);
if (retval)
free_irq(dev->irq, dev);
return retval;
}
static int jazzsonic_close(struct net_device* dev)
{
int err;
err = sonic_close(dev);
free_irq(dev->irq, dev);
return err;
}
static const struct net_device_ops sonic_netdev_ops = {
.ndo_open = jazzsonic_open,
.ndo_stop = jazzsonic_close,
.ndo_start_xmit = sonic_send_packet,
.ndo_get_stats = sonic_get_stats,
.ndo_set_multicast_list = sonic_multicast_list,
.ndo_tx_timeout = sonic_tx_timeout,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
};
static int __devinit sonic_probe1(struct net_device *dev)
{
static unsigned version_printed;
unsigned int silicon_revision;
unsigned int val;
struct sonic_local *lp = netdev_priv(dev);
int err = -ENODEV;
int i;
if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
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(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ",
dev_name(lp->device), dev->base_addr);
/*
* 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;
}
err = -ENOMEM;
/* Initialize the device structure. */
lp->dma_bitmode = SONIC_BITMODE32;
/* Allocate the entire chunk of memory for the descriptors.
Note that this cannot cross a 64K boundary. */
if ((lp->descriptors = dma_alloc_coherent(lp->device,
SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
&lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n",
dev_name(lp->device));
goto out;
}
/* Now set up the pointers to point to the appropriate places */
lp->cda = lp->descriptors;
lp->tda = lp->cda + (SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->cda_laddr = lp->descriptors_laddr;
lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
dev->netdev_ops = &sonic_netdev_ops;
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;
out:
release_mem_region(dev->base_addr, SONIC_MEM_SIZE);
return err;
}
/*
* Probe for a SONIC ethernet controller on a Mips Jazz board.
* Actually probing is superfluous but we're paranoid.
*/
static int __devinit jazz_sonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
struct resource *res;
int err = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
dev = alloc_etherdev(sizeof(struct sonic_local));
if (!dev)
return -ENOMEM;
lp = netdev_priv(dev);
lp->device = &pdev->dev;
SET_NETDEV_DEV(dev, &pdev->dev);
platform_set_drvdata(pdev, dev);
netdev_boot_setup_check(dev);
dev->base_addr = res->start;
dev->irq = platform_get_irq(pdev, 0);
err = sonic_probe1(dev);
if (err)
goto out;
err = register_netdev(dev);
if (err)
goto out1;
printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq);
return 0;
out1:
release_mem_region(dev->base_addr, SONIC_MEM_SIZE);
out:
free_netdev(dev);
return err;
}
MODULE_DESCRIPTION("Jazz SONIC ethernet driver");
module_param(sonic_debug, int, 0);
MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
MODULE_ALIAS("platform:jazzsonic");
#include "sonic.c"
static int __devexit jazz_sonic_device_remove (struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct sonic_local* lp = netdev_priv(dev);
unregister_netdev(dev);
dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
lp->descriptors, lp->descriptors_laddr);
release_mem_region(dev->base_addr, SONIC_MEM_SIZE);
free_netdev(dev);
return 0;
}
static struct platform_driver jazz_sonic_driver = {
.probe = jazz_sonic_probe,
.remove = __devexit_p(jazz_sonic_device_remove),
.driver = {
.name = jazz_sonic_string,
.owner = THIS_MODULE,
},
};
static int __init jazz_sonic_init_module(void)
{
return platform_driver_register(&jazz_sonic_driver);
}
static void __exit jazz_sonic_cleanup_module(void)
{
platform_driver_unregister(&jazz_sonic_driver);
}
module_init(jazz_sonic_init_module);
module_exit(jazz_sonic_cleanup_module);

View File

@@ -0,0 +1,666 @@
/*
* macsonic.c
*
* (C) 2005 Finn Thain
*
* Converted to DMA API, converted to unified driver model, made it work as
* a module again, and from the mac68k project, introduced more 32-bit cards
* and dhd's support for 16-bit cards.
*
* (C) 1998 Alan Cox
*
* Debugging Andreas Ehliar, Michael Schmitz
*
* Based on code
* (C) 1996 by Thomas Bogendoerfer (tsbogend@bigbug.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 Mac onboard Sonic ethernet chip.
*
* 98/12/21 MSch: judged from tests on Q800, it's basically working,
* but eating up both receive and transmit resources
* and duplicating packets. Needs more testing.
*
* 99/01/03 MSch: upgraded to version 0.92 of the core driver, fixed.
*
* 00/10/31 sammy@oh.verio.com: Updated driver for 2.4 kernels, fixed problems
* on centris.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/gfp.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/nubus.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/bitrev.h>
#include <linux/slab.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/hwtest.h>
#include <asm/dma.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/mac_via.h>
static char mac_sonic_string[] = "macsonic";
#include "sonic.h"
/* These should basically be bus-size and endian independent (since
the SONIC is at least smart enough that it uses the same endianness
as the host, unlike certain less enlightened Macintosh NICs) */
#define SONIC_READ(reg) (nubus_readw(dev->base_addr + (reg * 4) \
+ lp->reg_offset))
#define SONIC_WRITE(reg,val) (nubus_writew(val, dev->base_addr + (reg * 4) \
+ lp->reg_offset))
/* use 0 for production, 1 for verification, >1 for debug */
#ifdef SONIC_DEBUG
static unsigned int sonic_debug = SONIC_DEBUG;
#else
static unsigned int sonic_debug = 1;
#endif
static int sonic_version_printed;
/* For onboard SONIC */
#define ONBOARD_SONIC_REGISTERS 0x50F0A000
#define ONBOARD_SONIC_PROM_BASE 0x50f08000
enum macsonic_type {
MACSONIC_DUODOCK,
MACSONIC_APPLE,
MACSONIC_APPLE16,
MACSONIC_DAYNA,
MACSONIC_DAYNALINK
};
/* For the built-in SONIC in the Duo Dock */
#define DUODOCK_SONIC_REGISTERS 0xe10000
#define DUODOCK_SONIC_PROM_BASE 0xe12000
/* For Apple-style NuBus SONIC */
#define APPLE_SONIC_REGISTERS 0
#define APPLE_SONIC_PROM_BASE 0x40000
/* Daynalink LC SONIC */
#define DAYNALINK_PROM_BASE 0x400000
/* For Dayna-style NuBus SONIC (haven't seen one yet) */
#define DAYNA_SONIC_REGISTERS 0x180000
/* This is what OpenBSD says. However, this is definitely in NuBus
ROM space so we should be able to get it by walking the NuBus
resource directories */
#define DAYNA_SONIC_MAC_ADDR 0xffe004
#define SONIC_READ_PROM(addr) nubus_readb(prom_addr+addr)
/*
* For reversing the PROM address
*/
static inline void bit_reverse_addr(unsigned char addr[6])
{
int i;
for(i = 0; i < 6; i++)
addr[i] = bitrev8(addr[i]);
}
static irqreturn_t macsonic_interrupt(int irq, void *dev_id)
{
irqreturn_t result;
unsigned long flags;
local_irq_save(flags);
result = sonic_interrupt(irq, dev_id);
local_irq_restore(flags);
return result;
}
static int macsonic_open(struct net_device* dev)
{
int retval;
retval = request_irq(dev->irq, sonic_interrupt, IRQ_FLG_FAST,
"sonic", dev);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
dev->name, dev->irq);
goto err;
}
/* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes
* in at priority level 3. However, we sometimes get the level 2 inter-
* rupt as well, which must prevent re-entrance of the sonic handler.
*/
if (dev->irq == IRQ_AUTO_3) {
retval = request_irq(IRQ_NUBUS_9, macsonic_interrupt,
IRQ_FLG_FAST, "sonic", dev);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
dev->name, IRQ_NUBUS_9);
goto err_irq;
}
}
retval = sonic_open(dev);
if (retval)
goto err_irq_nubus;
return 0;
err_irq_nubus:
if (dev->irq == IRQ_AUTO_3)
free_irq(IRQ_NUBUS_9, dev);
err_irq:
free_irq(dev->irq, dev);
err:
return retval;
}
static int macsonic_close(struct net_device* dev)
{
int err;
err = sonic_close(dev);
free_irq(dev->irq, dev);
if (dev->irq == IRQ_AUTO_3)
free_irq(IRQ_NUBUS_9, dev);
return err;
}
static const struct net_device_ops macsonic_netdev_ops = {
.ndo_open = macsonic_open,
.ndo_stop = macsonic_close,
.ndo_start_xmit = sonic_send_packet,
.ndo_set_multicast_list = sonic_multicast_list,
.ndo_tx_timeout = sonic_tx_timeout,
.ndo_get_stats = sonic_get_stats,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
};
static int __devinit macsonic_init(struct net_device *dev)
{
struct sonic_local* lp = netdev_priv(dev);
/* Allocate the entire chunk of memory for the descriptors.
Note that this cannot cross a 64K boundary. */
if ((lp->descriptors = dma_alloc_coherent(lp->device,
SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
&lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n",
dev_name(lp->device));
return -ENOMEM;
}
/* Now set up the pointers to point to the appropriate places */
lp->cda = lp->descriptors;
lp->tda = lp->cda + (SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->cda_laddr = lp->descriptors_laddr;
lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
dev->netdev_ops = &macsonic_netdev_ops;
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;
}
#define INVALID_MAC(mac) (memcmp(mac, "\x08\x00\x07", 3) && \
memcmp(mac, "\x00\xA0\x40", 3) && \
memcmp(mac, "\x00\x80\x19", 3) && \
memcmp(mac, "\x00\x05\x02", 3))
static void __devinit mac_onboard_sonic_ethernet_addr(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
const int prom_addr = ONBOARD_SONIC_PROM_BASE;
unsigned short val;
/*
* On NuBus boards we can sometimes look in the ROM resources.
* No such luck for comm-slot/onboard.
* On the PowerBook 520, the PROM base address is a mystery.
*/
if (hwreg_present((void *)prom_addr)) {
int i;
for (i = 0; i < 6; i++)
dev->dev_addr[i] = SONIC_READ_PROM(i);
if (!INVALID_MAC(dev->dev_addr))
return;
/*
* Most of the time, the address is bit-reversed. The NetBSD
* source has a rather long and detailed historical account of
* why this is so.
*/
bit_reverse_addr(dev->dev_addr);
if (!INVALID_MAC(dev->dev_addr))
return;
/*
* If we still have what seems to be a bogus address, we'll
* look in the CAM. The top entry should be ours.
*/
printk(KERN_WARNING "macsonic: MAC address in PROM seems "
"to be invalid, trying CAM\n");
} else {
printk(KERN_WARNING "macsonic: cannot read MAC address from "
"PROM, trying CAM\n");
}
/* This only works if MacOS has already initialized the card. */
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
SONIC_WRITE(SONIC_CEP, 15);
val = SONIC_READ(SONIC_CAP2);
dev->dev_addr[5] = val >> 8;
dev->dev_addr[4] = val & 0xff;
val = SONIC_READ(SONIC_CAP1);
dev->dev_addr[3] = val >> 8;
dev->dev_addr[2] = val & 0xff;
val = SONIC_READ(SONIC_CAP0);
dev->dev_addr[1] = val >> 8;
dev->dev_addr[0] = val & 0xff;
if (!INVALID_MAC(dev->dev_addr))
return;
/* Still nonsense ... messed up someplace! */
printk(KERN_WARNING "macsonic: MAC address in CAM entry 15 "
"seems invalid, will use a random MAC\n");
random_ether_addr(dev->dev_addr);
}
static int __devinit mac_onboard_sonic_probe(struct net_device *dev)
{
/* Bwahahaha */
static int once_is_more_than_enough;
struct sonic_local* lp = netdev_priv(dev);
int sr;
int commslot = 0;
if (once_is_more_than_enough)
return -ENODEV;
once_is_more_than_enough = 1;
if (!MACH_IS_MAC)
return -ENODEV;
if (macintosh_config->ether_type != MAC_ETHER_SONIC)
return -ENODEV;
printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
/* Bogus probing, on the models which may or may not have
Ethernet (BTW, the Ethernet *is* always at the same
address, and nothing else lives there, at least if Apple's
documentation is to be believed) */
if (macintosh_config->ident == MAC_MODEL_Q630 ||
macintosh_config->ident == MAC_MODEL_P588 ||
macintosh_config->ident == MAC_MODEL_P575 ||
macintosh_config->ident == MAC_MODEL_C610) {
unsigned long flags;
int card_present;
local_irq_save(flags);
card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS);
local_irq_restore(flags);
if (!card_present) {
printk("none.\n");
return -ENODEV;
}
commslot = 1;
}
printk("yes\n");
/* Danger! My arms are flailing wildly! You *must* set lp->reg_offset
* and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */
dev->base_addr = ONBOARD_SONIC_REGISTERS;
if (via_alt_mapping)
dev->irq = IRQ_AUTO_3;
else
dev->irq = IRQ_NUBUS_9;
if (!sonic_version_printed) {
printk(KERN_INFO "%s", version);
sonic_version_printed = 1;
}
printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n",
dev_name(lp->device), dev->base_addr);
/* The PowerBook's SONIC is 16 bit always. */
if (macintosh_config->ident == MAC_MODEL_PB520) {
lp->reg_offset = 0;
lp->dma_bitmode = SONIC_BITMODE16;
sr = SONIC_READ(SONIC_SR);
} else if (commslot) {
/* Some of the comm-slot cards are 16 bit. But some
of them are not. The 32-bit cards use offset 2 and
have known revisions, we try reading the revision
register at offset 2, if we don't get a known revision
we assume 16 bit at offset 0. */
lp->reg_offset = 2;
lp->dma_bitmode = SONIC_BITMODE16;
sr = SONIC_READ(SONIC_SR);
if (sr == 0x0004 || sr == 0x0006 || sr == 0x0100 || sr == 0x0101)
/* 83932 is 0x0004 or 0x0006, 83934 is 0x0100 or 0x0101 */
lp->dma_bitmode = SONIC_BITMODE32;
else {
lp->dma_bitmode = SONIC_BITMODE16;
lp->reg_offset = 0;
sr = SONIC_READ(SONIC_SR);
}
} else {
/* All onboard cards are at offset 2 with 32 bit DMA. */
lp->reg_offset = 2;
lp->dma_bitmode = SONIC_BITMODE32;
sr = SONIC_READ(SONIC_SR);
}
printk(KERN_INFO
"%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
dev_name(lp->device), sr, lp->dma_bitmode?32:16, lp->reg_offset);
#if 0 /* This is sometimes useful to find out how MacOS configured the card. */
printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", dev_name(lp->device),
SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff);
#endif
/* Software reset, then initialize control registers. */
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
SONIC_WRITE(SONIC_DCR, SONIC_DCR_EXBUS | SONIC_DCR_BMS |
SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
(lp->dma_bitmode ? SONIC_DCR_DW : 0));
/* This *must* be written back to in order to restore the
* extended programmable output bits, as it may not have been
* initialised since the hardware reset. */
SONIC_WRITE(SONIC_DCR2, 0);
/* Clear *and* disable interrupts to be on the safe side */
SONIC_WRITE(SONIC_IMR, 0);
SONIC_WRITE(SONIC_ISR, 0x7fff);
/* Now look for the MAC address. */
mac_onboard_sonic_ethernet_addr(dev);
/* Shared init code */
return macsonic_init(dev);
}
static int __devinit mac_nubus_sonic_ethernet_addr(struct net_device *dev,
unsigned long prom_addr,
int id)
{
int i;
for(i = 0; i < 6; i++)
dev->dev_addr[i] = SONIC_READ_PROM(i);
/* Some of the addresses are bit-reversed */
if (id != MACSONIC_DAYNA)
bit_reverse_addr(dev->dev_addr);
return 0;
}
static int __devinit macsonic_ident(struct nubus_dev *ndev)
{
if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC &&
ndev->dr_sw == NUBUS_DRSW_SONIC_LC)
return MACSONIC_DAYNALINK;
if (ndev->dr_hw == NUBUS_DRHW_SONIC &&
ndev->dr_sw == NUBUS_DRSW_APPLE) {
/* There has to be a better way to do this... */
if (strstr(ndev->board->name, "DuoDock"))
return MACSONIC_DUODOCK;
else
return MACSONIC_APPLE;
}
if (ndev->dr_hw == NUBUS_DRHW_SMC9194 &&
ndev->dr_sw == NUBUS_DRSW_DAYNA)
return MACSONIC_DAYNA;
if (ndev->dr_hw == NUBUS_DRHW_APPLE_SONIC_LC &&
ndev->dr_sw == 0) { /* huh? */
return MACSONIC_APPLE16;
}
return -1;
}
static int __devinit mac_nubus_sonic_probe(struct net_device *dev)
{
static int slots;
struct nubus_dev* ndev = NULL;
struct sonic_local* lp = netdev_priv(dev);
unsigned long base_addr, prom_addr;
u16 sonic_dcr;
int id = -1;
int reg_offset, dma_bitmode;
/* Find the first SONIC that hasn't been initialized already */
while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
NUBUS_TYPE_ETHERNET, ndev)) != NULL)
{
/* Have we seen it already? */
if (slots & (1<<ndev->board->slot))
continue;
slots |= 1<<ndev->board->slot;
/* Is it one of ours? */
if ((id = macsonic_ident(ndev)) != -1)
break;
}
if (ndev == NULL)
return -ENODEV;
switch (id) {
case MACSONIC_DUODOCK:
base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE;
sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 |
SONIC_DCR_TFT0;
reg_offset = 2;
dma_bitmode = SONIC_BITMODE32;
break;
case MACSONIC_APPLE:
base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0;
reg_offset = 0;
dma_bitmode = SONIC_BITMODE32;
break;
case MACSONIC_APPLE16:
base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
SONIC_DCR_PO1 | SONIC_DCR_BMS;
reg_offset = 0;
dma_bitmode = SONIC_BITMODE16;
break;
case MACSONIC_DAYNALINK:
base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE;
sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
SONIC_DCR_PO1 | SONIC_DCR_BMS;
reg_offset = 0;
dma_bitmode = SONIC_BITMODE16;
break;
case MACSONIC_DAYNA:
base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR;
sonic_dcr = SONIC_DCR_BMS |
SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1;
reg_offset = 0;
dma_bitmode = SONIC_BITMODE16;
break;
default:
printk(KERN_ERR "macsonic: WTF, id is %d\n", id);
return -ENODEV;
}
/* Danger! My arms are flailing wildly! You *must* set lp->reg_offset
* and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */
dev->base_addr = base_addr;
lp->reg_offset = reg_offset;
lp->dma_bitmode = dma_bitmode;
dev->irq = SLOT2IRQ(ndev->board->slot);
if (!sonic_version_printed) {
printk(KERN_INFO "%s", version);
sonic_version_printed = 1;
}
printk(KERN_INFO "%s: %s in slot %X\n",
dev_name(lp->device), ndev->board->name, ndev->board->slot);
printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
dev_name(lp->device), SONIC_READ(SONIC_SR), dma_bitmode?32:16, reg_offset);
#if 0 /* This is sometimes useful to find out how MacOS configured the card. */
printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", dev_name(lp->device),
SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff);
#endif
/* Software reset, then initialize control registers. */
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
SONIC_WRITE(SONIC_DCR, sonic_dcr | (dma_bitmode ? SONIC_DCR_DW : 0));
/* This *must* be written back to in order to restore the
* extended programmable output bits, since it may not have been
* initialised since the hardware reset. */
SONIC_WRITE(SONIC_DCR2, 0);
/* Clear *and* disable interrupts to be on the safe side */
SONIC_WRITE(SONIC_IMR, 0);
SONIC_WRITE(SONIC_ISR, 0x7fff);
/* Now look for the MAC address. */
if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0)
return -ENODEV;
/* Shared init code */
return macsonic_init(dev);
}
static int __devinit mac_sonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
int err;
dev = alloc_etherdev(sizeof(struct sonic_local));
if (!dev)
return -ENOMEM;
lp = netdev_priv(dev);
lp->device = &pdev->dev;
SET_NETDEV_DEV(dev, &pdev->dev);
platform_set_drvdata(pdev, dev);
/* This will catch fatal stuff like -ENOMEM as well as success */
err = mac_onboard_sonic_probe(dev);
if (err == 0)
goto found;
if (err != -ENODEV)
goto out;
err = mac_nubus_sonic_probe(dev);
if (err)
goto out;
found:
err = register_netdev(dev);
if (err)
goto out;
printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq);
return 0;
out:
free_netdev(dev);
return err;
}
MODULE_DESCRIPTION("Macintosh SONIC ethernet driver");
module_param(sonic_debug, int, 0);
MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)");
MODULE_ALIAS("platform:macsonic");
#include "sonic.c"
static int __devexit mac_sonic_device_remove (struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct sonic_local* lp = netdev_priv(dev);
unregister_netdev(dev);
dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
lp->descriptors, lp->descriptors_laddr);
free_netdev(dev);
return 0;
}
static struct platform_driver mac_sonic_driver = {
.probe = mac_sonic_probe,
.remove = __devexit_p(mac_sonic_device_remove),
.driver = {
.name = mac_sonic_string,
.owner = THIS_MODULE,
},
};
static int __init mac_sonic_init_module(void)
{
return platform_driver_register(&mac_sonic_driver);
}
static void __exit mac_sonic_cleanup_module(void)
{
platform_driver_unregister(&mac_sonic_driver);
}
module_init(mac_sonic_init_module);
module_exit(mac_sonic_cleanup_module);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,742 @@
/*
* sonic.c
*
* (C) 2005 Finn Thain
*
* Converted to DMA API, added zero-copy buffer handling, and
* (from the mac68k project) introduced dhd's support for 16-bit cards.
*
* (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)
*
* Core code included by system sonic drivers
*
* And... partially rewritten again by David Huggins-Daines in order
* to cope with screwed up Macintosh NICs that may or may not use
* 16-bit DMA.
*
* (C) 1999 David Huggins-Daines <dhd@debian.org>
*
*/
/*
* Sources: Olivetti M700-10 Risc Personal Computer hardware handbook,
* National Semiconductors data sheet for the DP83932B Sonic Ethernet
* controller, and the files "8390.c" and "skeleton.c" in this directory.
*
* Additional sources: Nat Semi data sheet for the DP83932C and Nat Semi
* Application Note AN-746, the files "lance.c" and "ibmlana.c". See also
* the NetBSD file "sys/arch/mac68k/dev/if_sn.c".
*/
/*
* Open/initialize the SONIC controller.
*
* This routine should set everything up anew at each open, even
* registers that "should" only need to be set once at boot, so that
* there is non-reboot way to recover if something goes wrong.
*/
static int sonic_open(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
int i;
if (sonic_debug > 2)
printk("sonic_open: initializing sonic driver.\n");
for (i = 0; i < SONIC_NUM_RRS; i++) {
struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2);
if (skb == NULL) {
while(i > 0) { /* free any that were allocated successfully */
i--;
dev_kfree_skb(lp->rx_skb[i]);
lp->rx_skb[i] = NULL;
}
printk(KERN_ERR "%s: couldn't allocate receive buffers\n",
dev->name);
return -ENOMEM;
}
/* align IP header unless DMA requires otherwise */
if (SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
skb_reserve(skb, 2);
lp->rx_skb[i] = skb;
}
for (i = 0; i < SONIC_NUM_RRS; i++) {
dma_addr_t laddr = dma_map_single(lp->device, skb_put(lp->rx_skb[i], SONIC_RBSIZE),
SONIC_RBSIZE, DMA_FROM_DEVICE);
if (!laddr) {
while(i > 0) { /* free any that were mapped successfully */
i--;
dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE);
lp->rx_laddr[i] = (dma_addr_t)0;
}
for (i = 0; i < SONIC_NUM_RRS; i++) {
dev_kfree_skb(lp->rx_skb[i]);
lp->rx_skb[i] = NULL;
}
printk(KERN_ERR "%s: couldn't map rx DMA buffers\n",
dev->name);
return -ENOMEM;
}
lp->rx_laddr[i] = laddr;
}
/*
* Initialize the SONIC
*/
sonic_init(dev);
netif_start_queue(dev);
if (sonic_debug > 2)
printk("sonic_open: Initialization done.\n");
return 0;
}
/*
* Close the SONIC device
*/
static int sonic_close(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
int i;
if (sonic_debug > 2)
printk("sonic_close\n");
netif_stop_queue(dev);
/*
* stop the SONIC, disable interrupts
*/
SONIC_WRITE(SONIC_IMR, 0);
SONIC_WRITE(SONIC_ISR, 0x7fff);
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
/* unmap and free skbs that haven't been transmitted */
for (i = 0; i < SONIC_NUM_TDS; i++) {
if(lp->tx_laddr[i]) {
dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE);
lp->tx_laddr[i] = (dma_addr_t)0;
}
if(lp->tx_skb[i]) {
dev_kfree_skb(lp->tx_skb[i]);
lp->tx_skb[i] = NULL;
}
}
/* unmap and free the receive buffers */
for (i = 0; i < SONIC_NUM_RRS; i++) {
if(lp->rx_laddr[i]) {
dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE);
lp->rx_laddr[i] = (dma_addr_t)0;
}
if(lp->rx_skb[i]) {
dev_kfree_skb(lp->rx_skb[i]);
lp->rx_skb[i] = NULL;
}
}
return 0;
}
static void sonic_tx_timeout(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
int i;
/*
* put the Sonic into software-reset mode and
* disable all interrupts before releasing DMA buffers
*/
SONIC_WRITE(SONIC_IMR, 0);
SONIC_WRITE(SONIC_ISR, 0x7fff);
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
/* We could resend the original skbs. Easier to re-initialise. */
for (i = 0; i < SONIC_NUM_TDS; i++) {
if(lp->tx_laddr[i]) {
dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE);
lp->tx_laddr[i] = (dma_addr_t)0;
}
if(lp->tx_skb[i]) {
dev_kfree_skb(lp->tx_skb[i]);
lp->tx_skb[i] = NULL;
}
}
/* Try to restart the adaptor. */
sonic_init(dev);
lp->stats.tx_errors++;
dev->trans_start = jiffies; /* prevent tx timeout */
netif_wake_queue(dev);
}
/*
* transmit packet
*
* Appends new TD during transmission thus avoiding any TX interrupts
* until we run out of TDs.
* This routine interacts closely with the ISR in that it may,
* set tx_skb[i]
* reset the status flags of the new TD
* set and reset EOL flags
* stop the tx queue
* The ISR interacts with this routine in various ways. It may,
* reset tx_skb[i]
* test the EOL and status flags of the TDs
* wake the tx queue
* Concurrently with all of this, the SONIC is potentially writing to
* the status flags of the TDs.
* Until some mutual exclusion is added, this code will not work with SMP. However,
* MIPS Jazz machines and m68k Macs were all uni-processor machines.
*/
static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
dma_addr_t laddr;
int length;
int entry = lp->next_tx;
if (sonic_debug > 2)
printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev);
length = skb->len;
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
return NETDEV_TX_OK;
length = ETH_ZLEN;
}
/*
* Map the packet data into the logical DMA address space
*/
laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE);
if (!laddr) {
printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name);
dev_kfree_skb(skb);
return NETDEV_TX_BUSY;
}
sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */
sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */
sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */
sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_L, laddr & 0xffff);
sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_H, laddr >> 16);
sonic_tda_put(dev, entry, SONIC_TD_FRAG_SIZE, length);
sonic_tda_put(dev, entry, SONIC_TD_LINK,
sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL);
/*
* Must set tx_skb[entry] only after clearing status, and
* before clearing EOL and before stopping queue
*/
wmb();
lp->tx_len[entry] = length;
lp->tx_laddr[entry] = laddr;
lp->tx_skb[entry] = skb;
wmb();
sonic_tda_put(dev, lp->eol_tx, SONIC_TD_LINK,
sonic_tda_get(dev, lp->eol_tx, SONIC_TD_LINK) & ~SONIC_EOL);
lp->eol_tx = entry;
lp->next_tx = (entry + 1) & SONIC_TDS_MASK;
if (lp->tx_skb[lp->next_tx] != NULL) {
/* The ring is full, the ISR has yet to process the next TD. */
if (sonic_debug > 3)
printk("%s: stopping queue\n", dev->name);
netif_stop_queue(dev);
/* after this packet, wait for ISR to free up some TDAs */
} else netif_start_queue(dev);
if (sonic_debug > 2)
printk("sonic_send_packet: issuing Tx command\n");
SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
return NETDEV_TX_OK;
}
/*
* The typical workload of the driver:
* Handle the network interface interrupts.
*/
static irqreturn_t sonic_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct sonic_local *lp = netdev_priv(dev);
int status;
if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT))
return IRQ_NONE;
do {
if (status & SONIC_INT_PKTRX) {
if (sonic_debug > 2)
printk("%s: packet rx\n", dev->name);
sonic_rx(dev); /* got packet(s) */
SONIC_WRITE(SONIC_ISR, SONIC_INT_PKTRX); /* clear the interrupt */
}
if (status & SONIC_INT_TXDN) {
int entry = lp->cur_tx;
int td_status;
int freed_some = 0;
/* At this point, cur_tx is the index of a TD that is one of:
* unallocated/freed (status set & tx_skb[entry] clear)
* allocated and sent (status set & tx_skb[entry] set )
* allocated and not yet sent (status clear & tx_skb[entry] set )
* still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear)
*/
if (sonic_debug > 2)
printk("%s: tx done\n", dev->name);
while (lp->tx_skb[entry] != NULL) {
if ((td_status = sonic_tda_get(dev, entry, SONIC_TD_STATUS)) == 0)
break;
if (td_status & 0x0001) {
lp->stats.tx_packets++;
lp->stats.tx_bytes += sonic_tda_get(dev, entry, SONIC_TD_PKTSIZE);
} else {
lp->stats.tx_errors++;
if (td_status & 0x0642)
lp->stats.tx_aborted_errors++;
if (td_status & 0x0180)
lp->stats.tx_carrier_errors++;
if (td_status & 0x0020)
lp->stats.tx_window_errors++;
if (td_status & 0x0004)
lp->stats.tx_fifo_errors++;
}
/* We must free the original skb */
dev_kfree_skb_irq(lp->tx_skb[entry]);
lp->tx_skb[entry] = NULL;
/* and unmap DMA buffer */
dma_unmap_single(lp->device, lp->tx_laddr[entry], lp->tx_len[entry], DMA_TO_DEVICE);
lp->tx_laddr[entry] = (dma_addr_t)0;
freed_some = 1;
if (sonic_tda_get(dev, entry, SONIC_TD_LINK) & SONIC_EOL) {
entry = (entry + 1) & SONIC_TDS_MASK;
break;
}
entry = (entry + 1) & SONIC_TDS_MASK;
}
if (freed_some || lp->tx_skb[entry] == NULL)
netif_wake_queue(dev); /* The ring is no longer full */
lp->cur_tx = entry;
SONIC_WRITE(SONIC_ISR, SONIC_INT_TXDN); /* clear the interrupt */
}
/*
* check error conditions
*/
if (status & SONIC_INT_RFO) {
if (sonic_debug > 1)
printk("%s: rx fifo overrun\n", dev->name);
lp->stats.rx_fifo_errors++;
SONIC_WRITE(SONIC_ISR, SONIC_INT_RFO); /* clear the interrupt */
}
if (status & SONIC_INT_RDE) {
if (sonic_debug > 1)
printk("%s: rx descriptors exhausted\n", dev->name);
lp->stats.rx_dropped++;
SONIC_WRITE(SONIC_ISR, SONIC_INT_RDE); /* clear the interrupt */
}
if (status & SONIC_INT_RBAE) {
if (sonic_debug > 1)
printk("%s: rx buffer area exceeded\n", dev->name);
lp->stats.rx_dropped++;
SONIC_WRITE(SONIC_ISR, SONIC_INT_RBAE); /* clear the interrupt */
}
/* counter overruns; all counters are 16bit wide */
if (status & SONIC_INT_FAE) {
lp->stats.rx_frame_errors += 65536;
SONIC_WRITE(SONIC_ISR, SONIC_INT_FAE); /* clear the interrupt */
}
if (status & SONIC_INT_CRC) {
lp->stats.rx_crc_errors += 65536;
SONIC_WRITE(SONIC_ISR, SONIC_INT_CRC); /* clear the interrupt */
}
if (status & SONIC_INT_MP) {
lp->stats.rx_missed_errors += 65536;
SONIC_WRITE(SONIC_ISR, SONIC_INT_MP); /* clear the interrupt */
}
/* transmit error */
if (status & SONIC_INT_TXER) {
if ((SONIC_READ(SONIC_TCR) & SONIC_TCR_FU) && (sonic_debug > 2))
printk(KERN_ERR "%s: tx fifo underrun\n", dev->name);
SONIC_WRITE(SONIC_ISR, SONIC_INT_TXER); /* clear the interrupt */
}
/* bus retry */
if (status & SONIC_INT_BR) {
printk(KERN_ERR "%s: Bus retry occurred! Device interrupt disabled.\n",
dev->name);
/* ... to help debug DMA problems causing endless interrupts. */
/* Bounce the eth interface to turn on the interrupt again. */
SONIC_WRITE(SONIC_IMR, 0);
SONIC_WRITE(SONIC_ISR, SONIC_INT_BR); /* clear the interrupt */
}
/* load CAM done */
if (status & SONIC_INT_LCD)
SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */
} while((status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT));
return IRQ_HANDLED;
}
/*
* We have a good packet(s), pass it/them up the network stack.
*/
static void sonic_rx(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
int status;
int entry = lp->cur_rx;
while (sonic_rda_get(dev, entry, SONIC_RD_IN_USE) == 0) {
struct sk_buff *used_skb;
struct sk_buff *new_skb;
dma_addr_t new_laddr;
u16 bufadr_l;
u16 bufadr_h;
int pkt_len;
status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
if (status & SONIC_RCR_PRX) {
/* Malloc up new buffer. */
new_skb = dev_alloc_skb(SONIC_RBSIZE + 2);
if (new_skb == NULL) {
printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name);
lp->stats.rx_dropped++;
break;
}
/* provide 16 byte IP header alignment unless DMA requires otherwise */
if(SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
skb_reserve(new_skb, 2);
new_laddr = dma_map_single(lp->device, skb_put(new_skb, SONIC_RBSIZE),
SONIC_RBSIZE, DMA_FROM_DEVICE);
if (!new_laddr) {
dev_kfree_skb(new_skb);
printk(KERN_ERR "%s: Failed to map rx buffer, dropping packet.\n", dev->name);
lp->stats.rx_dropped++;
break;
}
/* now we have a new skb to replace it, pass the used one up the stack */
dma_unmap_single(lp->device, lp->rx_laddr[entry], SONIC_RBSIZE, DMA_FROM_DEVICE);
used_skb = lp->rx_skb[entry];
pkt_len = sonic_rda_get(dev, entry, SONIC_RD_PKTLEN);
skb_trim(used_skb, pkt_len);
used_skb->protocol = eth_type_trans(used_skb, dev);
netif_rx(used_skb);
lp->stats.rx_packets++;
lp->stats.rx_bytes += pkt_len;
/* and insert the new skb */
lp->rx_laddr[entry] = new_laddr;
lp->rx_skb[entry] = new_skb;
bufadr_l = (unsigned long)new_laddr & 0xffff;
bufadr_h = (unsigned long)new_laddr >> 16;
sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, bufadr_l);
sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, bufadr_h);
} else {
/* This should only happen, if we enable accepting broken packets. */
lp->stats.rx_errors++;
if (status & SONIC_RCR_FAER)
lp->stats.rx_frame_errors++;
if (status & SONIC_RCR_CRCR)
lp->stats.rx_crc_errors++;
}
if (status & SONIC_RCR_LPKT) {
/*
* this was the last packet out of the current receive buffer
* give the buffer back to the SONIC
*/
lp->cur_rwp += SIZEOF_SONIC_RR * SONIC_BUS_SCALE(lp->dma_bitmode);
if (lp->cur_rwp >= lp->rra_end) lp->cur_rwp = lp->rra_laddr & 0xffff;
SONIC_WRITE(SONIC_RWP, lp->cur_rwp);
if (SONIC_READ(SONIC_ISR) & SONIC_INT_RBE) {
if (sonic_debug > 2)
printk("%s: rx buffer exhausted\n", dev->name);
SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); /* clear the flag */
}
} else
printk(KERN_ERR "%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",
dev->name);
/*
* give back the descriptor
*/
sonic_rda_put(dev, entry, SONIC_RD_LINK,
sonic_rda_get(dev, entry, SONIC_RD_LINK) | SONIC_EOL);
sonic_rda_put(dev, entry, SONIC_RD_IN_USE, 1);
sonic_rda_put(dev, lp->eol_rx, SONIC_RD_LINK,
sonic_rda_get(dev, lp->eol_rx, SONIC_RD_LINK) & ~SONIC_EOL);
lp->eol_rx = entry;
lp->cur_rx = entry = (entry + 1) & SONIC_RDS_MASK;
}
/*
* If any worth-while packets have been received, netif_rx()
* has done a mark_bh(NET_BH) for us and will work on them
* when we get to the bottom-half routine.
*/
}
/*
* Get the current statistics.
* This may be called with the device open or closed.
*/
static struct net_device_stats *sonic_get_stats(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
/* read the tally counter from the SONIC and reset them */
lp->stats.rx_crc_errors += SONIC_READ(SONIC_CRCT);
SONIC_WRITE(SONIC_CRCT, 0xffff);
lp->stats.rx_frame_errors += SONIC_READ(SONIC_FAET);
SONIC_WRITE(SONIC_FAET, 0xffff);
lp->stats.rx_missed_errors += SONIC_READ(SONIC_MPT);
SONIC_WRITE(SONIC_MPT, 0xffff);
return &lp->stats;
}
/*
* Set or clear the multicast filter for this adaptor.
*/
static void sonic_multicast_list(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
unsigned int rcr;
struct netdev_hw_addr *ha;
unsigned char *addr;
int i;
rcr = SONIC_READ(SONIC_RCR) & ~(SONIC_RCR_PRO | SONIC_RCR_AMC);
rcr |= SONIC_RCR_BRD; /* accept broadcast packets */
if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
rcr |= SONIC_RCR_PRO;
} else {
if ((dev->flags & IFF_ALLMULTI) ||
(netdev_mc_count(dev) > 15)) {
rcr |= SONIC_RCR_AMC;
} else {
if (sonic_debug > 2)
printk("sonic_multicast_list: mc_count %d\n",
netdev_mc_count(dev));
sonic_set_cam_enable(dev, 1); /* always enable our own address */
i = 1;
netdev_for_each_mc_addr(ha, dev) {
addr = ha->addr;
sonic_cda_put(dev, i, SONIC_CD_CAP0, addr[1] << 8 | addr[0]);
sonic_cda_put(dev, i, SONIC_CD_CAP1, addr[3] << 8 | addr[2]);
sonic_cda_put(dev, i, SONIC_CD_CAP2, addr[5] << 8 | addr[4]);
sonic_set_cam_enable(dev, sonic_get_cam_enable(dev) | (1 << i));
i++;
}
SONIC_WRITE(SONIC_CDC, 16);
/* issue Load CAM command */
SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);
SONIC_WRITE(SONIC_CMD, SONIC_CR_LCAM);
}
}
if (sonic_debug > 2)
printk("sonic_multicast_list: setting RCR=%x\n", rcr);
SONIC_WRITE(SONIC_RCR, rcr);
}
/*
* Initialize the SONIC ethernet controller.
*/
static int sonic_init(struct net_device *dev)
{
unsigned int cmd;
struct sonic_local *lp = netdev_priv(dev);
int i;
/*
* put the Sonic into software-reset mode and
* disable all interrupts
*/
SONIC_WRITE(SONIC_IMR, 0);
SONIC_WRITE(SONIC_ISR, 0x7fff);
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
/*
* clear software reset flag, disable receiver, clear and
* enable interrupts, then completely initialize the SONIC
*/
SONIC_WRITE(SONIC_CMD, 0);
SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS);
/*
* initialize the receive resource area
*/
if (sonic_debug > 2)
printk("sonic_init: initialize receive resource area\n");
for (i = 0; i < SONIC_NUM_RRS; i++) {
u16 bufadr_l = (unsigned long)lp->rx_laddr[i] & 0xffff;
u16 bufadr_h = (unsigned long)lp->rx_laddr[i] >> 16;
sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l);
sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h);
sonic_rra_put(dev, i, SONIC_RR_BUFSIZE_L, SONIC_RBSIZE >> 1);
sonic_rra_put(dev, i, SONIC_RR_BUFSIZE_H, 0);
}
/* initialize all RRA registers */
lp->rra_end = (lp->rra_laddr + SONIC_NUM_RRS * SIZEOF_SONIC_RR *
SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
lp->cur_rwp = (lp->rra_laddr + (SONIC_NUM_RRS - 1) * SIZEOF_SONIC_RR *
SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
SONIC_WRITE(SONIC_RSA, lp->rra_laddr & 0xffff);
SONIC_WRITE(SONIC_REA, lp->rra_end);
SONIC_WRITE(SONIC_RRP, lp->rra_laddr & 0xffff);
SONIC_WRITE(SONIC_RWP, lp->cur_rwp);
SONIC_WRITE(SONIC_URRA, lp->rra_laddr >> 16);
SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE >> 1) - (lp->dma_bitmode ? 2 : 1));
/* load the resource pointers */
if (sonic_debug > 3)
printk("sonic_init: issuing RRRA command\n");
SONIC_WRITE(SONIC_CMD, SONIC_CR_RRRA);
i = 0;
while (i++ < 100) {
if (SONIC_READ(SONIC_CMD) & SONIC_CR_RRRA)
break;
}
if (sonic_debug > 2)
printk("sonic_init: status=%x i=%d\n", SONIC_READ(SONIC_CMD), i);
/*
* Initialize the receive descriptors so that they
* become a circular linked list, ie. let the last
* descriptor point to the first again.
*/
if (sonic_debug > 2)
printk("sonic_init: initialize receive descriptors\n");
for (i=0; i<SONIC_NUM_RDS; i++) {
sonic_rda_put(dev, i, SONIC_RD_STATUS, 0);
sonic_rda_put(dev, i, SONIC_RD_PKTLEN, 0);
sonic_rda_put(dev, i, SONIC_RD_PKTPTR_L, 0);
sonic_rda_put(dev, i, SONIC_RD_PKTPTR_H, 0);
sonic_rda_put(dev, i, SONIC_RD_SEQNO, 0);
sonic_rda_put(dev, i, SONIC_RD_IN_USE, 1);
sonic_rda_put(dev, i, SONIC_RD_LINK,
lp->rda_laddr +
((i+1) * SIZEOF_SONIC_RD * SONIC_BUS_SCALE(lp->dma_bitmode)));
}
/* fix last descriptor */
sonic_rda_put(dev, SONIC_NUM_RDS - 1, SONIC_RD_LINK,
(lp->rda_laddr & 0xffff) | SONIC_EOL);
lp->eol_rx = SONIC_NUM_RDS - 1;
lp->cur_rx = 0;
SONIC_WRITE(SONIC_URDA, lp->rda_laddr >> 16);
SONIC_WRITE(SONIC_CRDA, lp->rda_laddr & 0xffff);
/*
* initialize transmit descriptors
*/
if (sonic_debug > 2)
printk("sonic_init: initialize transmit descriptors\n");
for (i = 0; i < SONIC_NUM_TDS; i++) {
sonic_tda_put(dev, i, SONIC_TD_STATUS, 0);
sonic_tda_put(dev, i, SONIC_TD_CONFIG, 0);
sonic_tda_put(dev, i, SONIC_TD_PKTSIZE, 0);
sonic_tda_put(dev, i, SONIC_TD_FRAG_COUNT, 0);
sonic_tda_put(dev, i, SONIC_TD_LINK,
(lp->tda_laddr & 0xffff) +
(i + 1) * SIZEOF_SONIC_TD * SONIC_BUS_SCALE(lp->dma_bitmode));
lp->tx_skb[i] = NULL;
}
/* fix last descriptor */
sonic_tda_put(dev, SONIC_NUM_TDS - 1, SONIC_TD_LINK,
(lp->tda_laddr & 0xffff));
SONIC_WRITE(SONIC_UTDA, lp->tda_laddr >> 16);
SONIC_WRITE(SONIC_CTDA, lp->tda_laddr & 0xffff);
lp->cur_tx = lp->next_tx = 0;
lp->eol_tx = SONIC_NUM_TDS - 1;
/*
* put our own address to CAM desc[0]
*/
sonic_cda_put(dev, 0, SONIC_CD_CAP0, dev->dev_addr[1] << 8 | dev->dev_addr[0]);
sonic_cda_put(dev, 0, SONIC_CD_CAP1, dev->dev_addr[3] << 8 | dev->dev_addr[2]);
sonic_cda_put(dev, 0, SONIC_CD_CAP2, dev->dev_addr[5] << 8 | dev->dev_addr[4]);
sonic_set_cam_enable(dev, 1);
for (i = 0; i < 16; i++)
sonic_cda_put(dev, i, SONIC_CD_ENTRY_POINTER, i);
/*
* initialize CAM registers
*/
SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);
SONIC_WRITE(SONIC_CDC, 16);
/*
* load the CAM
*/
SONIC_WRITE(SONIC_CMD, SONIC_CR_LCAM);
i = 0;
while (i++ < 100) {
if (SONIC_READ(SONIC_ISR) & SONIC_INT_LCD)
break;
}
if (sonic_debug > 2) {
printk("sonic_init: CMD=%x, ISR=%x\n, i=%d",
SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR), i);
}
/*
* enable receiver, disable loopback
* and enable all interrupts
*/
SONIC_WRITE(SONIC_CMD, SONIC_CR_RXEN | SONIC_CR_STP);
SONIC_WRITE(SONIC_RCR, SONIC_RCR_DEFAULT);
SONIC_WRITE(SONIC_TCR, SONIC_TCR_DEFAULT);
SONIC_WRITE(SONIC_ISR, 0x7fff);
SONIC_WRITE(SONIC_IMR, SONIC_IMR_DEFAULT);
cmd = SONIC_READ(SONIC_CMD);
if ((cmd & SONIC_CR_RXEN) == 0 || (cmd & SONIC_CR_STP) == 0)
printk(KERN_ERR "sonic_init: failed, status=%x\n", cmd);
if (sonic_debug > 2)
printk("sonic_init: new status=%x\n",
SONIC_READ(SONIC_CMD));
return 0;
}
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,450 @@
/*
* Header file for sonic.c
*
* (C) Waldorf Electronics, Germany
* Written by Andreas Busse
*
* NOTE: most of the structure definitions here are endian dependent.
* If you want to use this driver on big endian machines, the data
* and pad structure members must be exchanged. Also, the structures
* need to be changed accordingly to the bus size.
*
* 981229 MSch: did just that for the 68k Mac port (32 bit, big endian)
*
* 990611 David Huggins-Daines <dhd@debian.org>: This machine abstraction
* does not cope with 16-bit bus sizes very well. Therefore I have
* rewritten it with ugly macros and evil inlines.
*
* 050625 Finn Thain: introduced more 32-bit cards and dhd's support
* for 16-bit cards (from the mac68k project).
*/
#ifndef SONIC_H
#define SONIC_H
/*
* SONIC register offsets
*/
#define SONIC_CMD 0x00
#define SONIC_DCR 0x01
#define SONIC_RCR 0x02
#define SONIC_TCR 0x03
#define SONIC_IMR 0x04
#define SONIC_ISR 0x05
#define SONIC_UTDA 0x06
#define SONIC_CTDA 0x07
#define SONIC_URDA 0x0d
#define SONIC_CRDA 0x0e
#define SONIC_EOBC 0x13
#define SONIC_URRA 0x14
#define SONIC_RSA 0x15
#define SONIC_REA 0x16
#define SONIC_RRP 0x17
#define SONIC_RWP 0x18
#define SONIC_RSC 0x2b
#define SONIC_CEP 0x21
#define SONIC_CAP2 0x22
#define SONIC_CAP1 0x23
#define SONIC_CAP0 0x24
#define SONIC_CE 0x25
#define SONIC_CDP 0x26
#define SONIC_CDC 0x27
#define SONIC_WT0 0x29
#define SONIC_WT1 0x2a
#define SONIC_SR 0x28
/* test-only registers */
#define SONIC_TPS 0x08
#define SONIC_TFC 0x09
#define SONIC_TSA0 0x0a
#define SONIC_TSA1 0x0b
#define SONIC_TFS 0x0c
#define SONIC_CRBA0 0x0f
#define SONIC_CRBA1 0x10
#define SONIC_RBWC0 0x11
#define SONIC_RBWC1 0x12
#define SONIC_TTDA 0x20
#define SONIC_MDT 0x2f
#define SONIC_TRBA0 0x19
#define SONIC_TRBA1 0x1a
#define SONIC_TBWC0 0x1b
#define SONIC_TBWC1 0x1c
#define SONIC_LLFA 0x1f
#define SONIC_ADDR0 0x1d
#define SONIC_ADDR1 0x1e
/*
* Error counters
*/
#define SONIC_CRCT 0x2c
#define SONIC_FAET 0x2d
#define SONIC_MPT 0x2e
#define SONIC_DCR2 0x3f
/*
* SONIC command bits
*/
#define SONIC_CR_LCAM 0x0200
#define SONIC_CR_RRRA 0x0100
#define SONIC_CR_RST 0x0080
#define SONIC_CR_ST 0x0020
#define SONIC_CR_STP 0x0010
#define SONIC_CR_RXEN 0x0008
#define SONIC_CR_RXDIS 0x0004
#define SONIC_CR_TXP 0x0002
#define SONIC_CR_HTX 0x0001
/*
* SONIC data configuration bits
*/
#define SONIC_DCR_EXBUS 0x8000
#define SONIC_DCR_LBR 0x2000
#define SONIC_DCR_PO1 0x1000
#define SONIC_DCR_PO0 0x0800
#define SONIC_DCR_SBUS 0x0400
#define SONIC_DCR_USR1 0x0200
#define SONIC_DCR_USR0 0x0100
#define SONIC_DCR_WC1 0x0080
#define SONIC_DCR_WC0 0x0040
#define SONIC_DCR_DW 0x0020
#define SONIC_DCR_BMS 0x0010
#define SONIC_DCR_RFT1 0x0008
#define SONIC_DCR_RFT0 0x0004
#define SONIC_DCR_TFT1 0x0002
#define SONIC_DCR_TFT0 0x0001
/*
* Constants for the SONIC receive control register.
*/
#define SONIC_RCR_ERR 0x8000
#define SONIC_RCR_RNT 0x4000
#define SONIC_RCR_BRD 0x2000
#define SONIC_RCR_PRO 0x1000
#define SONIC_RCR_AMC 0x0800
#define SONIC_RCR_LB1 0x0400
#define SONIC_RCR_LB0 0x0200
#define SONIC_RCR_MC 0x0100
#define SONIC_RCR_BC 0x0080
#define SONIC_RCR_LPKT 0x0040
#define SONIC_RCR_CRS 0x0020
#define SONIC_RCR_COL 0x0010
#define SONIC_RCR_CRCR 0x0008
#define SONIC_RCR_FAER 0x0004
#define SONIC_RCR_LBK 0x0002
#define SONIC_RCR_PRX 0x0001
#define SONIC_RCR_LB_OFF 0
#define SONIC_RCR_LB_MAC SONIC_RCR_LB0
#define SONIC_RCR_LB_ENDEC SONIC_RCR_LB1
#define SONIC_RCR_LB_TRANS (SONIC_RCR_LB0 | SONIC_RCR_LB1)
/* default RCR setup */
#define SONIC_RCR_DEFAULT (SONIC_RCR_BRD)
/*
* SONIC Transmit Control register bits
*/
#define SONIC_TCR_PINTR 0x8000
#define SONIC_TCR_POWC 0x4000
#define SONIC_TCR_CRCI 0x2000
#define SONIC_TCR_EXDIS 0x1000
#define SONIC_TCR_EXD 0x0400
#define SONIC_TCR_DEF 0x0200
#define SONIC_TCR_NCRS 0x0100
#define SONIC_TCR_CRLS 0x0080
#define SONIC_TCR_EXC 0x0040
#define SONIC_TCR_PMB 0x0008
#define SONIC_TCR_FU 0x0004
#define SONIC_TCR_BCM 0x0002
#define SONIC_TCR_PTX 0x0001
#define SONIC_TCR_DEFAULT 0x0000
/*
* Constants for the SONIC_INTERRUPT_MASK and
* SONIC_INTERRUPT_STATUS registers.
*/
#define SONIC_INT_BR 0x4000
#define SONIC_INT_HBL 0x2000
#define SONIC_INT_LCD 0x1000
#define SONIC_INT_PINT 0x0800
#define SONIC_INT_PKTRX 0x0400
#define SONIC_INT_TXDN 0x0200
#define SONIC_INT_TXER 0x0100
#define SONIC_INT_TC 0x0080
#define SONIC_INT_RDE 0x0040
#define SONIC_INT_RBE 0x0020
#define SONIC_INT_RBAE 0x0010
#define SONIC_INT_CRC 0x0008
#define SONIC_INT_FAE 0x0004
#define SONIC_INT_MP 0x0002
#define SONIC_INT_RFO 0x0001
/*
* The interrupts we allow.
*/
#define SONIC_IMR_DEFAULT ( SONIC_INT_BR | \
SONIC_INT_LCD | \
SONIC_INT_RFO | \
SONIC_INT_PKTRX | \
SONIC_INT_TXDN | \
SONIC_INT_TXER | \
SONIC_INT_RDE | \
SONIC_INT_RBAE | \
SONIC_INT_CRC | \
SONIC_INT_FAE | \
SONIC_INT_MP)
#define SONIC_EOL 0x0001
#define CAM_DESCRIPTORS 16
/* Offsets in the various DMA buffers accessed by the SONIC */
#define SONIC_BITMODE16 0
#define SONIC_BITMODE32 1
#define SONIC_BUS_SCALE(bitmode) ((bitmode) ? 4 : 2)
/* Note! These are all measured in bus-size units, so use SONIC_BUS_SCALE */
#define SIZEOF_SONIC_RR 4
#define SONIC_RR_BUFADR_L 0
#define SONIC_RR_BUFADR_H 1
#define SONIC_RR_BUFSIZE_L 2
#define SONIC_RR_BUFSIZE_H 3
#define SIZEOF_SONIC_RD 7
#define SONIC_RD_STATUS 0
#define SONIC_RD_PKTLEN 1
#define SONIC_RD_PKTPTR_L 2
#define SONIC_RD_PKTPTR_H 3
#define SONIC_RD_SEQNO 4
#define SONIC_RD_LINK 5
#define SONIC_RD_IN_USE 6
#define SIZEOF_SONIC_TD 8
#define SONIC_TD_STATUS 0
#define SONIC_TD_CONFIG 1
#define SONIC_TD_PKTSIZE 2
#define SONIC_TD_FRAG_COUNT 3
#define SONIC_TD_FRAG_PTR_L 4
#define SONIC_TD_FRAG_PTR_H 5
#define SONIC_TD_FRAG_SIZE 6
#define SONIC_TD_LINK 7
#define SIZEOF_SONIC_CD 4
#define SONIC_CD_ENTRY_POINTER 0
#define SONIC_CD_CAP0 1
#define SONIC_CD_CAP1 2
#define SONIC_CD_CAP2 3
#define SIZEOF_SONIC_CDA ((CAM_DESCRIPTORS * SIZEOF_SONIC_CD) + 1)
#define SONIC_CDA_CAM_ENABLE (CAM_DESCRIPTORS * SIZEOF_SONIC_CD)
/*
* Some tunables for the buffer areas. Power of 2 is required
* the current driver uses one receive buffer for each descriptor.
*
* MSch: use more buffer space for the slow m68k Macs!
*/
#define SONIC_NUM_RRS 16 /* number of receive resources */
#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */
#define SONIC_NUM_TDS 16 /* number of transmit descriptors */
#define SONIC_RDS_MASK (SONIC_NUM_RDS-1)
#define SONIC_TDS_MASK (SONIC_NUM_TDS-1)
#define SONIC_RBSIZE 1520 /* size of one resource buffer */
/* Again, measured in bus size units! */
#define SIZEOF_SONIC_DESC (SIZEOF_SONIC_CDA \
+ (SIZEOF_SONIC_TD * SONIC_NUM_TDS) \
+ (SIZEOF_SONIC_RD * SONIC_NUM_RDS) \
+ (SIZEOF_SONIC_RR * SONIC_NUM_RRS))
/* Information that need to be kept for each board. */
struct sonic_local {
/* Bus size. 0 == 16 bits, 1 == 32 bits. */
int dma_bitmode;
/* Register offset within the longword (independent of endianness,
and varies from one type of Macintosh SONIC to another
(Aarrgh)) */
int reg_offset;
void *descriptors;
/* Crud. These areas have to be within the same 64K. Therefore
we allocate a desriptors page, and point these to places within it. */
void *cda; /* CAM descriptor area */
void *tda; /* Transmit descriptor area */
void *rra; /* Receive resource area */
void *rda; /* Receive descriptor area */
struct sk_buff* volatile rx_skb[SONIC_NUM_RRS]; /* packets to be received */
struct sk_buff* volatile tx_skb[SONIC_NUM_TDS]; /* packets to be transmitted */
unsigned int tx_len[SONIC_NUM_TDS]; /* lengths of tx DMA mappings */
/* Logical DMA addresses on MIPS, bus addresses on m68k
* (so "laddr" is a bit misleading) */
dma_addr_t descriptors_laddr;
u32 cda_laddr; /* logical DMA address of CDA */
u32 tda_laddr; /* logical DMA address of TDA */
u32 rra_laddr; /* logical DMA address of RRA */
u32 rda_laddr; /* logical DMA address of RDA */
dma_addr_t rx_laddr[SONIC_NUM_RRS]; /* logical DMA addresses of rx skbuffs */
dma_addr_t tx_laddr[SONIC_NUM_TDS]; /* logical DMA addresses of tx skbuffs */
unsigned int rra_end;
unsigned int cur_rwp;
unsigned int cur_rx;
unsigned int cur_tx; /* first unacked transmit packet */
unsigned int eol_rx;
unsigned int eol_tx; /* last unacked transmit packet */
unsigned int next_tx; /* next free TD */
struct device *device; /* generic device */
struct net_device_stats stats;
};
#define TX_TIMEOUT (3 * HZ)
/* Index to functions, as function prototypes. */
static int sonic_open(struct net_device *dev);
static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t sonic_interrupt(int irq, void *dev_id);
static void sonic_rx(struct net_device *dev);
static int sonic_close(struct net_device *dev);
static struct net_device_stats *sonic_get_stats(struct net_device *dev);
static void sonic_multicast_list(struct net_device *dev);
static int sonic_init(struct net_device *dev);
static void sonic_tx_timeout(struct net_device *dev);
/* Internal inlines for reading/writing DMA buffers. Note that bus
size and endianness matter here, whereas they don't for registers,
as far as we can tell. */
/* OpenBSD calls this "SWO". I'd like to think that sonic_buf_put()
is a much better name. */
static inline void sonic_buf_put(void* base, int bitmode,
int offset, __u16 val)
{
if (bitmode)
#ifdef __BIG_ENDIAN
((__u16 *) base + (offset*2))[1] = val;
#else
((__u16 *) base + (offset*2))[0] = val;
#endif
else
((__u16 *) base)[offset] = val;
}
static inline __u16 sonic_buf_get(void* base, int bitmode,
int offset)
{
if (bitmode)
#ifdef __BIG_ENDIAN
return ((volatile __u16 *) base + (offset*2))[1];
#else
return ((volatile __u16 *) base + (offset*2))[0];
#endif
else
return ((volatile __u16 *) base)[offset];
}
/* Inlines that you should actually use for reading/writing DMA buffers */
static inline void sonic_cda_put(struct net_device* dev, int entry,
int offset, __u16 val)
{
struct sonic_local *lp = netdev_priv(dev);
sonic_buf_put(lp->cda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_CD) + offset, val);
}
static inline __u16 sonic_cda_get(struct net_device* dev, int entry,
int offset)
{
struct sonic_local *lp = netdev_priv(dev);
return sonic_buf_get(lp->cda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_CD) + offset);
}
static inline void sonic_set_cam_enable(struct net_device* dev, __u16 val)
{
struct sonic_local *lp = netdev_priv(dev);
sonic_buf_put(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE, val);
}
static inline __u16 sonic_get_cam_enable(struct net_device* dev)
{
struct sonic_local *lp = netdev_priv(dev);
return sonic_buf_get(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE);
}
static inline void sonic_tda_put(struct net_device* dev, int entry,
int offset, __u16 val)
{
struct sonic_local *lp = netdev_priv(dev);
sonic_buf_put(lp->tda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_TD) + offset, val);
}
static inline __u16 sonic_tda_get(struct net_device* dev, int entry,
int offset)
{
struct sonic_local *lp = netdev_priv(dev);
return sonic_buf_get(lp->tda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_TD) + offset);
}
static inline void sonic_rda_put(struct net_device* dev, int entry,
int offset, __u16 val)
{
struct sonic_local *lp = netdev_priv(dev);
sonic_buf_put(lp->rda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_RD) + offset, val);
}
static inline __u16 sonic_rda_get(struct net_device* dev, int entry,
int offset)
{
struct sonic_local *lp = netdev_priv(dev);
return sonic_buf_get(lp->rda, lp->dma_bitmode,
(entry * SIZEOF_SONIC_RD) + offset);
}
static inline void sonic_rra_put(struct net_device* dev, int entry,
int offset, __u16 val)
{
struct sonic_local *lp = netdev_priv(dev);
sonic_buf_put(lp->rra, lp->dma_bitmode,
(entry * SIZEOF_SONIC_RR) + offset, val);
}
static inline __u16 sonic_rra_get(struct net_device* dev, int entry,
int offset)
{
struct sonic_local *lp = netdev_priv(dev);
return sonic_buf_get(lp->rra, lp->dma_bitmode,
(entry * SIZEOF_SONIC_RR) + offset);
}
static const char *version =
"sonic.c:v0.92 20.9.98 tsbogend@alpha.franken.de\n";
#endif /* SONIC_H */

View File

@@ -0,0 +1,333 @@
/*
* xtsonic.c
*
* (C) 2001 - 2007 Tensilica Inc.
* Kevin Chea <kchea@yahoo.com>
* Marc Gauthier <marc@linux-xtensa.org>
* Chris Zankel <chris@zankel.net>
*
* (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 the XT2000.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/gfp.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/in.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 <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/dma.h>
static char xtsonic_string[] = "xtsonic";
extern unsigned xtboard_nvram_valid(void);
extern void xtboard_get_ether_addr(unsigned char *buf);
#include "sonic.h"
/*
* According to the documentation for the Sonic ethernet controller,
* EOBC should be 760 words (1520 bytes) for 32-bit applications, and,
* as such, 2 words less than the buffer size. The value for RBSIZE
* defined in sonic.h, however is only 1520.
*
* (Note that in 16-bit configurations, EOBC is 759 words (1518 bytes) and
* RBSIZE 1520 bytes)
*/
#undef SONIC_RBSIZE
#define SONIC_RBSIZE 1524
/*
* The chip provides 256 byte register space.
*/
#define SONIC_MEM_SIZE 0x100
/*
* Macros to access SONIC registers
*/
#define SONIC_READ(reg) \
(0xffff & *((volatile unsigned int *)dev->base_addr+reg))
#define SONIC_WRITE(reg,val) \
*((volatile unsigned int *)dev->base_addr+reg) = val
/* Use 0 for production, 1 for verification, and >2 for debug */
#ifdef SONIC_DEBUG
static unsigned int sonic_debug = SONIC_DEBUG;
#else
static unsigned int sonic_debug = 1;
#endif
/*
* 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[] =
{
0x101, /* SONIC 83934 */
0xffff /* end of list */
};
static int xtsonic_open(struct net_device *dev)
{
int retval;
retval = request_irq(dev->irq, sonic_interrupt, IRQF_DISABLED,
"sonic", dev);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
dev->name, dev->irq);
return -EAGAIN;
}
retval = sonic_open(dev);
if (retval)
free_irq(dev->irq, dev);
return retval;
}
static int xtsonic_close(struct net_device *dev)
{
int err;
err = sonic_close(dev);
free_irq(dev->irq, dev);
return err;
}
static const struct net_device_ops xtsonic_netdev_ops = {
.ndo_open = xtsonic_open,
.ndo_stop = xtsonic_close,
.ndo_start_xmit = sonic_send_packet,
.ndo_get_stats = sonic_get_stats,
.ndo_set_multicast_list = sonic_multicast_list,
.ndo_tx_timeout = sonic_tx_timeout,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
};
static int __init sonic_probe1(struct net_device *dev)
{
static unsigned version_printed = 0;
unsigned int silicon_revision;
struct sonic_local *lp = netdev_priv(dev);
unsigned int base_addr = dev->base_addr;
int i;
int err = 0;
if (!request_mem_region(base_addr, 0x100, xtsonic_string))
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);
return -ENODEV;
}
if (sonic_debug && version_printed++ == 0)
printk(version);
/*
* Put the sonic into software reset, then retrieve ethernet address.
* Note: we are assuming that the boot-loader has initialized the cam.
*/
SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
SONIC_WRITE(SONIC_DCR,
SONIC_DCR_WC0|SONIC_DCR_DW|SONIC_DCR_LBR|SONIC_DCR_SBUS);
SONIC_WRITE(SONIC_CEP,0);
SONIC_WRITE(SONIC_IMR,0);
SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
SONIC_WRITE(SONIC_CEP,0);
for (i=0; i<3; i++) {
unsigned int val = SONIC_READ(SONIC_CAP0-i);
dev->dev_addr[i*2] = val;
dev->dev_addr[i*2+1] = val >> 8;
}
/* Initialize the device structure. */
lp->dma_bitmode = SONIC_BITMODE32;
/*
* Allocate local private descriptor areas in uncached space.
* The entire structure must be located within the same 64kb segment.
* A simple way to ensure this is to allocate twice the
* size of the structure -- given that the structure is
* much less than 64 kB, at least one of the halves of
* the allocated area will be contained entirely in 64 kB.
* We also allocate extra space for a pointer to allow freeing
* this structure later on (in xtsonic_cleanup_module()).
*/
lp->descriptors =
dma_alloc_coherent(lp->device,
SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
&lp->descriptors_laddr, GFP_KERNEL);
if (lp->descriptors == NULL) {
printk(KERN_ERR "%s: couldn't alloc DMA memory for "
" descriptors.\n", dev_name(lp->device));
goto out;
}
lp->cda = lp->descriptors;
lp->tda = lp->cda + (SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
/* get the virtual dma address */
lp->cda_laddr = lp->descriptors_laddr;
lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
dev->netdev_ops = &xtsonic_netdev_ops;
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;
out:
release_region(dev->base_addr, SONIC_MEM_SIZE);
return err;
}
/*
* Probe for a SONIC ethernet controller on an XT2000 board.
* Actually probing is superfluous but we're paranoid.
*/
int __devinit xtsonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
struct resource *resmem, *resirq;
int err = 0;
if ((resmem = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == NULL)
return -ENODEV;
if ((resirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0)) == NULL)
return -ENODEV;
if ((dev = alloc_etherdev(sizeof(struct sonic_local))) == NULL)
return -ENOMEM;
lp = netdev_priv(dev);
lp->device = &pdev->dev;
SET_NETDEV_DEV(dev, &pdev->dev);
netdev_boot_setup_check(dev);
dev->base_addr = resmem->start;
dev->irq = resirq->start;
if ((err = sonic_probe1(dev)))
goto out;
if ((err = register_netdev(dev)))
goto out1;
printk("%s: SONIC ethernet @%08lx, MAC %pM, IRQ %d\n", dev->name,
dev->base_addr, dev->dev_addr, dev->irq);
return 0;
out1:
release_region(dev->base_addr, SONIC_MEM_SIZE);
out:
free_netdev(dev);
return err;
}
MODULE_DESCRIPTION("Xtensa XT2000 SONIC ethernet driver");
module_param(sonic_debug, int, 0);
MODULE_PARM_DESC(sonic_debug, "xtsonic debug level (1-4)");
#include "sonic.c"
static int __devexit xtsonic_device_remove (struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct sonic_local *lp = netdev_priv(dev);
unregister_netdev(dev);
dma_free_coherent(lp->device,
SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
lp->descriptors, lp->descriptors_laddr);
release_region (dev->base_addr, SONIC_MEM_SIZE);
free_netdev(dev);
return 0;
}
static struct platform_driver xtsonic_driver = {
.probe = xtsonic_probe,
.remove = __devexit_p(xtsonic_device_remove),
.driver = {
.name = xtsonic_string,
},
};
static int __init xtsonic_init(void)
{
return platform_driver_register(&xtsonic_driver);
}
static void __exit xtsonic_cleanup(void)
{
platform_driver_unregister(&xtsonic_driver);
}
module_init(xtsonic_init);
module_exit(xtsonic_cleanup);