*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:
@@ -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
|
||||
|
@@ -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"
|
||||
|
@@ -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/
|
||||
|
82
drivers/net/ethernet/natsemi/Kconfig
Normal file
82
drivers/net/ethernet/natsemi/Kconfig
Normal 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
|
10
drivers/net/ethernet/natsemi/Makefile
Normal file
10
drivers/net/ethernet/natsemi/Makefile
Normal 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
|
1075
drivers/net/ethernet/natsemi/ibmlana.c
Normal file
1075
drivers/net/ethernet/natsemi/ibmlana.c
Normal file
File diff suppressed because it is too large
Load Diff
278
drivers/net/ethernet/natsemi/ibmlana.h
Normal file
278
drivers/net/ethernet/natsemi/ibmlana.h
Normal 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_ */
|
308
drivers/net/ethernet/natsemi/jazzsonic.c
Normal file
308
drivers/net/ethernet/natsemi/jazzsonic.c
Normal 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);
|
666
drivers/net/ethernet/natsemi/macsonic.c
Normal file
666
drivers/net/ethernet/natsemi/macsonic.c
Normal 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);
|
3370
drivers/net/ethernet/natsemi/natsemi.c
Normal file
3370
drivers/net/ethernet/natsemi/natsemi.c
Normal file
File diff suppressed because it is too large
Load Diff
2312
drivers/net/ethernet/natsemi/ns83820.c
Normal file
2312
drivers/net/ethernet/natsemi/ns83820.c
Normal file
File diff suppressed because it is too large
Load Diff
742
drivers/net/ethernet/natsemi/sonic.c
Normal file
742
drivers/net/ethernet/natsemi/sonic.c
Normal 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");
|
450
drivers/net/ethernet/natsemi/sonic.h
Normal file
450
drivers/net/ethernet/natsemi/sonic.h
Normal 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 */
|
333
drivers/net/ethernet/natsemi/xtsonic.c
Normal file
333
drivers/net/ethernet/natsemi/xtsonic.c
Normal 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);
|
Reference in New Issue
Block a user