Commit c7e86e34 authored by Nathanael Nerode's avatar Nathanael Nerode Committed by David S. Miller

dgrs: remove from build, config, and maintainer list

Stop building and configuring driver for Digi RightSwitch, which was
never actually sold to anyone, and remove it from MAINTAINERS.

In response to an investigation into the firmware of the "Digi Rightswitch"
driver, Andres Salomon discovered:
>
> Dear Andres:
>
> After further research, we found that this product was killed in place
> and never reached the market.  We would like to request that this not be
> included.

Since the product never reached market, clearly nobody is using this orphaned
driver.
Signed-off-by: default avatarNathanael Nerode <neroden@gcc.gnu.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 928773c2
The Digi International RightSwitch SE-X (dgrs) Device Driver
This is a Linux driver for the Digi International RightSwitch SE-X
EISA and PCI boards. These are 4 (EISA) or 6 (PCI) port Ethernet
switches and a NIC combined into a single board. This driver can
be compiled into the kernel statically or as a loadable module.
There is also a companion management tool, called "xrightswitch".
The management tool lets you watch the performance graphically,
as well as set the SNMP agent IP and IPX addresses, IEEE Spanning
Tree, and Aging time. These can also be set from the command line
when the driver is loaded. The driver command line options are:
debug=NNN Debug printing level
dma=0/1 Disable/Enable DMA on PCI card
spantree=0/1 Disable/Enable IEEE spanning tree
hashexpire=NNN Change address aging time (default 300 seconds)
ipaddr=A,B,C,D Set SNMP agent IP address i.e. 199,86,8,221
iptrap=A,B,C,D Set SNMP agent IP trap address i.e. 199,86,8,221
ipxnet=NNN Set SNMP agent IPX network number
nicmode=0/1 Disable/Enable multiple NIC mode
There is also a tool for setting up input and output packet filters
on each port, called "dgrsfilt".
Both the management tool and the filtering tool are available
separately from the following FTP site:
ftp://ftp.dgii.com/drivers/rightswitch/linux/
When nicmode=1, the board and driver operate as 4 or 6 individual
NIC ports (eth0...eth5) instead of as a switch. All switching
functions are disabled. In the future, the board firmware may include
a routing cache when in this mode.
Copyright 1995-1996 Digi International Inc.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
For information on purchasing a RightSwitch SE-4 or SE-6
board, please contact Digi's sales department at 1-612-912-3444
or 1-800-DIGIBRD. Outside the U.S., please check our Web page at:
http://www.dgii.com
for sales offices worldwide. Tech support is also available through
the channels listed on the Web site, although as long as I am
employed on networking products at Digi I will be happy to provide
any bug fixes that may be needed.
-Rick Richardson, rick@dgii.com
......@@ -1274,12 +1274,6 @@ L: Eng.Linux@digi.com
W: http://www.digi.com
S: Orphaned
DIGI RIGHTSWITCH NETWORK DRIVER
P: Rick Richardson
L: netdev@vger.kernel.org
W: http://www.digi.com
S: Orphaned
DIRECTORY NOTIFICATION
P: Stephen Rothwell
M: sfr@canb.auug.org.au
......
......@@ -1459,21 +1459,6 @@ config TC35815
depends on NET_PCI && PCI && MIPS
select MII
config DGRS
tristate "Digi Intl. RightSwitch SE-X support"
depends on NET_PCI && (PCI || EISA)
---help---
This is support for the Digi International RightSwitch series of
PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6
models. If you have a network card of this type, say Y and read the
Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>. More specific
information is contained in <file:Documentation/networking/dgrs.txt>.
To compile this driver as a module, choose M here and read
<file:Documentation/networking/net-modules.txt>. The module
will be called dgrs.
config EEPRO100
tristate "EtherExpressPro/100 support (eepro100, original Becker driver)"
depends on NET_PCI && PCI
......
......@@ -44,7 +44,6 @@ obj-$(CONFIG_SUNVNET) += sunvnet.o
obj-$(CONFIG_MACE) += mace.o
obj-$(CONFIG_BMAC) += bmac.o
obj-$(CONFIG_DGRS) += dgrs.o
obj-$(CONFIG_VORTEX) += 3c59x.o
obj-$(CONFIG_TYPHOON) += typhoon.o
obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
......
/*
* Digi RightSwitch SE-X loadable device driver for Linux
*
* The RightSwitch is a 4 (EISA) or 6 (PCI) port etherswitch and
* a NIC on an internal board.
*
* Author: Rick Richardson, rick@remotepoint.com
* Derived from the SVR4.2 (UnixWare) driver for the same card.
*
* Copyright 1995-1996 Digi International Inc.
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* For information on purchasing a RightSwitch SE-4 or SE-6
* board, please contact Digi's sales department at 1-612-912-3444
* or 1-800-DIGIBRD. Outside the U.S., please check our Web page
* at http://www.dgii.com for sales offices worldwide.
*
* OPERATION:
* When compiled as a loadable module, this driver can operate
* the board as either a 4/6 port switch with a 5th or 7th port
* that is a conventional NIC interface as far as the host is
* concerned, OR as 4/6 independent NICs. To select multi-NIC
* mode, add "nicmode=1" on the insmod load line for the driver.
*
* This driver uses the "dev" common ethernet device structure
* and a private "priv" (dev->priv) structure that contains
* mostly DGRS-specific information and statistics. To keep
* the code for both the switch mode and the multi-NIC mode
* as similar as possible, I have introduced the concept of
* "dev0"/"priv0" and "devN"/"privN" pointer pairs in subroutines
* where needed. The first pair of pointers points to the
* "dev" and "priv" structures of the zeroth (0th) device
* interface associated with a board. The second pair of
* pointers points to the current (Nth) device interface
* for the board: the one for which we are processing data.
*
* In switch mode, the pairs of pointers are always the same,
* that is, dev0 == devN and priv0 == privN. This is just
* like previous releases of this driver which did not support
* NIC mode.
*
* In multi-NIC mode, the pairs of pointers may be different.
* We use the devN and privN pointers to reference just the
* name, port number, and statistics for the current interface.
* We use the dev0 and priv0 pointers to access the variables
* that control access to the board, such as board address
* and simulated 82596 variables. This is because there is
* only one "fake" 82596 that serves as the interface to
* the board. We do not want to try to keep the variables
* associated with this 82596 in sync across all devices.
*
* This scheme works well. As you will see, except for
* initialization, there is very little difference between
* the two modes as far as this driver is concerned. On the
* receive side in NIC mode, the interrupt *always* comes in on
* the 0th interface (dev0/priv0). We then figure out which
* real 82596 port it came in on from looking at the "chan"
* member that the board firmware adds at the end of each
* RBD (a.k.a. TBD). We get the channel number like this:
* int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan;
*
* On the transmit side in multi-NIC mode, we specify the
* output 82596 port by setting the new "dstchan" structure
* member that is at the end of the RFD, like this:
* priv0->rfdp->dstchan = privN->chan;
*
* TODO:
* - Multi-NIC mode is not yet supported when the driver is linked
* into the kernel.
* - Better handling of multicast addresses.
*
* Fixes:
* Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
* - fix dgrs_found_device wrt checking kmalloc return and
* rollbacking the partial steps of the whole process when
* one of the devices can't be allocated. Fix SET_MODULE_OWNER
* on the loop to use devN instead of repeated calls to dev.
*
* davej <davej@suse.de> - 9/2/2001
* - Enable PCI device before reading ioaddr/irq
*
*/
#include <linux/module.h>
#include <linux/eisa.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
static char version[] __initdata =
"$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $";
/*
* DGRS include files
*/
typedef unsigned char uchar;
#define vol volatile
#include "dgrs.h"
#include "dgrs_es4h.h"
#include "dgrs_plx9060.h"
#include "dgrs_i82596.h"
#include "dgrs_ether.h"
#include "dgrs_asstruct.h"
#include "dgrs_bcomm.h"
#ifdef CONFIG_PCI
static struct pci_device_id dgrs_pci_tbl[] = {
{ SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl);
#endif
#ifdef CONFIG_EISA
static struct eisa_device_id dgrs_eisa_tbl[] = {
{ "DBI0A01" },
{ }
};
MODULE_DEVICE_TABLE(eisa, dgrs_eisa_tbl);
#endif
MODULE_LICENSE("GPL");
/*
* Firmware. Compiled separately for local compilation,
* but #included for Linux distribution.
*/
#ifndef NOFW
#include "dgrs_firmware.c"
#else
extern int dgrs_firmnum;
extern char dgrs_firmver[];
extern char dgrs_firmdate[];
extern uchar dgrs_code[];
extern int dgrs_ncode;
#endif
/*
* Linux out*() is backwards from all other operating systems
*/
#define OUTB(ADDR, VAL) outb(VAL, ADDR)
#define OUTW(ADDR, VAL) outw(VAL, ADDR)
#define OUTL(ADDR, VAL) outl(VAL, ADDR)
/*
* Macros to convert switch to host and host to switch addresses
* (assumes a local variable priv points to board dependent struct)
*/
#define S2H(A) ( ((unsigned long)(A)&0x00ffffff) + priv0->vmem )
#define S2HN(A) ( ((unsigned long)(A)&0x00ffffff) + privN->vmem )
#define H2S(A) ( ((char *) (A) - priv0->vmem) + 0xA3000000 )
/*
* Convert a switch address to a "safe" address for use with the
* PLX 9060 DMA registers and the associated HW kludge that allows
* for host access of the DMA registers.
*/
#define S2DMA(A) ( (unsigned long)(A) & 0x00ffffff)
/*
* "Space.c" variables, now settable from module interface
* Use the name below, minus the "dgrs_" prefix. See init_module().
*/
static int dgrs_debug = 1;
static int dgrs_dma = 1;
static int dgrs_spantree = -1;
static int dgrs_hashexpire = -1;
static uchar dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff};
static uchar dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff};
static __u32 dgrs_ipxnet = -1;
static int dgrs_nicmode;
/*
* Private per-board data structure (dev->priv)
*/
typedef struct
{
/*
* DGRS specific data
*/
char *vmem;
struct bios_comm *bcomm; /* Firmware BIOS comm structure */
PORT *port; /* Ptr to PORT[0] struct in VM */
I596_SCB *scbp; /* Ptr to SCB struct in VM */
I596_RFD *rfdp; /* Current RFD list */
I596_RBD *rbdp; /* Current RBD list */
volatile int intrcnt; /* Count of interrupts */
/*
* SE-4 (EISA) board variables
*/
uchar is_reg; /* EISA: Value for ES4H_IS reg */
/*
* SE-6 (PCI) board variables
*
* The PLX "expansion rom" space is used for DMA register
* access from the host on the SE-6. These are the physical
* and virtual addresses of that space.
*/
ulong plxreg; /* Phys address of PLX chip */
char *vplxreg; /* Virtual address of PLX chip */
ulong plxdma; /* Phys addr of PLX "expansion rom" */
ulong volatile *vplxdma; /* Virtual addr of "expansion rom" */
int use_dma; /* Flag: use DMA */
DMACHAIN *dmadesc_s; /* area for DMA chains (SW addr.) */
DMACHAIN *dmadesc_h; /* area for DMA chains (Host Virtual) */
/*
* Multi-NIC mode variables
*
* All entries of the devtbl[] array are valid for the 0th
* device (i.e. eth0, but not eth1...eth5). devtbl[0] is
* valid for all devices (i.e. eth0, eth1, ..., eth5).
*/
int nports; /* Number of physical ports (4 or 6) */
int chan; /* Channel # (1-6) for this device */
struct net_device *devtbl[6]; /* Ptrs to N device structs */
} DGRS_PRIV;
/*
* reset or un-reset the IDT processor
*/
static void
proc_reset(struct net_device *dev0, int reset)
{
DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
if (priv0->plxreg)
{
ulong val;
val = inl(dev0->base_addr + PLX_MISC_CSR);
if (reset)
val |= SE6_RESET;
else
val &= ~SE6_RESET;
OUTL(dev0->base_addr + PLX_MISC_CSR, val);
}
else
{
OUTB(dev0->base_addr + ES4H_PC, reset ? ES4H_PC_RESET : 0);
}
}
/*
* See if the board supports bus master DMA
*/
static int
check_board_dma(struct net_device *dev0)
{
DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
ulong x;
/*
* If Space.c says not to use DMA, or if it's not a PLX based
* PCI board, or if the expansion ROM space is not PCI
* configured, then return false.
*/
if (!dgrs_dma || !priv0->plxreg || !priv0->plxdma)
return (0);
/*
* Set the local address remap register of the "expansion rom"
* area to 0x80000000 so that we can use it to access the DMA
* registers from the host side.
*/
OUTL(dev0->base_addr + PLX_ROM_BASE_ADDR, 0x80000000);
/*
* Set the PCI region descriptor to:
* Space 0:
* disable read-prefetch
* enable READY
* enable BURST
* 0 internal wait states
* Expansion ROM: (used for host DMA register access)
* disable read-prefetch
* enable READY
* disable BURST
* 0 internal wait states
*/
OUTL(dev0->base_addr + PLX_BUS_REGION, 0x49430343);
/*
* Now map the DMA registers into our virtual space
*/
priv0->vplxdma = (ulong *) ioremap (priv0->plxdma, 256);
if (!priv0->vplxdma)
{
printk("%s: can't *remap() the DMA regs\n", dev0->name);
return (0);
}
/*
* Now test to see if we can access the DMA registers
* If we write -1 and get back 1FFF, then we accessed the
* DMA register. Otherwise, we probably have an old board
* and wrote into regular RAM.
*/
priv0->vplxdma[PLX_DMA0_MODE/4] = 0xFFFFFFFF;
x = priv0->vplxdma[PLX_DMA0_MODE/4];
if (x != 0x00001FFF) {
iounmap((void *)priv0->vplxdma);
return (0);
}
return (1);
}
/*
* Initiate DMA using PLX part on PCI board. Spin the
* processor until completed. All addresses are physical!
*
* If pciaddr is NULL, then it's a chaining DMA, and lcladdr is
* the address of the first DMA descriptor in the chain.
*
* If pciaddr is not NULL, then it's a single DMA.
*
* In either case, "lcladdr" must have been fixed up to make
* sure the MSB isn't set using the S2DMA macro before passing
* the address to this routine.
*/
static int
do_plx_dma(
struct net_device *dev,
ulong pciaddr,
ulong lcladdr,
int len,
int to_host
)
{
int i;
ulong csr = 0;
DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
if (pciaddr)
{
/*
* Do a single, non-chain DMA
*/
priv->vplxdma[PLX_DMA0_PCI_ADDR/4] = pciaddr;
priv->vplxdma[PLX_DMA0_LCL_ADDR/4] = lcladdr;
priv->vplxdma[PLX_DMA0_SIZE/4] = len;
priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = to_host
? PLX_DMA_DESC_TO_HOST
: PLX_DMA_DESC_TO_BOARD;
priv->vplxdma[PLX_DMA0_MODE/4] =
PLX_DMA_MODE_WIDTH32
| PLX_DMA_MODE_WAITSTATES(0)
| PLX_DMA_MODE_READY
| PLX_DMA_MODE_NOBTERM
| PLX_DMA_MODE_BURST
| PLX_DMA_MODE_NOCHAIN;
}
else
{
/*
* Do a chaining DMA
*/
priv->vplxdma[PLX_DMA0_MODE/4] =
PLX_DMA_MODE_WIDTH32
| PLX_DMA_MODE_WAITSTATES(0)
| PLX_DMA_MODE_READY
| PLX_DMA_MODE_NOBTERM
| PLX_DMA_MODE_BURST
| PLX_DMA_MODE_CHAIN;
priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = lcladdr;
}
priv->vplxdma[PLX_DMA_CSR/4] =
PLX_DMA_CSR_0_ENABLE | PLX_DMA_CSR_0_START;
/*
* Wait for DMA to complete
*/
for (i = 0; i < 1000000; ++i)
{
/*
* Spin the host CPU for 1 usec, so we don't thrash
* the PCI bus while the PLX 9060 is doing DMA.
*/
udelay(1);
csr = (volatile unsigned long) priv->vplxdma[PLX_DMA_CSR/4];
if (csr & PLX_DMA_CSR_0_DONE)
break;
}
if ( ! (csr & PLX_DMA_CSR_0_DONE) )
{
printk("%s: DMA done never occurred. DMA disabled.\n",
dev->name);
priv->use_dma = 0;
return 1;
}
return 0;
}
/*
* dgrs_rcv_frame()
*
* Process a received frame. This is called from the interrupt
* routine, and works for both switch mode and multi-NIC mode.
*
* Note that when in multi-NIC mode, we want to always access the
* hardware using the dev and priv structures of the first port,
* so that we are using only one set of variables to maintain
* the board interface status, but we want to use the Nth port
* dev and priv structures to maintain statistics and to pass
* the packet up.
*
* Only the first device structure is attached to the interrupt.
* We use the special "chan" variable at the end of the first RBD
* to select the Nth device in multi-NIC mode.
*
* We currently do chained DMA on a per-packet basis when the
* packet is "long", and we spin the CPU a short time polling
* for DMA completion. This avoids a second interrupt overhead,
* and gives the best performance for light traffic to the host.
*
* However, a better scheme that could be implemented would be
* to see how many packets are outstanding for the host, and if
* the number is "large", create a long chain to DMA several
* packets into the host in one go. In this case, we would set
* up some state variables to let the host CPU continue doing
* other things until a DMA completion interrupt comes along.
*/
static void
dgrs_rcv_frame(
struct net_device *dev0,
DGRS_PRIV *priv0,
I596_CB *cbp
)
{
int len;
I596_TBD *tbdp;
struct sk_buff *skb;
uchar *putp;
uchar *p;
struct net_device *devN;
DGRS_PRIV *privN;
/*
* Determine Nth priv and dev structure pointers
*/
if (dgrs_nicmode)
{ /* Multi-NIC mode */
int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan;
devN = priv0->devtbl[chan-1];
/*
* If devN is null, we got an interrupt before the I/F
* has been initialized. Pitch the packet.
*/
if (devN == NULL)
goto out;
privN = (DGRS_PRIV *) devN->priv;
}
else
{ /* Switch mode */
devN = dev0;
privN = priv0;
}
if (0) printk("%s: rcv len=%ld\n", devN->name, cbp->xmit.count);
/*
* Allocate a message block big enough to hold the whole frame
*/
len = cbp->xmit.count;
if ((skb = dev_alloc_skb(len+5)) == NULL)
{
printk("%s: dev_alloc_skb failed for rcv buffer\n", devN->name);
++dev0->stats.rx_dropped;
/* discarding the frame */
goto out;
}
skb_reserve(skb, 2); /* Align IP header */
again:
putp = p = skb_put(skb, len);
/*
* There are three modes here for doing the packet copy.
* If we have DMA, and the packet is "long", we use the
* chaining mode of DMA. If it's shorter, we use single
* DMA's. Otherwise, we use memcpy().
*/
if (priv0->use_dma && priv0->dmadesc_h && len > 64)
{
/*
* If we can use DMA and it's a long frame, copy it using
* DMA chaining.
*/
DMACHAIN *ddp_h; /* Host virtual DMA desc. pointer */
DMACHAIN *ddp_s; /* Switch physical DMA desc. pointer */
uchar *phys_p;
/*
* Get the physical address of the STREAMS buffer.
* NOTE: allocb() guarantees that the whole buffer
* is in a single page if the length < 4096.
*/
phys_p = (uchar *) virt_to_phys(putp);
ddp_h = priv0->dmadesc_h;
ddp_s = priv0->dmadesc_s;
tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
for (;;)
{
int count;
int amt;
count = tbdp->count;
amt = count & 0x3fff;
if (amt == 0)
break; /* For safety */
if ( (p-putp) >= len)
{
printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
proc_reset(dev0, 1); /* Freeze IDT */
break; /* For Safety */
}
ddp_h->pciaddr = (ulong) phys_p;
ddp_h->lcladdr = S2DMA(tbdp->buf);
ddp_h->len = amt;
phys_p += amt;
p += amt;
if (count & I596_TBD_EOF)
{
ddp_h->next = PLX_DMA_DESC_TO_HOST
| PLX_DMA_DESC_EOC;
++ddp_h;
break;
}
else
{
++ddp_s;
ddp_h->next = PLX_DMA_DESC_TO_HOST
| (ulong) ddp_s;
tbdp = (I596_TBD *) S2H(tbdp->next);
++ddp_h;
}
}
if (ddp_h - priv0->dmadesc_h)
{
int rc;
rc = do_plx_dma(dev0,
0, (ulong) priv0->dmadesc_s, len, 0);
if (rc)
{
printk("%s: Chained DMA failure\n", devN->name);
goto again;
}
}
}
else if (priv0->use_dma)
{
/*
* If we can use DMA and it's a shorter frame, copy it
* using single DMA transfers.
*/
uchar *phys_p;
/*
* Get the physical address of the STREAMS buffer.
* NOTE: allocb() guarantees that the whole buffer
* is in a single page if the length < 4096.
*/
phys_p = (uchar *) virt_to_phys(putp);
tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
for (;;)
{
int count;
int amt;
int rc;
count = tbdp->count;
amt = count & 0x3fff;
if (amt == 0)
break; /* For safety */
if ( (p-putp) >= len)
{
printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
proc_reset(dev0, 1); /* Freeze IDT */
break; /* For Safety */
}
rc = do_plx_dma(dev0, (ulong) phys_p,
S2DMA(tbdp->buf), amt, 1);
if (rc)
{
memcpy(p, S2H(tbdp->buf), amt);
printk("%s: Single DMA failed\n", devN->name);
}
phys_p += amt;
p += amt;
if (count & I596_TBD_EOF)
break;
tbdp = (I596_TBD *) S2H(tbdp->next);
}
}
else
{
/*
* Otherwise, copy it piece by piece using memcpy()
*/
tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
for (;;)
{
int count;
int amt;
count = tbdp->count;
amt = count & 0x3fff;
if (amt == 0)
break; /* For safety */
if ( (p-putp) >= len)
{
printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
proc_reset(dev0, 1); /* Freeze IDT */
break; /* For Safety */
}
memcpy(p, S2H(tbdp->buf), amt);
p += amt;
if (count & I596_TBD_EOF)
break;
tbdp = (I596_TBD *) S2H(tbdp->next);
}
}
/*
* Pass the frame to upper half
*/
skb->protocol = eth_type_trans(skb, devN);
netif_rx(skb);
devN->last_rx = jiffies;
++devN->stats.rx_packets;
devN->stats.rx_bytes += len;
out:
cbp->xmit.status = I596_CB_STATUS_C | I596_CB_STATUS_OK;
}
/*
* Start transmission of a frame
*
* The interface to the board is simple: we pretend that we are
* a fifth 82596 ethernet controller 'receiving' data, and copy the
* data into the same structures that a real 82596 would. This way,
* the board firmware handles the host 'port' the same as any other.
*
* NOTE: we do not use Bus master DMA for this routine. Turns out
* that it is not needed. Slave writes over the PCI bus are about
* as fast as DMA, due to the fact that the PLX part can do burst
* writes. The same is not true for data being read from the board.
*
* For multi-NIC mode, we tell the firmware the desired 82596
* output port by setting the special "dstchan" member at the
* end of the traditional 82596 RFD structure.
*/
static int dgrs_start_xmit(struct sk_buff *skb, struct net_device *devN)
{
DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv;
struct net_device *dev0;
DGRS_PRIV *priv0;
I596_RBD *rbdp;
int count;
int i, len, amt;
/*
* Determine 0th priv and dev structure pointers
*/
if (dgrs_nicmode)
{
dev0 = privN->devtbl[0];
priv0 = (DGRS_PRIV *) dev0->priv;
}
else
{
dev0 = devN;
priv0 = privN;
}
if (dgrs_debug > 1)
printk("%s: xmit len=%d\n", devN->name, (int) skb->len);
devN->trans_start = jiffies;
netif_start_queue(devN);
if (priv0->rfdp->cmd & I596_RFD_EL)
{ /* Out of RFD's */
if (0) printk("%s: NO RFD's\n", devN->name);
goto no_resources;
}
rbdp = priv0->rbdp;
count = 0;
priv0->rfdp->rbdp = (I596_RBD *) H2S(rbdp);
i = 0; len = skb->len;
for (;;)
{
if (rbdp->size & I596_RBD_EL)
{ /* Out of RBD's */
if (0) printk("%s: NO RBD's\n", devN->name);
goto no_resources;
}
amt = min_t(unsigned int, len, rbdp->size - count);
skb_copy_from_linear_data_offset(skb, i, S2H(rbdp->buf) + count, amt);
i += amt;
count += amt;
len -= amt;
if (len == 0)
{
if (skb->len < 60)
rbdp->count = 60 | I596_RBD_EOF;
else
rbdp->count = count | I596_RBD_EOF;
rbdp = (I596_RBD *) S2H(rbdp->next);
goto frame_done;
}
else if (count < 32)
{
/* More data to come, but we used less than 32
* bytes of this RBD. Keep filling this RBD.
*/
{} /* Yes, we do nothing here */
}
else
{
rbdp->count = count;
rbdp = (I596_RBD *) S2H(rbdp->next);
count = 0;
}
}
frame_done:
priv0->rbdp = rbdp;
if (dgrs_nicmode)
priv0->rfdp->dstchan = privN->chan;
priv0->rfdp->status = I596_RFD_C | I596_RFD_OK;
priv0->rfdp = (I596_RFD *) S2H(priv0->rfdp->next);
++devN->stats.tx_packets;
dev_kfree_skb (skb);
return (0);
no_resources:
priv0->scbp->status |= I596_SCB_RNR; /* simulate I82596 */
return (-EAGAIN);
}
/*
* Open the interface
*/
static int
dgrs_open( struct net_device *dev )
{
netif_start_queue(dev);
return (0);
}
/*
* Close the interface
*/
static int dgrs_close( struct net_device *dev )
{
netif_stop_queue(dev);
return (0);
}
/*
* Set multicast list and/or promiscuous mode
*/
static void dgrs_set_multicast_list( struct net_device *dev)
{
DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
priv->port->is_promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
}
/*
* Unique ioctl's
*/
static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd)
{
DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv;
DGRS_IOCTL ioc;
int i;
if (cmd != DGRSIOCTL)
return -EINVAL;
if(copy_from_user(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL)))
return -EFAULT;
switch (ioc.cmd)
{
case DGRS_GETMEM:
if (ioc.len != sizeof(ulong))
return -EINVAL;
if(copy_to_user(ioc.data, &devN->mem_start, ioc.len))
return -EFAULT;
return (0);
case DGRS_SETFILTER:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (ioc.port > privN->bcomm->bc_nports)
return -EINVAL;
if (ioc.filter >= NFILTERS)
return -EINVAL;
if (ioc.len > privN->bcomm->bc_filter_area_len)
return -EINVAL;
/* Wait for old command to finish */
for (i = 0; i < 1000; ++i)
{
if ( (volatile long) privN->bcomm->bc_filter_cmd <= 0 )
break;
udelay(1);
}
if (i >= 1000)
return -EIO;
privN->bcomm->bc_filter_port = ioc.port;
privN->bcomm->bc_filter_num = ioc.filter;
privN->bcomm->bc_filter_len = ioc.len;
if (ioc.len)
{
if(copy_from_user(S2HN(privN->bcomm->bc_filter_area),
ioc.data, ioc.len))
return -EFAULT;
privN->bcomm->bc_filter_cmd = BC_FILTER_SET;
}
else
privN->bcomm->bc_filter_cmd = BC_FILTER_CLR;
return(0);
default:
return -EOPNOTSUPP;
}
}
/*
* Process interrupts
*
* dev, priv will always refer to the 0th device in Multi-NIC mode.
*/
static irqreturn_t dgrs_intr(int irq, void *dev_id)
{
struct net_device *dev0 = dev_id;
DGRS_PRIV *priv0 = dev0->priv;
I596_CB *cbp;
int cmd;
int i;
++priv0->intrcnt;
if (1) ++priv0->bcomm->bc_cnt[4];
if (0)
{
static int cnt = 100;
if (--cnt > 0)
printk("%s: interrupt: irq %d\n", dev0->name, irq);
}
/*
* Get 596 command
*/
cmd = priv0->scbp->cmd;
/*
* See if RU has been restarted
*/
if ( (cmd & I596_SCB_RUC) == I596_SCB_RUC_START)
{
if (0) printk("%s: RUC start\n", dev0->name);
priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp);
priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp);
priv0->scbp->status &= ~(I596_SCB_RNR|I596_SCB_RUS);
/*
* Tell upper half (halves)
*/
if (dgrs_nicmode)
{
for (i = 0; i < priv0->nports; ++i)
netif_wake_queue (priv0->devtbl[i]);
}
else
netif_wake_queue (dev0);
/* if (bd->flags & TX_QUEUED)
DL_sched(bd, bdd); */
}
/*
* See if any CU commands to process
*/
if ( (cmd & I596_SCB_CUC) != I596_SCB_CUC_START)
{
priv0->scbp->cmd = 0; /* Ignore all other commands */
goto ack_intr;
}
priv0->scbp->status &= ~(I596_SCB_CNA|I596_SCB_CUS);
/*
* Process a command
*/
cbp = (I596_CB *) S2H(priv0->scbp->cbp);
priv0->scbp->cmd = 0; /* Safe to clear the command */
for (;;)
{
switch (cbp->nop.cmd & I596_CB_CMD)
{
case I596_CB_CMD_XMIT:
dgrs_rcv_frame(dev0, priv0, cbp);
break;
default:
cbp->nop.status = I596_CB_STATUS_C | I596_CB_STATUS_OK;
break;
}
if (cbp->nop.cmd & I596_CB_CMD_EL)
break;
cbp = (I596_CB *) S2H(cbp->nop.next);
}
priv0->scbp->status |= I596_SCB_CNA;
/*
* Ack the interrupt
*/
ack_intr:
if (priv0->plxreg)
OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1);
return IRQ_HANDLED;
}
/*
* Download the board firmware
*/
static int __init
dgrs_download(struct net_device *dev0)
{
DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
int is;
unsigned long i;
static const int iv2is[16] = {
0, 0, 0, ES4H_IS_INT3,
0, ES4H_IS_INT5, 0, ES4H_IS_INT7,
0, 0, ES4H_IS_INT10, ES4H_IS_INT11,
ES4H_IS_INT12, 0, 0, ES4H_IS_INT15 };
/*
* Map in the dual port memory
*/
priv0->vmem = ioremap(dev0->mem_start, 2048*1024);
if (!priv0->vmem)
{
printk("%s: cannot map in board memory\n", dev0->name);
return -ENXIO;
}
/*
* Hold the processor and configure the board addresses
*/
if (priv0->plxreg)
{ /* PCI bus */
proc_reset(dev0, 1);
}
else
{ /* EISA bus */
is = iv2is[dev0->irq & 0x0f];
if (!is)
{
printk("%s: Illegal IRQ %d\n", dev0->name, dev0->irq);
iounmap(priv0->vmem);
priv0->vmem = NULL;
return -ENXIO;
}
OUTB(dev0->base_addr + ES4H_AS_31_24,
(uchar) (dev0->mem_start >> 24) );
OUTB(dev0->base_addr + ES4H_AS_23_16,
(uchar) (dev0->mem_start >> 16) );
priv0->is_reg = ES4H_IS_LINEAR | is |
((uchar) (dev0->mem_start >> 8) & ES4H_IS_AS15);
OUTB(dev0->base_addr + ES4H_IS, priv0->is_reg);
OUTB(dev0->base_addr + ES4H_EC, ES4H_EC_ENABLE);
OUTB(dev0->base_addr + ES4H_PC, ES4H_PC_RESET);
OUTB(dev0->base_addr + ES4H_MW, ES4H_MW_ENABLE | 0x00);
}
/*
* See if we can do DMA on the SE-6
*/
priv0->use_dma = check_board_dma(dev0);
if (priv0->use_dma)
printk("%s: Bus Master DMA is enabled.\n", dev0->name);
/*
* Load and verify the code at the desired address
*/
memcpy(priv0->vmem, dgrs_code, dgrs_ncode); /* Load code */
if (memcmp(priv0->vmem, dgrs_code, dgrs_ncode))
{
iounmap(priv0->vmem);
priv0->vmem = NULL;
printk("%s: download compare failed\n", dev0->name);
return -ENXIO;
}
/*
* Configurables
*/
priv0->bcomm = (struct bios_comm *) (priv0->vmem + 0x0100);
priv0->bcomm->bc_nowait = 1; /* Tell board to make printf not wait */
priv0->bcomm->bc_squelch = 0; /* Flag from Space.c */
priv0->bcomm->bc_150ohm = 0; /* Flag from Space.c */
priv0->bcomm->bc_spew = 0; /* Debug flag from Space.c */
priv0->bcomm->bc_maxrfd = 0; /* Debug flag from Space.c */
priv0->bcomm->bc_maxrbd = 0; /* Debug flag from Space.c */
/*
* Tell board we are operating in switch mode (1) or in
* multi-NIC mode (2).
*/
priv0->bcomm->bc_host = dgrs_nicmode ? BC_MULTINIC : BC_SWITCH;
/*
* Request memory space on board for DMA chains
*/
if (priv0->use_dma)
priv0->bcomm->bc_hostarea_len = (2048/64) * 16;
/*
* NVRAM configurables from Space.c
*/
priv0->bcomm->bc_spantree = dgrs_spantree;
priv0->bcomm->bc_hashexpire = dgrs_hashexpire;
memcpy(priv0->bcomm->bc_ipaddr, dgrs_ipaddr, 4);
memcpy(priv0->bcomm->bc_iptrap, dgrs_iptrap, 4);
memcpy(priv0->bcomm->bc_ipxnet, &dgrs_ipxnet, 4);
/*
* Release processor, wait 8 seconds for board to initialize
*/
proc_reset(dev0, 0);
for (i = jiffies + 8 * HZ; time_after(i, jiffies); )
{
barrier(); /* Gcc 2.95 needs this */
if (priv0->bcomm->bc_status >= BC_RUN)
break;
}
if (priv0->bcomm->bc_status < BC_RUN)
{
printk("%s: board not operating\n", dev0->name);
iounmap(priv0->vmem);
priv0->vmem = NULL;
return -ENXIO;
}
priv0->port = (PORT *) S2H(priv0->bcomm->bc_port);
priv0->scbp = (I596_SCB *) S2H(priv0->port->scbp);
priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp);
priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp);
priv0->scbp->status = I596_SCB_CNA; /* CU is idle */
/*
* Get switch physical and host virtual pointers to DMA
* chaining area. NOTE: the MSB of the switch physical
* address *must* be turned off. Otherwise, the HW kludge
* that allows host access of the PLX DMA registers will
* erroneously select the PLX registers.
*/
priv0->dmadesc_s = (DMACHAIN *) S2DMA(priv0->bcomm->bc_hostarea);
if (priv0->dmadesc_s)
priv0->dmadesc_h = (DMACHAIN *) S2H(priv0->dmadesc_s);
else
priv0->dmadesc_h = NULL;
/*
* Enable board interrupts
*/
if (priv0->plxreg)
{ /* PCI bus */
OUTL(dev0->base_addr + PLX_INT_CSR,
inl(dev0->base_addr + PLX_INT_CSR)
| PLX_PCI_DOORBELL_IE); /* Enable intr to host */
OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1);
}
else
{ /* EISA bus */
}
return (0);
}
/*
* Probe (init) a board
*/
static int __init
dgrs_probe1(struct net_device *dev)
{
DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
unsigned long i;
int rc;
DECLARE_MAC_BUF(mac);
printk("%s: Digi RightSwitch io=%lx mem=%lx irq=%d plx=%lx dma=%lx\n",
dev->name, dev->base_addr, dev->mem_start, dev->irq,
priv->plxreg, priv->plxdma);
/*
* Download the firmware and light the processor
*/
rc = dgrs_download(dev);
if (rc)
goto err_out;
/*
* Get ether address of board
*/
memcpy(dev->dev_addr, priv->port->ethaddr, 6);
printk("%s: Ethernet address %s\n",
dev->name, print_mac(mac, dev->dev_addr));
if (dev->dev_addr[0] & 1)
{
printk("%s: Illegal Ethernet Address\n", dev->name);
rc = -ENXIO;
goto err_out;
}
/*
* ACK outstanding interrupts, hook the interrupt,
* and verify that we are getting interrupts from the board.
*/
if (priv->plxreg)
OUTL(dev->base_addr + PLX_LCL2PCI_DOORBELL, 1);
rc = request_irq(dev->irq, &dgrs_intr, IRQF_SHARED, "RightSwitch", dev);
if (rc)
goto err_out;
priv->intrcnt = 0;
for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); )
{
cpu_relax();
if (priv->intrcnt >= 2)
break;
}
if (priv->intrcnt < 2)
{
printk(KERN_ERR "%s: Not interrupting on IRQ %d (%d)\n",
dev->name, dev->irq, priv->intrcnt);
rc = -ENXIO;
goto err_free_irq;
}
/*
* Entry points...
*/
dev->open = &dgrs_open;
dev->stop = &dgrs_close;
dev->hard_start_xmit = &dgrs_start_xmit;
dev->set_multicast_list = &dgrs_set_multicast_list;
dev->do_ioctl = &dgrs_ioctl;
return rc;
err_free_irq:
free_irq(dev->irq, dev);
err_out:
return rc;
}
static int __init
dgrs_initclone(struct net_device *dev)
{
DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
DECLARE_MAC_BUF(mac);
printk("%s: Digi RightSwitch port %d %s\n",
dev->name, priv->chan, print_mac(mac, dev->dev_addr));
return 0;
}
static struct net_device * __init
dgrs_found_device(
int io,
ulong mem,
int irq,
ulong plxreg,
ulong plxdma,
struct device *pdev
)
{
DGRS_PRIV *priv;
struct net_device *dev;
int i, ret = -ENOMEM;
dev = alloc_etherdev(sizeof(DGRS_PRIV));
if (!dev)
goto err0;
priv = (DGRS_PRIV *)dev->priv;
dev->base_addr = io;
dev->mem_start = mem;
dev->mem_end = mem + 2048 * 1024 - 1;
dev->irq = irq;
priv->plxreg = plxreg;
priv->plxdma = plxdma;
priv->vplxdma = NULL;
priv->chan = 1;
priv->devtbl[0] = dev;
SET_NETDEV_DEV(dev, pdev);
ret = dgrs_probe1(dev);
if (ret)
goto err1;
ret = register_netdev(dev);
if (ret)
goto err2;
if ( !dgrs_nicmode )
return dev; /* Switch mode, we are done */
/*
* Operating card as N separate NICs
*/
priv->nports = priv->bcomm->bc_nports;
for (i = 1; i < priv->nports; ++i)
{
struct net_device *devN;
DGRS_PRIV *privN;
/* Allocate new dev and priv structures */
devN = alloc_etherdev(sizeof(DGRS_PRIV));
ret = -ENOMEM;
if (!devN)
goto fail;
/* Don't copy the network device structure! */
/* copy the priv structure of dev[0] */
privN = (DGRS_PRIV *)devN->priv;
*privN = *priv;
/* ... and zero out VM areas */
privN->vmem = NULL;
privN->vplxdma = NULL;
/* ... and zero out IRQ */
devN->irq = 0;
/* ... and base MAC address off address of 1st port */
devN->dev_addr[5] += i;
ret = dgrs_initclone(devN);
if (ret)
goto fail;
SET_NETDEV_DEV(dev, pdev);
ret = register_netdev(devN);
if (ret) {
free_netdev(devN);
goto fail;
}
privN->chan = i+1;
priv->devtbl[i] = devN;
}
return dev;
fail:
while (i >= 0) {
struct net_device *d = priv->devtbl[i--];
unregister_netdev(d);
free_netdev(d);
}
err2:
free_irq(dev->irq, dev);
err1:
free_netdev(dev);
err0:
return ERR_PTR(ret);
}
static void __devexit dgrs_remove(struct net_device *dev)
{
DGRS_PRIV *priv = dev->priv;
int i;
unregister_netdev(dev);
for (i = 1; i < priv->nports; ++i) {
struct net_device *d = priv->devtbl[i];
if (d) {
unregister_netdev(d);
free_netdev(d);
}
}
proc_reset(priv->devtbl[0], 1);
if (priv->vmem)
iounmap(priv->vmem);
if (priv->vplxdma)
iounmap((uchar *) priv->vplxdma);
if (dev->irq)
free_irq(dev->irq, dev);
for (i = 1; i < priv->nports; ++i) {
if (priv->devtbl[i])
unregister_netdev(priv->devtbl[i]);
}
}
#ifdef CONFIG_PCI
static int __init dgrs_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct net_device *dev;
int err;
uint io;
uint mem;
uint irq;
uint plxreg;
uint plxdma;
/*
* Get and check the bus-master and latency values.
* Some PCI BIOSes fail to set the master-enable bit,
* and the latency timer must be set to the maximum
* value to avoid data corruption that occurs when the
* timer expires during a transfer. Yes, it's a bug.
*/
err = pci_enable_device(pdev);
if (err)
return err;
err = pci_request_regions(pdev, "RightSwitch");
if (err)
return err;
pci_set_master(pdev);
plxreg = pci_resource_start (pdev, 0);
io = pci_resource_start (pdev, 1);
mem = pci_resource_start (pdev, 2);
pci_read_config_dword(pdev, 0x30, &plxdma);
irq = pdev->irq;
plxdma &= ~15;
/*
* On some BIOSES, the PLX "expansion rom" (used for DMA)
* address comes up as "0". This is probably because
* the BIOS doesn't see a valid 55 AA ROM signature at
* the "ROM" start and zeroes the address. To get
* around this problem the SE-6 is configured to ask
* for 4 MB of space for the dual port memory. We then
* must set its range back to 2 MB, and use the upper
* half for DMA register access
*/
OUTL(io + PLX_SPACE0_RANGE, 0xFFE00000L);
if (plxdma == 0)
plxdma = mem + (2048L * 1024L);
pci_write_config_dword(pdev, 0x30, plxdma + 1);
pci_read_config_dword(pdev, 0x30, &plxdma);
plxdma &= ~15;
dev = dgrs_found_device(io, mem, irq, plxreg, plxdma, &pdev->dev);
if (IS_ERR(dev)) {
pci_release_regions(pdev);
return PTR_ERR(dev);
}
pci_set_drvdata(pdev, dev);
return 0;
}
static void __devexit dgrs_pci_remove(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
dgrs_remove(dev);
pci_release_regions(pdev);
free_netdev(dev);
}
static struct pci_driver dgrs_pci_driver = {
.name = "dgrs",
.id_table = dgrs_pci_tbl,
.probe = dgrs_pci_probe,
.remove = __devexit_p(dgrs_pci_remove),
};
#else
static struct pci_driver dgrs_pci_driver = {};
#endif
#ifdef CONFIG_EISA
static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 };
static int __init dgrs_eisa_probe (struct device *gendev)
{
struct net_device *dev;
struct eisa_device *edev = to_eisa_device(gendev);
uint io = edev->base_addr;
uint mem;
uint irq;
int rc = -ENODEV; /* Not EISA configured */
if (!request_region(io, 256, "RightSwitch")) {
printk(KERN_ERR "dgrs: eisa io 0x%x, which is busy.\n", io);
return -EBUSY;
}
if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) )
goto err_out;
mem = (inb(io+ES4H_AS_31_24) << 24)
+ (inb(io+ES4H_AS_23_16) << 16);
irq = is2iv[ inb(io+ES4H_IS) & ES4H_IS_INTMASK ];
dev = dgrs_found_device(io, mem, irq, 0L, 0L, gendev);
if (IS_ERR(dev)) {
rc = PTR_ERR(dev);
goto err_out;
}
gendev->driver_data = dev;
return 0;
err_out:
release_region(io, 256);
return rc;
}
static int __devexit dgrs_eisa_remove(struct device *gendev)
{
struct net_device *dev = gendev->driver_data;
dgrs_remove(dev);
release_region(dev->base_addr, 256);
free_netdev(dev);
return 0;
}
static struct eisa_driver dgrs_eisa_driver = {
.id_table = dgrs_eisa_tbl,
.driver = {
.name = "dgrs",
.probe = dgrs_eisa_probe,
.remove = __devexit_p(dgrs_eisa_remove),
}
};
#endif
/*
* Variables that can be overriden from module command line
*/
static int debug = -1;
static int dma = -1;
static int hashexpire = -1;
static int spantree = -1;
static int ipaddr[4] = { -1 };
static int iptrap[4] = { -1 };
static __u32 ipxnet = -1;
static int nicmode = -1;
module_param(debug, int, 0);
module_param(dma, int, 0);
module_param(hashexpire, int, 0);
module_param(spantree, int, 0);
module_param_array(ipaddr, int, NULL, 0);
module_param_array(iptrap, int, NULL, 0);
module_param(ipxnet, int, 0);
module_param(nicmode, int, 0);
MODULE_PARM_DESC(debug, "Digi RightSwitch enable debugging (0-1)");
MODULE_PARM_DESC(dma, "Digi RightSwitch enable BM DMA (0-1)");
MODULE_PARM_DESC(nicmode, "Digi RightSwitch operating mode (1: switch, 2: multi-NIC)");
static int __init dgrs_init_module (void)
{
int i;
int err;
/*
* Command line variable overrides
* debug=NNN
* dma=0/1
* spantree=0/1
* hashexpire=NNN
* ipaddr=A,B,C,D
* iptrap=A,B,C,D
* ipxnet=NNN
* nicmode=NNN
*/
if (debug >= 0)
dgrs_debug = debug;
if (dma >= 0)
dgrs_dma = dma;
if (nicmode >= 0)
dgrs_nicmode = nicmode;
if (hashexpire >= 0)
dgrs_hashexpire = hashexpire;
if (spantree >= 0)
dgrs_spantree = spantree;
if (ipaddr[0] != -1)
for (i = 0; i < 4; ++i)
dgrs_ipaddr[i] = ipaddr[i];
if (iptrap[0] != -1)
for (i = 0; i < 4; ++i)
dgrs_iptrap[i] = iptrap[i];
if (ipxnet != -1)
dgrs_ipxnet = htonl( ipxnet );
if (dgrs_debug)
{
printk(KERN_INFO "dgrs: SW=%s FW=Build %d %s\nFW Version=%s\n",
version, dgrs_firmnum, dgrs_firmdate, dgrs_firmver);
}
/*
* Find and configure all the cards
*/
#ifdef CONFIG_EISA
err = eisa_driver_register(&dgrs_eisa_driver);
if (err)
return err;
#endif
err = pci_register_driver(&dgrs_pci_driver);
if (err)
return err;
return 0;
}
static void __exit dgrs_cleanup_module (void)
{
#ifdef CONFIG_EISA
eisa_driver_unregister (&dgrs_eisa_driver);
#endif
#ifdef CONFIG_PCI
pci_unregister_driver (&dgrs_pci_driver);
#endif
}
module_init(dgrs_init_module);
module_exit(dgrs_cleanup_module);
/*
* ioctl's for the Digi Intl. RightSwitch
*
* These network driver ioctl's are a bit obtuse compared to the usual
* ioctl's for a "normal" device driver. Hey, I didn't invent it.
*
* Typical use:
*
* struct ifreq ifr;
* DGRS_IOCTL ioc;
* int x;
*
* strcpy(ifr.ifr_name, "eth1");
* ifr.ifr_data = (caddr_t) &ioc;
* ioc.cmd = DGRS_GETMEM;
* ioc.len = sizeof(x);
* ioc.data = (caddr_t) &x;
* rc = ioctl(fd, DGRSIOCTL, &ifr);
* printf("rc=%d mem=%x\n", rc, x);
*
*/
#include <linux/sockios.h>
#define DGRSIOCTL SIOCDEVPRIVATE
typedef struct dgrs_ioctl {
unsigned short cmd; /* Command to run */
unsigned short len; /* Length of the data buffer */
unsigned char __user *data; /* Pointer to the data buffer */
unsigned short port; /* port number for command, if needed */
unsigned short filter; /* filter number for command, if needed */
} DGRS_IOCTL;
/*
* Commands for the driver
*/
#define DGRS_GETMEM 0x01 /* Get the dual port memory address */
#define DGRS_SETFILTER 0x02 /* Set a filter */
/*
* For declaring structures shared with assembly routines
*
* $Id: asstruct.h,v 1.1.1.1 1994/10/23 05:08:32 rick Exp $
*/
#ifdef ASSEMBLER
# define MO(t,a) (a)
# define VMO(t,a) (a)
# define BEGIN_STRUCT(x) _Off=0
# define S1A(t,x,n) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+(1*n)
# define S2A(t,x,n) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+(2*n)
# define S4A(t,x,n) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n)
# define WORD(x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
# define WORDA(x,n) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n)
# define VWORD(x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
# define S1(t,x) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+1
# define S2(t,x) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+2
# define S4(t,x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
# define END_STRUCT(x) _Off=(_Off+3)&~3; x=_Off
#else /* C */
#define VMO(t,a) (*(volatile t *)(a))
# define BEGIN_STRUCT(x) struct x {
# define S1(t,x) t x ;
# define S1A(t,x,n) t x[n] ;
# define S2(t,x) t x ;
# define S2A(t,x,n) t x[n] ;
# define S4(t,x) t x ;
# define S4A(t,x,n) t x[n] ;
# define END_STRUCT(x) } ;
#endif
/*
* The bios low-memory structure
*
* Some of the variables in here can be used to set parameters that
* are stored in NVRAM and will retain their old values the next time
* the card is brought up. To use the values stored in NVRAM, the
* parameter should be set to "all ones". This tells the firmware to
* use the NVRAM value or a suitable default. The value that is used
* will be stored back into this structure by the firmware. If the
* value of the variable is not "all ones", then that value will be
* used and will be stored into NVRAM if it isn't already there.
* The variables this applies to are the following:
* Variable Set to: Gets default of:
* bc_hashexpire -1 300 (5 minutes)
* bc_spantree -1 1 (spanning tree on)
* bc_ipaddr FF:FF:FF:FF 0 (no SNMP IP address)
* bc_ipxnet FF:FF:FF:FF 0 (no SNMP IPX net)
* bc_iptrap FF:FF:FF:FF 0 (no SNMP IP trap address)
*
* Some variables MUST have their value set after the firmware
* is loaded onto the board, but before the processor is released.
* These are:
* bc_host 0 means no host "port", run as standalone switch.
* 1 means run as a switch, with a host port. (normal)
* 2 means run as multiple NICs, not as a switch.
* -1 means run in diagnostics mode.
* bc_nowait
* bc_hostarea_len
* bc_filter_len
*
*/
BEGIN_STRUCT(bios_comm)
S4(ulong, bc_intflag) /* Count of all interrupts */
S4(ulong, bc_lbolt) /* Count of timer interrupts */
S4(ulong, bc_maincnt) /* Count of main loops */
S4(ulong, bc_hashcnt) /* Count of entries in hash table */
S4A(ulong, bc_cnt, 8) /* Misc counters, for debugging */
S4A(ulong, bc_flag, 8) /* Misc flags, for debugging */
S4(ulong, bc_memsize) /* Size of memory */
S4(ulong, bc_dcache) /* Size of working dcache */
S4(ulong, bc_icache) /* Size of working icache */
S4(long, bc_status) /* Firmware status */
S1A(char, bc_file, 8) /* File name of assertion failure */
S4(ulong, bc_line) /* Line # of assertion failure */
S4(uchar *, bc_ramstart)
S4(uchar *, bc_ramend)
S4(uchar *, bc_heapstart) /* Start of heap (end of loaded memory) */
S4(uchar *, bc_heapend) /* End of heap */
/* Configurable Parameters */
S4(long, bc_host) /* 1=Host Port, 0=No Host Port, -1=Test Mode */
S4(long, bc_nowait) /* Don't wait for 2host circ buffer to empty*/
S4(long, bc_150ohm) /* 0 == 100 ohm UTP, 1 == 150 ohm STP */
S4(long, bc_squelch) /* 0 == normal squelch, 1 == reduced squelch */
S4(ulong, bc_hashexpire) /* Expiry time in seconds for hash table */
S4(long, bc_spantree) /* 1 == enable IEEE spanning tree */
S2A(ushort, bc_eaddr, 3) /* New ether address */
S2(ushort, bc_dummy1) /* padding for DOS compilers */
/* Various debugging aids */
S4(long, bc_debug) /* Debugging is turned on */
S4(long, bc_spew) /* Spew data on port 4 for bs_spew seconds */
S4(long, bc_spewlen) /* Length of spewed data packets */
S4(long, bc_maxrfd) /* If != 0, max number of RFD's to allocate */
S4(long, bc_maxrbd) /* If != 0, max number of RBD's to allocate */
/* Circular buffers for messages to/from host */
S4(ulong, bc_2host_head)
S4(ulong, bc_2host_tail)
S4(ulong, bc_2host_mask)
S1A(char, bc_2host, 0x200) /* Circ buff to host */
S4(ulong, bc_2idt_head)
S4(ulong, bc_2idt_tail)
S4(ulong, bc_2idt_mask)
S1A(char, bc_2idt, 0x200) /* Circ buff to idt */
/* Pointers to structures for driver access */
S4(uchar *, bc_port) /* pointer to Port[] structures */
S4(long, bc_nports) /* Number of ports */
S4(long, bc_portlen) /* sizeof(PORT) */
S4(uchar *, bc_hash) /* Pointer to hash table */
S4(long, bc_hashlen) /* sizeof(Table) */
/* SNMP agent addresses */
S1A(uchar, bc_ipaddr, 4) /* IP address for SNMP */
S1A(uchar, bc_ipxnet, 4) /* IPX net address for SNMP */
S4(long, bc_nohostintr) /* Do not cause periodic host interrupts */
S4(uchar *, bc_dmaaddr) /* Physical addr of host DMA buf for diags */
S4(ulong, bc_dmalen) /* Length of DMA buffer 0..2048 */
/*
* Board memory allocated on startup for use by host, usually
* for the purposes of creating DMA chain descriptors. The
* "len" must be set before the processor is released. The
* address of the area is returned in bc_hostarea. The area
* is guaranteed to be aligned on a 16 byte boundary.
*/
S4(ulong, bc_hostarea_len) /* RW: Number of bytes to allocate */
S4(uchar *, bc_hostarea) /* RO: Address of allocated memory */
/*
* Variables for communicating filters into the board
*/
S4(ulong *, bc_filter_area) /* RO: Space to put filter into */
S4(ulong, bc_filter_area_len) /* RO: Length of area, in bytes */
S4(long, bc_filter_cmd) /* RW: Filter command, see below */
S4(ulong, bc_filter_len) /* RW: Actual length of filter */
S4(ulong, bc_filter_port) /* RW: Port # for filter 0..6 */
S4(ulong, bc_filter_num) /* RW: Filter #, 0=input, 1=output */
/* more SNMP agent addresses */
S1A(uchar, bc_iptrap, 4) /* IP address for SNMP */
S4A(long, bc_spare, 2) /* spares */
END_STRUCT(bios_comm)
#define bc VMO(struct bios_comm, 0xa3000100)
/*
* bc_status values
*/
#define BC_INIT 0
#define BC_RUN 100
/*
* bc_host values
*/
#define BC_DIAGS -1
#define BC_SASWITCH 0
#define BC_SWITCH 1
#define BC_MULTINIC 2
/*
* Values for spew (debugging)
*/
#define BC_SPEW_ENABLE 0x80000000
/*
* filter commands
*/
#define BC_FILTER_ERR -1
#define BC_FILTER_OK 0
#define BC_FILTER_SET 1
#define BC_FILTER_CLR 2
/************************************************************************/
/* */
/* es4h.h: Hardware definition of the ES/4h Ethernet Switch, from */
/* both the host and the 3051's point of view. */
/* NOTE: this name is a misnomer now that there is a PCI */
/* board. Everything that says "es4h" should really be */
/* "se4". But we'll keep the old name for now. */
/* */
/* $Id: es4h.h,v 1.10 1996/08/22 17:16:53 rick Exp $ */
/* */
/************************************************************************/
/************************************************************************/
/* */
/* EISA I/O Registers. These are located at 0x1000 * slot-number */
/* plus the indicated address. I.E. 0x4000-0x4009 for slot 4. */
/* */
/************************************************************************/
#define ES4H_MANUFmsb 0x00 /* Read-only */
#define ES4H_MANUFlsb 0x01 /* Read-only */
# define ES4H_MANUF_CODE 0x1049 /* = "DBI" */
#define ES4H_PRODUCT 0x02 /* Read-only */
# define ES4H_PRODUCT_CODE 0x0A
# define EPC_PRODUCT_CODE 0x03
#define ES4H_REVISION 0x03 /* Read-only */
# define ES4H_REVISION_CODE 0x01
#define ES4H_EC 0x04 /* EISA Control */
# define ES4H_EC_RESET 0x04 /* WO, EISA reset */
# define ES4H_EC_ENABLE 0x01 /* RW, EISA enable - set to */
/* 1 before memory enable */
#define ES4H_PC 0x05 /* Processor Control */
# define ES4H_PC_RESET 0x04 /* RW, 3051 reset */
# define ES4H_PC_INT 0x08 /* WO, assert 3051 intr. 3 */
#define ES4H_MW 0x06 /* Memory Window select and enable */
# define ES4H_MW_ENABLE 0x80 /* WO, enable memory */
# define ES4H_MW_SELECT_MASK 0x1f /* WO, 32k window selected */
#define ES4H_IS 0x07 /* Interrupt, addr select */
# define ES4H_IS_INTMASK 0x07 /* WO, interrupt select */
# define ES4H_IS_INTOFF 0x00 /* No IRQ */
# define ES4H_IS_INT3 0x03 /* IRQ 3 */
# define ES4H_IS_INT5 0x02 /* IRQ 5 */
# define ES4H_IS_INT7 0x01 /* IRQ 7 */
# define ES4H_IS_INT10 0x04 /* IRQ 10 */
# define ES4H_IS_INT11 0x05 /* IRQ 11 */
# define ES4H_IS_INT12 0x06 /* IRQ 12 */
# define ES4H_IS_INT15 0x07 /* IRQ 15 */
# define ES4H_IS_INTACK 0x10 /* WO, interrupt ack */
# define ES4H_IS_INTPEND 0x10 /* RO, interrupt pending */
# define ES4H_IS_LINEAR 0x40 /* WO, no memory windowing */
# define ES4H_IS_AS15 0x80 /* RW, address select bit 15 */
#define ES4H_AS_23_16 0x08 /* Address select bits 23-16 */
#define ES4H_AS_31_24 0x09 /* Address select bits 31-24 */
#define ES4H_IO_MAX 0x09 /* Size of I/O space */
/*
* PCI
*/
#define SE6_RESET PLX_USEROUT
/************************************************************************/
/* */
/* 3051 Memory Map */
/* */
/* Note: 3051 has 4K I-cache, 2K D-cache. 1 cycle is 50 nsec. */
/* */
/************************************************************************/
#define SE4_NPORTS 4 /* # of ethernet ports */
#define SE6_NPORTS 6 /* # of ethernet ports */
#define SE_NPORTS 6 /* Max # of ethernet ports */
#define ES4H_RAM_BASE 0x83000000 /* Base address of RAM */
#define ES4H_RAM_SIZE 0x00200000 /* Size of RAM (2MB) */
#define ES4H_RAM_INTBASE 0x83800000 /* Base of int-on-write RAM */
/* a.k.a. PKT RAM */
/* Ethernet controllers */
/* See: i82596.h */
#define ES4H_ETHER0_PORT 0xA2000000
#define ES4H_ETHER0_CMD 0xA2000100
#define ES4H_ETHER1_PORT 0xA2000200
#define ES4H_ETHER1_CMD 0xA2000300
#define ES4H_ETHER2_PORT 0xA2000400
#define ES4H_ETHER2_CMD 0xA2000500
#define ES4H_ETHER3_PORT 0xA2000600
#define ES4H_ETHER3_CMD 0xA2000700
#define ES4H_ETHER4_PORT 0xA2000800 /* RS SE-6 only */
#define ES4H_ETHER4_CMD 0xA2000900 /* RS SE-6 only */
#define ES4H_ETHER5_PORT 0xA2000A00 /* RS SE-6 only */
#define ES4H_ETHER5_CMD 0xA2000B00 /* RS SE-6 only */
#define ES4H_I8254 0xA2040000 /* 82C54 timers */
/* See: i8254.h */
#define SE4_I8254_HZ (23000000/4) /* EISA clock input freq. */
#define SE4_IDT_HZ (46000000) /* EISA CPU freq. */
#define SE6_I8254_HZ (20000000/4) /* PCI clock input freq. */
#define SE6_IDT_HZ (50000000) /* PCI CPU freq. */
#define ES4H_I8254_HZ (23000000/4) /* EISA clock input freq. */
#define ES4H_GPP 0xA2050000 /* General purpose port */
/*
* SE-4 (EISA) GPP bits
*/
# define ES4H_GPP_C0_100 0x0001 /* WO, Chan 0: 100 ohm TP */
# define ES4H_GPP_C0_SQE 0x0002 /* WO, Chan 0: normal squelch */
# define ES4H_GPP_C1_100 0x0004 /* WO, Chan 1: 100 ohm TP */
# define ES4H_GPP_C1_SQE 0x0008 /* WO, Chan 1: normal squelch */
# define ES4H_GPP_C2_100 0x0010 /* WO, Chan 2: 100 ohm TP */
# define ES4H_GPP_C2_SQE 0x0020 /* WO, Chan 2: normal squelch */
# define ES4H_GPP_C3_100 0x0040 /* WO, Chan 3: 100 ohm TP */
# define ES4H_GPP_C3_SQE 0x0080 /* WO, Chan 3: normal squelch */
# define ES4H_GPP_SQE 0x00AA /* WO, All: normal squelch */
# define ES4H_GPP_100 0x0055 /* WO, All: 100 ohm TP */
# define ES4H_GPP_HOSTINT 0x0100 /* RO, cause intr. to host */
/* Hold high > 250 nsec */
# define SE4_GPP_EED 0x0200 /* RW, EEPROM data bit */
# define SE4_GPP_EECS 0x0400 /* RW, EEPROM chip select */
# define SE4_GPP_EECK 0x0800 /* RW, EEPROM clock */
/*
* SE-6 (PCI) GPP bits
*/
# define SE6_GPP_EED 0x0001 /* RW, EEPROM data bit */
# define SE6_GPP_EECS 0x0002 /* RW, EEPROM chip select */
# define SE6_GPP_EECK 0x0004 /* RW, EEPROM clock */
# define SE6_GPP_LINK 0x00fc /* R, Link status LEDs */
#define ES4H_INTVEC 0xA2060000 /* RO: Interrupt Vector */
# define ES4H_IV_DMA0 0x01 /* Chan 0 DMA interrupt */
# define ES4H_IV_PKT0 0x02 /* Chan 0 PKT interrupt */
# define ES4H_IV_DMA1 0x04 /* Chan 1 DMA interrupt */
# define ES4H_IV_PKT1 0x08 /* Chan 1 PKT interrupt */
# define ES4H_IV_DMA2 0x10 /* Chan 2 DMA interrupt */
# define ES4H_IV_PKT2 0x20 /* Chan 2 PKT interrupt */
# define ES4H_IV_DMA3 0x40 /* Chan 3 DMA interrupt */
# define ES4H_IV_PKT3 0x80 /* Chan 3 PKT interrupt */
#define ES4H_INTACK 0xA2060000 /* WO: Interrupt Ack */
# define ES4H_INTACK_8254 0x01 /* Real Time Clock (int 0) */
# define ES4H_INTACK_HOST 0x02 /* Host (int 1) */
# define ES4H_INTACK_PKT0 0x04 /* Chan 0 Pkt (int 2) */
# define ES4H_INTACK_PKT1 0x08 /* Chan 1 Pkt (int 3) */
# define ES4H_INTACK_PKT2 0x10 /* Chan 2 Pkt (int 4) */
# define ES4H_INTACK_PKT3 0x20 /* Chan 3 Pkt (int 5) */
#define SE6_PLX 0xA2070000 /* PLX 9060, SE-6 (PCI) only */
/* see plx9060.h */
#define SE6_PCI_VENDOR_ID 0x114F /* Digi PCI vendor ID */
#define SE6_PCI_DEVICE_ID 0x0003 /* RS SE-6 device ID */
#define SE6_PCI_ID ((SE6_PCI_DEVICE_ID<<16) | SE6_PCI_VENDOR_ID)
/*
* IDT Interrupts
*/
#define ES4H_INT_8254 IDT_INT0
#define ES4H_INT_HOST IDT_INT1
#define ES4H_INT_ETHER0 IDT_INT2
#define ES4H_INT_ETHER1 IDT_INT3
#define ES4H_INT_ETHER2 IDT_INT4
#define ES4H_INT_ETHER3 IDT_INT5
/*
* Because there are differences between the SE-4 and the SE-6,
* we assume that the following globals will be set up at init
* time in main.c to containt the appropriate constants from above
*/
extern ushort Gpp; /* Softcopy of GPP register */
extern ushort EEck; /* Clock bit */
extern ushort EEcs; /* CS bit */
extern ushort EEd; /* Data bit */
extern ulong I8254_Hz; /* i8254 input frequency */
extern ulong IDT_Hz; /* IDT CPU frequency */
extern int Nports; /* Number of ethernet controllers */
extern int Nchan; /* Nports+1 */
/*
* A filtering function. There are two filters/port. Filter "0"
* is the input filter, and filter "1" is the output filter.
*/
typedef int (FILTER_FUNC)(uchar *pktp, int pktlen, ulong *scratch, int port);
#define NFILTERS 2
/*
* The per port structure
*/
typedef struct
{
int chan; /* Channel number (0-3) */
ulong portaddr; /* address of 596 port register */
volatile ulong *ca; /* address of 596 chan attention */
ulong intmask; /* Interrupt mask for this port */
ulong intack; /* Ack bit for this port */
uchar ethaddr[6]; /* Ethernet address of this port */
int is_promisc; /* Port is promiscuous */
int debug; /* Debugging turned on */
I596_ISCP *iscpp; /* Uncached ISCP pointer */
I596_SCP *scpp; /* Uncached SCP pointer */
I596_SCB *scbp; /* Uncached SCB pointer */
I596_ISCP iscp;
I596_SCB scb;
/* Command Queue */
I596_CB *cb0;
I596_CB *cbN;
I596_CB *cb_head;
I596_CB *cb_tail;
/* Receive Queue */
I596_RFD *rfd0;
I596_RFD *rfdN;
I596_RFD *rfd_head;
I596_RFD *rfd_tail;
/* Receive Buffers */
I596_RBD *rbd0;
I596_RBD *rbdN;
I596_RBD *rbd_head;
I596_RBD *rbd_tail;
int buf_size; /* Size of an RBD buffer */
int buf_cnt; /* Total RBD's allocated */
/* Rx Statistics */
ulong cnt_rx_cnt; /* Total packets rcvd, good and bad */
ulong cnt_rx_good; /* Total good packets rcvd */
ulong cnt_rx_bad; /* Total of all bad packets rcvd */
/* Subtotals can be gotten from SCB */
ulong cnt_rx_nores; /* No resources */
ulong cnt_rx_bytes; /* Total bytes rcvd */
/* Tx Statistics */
ulong cnt_tx_queued;
ulong cnt_tx_done;
ulong cnt_tx_freed;
ulong cnt_tx_nores; /* No resources */
ulong cnt_tx_bad;
ulong cnt_tx_err_late;
ulong cnt_tx_err_nocrs;
ulong cnt_tx_err_nocts;
ulong cnt_tx_err_under;
ulong cnt_tx_err_maxcol;
ulong cnt_tx_collisions;
/* Special stuff for host */
# define rfd_freed cnt_rx_cnt
ulong rbd_freed;
int host_timer;
/* Added after first beta */
ulong cnt_tx_races; /* Counts race conditions */
int spanstate;
ulong cnt_st_tx; /* send span tree pkts */
ulong cnt_st_fail_tx; /* Failures to send span tree pkts */
ulong cnt_st_fail_rbd;/* Failures to send span tree pkts */
ulong cnt_st_rx; /* rcv span tree pkts */
ulong cnt_st_rx_bad; /* bogus st packets rcvd */
ulong cnt_rx_fwd; /* Rcvd packets that were forwarded */
ulong cnt_rx_mcast; /* Multicast pkts received */
ulong cnt_tx_mcast; /* Multicast pkts transmitted */
ulong cnt_tx_bytes; /* Bytes transmitted */
/*
* Packet filtering
* Filter 0: input filter
* Filter 1: output filter
*/
ulong *filter_space[NFILTERS];
FILTER_FUNC *filter_func[NFILTERS];
ulong filter_cnt[NFILTERS];
ulong filter_len[NFILTERS];
ulong pad[ (512-300) / 4];
} PORT;
/*
* Port[0] is host interface
* Port[1..SE_NPORTS] are external 10 Base T ports. Fewer may be in
* use, depending on whether this is an SE-4 or
* an SE-6.
* Port[SE_NPORTS] Pseudo-port for Spanning tree and SNMP
*/
extern PORT Port[1+SE_NPORTS+1];
extern int Nports; /* Number of genuine ethernet controllers */
extern int Nchan; /* ... plus one for host interface */
extern int FirstChan; /* 0 or 1, depedning on whether host is used */
extern int NumChan; /* 4 or 5 */
/*
* A few globals
*/
extern int IsPromisc;
extern int MultiNicMode;
/*
* Functions
*/
extern void eth_xmit_spew_on(PORT *p, int cnt);
extern void eth_xmit_spew_off(PORT *p);
extern I596_RBD *alloc_rbds(PORT *p, int num);
extern I596_CB * eth_cb_alloc(PORT *p);
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* i82596 ethernet controller bits and structures (little endian)
*
* $Id: i82596.h,v 1.8 1996/09/03 11:19:03 rick Exp $
*/
/************************************************************************/
/* */
/* PORT commands (p. 4-20). The least significant nibble is one */
/* of these commands, the rest of the command is a memory address */
/* aligned on a 16 byte boundary. Note that port commands must */
/* be written to the PORT address and the PORT address+2 with two */
/* halfword writes. Write the LSH first to PORT, then the MSH to */
/* PORT+2. Blame Intel. */
/* */
/************************************************************************/
#define I596_PORT_RESET 0x0 /* Reset. Wait 5 SysClks & 10 TxClks */
#define I596_PORT_SELFTEST 0x1 /* Do a selftest */
#define I596_PORT_SCP_ADDR 0x2 /* Set new SCP address */
#define I596_PORT_DUMP 0x3 /* Dump internal data structures */
/*
* I596_ST: Selftest results (p. 4-21)
*/
typedef volatile struct
{
ulong signature; /* ROM checksum */
ulong result; /* Selftest results: non-zero is a failure */
} I596_ST;
#define I596_ST_SELFTEST_FAIL 0x1000 /* Selftest Failed */
#define I596_ST_DIAGNOSE_FAIL 0x0020 /* Diagnose Failed */
#define I596_ST_BUSTIMER_FAIL 0x0010 /* Bus Timer Failed */
#define I596_ST_REGISTER_FAIL 0x0008 /* Register Failed */
#define I596_ST_ROM_FAIL 0x0004 /* ROM Failed */
/*
* I596_DUMP: Dump results
*/
typedef volatile struct
{
ulong dump[77];
} I596_DUMP;
/************************************************************************/
/* */
/* I596_TBD: Transmit Buffer Descriptor (p. 4-59) */
/* */
/************************************************************************/
typedef volatile struct _I596_TBD
{
ulong count;
vol struct _I596_TBD *next;
uchar *buf;
ushort unused1;
ushort unused2;
} I596_TBD;
#define I596_TBD_NOLINK ((I596_TBD *) 0xffffffff)
#define I596_TBD_EOF 0x8000
#define I596_TBD_COUNT_MASK 0x3fff
/************************************************************************/
/* */
/* I596_TFD: Transmit Frame Descriptor (p. 4-56) */
/* a.k.a. I596_CB_XMIT */
/* */
/************************************************************************/
typedef volatile struct
{
ushort status;
ushort cmd;
union _I596_CB *next;
I596_TBD *tbdp;
ulong count; /* for speed */
/* Application defined data follows structure... */
#if 0 /* We don't use these intel defined ones */
uchar addr[6];
ushort len;
uchar data[1];
#else
ulong dstchan;/* Used by multi-NIC mode */
#endif
} I596_TFD;
#define I596_TFD_NOCRC 0x0010 /* cmd: No CRC insertion */
#define I596_TFD_FLEX 0x0008 /* cmd: Flexible mode */
/************************************************************************/
/* */
/* I596_RBD: Receive Buffer Descriptor (p. 4-84) */
/* */
/************************************************************************/
typedef volatile struct _I596_RBD
{
#ifdef INTEL_RETENTIVE
ushort count; /* Length of data in buf */
ushort offset;
#else
ulong count; /* Length of data in buf */
#endif
vol struct _I596_RBD *next; /* Next buffer descriptor in list */
uchar *buf; /* Data buffer */
#ifdef INTEL_RETENTIVE
ushort size; /* Size of buf (constant) */
ushort zero;
#else
ulong size; /* Size of buf (constant) */
#endif
/* Application defined data follows structure... */
uchar chan;
uchar refcnt;
ushort len;
} I596_RBD;
#define I596_RBD_NOLINK ((I596_RBD *) 0xffffffff)
#define I596_RBD_EOF 0x8000 /* This is last buffer in a frame */
#define I596_RBD_F 0x4000 /* The actual count is valid */
#define I596_RBD_EL 0x8000 /* Last buffer in list */
/************************************************************************/
/* */
/* I596_RFD: Receive Frame Descriptor (p. 4-79) */
/* */
/************************************************************************/
typedef volatile struct _I596_RFD
{
ushort status;
ushort cmd;
vol struct _I596_RFD *next;
vol struct _I596_RBD *rbdp;
ushort count; /* Len of data in RFD: always 0 */
ushort size; /* Size of RFD buffer: always 0 */
/* Application defined data follows structure... */
# if 0 /* We don't use these intel defined ones */
uchar addr[6];
ushort len;
uchar data[1];
# else
ulong dstchan;/* Used by multi-nic mode */
# endif
} I596_RFD;
#define I596_RFD_C 0x8000 /* status: frame complete */
#define I596_RFD_B 0x4000 /* status: frame busy or waiting */
#define I596_RFD_OK 0x2000 /* status: frame OK */
#define I596_RFD_ERR_LENGTH 0x1000 /* status: length error */
#define I596_RFD_ERR_CRC 0x0800 /* status: CRC error */
#define I596_RFD_ERR_ALIGN 0x0400 /* status: alignment error */
#define I596_RFD_ERR_NOBUFS 0x0200 /* status: resource error */
#define I596_RFD_ERR_DMA 0x0100 /* status: DMA error */
#define I596_RFD_ERR_SHORT 0x0080 /* status: too short error */
#define I596_RFD_NOMATCH 0x0002 /* status: IA was not matched */
#define I596_RFD_COLLISION 0x0001 /* status: collision during receive */
#define I596_RFD_EL 0x8000 /* cmd: end of RFD list */
#define I596_RFD_FLEX 0x0008 /* cmd: Flexible mode */
#define I596_RFD_EOF 0x8000 /* count: last buffer in the frame */
#define I596_RFD_F 0x4000 /* count: The actual count is valid */
/************************************************************************/
/* */
/* Commands */
/* */
/************************************************************************/
/* values for cmd halfword in all the structs below */
#define I596_CB_CMD 0x07 /* CB COMMANDS */
#define I596_CB_CMD_NOP 0
#define I596_CB_CMD_IA 1
#define I596_CB_CMD_CONF 2
#define I596_CB_CMD_MCAST 3
#define I596_CB_CMD_XMIT 4
#define I596_CB_CMD_TDR 5
#define I596_CB_CMD_DUMP 6
#define I596_CB_CMD_DIAG 7
#define I596_CB_CMD_EL 0x8000 /* CB is last in linked list */
#define I596_CB_CMD_S 0x4000 /* Suspend after execution */
#define I596_CB_CMD_I 0x2000 /* cause interrupt */
/* values for the status halfword in all the struct below */
#define I596_CB_STATUS 0xF000 /* All four status bits */
#define I596_CB_STATUS_C 0x8000 /* Command complete */
#define I596_CB_STATUS_B 0x4000 /* Command busy executing */
#define I596_CB_STATUS_C_OR_B 0xC000 /* Command complete or busy */
#define I596_CB_STATUS_OK 0x2000 /* Command complete, no errors */
#define I596_CB_STATUS_A 0x1000 /* Command busy executing */
#define I596_CB_NOLINK ((I596_CB *) 0xffffffff)
/*
* I596_CB_NOP: NOP Command (p. 4-34)
*/
typedef volatile struct
{
ushort status;
ushort cmd;
union _I596_CB *next;
} I596_CB_NOP;
/*
* Same as above, but command and status in one ulong for speed
*/
typedef volatile struct
{
ulong csr;
union _I596_CB *next;
} I596_CB_FAST;
#define FASTs(X) (X)
#define FASTc(X) ((X)<<16)
/*
* I596_CB_IA: Individual (MAC) Address Command (p. 4-35)
*/
typedef volatile struct
{
ushort status;
ushort cmd;
union _I596_CB *next;
uchar addr[6];
} I596_CB_IA;
/*
* I596_CB_CONF: Configure Command (p. 4-37)
*/
typedef volatile struct
{
ushort status;
ushort cmd;
union _I596_CB *next;
uchar conf[14];
} I596_CB_CONF;
#define I596_CONF0_P 0x80 /* Enable RBD Prefetch Bit */
#define I596_CONF0_COUNT 14 /* Count of configuration bytes */
#define I596_CONF1_MON_OFF 0xC0 /* Monitor mode: Monitor off */
#define I596_CONF1_MON_ON 0x80 /* Monitor mode: Monitor on */
#define I596_CONF1_TxFIFO(W) (W) /* TxFIFO trigger, in words */
#define I596_CONF2_SAVEBF 0x80 /* Save bad frames */
#define I596_CONF3_ADDRLEN(B) (B) /* Address length */
#define I596_CONF3_NOSRCINSERT 0x08 /* Do not insert source address */
#define I596_CONF3_PREAMBLE8 0x20 /* 8 byte preamble */
#define I596_CONF3_LOOPOFF 0x00 /* Loopback: Off */
#define I596_CONF3_LOOPINT 0x40 /* Loopback: internal */
#define I596_CONF3_LOOPEXT 0xC0 /* Loopback: external */
#define I596_CONF4_LINPRI(ST) (ST) /* Linear priority: slot times */
#define I596_CONF4_EXPPRI(ST) (ST) /* Exponential priority: slot times */
#define I596_CONF4_IEEE_BOM 0 /* IEEE 802.3 backoff method */
#define I596_CONF5_IFS(X) (X) /* Interframe spacing in clocks */
#define I596_CONF6_ST_LOW(X) (X&255) /* Slot time, low byte */
#define I596_CONF7_ST_HI(X) (X>>8) /* Slot time, high bits */
#define I596_CONF7_RETRY(X) (X<<4) /* Max retry number */
#define I596_CONF8_PROMISC 0x01 /* Rcv all frames */
#define I596_CONF8_NOBROAD 0x02
#define I596_CONF8_MANCHESTER 0x04
#define I596_CONF8_TxNOCRS 0x08
#define I596_CONF8_NOCRC 0x10
#define I596_CONF8_CRC_CCITT 0x20
#define I596_CONF8_BITSTUFFING 0x40
#define I596_CONF8_PADDING 0x80
#define I596_CONF9_CSFILTER(X) (X)
#define I596_CONF9_CSINT(X) 0x08
#define I596_CONF9_CDFILTER(X) (X<<4)
#define I596_CONF9_CDINT(X) 0x80
#define I596_CONF10_MINLEN(X) (X) /* Minimum frame length */
#define I596_CONF11_PRECRS_ 0x01 /* Preamble before carrier sense */
#define I596_CONF11_LNGFLD_ 0x02 /* Padding in End of Carrier */
#define I596_CONF11_CRCINM_ 0x04 /* CRC in memory */
#define I596_CONF11_AUTOTX 0x08 /* Auto retransmit */
#define I596_CONF11_CSBSAC_ 0x10 /* Collision detect by src addr cmp. */
#define I596_CONF11_MCALL_ 0x20 /* Multicast all */
#define I596_CONF13_RESERVED 0x3f /* Reserved: must be ones */
#define I596_CONF13_MULTIA 0x40 /* Enable multiple addr. reception */
#define I596_CONF13_DISBOF 0x80 /* Disable backoff algorithm */
/*
* I596_CB_MCAST: Multicast-Setup Command (p. 4-54)
*/
typedef volatile struct
{
ushort status;
ushort cmd;
union _I596_CB *next;
ushort count; /* Number of 6-byte addrs that follow */
uchar addr[6][1];
} I596_CB_MCAST;
/*
* I596_CB_XMIT: Transmit Command (p. 4-56)
*/
typedef I596_TFD I596_CB_XMIT;
#define I596_CB_XMIT_NOCRC 0x0010 /* cmd: No CRC insertion */
#define I596_CB_XMIT_FLEX 0x0008 /* cmd: Flexible memory mode */
#define I596_CB_XMIT_ERR_LATE 0x0800 /* status: error: late collision */
#define I596_CB_XMIT_ERR_NOCRS 0x0400 /* status: error: no carriers sense */
#define I596_CB_XMIT_ERR_NOCTS 0x0200 /* status: error: loss of CTS */
#define I596_CB_XMIT_ERR_UNDER 0x0100 /* status: error: DMA underrun */
#define I596_CB_XMIT_ERR_MAXCOL 0x0020 /* status: error: maximum collisions */
#define I596_CB_XMIT_COLLISIONS 0x000f /* status: number of collisions */
/*
* I596_CB_TDR: Time Domain Reflectometry Command (p. 4-63)
*/
typedef volatile struct
{
ushort status;
ushort cmd;
union _I596_CB *next;
ushort time;
} I596_CB_TDR;
/*
* I596_CB_DUMP: Dump Command (p. 4-65)
*/
typedef volatile struct
{
ushort status;
ushort cmd;
union _I596_CB *next;
uchar *buf;
} I596_CB_DUMP;
/*
* I596_CB_DIAG: Diagnose Command (p. 4-77)
*/
typedef volatile struct
{
ushort status;
ushort cmd;
union _I596_CB *next;
} I596_CB_DIAG;
/*
* I596_CB: Command Block
*/
typedef union _I596_CB
{
I596_CB_NOP nop;
I596_CB_IA ia;
I596_CB_CONF conf;
I596_CB_MCAST mcast;
I596_CB_XMIT xmit;
I596_CB_TDR tdr;
I596_CB_DUMP dump;
I596_CB_DIAG diag;
/* command and status in one ulong for speed... */
I596_CB_FAST fast;
} I596_CB;
/************************************************************************/
/* */
/* I596_SCB: System Configuration Block (p. 4-26) */
/* */
/************************************************************************/
typedef volatile struct
{
volatile ushort status; /* Status word */
volatile ushort cmd; /* Command word */
I596_CB *cbp;
I596_RFD *rfdp;
ulong crc_errs;
ulong align_errs;
ulong resource_errs;
ulong overrun_errs;
ulong rcvcdt_errs;
ulong short_errs;
ushort toff;
ushort ton;
} I596_SCB;
/* cmd halfword values */
#define I596_SCB_ACK 0xF000 /* ACKNOWLEDGMENTS */
#define I596_SCB_ACK_CX 0x8000 /* Ack command completion */
#define I596_SCB_ACK_FR 0x4000 /* Ack received frame */
#define I596_SCB_ACK_CNA 0x2000 /* Ack command unit not active */
#define I596_SCB_ACK_RNR 0x1000 /* Ack rcv unit not ready */
#define I596_SCB_ACK_ALL 0xF000 /* Ack everything */
#define I596_SCB_CUC 0x0700 /* COMMAND UNIT COMMANDS */
#define I596_SCB_CUC_NOP 0x0000 /* No operation */
#define I596_SCB_CUC_START 0x0100 /* Start execution of first CB */
#define I596_SCB_CUC_RESUME 0x0200 /* Resume execution */
#define I596_SCB_CUC_SUSPEND 0x0300 /* Suspend after current CB */
#define I596_SCB_CUC_ABORT 0x0400 /* Abort current CB immediately */
#define I596_SCB_CUC_LOAD 0x0500 /* Load Bus throttle timers */
#define I596_SCB_CUC_LOADIMM 0x0600 /* Load Bus throttle timers, now */
#define I596_SCB_RUC 0x0070 /* RECEIVE UNIT COMMANDS */
#define I596_SCB_RUC_NOP 0x0000 /* No operation */
#define I596_SCB_RUC_START 0x0010 /* Start reception */
#define I596_SCB_RUC_RESUME 0x0020 /* Resume reception */
#define I596_SCB_RUC_SUSPEND 0x0030 /* Suspend reception */
#define I596_SCB_RUC_ABORT 0x0040 /* Abort reception */
#define I596_SCB_RESET 0x0080 /* Hard reset chip */
/* status halfword values */
#define I596_SCB_STAT 0xF000 /* STATUS */
#define I596_SCB_CX 0x8000 /* command completion */
#define I596_SCB_FR 0x4000 /* received frame */
#define I596_SCB_CNA 0x2000 /* command unit not active */
#define I596_SCB_RNR 0x1000 /* rcv unit not ready */
#define I596_SCB_CUS 0x0700 /* COMMAND UNIT STATUS */
#define I596_SCB_CUS_IDLE 0x0000 /* Idle */
#define I596_SCB_CUS_SUSPENDED 0x0100 /* Suspended */
#define I596_SCB_CUS_ACTIVE 0x0200 /* Active */
#define I596_SCB_RUS 0x00F0 /* RECEIVE UNIT STATUS */
#define I596_SCB_RUS_IDLE 0x0000 /* Idle */
#define I596_SCB_RUS_SUSPENDED 0x0010 /* Suspended */
#define I596_SCB_RUS_NORES 0x0020 /* No Resources */
#define I596_SCB_RUS_READY 0x0040 /* Ready */
#define I596_SCB_RUS_NORBDS 0x0080 /* No more RBDs modifier */
#define I596_SCB_LOADED 0x0008 /* Bus timers loaded */
/************************************************************************/
/* */
/* I596_ISCP: Intermediate System Configuration Ptr (p 4-26) */
/* */
/************************************************************************/
typedef volatile struct
{
ulong busy; /* Set to 1; I596 clears it when scbp is read */
I596_SCB *scbp;
} I596_ISCP;
/************************************************************************/
/* */
/* I596_SCP: System Configuration Pointer (p. 4-23) */
/* */
/************************************************************************/
typedef volatile struct
{
ulong sysbus;
ulong dummy;
I596_ISCP *iscpp;
} I596_SCP;
/* .sysbus values */
#define I596_SCP_RESERVED 0x400000 /* Reserved bits must be set */
#define I596_SCP_INTLOW 0x200000 /* Intr. Polarity active low */
#define I596_SCP_INTHIGH 0 /* Intr. Polarity active high */
#define I596_SCP_LOCKDIS 0x100000 /* Lock Function disabled */
#define I596_SCP_LOCKEN 0 /* Lock Function enabled */
#define I596_SCP_ETHROTTLE 0x080000 /* External Bus Throttle */
#define I596_SCP_ITHROTTLE 0 /* Internal Bus Throttle */
#define I596_SCP_LINEAR 0x040000 /* Linear Mode */
#define I596_SCP_SEGMENTED 0x020000 /* Segmented Mode */
#define I596_SCP_82586 0x000000 /* 82586 Mode */
/*
* PLX 9060 PCI Interface chip
*/
/*
* PCI configuration registers, same offset on local and PCI sides,
* but on PCI side, must use PCI BIOS calls to read/write.
*/
#define PCI_PLXREGS_BASE_ADDR 0x10
#define PCI_PLXREGS_IO_ADDR 0x14
#define PCI_SPACE0_BASE_ADDR 0x18
#define PCI_ROM_BASE_ADDR 0x30
# define PCI_ROM_ENABLED 0x00000001
#define PCI_INT_LINE 0x3C
/*
* Registers accessible directly from PCI and local side.
* Offset is from PCI side. Add PLX_LCL_OFFSET for local address.
*/
#define PLX_LCL_OFFSET 0x80 /* Offset of regs from local side */
/*
* Local Configuration Registers
*/
#define PLX_SPACE0_RANGE 0x00 /* Range for PCI to Lcl Addr Space 0 */
#define PLX_SPACE0_BASE_ADDR 0x04 /* Lcl Base address remap */
#define PLX_ROM_RANGE 0x10 /* Range for expansion ROM (DMA) */
#define PLX_ROM_BASE_ADDR 0x14 /* Lcl base address remap for ROM */
#define PLX_BUS_REGION 0x18 /* Bus Region Descriptors */
/*
* Shared Run Time Registers
*/
#define PLX_MBOX0 0x40
#define PLX_MBOX1 0x44
#define PLX_MBOX2 0x48
#define PLX_MBOX3 0x4C
#define PLX_MBOX4 0x50
#define PLX_MBOX5 0x54
#define PLX_MBOX6 0x58
#define PLX_MBOX7 0x5C
#define PLX_PCI2LCL_DOORBELL 0x60
#define PLX_LCL2PCI_DOORBELL 0x64
#define PLX_INT_CSR 0x68 /* Interrupt Control/Status */
# define PLX_LSERR_ENABLE 0x00000001
# define PLX_LSERR_PE 0x00000002
# define PLX_SERR 0x00000004
# undef PLX_UNUSED /* 0x00000008 */
# undef PLX_UNUSED /* 0x00000010 */
# undef PLX_UNUSED /* 0x00000020 */
# undef PLX_UNUSED /* 0x00000040 */
# undef PLX_UNUSED /* 0x00000080 */
# define PLX_PCI_IE 0x00000100
# define PLX_PCI_DOORBELL_IE 0x00000200
# define PLX_PCI_ABORT_IE 0x00000400
# define PLX_PCI_LOCAL_IE 0x00000800
# define PLX_RETRY_ABORT_ENABLE 0x00001000
# define PLX_PCI_DOORBELL_INT 0x00002000
# define PLX_PCI_ABORT_INT 0x00004000
# define PLX_PCI_LOCAL_INT 0x00008000
# define PLX_LCL_IE 0x00010000
# define PLX_LCL_DOORBELL_IE 0x00020000
# define PLX_LCL_DMA0_IE 0x00040000
# define PLX_LCL_DMA1_IE 0x00080000
# define PLX_LCL_DOORBELL_INT 0x00100000
# define PLX_LCL_DMA0_INT 0x00200000
# define PLX_LCL_DMA1_INT 0x00400000
# define PLX_LCL_BIST_INT 0x00800000
# define PLX_BM_DIRECT_ 0x01000000
# define PLX_BM_DMA0_ 0x02000000
# define PLX_BM_DMA1_ 0x04000000
# define PLX_BM_ABORT_ 0x08000000
# undef PLX_UNUSED /* 0x10000000 */
# undef PLX_UNUSED /* 0x20000000 */
# undef PLX_UNUSED /* 0x40000000 */
# undef PLX_UNUSED /* 0x80000000 */
#define PLX_MISC_CSR 0x6c /* EEPROM,PCI,User,Init Control/Status*/
# define PLX_USEROUT 0x00010000
# define PLX_USERIN 0x00020000
# define PLX_EECK 0x01000000
# define PLX_EECS 0x02000000
# define PLX_EEWD 0x04000000
# define PLX_EERD 0x08000000
/*
* DMA registers. Offset is from local side
*/
#define PLX_DMA0_MODE 0x100
# define PLX_DMA_MODE_WIDTH32 0x00000003
# define PLX_DMA_MODE_WAITSTATES(X) ((X)<<2)
# define PLX_DMA_MODE_NOREADY 0x00000000
# define PLX_DMA_MODE_READY 0x00000040
# define PLX_DMA_MODE_NOBTERM 0x00000000
# define PLX_DMA_MODE_BTERM 0x00000080
# define PLX_DMA_MODE_NOBURST 0x00000000
# define PLX_DMA_MODE_BURST 0x00000100
# define PLX_DMA_MODE_NOCHAIN 0x00000000
# define PLX_DMA_MODE_CHAIN 0x00000200
# define PLX_DMA_MODE_DONE_IE 0x00000400
# define PLX_DMA_MODE_ADDR_HOLD 0x00000800
#define PLX_DMA0_PCI_ADDR 0x104
/* non-chaining mode PCI address */
#define PLX_DMA0_LCL_ADDR 0x108
/* non-chaining mode local address */
#define PLX_DMA0_SIZE 0x10C
/* non-chaining mode length */
#define PLX_DMA0_DESCRIPTOR 0x110
# define PLX_DMA_DESC_EOC 0x00000002
# define PLX_DMA_DESC_TC_IE 0x00000004
# define PLX_DMA_DESC_TO_HOST 0x00000008
# define PLX_DMA_DESC_TO_BOARD 0x00000000
# define PLX_DMA_DESC_NEXTADDR 0xFFFFfff0
#define PLX_DMA1_MODE 0x114
#define PLX_DMA1_PCI_ADDR 0x118
#define PLX_DMA1_LCL_ADDR 0x11C
#define PLX_DMA1_SIZE 0x110
#define PLX_DMA1_DESCRIPTOR 0x124
#define PLX_DMA_CSR 0x128
# define PLX_DMA_CSR_0_ENABLE 0x00000001
# define PLX_DMA_CSR_0_START 0x00000002
# define PLX_DMA_CSR_0_ABORT 0x00000004
# define PLX_DMA_CSR_0_CLR_INTR 0x00000008
# define PLX_DMA_CSR_0_DONE 0x00000010
# define PLX_DMA_CSR_1_ENABLE 0x00000100
# define PLX_DMA_CSR_1_START 0x00000200
# define PLX_DMA_CSR_1_ABORT 0x00000400
# define PLX_DMA_CSR_1_CLR_INTR 0x00000800
# define PLX_DMA_CSR_1_DONE 0x00001000
#define PLX_DMA_ARB0 0x12C
# define PLX_DMA_ARB0_LATENCY_T 0x000000FF
# define PLX_DMA_ARB0_PAUSE_T 0x0000FF00
# define PLX_DMA_ARB0_LATENCY_EN 0x00010000
# define PLX_DMA_ARB0_PAUSE_EN 0x00020000
# define PLX_DMA_ARB0_BREQ_EN 0x00040000
# define PLX_DMA_ARB0_PRI 0x00180000
# define PLX_DMA_ARB0_PRI_ROUND 0x00000000
# define PLX_DMA_ARB0_PRI_0 0x00080000
# define PLX_DMA_ARB0_PRI_1 0x00100000
#define PLX_DMA_ARB1 0x130
/* Chan 0: FIFO DEPTH=16 */
# define PLX_DMA_ARB1_0_P2L_LW_TRIG(X) ( ((X)&15) << 0 )
# define PLX_DMA_ARB1_0_L2P_LR_TRIG(X) ( ((X)&15) << 4 )
# define PLX_DMA_ARB1_0_L2P_PW_TRIG(X) ( ((X)&15) << 8 )
# define PLX_DMA_ARB1_0_P2L_PR_TRIG(X) ( ((X)&15) << 12 )
/* Chan 1: FIFO DEPTH=8 */
# define PLX_DMA_ARB1_1_P2L_LW_TRIG(X) ( ((X)& 7) << 16 )
# define PLX_DMA_ARB1_1_L2P_LR_TRIG(X) ( ((X)& 7) << 20 )
# define PLX_DMA_ARB1_1_L2P_PW_TRIG(X) ( ((X)& 7) << 24 )
# define PLX_DMA_ARB1_1_P2L_PR_TRIG(X) ( ((X)& 7) << 28 )
typedef struct _dmachain
{
ulong pciaddr;
ulong lcladdr;
ulong len;
ulong next;
} DMACHAIN;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment