/* Intel Professional Workstation/panther ethernet driver */
/* lp486e.c: A panther 82596 ethernet driver for linux. */
/*
History and copyrights:
Driver skeleton
Written 1993 by Donald Becker.
Copyright 1993 United States Government as represented by the Director,
National Security Agency. This software may only be used and
distributed according to the terms of the GNU General Public License
as modified by SRC, incorporated herein by reference.
The author may be reached as becker@scyld.com, or C/O
Scyld Computing Corporation
410 Severn Ave., Suite 210
Annapolis MD 21403
Apricot
Written 1994 by Mark Evans.
This driver is for the Apricot 82596 bus-master interface
Modularised 12/94 Mark Evans
Professional Workstation
Derived from apricot.c by Ard van Breemen
<ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org>
Credits:
Thanks to Murphy Software BV for letting me write this in their time.
Well, actually, I get payed doing this...
(Also: see http://www.murphy.nl for murphy, and my homepage ~ard for
more information on the Professional Workstation)
Present version
aeb@cwi.nl
*/
/*
There are currently two motherboards that I know of in the
professional workstation. The only one that I know is the
intel panther motherboard. -- ard
*/
/*
The pws is equipped with an intel 82596. This is a very intelligent controller
which runs its own micro-code. Communication with the hostprocessor is done
through linked lists of commands and buffers in the hostprocessors memory.
A complete description of the 82596 is available from intel. Search for
a file called "29021806.pdf". It is a complete description of the chip itself.
To use it for the pws some additions are needed regarding generation of
the PORT and CA signal, and the interrupt glue needed for a pc.
I/O map:
PORT SIZE ACTION MEANING
0xCB0 2 WRITE Lower 16 bits for PORT command
0xCB2 2 WRITE Upper 16 bits for PORT command, and issue of PORT command
0xCB4 1 WRITE Generation of CA signal
0xCB8 1 WRITE Clear interrupt glue
All other communication is through memory!
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#define DRV_NAME "lp486e"
/* debug print flags */
#define LOG_SRCDST 0x80000000
#define LOG_STATINT 0x40000000
#define LOG_STARTINT 0x20000000
#define i596_debug debug
static int i596_debug = 0;
static const char * const medianame[] = {
"10baseT", "AUI",
"10baseT-FD", "AUI-FD",
};
#define LP486E_TOTAL_SIZE 16
#define I596_NULL (0xffffffff)
#define CMD_EOL 0x8000 /* The last command of the list, stop. */
#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
#define CMD_FLEX 0x0008 /* Enable flexible memory model */
enum commands {
CmdNOP = 0,
CmdIASetup = 1,
CmdConfigure = 2,
CmdMulticastList = 3,
CmdTx = 4,
CmdTDR = 5,
CmdDump = 6,
CmdDiagnose = 7
};
#if 0
static const char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
"Tx", "TDR", "Dump", "Diagnose" };
#endif
/* Status word bits */
#define STAT_CX 0x8000 /* The CU finished executing a command
with the Interrupt bit set */
#define STAT_FR 0x4000 /* The RU finished receiving a frame */
#define STAT_CNA 0x2000 /* The CU left the active state */
#define STAT_RNR 0x1000 /* The RU left the active state */
#define STAT_ACK (STAT_CX | STAT_FR | STAT_CNA | STAT_RNR)
#define STAT_CUS 0x0700 /* Status of CU: 0: idle, 1: suspended,
2: active, 3-7: unused */
#define STAT_RUS 0x00f0 /* Status of RU: 0: idle, 1: suspended,
2: no resources, 4: ready,
10: no resources due to no more RBDs,
12: no more RBDs, other: unused */
#define STAT_T 0x0008 /* Bus throttle timers loaded */
#define STAT_ZERO 0x0807 /* Always zero */
#if 0
static char *CUstates[8] = {
"idle", "suspended", "active", 0, 0, 0, 0, 0
};
static char *RUstates[16] = {
"idle", "suspended", "no resources", 0, "ready", 0, 0, 0,
0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0
};
static void
i596_out_status(int status) {
int bad = 0;
char *s;
printk("status %4.4x:", status);
if (status == 0xffff)
printk(" strange..\n");
else {
if (status & STAT_CX)