Now that we have the en(4) driver, we no longer need the hea driver.
Approved by: harti@
This commit is contained in:
parent
6ee2f106aa
commit
1da8b3b984
@ -653,9 +653,6 @@ options ZERO_COPY_SOCKETS
|
||||
# ATM_UNI includes support for the `uni30' and `uni31' signalling managers,
|
||||
# which run the ATM Forum UNI 3.x signalling protocols.
|
||||
#
|
||||
# The `hea' driver provides support for the Efficient Networks, Inc.
|
||||
# ENI-155p ATM PCI Adapter.
|
||||
#
|
||||
# The `hfa' driver provides support for the FORE Systems, Inc.
|
||||
# PCA-200E ATM PCI Adapter.
|
||||
#
|
||||
@ -667,7 +664,6 @@ options ATM_SIGPVC #SIGPVC signalling manager
|
||||
options ATM_SPANS #SPANS signalling manager
|
||||
options ATM_UNI #UNI signalling manager
|
||||
|
||||
device hea #Efficient ENI-155p ATM PCI
|
||||
device hfa #FORE PCA-200E ATM PCI
|
||||
device harp #Pseudo-interface for NATM
|
||||
|
||||
|
@ -430,17 +430,6 @@ dev/hatm/if_hatm_intr.c optional hatm pci
|
||||
dev/hatm/if_hatm_ioctl.c optional hatm pci
|
||||
dev/hatm/if_hatm_rx.c optional hatm pci
|
||||
dev/hatm/if_hatm_tx.c optional hatm pci
|
||||
dev/hea/eni.c optional hea nowerror
|
||||
dev/hea/eni_buffer.c optional hea nowerror
|
||||
dev/hea/eni_globals.c optional hea
|
||||
dev/hea/eni_if.c optional hea
|
||||
dev/hea/eni_init.c optional hea
|
||||
dev/hea/eni_intr.c optional hea
|
||||
dev/hea/eni_receive.c optional hea
|
||||
dev/hea/eni_transmit.c optional hea
|
||||
dev/hea/eni_vcm.c optional hea nowerror
|
||||
dev/hea/hea_pci.c optional hea pci
|
||||
dev/hea/hea_freebsd.c optional hea
|
||||
dev/hfa/fore_buffer.c optional hfa
|
||||
dev/hfa/fore_command.c optional hfa
|
||||
dev/hfa/fore_globals.c optional hfa
|
||||
|
@ -1,697 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Efficient ENI adapter support
|
||||
* -----------------------------
|
||||
*
|
||||
* Module supports PCI interface to ENI adapter
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
|
||||
#include <netatm/port.h>
|
||||
#include <netatm/queue.h>
|
||||
#include <netatm/atm.h>
|
||||
#include <netatm/atm_sys.h>
|
||||
#include <netatm/atm_sap.h>
|
||||
#include <netatm/atm_cm.h>
|
||||
#include <netatm/atm_if.h>
|
||||
#include <netatm/atm_stack.h>
|
||||
#include <netatm/atm_pcb.h>
|
||||
#include <netatm/atm_var.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
#include <dev/hea/eni_stats.h>
|
||||
#include <dev/hea/eni.h>
|
||||
#include <dev/hea/eni_var.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("@(#) $FreeBSD$");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Typedef local functions
|
||||
*/
|
||||
#if 0
|
||||
static const char *eni_pci_probe(pcici_t, pcidi_t);
|
||||
static void eni_pci_attach(pcici_t, int);
|
||||
#endif
|
||||
static int eni_get_ack(Eni_unit *);
|
||||
static int eni_get_sebyte(Eni_unit *);
|
||||
void eni_read_seeprom(Eni_unit *);
|
||||
#if 0
|
||||
#if BSD < 199506
|
||||
static int eni_pci_shutdown(struct kern_devconf *, int);
|
||||
#else
|
||||
static void eni_pci_shutdown(void *, int);
|
||||
#endif
|
||||
static void eni_pci_reset(Eni_unit *);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Used by kernel to return number of claimed devices
|
||||
*/
|
||||
static u_long eni_nunits;
|
||||
|
||||
static struct pci_device eni_pci_device = {
|
||||
ENI_DEV_NAME,
|
||||
eni_pci_probe,
|
||||
eni_pci_attach,
|
||||
&eni_nunits,
|
||||
#if BSD < 199506
|
||||
eni_pci_shutdown
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
COMPAT_PCI_DRIVER (eni_pci, eni_pci_device);
|
||||
|
||||
/*
|
||||
* Called by kernel with PCI device_id which was read from the PCI
|
||||
* register set. If the identified vendor is Efficient, see if we
|
||||
* recognize the particular device. If so, return an identifying string,
|
||||
* if not, return null.
|
||||
*
|
||||
* Arguments:
|
||||
* config_id PCI config token
|
||||
* device_id contents of PCI device ID register
|
||||
*
|
||||
* Returns:
|
||||
* string Identifying string if we will handle this device
|
||||
* NULL unrecognized vendor/device
|
||||
*
|
||||
*/
|
||||
static const char *
|
||||
eni_pci_probe ( pcici_t config_id, pcidi_t device_id )
|
||||
{
|
||||
|
||||
if ( (device_id & 0xFFFF) == EFF_VENDOR_ID ) {
|
||||
switch ( (device_id >> 16) ) {
|
||||
case EFF_DEV_ID:
|
||||
return ( "Efficient ENI ATM Adapter" );
|
||||
/* NOTREACHED */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ( NULL );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The ENI-155p adapter uses an ATMEL AT24C01 serial EEPROM to store
|
||||
* configuration information. The SEEPROM is accessed via two wires,
|
||||
* CLOCK and DATA, which are accessible via the PCI configuration
|
||||
* registers. The following macros manipulate the lines to access the
|
||||
* SEEPROM. See http://www.atmel.com/atmel/products/prod162.htm for
|
||||
* a description of the AT24C01 part. Value to be read/written is
|
||||
* part of the per unit structure.
|
||||
*/
|
||||
/*
|
||||
* Write bits to SEEPROM
|
||||
*/
|
||||
#define WRITE_SEEPROM() ( \
|
||||
{ \
|
||||
(void) pci_write_config(eup->eu_pcitag, SEEPROM, \
|
||||
eup->eu_sevar, 4); \
|
||||
DELAY(SEPROM_DELAY); \
|
||||
} \
|
||||
)
|
||||
/*
|
||||
* Stobe first the DATA, then the CLK lines high
|
||||
*/
|
||||
#define STROBE_HIGH() ( \
|
||||
{ \
|
||||
eup->eu_sevar |= SEPROM_DATA; WRITE_SEEPROM(); \
|
||||
eup->eu_sevar |= SEPROM_CLK; WRITE_SEEPROM(); \
|
||||
} \
|
||||
)
|
||||
/*
|
||||
* Strobe first the CLK, then the DATA lines high
|
||||
*/
|
||||
#define INV_STROBE_HIGH() ( \
|
||||
{ \
|
||||
eup->eu_sevar |= SEPROM_CLK; WRITE_SEEPROM(); \
|
||||
eup->eu_sevar |= SEPROM_DATA; WRITE_SEEPROM(); \
|
||||
} \
|
||||
)
|
||||
/*
|
||||
* Strobe first the CLK, then the DATA lines low - companion to
|
||||
* STROBE_HIGH()
|
||||
*/
|
||||
#define STROBE_LOW() ( \
|
||||
{ \
|
||||
eup->eu_sevar &= ~SEPROM_CLK; WRITE_SEEPROM(); \
|
||||
eup->eu_sevar &= ~SEPROM_DATA; WRITE_SEEPROM(); \
|
||||
} \
|
||||
)
|
||||
/*
|
||||
* Strobe first the DATA, then the CLK lines low - companion to
|
||||
* INV_STROBE_HIGH()
|
||||
*/
|
||||
#define INV_STROBE_LOW() ( \
|
||||
{ \
|
||||
eup->eu_sevar &= ~SEPROM_DATA; WRITE_SEEPROM(); \
|
||||
eup->eu_sevar &= ~SEPROM_CLK; WRITE_SEEPROM(); \
|
||||
} \
|
||||
)
|
||||
/*
|
||||
* Strobe the CLK line high, then low
|
||||
*/
|
||||
#define STROBE_CLK() ( \
|
||||
{ \
|
||||
eup->eu_sevar |= SEPROM_CLK; WRITE_SEEPROM(); \
|
||||
eup->eu_sevar &= ~SEPROM_CLK; WRITE_SEEPROM(); \
|
||||
} \
|
||||
)
|
||||
|
||||
/*
|
||||
* Look for a positive ACK from the SEEPROM. Cycle begins by asserting
|
||||
* the DATA line, then the CLK line. The DATA line is then read to
|
||||
* retrieve the ACK status, and then the cycle is finished by deasserting
|
||||
* the CLK line, and asserting the DATA line.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to per unit structure
|
||||
*
|
||||
* Returns:
|
||||
* 0/1 value of ACK
|
||||
*
|
||||
*/
|
||||
static int
|
||||
eni_get_ack (eup)
|
||||
Eni_unit *eup;
|
||||
{
|
||||
int ack;
|
||||
|
||||
STROBE_HIGH();
|
||||
/*
|
||||
* Read DATA line from SEPROM
|
||||
*/
|
||||
eup->eu_sevar = pci_read_config(eup->eu_pcitag, SEEPROM, 4);
|
||||
DELAY ( SEPROM_DELAY );
|
||||
ack = eup->eu_sevar & SEPROM_DATA;
|
||||
|
||||
eup->eu_sevar &= ~SEPROM_CLK;
|
||||
WRITE_SEEPROM();
|
||||
eup->eu_sevar |= SEPROM_DATA;
|
||||
WRITE_SEEPROM();
|
||||
|
||||
return ( ack );
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a byte from the SEEPROM. Data is read as 8 bits. There are two types
|
||||
* of read operations. The first is a single byte read, the second is
|
||||
* multiple sequential bytes read. Both cycles begin with a 'START' operation,
|
||||
* followed by a memory address word. Following the memory address, the
|
||||
* SEEPROM will send a data byte, followed by an ACK. If the host responds
|
||||
* with a 'STOP' operation, then a single byte cycle is performed. If the
|
||||
* host responds with an 'ACK', then the memory address is incremented, and
|
||||
* the next sequential memory byte is serialized.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to per unit structure
|
||||
*
|
||||
* Returns:
|
||||
* val value of byte read from SEEPROM
|
||||
*
|
||||
*/
|
||||
static int
|
||||
eni_get_sebyte(eup)
|
||||
Eni_unit *eup;
|
||||
{
|
||||
int i;
|
||||
int data;
|
||||
int rval;
|
||||
|
||||
/* Initial value */
|
||||
rval = 0;
|
||||
/* Read 8 bits */
|
||||
for ( i = 0; i < 8; i++ ) {
|
||||
/* Shift bits to left so the next bit goes to position 0 */
|
||||
rval <<= 1;
|
||||
/* Indicate we're ready to read bit */
|
||||
STROBE_HIGH();
|
||||
/*
|
||||
* Read DATA line from SEPROM
|
||||
*/
|
||||
data = pci_read_config(eup->eu_pcitag, SEEPROM, 4);
|
||||
DELAY ( SEPROM_DELAY );
|
||||
/* (Possibly) mask bit into accumulating value */
|
||||
if ( data & SEPROM_DATA )
|
||||
rval |= 1; /* If DATA bit '1' */
|
||||
/* Indicate we're done reading this bit */
|
||||
STROBE_LOW();
|
||||
}
|
||||
|
||||
/* Return acquired byte */
|
||||
return ( rval );
|
||||
}
|
||||
|
||||
/*
|
||||
* The AT24C01 is a 1024 bit part organized as 128 words by 8 bits.
|
||||
* We will read the entire contents into the per unit structure. Later,
|
||||
* we'll retrieve the MAC address and serial number from the data read.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to per unit structure
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
eni_read_seeprom ( eup )
|
||||
Eni_unit *eup;
|
||||
{
|
||||
int addr;
|
||||
int i, j;
|
||||
|
||||
/*
|
||||
* Set initial state
|
||||
*/
|
||||
eup->eu_sevar = SEPROM_DATA | SEPROM_CLK;
|
||||
WRITE_SEEPROM ();
|
||||
|
||||
/* Loop for all bytes */
|
||||
for ( i = 0; i < SEPROM_SIZE ; i++ ) {
|
||||
/* Send START operation */
|
||||
STROBE_HIGH();
|
||||
INV_STROBE_LOW();
|
||||
|
||||
/*
|
||||
* Send address. Addresses are sent as 7 bits plus
|
||||
* last bit high.
|
||||
*/
|
||||
addr = ((i) << 1) + 1;
|
||||
/*
|
||||
* Start with high order bit first working toward low
|
||||
* order bit.
|
||||
*/
|
||||
for ( j = 7; j >= 0; j-- ) {
|
||||
/* Set current bit value */
|
||||
eup->eu_sevar = ( addr >> j ) & 1 ?
|
||||
eup->eu_sevar | SEPROM_DATA :
|
||||
eup->eu_sevar & ~SEPROM_DATA;
|
||||
WRITE_SEEPROM ();
|
||||
/* Indicate we've sent it */
|
||||
STROBE_CLK();
|
||||
}
|
||||
/*
|
||||
* We expect a zero ACK after sending the address
|
||||
*/
|
||||
if ( !eni_get_ack ( eup ) ) {
|
||||
/* Address okay - read data byte */
|
||||
eup->eu_seeprom[i] = eni_get_sebyte ( eup );
|
||||
/* Grab but ignore the ACK op */
|
||||
(void) eni_get_ack ( eup );
|
||||
} else {
|
||||
/* Address ACK was bad - can't retrieve data byte */
|
||||
eup->eu_seeprom[i] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* The kernel has found a device which we are willing to support.
|
||||
* We are now being called to do any necessary work to make the
|
||||
* device initially usable. In our case, this means allocating
|
||||
* structure memory, configuring registers, mapping device
|
||||
* memory, setting pointers, registering with the core services,
|
||||
* and doing the initial PDU processing configuration.
|
||||
*
|
||||
* Arguments:
|
||||
* config_id PCI device token
|
||||
* unit instance of the unit
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
static void
|
||||
eni_pci_attach ( pcici_t config_id, int unit )
|
||||
{
|
||||
vm_offset_t va;
|
||||
vm_offset_t pa;
|
||||
Eni_unit *eup;
|
||||
long val;
|
||||
|
||||
/*
|
||||
* Just checking...
|
||||
*/
|
||||
if ( unit >= ENI_MAX_UNITS ) {
|
||||
log ( LOG_ERR, "%s%d: too many devices\n",
|
||||
ENI_DEV_NAME, unit );
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure this isn't a duplicate unit
|
||||
*/
|
||||
if ( eni_units[unit] != NULL )
|
||||
return;
|
||||
|
||||
/*
|
||||
* Allocate a new unit structure
|
||||
*/
|
||||
eup = (Eni_unit *) atm_dev_alloc ( sizeof(Eni_unit), sizeof(int), 0 );
|
||||
if ( eup == NULL )
|
||||
return;
|
||||
|
||||
/*
|
||||
* Start initializing it
|
||||
*/
|
||||
eup->eu_unit = unit;
|
||||
eup->eu_mtu = ENI_IFF_MTU;
|
||||
eup->eu_pcitag = config_id;
|
||||
eup->eu_ioctl = eni_atm_ioctl;
|
||||
eup->eu_instvcc = eni_instvcc;
|
||||
eup->eu_openvcc = eni_openvcc;
|
||||
eup->eu_closevcc = eni_closevcc;
|
||||
eup->eu_output = eni_output;
|
||||
eup->eu_vcc_zone = eni_vcc_zone;
|
||||
eup->eu_nif_zone = eni_nif_zone;
|
||||
|
||||
/*
|
||||
* Enable Memory Mapping / Bus Mastering
|
||||
*/
|
||||
val = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
|
||||
val |= (PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
|
||||
pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, val);
|
||||
|
||||
/*
|
||||
* Map in adapter RAM
|
||||
*/
|
||||
val = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
|
||||
if ((val & PCIM_CMD_MEMEN) == 0) {
|
||||
log(LOG_ERR, "%s%d: memory mapping not enabled\n",
|
||||
ENI_DEV_NAME, unit);
|
||||
goto failed;
|
||||
}
|
||||
if ( ( pci_map_mem ( config_id, PCI_MAP_REG_START, &va, &pa ) ) == 0 )
|
||||
{
|
||||
log(LOG_ERR, "%s%d: unable to map memory\n",
|
||||
ENI_DEV_NAME, unit);
|
||||
goto failed;
|
||||
}
|
||||
/*
|
||||
* Map okay - retain address assigned
|
||||
*/
|
||||
eup->eu_base = (Eni_mem)va;
|
||||
eup->eu_ram = (Eni_mem)(eup->eu_base + RAM_OFFSET);
|
||||
|
||||
/*
|
||||
* Map memory structures into adapter space
|
||||
*/
|
||||
eup->eu_suni = (Eni_mem)(eup->eu_base + SUNI_OFFSET);
|
||||
eup->eu_midway = (Eni_mem)(eup->eu_base + MIDWAY_OFFSET);
|
||||
eup->eu_vcitbl = (VCI_Table *)(eup->eu_base + VCITBL_OFFSET);
|
||||
eup->eu_rxdma = (Eni_mem)(eup->eu_base + RXQUEUE_OFFSET);
|
||||
eup->eu_txdma = (Eni_mem)(eup->eu_base + TXQUEUE_OFFSET);
|
||||
eup->eu_svclist = (Eni_mem)(eup->eu_base + SVCLIST_OFFSET);
|
||||
eup->eu_servread = 0;
|
||||
|
||||
/*
|
||||
* Reset the midway chip
|
||||
*/
|
||||
eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET;
|
||||
|
||||
/*
|
||||
* Size and test adapter memory. Initialize our adapter memory
|
||||
* allocater.
|
||||
*/
|
||||
if ( eni_init_memory ( eup ) < 0 ) {
|
||||
/*
|
||||
* Adapter memory test failed. Clean up and
|
||||
* return.
|
||||
*/
|
||||
log(LOG_ERR, "%s%d: memory test failed\n",
|
||||
ENI_DEV_NAME, unit);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the contents of the SEEPROM
|
||||
*/
|
||||
eni_read_seeprom ( eup );
|
||||
/*
|
||||
* Copy MAC address to PIF and config structures
|
||||
*/
|
||||
bcopy ( (caddr_t)&eup->eu_seeprom[SEPROM_MAC_OFF],
|
||||
(caddr_t)&eup->eu_pif.pif_macaddr, sizeof(struct mac_addr) );
|
||||
eup->eu_config.ac_macaddr = eup->eu_pif.pif_macaddr;
|
||||
|
||||
/*
|
||||
* Copy serial number into config space
|
||||
*/
|
||||
eup->eu_config.ac_serial =
|
||||
ntohl(*(u_long *)&eup->eu_seeprom[SEPROM_SN_OFF]);
|
||||
|
||||
/*
|
||||
* Convert Endianess on DMA
|
||||
*/
|
||||
val = pci_conf_read ( config_id, PCI_CONTROL_REG );
|
||||
val |= ENDIAN_SWAP_DMA;
|
||||
pci_conf_write ( config_id, PCI_CONTROL_REG, val );
|
||||
|
||||
/*
|
||||
* Map interrupt in
|
||||
*/
|
||||
if ( !pci_map_int ( config_id, eni_intr, (void *)eup, &net_imask ) )
|
||||
{
|
||||
log(LOG_ERR, "%s%d: unable to map interrupt\n",
|
||||
ENI_DEV_NAME, unit);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup some of the adapter configuration
|
||||
*/
|
||||
/*
|
||||
* Get MIDWAY ID
|
||||
*/
|
||||
val = eup->eu_midway[MIDWAY_ID];
|
||||
eup->eu_config.ac_vendor = VENDOR_ENI;
|
||||
eup->eu_config.ac_vendapi = VENDAPI_ENI_1;
|
||||
eup->eu_config.ac_device = DEV_ENI_155P;
|
||||
eup->eu_config.ac_media = val & MEDIA_MASK ? MEDIA_UTP155 : MEDIA_OC3C;
|
||||
eup->eu_pif.pif_pcr = ATM_PCR_OC3C;
|
||||
eup->eu_config.ac_bustype = BUS_PCI;
|
||||
eup->eu_config.ac_busslot = config_id->bus << 8 | config_id->slot;
|
||||
|
||||
/*
|
||||
* Make a hw version number from the ID register values.
|
||||
* Format: {Midway ID}.{Mother board ID}.{Daughter board ID}
|
||||
*/
|
||||
snprintf ( eup->eu_config.ac_hard_vers,
|
||||
sizeof ( eup->eu_config.ac_hard_vers ),
|
||||
"%ld/%ld/%ld",
|
||||
(val >> ID_SHIFT) & ID_MASK,
|
||||
(val >> MID_SHIFT) & MID_MASK,
|
||||
(val >> DID_SHIFT) & DID_MASK );
|
||||
|
||||
/*
|
||||
* There is no software version number
|
||||
*/
|
||||
eup->eu_config.ac_firm_vers[0] = '\0';
|
||||
|
||||
/*
|
||||
* Save device ram info for user-level programs
|
||||
* NOTE: This really points to start of EEPROM
|
||||
* and includes all the device registers in the
|
||||
* lower 2 Megabytes.
|
||||
*/
|
||||
eup->eu_config.ac_ram = (long)eup->eu_base;
|
||||
eup->eu_config.ac_ramsize = eup->eu_ramsize + ENI_REG_SIZE;
|
||||
|
||||
/*
|
||||
* Setup max VPI/VCI values
|
||||
*/
|
||||
eup->eu_pif.pif_maxvpi = ENI_MAX_VPI;
|
||||
eup->eu_pif.pif_maxvci = ENI_MAX_VCI;
|
||||
|
||||
/*
|
||||
* Register this interface with ATM core services
|
||||
*/
|
||||
if ( atm_physif_register
|
||||
( (Cmn_unit *)eup, ENI_DEV_NAME, eni_services ) != 0 )
|
||||
{
|
||||
/*
|
||||
* Registration failed - back everything out
|
||||
*/
|
||||
log(LOG_ERR, "%s%d: atm_physif_register failed\n",
|
||||
ENI_DEV_NAME, unit);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
eni_units[unit] = eup;
|
||||
|
||||
#if BSD >= 199506
|
||||
/*
|
||||
* Add hook to out shutdown function
|
||||
*/
|
||||
EVENTHANDLER_REGISTER(shutdown_post_sync, eni_pci_shutdown, eup,
|
||||
SHUTDOWN_PRI_DEFAULT);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize driver processing
|
||||
*/
|
||||
if ( eni_init ( eup ) ) {
|
||||
log(LOG_ERR, "%s%d: adapter init failed\n",
|
||||
ENI_DEV_NAME, unit);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
failed:
|
||||
/*
|
||||
* Attach failed - clean up
|
||||
*/
|
||||
eni_pci_reset(eup);
|
||||
(void) pci_unmap_int(config_id);
|
||||
atm_dev_free(eup);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device reset routine
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to per unit structure
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
static void
|
||||
eni_pci_reset ( eup )
|
||||
Eni_unit *eup;
|
||||
{
|
||||
|
||||
/*
|
||||
* We should really close down any open VCI's and
|
||||
* release all memory (TX and RX) buffers. For now,
|
||||
* we assume we're shutting the card down for good.
|
||||
*/
|
||||
|
||||
if (eup->eu_midway) {
|
||||
/*
|
||||
* Issue RESET command to Midway chip
|
||||
*/
|
||||
eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET;
|
||||
|
||||
/*
|
||||
* Delay to allow everything to terminate
|
||||
*/
|
||||
DELAY ( MIDWAY_DELAY );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if BSD < 199506
|
||||
/*
|
||||
* Device shutdown routine
|
||||
*
|
||||
* Arguments:
|
||||
* kdc pointer to device's configuration table
|
||||
* force forced shutdown flag
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
static int
|
||||
eni_pci_shutdown ( kdc, force )
|
||||
struct kern_devconf *kdc;
|
||||
int force;
|
||||
{
|
||||
Eni_unit *eup = NULL;
|
||||
|
||||
if ( kdc->kdc_unit < eni_nunits ) {
|
||||
|
||||
eup = eni_units[kdc->kdc_unit];
|
||||
if ( eup != NULL ) {
|
||||
/* Do device reset */
|
||||
eni_pci_reset ( eup );
|
||||
}
|
||||
}
|
||||
|
||||
(void) dev_detach ( kdc );
|
||||
return ( 0 );
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Device shutdown routine
|
||||
*
|
||||
* Arguments:
|
||||
* howto type of shutdown
|
||||
* eup pointer to device unit structure
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
static void
|
||||
eni_pci_shutdown ( eup, howto )
|
||||
void *eup;
|
||||
int howto;
|
||||
{
|
||||
|
||||
/* Do device reset */
|
||||
eni_pci_reset ( eup );
|
||||
|
||||
}
|
||||
#endif /* BSD < 199506 */
|
||||
#endif
|
@ -1,504 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
* @(#) $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
*
|
||||
* Protocol and implementation definitions
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ENI_ENI_H
|
||||
#define _ENI_ENI_H
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
/*
|
||||
* Physical device name - used to configure HARP devices
|
||||
*/
|
||||
#ifndef ENI_DEV_NAME
|
||||
#define ENI_DEV_NAME "hea" /* HARP Efficient ATM */
|
||||
#endif
|
||||
|
||||
#define ENI_MAX_UNITS 4
|
||||
|
||||
#define ENI_IFF_MTU 9188
|
||||
#define ENI_MAX_VCI 1023 /* 0 - 1023 */
|
||||
#define ENI_MAX_VPI 0
|
||||
|
||||
#define ENI_IFQ_MAXLEN 1000 /* rx/tx queue lengths */
|
||||
|
||||
#ifdef BSD
|
||||
/*
|
||||
* Size of small and large receive buffers
|
||||
*/
|
||||
#define ENI_SMALL_BSIZE 64
|
||||
#define ENI_LARGE_BSIZE MCLBYTES
|
||||
#endif /* BSD */
|
||||
|
||||
/*
|
||||
* ENI memory map offsets IN WORDS, not bytes
|
||||
*
|
||||
* The Efficient Adapter implements a 4 MB address space. The lower
|
||||
* 2 MB are used by bootprom (E)EPROM and by chipset registers such
|
||||
* as the MIDWAY and SUNI chips. The (upto) upper 2 MB is used for
|
||||
* RAM. Of the RAM, the lower 28 KB is used for fixed tables - the
|
||||
* VCI table, the RX and TX DMA queues, and the Service List queue.
|
||||
* Memory above the 28 KB range is available for RX and TX buffers.
|
||||
*
|
||||
* NOTE: Access to anything other then the (E)EPROM MUST be as a 32 bit
|
||||
* access. Also note that Efficient uses both byte addresses and word
|
||||
* addresses when describing offsets. BE CAREFUL or you'll get confused!
|
||||
*/
|
||||
/*
|
||||
* Size of memory space reserved for registers and expansion (e)eprom.
|
||||
*/
|
||||
#define ENI_REG_SIZE 0x200000 /* Two megabytes */
|
||||
|
||||
#define SUNI_OFFSET 0x008000 /* SUNI chip registers */
|
||||
#define MIDWAY_OFFSET 0x010000 /* MIDWAY chip registers */
|
||||
#define RAM_OFFSET 0x080000 /* Adapter RAM */
|
||||
#define VCITBL_OFFSET 0x080000 /* VCI Table offset */
|
||||
#define RXQUEUE_OFFSET 0x081000 /* RX DMA Queue offset */
|
||||
#define TXQUEUE_OFFSET 0x081400 /* TX DMA Queue offset */
|
||||
#define SVCLIST_OFFSET 0x081800 /* SVC List Queue offset */
|
||||
|
||||
#define SEGBUF_BASE 0x007000 /* Base from start of RAM */
|
||||
|
||||
#define DMA_LIST_SIZE 512 /* 1024 words / 2 words per entry */
|
||||
#define SVC_LIST_SIZE 1024 /* 1024 words / 1 word per entry */
|
||||
|
||||
/*
|
||||
* Values for testing size of RAM on adapter
|
||||
*
|
||||
* Efficient has (at least) two different memory sizes available. One
|
||||
* is a client card which has either 128 KB or 512 KB RAM, the other
|
||||
* is a server card which has 2 MB RAM. The driver will size and test
|
||||
* the memory to correctly determine what's available.
|
||||
*/
|
||||
#define MAX_ENI_MEM 0x200000 /* 2 MB - max. mem supported */
|
||||
#define TEST_STEP 0x000400 /* Look at 1 KB steps */
|
||||
#define TEST_PAT 0xA5A5A5A5 /* Test pattern */
|
||||
|
||||
/*
|
||||
* Values for memory allocator
|
||||
*/
|
||||
#define ENI_BUF_PGSZ 1024 /* Allocation unit of buffers */
|
||||
#define ENI_BUF_NBIT 8 /* Number of bits to get from */
|
||||
/* min buffer (1KB) to max (128KB) */
|
||||
|
||||
/*
|
||||
* Values for allocating TX buffers
|
||||
*/
|
||||
#define MAX_CLIENT_RAM 512 /* Most RAM a client card will have */
|
||||
#define TX_SMALL_BSIZE 32 /* Small buffer - 32KB */
|
||||
#define TX_LARGE_BSIZE 128 /* Large buffer - 128KB */
|
||||
|
||||
/*
|
||||
* Values for allocating RX buffers
|
||||
*/
|
||||
#define RX_SIG_BSIZE 4 /* Signalling buffer - 4KB */
|
||||
#define RX_CLIENT_BSIZE 16 /* Client buffer - 16KB */
|
||||
#define RX_SERVER_BSIZE 32 /* Server buffer - 32KB */
|
||||
|
||||
/*
|
||||
* Adapter bases all addresses off of some power from 1KB. Thus, it
|
||||
* only needs to store the most sigificant bits and can drop the lower
|
||||
* 10 bits.
|
||||
*/
|
||||
#define ENI_LOC_PREDIV 10 /* Bits location is shifted */
|
||||
/* Location is prescaled by 1KB */
|
||||
/* before use in various places */
|
||||
|
||||
#define MIDWAY_DELAY 10 /* Time to wait for Midway finish */
|
||||
|
||||
/*
|
||||
* Define the MIDWAY register offsets and any interesting bits within
|
||||
* the register
|
||||
*/
|
||||
#define MIDWAY_ID 0x00 /* ID/Reset register */
|
||||
#define MIDWAY_RESET 0 /* iWrite of any value */
|
||||
#define ID_SHIFT 27 /* Midway ID version */
|
||||
#define ID_MASK 0x1F /* ID mask */
|
||||
#define MID_SHIFT 7 /* Mother board ID */
|
||||
#define MID_MASK 0x7 /* MID mask */
|
||||
#define DID_SHIFT 0 /* Daughter board ID */
|
||||
#define DID_MASK 0x1F /* DID mask */
|
||||
/*
|
||||
* Efficient defines the following IDs for their adapters:
|
||||
* 0x420/0x620 - SONET MMF, client memory size
|
||||
* 0x430/0x630 - SONET MMF, server memory size
|
||||
* 0x424/0x624 - UTP-5, client memory size
|
||||
* 0x434/0x634 - UTP-5, server memory size
|
||||
*/
|
||||
#define MEDIA_MASK 0x04 /* Mask off UTP-5/MMF media */
|
||||
|
||||
#define MIDWAY_ISA 0x01 /* Interrupt Status Ack. */
|
||||
/* Reading this register */
|
||||
/* also acknowledges the */
|
||||
/* posted interrupt(s) */
|
||||
|
||||
#define MIDWAY_IS 0x02 /* Interrupt Status */
|
||||
/* Reading this register */
|
||||
/* does NOT acknowledge the */
|
||||
/* posted interrupt(s) */
|
||||
/* Interrupt names */
|
||||
#define ENI_INT_STAT 0x00000001
|
||||
#define ENI_INT_SUNI 0x00000002
|
||||
#define ENI_INT_SERVICE 0x00000004
|
||||
#define ENI_INT_TX_DMA 0x00000008
|
||||
#define ENI_INT_RX_DMA 0x00000010
|
||||
#define ENI_INT_DMA_ERR 0x00000020
|
||||
#define ENI_INT_DMA_LERR 0x00000040
|
||||
#define ENI_INT_IDEN 0x00000080
|
||||
#define ENI_INT_DMA_OVFL 0x00000100
|
||||
#define ENI_INT_TX_MASK 0x0001FE00
|
||||
|
||||
#define MIDWAY_IE 0x03 /* Interrupt Enable register */
|
||||
/* Interrupt enable bits are the same as the Interrupt names */
|
||||
|
||||
#define MIDWAY_MASTER 0x04 /* Master Control */
|
||||
/* Master control bits */
|
||||
#define ENI_M_WAIT500 0x00000001 /* Disable interrupts .5 ms */
|
||||
#define ENI_M_WAIT1 0x00000002 /* Disable interrupts 1 ms */
|
||||
#define ENI_M_RXENABLE 0x00000004 /* Enable RX engine */
|
||||
#define ENI_M_TXENABLE 0x00000008 /* Enable TX engine */
|
||||
#define ENI_M_DMAENABLE 0x00000010 /* Enable DMA */
|
||||
#define ENI_M_TXLOCK 0x00000020 /* 0: Streaming, 1: Lock */
|
||||
#define ENI_M_INTSEL 0x000001C0 /* Int Select mask */
|
||||
#define ENI_ISEL_SHIFT 6 /* Bits to shift ISEL value */
|
||||
|
||||
#define MIDWAY_STAT 0x05 /* Statistics register */
|
||||
|
||||
#define MIDWAY_SVCWR 0x06 /* Svc List write pointer */
|
||||
#define SVC_SIZE_MASK 0x3FF /* Valid bits in svc pointer */
|
||||
|
||||
#define MIDWAY_DMAADDR 0x07 /* Current virtual DMA addr */
|
||||
|
||||
#define MIDWAY_RX_WR 0x08 /* Write ptr to RX DMA queue */
|
||||
|
||||
#define MIDWAY_RX_RD 0x09 /* Read ptr to RX DMA queue */
|
||||
|
||||
#define MIDWAY_TX_WR 0x0A /* Write ptr to TX DMA queue */
|
||||
|
||||
#define MIDWAY_TX_RD 0x0B /* Read ptr to TX DMA queue */
|
||||
|
||||
/*
|
||||
* Registers 0x0C - 0x0F are unused
|
||||
*/
|
||||
|
||||
/*
|
||||
* MIDWAY supports 8 transmit channels. Each channel has 3 registers
|
||||
* to control operation. Each new channel starts on N * 4 set. Thus,
|
||||
* channel 0 uses register 0x10 - 0x13, channel 1 uses 0x14 - 0x17, etc.
|
||||
* Register 0x13 + N * 4 is unused.
|
||||
*/
|
||||
|
||||
#define MIDWAY_TXPLACE 0x10 /* Channel N TX location */
|
||||
#define TXSIZE_SHIFT 11 /* Bits to shift size by */
|
||||
#define TX_PLACE_MASK 0x7FF /* Valid bits in TXPLACE */
|
||||
|
||||
#define MIDWAY_RDPTR 0x11 /* Channel N Read ptr */
|
||||
|
||||
#define MIDWAY_DESCR 0x12 /* Channel N Descr ptr */
|
||||
|
||||
/*
|
||||
* Register 0x30 on up are unused
|
||||
*/
|
||||
|
||||
/*
|
||||
* Part of PCI configuration registers but not defined in <dev/pci/pcireg.h>
|
||||
*/
|
||||
#define PCI_CONTROL_REG 0x60
|
||||
#define ENDIAN_SWAP_DMA 0x80 /* Enable endian swaps on DMA */
|
||||
|
||||
/*
|
||||
* The Efficient adapter references adapter RAM through the use of
|
||||
* location and size values. Eight sizes are defined. When allocating
|
||||
* buffers, there size must be rounded up to the next size which will
|
||||
* hold the requested size. Buffers are allocated on 'SIZE' boundaries.
|
||||
* See eni_buffer.c for more info.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Buffer SIZE definitions - in words, so from 1 KB to 128 KB
|
||||
*/
|
||||
#define SIZE_256 0x00
|
||||
#define SIZE_512 0x01
|
||||
#define SIZE_1K 0x02
|
||||
#define SIZE_2K 0x03
|
||||
#define SIZE_4K 0x04
|
||||
#define SIZE_8K 0x05
|
||||
#define SIZE_16K 0x06
|
||||
#define SIZE_32K 0x07
|
||||
|
||||
/*
|
||||
* Define values for DMA type - DMA descriptors include a type field and a
|
||||
* count field except in the special case of JK (just-kidding). With type JK,
|
||||
* the count field should be set to the address which will be loaded
|
||||
* into the pointer, ie. where the pointer should next point to, since
|
||||
* JK doesn't have a "size" associated with it. JK DMA is used to skip
|
||||
* over descriptor words, and to strip off padding of AAL5 PDUs. The
|
||||
* DMA_nWORDM types will do a n word DMA burst, but the count field
|
||||
* does not have to equal n. Any difference results in garbage filling
|
||||
* the remaining words of the DMA. These types could be used where a
|
||||
* particular burst size yields better DMA performance.
|
||||
*/
|
||||
#define DMA_WORD 0x00
|
||||
#define DMA_BYTE 0x01
|
||||
#define DMA_HWORD 0x02
|
||||
#define DMA_JK 0x03
|
||||
#define DMA_4WORD 0x04
|
||||
#define DMA_8WORD 0x05
|
||||
#define DMA_16WORD 0x06
|
||||
#define DMA_2WORD 0x07
|
||||
#define DMA_4WORDM 0x0C
|
||||
#define DMA_8WORDM 0x0D
|
||||
#define DMA_16WORDM 0x0E
|
||||
#define DMA_2WORDM 0x0F
|
||||
|
||||
/*
|
||||
* Define the size of the local DMA list we'll build before
|
||||
* giving up on the PDU.
|
||||
*/
|
||||
#define TEMP_DMA_SIZE 120 /* Enough for 58/59 buffers */
|
||||
|
||||
#define DMA_COUNT_SHIFT 16 /* Number of bits to shift count */
|
||||
/* in DMA descriptor word */
|
||||
#define DMA_VCC_SHIFT 6 /* Number of bits to shift RX VCC or */
|
||||
/* TX channel in DMA descriptor word */
|
||||
#define DMA_END_BIT 0x20 /* Signal end of DMA list */
|
||||
|
||||
/*
|
||||
* Defines for VCI table
|
||||
*
|
||||
* The VCI table is a 1K by 4 word table allowing up to 1024 (0-1023)
|
||||
* VCIs. Entries into the table use the VCI number as the index.
|
||||
*/
|
||||
struct vci_table {
|
||||
u_long vci_control; /* Control word */
|
||||
u_long vci_descr; /* Descr/ReadPtr */
|
||||
u_long vci_write; /* WritePtr/State/Cell count */
|
||||
u_long vci_crc; /* ongoing CRC calculation */
|
||||
};
|
||||
typedef volatile struct vci_table VCI_Table;
|
||||
|
||||
#define VCI_MODE_SHIFT 30 /* Shift to get MODE field */
|
||||
#define VCI_MODE_MASK 0x3FFFFFFF /* Bits to strip MODE off */
|
||||
#define VCI_PTI_SHIFT 29 /* Shift to get PTI mode field */
|
||||
#define VCI_LOC_SHIFT 18 /* Shift to get location field */
|
||||
#define VCI_LOC_MASK 0x7FF /* Valid bits in location field */
|
||||
#define VCI_SIZE_SHIFT 15 /* Shift to get size field */
|
||||
#define VCI_SIZE_MASK 7 /* Valid bits in size field */
|
||||
#define VCI_IN_SERVICE 1 /* Mask for IN_SERVICE field */
|
||||
|
||||
/*
|
||||
* Defines for VC mode
|
||||
*/
|
||||
#define VCI_MODE_TRASH 0x00 /* Trash all cells for this VC */
|
||||
#define VCI_MODE_AAL0 0x01 /* Reassemble as AAL_0 PDU */
|
||||
#define VCI_MODE_AAL5 0x02 /* Reassemble as AAL_5 PDU */
|
||||
/*
|
||||
* Defines for handling cells with PTI(2) set to 1.
|
||||
*/
|
||||
#define PTI_MODE_TRASH 0x00 /* Trash cell */
|
||||
#define PTI_MODE_PRESV 0x01 /* Send cell to OAM channel */
|
||||
/*
|
||||
* Current state of VC
|
||||
*/
|
||||
#define VCI_STATE_IDLE 0x00 /* VC is idle */
|
||||
#define VCI_STATE_REASM 0x01 /* VC is reassembling PDU */
|
||||
#define VCI_STATE_TRASH 0x03 /* VC is trashing cells */
|
||||
|
||||
/*
|
||||
* RX Descriptor word values
|
||||
*/
|
||||
#define DESCR_TRASH_BIT 0x1000 /* VCI was trashing cells */
|
||||
#define DESCR_CRC_ERR 0x0800 /* PDU has CRC error */
|
||||
#define DESCR_CELL_COUNT 0x07FF /* Mask to get cell count */
|
||||
/*
|
||||
* TX Descriptor word values
|
||||
*/
|
||||
#define TX_IDEN_SHIFT 28 /* Unique identifier location */
|
||||
#define TX_MODE_SHIFT 27 /* AAL5 or AAL0 */
|
||||
#define TX_VCI_SHIFT 4 /* Bits to shift VCI value */
|
||||
|
||||
/*
|
||||
* When setting up descriptor words (at head of segmentation queues), there
|
||||
* is a unique identifier used to help detect sync problems.
|
||||
*/
|
||||
#define MIDWAY_UNQ_ID 0x0B
|
||||
|
||||
/*
|
||||
* Defines for cell sizes
|
||||
*/
|
||||
#define BYTES_PER_CELL 48 /* Number of data bytes per cell */
|
||||
#define WORDS_PER_CELL 12 /* Number of data words per cell */
|
||||
|
||||
/*
|
||||
* Access to Serial EEPROM [as opposed to expansion (E)PROM].
|
||||
*
|
||||
* This is an ATMEL AT24C01 serial EEPROM part.
|
||||
* See http://www.atmel.com/atmel/products/prod162.htm for timimg diagrams
|
||||
* for START/STOP/ACK/READ cycles.
|
||||
*/
|
||||
#define SEEPROM PCI_CONTROL_REG /* Serial EEPROM is accessed thru */
|
||||
/* PCI control register */
|
||||
#define SEPROM_DATA 0x02 /* SEEPROM DATA line */
|
||||
#define SEPROM_CLK 0x01 /* SEEPROM CLK line */
|
||||
#define SEPROM_SIZE 128 /* Size of Serial EEPROM */
|
||||
#define SEPROM_MAC_OFF 64 /* Offset to MAC address */
|
||||
#define SEPROM_SN_OFF 112 /* Offset to serial number */
|
||||
#define SEPROM_DELAY 10 /* Delay when strobing CLK/DATA lines */
|
||||
|
||||
/*
|
||||
* Host protocol control blocks
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Device VCC Entry
|
||||
*
|
||||
* Contains the common and ENI-specific information for each VCC
|
||||
* which is opened through an ENI device.
|
||||
*/
|
||||
struct eni_vcc {
|
||||
struct cmn_vcc ev_cmn; /* Common VCC stuff */
|
||||
caddr_t ev_rxbuf; /* Receive buffer */
|
||||
u_long ev_rxpos; /* Adapter buffer read pointer */
|
||||
};
|
||||
typedef struct eni_vcc Eni_vcc;
|
||||
|
||||
#define ev_next ev_cmn.cv_next
|
||||
#define ev_toku ev_cmn.cv_toku
|
||||
#define ev_upper ev_cmn.cv_upper
|
||||
#define ev_connvc ev_cmn.cv_connvc
|
||||
#define ev_state ev_cmn.cv_state
|
||||
|
||||
typedef volatile unsigned long * Eni_mem;
|
||||
|
||||
/*
|
||||
* Define the ID's we'll look for in the PCI config
|
||||
* register when deciding if we'll support this device.
|
||||
* The DEV_ID will need to be turned into an array of
|
||||
* ID's in order to support multiple adapters with
|
||||
* the same driver.
|
||||
*/
|
||||
#define EFF_VENDOR_ID 0x111A
|
||||
#define EFF_DEV_ID 0x0002
|
||||
|
||||
/*
|
||||
* Memory allocator defines and buffer descriptors
|
||||
*/
|
||||
#define MEM_FREE 0
|
||||
#define MEM_INUSE 1
|
||||
|
||||
typedef struct mbd Mbd;
|
||||
struct mbd {
|
||||
Mbd *prev;
|
||||
Mbd *next;
|
||||
caddr_t base; /* Adapter base address */
|
||||
int size; /* Size of buffer */
|
||||
int state; /* INUSE or FREE */
|
||||
};
|
||||
|
||||
/*
|
||||
* We use a hack to allocate a smaller RX buffer for signalling
|
||||
* channels as they tend to have small MTU lengths.
|
||||
*/
|
||||
#define UNI_SIG_VCI 5
|
||||
|
||||
/*
|
||||
* Device Unit Structure
|
||||
*
|
||||
* Contains all the information for a single device (adapter).
|
||||
*/
|
||||
struct eni_unit {
|
||||
Cmn_unit eu_cmn; /* Common unit stuff */
|
||||
void * eu_pcitag; /* PCI tag */
|
||||
Eni_mem eu_base; /* Adapter memory base */
|
||||
Eni_mem eu_ram; /* Adapter RAM */
|
||||
u_long eu_ramsize;
|
||||
|
||||
Eni_mem eu_suni; /* SUNI registers */
|
||||
|
||||
Eni_mem eu_midway; /* MIDWAY registers */
|
||||
|
||||
VCI_Table *eu_vcitbl; /* VCI Table */
|
||||
Eni_mem eu_rxdma; /* Receive DMA queue */
|
||||
Eni_mem eu_txdma; /* Transmit DMA queue */
|
||||
Eni_mem eu_svclist; /* Service list */
|
||||
u_long eu_servread; /* Read pointer into Service list */
|
||||
|
||||
caddr_t eu_txbuf; /* One large TX buff for everything */
|
||||
u_long eu_txsize; /* Size of TX buffer */
|
||||
u_long eu_txpos; /* Current word being stored in RAM */
|
||||
u_long eu_txfirst; /* First word of unack'ed data */
|
||||
|
||||
u_long eu_trash;
|
||||
u_long eu_ovfl;
|
||||
|
||||
struct ifqueue eu_txqueue;
|
||||
u_long eu_txdmawr;
|
||||
struct ifqueue eu_rxqueue;
|
||||
u_long eu_rxdmawr; /* DMA list write pointer */
|
||||
|
||||
u_char eu_seeprom[SEPROM_SIZE]; /* Serial EEPROM contents */
|
||||
u_int eu_sevar; /* Unique (per unit) seeprom var. */
|
||||
|
||||
Mbd *eu_memmap; /* Adapter RAM memory allocator map */
|
||||
int eu_memclicks[ENI_BUF_NBIT];/* Count of INUSE buffers */
|
||||
|
||||
Eni_stats eu_stats; /* Statistics */
|
||||
|
||||
int eu_type;
|
||||
#define TYPE_UNKNOWN 0
|
||||
#define TYPE_ENI 1
|
||||
#define TYPE_ADP 2
|
||||
};
|
||||
typedef struct eni_unit Eni_unit;
|
||||
|
||||
#define eu_pif eu_cmn.cu_pif
|
||||
#define eu_unit eu_cmn.cu_unit
|
||||
#define eu_flags eu_cmn.cu_flags
|
||||
#define eu_mtu eu_cmn.cu_mtu
|
||||
#define eu_open_vcc eu_cmn.cu_open_vcc
|
||||
#define eu_vcc eu_cmn.cu_vcc
|
||||
#define eu_vcc_zone eu_cmn.cu_vcc_zone
|
||||
#define eu_nif_zone eu_cmn.cu_nif_zone
|
||||
#define eu_ioctl eu_cmn.cu_ioctl
|
||||
#define eu_instvcc eu_cmn.cu_instvcc
|
||||
#define eu_openvcc eu_cmn.cu_openvcc
|
||||
#define eu_closevcc eu_cmn.cu_closevcc
|
||||
#define eu_output eu_cmn.cu_output
|
||||
#define eu_config eu_cmn.cu_config
|
||||
#define eu_softc eu_cmn.cu_softc
|
||||
|
||||
#endif /* _ENI_ENI_H */
|
@ -1,475 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
* -----------------------------
|
||||
*
|
||||
* Handle adapter memory buffers for ENI adapters
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include <netatm/port.h>
|
||||
#include <netatm/queue.h>
|
||||
#include <netatm/atm.h>
|
||||
#include <netatm/atm_sys.h>
|
||||
#include <netatm/atm_cm.h>
|
||||
#include <netatm/atm_if.h>
|
||||
|
||||
#include <dev/hea/eni_stats.h>
|
||||
#include <dev/hea/eni.h>
|
||||
#include <dev/hea/eni_var.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("@(#) $FreeBSD$");
|
||||
#endif
|
||||
|
||||
static int eni_test_memory(Eni_unit *);
|
||||
|
||||
/*
|
||||
* The host is going to manage (that is, allocate and free) buffers
|
||||
* in the adapters RAM space. We are going to implement this as a
|
||||
* linked list describing FREE and INUSE memory segments. Initially,
|
||||
* the list contains one element with all memory marked free. As requests
|
||||
* are made, we search the list until we find the first free element
|
||||
* which can satisfy the request. If necessary, we will break the free
|
||||
* element into an INUSE element, and a new FREE element. When freeing
|
||||
* memory, we look at adjacent elements and if one or more are free,
|
||||
* we will combine into a single larger FREE element.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is for testing purposes. Since there are two versions of
|
||||
* the Efficient adapter with different memory sizes, this allows
|
||||
* us to fool an adapter with more memory into thinking it has less.
|
||||
*/
|
||||
static int eni_mem_max = MAX_ENI_MEM; /* Default to all available memory */
|
||||
|
||||
/*
|
||||
* Size and test adapter RAM
|
||||
*
|
||||
* Walk through adapter RAM writing known patterns and reading back
|
||||
* for comparison. We write more than one pattern on the off chance
|
||||
* that we "get lucky" and read what we expected.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to device unit structure
|
||||
*
|
||||
* Returns
|
||||
* size memory size in bytes
|
||||
*/
|
||||
static int
|
||||
eni_test_memory ( eup )
|
||||
Eni_unit *eup;
|
||||
{
|
||||
int ram_size = 0;
|
||||
int i;
|
||||
Eni_mem mp;
|
||||
|
||||
/*
|
||||
* Walk through to maximum looking for RAM
|
||||
*/
|
||||
for ( i = 0; i < MAX_ENI_MEM; i += TEST_STEP ) {
|
||||
mp = (Eni_mem)((intptr_t)eup->eu_ram + i);
|
||||
/* write pattern */
|
||||
*mp = (u_long)TEST_PAT;
|
||||
/* read pattern, match? */
|
||||
if ( *mp == (u_long)TEST_PAT ) {
|
||||
/* yes - write inverse pattern */
|
||||
*mp = (u_long)~TEST_PAT;
|
||||
/* read pattern, match? */
|
||||
if ( *mp == (u_long)~TEST_PAT ) {
|
||||
/* yes - assume another 1K available */
|
||||
ram_size = i + TEST_STEP;
|
||||
} else
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Clear all RAM to initial value of zero.
|
||||
* This makes sure we don't leave anything funny in the
|
||||
* queues.
|
||||
*/
|
||||
bzero ( (void *)(uintptr_t)eup->eu_ram, ram_size );
|
||||
|
||||
/*
|
||||
* If we'd like to claim to have less memory, here's where
|
||||
* we do so. We take the minimum of what we'd like and what
|
||||
* we really found on the adapter.
|
||||
*/
|
||||
ram_size = MIN ( ram_size, eni_mem_max );
|
||||
|
||||
return ( ram_size );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize our memory allocator.
|
||||
*
|
||||
* Arguments:
|
||||
* eup Pointer to per unit structure
|
||||
*
|
||||
* Returns:
|
||||
* size Physical RAM size
|
||||
* -1 failed to initialize memory
|
||||
*
|
||||
*/
|
||||
int
|
||||
eni_init_memory ( eup )
|
||||
Eni_unit *eup;
|
||||
{
|
||||
|
||||
/*
|
||||
* Have we (somehow) been called before?
|
||||
*/
|
||||
if ( eup->eu_memmap != NULL )
|
||||
{
|
||||
/* Oops - it's already been initialized */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate initial element which will hold all of memory
|
||||
*/
|
||||
eup->eu_memmap = malloc(sizeof(Mbd), M_DEVBUF, M_NOWAIT);
|
||||
if (eup->eu_memmap == NULL)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Test and size memory
|
||||
*/
|
||||
eup->eu_ramsize = eni_test_memory ( eup );
|
||||
|
||||
/*
|
||||
* Initialize a one element list which contains
|
||||
* all buffer memory
|
||||
*/
|
||||
eup->eu_memmap->prev = eup->eu_memmap->next = NULL;
|
||||
eup->eu_memmap->base = (caddr_t)SEGBUF_BASE;
|
||||
eup->eu_memmap->size = eup->eu_ramsize - SEGBUF_BASE;
|
||||
eup->eu_memmap->state = MEM_FREE;
|
||||
|
||||
return ( eup->eu_ramsize );
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a buffer from adapter RAM. Due to constraints on the card,
|
||||
* we may roundup the size request to the next largest chunksize. Note
|
||||
* also that we must pay attention to address alignment within adapter
|
||||
* memory as well.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to per unit structure
|
||||
* size pointer to requested size - in bytes
|
||||
*
|
||||
* Returns:
|
||||
* addr address relative to adapter of allocated memory
|
||||
* size modified to reflect actual size of buffer
|
||||
*
|
||||
*/
|
||||
caddr_t
|
||||
eni_allocate_buffer ( eup, size )
|
||||
Eni_unit *eup;
|
||||
u_long *size;
|
||||
{
|
||||
int nsize;
|
||||
int nclicks;
|
||||
Mbd *eptr = eup->eu_memmap;
|
||||
|
||||
/*
|
||||
* Initial size requested
|
||||
*/
|
||||
nsize = *size;
|
||||
|
||||
/*
|
||||
* Find the buffer size which will hold this request. There
|
||||
* are 8 possible sizes, each a power of two up, starting at
|
||||
* 256 words or 1024 bytes.
|
||||
*/
|
||||
for ( nclicks = 0; nclicks < ENI_BUF_NBIT; nclicks++ )
|
||||
if ( ( 1 << nclicks ) * ENI_BUF_PGSZ >= nsize )
|
||||
break;
|
||||
|
||||
/*
|
||||
* Request was for larger then the card supports
|
||||
*/
|
||||
if ( nclicks >= ENI_BUF_NBIT ) {
|
||||
eup->eu_stats.eni_st_drv.drv_mm_toobig++;
|
||||
/* Indicate 0 bytes allocated */
|
||||
*size = 0;
|
||||
/* Return NULL buffer */
|
||||
return ( (caddr_t)NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
* New size will be buffer size
|
||||
*/
|
||||
nsize = ( 1 << nclicks ) * ENI_BUF_PGSZ;
|
||||
|
||||
/*
|
||||
* Look through memory for a segment large enough to
|
||||
* hold request
|
||||
*/
|
||||
while ( eptr ) {
|
||||
/*
|
||||
* State must be FREE and size must hold request
|
||||
*/
|
||||
if ( eptr->state == MEM_FREE && eptr->size >= nsize )
|
||||
{
|
||||
/*
|
||||
* Request will fit - now check if the
|
||||
* alignment needs fixing
|
||||
*/
|
||||
if ( ((uintptr_t)eptr->base & (nsize-1)) != 0 )
|
||||
{
|
||||
caddr_t nbase;
|
||||
|
||||
/*
|
||||
* Calculate where the buffer would have to
|
||||
* fall to be aligned.
|
||||
*/
|
||||
nbase = (caddr_t)((uintptr_t)( eptr->base + nsize ) &
|
||||
~(nsize-1));
|
||||
/*
|
||||
* If we use this alignment, will it still fit?
|
||||
*/
|
||||
if ( (eptr->size - (nbase - eptr->base)) >= nsize )
|
||||
{
|
||||
Mbd *etmp;
|
||||
|
||||
/* Yep - create a new segment */
|
||||
etmp = malloc(sizeof(Mbd), M_DEVBUF, M_NOWAIT);
|
||||
if (etmp == NULL) {
|
||||
/*
|
||||
* Couldn't allocate a new descriptor. Indicate
|
||||
* failure and exit now or we'll start losing
|
||||
* memory.
|
||||
*/
|
||||
eup->eu_stats.eni_st_drv.drv_mm_nodesc++;
|
||||
*size = 0;
|
||||
return (NULL);
|
||||
}
|
||||
/* Place it in the list */
|
||||
etmp->next = eptr->next;
|
||||
if ( etmp->next )
|
||||
etmp->next->prev = etmp;
|
||||
etmp->prev = eptr;
|
||||
eptr->next = etmp;
|
||||
/* Fill in new base and size */
|
||||
etmp->base = nbase;
|
||||
etmp->size = eptr->size - ( nbase - eptr->base );
|
||||
/* Adjust old size */
|
||||
eptr->size -= etmp->size;
|
||||
/* Mark its state */
|
||||
etmp->state = MEM_FREE;
|
||||
eptr = etmp;
|
||||
/* Done - outa here */
|
||||
break;
|
||||
}
|
||||
} else
|
||||
break; /* Alignment is okay - we're done */
|
||||
}
|
||||
/* Haven't found anything yet - keep looking */
|
||||
eptr = eptr->next;
|
||||
}
|
||||
|
||||
if ( eptr != NULL )
|
||||
{
|
||||
/* Found a usable segment - grab what we need */
|
||||
/* Exact fit? */
|
||||
if ( eptr->size == nsize )
|
||||
/* Mark it as INUSE */
|
||||
eptr->state = MEM_INUSE;
|
||||
else
|
||||
{
|
||||
Mbd *etmp;
|
||||
/* larger then we need - split it */
|
||||
|
||||
etmp = (Mbd *)malloc(sizeof(Mbd), M_DEVBUF, M_NOWAIT);
|
||||
if ( etmp == (Mbd *)NULL ) {
|
||||
/*
|
||||
* Couldn't allocate new descriptor. Indicate
|
||||
* failure and exit now or we'll start losing
|
||||
* memory.
|
||||
*/
|
||||
eup->eu_stats.eni_st_drv.drv_mm_nodesc++;
|
||||
*size = 0;
|
||||
return ( (caddr_t)NULL );
|
||||
}
|
||||
/* Place new element in list */
|
||||
etmp->next = eptr->next;
|
||||
if ( etmp->next )
|
||||
etmp->next->prev = etmp;
|
||||
etmp->prev = eptr;
|
||||
eptr->next = etmp;
|
||||
/* Set new base, size and state */
|
||||
etmp->base = eptr->base + nsize;
|
||||
etmp->size = eptr->size - nsize;
|
||||
etmp->state = MEM_FREE;
|
||||
/* Adjust size and state of element we intend to use */
|
||||
eptr->size = nsize;
|
||||
eptr->state = MEM_INUSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* After all that, did we find a usable buffer? */
|
||||
if ( eptr )
|
||||
{
|
||||
/* Record another inuse buffer of this size */
|
||||
if ( eptr->base )
|
||||
eup->eu_memclicks[nclicks]++;
|
||||
|
||||
/*
|
||||
* Return true size of allocated buffer
|
||||
*/
|
||||
*size = eptr->size;
|
||||
/*
|
||||
* Make address relative to start of RAM since
|
||||
* its (the address) for use by the adapter, not
|
||||
* the host.
|
||||
*/
|
||||
return ((caddr_t)eptr->base);
|
||||
} else {
|
||||
eup->eu_stats.eni_st_drv.drv_mm_nobuf++;
|
||||
/* No buffer to return - indicate zero length */
|
||||
*size = 0;
|
||||
/* Return NULL buffer */
|
||||
return ( (caddr_t)NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Procedure to release a buffer previously allocated from adapter
|
||||
* RAM. When possible, we'll compact memory.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to per unit structure
|
||||
* base base adapter address of buffer to be freed
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
eni_free_buffer ( eup, base )
|
||||
Eni_unit *eup;
|
||||
caddr_t base;
|
||||
{
|
||||
Mbd *eptr = eup->eu_memmap;
|
||||
int nclicks;
|
||||
|
||||
/* Look through entire list */
|
||||
while ( eptr )
|
||||
{
|
||||
/* Is this the buffer to be freed? */
|
||||
if ( eptr->base == base )
|
||||
{
|
||||
/*
|
||||
* We're probably asking for trouble but,
|
||||
* assume this is it.
|
||||
*/
|
||||
if ( eptr->state != MEM_INUSE )
|
||||
{
|
||||
eup->eu_stats.eni_st_drv.drv_mm_notuse++;
|
||||
/* Huh? Something's wrong */
|
||||
return;
|
||||
}
|
||||
/* Reset state to FREE */
|
||||
eptr->state = MEM_FREE;
|
||||
|
||||
/* Determine size for stats info */
|
||||
for ( nclicks = 0; nclicks < ENI_BUF_NBIT; nclicks++ )
|
||||
if ( ( 1 << nclicks ) * ENI_BUF_PGSZ == eptr->size )
|
||||
break;
|
||||
|
||||
/* Valid size? Yes - decrement inuse count */
|
||||
if ( nclicks < ENI_BUF_NBIT )
|
||||
eup->eu_memclicks[nclicks]--;
|
||||
|
||||
/* Try to compact neighbors */
|
||||
/* with previous */
|
||||
if ( eptr->prev )
|
||||
if ( eptr->prev->state == MEM_FREE )
|
||||
{
|
||||
Mbd *etmp = eptr;
|
||||
/* Add to previous block */
|
||||
eptr->prev->size += eptr->size;
|
||||
/* Set prev block to skip this one */
|
||||
eptr->prev->next = eptr->next;
|
||||
/* Set next block to skip this one */
|
||||
if ( eptr->next )
|
||||
eptr->next->prev = eptr->prev;
|
||||
/* Reset to where we want to be */
|
||||
eptr = eptr->prev;
|
||||
/* and free this element */
|
||||
free(etmp, M_DEVBUF);
|
||||
}
|
||||
/* with next */
|
||||
if ( eptr->next )
|
||||
if ( eptr->next->state == MEM_FREE )
|
||||
{
|
||||
Mbd *etmp = eptr->next;
|
||||
|
||||
/* add following block in */
|
||||
eptr->size += etmp->size;
|
||||
/* set next next block to skip next block */
|
||||
if ( etmp->next )
|
||||
etmp->next->prev = eptr;
|
||||
/* skip next block */
|
||||
eptr->next = etmp->next;
|
||||
/* and free next element */
|
||||
free(etmp, M_DEVBUF);
|
||||
}
|
||||
/*
|
||||
* We've freed the buffer and done any compaction,
|
||||
* we needn't look any further...
|
||||
*/
|
||||
return;
|
||||
}
|
||||
eptr = eptr->next;
|
||||
}
|
||||
|
||||
if ( eptr == NULL )
|
||||
{
|
||||
/* Oops - failed to find the buffer. This is BAD */
|
||||
eup->eu_stats.eni_st_drv.drv_mm_notfnd++;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
* -----------------------------
|
||||
*
|
||||
* Global variable definitions
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <net/if.h>
|
||||
#include <netatm/port.h>
|
||||
#include <netatm/queue.h>
|
||||
#include <netatm/atm.h>
|
||||
#include <netatm/atm_sys.h>
|
||||
#include <netatm/atm_sap.h>
|
||||
#include <netatm/atm_cm.h>
|
||||
#include <netatm/atm_if.h>
|
||||
#include <netatm/atm_stack.h>
|
||||
#include <netatm/atm_pcb.h>
|
||||
#include <netatm/atm_var.h>
|
||||
|
||||
#include <dev/hea/eni_stats.h>
|
||||
#include <dev/hea/eni.h>
|
||||
|
||||
#include <vm/uma.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("@(#) $FreeBSD$");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Device unit table
|
||||
*/
|
||||
Eni_unit *eni_units[ENI_MAX_UNITS] = {NULL};
|
||||
|
||||
/*
|
||||
* ATM Interface services
|
||||
*/
|
||||
/*
|
||||
* AAL5 service stack
|
||||
*/
|
||||
static struct stack_defn eni_svaal5 = {
|
||||
NULL,
|
||||
SAP_CPCS_AAL5,
|
||||
SDF_TERM,
|
||||
atm_dev_inst,
|
||||
atm_dev_lower,
|
||||
NULL,
|
||||
0,
|
||||
};
|
||||
/*
|
||||
* Efficient hardware doesn't support AAL3/4. Don't define
|
||||
* an AAL3/4 stack.
|
||||
*/
|
||||
/*
|
||||
* AAL0 service stack
|
||||
*/
|
||||
static struct stack_defn eni_svaal0 = {
|
||||
&eni_svaal5,
|
||||
SAP_ATM,
|
||||
SDF_TERM,
|
||||
atm_dev_inst,
|
||||
atm_dev_lower,
|
||||
NULL,
|
||||
0,
|
||||
};
|
||||
struct stack_defn *eni_services = &eni_svaal0;
|
||||
|
||||
/*
|
||||
* Storage pools
|
||||
*/
|
||||
uma_zone_t eni_nif_zone;
|
||||
uma_zone_t eni_vcc_zone;
|
@ -1,287 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
* @(#) $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
* -----------------------------
|
||||
*
|
||||
* Network interface layer support
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <net/if.h>
|
||||
#include <netatm/port.h>
|
||||
#include <netatm/queue.h>
|
||||
#include <netatm/atm.h>
|
||||
#include <netatm/atm_sys.h>
|
||||
#include <netatm/atm_sap.h>
|
||||
#include <netatm/atm_cm.h>
|
||||
#include <netatm/atm_if.h>
|
||||
#include <netatm/atm_ioctl.h>
|
||||
#include <netatm/atm_stack.h>
|
||||
#include <netatm/atm_pcb.h>
|
||||
#include <netatm/atm_var.h>
|
||||
|
||||
#include <dev/hea/eni_stats.h>
|
||||
#include <dev/hea/eni.h>
|
||||
#include <dev/hea/eni_suni.h>
|
||||
#include <dev/hea/eni_var.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("@(#) $FreeBSD$");
|
||||
#endif
|
||||
|
||||
static void eni_get_stats(Eni_unit *);
|
||||
|
||||
/*
|
||||
* SUNI statistics counters take one of three forms:
|
||||
* single byte value (0x0 - 0xff)
|
||||
* two byte value (0x0 - 0xffff)
|
||||
* two + 1/2 (three) byte value
|
||||
* (0x0 - 0x0fffff)
|
||||
*/
|
||||
#define READ_ONE(x) ( (eup->eu_suni[(x)] & 0xff) )
|
||||
|
||||
#define READ_TWO(x) ( (eup->eu_suni[(x)+1] & 0xff) << 8 | \
|
||||
(eup->eu_suni[(x)] & 0xff) )
|
||||
|
||||
#define READ_THREE(x) ( (eup->eu_suni[(x)+2] & 0xf) << 16 | \
|
||||
(eup->eu_suni[(x)+1] & 0xff) << 8 | \
|
||||
(eup->eu_suni[(x)] & 0xff) )
|
||||
|
||||
/*
|
||||
* Do an initial read of the error counters without saving them.
|
||||
* In effect, this will "zero" our idea of the number of errors
|
||||
* which have occurred since the driver was loaded.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to per unit structure
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
eni_zero_stats ( eup )
|
||||
Eni_unit *eup;
|
||||
{
|
||||
int val;
|
||||
|
||||
/*
|
||||
* Write the SUNI master control register which
|
||||
* will cause all the statistics counters to be
|
||||
* loaded.
|
||||
*/
|
||||
eup->eu_suni[SUNI_MASTER_REG] = eup->eu_suni[SUNI_MASTER_REG];
|
||||
|
||||
/*
|
||||
* Delay to allow for counter load time...
|
||||
*/
|
||||
DELAY ( SUNI_DELAY );
|
||||
|
||||
/*
|
||||
* Statistics counters contain the number of events
|
||||
* since the last time the counter was read.
|
||||
*/
|
||||
val = READ_TWO ( SUNI_SECT_BIP_REG ); /* oc3_sect_bip8 */
|
||||
val = READ_TWO ( SUNI_PATH_BIP_REG ); /* oc3_path_bip8 */
|
||||
val = READ_THREE ( SUNI_LINE_BIP_REG ); /* oc3_line_bip24 */
|
||||
val = READ_THREE ( SUNI_LINE_FEBE_REG ); /* oc3_line_febe */
|
||||
val = READ_TWO ( SUNI_PATH_FEBE_REG ); /* oc3_path_febe */
|
||||
val = READ_ONE ( SUNI_HECS_REG ); /* oc3_hec_corr */
|
||||
val = READ_ONE ( SUNI_UHECS_REG ); /* oc3_hec_uncorr */
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve SUNI stats
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to per unit structure
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
static void
|
||||
eni_get_stats ( eup )
|
||||
Eni_unit *eup;
|
||||
{
|
||||
/*
|
||||
* Write the SUNI master control register which
|
||||
* will cause all the statistics counters to be
|
||||
* loaded.
|
||||
*/
|
||||
eup->eu_suni[SUNI_MASTER_REG] = eup->eu_suni[SUNI_MASTER_REG];
|
||||
|
||||
/*
|
||||
* Delay to allow for counter load time...
|
||||
*/
|
||||
DELAY ( 10 );
|
||||
|
||||
/*
|
||||
* Statistics counters contain the number of events
|
||||
* since the last time the counter was read.
|
||||
*/
|
||||
eup->eu_stats.eni_st_oc3.oc3_sect_bip8 +=
|
||||
READ_TWO ( SUNI_SECT_BIP_REG );
|
||||
eup->eu_stats.eni_st_oc3.oc3_path_bip8 +=
|
||||
READ_TWO ( SUNI_PATH_BIP_REG );
|
||||
eup->eu_stats.eni_st_oc3.oc3_line_bip24 +=
|
||||
READ_THREE ( SUNI_LINE_BIP_REG );
|
||||
eup->eu_stats.eni_st_oc3.oc3_line_febe +=
|
||||
READ_THREE ( SUNI_LINE_FEBE_REG );
|
||||
eup->eu_stats.eni_st_oc3.oc3_path_febe +=
|
||||
READ_TWO ( SUNI_PATH_FEBE_REG );
|
||||
eup->eu_stats.eni_st_oc3.oc3_hec_corr +=
|
||||
READ_ONE ( SUNI_HECS_REG );
|
||||
eup->eu_stats.eni_st_oc3.oc3_hec_uncorr +=
|
||||
READ_ONE ( SUNI_UHECS_REG );
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle netatm core service interface ioctl requests
|
||||
*
|
||||
* Called at splnet.
|
||||
*
|
||||
* Arguments:
|
||||
* code ioctl function (sub)code
|
||||
* data data to/from ioctl
|
||||
* arg optional code-specific argument
|
||||
*
|
||||
* Returns:
|
||||
* 0 request processed successfully
|
||||
* error request failed - reason code
|
||||
*
|
||||
*/
|
||||
int
|
||||
eni_atm_ioctl ( code, data, arg )
|
||||
int code;
|
||||
caddr_t data;
|
||||
caddr_t arg;
|
||||
{
|
||||
struct atminfreq *aip = (struct atminfreq *)data;
|
||||
struct atm_pif *pip = (struct atm_pif *)arg;
|
||||
Eni_unit *eup = (Eni_unit *)pip;
|
||||
caddr_t buf = aip->air_buf_addr;
|
||||
struct air_vinfo_rsp *avr;
|
||||
size_t len;
|
||||
size_t count;
|
||||
size_t buf_len = aip->air_buf_len;
|
||||
int err = 0;
|
||||
char ifname[2*IFNAMSIZ];
|
||||
|
||||
ATM_DEBUG2("eni_atm_ioctl: code=%d, opcode=%d\n",
|
||||
code, aip->air_opcode );
|
||||
|
||||
switch ( aip->air_opcode ) {
|
||||
|
||||
case AIOCS_INF_VST:
|
||||
/*
|
||||
* Get vendor statistics
|
||||
*/
|
||||
if ( eup == NULL )
|
||||
return ( ENXIO );
|
||||
snprintf ( ifname, sizeof(ifname),
|
||||
"%s%d", pip->pif_name, pip->pif_unit );
|
||||
|
||||
/*
|
||||
* Cast response structure onto user's buffer
|
||||
*/
|
||||
avr = (struct air_vinfo_rsp *)buf;
|
||||
|
||||
/*
|
||||
* How large is the response structure
|
||||
*/
|
||||
len = sizeof(struct air_vinfo_rsp);
|
||||
|
||||
/*
|
||||
* Sanity check - enough room for response structure?
|
||||
*/
|
||||
if ( buf_len < len )
|
||||
return ( ENOSPC );
|
||||
|
||||
/*
|
||||
* Copy interface name into response structure
|
||||
*/
|
||||
if ((err = copyout(ifname, avr->avsp_intf, IFNAMSIZ)) != 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Advance the buffer address and decrement the size
|
||||
*/
|
||||
buf += len;
|
||||
buf_len -= len;
|
||||
|
||||
/*
|
||||
* Get the vendor stats (SUNI) from the hardware
|
||||
*/
|
||||
eni_get_stats ( eup );
|
||||
/*
|
||||
* Stick as much of it as we have room for
|
||||
* into the response
|
||||
*/
|
||||
count = MIN ( sizeof(Eni_stats), buf_len );
|
||||
|
||||
/*
|
||||
* Copy stats into user's buffer. Return value is
|
||||
* amount of data copied.
|
||||
*/
|
||||
if ((err = copyout((void *)&eup->eu_stats, buf, count)) != 0)
|
||||
break;
|
||||
buf += count;
|
||||
buf_len -= count;
|
||||
if ( count < sizeof(Eni_stats) )
|
||||
err = ENOSPC;
|
||||
|
||||
/*
|
||||
* Record amount we're returning as vendor info...
|
||||
*/
|
||||
if ((err = copyout(&count, &avr->avsp_len, sizeof(count))) != 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Update the reply pointers and length
|
||||
*/
|
||||
aip->air_buf_addr = buf;
|
||||
aip->air_buf_len = buf_len;
|
||||
break;
|
||||
|
||||
default:
|
||||
err = ENOSYS; /* Operation not supported */
|
||||
break;
|
||||
}
|
||||
|
||||
return ( err );
|
||||
|
||||
}
|
||||
|
@ -1,152 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
* -----------------------------
|
||||
*
|
||||
* Driver initialization support
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <netatm/port.h>
|
||||
#include <netatm/queue.h>
|
||||
#include <netatm/atm.h>
|
||||
#include <netatm/atm_sys.h>
|
||||
#include <netatm/atm_cm.h>
|
||||
#include <netatm/atm_if.h>
|
||||
|
||||
#include <dev/hea/eni_stats.h>
|
||||
#include <dev/hea/eni.h>
|
||||
#include <dev/hea/eni_var.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("@(#) $FreeBSD$");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize adapter for PDU processing
|
||||
*
|
||||
* Enable interrupts, set master control, initialize TX buffer,
|
||||
* set initial pointers, etc.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to device unit structure
|
||||
*
|
||||
* Returns:
|
||||
* 0 successful
|
||||
* error error condition
|
||||
*/
|
||||
int
|
||||
eni_init ( eup )
|
||||
Eni_unit *eup;
|
||||
{
|
||||
u_long words, order;
|
||||
|
||||
/*
|
||||
* Allocate one large TX buffer. Currently we use only one
|
||||
* channel with full cell rate which all VCs will use.
|
||||
* This will (probably) have to change (alot) when we
|
||||
* implement QoS.
|
||||
*/
|
||||
/*
|
||||
* Server cards, which have more then 512KB of RAM, will
|
||||
* allocate a 128KB TX buffer, while client cards, with
|
||||
* 512KB or less will allocate a 32KB TX buffer.
|
||||
*/
|
||||
words = ( eup->eu_ramsize > MAX_CLIENT_RAM * ENI_BUF_PGSZ ?
|
||||
TX_LARGE_BSIZE : TX_SMALL_BSIZE ) * ENI_BUF_PGSZ;
|
||||
if ( ( eup->eu_txbuf = eni_allocate_buffer ( eup, &words ) ) ==
|
||||
(caddr_t)NULL ) {
|
||||
return ENOMEM;
|
||||
}
|
||||
eup->eu_txsize = words >> 2; /* Bytes to words */
|
||||
words >>= ENI_LOC_PREDIV; /* Predivide by 256 words */
|
||||
for ( order = -1; words; order++ )
|
||||
words >>= 1;
|
||||
eup->eu_midway[MIDWAY_TXPLACE] =
|
||||
(order << TXSIZE_SHIFT) | ((intptr_t)eup->eu_txbuf >> ENI_LOC_PREDIV);
|
||||
eup->eu_txpos = eup->eu_midway[MIDWAY_DESCR] & 0x7FFF;
|
||||
/*
|
||||
* Set first word of unack'ed data to start
|
||||
*/
|
||||
eup->eu_txfirst = eup->eu_txpos;
|
||||
|
||||
/*
|
||||
* Set initial values of local DMA pointer used to prevent wraps
|
||||
*/
|
||||
eup->eu_txdmawr = 0;
|
||||
eup->eu_rxdmawr = 0;
|
||||
|
||||
/*
|
||||
* Initialize queue's for receive/transmit pdus
|
||||
*/
|
||||
eup->eu_txqueue.ifq_maxlen = ENI_IFQ_MAXLEN;
|
||||
eup->eu_rxqueue.ifq_maxlen = ENI_IFQ_MAXLEN;
|
||||
|
||||
/*
|
||||
* Acknowledge any interrupts
|
||||
*/
|
||||
(void) eup->eu_midway[MIDWAY_ISA];
|
||||
|
||||
/*
|
||||
* "Zero" Sonet error counters
|
||||
*/
|
||||
eni_zero_stats ( eup );
|
||||
|
||||
/*
|
||||
* Set master control register
|
||||
*
|
||||
* IntSel1 | LOCK_MODE | DMA_ENABLE | TX_ENABLE | RX_ENABLE
|
||||
*
|
||||
*/
|
||||
eup->eu_midway[MIDWAY_MASTER] = 1 << ENI_ISEL_SHIFT |
|
||||
ENI_M_DMAENABLE | ENI_M_TXENABLE | ENI_M_RXENABLE;
|
||||
|
||||
/*
|
||||
* Enable interrupts
|
||||
*/
|
||||
eup->eu_midway[MIDWAY_IE] = ENI_INT_SERVICE | ENI_INT_RX_DMA |
|
||||
ENI_INT_TX_DMA | ENI_INT_DMA_ERR | ENI_INT_DMA_LERR |
|
||||
ENI_INT_IDEN | ENI_INT_DMA_OVFL;
|
||||
|
||||
/*
|
||||
* Last thing to do is to indicate that we've finished initializing
|
||||
* this unit.
|
||||
*/
|
||||
eup->eu_flags |= CUF_INITED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,242 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
* -----------------------------
|
||||
*
|
||||
* Interrupt processing
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <net/if.h>
|
||||
#include <netatm/port.h>
|
||||
#include <netatm/queue.h>
|
||||
#include <netatm/atm.h>
|
||||
#include <netatm/atm_sys.h>
|
||||
#include <netatm/atm_cm.h>
|
||||
#include <netatm/atm_if.h>
|
||||
|
||||
#include <dev/hea/eni_stats.h>
|
||||
#include <dev/hea/eni.h>
|
||||
#include <dev/hea/eni_suni.h>
|
||||
#include <dev/hea/eni_var.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("@(#) $FreeBSD$");
|
||||
#endif
|
||||
|
||||
static void eni_suni_intr(Eni_unit *);
|
||||
|
||||
/*
|
||||
* SUNI Interrupt processing
|
||||
*
|
||||
* Currently, we don't do anything more then clear the interrupt
|
||||
* for the SUNI chip.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to device unit structure
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
static void
|
||||
eni_suni_intr ( eup )
|
||||
Eni_unit *eup;
|
||||
{
|
||||
int SuniInt;
|
||||
int val;
|
||||
|
||||
SuniInt = eup->eu_suni[SUNI_IS_REG];
|
||||
|
||||
/* RSOPI */
|
||||
if ( SuniInt & SUNI_RSOPI )
|
||||
val = eup->eu_suni[SUNI_RSOP_REG];
|
||||
|
||||
/* RLOPI */
|
||||
if ( SuniInt & SUNI_RLOPI )
|
||||
val = eup->eu_suni[SUNI_RLOP_REG];
|
||||
|
||||
/* RPOPI */
|
||||
if ( SuniInt & SUNI_RPOPI )
|
||||
val = eup->eu_suni[SUNI_RPOP_IS_REG];
|
||||
|
||||
/* RACPI */
|
||||
if ( SuniInt & SUNI_RACPI )
|
||||
val = eup->eu_suni[SUNI_RACP_REG];
|
||||
|
||||
/* TACPI */
|
||||
if ( SuniInt & SUNI_TACPI )
|
||||
val = eup->eu_suni[SUNI_TACP_REG];
|
||||
|
||||
/* TROOLI */
|
||||
if ( SuniInt & SUNI_TROOLI )
|
||||
val = eup->eu_suni[SUNI_CLOCK_REG];
|
||||
|
||||
/* LCDI */
|
||||
/* Cleared when reading Master Interrupt Status Reg */
|
||||
|
||||
/* RDOOLI */
|
||||
if ( SuniInt & SUNI_RDOOLI )
|
||||
val = eup->eu_suni[SUNI_CLOCK_REG];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device interrupt routine
|
||||
*
|
||||
* Service an interrupt from this device
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to device unit structure
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
#if defined(BSD) && BSD < 199506
|
||||
int
|
||||
#else
|
||||
void
|
||||
#endif
|
||||
eni_intr ( arg )
|
||||
void *arg;
|
||||
{
|
||||
Eni_unit *eup = (Eni_unit *)arg;
|
||||
#if defined(BSD) && BSD < 199506
|
||||
int serviced = 1;
|
||||
#endif /* BSD < 199506 */
|
||||
|
||||
/*
|
||||
* Read and acknowledge any interrupts
|
||||
*/
|
||||
u_long mask = eup->eu_midway[MIDWAY_ISA];
|
||||
/*
|
||||
* Read the error statistics counter
|
||||
*/
|
||||
u_long sval = eup->eu_midway[MIDWAY_STAT];
|
||||
|
||||
/*
|
||||
* Update statistics from adapter
|
||||
*/
|
||||
eup->eu_trash += ( sval >> 16 );
|
||||
eup->eu_ovfl += ( sval & 0xffff );
|
||||
|
||||
/*
|
||||
* We handle any DMA completes first so
|
||||
* that we can free resources for use
|
||||
* during transmit and especially receive
|
||||
*/
|
||||
/*
|
||||
* Handle RX DMA Complete
|
||||
*/
|
||||
if ( mask & ENI_INT_RX_DMA ) {
|
||||
eni_recv_drain ( eup );
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle TX DMA Complete
|
||||
*/
|
||||
if ( mask & ENI_INT_TX_DMA ) {
|
||||
eni_xmit_drain ( eup );
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for any PDUs in service list
|
||||
*/
|
||||
if ( mask & ENI_INT_SERVICE ) {
|
||||
eni_do_service ( eup );
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle miscelaneous interrupts
|
||||
*/
|
||||
if ( mask & ENI_INT_STAT ) { /* STAT_OVFL */
|
||||
log ( LOG_INFO, "eni_intr: stat_ovfl: 0x%lx\n", sval );
|
||||
}
|
||||
if ( mask & ENI_INT_SUNI ) { /* SUNI_INTR */
|
||||
eni_suni_intr ( eup );
|
||||
}
|
||||
if ( mask & ENI_INT_DMA_ERR ) { /* DMA Error */
|
||||
log ( LOG_ERR,
|
||||
"eni_intr: DMA Error\n" );
|
||||
/*
|
||||
* We don't know how to recover from DMA errors
|
||||
* yet. The adapter has disabled any further
|
||||
* processing and we're going to leave it like
|
||||
* that.
|
||||
*/
|
||||
#if defined(BSD) && BSD < 199506
|
||||
return serviced; /* Leave now */
|
||||
#else
|
||||
return; /* Leave now */
|
||||
#endif
|
||||
}
|
||||
if ( mask & ENI_INT_IDEN ) {
|
||||
log ( LOG_ERR,
|
||||
"eni_intr: TX DMA Ident mismatch\n" );
|
||||
/*
|
||||
* Something in the TX buffer has really gotten messed
|
||||
* up. Since this is most likely a driver bug, and
|
||||
* the adapter has shut everything down, leave it
|
||||
* like that.
|
||||
*/
|
||||
#if BSD < 199506
|
||||
return 0; /* Leave now */
|
||||
#else
|
||||
return; /* Leave now */
|
||||
#endif
|
||||
}
|
||||
if ( mask & ENI_INT_DMA_OVFL )
|
||||
eup->eu_stats.eni_st_drv.drv_xm_dmaovfl++;
|
||||
if ( mask & ENI_INT_DMA_LERR ) {
|
||||
log ( LOG_ERR,
|
||||
"eni_intr: DMA LERR\n" );
|
||||
#if BSD < 199506
|
||||
return 0;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BSD < 199506
|
||||
return 0;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
@ -1,878 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
* -----------------------------
|
||||
*
|
||||
* Receive management
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <net/if.h>
|
||||
#include <net/netisr.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netatm/port.h>
|
||||
#include <netatm/queue.h>
|
||||
#include <netatm/atm.h>
|
||||
#include <netatm/atm_sys.h>
|
||||
#include <netatm/atm_sap.h>
|
||||
#include <netatm/atm_cm.h>
|
||||
#include <netatm/atm_if.h>
|
||||
#include <netatm/atm_vc.h>
|
||||
#include <netatm/atm_stack.h>
|
||||
#include <netatm/atm_pcb.h>
|
||||
#include <netatm/atm_var.h>
|
||||
|
||||
#include <dev/hea/eni_stats.h>
|
||||
#include <dev/hea/eni.h>
|
||||
#include <dev/hea/eni_var.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("@(#) $FreeBSD$");
|
||||
#endif
|
||||
|
||||
static void eni_recv_stack(void *, KBuffer *);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
extern int eni_pdu_print;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Procedure to remove VCs from the Service List and generate DMA
|
||||
* requests to move the associated PDUs into host memory. As PDUs
|
||||
* are completed in adapter memory, the adapter examines the IN_SERVICE
|
||||
* bit for the VC in the VC table. If this bit is not set, the adapter
|
||||
* will place the VC number at the end of the service list queue, set
|
||||
* the IN_SERVICE bit in the VC table, and interrupt the host. The host
|
||||
* will remove VCs from the service list, clear the IN_SERVICE bit in
|
||||
* the VC table, and create a DMA list to move the PDU into host buffers.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to per unit structure
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
eni_do_service ( eup )
|
||||
Eni_unit *eup;
|
||||
{
|
||||
int vcc;
|
||||
Eni_vcc *evp;
|
||||
u_long servwrite;
|
||||
VCI_Table *vct;
|
||||
u_long rdptr;
|
||||
u_long *rxp;
|
||||
KBuffer *m;
|
||||
u_long dma[TEMP_DMA_SIZE];
|
||||
u_long i, j;
|
||||
u_long dma_rd, dma_wr;
|
||||
u_long dma_avail;
|
||||
int pdulen;
|
||||
int mask;
|
||||
u_long *upp;
|
||||
|
||||
/*
|
||||
* Where is the adapter currently inserting entries?
|
||||
*/
|
||||
servwrite = eup->eu_midway[MIDWAY_SVCWR] & SVC_SIZE_MASK;
|
||||
/*
|
||||
* As long as we're not caught up with the adapter, keep
|
||||
* removing VCs from the service list.
|
||||
*/
|
||||
while ( servwrite != eup->eu_servread ) {
|
||||
int vci_hdr;
|
||||
u_long descr;
|
||||
|
||||
/*
|
||||
* Get VC number and find VC table entry.
|
||||
*/
|
||||
vcc = eup->eu_svclist[eup->eu_servread];
|
||||
vct = &eup->eu_vcitbl[vcc];
|
||||
vci_hdr = vct->vci_control; /* Current status */
|
||||
|
||||
/*
|
||||
* Check that this VCC still needs servicing. We
|
||||
* might have closed this VCC down in between
|
||||
* the adapter setting the flag and our checking
|
||||
* the flag. Also check that we haven't placed the
|
||||
* VCC into TRASH mode.
|
||||
*/
|
||||
if ( ( vci_hdr & VCI_IN_SERVICE ) == 0 ||
|
||||
( (vci_hdr & ~VCI_MODE_MASK) ==
|
||||
(VCI_MODE_TRASH << VCI_MODE_SHIFT) ) )
|
||||
goto next_vcc;
|
||||
|
||||
/*
|
||||
* Find the size of this VCs buffer
|
||||
*/
|
||||
mask = (vci_hdr >> VCI_SIZE_SHIFT) & VCI_SIZE_MASK;
|
||||
mask = 1 << (ENI_LOC_PREDIV + mask);
|
||||
/* Turn byte count into word count */
|
||||
mask >>= 2;
|
||||
/*
|
||||
* Find the start of the adapter buffer for this VC.
|
||||
*/
|
||||
rxp = (u_long *)
|
||||
((intptr_t)(((vci_hdr >> VCI_LOC_SHIFT ) & VCI_LOC_MASK)
|
||||
<< ENI_LOC_PREDIV) + (intptr_t)eup->eu_ram);
|
||||
/*
|
||||
* Locate incoming VCC for this PDU and find where we
|
||||
* should next read from.
|
||||
*/
|
||||
evp = (Eni_vcc *) atm_dev_vcc_find ( (Cmn_unit *)eup,
|
||||
0, vcc, VCC_IN );
|
||||
if ( evp == (Eni_vcc *)NULL )
|
||||
goto next_vcc; /* VCI no longer active */
|
||||
rdptr = evp->ev_rxpos;
|
||||
/*
|
||||
* Find out where the adapter is currently reassembling.
|
||||
* The PDU which starts at descr is not yet complete so we
|
||||
* must stop there.
|
||||
*/
|
||||
descr = ( vct->vci_descr >> 16 ) & 0x7FFF;
|
||||
/*
|
||||
* As long as we haven't processed all the completed PDUs on
|
||||
* this VC, keep going...
|
||||
*/
|
||||
while ( rdptr != descr )
|
||||
{
|
||||
int n_cells;
|
||||
int pdu_descr;
|
||||
int aal5;
|
||||
|
||||
/*
|
||||
* Ensure that the following are reset for every new
|
||||
* PDU.
|
||||
*/
|
||||
upp = NULL;
|
||||
m = NULL;
|
||||
|
||||
/*
|
||||
* Fisrt build a DMA with JK to skip the descriptor word.
|
||||
* We must always skip the descriptor even if it turns out
|
||||
* that there isn't any PDU here.
|
||||
*/
|
||||
j = 0;
|
||||
dma[j++] = (((rdptr + 1) & (mask-1)) << DMA_COUNT_SHIFT ) |
|
||||
( vcc << DMA_VCC_SHIFT ) | DMA_JK;
|
||||
dma[j++] = 0;
|
||||
|
||||
/*
|
||||
* We'll use some of the values below for skipping
|
||||
* bad PDUs or counting statistics so compute them
|
||||
* now.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Grab a copy of the descriptor word
|
||||
*/
|
||||
pdu_descr = rxp[rdptr];
|
||||
|
||||
/*
|
||||
* Strip out cell count from descriptor word.
|
||||
* At this point, we still don't know if there
|
||||
* is any real data until after we check for
|
||||
* TRASH mode.
|
||||
*/
|
||||
n_cells = pdu_descr & DESCR_CELL_COUNT;
|
||||
|
||||
/*
|
||||
* Is this an AAL5 PDU? Check MODE in vci_hdr.
|
||||
*/
|
||||
aal5 = ( ( vci_hdr & ~VCI_MODE_MASK ) ==
|
||||
VCI_MODE_AAL5 << VCI_MODE_SHIFT );
|
||||
|
||||
/*
|
||||
* Now check to see if we're trashing on this vcc.
|
||||
* If so, there is no data with this VC and the
|
||||
* next word after the current descriptor is the
|
||||
* descriptor for the next PDU.
|
||||
*/
|
||||
if ( ( pdu_descr & DESCR_TRASH_BIT ) != 0 ) {
|
||||
if ( aal5 )
|
||||
/*
|
||||
* Count as number of AAL5 cells dropped
|
||||
*/
|
||||
eup->eu_stats.eni_st_aal5.aal5_drops += n_cells;
|
||||
else
|
||||
/*
|
||||
* Count as number of AAL0 cells dropped
|
||||
*/
|
||||
eup->eu_stats.eni_st_aal0.aal0_drops += n_cells;
|
||||
eup->eu_pif.pif_ierrors++;
|
||||
/*
|
||||
* When cells have been trashed, all we have in the
|
||||
* buffer is a descriptor word. There are no data
|
||||
* words. Set the number of cells to zero so that
|
||||
* we correctly skip to the next word which will
|
||||
* be the descriptor for the next PDU.
|
||||
*/
|
||||
n_cells = 0;
|
||||
/*
|
||||
* Go issue the DMA to skip this descriptor word.
|
||||
*/
|
||||
goto send_dma;
|
||||
}
|
||||
|
||||
/*
|
||||
* Data length: number of cells * cell size
|
||||
*/
|
||||
pdulen = n_cells * BYTES_PER_CELL;
|
||||
|
||||
/*
|
||||
* If this is an AAL5 PDU, then we need to check
|
||||
* for the presence of any CRC errors. If there
|
||||
* is one or more CRC errors, then we are going to
|
||||
* drop this PDU.
|
||||
*/
|
||||
if ( aal5 && ( pdu_descr & DESCR_CRC_ERR ) ) {
|
||||
/*
|
||||
* Count the stat
|
||||
*/
|
||||
eup->eu_pif.pif_ierrors++;
|
||||
eup->eu_stats.eni_st_aal5.aal5_pdu_crc++;
|
||||
if ( evp->ev_connvc->cvc_vcc )
|
||||
evp->ev_connvc->cvc_vcc->vc_ierrors++;
|
||||
/*
|
||||
* Build a DMA entry to skip the rest of this
|
||||
* PDU.
|
||||
*/
|
||||
dma[j++] =
|
||||
(((rdptr + n_cells*WORDS_PER_CELL + 1)
|
||||
& (mask-1)) << DMA_COUNT_SHIFT ) |
|
||||
(vcc << DMA_VCC_SHIFT ) | DMA_JK;
|
||||
dma[j++] = 0;
|
||||
/*
|
||||
* All done with this PDU. Get a buffer to save some
|
||||
* data for reclamation services.
|
||||
*/
|
||||
KB_ALLOCPKT ( m, ENI_SMALL_BSIZE, KB_F_NOWAIT,
|
||||
KB_T_DATA );
|
||||
if ( m ) {
|
||||
u_long *up;
|
||||
|
||||
KB_DATASTART ( m, up, u_long * );
|
||||
/*
|
||||
* Indicate no PDU
|
||||
*/
|
||||
KB_PLENSET ( m, 0 );
|
||||
/*
|
||||
* Set buffer length - only driver overhead
|
||||
*/
|
||||
KB_LEN ( m ) = 3 * sizeof ( u_long );
|
||||
/*
|
||||
* Insert vcc, space for DMA pointers,
|
||||
* and pdulen
|
||||
*/
|
||||
*up++ = vcc;
|
||||
upp = up; /* Remember location */
|
||||
up++; /* And skip it */
|
||||
/* - to be filled later */
|
||||
*up = pdulen; /* Actual PDU length if it */
|
||||
/* were valid */
|
||||
} else {
|
||||
/*
|
||||
* We've a real problem here as now we can't
|
||||
* reclaim/advance resources/safety pointers.
|
||||
*/
|
||||
eup->eu_stats.eni_st_drv.drv_rv_norsc++;
|
||||
#ifdef DO_LOG
|
||||
log ( LOG_ERR,
|
||||
"eni_do_service: No drain buffers available. Receiver about to lock.\n" );
|
||||
#endif
|
||||
}
|
||||
goto send_dma;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do we need to strip the AAL layer? Yes if this
|
||||
* is an AAL5 PDU.
|
||||
*/
|
||||
if ( aal5 ) {
|
||||
/*
|
||||
* Grab the CS-PDU length. Find the address of the
|
||||
* last word, back up one word to skip CRC, and
|
||||
* then mask the whole thing to handle circular wraps.
|
||||
*/
|
||||
pdulen = rxp[(rdptr + n_cells*WORDS_PER_CELL - 1)
|
||||
& (mask-1)]
|
||||
& 0xFFFF;
|
||||
}
|
||||
|
||||
/*
|
||||
* We now have a valid PDU of some length. Build
|
||||
* the necessary DMA list to move it into host
|
||||
* memory.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get an initial buffer.
|
||||
*/
|
||||
KB_ALLOCPKT ( m, ENI_SMALL_BSIZE, KB_F_NOWAIT, KB_T_DATA );
|
||||
/*
|
||||
* Do we have a valid buffer?
|
||||
*/
|
||||
if ( m != (KBuffer *)NULL )
|
||||
{
|
||||
int len;
|
||||
u_long *up;
|
||||
KBuffer *m0;
|
||||
|
||||
KB_DATASTART ( m, up, u_long * );
|
||||
/*
|
||||
* Fill in pdulen in PKTHDR structure (for IP).
|
||||
*/
|
||||
KB_PLENSET ( m, pdulen );
|
||||
/*
|
||||
* We're going to save the VCI nuber, the start
|
||||
* and stop DMA pointers, and the PDU length at
|
||||
* the head of the buffer. We'll pull this out
|
||||
* later after the DMA has completed.
|
||||
*
|
||||
* Insert VCI number as first word in first buffer,
|
||||
* remeber where we want to store the start/stop
|
||||
* pointers, and store the PDU length.
|
||||
*/
|
||||
*up++ = vcc; /* PDU's VCC */
|
||||
upp = up; /* Remember where we are */
|
||||
up++; /* To stuff start/stop pointers in */
|
||||
*up++ = pdulen; /* PDU's length */
|
||||
/*
|
||||
* Leave some extra room in case a higher protocol
|
||||
* (IP) wants to do a pullup. Maybe we can keep
|
||||
* someone from having to allocate another buffer
|
||||
* a do a larger memory copy.
|
||||
*/
|
||||
len = MIN ( ENI_SMALL_BSIZE, pdulen );
|
||||
(void) eni_set_dma ( eup, 1, dma, TEMP_DMA_SIZE, &j,
|
||||
vcc, (u_long)up, len );
|
||||
/*
|
||||
* Adjust length of remaining data in PDU
|
||||
*/
|
||||
pdulen -= len;
|
||||
/*
|
||||
* Set buffer length, including our overhead
|
||||
*/
|
||||
KB_LEN ( m ) = len + 3 * sizeof ( u_long );
|
||||
/*
|
||||
* Finish by moving anything which won't fit in
|
||||
* first buffer
|
||||
*/
|
||||
m0 = m;
|
||||
while ( pdulen ) {
|
||||
KBuffer *m1;
|
||||
u_long data_addr;
|
||||
|
||||
/*
|
||||
* Get another buffer
|
||||
*/
|
||||
KB_ALLOCEXT ( m1, ENI_LARGE_BSIZE, KB_F_NOWAIT,
|
||||
KB_T_DATA );
|
||||
|
||||
/*
|
||||
* If we succeeded...
|
||||
*/
|
||||
if ( m1 ) {
|
||||
/*
|
||||
* Figure out how much we can move into
|
||||
* this buffer.
|
||||
*/
|
||||
len = MIN ( ENI_LARGE_BSIZE, pdulen );
|
||||
/*
|
||||
* Setup DMA list for this buffer
|
||||
*/
|
||||
KB_DATASTART ( m1, data_addr, u_long );
|
||||
(void) eni_set_dma
|
||||
( eup, 1, dma, TEMP_DMA_SIZE, &j, vcc,
|
||||
data_addr, len );
|
||||
/*
|
||||
* Adjust remaining length
|
||||
*/
|
||||
pdulen -= len;
|
||||
/*
|
||||
* Set buffer length
|
||||
*/
|
||||
KB_LEN ( m1 ) = len;
|
||||
/*
|
||||
* Link new buffer onto end and advance
|
||||
* pointer
|
||||
*/
|
||||
KB_NEXT ( m0 ) = m1;
|
||||
m0 = m1;
|
||||
} else {
|
||||
/*
|
||||
* Either we were unable to grab another
|
||||
* buffer or there are no large buffers
|
||||
* available. We know that the first
|
||||
* buffer is valid, so drop everything
|
||||
* else, build a JK DMA to skip/drop this
|
||||
* PDU, set the pointers to reclaim
|
||||
* resources/advance pointers, and
|
||||
* finish this PDU now.
|
||||
*/
|
||||
if ( KB_NEXT ( m ) )
|
||||
KB_FREEALL ( KB_NEXT ( m ) );
|
||||
eup->eu_pif.pif_ierrors++;
|
||||
j = 2;
|
||||
dma[j++] =
|
||||
(((rdptr + n_cells*WORDS_PER_CELL + 1)
|
||||
& (mask-1)) << DMA_COUNT_SHIFT ) |
|
||||
(vcc << DMA_VCC_SHIFT ) |
|
||||
DMA_JK;
|
||||
dma[j++] = 0;
|
||||
/*
|
||||
* Reset PDU length to zero
|
||||
*/
|
||||
KB_PLENSET ( m, 0 );
|
||||
/*
|
||||
* Count some statistics
|
||||
*/
|
||||
/*
|
||||
* Count this as dropped cells
|
||||
*/
|
||||
if ( aal5 ) {
|
||||
eup->eu_stats.eni_st_aal5.aal5_drops +=
|
||||
n_cells;
|
||||
eup->eu_stats.eni_st_aal5.aal5_pdu_drops++;
|
||||
} else
|
||||
eup->eu_stats.eni_st_aal0.aal0_drops +=
|
||||
n_cells;
|
||||
/*
|
||||
* Drop it
|
||||
*/
|
||||
goto send_dma;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If necessary, skip AAL layer
|
||||
*/
|
||||
if ( aal5 ) {
|
||||
dma[j++] =
|
||||
(((rdptr + n_cells*WORDS_PER_CELL + 1)
|
||||
& (mask-1)) << DMA_COUNT_SHIFT)
|
||||
| (vcc << DMA_VCC_SHIFT) | DMA_JK;
|
||||
dma[j++] = 0;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We failed to get an initial buffer. Since we
|
||||
* haven't changed anything for this PDU yet and the
|
||||
* PDU is still valid, exit now and try to service it
|
||||
* next time around. We're not very likely to get
|
||||
* another buffer right now anyways.
|
||||
*/
|
||||
eup->eu_stats.eni_st_drv.drv_rv_nobufs++;
|
||||
#ifdef DO_LOG
|
||||
log ( LOG_ERR,
|
||||
"eni_do_service: No buffers available. Exiting without servicing service list.\n" );
|
||||
#endif
|
||||
/*
|
||||
* Clear the IN_SERVICE indicator for this VCC
|
||||
*/
|
||||
vct->vci_control &= ~VCI_IN_SERVICE;
|
||||
return;
|
||||
}
|
||||
|
||||
send_dma:
|
||||
/*
|
||||
* Set the end bit on the last DMA for this PDU
|
||||
*/
|
||||
dma[j-2] |= DMA_END_BIT;
|
||||
|
||||
/*
|
||||
* Where are the current DMA pointers
|
||||
*/
|
||||
dma_rd = eup->eu_midway[MIDWAY_RX_RD];
|
||||
dma_wr = eup->eu_midway[MIDWAY_RX_WR];
|
||||
|
||||
/*
|
||||
* Check how much space is available
|
||||
*/
|
||||
if ( dma_rd == dma_wr )
|
||||
dma_avail = DMA_LIST_SIZE;
|
||||
else
|
||||
dma_avail = ( dma_rd + DMA_LIST_SIZE - dma_wr )
|
||||
& (DMA_LIST_SIZE-1);
|
||||
|
||||
/*
|
||||
* Check for queue full or wrap past write okay pointer
|
||||
*/
|
||||
if ( dma_avail < j ||
|
||||
( dma_wr + j > eup->eu_rxdmawr + DMA_LIST_SIZE ) ) {
|
||||
/*
|
||||
* There's no room in the DMA list to insert
|
||||
* this request. Since we haven't changed anything
|
||||
* yet and the PDU is good, exit now and service
|
||||
* it next time around. What we really need to do
|
||||
* is wait for the RX list to drain and that won't
|
||||
* happen if we keep trying to process PDUs here.
|
||||
*/
|
||||
eup->eu_stats.eni_st_drv.drv_rv_nodma++;
|
||||
#ifdef DO_LOG
|
||||
log ( LOG_ERR,
|
||||
"eni_do_service: No room in receive DMA list. Postponing service request.\n" );
|
||||
#endif
|
||||
/*
|
||||
* Free the local buffer chain
|
||||
*/
|
||||
KB_FREEALL ( m );
|
||||
/*
|
||||
* Clear the IN_SERVICE indicator for this VCC.
|
||||
*/
|
||||
vct->vci_control &= ~VCI_IN_SERVICE;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a buffer chain, save the starting
|
||||
* dma_list location.
|
||||
*/
|
||||
if ( upp ) {
|
||||
*upp = dma_wr << 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stuff the DMA list
|
||||
*/
|
||||
j >>= 1;
|
||||
for ( i = 0; i < j; i++ ) {
|
||||
eup->eu_rxdma[dma_wr*2] = dma[i*2];
|
||||
eup->eu_rxdma[dma_wr*2+1] = dma[i*2+1];
|
||||
dma_wr = (dma_wr+1) & (DMA_LIST_SIZE-1);
|
||||
}
|
||||
/*
|
||||
* If we have a buffer chain, save the location of
|
||||
* the ending dma_list location and queue the chain
|
||||
* so that we can recover the resources later.
|
||||
*/
|
||||
if ( upp ) {
|
||||
*upp |= dma_wr;
|
||||
/*
|
||||
* Place buffer on receive queue waiting for RX_DMA
|
||||
*/
|
||||
if ( _IF_QFULL ( &eup->eu_rxqueue ) ) {
|
||||
/*
|
||||
* We haven't done anything we can't back out
|
||||
* of. Drop request and service it next time.
|
||||
* We've inserted the DMA list but it's not
|
||||
* valid until we advance the RX_WR pointer,
|
||||
* thus it's okay to bail here...
|
||||
*/
|
||||
eup->eu_stats.eni_st_drv.drv_rv_rxq++;
|
||||
#ifdef DO_LOG
|
||||
log ( LOG_ERR,
|
||||
"eni_do_service: RX drain queue full. Postponing servicing.\n" );
|
||||
#endif
|
||||
KB_FREEALL ( m );
|
||||
/*
|
||||
* Clear the IN_SERVICE indicator for this VCC.
|
||||
*/
|
||||
vct->vci_control &= ~VCI_IN_SERVICE;
|
||||
return;
|
||||
} else {
|
||||
_IF_ENQUEUE ( &eup->eu_rxqueue, m );
|
||||
/*
|
||||
* Advance the RX_WR pointer to cause
|
||||
* the adapter to work on this DMA list.
|
||||
*/
|
||||
eup->eu_midway[MIDWAY_RX_WR] = dma_wr;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Advance our notion of where the next PDU
|
||||
* should start.
|
||||
*/
|
||||
rdptr = (rdptr + n_cells*WORDS_PER_CELL + 1)
|
||||
& (mask-1);
|
||||
evp->ev_rxpos = rdptr;
|
||||
|
||||
/*
|
||||
* Increment cells/pdu received stats.
|
||||
*/
|
||||
eup->eu_stats.eni_st_atm.atm_rcvd += n_cells;
|
||||
if ( aal5 ) {
|
||||
eup->eu_stats.eni_st_aal5.aal5_rcvd += n_cells;
|
||||
eup->eu_stats.eni_st_aal5.aal5_pdu_rcvd++;
|
||||
} else {
|
||||
eup->eu_stats.eni_st_aal0.aal0_rcvd += n_cells;
|
||||
}
|
||||
|
||||
/*
|
||||
* Continue processing PDUs on this same VCI
|
||||
*/
|
||||
}
|
||||
|
||||
next_vcc:
|
||||
/*
|
||||
* Advance to next entry in the service_list.
|
||||
*/
|
||||
eup->eu_servread = (eup->eu_servread + 1) & SVC_SIZE_MASK;
|
||||
|
||||
/*
|
||||
* And clear the IN_SERVICE indicator for this VCC.
|
||||
*/
|
||||
vct->vci_control &= ~VCI_IN_SERVICE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Drain Receive queue
|
||||
*
|
||||
* As we build DMA lists to move PDUs from adapter buffers into host
|
||||
* buffers, we place the request on a private ifqueue so that we can
|
||||
* free any resources AFTER we know they've been successfully DMAed.
|
||||
* As part of the service processing, we record the PDUs start and stop
|
||||
* entries in the DMA list, and prevent wrapping. When we pull the top
|
||||
* entry off, we simply check that the current DMA location is outside
|
||||
* this PDU and if so, it's okay to free things.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to device unit structure
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
eni_recv_drain ( eup )
|
||||
Eni_unit *eup;
|
||||
{
|
||||
KBuffer *m;
|
||||
Eni_vcc *evp;
|
||||
struct vccb *vcp;
|
||||
u_long vcc;
|
||||
u_long DMA_Rdptr;
|
||||
u_long dma_wrp;
|
||||
u_long start, stop;
|
||||
int s;
|
||||
|
||||
s = splimp();
|
||||
/* Pop first buffer */
|
||||
_IF_DEQUEUE ( &eup->eu_rxqueue, m );
|
||||
while ( m ) {
|
||||
u_long *up;
|
||||
u_long pdulen;
|
||||
|
||||
KB_DATASTART ( m, up, u_long * );
|
||||
|
||||
/*
|
||||
* Grab the VCI number
|
||||
*/
|
||||
vcc = *up++;
|
||||
|
||||
/*
|
||||
* Check to see if we can process this buffer yet.
|
||||
*/
|
||||
/* Get current DMA_Rdptr */
|
||||
DMA_Rdptr = eup->eu_midway[MIDWAY_RX_RD];
|
||||
/* Boundaries for first buffer */
|
||||
dma_wrp = *up++;
|
||||
start = dma_wrp >> 16;
|
||||
stop = dma_wrp & 0xffff;
|
||||
/*
|
||||
* Start should not equal stop because that would
|
||||
* mean we tried inserting a NULL DMA list.
|
||||
*/
|
||||
if ( start > stop ) { /* We wrapped */
|
||||
if ( !(DMA_Rdptr >= stop && DMA_Rdptr < start) ) {
|
||||
_IF_PREPEND ( &eup->eu_rxqueue, m );
|
||||
goto finish;
|
||||
}
|
||||
} else {
|
||||
if ( DMA_Rdptr < stop && DMA_Rdptr >= start ) {
|
||||
_IF_PREPEND ( &eup->eu_rxqueue, m );
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Adapter is finished with this buffer, we can
|
||||
* continue processing it now.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Locate incoming VCC for this PDU
|
||||
*/
|
||||
evp = (Eni_vcc *) atm_dev_vcc_find ( (Cmn_unit *)eup,
|
||||
0, vcc, VCC_IN );
|
||||
|
||||
if ( evp == NULL ) {
|
||||
eup->eu_stats.eni_st_drv.drv_rv_novcc++;
|
||||
KB_FREEALL ( m );
|
||||
goto next_buffer;
|
||||
}
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if ( eni_pdu_print )
|
||||
atm_dev_pdu_print ( (Cmn_unit *)eup, (Cmn_vcc *)evp, m,
|
||||
"eni_stack_drain" );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Grab theoretical PDU length
|
||||
*/
|
||||
pdulen = *up++;
|
||||
|
||||
/*
|
||||
* Quick, count the PDU
|
||||
*/
|
||||
eup->eu_pif.pif_ipdus++;
|
||||
eup->eu_pif.pif_ibytes += pdulen;
|
||||
if ( evp ) {
|
||||
vcp = evp->ev_connvc->cvc_vcc;
|
||||
if ( vcp ) {
|
||||
vcp->vc_ipdus++;
|
||||
vcp->vc_ibytes += pdulen;
|
||||
if ( vcp->vc_nif ) {
|
||||
vcp->vc_nif->nif_ibytes += pdulen;
|
||||
vcp->vc_nif->nif_if.if_ipackets++;
|
||||
#if (defined(BSD) && (BSD >= 199103))
|
||||
vcp->vc_nif->nif_if.if_ibytes += pdulen;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance DMA write allowable pointer
|
||||
*/
|
||||
eup->eu_rxdmawr = stop;
|
||||
|
||||
/*
|
||||
* Get packet PDU length
|
||||
*/
|
||||
KB_PLENGET ( m, pdulen );
|
||||
|
||||
/*
|
||||
* Only try queueing this if there is data
|
||||
* to be handed up to the next layer. Errors
|
||||
* such as CRC and VC trashing will get us this
|
||||
* far to advance pointers, etc., but the PDU
|
||||
* length will be zero.
|
||||
*/
|
||||
if ( pdulen ) {
|
||||
/*
|
||||
* We saved three words back in eni_do_service()
|
||||
* to use for callback. Since the core only
|
||||
* expects two words, skip over the first one.
|
||||
* Then, reset up pointer to start of buffer data
|
||||
* area and write the callback info.
|
||||
*/
|
||||
KB_HEADADJ ( m, -sizeof(u_long) );
|
||||
KB_DATASTART ( m, up, u_long * );
|
||||
*((int *)up) = (int)eni_recv_stack;
|
||||
up++;
|
||||
*((int *)up) = (int)(intptr_t)evp;
|
||||
/*
|
||||
* Schedule callback
|
||||
*/
|
||||
if (! netisr_queue(NETISR_ATM, m)) {
|
||||
eup->eu_stats.eni_st_drv.drv_rv_intrq++;
|
||||
eup->eu_pif.pif_ierrors++;
|
||||
#ifdef DO_LOG
|
||||
log ( LOG_ERR,
|
||||
"eni_receive_drain: ATM_INTRQ is full. Unable to pass up stack.\n" );
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Free zero-length buffer
|
||||
*/
|
||||
KB_FREEALL(m);
|
||||
}
|
||||
|
||||
next_buffer:
|
||||
/*
|
||||
* Look for next buffer
|
||||
*/
|
||||
_IF_DEQUEUE ( &eup->eu_rxqueue, m );
|
||||
}
|
||||
finish:
|
||||
(void) splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass incoming PDU up Stack
|
||||
*
|
||||
* This function is called via the core ATM interrupt queue callback
|
||||
* set in eni_recv_drain(). It will pass the supplied incoming
|
||||
* PDU up the incoming VCC's stack.
|
||||
*
|
||||
* Arguments:
|
||||
* tok token to identify stack instantiation
|
||||
* m pointer to incoming PDU buffer chain
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*/
|
||||
static void
|
||||
eni_recv_stack ( tok, m )
|
||||
void *tok;
|
||||
KBuffer *m;
|
||||
{
|
||||
Eni_vcc *evp = (Eni_vcc *)tok;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* This should never happen now but if it does and we don't stop it,
|
||||
* we end up panic'ing in netatm when trying to pull a function
|
||||
* pointer and token value out of a buffer with address zero.
|
||||
*/
|
||||
if ( !m ) {
|
||||
#ifdef DO_LOG
|
||||
log ( LOG_ERR,
|
||||
"eni_recv_stack: NULL buffer, tok = %p\n", tok );
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the data up the stack
|
||||
*/
|
||||
STACK_CALL ( CPCS_UNITDATA_SIG, evp->ev_upper,
|
||||
(void *)evp->ev_toku, evp->ev_connvc, (intptr_t)m, 0, err );
|
||||
if ( err ) {
|
||||
KB_FREEALL ( m );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
* @(#) $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
* -----------------------------
|
||||
*
|
||||
* Defines for statistics
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ENI_ENI_STATS_H
|
||||
#define _ENI_ENI_STATS_H
|
||||
|
||||
struct eni_stats_oc3 {
|
||||
u_long oc3_sect_bip8; /* Section 8-bit intrlv parity errors */
|
||||
u_long oc3_path_bip8; /* Path 8-bit intrlv parity errors */
|
||||
u_long oc3_line_bip24; /* Line 24-bit intrlv parity errors */
|
||||
u_long oc3_line_febe; /* Line far-end block errors */
|
||||
u_long oc3_path_febe; /* Path far-end block errors */
|
||||
u_long oc3_hec_corr; /* Correctable HEC errors */
|
||||
u_long oc3_hec_uncorr; /* Uncorrectable HEC errors */
|
||||
u_long oc3_pad; /* Pad to quad-word boundary */
|
||||
};
|
||||
typedef struct eni_stats_oc3 Eni_Stats_oc3;
|
||||
|
||||
struct eni_stats_atm {
|
||||
u_long atm_xmit; /* Cells transmitted */
|
||||
u_long atm_rcvd; /* Cells received */
|
||||
u_long atm_pad[2]; /* Pad to quad-word boundary */
|
||||
};
|
||||
typedef struct eni_stats_atm Eni_Stats_atm;
|
||||
|
||||
struct eni_stats_aal0 {
|
||||
u_long aal0_xmit; /* Cells transmitted */
|
||||
u_long aal0_rcvd; /* Cells received */
|
||||
u_long aal0_drops; /* Cells dropped */
|
||||
u_long aal0_pad; /* Pad to quad-word boundary */
|
||||
};
|
||||
typedef struct eni_stats_aal0 Eni_Stats_aal0;
|
||||
|
||||
struct eni_stats_aal5 {
|
||||
u_long aal5_xmit; /* Cells transmitted */
|
||||
u_long aal5_rcvd; /* Cells received */
|
||||
u_long aal5_crc_len; /* Cells with CRC/length errors */
|
||||
u_long aal5_drops; /* Cell drops */
|
||||
u_long aal5_pdu_xmit; /* CS PDUs transmitted */
|
||||
u_long aal5_pdu_rcvd; /* CS PDUs received */
|
||||
u_long aal5_pdu_crc; /* CS PDUs with CRC errors */
|
||||
u_long aal5_pdu_errs; /* CS layer protocol errors */
|
||||
u_long aal5_pdu_drops; /* CS PDUs dropped */
|
||||
u_long aal5_pad[3]; /* Pad to quad-word boundary */
|
||||
};
|
||||
typedef struct eni_stats_aal5 Eni_Stats_aal5;
|
||||
|
||||
struct eni_stats_driver {
|
||||
/*
|
||||
* Adapter memory allocator stats
|
||||
*/
|
||||
u_long drv_mm_toobig; /* Size larger then adapter supports */
|
||||
u_long drv_mm_nodesc; /* No memory area descriptor avail */
|
||||
u_long drv_mm_nobuf; /* No memory buffer available */
|
||||
u_long drv_mm_notuse; /* Calling free() on free buffer */
|
||||
u_long drv_mm_notfnd; /* Couldn't find descr for free() */
|
||||
|
||||
/*
|
||||
* VCM sats
|
||||
*/
|
||||
u_long drv_vc_maxpdu; /* Requested PDU size too large */
|
||||
u_long drv_vc_badrng; /* VPI and/or VCI too large */
|
||||
|
||||
/*
|
||||
* Receive stats
|
||||
*/
|
||||
u_long drv_rv_norsc; /* No buffer for resource pointers */
|
||||
u_long drv_rv_nobufs; /* No buffers for PDU */
|
||||
u_long drv_rv_nodma; /* No room in RXDMA list */
|
||||
u_long drv_rv_rxq; /* No room in local rxqueue */
|
||||
u_long drv_rv_novcc; /* Draining PDU on closed VCC */
|
||||
u_long drv_rv_intrq; /* No room in atm_intrq */
|
||||
u_long drv_rv_null; /* Trying to pass null PDU up stack */
|
||||
u_long drv_rv_segdma; /* No DMA address */
|
||||
|
||||
/*
|
||||
* Transmit stats
|
||||
*/
|
||||
u_long drv_xm_segdma; /* No DMA address */
|
||||
u_long drv_xm_segnoal; /* Non-aligned segment */
|
||||
u_long drv_xm_seglen; /* Padded length segment */
|
||||
u_long drv_xm_maxpdu; /* Too many segments - dropped */
|
||||
u_long drv_xm_nobuf; /* No space in TX buffer - dropped */
|
||||
u_long drv_xm_norsc; /* No buffers for resource pointers */
|
||||
u_long drv_xm_nodma; /* No space in TXDMA list */
|
||||
u_long drv_xm_dmaovfl; /* DMA overflow */
|
||||
|
||||
};
|
||||
typedef struct eni_stats_driver Eni_Stats_drv;
|
||||
|
||||
struct eni_stats {
|
||||
Eni_Stats_oc3 eni_st_oc3; /* OC3 layer stats */
|
||||
Eni_Stats_atm eni_st_atm; /* ATM layer stats */
|
||||
Eni_Stats_aal0 eni_st_aal0; /* AAL0 layer stats */
|
||||
Eni_Stats_aal5 eni_st_aal5; /* AAL5 layer stats */
|
||||
Eni_Stats_drv eni_st_drv; /* Driver stats */
|
||||
};
|
||||
typedef struct eni_stats Eni_stats;
|
||||
|
||||
#endif /* _ENI_ENI_STATS_H */
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
* @(#) $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
* -----------------------------
|
||||
*
|
||||
* Defines for SUNI chip
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ENI_ENI_SUNI_H
|
||||
#define _ENI_ENI_SUNI_H
|
||||
|
||||
/*
|
||||
* Interrupt bits in SUNI Master Interrupt Status Reg
|
||||
*/
|
||||
#define SUNI_RSOPI 0x01
|
||||
#define SUNI_RLOPI 0x02
|
||||
#define SUNI_RPOPI 0x04
|
||||
#define SUNI_RACPI 0x08
|
||||
#define SUNI_TACPI 0x10
|
||||
#define SUNI_RDOOLI 0x20
|
||||
#define SUNI_LCDI 0x40
|
||||
#define SUNI_TROOLI 0x80
|
||||
|
||||
/*
|
||||
* SUNI Register numbers
|
||||
*/
|
||||
#define SUNI_MASTER_REG 0x00 /* Master reset and ID */
|
||||
#define SUNI_IS_REG 0x02 /* Master Interrupt Status */
|
||||
#define SUNI_CLOCK_REG 0x06 /* Clock synth/control/status */
|
||||
#define SUNI_RSOP_REG 0x10 /* RSOP control/Interrupt Status */
|
||||
#define SUNI_SECT_BIP_REG 0x12
|
||||
#define SUNI_RLOP_REG 0x18 /* RLOP control/Interrupt Status */
|
||||
#define SUNI_LINE_BIP_REG 0x1A
|
||||
#define SUNI_LINE_FEBE_REG 0x1D
|
||||
#define SUNI_RPOP_IS_REG 0x31 /* RPOP Interrupt Status */
|
||||
#define SUNI_PATH_BIP_REG 0x38
|
||||
#define SUNI_PATH_FEBE_REG 0x3A
|
||||
#define SUNI_RACP_REG 0x50 /* RACP control/status */
|
||||
#define SUNI_HECS_REG 0x54
|
||||
#define SUNI_UHECS_REG 0x55
|
||||
#define SUNI_TACP_REG 0x60 /* TACP control/status */
|
||||
|
||||
/*
|
||||
* Delay timer to allow SUNI statistic registers to load
|
||||
*/
|
||||
#define SUNI_DELAY 10
|
||||
|
||||
#endif /* _ENI_ENI_SUNI_H */
|
||||
|
@ -1,846 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
* -----------------------------
|
||||
*
|
||||
* Transmit queue management and PDU output processing
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netatm/port.h>
|
||||
#include <netatm/queue.h>
|
||||
#include <netatm/atm.h>
|
||||
#include <netatm/atm_sys.h>
|
||||
#include <netatm/atm_sap.h>
|
||||
#include <netatm/atm_cm.h>
|
||||
#include <netatm/atm_if.h>
|
||||
#include <netatm/atm_vc.h>
|
||||
#include <netatm/atm_stack.h>
|
||||
#include <netatm/atm_pcb.h>
|
||||
#include <netatm/atm_var.h>
|
||||
|
||||
#include <dev/hea/eni_stats.h>
|
||||
#include <dev/hea/eni.h>
|
||||
#include <dev/hea/eni_var.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("@(#) $FreeBSD$");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make a variable which controls printing of PDUs
|
||||
* as they travel through the driver.
|
||||
*/
|
||||
#ifdef DIAGNOSTIC
|
||||
int eni_pdu_print = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some PCI chipsets do not handle one or more of the 8WORD or
|
||||
* 4WORD DMA transfer sizes. Default to using only 1WORD transfer
|
||||
* sizes unless the user wishes to experiment.
|
||||
*
|
||||
* Make sure that these have to be changed here in this module.
|
||||
*/
|
||||
#define DMA_USE_8WORD
|
||||
#define DMA_USE_4WORD
|
||||
|
||||
/*
|
||||
* Create a DMA list entry
|
||||
*
|
||||
* DMA entries consist of a control word and a physical address.
|
||||
* Control words are comprised of a DMA type, a count of type transfers
|
||||
* to occur, and a variable which for TX requests is the TX channel
|
||||
* number and for RX requests is the VCC number.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to unit structure
|
||||
* rx set if receiving
|
||||
* dma_list pointer to DMA list structure
|
||||
* list_size length of DMA list structure
|
||||
* idx pointer to current list entry
|
||||
* val TX channel or RX vcc
|
||||
* addr virtual DMA address of data buffer
|
||||
* size size in bytes of DMA request to be built
|
||||
*
|
||||
* Returns:
|
||||
* dma_list updated with new entries
|
||||
* idx points to next list entry
|
||||
* -1 no room in DMA list structure or DMA_GET_ADDR failed
|
||||
*/
|
||||
int
|
||||
eni_set_dma ( eup, rx, dma_list, list_size, idx, val, addr, size )
|
||||
Eni_unit *eup;
|
||||
int rx;
|
||||
u_long *dma_list;
|
||||
int list_size;
|
||||
long *idx;
|
||||
int val;
|
||||
u_long addr;
|
||||
int size;
|
||||
{
|
||||
int dsize; /* Size of current DMA request */
|
||||
|
||||
/*
|
||||
* Round up to multiple of word and convert to number
|
||||
* of words rather then number of bytes.
|
||||
*/
|
||||
size = ( size + 3 ) >> 2;
|
||||
|
||||
#ifdef DMA_USE_8WORD
|
||||
/*
|
||||
* Check for room in DMA list - we need two entires
|
||||
*/
|
||||
if ( *idx + 2 >= list_size )
|
||||
return ( -1 );
|
||||
|
||||
/*
|
||||
* Here is the big win. Move as much data possible with
|
||||
* n 8WORD DMAs.
|
||||
*/
|
||||
/*
|
||||
* Check if we can do one or more 8WORD DMAs
|
||||
*/
|
||||
dsize = size & ~7;
|
||||
if ( dsize ) {
|
||||
dma_list[(*idx)++] = ( dsize >> 3 ) << DMA_COUNT_SHIFT |
|
||||
val << DMA_VCC_SHIFT | DMA_8WORD;
|
||||
dma_list[*idx] = (u_long)vtophys(addr);
|
||||
if ( dma_list[*idx] == 0 ) {
|
||||
if ( rx )
|
||||
eup->eu_stats.eni_st_drv.drv_rv_segdma++;
|
||||
else
|
||||
eup->eu_stats.eni_st_drv.drv_xm_segdma++;
|
||||
return ( -1 ); /* DMA_GET_ADDR failed */
|
||||
} else
|
||||
(*idx)++; /* increment index */
|
||||
/*
|
||||
* Adjust addr and size
|
||||
*/
|
||||
addr += dsize << 2;
|
||||
size &= 7;
|
||||
}
|
||||
#endif /* DMA_USE_8WORD */
|
||||
|
||||
#ifdef DMA_USE_4WORD
|
||||
/*
|
||||
* Check for room in DMA list - we need two entries
|
||||
*/
|
||||
if ( *idx + 2 >= list_size )
|
||||
return ( -1 );
|
||||
|
||||
/*
|
||||
* Kindof a tossup from this point on. Since we hacked as many
|
||||
* 8WORD DMAs off as possible, we are left with 0-7 words
|
||||
* of remaining data. We could do upto one 4WORD with 0-3
|
||||
* words left, or upto three 2WORDS with 0-1 words left,
|
||||
* or upto seven WORDS with nothing left. Someday we should
|
||||
* experiment with performance and see if any particular
|
||||
* combination is a better win then some other...
|
||||
*/
|
||||
/*
|
||||
* Check if we can do one or more 4WORD DMAs
|
||||
*/
|
||||
dsize = size & ~3;
|
||||
if ( dsize ) {
|
||||
dma_list[(*idx)++] = ( dsize >> 2 ) << DMA_COUNT_SHIFT |
|
||||
val << DMA_VCC_SHIFT | DMA_4WORD;
|
||||
dma_list[*idx] = (u_long)vtophys(addr);
|
||||
if ( dma_list[*idx] == 0 ) {
|
||||
if ( rx )
|
||||
eup->eu_stats.eni_st_drv.drv_rv_segdma++;
|
||||
else
|
||||
eup->eu_stats.eni_st_drv.drv_xm_segdma++;
|
||||
return ( -1 ); /* DMA_GET_ADDR failed */
|
||||
} else
|
||||
(*idx)++; /* increment index */
|
||||
/*
|
||||
* Adjust addr and size
|
||||
*/
|
||||
addr += dsize << 2;
|
||||
size &= 3;
|
||||
}
|
||||
#endif /* DMA_USE_4WORD */
|
||||
|
||||
/*
|
||||
* Check for room in DMA list - we need two entries
|
||||
*/
|
||||
if ( *idx + 2 >= list_size )
|
||||
return ( -1 );
|
||||
|
||||
/*
|
||||
* Hard to know if one 2WORD and 0/1 WORD DMA would be better
|
||||
* then 2/3 WORD DMAs. For now, skip 2WORD DMAs in favor of
|
||||
* WORD DMAs.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Finish remaining size a 1WORD DMAs
|
||||
*/
|
||||
if ( size ) {
|
||||
dma_list[(*idx)++] = ( size ) << DMA_COUNT_SHIFT |
|
||||
val << DMA_VCC_SHIFT | DMA_WORD;
|
||||
dma_list[*idx] = (u_long)vtophys(addr);
|
||||
if ( dma_list[*idx] == 0 ) {
|
||||
if ( rx )
|
||||
eup->eu_stats.eni_st_drv.drv_rv_segdma++;
|
||||
else
|
||||
eup->eu_stats.eni_st_drv.drv_xm_segdma++;
|
||||
return ( -1 ); /* DMA_GET_ADDR failed */
|
||||
} else
|
||||
(*idx)++; /* increment index */
|
||||
}
|
||||
|
||||
/*
|
||||
* Inserted descriptor okay
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Drain Transmit queue
|
||||
*
|
||||
* As PDUs are given to the adapter to be transmitted, we
|
||||
* place them into a private ifqueue so that we can free
|
||||
* any resources AFTER we know they've been successfully DMAed.
|
||||
* As part of the output processing, we record the PDUs start
|
||||
* and stop entries in the DMA list, and prevent wrapping. When
|
||||
* we pull the top element off, we simply check that the current
|
||||
* DMA location is outside this PDU and if so, it's okay to free
|
||||
* things.
|
||||
*
|
||||
* PDUs are always in ascending order in the queue.
|
||||
*
|
||||
* Arguments:
|
||||
* eup pointer to device unit structure
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
eni_xmit_drain ( eup )
|
||||
Eni_unit *eup;
|
||||
{
|
||||
KBuffer *m;
|
||||
Eni_vcc *evp;
|
||||
struct vccb *vcp;
|
||||
u_long pdulen;
|
||||
u_long start, stop;
|
||||
u_long dmap;
|
||||
int s = splimp();
|
||||
|
||||
/*
|
||||
* Pull the top element (PDU) off
|
||||
*/
|
||||
_IF_DEQUEUE ( &eup->eu_txqueue, m );
|
||||
/*
|
||||
* As long as there are valid elements
|
||||
*/
|
||||
while ( m ) {
|
||||
u_long *up;
|
||||
|
||||
/*
|
||||
* Find start of buffer
|
||||
*/
|
||||
KB_DATASTART ( m, up, u_long * );
|
||||
|
||||
/*
|
||||
* First word is the VCC for this PDU
|
||||
*/
|
||||
/*
|
||||
* NOTE: There is a potential problem here in that
|
||||
* if the VCC is closed after this buffer was transmitted
|
||||
* but before we get here, that while evp is non-null,
|
||||
* it will not reference a valid vccb. We need to either
|
||||
* delay closing the VCC until all references are removed
|
||||
* from the drain stacks, actually go through the drain
|
||||
* stacks and remove any references, or find someway of
|
||||
* indicating that this vccb is nolonger usable.
|
||||
*/
|
||||
evp = (Eni_vcc *)*up++;
|
||||
/*
|
||||
* Second word is the start and stop DMA pointers
|
||||
*/
|
||||
start = *up >> 16;
|
||||
stop = *up++ & 0xffff;
|
||||
/*
|
||||
* Find out where the TX engine is at
|
||||
*/
|
||||
dmap = eup->eu_midway[MIDWAY_TX_RD];
|
||||
/*
|
||||
* Check to see if TX engine has processed this
|
||||
* PDU yet. Remember that everything is circular
|
||||
* and that stop might be less than start numerically.
|
||||
*/
|
||||
if ( start > stop ) {
|
||||
if ( !(dmap >= stop && dmap < start) ) {
|
||||
/*
|
||||
* Haven't finished this PDU yet - replace
|
||||
* it as the head of list.
|
||||
*/
|
||||
_IF_PREPEND ( &eup->eu_txqueue, m );
|
||||
/*
|
||||
* If this one isn't done, none of the others
|
||||
* are either.
|
||||
*/
|
||||
(void) splx(s);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ( dmap < stop && dmap >= start ) {
|
||||
/*
|
||||
* Haven't finished this PDU yet - replace
|
||||
* it as the head of list.
|
||||
*/
|
||||
_IF_PREPEND ( &eup->eu_txqueue, m );
|
||||
/*
|
||||
* If this one isn't done, none of the others
|
||||
* are either.
|
||||
*/
|
||||
(void) splx(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the PDU stats for this interface
|
||||
*/
|
||||
eup->eu_pif.pif_opdus++;
|
||||
/*
|
||||
* Third word is PDU length from eni_output().
|
||||
*/
|
||||
pdulen = *up++;
|
||||
eup->eu_txfirst = (eup->eu_txfirst + *up) &
|
||||
(eup->eu_txsize - 1);
|
||||
eup->eu_pif.pif_obytes += pdulen;
|
||||
|
||||
/*
|
||||
* Now lookup the VCC entry and counts the stats for
|
||||
* this VC.
|
||||
*/
|
||||
if ( evp ) {
|
||||
vcp = evp->ev_connvc->cvc_vcc;
|
||||
if ( vcp ) {
|
||||
vcp->vc_opdus++;
|
||||
vcp->vc_obytes += pdulen;
|
||||
/*
|
||||
* If we also have a network interface, count the PDU
|
||||
* there also.
|
||||
*/
|
||||
if ( vcp->vc_nif ) {
|
||||
vcp->vc_nif->nif_obytes += pdulen;
|
||||
vcp->vc_nif->nif_if.if_opackets++;
|
||||
#if (defined(BSD) && (BSD >= 199103))
|
||||
vcp->vc_nif->nif_if.if_obytes += pdulen;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Free the buffer chain
|
||||
*/
|
||||
KB_FREEALL ( m );
|
||||
|
||||
/*
|
||||
* Advance DMA write okay pointer
|
||||
*/
|
||||
eup->eu_txdmawr = stop;
|
||||
|
||||
/*
|
||||
* Look for next completed transmit PDU
|
||||
*/
|
||||
_IF_DEQUEUE ( &eup->eu_txqueue, m );
|
||||
}
|
||||
/*
|
||||
* We've drained the queue...
|
||||
*/
|
||||
(void) splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a PDU
|
||||
*
|
||||
* This function is called via the common driver code after receiving a
|
||||
* stack *_DATA* command. The common code has already validated most of
|
||||
* the request so we just need to check a few more ENI-specific details.
|
||||
* Then we just build a segmentation structure for the PDU and place the
|
||||
* address into the DMA_Transmit_queue.
|
||||
*
|
||||
* Arguments:
|
||||
* cup pointer to device common unit
|
||||
* cvp pointer to common VCC entry
|
||||
* m pointer to output PDU buffer chain head
|
||||
*
|
||||
* Returns:
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
eni_output ( cup, cvp, m )
|
||||
Cmn_unit *cup;
|
||||
Cmn_vcc *cvp;
|
||||
KBuffer *m;
|
||||
{
|
||||
Eni_unit *eup = (Eni_unit *)cup;
|
||||
Eni_vcc *evp = (Eni_vcc *)cvp;
|
||||
int s, s2;
|
||||
int pdulen = 0;
|
||||
u_long size;
|
||||
u_long buf_avail;
|
||||
u_long dma_rd, dma_wr;
|
||||
u_long dma[TEMP_DMA_SIZE];
|
||||
int aal5, i;
|
||||
long j;
|
||||
u_long dma_avail;
|
||||
u_long dma_start;
|
||||
Eni_mem tx_send;
|
||||
u_long *up;
|
||||
KBuffer *m0 = m, *m1, *mprev = NULL;
|
||||
caddr_t cp, bfr;
|
||||
u_int len, align;
|
||||
int compressed = 0;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if ( eni_pdu_print )
|
||||
atm_dev_pdu_print ( cup, cvp, m, "eni output" );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Re-entry point for after buffer compression (if needed)
|
||||
*/
|
||||
retry:
|
||||
|
||||
/*
|
||||
* We can avoid traversing the buffer list twice by building
|
||||
* the middle (minus header and trailer) dma list at the
|
||||
* same time we massage address and size alignments. Since
|
||||
* this list remains local until we determine we've enough
|
||||
* room, we're not going to trash anything by not checking
|
||||
* sizes, etc. yet. Skip first entry to be used later to skip
|
||||
* descriptor word.
|
||||
*/
|
||||
j = 2;
|
||||
/*
|
||||
* Do data positioning for address and length alignment
|
||||
*/
|
||||
while ( m ) {
|
||||
u_long buf_addr; /* For passing addr to eni_set_dma() */
|
||||
|
||||
/*
|
||||
* Get rid of any zero length buffers
|
||||
*/
|
||||
if ( KB_LEN ( m ) == 0 ) {
|
||||
if ( mprev ) {
|
||||
KB_UNLINK ( m, mprev, m1 );
|
||||
} else {
|
||||
KB_UNLINKHEAD ( m, m1 );
|
||||
m0 = m1;
|
||||
}
|
||||
m = m1;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Get start of data onto full-word alignment
|
||||
*/
|
||||
KB_DATASTART ( m, cp, caddr_t );
|
||||
if ((align = ((uintptr_t)cp) & (sizeof(u_long)-1)) != 0) {
|
||||
/*
|
||||
* Gotta slide the data up
|
||||
*/
|
||||
eup->eu_stats.eni_st_drv.drv_xm_segnoal++;
|
||||
bfr = cp - align;
|
||||
bcopy ( cp, bfr, KB_LEN ( m ) );
|
||||
KB_HEADMOVE ( m, -align );
|
||||
} else {
|
||||
/*
|
||||
* Data already aligned
|
||||
*/
|
||||
bfr = cp;
|
||||
}
|
||||
/*
|
||||
* Now work on getting the data length correct
|
||||
*/
|
||||
len = KB_LEN ( m );
|
||||
while ( ( align = ( len & (sizeof(u_long)-1))) &&
|
||||
(m1 = KB_NEXT ( m ) ) ) {
|
||||
|
||||
/*
|
||||
* Have to move some data from following buffer(s)
|
||||
* to word-fill this buffer
|
||||
*/
|
||||
u_int ncopy = MIN ( sizeof(u_long) - align,
|
||||
KB_LEN ( m1 ) );
|
||||
|
||||
if ( ncopy ) {
|
||||
/*
|
||||
* Move data to current buffer
|
||||
*/
|
||||
caddr_t dest;
|
||||
|
||||
eup->eu_stats.eni_st_drv.drv_xm_seglen++;
|
||||
KB_DATASTART ( m1, cp, caddr_t );
|
||||
dest = bfr + len;
|
||||
KB_HEADADJ ( m1, -ncopy );
|
||||
KB_TAILADJ ( m, ncopy );
|
||||
len += ncopy;
|
||||
while ( ncopy-- ) {
|
||||
*dest++ = *cp++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we've drained the buffer, free it
|
||||
*/
|
||||
if ( KB_LEN ( m1 ) == 0 ) {
|
||||
KBuffer *m2;
|
||||
|
||||
KB_UNLINK ( m1, m, m2 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Address and size are now aligned. Build dma list
|
||||
* using TX channel 0. Also, round length up to a word
|
||||
* size which should only effect the last buffer in the
|
||||
* chain. This works because the PDU length is maintained
|
||||
* separately and we're not really adjusting the buffer's
|
||||
* idea of its length.
|
||||
*/
|
||||
KB_DATASTART ( m, buf_addr, u_long );
|
||||
if ( eni_set_dma ( eup, 0, dma, TEMP_DMA_SIZE, &j, 0,
|
||||
buf_addr, KB_LEN ( m ) ) < 0 ) {
|
||||
/*
|
||||
* Failed to build DMA list. First, we'll try to
|
||||
* compress the buffer chain into a smaller number
|
||||
* of buffers. After compressing, we'll try to send
|
||||
* the new buffer chain. If we still fail, then
|
||||
* we'll drop the pdu.
|
||||
*/
|
||||
if ( compressed ) {
|
||||
#ifdef DO_LOG
|
||||
log ( LOG_ERR,
|
||||
"eni_output: eni_set_dma failed\n" );
|
||||
#endif
|
||||
eup->eu_pif.pif_oerrors++;
|
||||
KB_FREEALL ( m0 );
|
||||
return;
|
||||
}
|
||||
|
||||
eup->eu_stats.eni_st_drv.drv_xm_maxpdu++;
|
||||
|
||||
m = atm_dev_compress ( m0 );
|
||||
if ( m == NULL ) {
|
||||
#ifdef DO_LOG
|
||||
log ( LOG_ERR,
|
||||
"eni_output: atm_dev_compress() failed\n" );
|
||||
#endif
|
||||
eup->eu_pif.pif_oerrors++;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset to new head of buffer chain
|
||||
*/
|
||||
m0 = m;
|
||||
|
||||
/*
|
||||
* Indicate we've been through here
|
||||
*/
|
||||
compressed = 1;
|
||||
|
||||
/*
|
||||
* Retry to build the DMA descriptors for the newly
|
||||
* compressed buffer chain
|
||||
*/
|
||||
goto retry;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Now count the length
|
||||
*/
|
||||
pdulen += KB_LEN ( m );
|
||||
|
||||
/*
|
||||
* Bump counters and get ready for next buffer
|
||||
*/
|
||||
mprev = m;
|
||||
m = KB_NEXT ( m );
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a buffer to use in a private queue so that we can
|
||||
* reclaim resources after the DMA has finished.
|
||||
*/
|
||||
KB_ALLOC ( m, ENI_SMALL_BSIZE, KB_F_NOWAIT, KB_T_DATA );
|
||||
if ( m ) {
|
||||
/*
|
||||
* Link the PDU onto our new head
|
||||
*/
|
||||
KB_NEXT ( m ) = m0;
|
||||
} else {
|
||||
/*
|
||||
* Drop this PDU and let the sender try again.
|
||||
*/
|
||||
eup->eu_stats.eni_st_drv.drv_xm_norsc++;
|
||||
#ifdef DO_LOG
|
||||
log(LOG_ERR, "eni_output: Unable to allocate drain buffer.\n");
|
||||
#endif
|
||||
eup->eu_pif.pif_oerrors++;
|
||||
KB_FREEALL ( m0 );
|
||||
return;
|
||||
}
|
||||
|
||||
s = splnet();
|
||||
|
||||
/*
|
||||
* Calculate size of buffer necessary to store PDU. If this
|
||||
* is an AAL5 PDU, we'll need to know where to stuff the length
|
||||
* value in the trailer.
|
||||
*/
|
||||
/*
|
||||
* AAL5 PDUs need an extra two words for control/length and
|
||||
* CRC. Check for AAL5 and add requirements here.
|
||||
*/
|
||||
if ((aal5 = (evp->ev_connvc->cvc_attr.aal.type == ATM_AAL5)) != 0)
|
||||
size = pdulen + 2 * sizeof(long);
|
||||
else
|
||||
size = pdulen;
|
||||
/*
|
||||
* Pad to next complete cell boundary
|
||||
*/
|
||||
size += (BYTES_PER_CELL - 1);
|
||||
size -= size % BYTES_PER_CELL;
|
||||
/*
|
||||
* Convert size to words and add 2 words overhead for every
|
||||
* PDU (descriptor and cell header).
|
||||
*/
|
||||
size = (size >> 2) + 2;
|
||||
|
||||
/*
|
||||
* First, check to see if there's enough buffer space to
|
||||
* store the PDU. We do this by checking to see if the size
|
||||
* required crosses the eu_txfirst pointer. However, we don't
|
||||
* want to exactly fill the buffer, because we won't be able to
|
||||
* distinguish between a full and empty buffer.
|
||||
*/
|
||||
if ( eup->eu_txpos == eup->eu_txfirst )
|
||||
buf_avail = eup->eu_txsize;
|
||||
else
|
||||
if ( eup->eu_txpos > eup->eu_txfirst )
|
||||
buf_avail = eup->eu_txsize - ( eup->eu_txpos - eup->eu_txfirst );
|
||||
else
|
||||
buf_avail = eup->eu_txfirst - eup->eu_txpos;
|
||||
|
||||
if ( size >= buf_avail )
|
||||
{
|
||||
/*
|
||||
* No buffer space in the adapter to store this PDU.
|
||||
* Drop PDU and return.
|
||||
*/
|
||||
eup->eu_stats.eni_st_drv.drv_xm_nobuf++;
|
||||
#ifdef DO_LOG
|
||||
log ( LOG_ERR,
|
||||
"eni_output: not enough room in buffer\n" );
|
||||
#endif
|
||||
eup->eu_pif.pif_oerrors++;
|
||||
KB_FREEALL ( m );
|
||||
(void) splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out where current DMA pointers are at
|
||||
*/
|
||||
dma_start = dma_wr = eup->eu_midway[MIDWAY_TX_WR];
|
||||
dma_rd = eup->eu_midway[MIDWAY_TX_RD];
|
||||
|
||||
/*
|
||||
* Figure out how much DMA room we have available
|
||||
*/
|
||||
if ( dma_rd == dma_wr ) { /* Queue is empty */
|
||||
dma_avail = DMA_LIST_SIZE;
|
||||
} else {
|
||||
dma_avail = ( dma_rd + DMA_LIST_SIZE - dma_wr )
|
||||
& ( DMA_LIST_SIZE - 1 );
|
||||
}
|
||||
/*
|
||||
* Check to see if we can describe this PDU or if we're:
|
||||
* out of room, will wrap past recovered resources.
|
||||
*/
|
||||
if ( dma_avail < (j / 2 + 4) ||
|
||||
( dma_wr + (j / 2 + 4) > eup->eu_txdmawr + DMA_LIST_SIZE ) ) {
|
||||
/*
|
||||
* No space to insert DMA list into queue. Drop this PDU.
|
||||
*/
|
||||
eup->eu_stats.eni_st_drv.drv_xm_nodma++;
|
||||
#ifdef DO_LOG
|
||||
log ( LOG_ERR,
|
||||
"eni_output: not enough room in DMA queue\n" );
|
||||
#endif
|
||||
eup->eu_pif.pif_oerrors++;
|
||||
KB_FREEALL( m );
|
||||
(void) splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create DMA descriptor for header. There is a descriptor word
|
||||
* and also a cell header word which we'll set manually.
|
||||
*/
|
||||
dma[0] = (((int)(eup->eu_txpos + 2) & (eup->eu_txsize-1)) <<
|
||||
DMA_COUNT_SHIFT) | DMA_JK;
|
||||
dma[1] = 0;
|
||||
|
||||
/*
|
||||
* JK for AAL5 trailer. Set END bit as well.
|
||||
*/
|
||||
if ( aal5 ) {
|
||||
dma[j++] = (((int)(eup->eu_txpos+size) & (eup->eu_txsize-1)) <<
|
||||
DMA_COUNT_SHIFT) | DMA_END_BIT | DMA_JK;
|
||||
dma[j++] = 0;
|
||||
} else {
|
||||
dma[j-2] |= DMA_END_BIT; /* Backup and set END bit */
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out where in adapter memory this TX buffer starts.
|
||||
*/
|
||||
tx_send = (Eni_mem)
|
||||
((((int)eup->eu_midway[MIDWAY_TXPLACE] & 0x7ff) << ENI_LOC_PREDIV) +
|
||||
(intptr_t)eup->eu_ram);
|
||||
|
||||
/*
|
||||
* Set descriptor word
|
||||
*/
|
||||
tx_send[eup->eu_txpos] =
|
||||
(MIDWAY_UNQ_ID << 28) | (aal5 ? 1 << 27 : 0)
|
||||
| (size / WORDS_PER_CELL);
|
||||
/*
|
||||
* Set cell header
|
||||
*/
|
||||
tx_send[(eup->eu_txpos+1)&(eup->eu_txsize-1)] =
|
||||
evp->ev_connvc->cvc_vcc->vc_vci << 4;
|
||||
|
||||
/*
|
||||
* We've got all our resources, count the stats
|
||||
*/
|
||||
if ( aal5 ) {
|
||||
/*
|
||||
* If this is an AAL5 PDU, we need to set the length
|
||||
*/
|
||||
tx_send[(eup->eu_txpos+size-2) &
|
||||
(eup->eu_txsize-1)] = pdulen;
|
||||
/*
|
||||
* Increment AAL5 stats
|
||||
*/
|
||||
eup->eu_stats.eni_st_aal5.aal5_pdu_xmit++;
|
||||
eup->eu_stats.eni_st_aal5.aal5_xmit += (size - 2) / WORDS_PER_CELL;
|
||||
} else {
|
||||
/*
|
||||
* Increment AAL0 stats
|
||||
*/
|
||||
eup->eu_stats.eni_st_aal0.aal0_xmit += (size - 2) / WORDS_PER_CELL;
|
||||
}
|
||||
/*
|
||||
* Increment ATM stats
|
||||
*/
|
||||
eup->eu_stats.eni_st_atm.atm_xmit += (size - 2) / WORDS_PER_CELL;
|
||||
|
||||
/*
|
||||
* Store the DMA list
|
||||
*/
|
||||
j = j >> 1;
|
||||
for ( i = 0; i < j; i++ ) {
|
||||
eup->eu_txdma[dma_wr*2] = dma[i*2];
|
||||
eup->eu_txdma[dma_wr*2+1] = dma[i*2+1];
|
||||
dma_wr = (dma_wr+1) & (DMA_LIST_SIZE-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build drain buffer
|
||||
*
|
||||
* We toss four words in to help keep track of this
|
||||
* PDU. The first is a pointer to the VC control block
|
||||
* so we can find which VCI this went out on, the second
|
||||
* is the start and stop pointers for the DMA list which
|
||||
* describes this PDU, the third is the PDU length
|
||||
* since we'll want to know that for stats gathering,
|
||||
* and the fourth is the number of DMA words.
|
||||
*/
|
||||
KB_DATASTART ( m, up, u_long * );
|
||||
*up++ = (u_long)cvp;
|
||||
*up++ = dma_start << 16 | dma_wr;
|
||||
*up++ = pdulen;
|
||||
*up = size;
|
||||
|
||||
/*
|
||||
* Set length of our buffer
|
||||
*/
|
||||
KB_LEN ( m ) = 4 * sizeof ( long );
|
||||
|
||||
/*
|
||||
* Place buffers onto transmit queue for draining
|
||||
*/
|
||||
s2 = splimp();
|
||||
_IF_ENQUEUE ( &eup->eu_txqueue, m );
|
||||
(void) splx(s2);
|
||||
|
||||
/*
|
||||
* Update next word to be stored
|
||||
*/
|
||||
eup->eu_txpos = ((eup->eu_txpos + size) & (eup->eu_txsize - 1));
|
||||
|
||||
/*
|
||||
* Update MIDWAY_TX_WR pointer
|
||||
*/
|
||||
eup->eu_midway[MIDWAY_TX_WR] = dma_wr;
|
||||
|
||||
(void) splx ( s );
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
* @(#) $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
* -----------------------------
|
||||
*
|
||||
* Local driver include files and global declarations
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ENI_ENI_VAR_H
|
||||
#define _ENI_ENI_VAR_H
|
||||
|
||||
/*
|
||||
* Global function declarations
|
||||
*/
|
||||
/* eni_buffer.c */
|
||||
int eni_init_memory(Eni_unit *);
|
||||
caddr_t eni_allocate_buffer(Eni_unit *, u_long *);
|
||||
void eni_free_buffer(Eni_unit *, caddr_t);
|
||||
|
||||
/* eni_if.c */
|
||||
int eni_atm_ioctl(int, caddr_t, caddr_t);
|
||||
void eni_zero_stats(Eni_unit *);
|
||||
|
||||
/* eni_init.c */
|
||||
int eni_init(Eni_unit *);
|
||||
|
||||
/* eni_intr.c */
|
||||
#if defined(BSD) && BSD < 199506
|
||||
int eni_intr(void *);
|
||||
#else
|
||||
void eni_intr(void *);
|
||||
#endif
|
||||
|
||||
/* eni_receive.c */
|
||||
void eni_do_service(Eni_unit *);
|
||||
void eni_recv_drain(Eni_unit *);
|
||||
|
||||
/* eni_transmit.c */
|
||||
int eni_set_dma(Eni_unit *, int, u_long *, int, long *, int, u_long, int );
|
||||
void eni_output(Cmn_unit *, Cmn_vcc *, KBuffer *);
|
||||
void eni_xmit_drain(Eni_unit *);
|
||||
|
||||
/* eni_vcm.c */
|
||||
int eni_instvcc(Cmn_unit *, Cmn_vcc *);
|
||||
int eni_openvcc(Cmn_unit *, Cmn_vcc *);
|
||||
int eni_closevcc(Cmn_unit *, Cmn_vcc *);
|
||||
|
||||
/*
|
||||
* Global variable declarations
|
||||
*/
|
||||
extern Eni_unit *eni_units[];
|
||||
extern struct stack_defn *eni_services;
|
||||
extern uma_zone_t eni_nif_zone;
|
||||
extern uma_zone_t eni_vcc_zone;
|
||||
|
||||
#endif /* _ENI_ENI_VAR_H */
|
@ -1,295 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Efficient ENI Adapter Support
|
||||
* -----------------------------
|
||||
*
|
||||
* Virtual Channel Managment
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <netatm/port.h>
|
||||
#include <netatm/queue.h>
|
||||
#include <netatm/atm.h>
|
||||
#include <netatm/atm_sys.h>
|
||||
#include <netatm/atm_cm.h>
|
||||
#include <netatm/atm_if.h>
|
||||
#include <netatm/atm_vc.h>
|
||||
|
||||
#include <dev/hea/eni_stats.h>
|
||||
#include <dev/hea/eni.h>
|
||||
#include <dev/hea/eni_var.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("@(#) $FreeBSD$");
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* VCC Stack Instantiation
|
||||
*
|
||||
* This function is called via the common driver code during a device VCC
|
||||
* stack instantiation. The common code has already validated some of
|
||||
* the request so we just need to check a few more ENI-specific details.
|
||||
*
|
||||
* Called at splnet.
|
||||
*
|
||||
* Arguments:
|
||||
* cup pointer to device common unit
|
||||
* cvp pointer to common VCC entry
|
||||
*
|
||||
* Returns:
|
||||
* 0 instantiation successful
|
||||
* err instantiation failed - reason indicated
|
||||
*
|
||||
*/
|
||||
int
|
||||
eni_instvcc(cup, cvp)
|
||||
Cmn_unit *cup;
|
||||
Cmn_vcc *cvp;
|
||||
{
|
||||
Eni_unit *eup = (Eni_unit *)cup;
|
||||
Eni_vcc *evp = (Eni_vcc *)cvp;
|
||||
Atm_attributes *ap = &evp->ev_connvc->cvc_attr;
|
||||
|
||||
/*
|
||||
* Validate requested AAL
|
||||
*/
|
||||
switch (ap->aal.type) {
|
||||
|
||||
case ATM_AAL0:
|
||||
break;
|
||||
|
||||
case ATM_AAL5:
|
||||
if ((ap->aal.v.aal5.forward_max_SDU_size > ENI_IFF_MTU) ||
|
||||
(ap->aal.v.aal5.backward_max_SDU_size > ENI_IFF_MTU)) {
|
||||
eup->eu_stats.eni_st_drv.drv_vc_maxpdu++;
|
||||
return (EINVAL);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Open a VCC
|
||||
*
|
||||
* This function is called via the common driver code after receiving a
|
||||
* stack *_INIT* command. The common code has already validated most of
|
||||
* the request so we just need to check a few more ENI-specific details.
|
||||
*
|
||||
* Called at splimp.
|
||||
*
|
||||
* Arguments:
|
||||
* cup pointer to device common unit
|
||||
* cvp pointer to common VCC entry
|
||||
*
|
||||
* Returns:
|
||||
* 0 open sucessful
|
||||
* err open failed
|
||||
*
|
||||
*/
|
||||
int
|
||||
eni_openvcc ( cup, cvp )
|
||||
Cmn_unit *cup;
|
||||
Cmn_vcc *cvp;
|
||||
{
|
||||
Eni_unit *eup = (Eni_unit *)cup;
|
||||
Eni_vcc *evp = (Eni_vcc *)cvp;
|
||||
struct vccb *vcp = evp->ev_connvc->cvc_vcc;
|
||||
int err = 0;
|
||||
|
||||
VCI_Table *vct;
|
||||
int size;
|
||||
int mode;
|
||||
int nsize;
|
||||
|
||||
/*
|
||||
* Validate the VPI and VCI values
|
||||
*/
|
||||
if ( (vcp->vc_vpi > eup->eu_pif.pif_maxvpi) ||
|
||||
(vcp->vc_vci > eup->eu_pif.pif_maxvci) ) {
|
||||
eup->eu_stats.eni_st_drv.drv_vc_badrng++;
|
||||
return ( EFAULT );
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if this VCI is already active
|
||||
*/
|
||||
vct = &eup->eu_vcitbl[ vcp->vc_vci ];
|
||||
if ( vct->vci_control >> VCI_MODE_SHIFT != VCI_MODE_TRASH ) {
|
||||
return ( EEXIST );
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate some permanent adapter memory for the reassembly
|
||||
* buffer. Special case the signalling channel(s) buffer size.
|
||||
* Otherwise, the buffer size will be based on whether this is
|
||||
* a server or client card.
|
||||
*/
|
||||
if ( vcp->vc_vci == UNI_SIG_VCI ) /* HACK */
|
||||
size = RX_SIG_BSIZE;
|
||||
else
|
||||
size = (eup->eu_ramsize > MAX_CLIENT_RAM * ENI_BUF_PGSZ) ?
|
||||
RX_SERVER_BSIZE * ENI_BUF_PGSZ :
|
||||
RX_CLIENT_BSIZE * ENI_BUF_PGSZ;
|
||||
|
||||
if ( ( evp->ev_rxbuf = eni_allocate_buffer ( eup, (u_long *)&size ) )
|
||||
== (caddr_t)NULL ) {
|
||||
return ( ENOMEM );
|
||||
}
|
||||
evp->ev_rxpos = 0;
|
||||
|
||||
/*
|
||||
* We only need to open incoming VCI's so outbound VCI's
|
||||
* just get set to CVS_ACTIVE state.
|
||||
*/
|
||||
if ( ( vcp->vc_type & VCC_IN ) == 0 ) {
|
||||
/*
|
||||
* Set the state and return - nothing else needs to be done.
|
||||
*/
|
||||
evp->ev_state = CVS_ACTIVE;
|
||||
return ( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the VCI Table entry to start receiving
|
||||
*/
|
||||
mode = ( evp->ev_connvc->cvc_attr.aal.type == ATM_AAL5
|
||||
? VCI_MODE_AAL5 : VCI_MODE_AAL0 );
|
||||
size >>= ENI_LOC_PREDIV; /* Predivide by 256 WORDS */
|
||||
for ( nsize = -1; size; nsize++ )
|
||||
size >>= 1;
|
||||
|
||||
vct->vci_control = mode << VCI_MODE_SHIFT |
|
||||
PTI_MODE_TRASH << VCI_PTI_SHIFT |
|
||||
( (uintptr_t)(evp->ev_rxbuf) >> ENI_LOC_PREDIV ) << VCI_LOC_SHIFT |
|
||||
nsize << VCI_SIZE_SHIFT;
|
||||
vct->vci_descr = 0; /* Descr = Rdptr = 0 */
|
||||
vct->vci_write = 0; /* WritePtr = CellCount = 0 */
|
||||
|
||||
/*
|
||||
* Indicate VC active
|
||||
*/
|
||||
evp->ev_state = CVS_ACTIVE;
|
||||
|
||||
return ( err );
|
||||
}
|
||||
|
||||
/*
|
||||
* Close a VCC
|
||||
*
|
||||
* This function is called via the common driver code after receiving a
|
||||
* stack *_TERM* command. The common code has already validated most of
|
||||
* the request so we just need to check a few more ENI-specific details.
|
||||
*
|
||||
* Called at splimp.
|
||||
*
|
||||
* Arguments:
|
||||
* cup pointer to device common unit
|
||||
* cvp pointer to common VCC entry
|
||||
*
|
||||
* Returns:
|
||||
* 0 close sucessful
|
||||
* err close failed
|
||||
*
|
||||
*/
|
||||
int
|
||||
eni_closevcc ( cup, cvp )
|
||||
Cmn_unit *cup;
|
||||
Cmn_vcc *cvp;
|
||||
{
|
||||
Eni_unit *eup = (Eni_unit *)cup;
|
||||
Eni_vcc *evp = (Eni_vcc *)cvp;
|
||||
struct vccb *vcp = evp->ev_connvc->cvc_vcc;
|
||||
int err = 0;
|
||||
|
||||
VCI_Table *vct;
|
||||
|
||||
/*
|
||||
* Clear any references to this VCC in our transmit queue
|
||||
*/
|
||||
/*
|
||||
* We'll simply allow any existing TX requests to be
|
||||
* sent as that's easier then pulling them out of
|
||||
* everywhere. Besides, they should be ignored at the
|
||||
* receiver whenever the other end shuts down.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Free the adapter receive buffer
|
||||
*/
|
||||
(void) eni_free_buffer ( eup, (caddr_t)evp->ev_rxbuf );
|
||||
|
||||
/*
|
||||
* If this is an outbound only VCI, then we can close
|
||||
* immediately.
|
||||
*/
|
||||
if ( ( vcp->vc_type & VCC_IN ) == 0 ) {
|
||||
/*
|
||||
* The state will be set to TERM when we return
|
||||
* to the *_TERM caller.
|
||||
*/
|
||||
return ( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Find VCI entry in VCI Table
|
||||
*/
|
||||
vct = &eup->eu_vcitbl[ vcp->vc_vci ];
|
||||
|
||||
/*
|
||||
* Reset the VCI state
|
||||
*/
|
||||
vct->vci_control = ( vct->vci_control & VCI_MODE_MASK )
|
||||
/* | VCI_MODE_TRASH */;
|
||||
DELAY ( MIDWAY_DELAY ); /* Give the adapter time to */
|
||||
/* make the transition */
|
||||
|
||||
/*
|
||||
* Reset everything
|
||||
*/
|
||||
bzero ( (void *)(uintptr_t)vct, sizeof(VCI_Table) );
|
||||
|
||||
return ( err );
|
||||
}
|
||||
|
@ -1,427 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2002 Matthew N. Dodd <winter@jurai.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
|
||||
#include <sys/module.h>
|
||||
#include <machine/bus_memio.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netatm/port.h>
|
||||
#include <netatm/queue.h>
|
||||
#include <netatm/atm.h>
|
||||
#include <netatm/atm_sys.h>
|
||||
#include <netatm/atm_sap.h>
|
||||
#include <netatm/atm_cm.h>
|
||||
#include <netatm/atm_if.h>
|
||||
#include <netatm/atm_stack.h>
|
||||
#include <netatm/atm_pcb.h>
|
||||
#include <netatm/atm_var.h>
|
||||
|
||||
#include <dev/hea/eni_stats.h>
|
||||
#include <dev/hea/eni.h>
|
||||
#include <dev/hea/eni_suni.h>
|
||||
#include <dev/hea/eni_var.h>
|
||||
|
||||
#include <dev/hea/hea_freebsd.h>
|
||||
|
||||
devclass_t hea_devclass;
|
||||
|
||||
static int hea_modevent(module_t, int, void *);
|
||||
|
||||
int
|
||||
hea_alloc (device_t dev)
|
||||
{
|
||||
struct hea_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = (struct hea_softc *)device_get_softc(dev);
|
||||
error = 0;
|
||||
|
||||
sc->mem = bus_alloc_resource(dev, sc->mem_type, &sc->mem_rid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
if (sc->mem == NULL) {
|
||||
device_printf(dev, "Unable to allocate memory resource.\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid,
|
||||
0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
|
||||
if (sc->irq == NULL) {
|
||||
device_printf(dev, "Unable to allocate interrupt resource.\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mtx_init(&sc->mtx, device_get_nameunit(dev), "Interrupt lock", MTX_DEF|MTX_RECURSE);
|
||||
|
||||
fail:
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
hea_free (device_t dev)
|
||||
{
|
||||
struct hea_softc *sc;
|
||||
|
||||
sc = (struct hea_softc *)device_get_softc(dev);
|
||||
if (sc->mem)
|
||||
bus_release_resource(dev, sc->mem_type, sc->mem_rid, sc->mem);
|
||||
if (sc->irq_ih)
|
||||
bus_teardown_intr(dev, sc->irq, sc->irq_ih);
|
||||
if (sc->irq)
|
||||
bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
|
||||
|
||||
/*
|
||||
* Destroy the mutex.
|
||||
*/
|
||||
if (mtx_initialized(&sc->mtx) != 0)
|
||||
mtx_destroy(&sc->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
hea_attach (device_t dev)
|
||||
{
|
||||
struct hea_softc *sc;
|
||||
Eni_unit *eup;
|
||||
int error;
|
||||
long val;
|
||||
|
||||
sc = (struct hea_softc *)device_get_softc(dev);
|
||||
eup = &sc->eup;
|
||||
error = 0;
|
||||
|
||||
/*
|
||||
* Start initializing it
|
||||
*/
|
||||
eup->eu_unit = device_get_unit(dev);
|
||||
eup->eu_mtu = ENI_IFF_MTU;
|
||||
eup->eu_vcc_zone = eni_vcc_zone;
|
||||
eup->eu_nif_zone = eni_nif_zone;
|
||||
eup->eu_ioctl = eni_atm_ioctl;
|
||||
eup->eu_instvcc = eni_instvcc;
|
||||
eup->eu_openvcc = eni_openvcc;
|
||||
eup->eu_closevcc = eni_closevcc;
|
||||
eup->eu_output = eni_output;
|
||||
|
||||
eup->eu_pcitag = dev;
|
||||
eup->eu_softc = (void *)sc;
|
||||
|
||||
/*
|
||||
* Map memory structures into adapter space
|
||||
*/
|
||||
eup->eu_suni = (Eni_mem)(eup->eu_base + SUNI_OFFSET);
|
||||
eup->eu_midway = (Eni_mem)(eup->eu_base + MIDWAY_OFFSET);
|
||||
eup->eu_vcitbl = (VCI_Table *)(eup->eu_base + VCITBL_OFFSET);
|
||||
eup->eu_rxdma = (Eni_mem)(eup->eu_base + RXQUEUE_OFFSET);
|
||||
eup->eu_txdma = (Eni_mem)(eup->eu_base + TXQUEUE_OFFSET);
|
||||
eup->eu_svclist = (Eni_mem)(eup->eu_base + SVCLIST_OFFSET);
|
||||
eup->eu_servread = 0;
|
||||
|
||||
/*
|
||||
* Reset the midway chip
|
||||
*/
|
||||
eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET;
|
||||
|
||||
/*
|
||||
* Size and test adapter memory. Initialize our adapter memory
|
||||
* allocater.
|
||||
*/
|
||||
if (eni_init_memory(eup) < 0) {
|
||||
/*
|
||||
* Adapter memory test failed. Clean up and
|
||||
* return.
|
||||
*/
|
||||
device_printf(dev, "memory test failed.\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (eup->eu_type == TYPE_ADP) {
|
||||
int i;
|
||||
#define MID_ADPMACOFF 0xffc0 /* mac address offset (adaptec only) */
|
||||
|
||||
for (i = 0; i < sizeof(struct mac_addr); i++) {
|
||||
eup->eu_pif.pif_macaddr.ma_data[i] =
|
||||
bus_space_read_1(rman_get_bustag(sc->mem),
|
||||
rman_get_bushandle(sc->mem),
|
||||
MID_ADPMACOFF + i);
|
||||
}
|
||||
|
||||
} else
|
||||
if (eup->eu_type == TYPE_ENI) {
|
||||
/*
|
||||
* Read the contents of the SEEPROM
|
||||
*/
|
||||
eni_read_seeprom(eup);
|
||||
|
||||
/*
|
||||
* Copy MAC address to PIF and config structures
|
||||
*/
|
||||
bcopy((caddr_t)&eup->eu_seeprom[SEPROM_MAC_OFF],
|
||||
(caddr_t)&eup->eu_pif.pif_macaddr,
|
||||
sizeof(struct mac_addr));
|
||||
/*
|
||||
* Copy serial number into config space
|
||||
*/
|
||||
eup->eu_config.ac_serial =
|
||||
ntohl(*(u_long *)&eup->eu_seeprom[SEPROM_SN_OFF]);
|
||||
} else {
|
||||
device_printf(dev, "Unknown adapter type!\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
eup->eu_config.ac_macaddr = eup->eu_pif.pif_macaddr;
|
||||
|
||||
/*
|
||||
* Setup some of the adapter configuration
|
||||
*/
|
||||
/*
|
||||
* Get MIDWAY ID
|
||||
*/
|
||||
val = eup->eu_midway[MIDWAY_ID];
|
||||
eup->eu_config.ac_vendor = VENDOR_ENI;
|
||||
eup->eu_config.ac_vendapi = VENDAPI_ENI_1;
|
||||
eup->eu_config.ac_device = DEV_ENI_155P;
|
||||
eup->eu_config.ac_media = val & MEDIA_MASK ? MEDIA_UTP155 : MEDIA_OC3C;
|
||||
eup->eu_pif.pif_pcr = ATM_PCR_OC3C;
|
||||
|
||||
/*
|
||||
* Make a hw version number from the ID register values.
|
||||
* Format: {Midway ID}.{Mother board ID}.{Daughter board ID}
|
||||
*/
|
||||
snprintf(eup->eu_config.ac_hard_vers,
|
||||
sizeof(eup->eu_config.ac_hard_vers),
|
||||
"%ld/%ld/%ld",
|
||||
(val >> ID_SHIFT) & ID_MASK,
|
||||
(val >> MID_SHIFT) & MID_MASK,
|
||||
(val >> DID_SHIFT) & DID_MASK );
|
||||
|
||||
/*
|
||||
* There is no software version number
|
||||
*/
|
||||
eup->eu_config.ac_firm_vers[0] = '\0';
|
||||
|
||||
/*
|
||||
* Save device ram info for user-level programs
|
||||
* NOTE: This really points to start of EEPROM
|
||||
* and includes all the device registers in the
|
||||
* lower 2 Megabytes.
|
||||
*/
|
||||
eup->eu_config.ac_ram = (long)eup->eu_base;
|
||||
eup->eu_config.ac_ramsize = eup->eu_ramsize + ENI_REG_SIZE;
|
||||
|
||||
/*
|
||||
* Setup max VPI/VCI values
|
||||
*/
|
||||
eup->eu_pif.pif_maxvpi = ENI_MAX_VPI;
|
||||
eup->eu_pif.pif_maxvci = ENI_MAX_VCI;
|
||||
|
||||
/*
|
||||
* Register this interface with ATM core services
|
||||
*/
|
||||
error = atm_physif_register((Cmn_unit *)eup, ENI_DEV_NAME, eni_services);
|
||||
if (error)
|
||||
goto fail;
|
||||
|
||||
eni_units[device_get_unit(dev)] = eup;
|
||||
|
||||
/*
|
||||
* Initialize driver processing
|
||||
*/
|
||||
error = eni_init(eup);
|
||||
if (error) {
|
||||
device_printf(dev, "adapter init failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
hea_detach (device_t dev)
|
||||
{
|
||||
struct hea_softc *sc;
|
||||
Eni_unit *eup;
|
||||
int error;
|
||||
|
||||
sc = (struct hea_softc *)device_get_softc(dev);
|
||||
eup = &sc->eup;
|
||||
error = 0;
|
||||
|
||||
/*
|
||||
* De-Register this interface with ATM core services
|
||||
*/
|
||||
error = atm_physif_deregister((Cmn_unit *)eup);
|
||||
|
||||
/*
|
||||
* Reset the board.
|
||||
*/
|
||||
hea_reset(dev);
|
||||
|
||||
hea_free(dev);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
hea_intr (void * arg)
|
||||
{
|
||||
struct hea_softc *sc;
|
||||
|
||||
sc = (struct hea_softc *)arg;
|
||||
|
||||
HEA_LOCK(sc);
|
||||
eni_intr(&sc->eup);
|
||||
HEA_UNLOCK(sc);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
hea_reset (device_t dev)
|
||||
{
|
||||
struct hea_softc *sc;
|
||||
Eni_unit *eup;
|
||||
|
||||
sc = (struct hea_softc *)device_get_softc(dev);
|
||||
eup = &sc->eup;
|
||||
|
||||
/*
|
||||
* We should really close down any open VCI's and
|
||||
* release all memory (TX and RX) buffers. For now,
|
||||
* we assume we're shutting the card down for good.
|
||||
*/
|
||||
|
||||
if (eup->eu_midway) {
|
||||
/*
|
||||
* Issue RESET command to Midway chip
|
||||
*/
|
||||
eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET;
|
||||
|
||||
/*
|
||||
* Delay to allow everything to terminate
|
||||
*/
|
||||
DELAY(MIDWAY_DELAY);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
hea_modevent (module_t mod, int type, void *data)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = 0;
|
||||
|
||||
switch (type) {
|
||||
case MOD_LOAD:
|
||||
|
||||
eni_nif_zone = uma_zcreate("eni nif", sizeof(struct atm_nif),
|
||||
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
|
||||
if (eni_nif_zone == NULL)
|
||||
panic("%s(): uma_zcreate nif", __func__);
|
||||
uma_zone_set_max(eni_nif_zone, 52);
|
||||
|
||||
eni_vcc_zone = uma_zcreate("eni vcc", sizeof(Eni_vcc),
|
||||
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
|
||||
if (eni_vcc_zone == NULL)
|
||||
panic("%s(): uma_zcreate vcc", __func__);
|
||||
uma_zone_set_max(eni_vcc_zone, 100);
|
||||
|
||||
break;
|
||||
|
||||
case MOD_UNLOAD:
|
||||
|
||||
uma_zdestroy(eni_nif_zone);
|
||||
uma_zdestroy(eni_vcc_zone);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static moduledata_t hea_moduledata = {
|
||||
"hea",
|
||||
hea_modevent,
|
||||
NULL
|
||||
};
|
||||
DECLARE_MODULE(hea, hea_moduledata, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
|
||||
MODULE_VERSION(hea, 1);
|
@ -1,59 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2002 Matthew N. Dodd <winter@jurai.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
struct hea_softc {
|
||||
device_t dev;
|
||||
|
||||
struct resource * mem;
|
||||
int mem_rid;
|
||||
int mem_type;
|
||||
|
||||
struct resource * irq;
|
||||
int irq_rid;
|
||||
void * irq_ih;
|
||||
|
||||
struct mtx mtx;
|
||||
|
||||
Eni_unit eup;
|
||||
};
|
||||
|
||||
#define HEA_LOCK(_sc) mtx_lock(&(_sc)->mtx)
|
||||
#define HEA_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
|
||||
|
||||
extern devclass_t hea_devclass;
|
||||
|
||||
int hea_alloc (device_t);
|
||||
int hea_free (device_t);
|
||||
|
||||
int hea_attach (device_t);
|
||||
int hea_detach (device_t);
|
||||
|
||||
void hea_intr (void *);
|
||||
void hea_reset (device_t);
|
||||
|
||||
void eni_read_seeprom(Eni_unit *);
|
@ -1,238 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2002 Matthew N. Dodd <winter@jurai.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
*
|
||||
* ===================================
|
||||
* HARP | Host ATM Research Platform
|
||||
* ===================================
|
||||
*
|
||||
*
|
||||
* This Host ATM Research Platform ("HARP") file (the "Software") is
|
||||
* made available by Network Computing Services, Inc. ("NetworkCS")
|
||||
* "AS IS". NetworkCS does not provide maintenance, improvements or
|
||||
* support of any kind.
|
||||
*
|
||||
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
|
||||
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
|
||||
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
|
||||
* In no event shall NetworkCS be responsible for any damages, including
|
||||
* but not limited to consequential damages, arising from or relating to
|
||||
* any use of the Software or related support.
|
||||
*
|
||||
* Copyright 1994-1998 Network Computing Services, Inc.
|
||||
*
|
||||
* Copies of this Software may be made, however, the above copyright
|
||||
* notice must be reproduced on all copies.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
|
||||
#include <sys/module.h>
|
||||
#include <machine/bus_memio.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netatm/port.h>
|
||||
#include <netatm/queue.h>
|
||||
#include <netatm/atm.h>
|
||||
#include <netatm/atm_sys.h>
|
||||
#include <netatm/atm_sap.h>
|
||||
#include <netatm/atm_cm.h>
|
||||
#include <netatm/atm_if.h>
|
||||
#include <netatm/atm_stack.h>
|
||||
#include <netatm/atm_pcb.h>
|
||||
#include <netatm/atm_var.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
#include <dev/hea/eni_stats.h>
|
||||
#include <dev/hea/eni.h>
|
||||
#include <dev/hea/eni_suni.h>
|
||||
#include <dev/hea/eni_var.h>
|
||||
|
||||
#include <dev/hea/hea_freebsd.h>
|
||||
|
||||
static int hea_pci_probe(device_t);
|
||||
static int hea_pci_attach(device_t);
|
||||
|
||||
#define ENI_VENDORID 0x111A
|
||||
#define ENI_DEVICEID_ENI155PF 0x0000
|
||||
#define ENI_DEVICEID_ENI155PA 0x0002
|
||||
|
||||
#define ADP_VENDORID 0x9004
|
||||
#define ADP_DEVICEID_AIC5900 0x5900
|
||||
#define ADP_DEVICEID_AIC5905 0x5905
|
||||
|
||||
struct hea_pci_type {
|
||||
u_int16_t vid;
|
||||
u_int16_t did;
|
||||
char * name;
|
||||
} hea_pci_devs[] = {
|
||||
{ ENI_VENDORID, ENI_DEVICEID_ENI155PF,
|
||||
"Efficient Networks 155P-MF1 (FPGA) ATM Adapter" },
|
||||
{ ENI_VENDORID, ENI_DEVICEID_ENI155PA,
|
||||
"Efficient Networks 155P-MF1 (ASIC) ATM Adapter" },
|
||||
{ ADP_VENDORID, ADP_DEVICEID_AIC5900,
|
||||
"ANA-5910/5930/5940 ATM155 & 25 LAN Adapter" },
|
||||
{ ADP_VENDORID, ADP_DEVICEID_AIC5905,
|
||||
"ANA-5910A/5930A/5940A ATM Adapter" },
|
||||
{ 0, 0, NULL },
|
||||
};
|
||||
|
||||
static int
|
||||
hea_pci_probe (dev)
|
||||
device_t dev;
|
||||
{
|
||||
struct hea_pci_type * t = hea_pci_devs;
|
||||
|
||||
while (t->name != NULL) {
|
||||
if ((pci_get_vendor(dev) == t->vid) &&
|
||||
(pci_get_device(dev) == t->did)) {
|
||||
device_set_desc(dev, t->name);
|
||||
return(0);
|
||||
}
|
||||
t++;
|
||||
}
|
||||
|
||||
return(ENXIO);
|
||||
}
|
||||
|
||||
static int
|
||||
hea_pci_attach (dev)
|
||||
device_t dev;
|
||||
{
|
||||
struct hea_softc *sc;
|
||||
Eni_unit *eup;
|
||||
u_int32_t command;
|
||||
vm_offset_t va;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
eup = &sc->eup;
|
||||
error = 0;
|
||||
|
||||
pci_enable_busmaster(dev);
|
||||
|
||||
sc->mem_rid = PCIR_BAR(0);
|
||||
sc->mem_type = SYS_RES_MEMORY;
|
||||
sc->irq_rid = 0;
|
||||
|
||||
error = hea_alloc(dev);
|
||||
if (error) {
|
||||
device_printf(dev, "hea_alloc() failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
va = (vm_offset_t) rman_get_virtual(sc->mem);
|
||||
|
||||
eup->eu_base = (Eni_mem)va;
|
||||
eup->eu_ram = (Eni_mem)(eup->eu_base + RAM_OFFSET);
|
||||
|
||||
/*
|
||||
* Convert Endianess on DMA
|
||||
*/
|
||||
command = pci_read_config(dev, PCI_CONTROL_REG, 4);
|
||||
command |= ENDIAN_SWAP_DMA;
|
||||
pci_write_config(dev, PCI_CONTROL_REG, command, 4);
|
||||
|
||||
/*
|
||||
* Map interrupt in
|
||||
*/
|
||||
error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET,
|
||||
hea_intr, sc, &sc->irq_ih);
|
||||
if (error) {
|
||||
device_printf(dev, "Interrupt handler setup failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
eup->eu_config.ac_bustype = BUS_PCI;
|
||||
eup->eu_config.ac_busslot = (pci_get_bus(dev) << 8)| pci_get_slot(dev);
|
||||
|
||||
switch (pci_get_vendor(dev)) {
|
||||
case ENI_VENDORID:
|
||||
eup->eu_type = TYPE_ENI;
|
||||
break;
|
||||
case ADP_VENDORID:
|
||||
eup->eu_type = TYPE_ADP;
|
||||
break;
|
||||
default:
|
||||
eup->eu_type = TYPE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
error = hea_attach(dev);
|
||||
if (error) {
|
||||
device_printf(dev, "hea_attach() failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
fail:
|
||||
hea_detach(dev);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static device_method_t hea_pci_methods[] = {
|
||||
DEVMETHOD(device_probe, hea_pci_probe),
|
||||
DEVMETHOD(device_attach, hea_pci_attach),
|
||||
|
||||
DEVMETHOD(device_detach, hea_detach),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t hea_pci_driver = {
|
||||
"hea",
|
||||
hea_pci_methods,
|
||||
sizeof(struct hea_softc)
|
||||
};
|
||||
|
||||
DRIVER_MODULE(hea, pci, hea_pci_driver, hea_devclass, 0, 0);
|
||||
MODULE_DEPEND(hea, pci, 1, 1, 1);
|
||||
MODULE_DEPEND(hea, hea, 1, 1, 1);
|
Loading…
Reference in New Issue
Block a user