Convert the midway driver to use busdma. Except for this conversion the

following changes have been done:

- stylify. The original code was too hard to read.
- get rid of a number of compilation options (Adaptec-only, Eni-only, no-DMA).
- more debugging features.
- locking. This is not correct yet in the absence of interface layer locking,
  but is correct enough to not to cause lock order reversals.
- remove RAW mode. There are no users of this in the tree and I doubt that
  there are any.
- remove NetBSD compatibility code. There was no way to keep NetBSD non-busdma
  and FreeBSD busdma code together.
- if_en now buildable as a module.

This has been actively tested on sparc64 and i386 with ENI server and
client cards and an Adaptec card (thanks to kjc).

Reviewed by:	mdodd, arr
This commit is contained in:
Hartmut Brandt 2003-04-25 16:14:03 +00:00
parent d8ca78d02f
commit 33cfde03bc
7 changed files with 3488 additions and 3664 deletions

View File

@ -44,18 +44,21 @@
* FreeBSD PCI glue for the eni155p card.
* thanks to Matt Thomas for figuring out FreeBSD vs NetBSD vs etc.. diffs.
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <vm/uma.h>
#include <net/if.h>
#include <net/if_atm.h>
#include <pci/pcivar.h>
#include <pci/pcireg.h>
@ -63,61 +66,44 @@
#include <dev/en/midwayreg.h>
#include <dev/en/midwayvar.h>
/*
* prototypes
*/
static int en_pci_probe(device_t);
static int en_pci_attach(device_t);
static int en_pci_detach(device_t);
static int en_pci_shutdown(device_t);
/*
* local structures
*/
struct en_pci_softc {
/* bus independent stuff */
struct en_softc esc; /* includes "device" structure */
/* bus independent stuff */
struct en_softc esc; /* includes "device" structure */
/* freebsd newbus glue */
struct resource *res; /* resource descriptor for registers */
struct resource *irq; /* resource descriptor for interrupt */
void *ih; /* interrupt handle */
/* freebsd newbus glue */
struct resource *res; /* resource descriptor for registers */
struct resource *irq; /* resource descriptor for interrupt */
void *ih; /* interrupt handle */
};
#if !defined(MIDWAY_ENIONLY)
static void eni_get_macaddr(device_t, struct en_pci_softc *);
#endif
#if !defined(MIDWAY_ADPONLY)
static void adp_get_macaddr(struct en_pci_softc *);
#endif
/*
* local defines (PCI specific stuff)
*/
/*
* address of config base memory address register in PCI config space
* (this is card specific)
*/
#define PCI_CBMA 0x10
/*
* tonga (pci bridge). ENI cards only!
*/
#define EN_TONGA 0x60 /* PCI config addr of tonga reg */
#define TONGA_SWAP_DMA 0x80 /* endian swap control */
#define TONGA_SWAP_BYTE 0x40
#define TONGA_SWAP_WORD 0x20
#define TONGA_READ_MULT 0x00
#define TONGA_READ_MEM 0x04
#define TONGA_READ_IVAN 0x08
#define TONGA_READ_KEN 0x0C
/*
* adaptec pci bridge. ADP cards only!
*/
#define ADP_PCIREG 0x050040 /* PCI control register */
#define ADP_PCIREG_RESET 0x1 /* reset card */
@ -134,187 +120,184 @@ static void adp_get_macaddr(struct en_pci_softc *);
#define PCI_VENDOR(x) ((x) & 0xFFFF)
#define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF)
#if !defined(MIDWAY_ENIONLY)
static void adp_busreset(void *);
/*
* bus specific reset function [ADP only!]
*/
static void adp_busreset(v)
void *v;
static void
adp_busreset(void *v)
{
struct en_softc *sc = (struct en_softc *) v;
u_int32_t dummy;
struct en_softc *sc = (struct en_softc *)v;
uint32_t dummy;
bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG, ADP_PCIREG_RESET);
DELAY(1000); /* let it reset */
dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG,
(ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA|ADP_PCIREG_IENABLE));
dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
if ((dummy & (ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA)) !=
(ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA))
printf("adp_busreset: Adaptec ATM did NOT reset!\n");
bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG,
ADP_PCIREG_RESET);
DELAY(1000); /* let it reset */
dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG,
(ADP_PCIREG_SWAP_DMA | ADP_PCIREG_IENABLE));
dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
if ((dummy & (ADP_PCIREG_SWAP_WORD | ADP_PCIREG_SWAP_DMA)) !=
ADP_PCIREG_SWAP_DMA)
if_printf(&sc->enif, "adp_busreset: Adaptec ATM did "
"NOT reset!\n");
}
#endif
/***********************************************************************/
/*
* autoconfig stuff
*/
static int
en_pci_probe(device_t dev)
{
switch (pci_get_vendor(dev)) {
#if !defined(MIDWAY_ADPONLY)
case PCI_VENDOR_EFFICIENTNETS:
switch (pci_get_device(dev)) {
case PCI_PRODUCT_EFFICIENTNETS_ENI155PF:
case PCI_PRODUCT_EFFICIENTNETS_ENI155PA:
device_set_desc(dev, "Efficient Networks ENI-155p");
return 0;
}
break;
#endif
#if !defined(MIDWAY_ENIONLY)
case PCI_VENDOR_ADP:
switch (pci_get_device(dev)) {
case PCI_PRODUCT_ADP_AIC5900:
case PCI_PRODUCT_ADP_AIC5905:
device_set_desc(dev, "Adaptec 155 ATM");
return 0;
}
break;
#endif
}
return ENXIO;
switch (pci_get_vendor(dev)) {
case PCI_VENDOR_EFFICIENTNETS:
switch (pci_get_device(dev)) {
case PCI_PRODUCT_EFFICIENTNETS_ENI155PF:
case PCI_PRODUCT_EFFICIENTNETS_ENI155PA:
device_set_desc(dev, "Efficient Networks ENI-155p");
return (0);
}
break;
case PCI_VENDOR_ADP:
switch (pci_get_device(dev)) {
case PCI_PRODUCT_ADP_AIC5900:
case PCI_PRODUCT_ADP_AIC5905:
device_set_desc(dev, "Adaptec 155 ATM");
return (0);
}
break;
}
return (ENXIO);
}
static int
en_pci_attach(device_t dev)
{
struct en_softc *sc;
struct en_pci_softc *scp;
u_long val;
int rid, s, unit, error = 0;
struct en_softc *sc;
struct en_pci_softc *scp;
u_long val;
int rid, unit, error = 0;
sc = device_get_softc(dev);
scp = (struct en_pci_softc *)sc;
bzero(scp, sizeof(*scp)); /* zero */
sc = device_get_softc(dev);
scp = (struct en_pci_softc *)sc;
s = splimp();
unit = device_get_unit(dev);
sc->enif.if_unit = unit;
sc->enif.if_name = "en";
/*
* Enable bus mastering.
*/
val = pci_read_config(dev, PCIR_COMMAND, 2);
val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
pci_write_config(dev, PCIR_COMMAND, val, 2);
/*
* Enable bus mastering.
*/
val = pci_read_config(dev, PCIR_COMMAND, 2);
val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
pci_write_config(dev, PCIR_COMMAND, val, 2);
/*
* Map control/status registers.
*/
rid = PCI_CBMA;
scp->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
0, ~0, 1, RF_ACTIVE);
if (!scp->res) {
device_printf(dev, "could not map memory\n");
error = ENXIO;
goto fail;
}
/*
* Map control/status registers.
*/
rid = PCI_CBMA;
scp->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
0, ~0, 1, RF_ACTIVE);
if (scp->res == NULL) {
device_printf(dev, "could not map memory\n");
error = ENXIO;
goto fail;
}
sc->en_memt = rman_get_bustag(scp->res);
sc->en_base = rman_get_bushandle(scp->res);
/*
* Allocate our interrupt.
*/
rid = 0;
scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
RF_SHAREABLE | RF_ACTIVE);
if (scp->irq == NULL) {
device_printf(dev, "could not map interrupt\n");
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
error = ENXIO;
goto fail;
}
sc->dev = dev;
sc->en_memt = rman_get_bustag(scp->res);
sc->en_base = rman_get_bushandle(scp->res);
error = bus_setup_intr(dev, scp->irq, INTR_TYPE_NET,
en_intr, sc, &scp->ih);
if (error) {
device_printf(dev, "could not setup irq\n");
bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
goto fail;
}
sc->ipl = 1; /* XXX (required to enable interrupt on midway) */
/*
* Allocate our interrupt.
*/
rid = 0;
scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
RF_SHAREABLE | RF_ACTIVE);
if (scp->irq == NULL) {
device_printf(dev, "could not map interrupt\n");
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
error = ENXIO;
goto fail;
}
unit = device_get_unit(dev);
snprintf(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname), "en%d", unit);
sc->enif.if_unit = unit;
sc->enif.if_name = "en";
sc->ipl = 1; /* XXX (required to enable interrupt on midway) */
/* figure out if we are an adaptec card or not */
sc->is_adaptec = (pci_get_vendor(dev) == PCI_VENDOR_ADP) ? 1 : 0;
/*
* set up pci bridge
*/
#if !defined(MIDWAY_ENIONLY)
if (sc->is_adaptec) {
adp_get_macaddr(scp);
sc->en_busreset = adp_busreset;
adp_busreset(sc);
}
#endif
/* figure out if we are an adaptec card or not */
sc->is_adaptec = (pci_get_vendor(dev) == PCI_VENDOR_ADP) ? 1 : 0;
#if !defined(MIDWAY_ADPONLY)
if (!sc->is_adaptec) {
eni_get_macaddr(dev, scp);
sc->en_busreset = NULL;
pci_write_config(dev, EN_TONGA, (TONGA_SWAP_DMA|TONGA_SWAP_WORD), 4);
}
#endif
/*
* set up pci bridge
*/
if (sc->is_adaptec) {
adp_get_macaddr(scp);
sc->en_busreset = adp_busreset;
adp_busreset(sc);
} else {
eni_get_macaddr(dev, scp);
sc->en_busreset = NULL;
pci_write_config(dev, EN_TONGA, TONGA_SWAP_DMA | TONGA_READ_IVAN, 4);
}
/*
* done PCI specific stuff
*/
/*
* Common attach stuff
*/
if ((error = en_attach(sc)) != 0) {
device_printf(dev, "attach failed\n");
bus_teardown_intr(dev, scp->irq, scp->ih);
bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
goto fail;
}
en_attach(sc);
/*
* Do the interrupt SETUP last just before returning
*/
error = bus_setup_intr(dev, scp->irq, INTR_TYPE_NET,
en_intr, sc, &scp->ih);
if (error) {
en_reset(sc);
if_detach(&sc->enif);
device_printf(dev, "could not setup irq\n");
bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
en_destroy(sc);
goto fail;
}
splx(s);
return (0);
return 0;
fail:
splx(s);
return error;
fail:
return (error);
}
/*
* Detach the adapter
*/
static int
en_pci_detach(device_t dev)
{
struct en_softc *sc = device_get_softc(dev);
struct en_pci_softc *scp = (struct en_pci_softc *)sc;
int s;
s = splimp();
/*
* Close down routes etc.
*/
if_detach(&sc->enif);
/*
* Stop DMA and drop transmit queue.
*/
if ((sc->enif.if_flags & IFF_RUNNING)) {
if_printf(&sc->enif, "still running\n");
sc->enif.if_flags &= ~IFF_RUNNING;
}
/*
* Close down routes etc.
*/
en_reset(sc);
if_detach(&sc->enif);
/*
* Deallocate resources.
@ -323,146 +306,157 @@ en_pci_detach(device_t dev)
bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
#ifdef notyet
/*
* Free all the driver internal resources
*/
#endif
en_destroy(sc);
splx(s);
return 0;
return (0);
}
static int
en_pci_shutdown(device_t dev)
{
struct en_pci_softc *psc = (struct en_pci_softc *)device_get_softc(dev);
struct en_pci_softc *psc = device_get_softc(dev);
en_reset(&psc->esc);
DELAY(10); /* is this necessary? */
return (0);
en_reset(&psc->esc);
DELAY(10); /* is this necessary? */
return (0);
}
#if !defined(MIDWAY_ENIONLY)
#if defined(sparc)
#define bus_space_read_1(t, h, o) \
((void)t, (*(volatile u_int8_t *)((h) + (o))))
#endif
/*
* Get the MAC address from an Adaptec board. No idea how to get
* serial number or other stuff, because I have no documentation for that
* card.
*/
static void
adp_get_macaddr(scp)
struct en_pci_softc *scp;
adp_get_macaddr(struct en_pci_softc *scp)
{
struct en_softc * sc = (struct en_softc *)scp;
int lcv;
struct en_softc * sc = (struct en_softc *)scp;
int lcv;
for (lcv = 0; lcv < sizeof(sc->macaddr); lcv++)
sc->macaddr[lcv] = bus_space_read_1(sc->en_memt, sc->en_base,
MID_ADPMACOFF + lcv);
for (lcv = 0; lcv < sizeof(sc->macaddr); lcv++)
sc->macaddr[lcv] = bus_space_read_1(sc->en_memt, sc->en_base,
MID_ADPMACOFF + lcv);
}
#endif /* MIDWAY_ENIONLY */
#if !defined(MIDWAY_ADPONLY)
/*
* Read station (MAC) address from serial EEPROM.
* derived from linux drivers/atm/eni.c by Werner Almesberger, EPFL LRC.
*/
#define EN_PROM_MAGIC 0x0c
#define EN_PROM_DATA 0x02
#define EN_PROM_CLK 0x01
#define EN_ESI 64
#define EN_PROM_MAGIC 0x0c
#define EN_PROM_DATA 0x02
#define EN_PROM_CLK 0x01
#define EN_ESI 64
#define EN_SERIAL 112
/*
* Read a byte from the given address in the EEPROM
*/
static uint8_t
eni_get_byte(device_t dev, uint32_t *data, u_int address)
{
int j;
uint8_t tmp;
address = (address << 1) + 1;
/* start operation */
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data &= ~EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
/* send address with serial line */
for ( j = 7 ; j >= 0 ; j --) {
*data = ((address >> j) & 1) ? (*data | EN_PROM_DATA) :
(*data & ~EN_PROM_DATA);
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
}
/* get ack */
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data = pci_read_config(dev, EN_TONGA, 4);
*data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
tmp = 0;
for ( j = 7 ; j >= 0 ; j --) {
tmp <<= 1;
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data = pci_read_config(dev, EN_TONGA, 4);
if(*data & EN_PROM_DATA) tmp |= 1;
*data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
}
/* get ack */
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data = pci_read_config(dev, EN_TONGA, 4);
*data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
return (tmp);
}
/*
* Get MAC address and other stuff from the EEPROM
*/
static void
eni_get_macaddr(device_t dev, struct en_pci_softc *scp)
{
struct en_softc * sc = (struct en_softc *)scp;
int i, j, address, status;
u_int32_t data, t_data;
u_int8_t tmp;
t_data = pci_read_config(dev, EN_TONGA, 4) & 0xffffff00;
struct en_softc * sc = (struct en_softc *)scp;
int i;
uint32_t data, t_data;
data = EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK;
pci_write_config(dev, EN_TONGA, data, 4);
t_data = pci_read_config(dev, EN_TONGA, 4) & 0xffffff00;
for (i = 0; i < sizeof(sc->macaddr); i ++){
/* start operation */
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data &= ~EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
/* send address with serial line */
address = ((i + EN_ESI) << 1) + 1;
for ( j = 7 ; j >= 0 ; j --){
data = (address >> j) & 1 ? data | EN_PROM_DATA :
data & ~EN_PROM_DATA;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
}
/* get ack */
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data = pci_read_config(dev, EN_TONGA, 4);
status = data & EN_PROM_DATA;
data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data = EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK;
pci_write_config(dev, EN_TONGA, data, 4);
tmp = 0;
for (i = 0; i < sizeof(sc->macaddr); i ++)
sc->macaddr[i] = eni_get_byte(dev, &data, i + EN_ESI);
for ( j = 7 ; j >= 0 ; j --){
tmp <<= 1;
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data = pci_read_config(dev, EN_TONGA, 4);
if(data & EN_PROM_DATA) tmp |= 1;
data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
}
/* get ack */
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data = pci_read_config(dev, EN_TONGA, 4);
status = data & EN_PROM_DATA;
data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
sc->macaddr[i] = tmp;
}
/* stop operation */
data &= ~EN_PROM_DATA;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_DATA;
pci_write_config(dev, EN_TONGA, data, 4);
pci_write_config(dev, EN_TONGA, t_data, 4);
sc->serial = 0;
for (i = 0; i < 4; i++) {
sc->serial <<= 8;
sc->serial |= eni_get_byte(dev, &data, i + EN_SERIAL);
}
/* stop operation */
data &= ~EN_PROM_DATA;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_DATA;
pci_write_config(dev, EN_TONGA, data, 4);
pci_write_config(dev, EN_TONGA, t_data, 4);
}
#endif /* !MIDWAY_ADPONLY */
/*
* Driver infrastructure
*/
static device_method_t en_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, en_pci_probe),
@ -482,4 +476,3 @@ static driver_t en_driver = {
static devclass_t en_devclass;
DRIVER_MODULE(en, pci, en_driver, en_devclass, 0, 0);

File diff suppressed because it is too large Load Diff

View File

@ -9,28 +9,11 @@
* $FreeBSD$
*/
#if defined(sparc)
/* XXX: gross. netbsd/sparc doesn't have machine/bus.h yet. */
typedef void * bus_space_tag_t;
typedef u_int32_t pci_chipset_tag_t;
typedef caddr_t bus_space_handle_t;
typedef u_int32_t bus_size_t;
typedef caddr_t bus_addr_t;
#define bus_space_read_4(t, h, o) ((void) t, \
(*(volatile u_int32_t *)((h) + (o))))
#define bus_space_write_4(t, h, o, v) \
((void) t, ((void)(*(volatile u_int32_t *)((h) + (o)) = (v))))
#define vtophys(x) ((u_int32_t)(x)) /* sun4c dvma */
#endif
#define MID_SZTOB(X) ((X) * 256 * 4) /* size to bytes */
#define MID_BTOSZ(X) ((X) / 256 / 4) /* bytes to "size" */
#define MID_N_VC 1024 /* # of VCs we can use */
#define MID_VCI_BITS 10 /* number of bits */
#define MID_NTX_CH 8 /* 8 transmit channels (shared) */
#define MID_ATMDATASZ 48 /* need data in 48 byte blocks */
@ -50,6 +33,7 @@ typedef caddr_t bus_addr_t;
*/
/* byte offsets from en_base of various items */
#define MID_SUNIOFF 0x020000 /* SUNI offset */
#define MID_PHYOFF 0x030000 /* PHY offset */
#define MID_MIDOFF 0x040000 /* midway regs offset */
#define MID_RAMOFF 0x200000 /* RAM offset */
@ -68,11 +52,11 @@ typedef caddr_t bus_addr_t;
* prom & phy: not defined here
*/
#define MID_ADPMACOFF 0xffc0 /* mac address offset (adaptec only) */
#define MID_NSUNI 256 /* suni registers */
/*
* midway regs (byte offsets from en_base)
*/
#define MID_RESID 0x40000 /* write=reset reg, read=ID reg */
#define MID_VER(X) (((X) & 0xf0000000) >> 28) /* midway version # */
@ -135,7 +119,7 @@ typedef caddr_t bus_addr_t;
#define MID_DMA_RDTX 0x4002c /* read ptr for DMA xmit queue (r/o) */
/* (i.e. current host->adaptor xfer) */
/* xmit channel regs (1 per channel, MID_NTX_CH max channels) */
/* xmit channel regs (1 per channel, MID_NTX_CH max channels) */
#define MIDX_PLACE(N) (0x40040+((N)*0x10)) /* xmit place */
@ -143,12 +127,13 @@ typedef caddr_t bus_addr_t;
#define MIDX_LOC(X) ((X) & 0x7ff) /* location in obmem */
#define MIDX_SZ(X) ((X) >> 11) /* (size of block / 256) in int32_t's*/
#define MIDX_BASE(X) \
(((MIDX_LOC(X) << MIDV_LOCTOPSHFT) * sizeof(u_int32_t)) + MID_RAMOFF)
/* the following two regs are word offsets in the block */
#define MIDX_READPTR(N) (0x40044+((N)*0x10)) /* xmit read pointer (r/o) */
#define MIDX_DESCSTART(N) (0x40048+((N)*0x10)) /* seg currently in DMA (r/o) */
(((MIDX_LOC(X) << MIDV_LOCTOPSHFT) * sizeof(uint32_t)) + MID_RAMOFF)
/* the following two regs are word offsets in the block */
/* xmit read pointer (r/o) */
#define MIDX_READPTR(N) (0x40044 + ((N) * 0x10))
/* seg currently in DMA (r/o) */
#define MIDX_DESCSTART(N) (0x40048 + ((N) * 0x10))
/*
* obmem items
@ -157,8 +142,7 @@ typedef caddr_t bus_addr_t;
/*
* vci table in obmem (offset from MID_VCTOFF)
*/
#define MID_VC(N) (MID_RAMOFF+((N)*0x10))
#define MID_VC(N) (MID_RAMOFF + ((N) * 0x10))
#define MIDV_TRASH 0x00000000 /* ignore VC */
#define MIDV_AAL5 0x80000000 /* do AAL5 on it */
@ -196,45 +180,43 @@ typedef caddr_t bus_addr_t;
/*
* dma recv q.
*/
#define MID_DMA_END (1 << 5) /* for both tx and rx */
#define MID_DMA_CNT(X) (((X) >> 16) & 0xffff)
#define MID_DMA_TXCHAN(X) (((X) >> 6) & 0x7)
#define MID_DMA_RXVCI(X) (((X) >> 6) & 0x3ff)
#define MID_DMA_TYPE(X) ((X) & 0xf)
#define MID_DMA_END (1 << 5) /* for both tx and rx */
#define MID_DMA_CNT(X) (((X) >> 16) & 0xffff)
#define MID_DMA_TXCHAN(X) (((X) >> 6) & 0x7)
#define MID_DMA_RXVCI(X) (((X) >> 6) & 0x3ff)
#define MID_DMA_TYPE(X) ((X) & 0xf)
#define MID_DRQ_N 512 /* # of descriptors */
#define MID_DRQ_N 512 /* # of descriptors */
/* convert byte offset to reg value */
#define MID_DRQ_A2REG(N) (((N) - MID_DRQOFF) >> 3)
/* convert byte offset to reg value */
#define MID_DRQ_REG2A(N) (((N) << 3) + MID_DRQOFF) /* and back */
/* and back */
#define MID_DRQ_REG2A(N) (((N) << 3) + MID_DRQOFF)
/* note: format of word 1 of RXQ is different beween ENI and ADP cards */
#define MID_MK_RXQ_ENI(CNT,VC,END,TYPE) \
( ((CNT) << 16)|((VC) << 6)|(END)|(TYPE) )
#define MID_MK_RXQ_ENI(CNT, VC, END, TYPE) \
(((CNT) << 16) | ((VC) << 6) | (END) | (TYPE))
#define MID_MK_RXQ_ADP(CNT,VC,END,JK) \
( ((CNT) << 12)|((VC) << 2)|((END) >> 4)|(((JK) != 0) ? 1 : 0))
#define MID_MK_RXQ_ADP(CNT, VC, END, JK) \
(((CNT) << 12) | ((VC) << 2) | ((END) >> 4) | (((JK) != 0) ? 1 : 0))
/*
* dma xmit q.
*/
#define MID_DTQ_N 512 /* # of descriptors */
#define MID_DTQ_N 512 /* # of descriptors */
/* convert byte offset to reg value */
#define MID_DTQ_A2REG(N) (((N) - MID_DTQOFF) >> 3)
/* convert byte offset to reg value */
#define MID_DTQ_REG2A(N) (((N) << 3) + MID_DTQOFF) /* and back */
/* and back */
#define MID_DTQ_REG2A(N) (((N) << 3) + MID_DTQOFF)
/* note: format of word 1 of TXQ is different beween ENI and ADP cards */
#define MID_MK_TXQ_ENI(CNT,CHN,END,TYPE) \
( ((CNT) << 16)|((CHN) << 6)|(END)|(TYPE) )
#define MID_MK_TXQ_ENI(CNT, CHN, END, TYPE) \
(((CNT) << 16) | ((CHN) << 6) | (END) | (TYPE))
#define MID_MK_TXQ_ADP(CNT,CHN,END,JK) \
( ((CNT) << 12)|((CHN) << 2)|((END) >> 4)|(((JK) != 0) ? 1 : 0) )
#define MID_MK_TXQ_ADP(CNT, CHN, END, JK) \
(((CNT) << 12) | ((CHN) << 2) | ((END) >> 4) | (((JK) != 0) ? 1 : 0))
/*
* dma types
*/
#define MIDDMA_JK 0x3 /* just kidding */
#define MIDDMA_BYTE 0x1 /* byte */
#define MIDDMA_2BYTE 0x2 /* 2 bytes */
@ -249,25 +231,23 @@ typedef caddr_t bus_addr_t;
#define MIDDMA_16WMAYBE 0xe /* 16 words, maybe */
#define MIDDMA_MAYBE 0xc /* mask to detect WMAYBE dma code */
#define MIDDMA_MAXBURST (16 * sizeof(u_int32_t)) /* largest burst */
#define MIDDMA_MAXBURST (16 * sizeof(uint32_t)) /* largest burst */
/*
* service list
*/
#define MID_SL_N 1024 /* max # entries on slist */
#define MID_SL_A2REG(N) (((N) - MID_SLOFF) >> 2)
/* convert byte offset to reg value */
#define MID_SL_REG2A(N) (((N) << 2) + MID_SLOFF) /* and back */
#define MID_SL_N 1024 /* max # entries on slist */
/* convert byte offset to reg value */
#define MID_SL_A2REG(N) (((N) - MID_SLOFF) >> 2)
/* and back */
#define MID_SL_REG2A(N) (((N) << 2) + MID_SLOFF)
/*
* data in the buffer area of obmem
*/
/*
* recv buffer desc. (1 u_int32_t at start of buffer)
* recv buffer desc. (1 uint32_t at start of buffer)
*/
#define MID_RBD_SIZE 4 /* RBD size */
#define MID_CHDR_SIZE 4 /* on aal0, cell header size */
#define MID_RBD_ID(X) ((X) & 0xfe000000) /* get ID */
@ -279,26 +259,24 @@ typedef caddr_t bus_addr_t;
#define MID_RBD_CNT(X) ((X) & 0x7ff) /* cell count */
/*
* xmit buffer desc. (2 u_int32_t's at start of buffer)
* (note we treat the PR & RATE as a single u_int8_t)
* xmit buffer desc. (2 uint32_t's at start of buffer)
* (note we treat the PR & RATE as a single uint8_t)
*/
#define MID_TBD_SIZE 8
#define MID_TBD_MK1(AAL,PR_RATE,CNT) \
(MID_TBD_STDID|(AAL)|((PR_RATE) << 19)|(CNT))
(MID_TBD_STDID | (AAL) | ((PR_RATE) << 19) | (CNT))
#define MID_TBD_STDID 0xb0000000 /* standard ID */
#define MID_TBD_AAL5 0x08000000 /* AAL 5 */
#define MID_TBD_NOAAL5 0x00000000 /* not AAL 5 */
#define MID_TBD_MK2(VCI,PTI,CLP) \
(((VCI) << 4)|((PTI) << 1)|(CLP))
(((VCI) << 4) | ((PTI) << 1) | (CLP))
/*
* aal5 pdu tail, last 2 words of last cell of AAL5 frame
* (word 2 is CRC .. handled by hw)
*/
#define MID_PDU_SIZE 8
#define MID_PDU_MK1(UU,CPI,LEN) \
(((UU) << 24)|((CPI) << 16)|(LEN))
#define MID_PDU_SIZE 8
#define MID_PDU_MK1(UU, CPI, LEN) \
(((UU) << 24) | ((CPI) << 16) | (LEN))
#define MID_PDU_LEN(X) ((X) & 0xffff)

View File

@ -38,8 +38,7 @@
* m i d w a y v a r . h
*
* we define the en_softc here so that bus specific modules can allocate
* it as the first item in their softc. note that BSD-required
* "struct device" is in the mid_softc!
* it as the first item in their softc.
*
* author: Chuck Cranor <chuck@ccrc.wustl.edu>
*/
@ -47,7 +46,6 @@
/*
* params needed to determine softc size
*/
#ifndef EN_NTX
#define EN_NTX 8 /* number of tx bufs to use */
#endif
@ -57,144 +55,176 @@
#ifndef EN_RXSZ
#define EN_RXSZ 32 /* recv buf size in KB */
#endif
#define EN_MAXNRX ((2048-(EN_NTX*EN_TXSZ))/EN_RXSZ)
/* largest possible NRX (depends on RAM size) */
/* largest possible NRX (depends on RAM size) */
#define EN_MAXNRX ((2048 - (EN_NTX * EN_TXSZ)) / EN_RXSZ)
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
#define EN_INTR_TYPE int
#define EN_INTR_RET(X) return(X)
#if defined(__NetBSD__) || defined(__OpenBSD__)
#define EN_IOCTL_CMDT u_long
#elif defined(__bsdi__)
#define EN_IOCTL_CMDT int
#ifndef EN_MAX_DMASEG
#define EN_MAX_DMASEG 32
#endif
#elif defined(__FreeBSD__)
/* number of bytes to use in the first receive buffer. This must not be larger
* than MHLEN, should be a multiple of 64 and must be a multiple of 4. */
#define EN_RX1BUF 128
#define EN_INTR_TYPE void
#define EN_INTR_RET(X) return
#define EN_IOCTL_CMDT u_long
/*
* Structure to hold DMA maps. These are handle via a typestable uma zone.
*/
struct en_map {
uintptr_t flags; /* map flags */
struct en_map *rsvd2; /* see uma_zalloc(9) */
struct en_softc *sc; /* back pointer */
bus_dmamap_t map; /* the map */
};
#define ENMAP_LOADED 0x02
#define ENMAP_ALLOC 0x01
struct midway_device {
char dv_xname[IFNAMSIZ];
#define EN_MAX_MAPS 400
/*
* Statistics
*/
struct en_stats {
uint32_t vtrash; /* sw copy of counter */
uint32_t otrash; /* sw copy of counter */
uint32_t ttrash; /* # of RBD's with T bit set */
uint32_t mfixaddr; /* # of times we had to mfix an address */
uint32_t mfixlen; /* # of times we had to mfix a lenght*/
uint32_t mfixfail; /* # of times mfix failed */
uint32_t txmbovr; /* # of times we dropped due to mbsize */
uint32_t dmaovr; /* tx dma overflow count */
uint32_t txoutspace; /* out of space in xmit buffer */
uint32_t txdtqout; /* out of DTQs */
uint32_t launch; /* total # of launches */
uint32_t hwpull; /* # of pulls off hardware service list */
uint32_t swadd; /* # of pushes on sw service list */
uint32_t rxqnotus; /* # of times we pull from rx q, but fail */
uint32_t rxqus; /* # of good pulls from rx q */
uint32_t rxdrqout; /* # of times out of DRQs */
uint32_t rxmbufout; /* # of time out of mbufs */
uint32_t txnomap; /* out of DMA maps in TX */
};
#define DV_IFNET 1
/*
* Each of these structures describes one of the eight transmit channels
*/
struct en_txslot {
uint32_t mbsize; /* # mbuf bytes in use (max=TXHIWAT) */
uint32_t bfree; /* # free bytes in buffer */
uint32_t start; /* start of buffer area (byte offset) */
uint32_t stop; /* ends of buffer area (byte offset) */
uint32_t cur; /* next free area (byte offset) */
uint32_t nref; /* # of VCs using this channel */
struct ifqueue q; /* mbufs waiting for DMA now */
struct ifqueue indma; /* mbufs waiting for DMA now */
};
#endif
/*
* Each of these structures is used for each of the receive buffers on the
* card.
*/
struct en_rxslot {
void *rxhand; /* recv. handle for direct delivery */
uint32_t mode; /* saved copy of mode info */
uint32_t start; /* begin of my buffer area */
uint32_t stop; /* end of my buffer area */
uint32_t cur; /* where I am at in the buffer */
uint16_t atm_vci; /* backpointer to VCI */
uint8_t atm_flags; /* copy of atm_flags from atm_ph */
uint8_t oth_flags; /* other flags */
uint32_t raw_threshold; /* for raw mode */
struct ifqueue q; /* mbufs waiting for dma now */
struct ifqueue indma; /* mbufs being dma'd now */
};
/*
* softc
*/
struct en_softc {
/* bsd glue */
struct midway_device sc_dev; /* system device */
struct ifnet enif; /* network ifnet handle */
/* bsd glue */
struct ifnet enif; /* network ifnet handle */
device_t dev;
/* bus glue */
bus_space_tag_t en_memt; /* for EN_READ/EN_WRITE */
bus_space_handle_t en_base; /* base of en card */
bus_size_t en_obmemsz; /* size of en card (bytes) */
void (*en_busreset)(void *);
/* bus specific reset function */
/* bus glue */
bus_space_tag_t en_memt; /* for EN_READ/EN_WRITE */
bus_space_handle_t en_base; /* base of en card */
bus_size_t en_obmemsz; /* size of en card (bytes) */
void (*en_busreset)(void *); /* bus specific reset function */
bus_dma_tag_t txtag; /* TX DMA tag */
/* serv list */
u_int32_t hwslistp; /* hw pointer to service list (byte offset) */
u_int16_t swslist[MID_SL_N]; /* software service list (see en_service()) */
u_int16_t swsl_head, /* ends of swslist (index into swslist) */
swsl_tail;
u_int32_t swsl_size; /* # of items in swsl */
/* serv list */
uint32_t hwslistp; /* hw pointer to service list (byte offset) */
uint16_t swslist[MID_SL_N]; /* software svc list (see en_service()) */
uint16_t swsl_head; /* ends of swslist (index into swslist) */
uint16_t swsl_tail;
uint32_t swsl_size; /* # of items in swsl */
/* xmit dma */
u_int32_t dtq[MID_DTQ_N]; /* sw copy of dma q (see ENIDQ macros) */
u_int32_t dtq_free; /* # of dtq's free */
u_int32_t dtq_us; /* software copy of our pointer (byte offset) */
u_int32_t dtq_chip; /* chip's pointer (byte offset) */
u_int32_t need_dtqs; /* true if we ran out of DTQs */
/* xmit dma */
uint32_t dtq[MID_DTQ_N];/* sw copy of dma q (see EN_DQ_MK macros) */
uint32_t dtq_free; /* # of dtq's free */
uint32_t dtq_us; /* software copy of our pointer (byte offset) */
uint32_t dtq_chip; /* chip's pointer (byte offset) */
uint32_t need_dtqs; /* true if we ran out of DTQs */
/* recv dma */
u_int32_t drq[MID_DRQ_N]; /* sw copy of dma q (see ENIDQ macros) */
u_int32_t drq_free; /* # of drq's free */
u_int32_t drq_us; /* software copy of our pointer (byte offset) */
u_int32_t drq_chip; /* chip's pointer (byte offset) */
u_int32_t need_drqs; /* true if we ran out of DRQs */
/* recv dma */
uint32_t drq[MID_DRQ_N];/* sw copy of dma q (see ENIDQ macros) */
uint32_t drq_free; /* # of drq's free */
uint32_t drq_us; /* software copy of our pointer (byte offset) */
uint32_t drq_chip; /* chip's pointer (byte offset) */
uint32_t need_drqs; /* true if we ran out of DRQs */
/* xmit buf ctrl. (per channel) */
struct {
u_int32_t mbsize; /* # mbuf bytes we are using (max=TXHIWAT) */
u_int32_t bfree; /* # free bytes in buffer (not dma or xmit) */
u_int32_t start, stop; /* ends of buffer area (byte offset) */
u_int32_t cur; /* next free area (byte offset) */
u_int32_t nref; /* # of VCs using this channel */
struct ifqueue indma; /* mbufs being dma'd now */
struct ifqueue q; /* mbufs waiting for dma now */
} txslot[MID_NTX_CH];
/* xmit buf ctrl. (per channel) */
struct en_txslot txslot[MID_NTX_CH];
/* xmit vc ctrl. (per vc) */
u_int8_t txspeed[MID_N_VC]; /* speed of tx on a VC */
u_int8_t txvc2slot[MID_N_VC]; /* map VC to slot */
/* xmit vc ctrl. (per vc) */
uint8_t txspeed[MID_N_VC]; /* speed of tx on a VC */
uint8_t txvc2slot[MID_N_VC]; /* map VC to slot */
/* recv vc ctrl. (per vc). maps VC number to recv slot */
u_int16_t rxvc2slot[MID_N_VC];
int en_nrx; /* # of active rx slots */
/* recv vc ctrl. (per vc). maps VC number to recv slot */
uint16_t rxvc2slot[MID_N_VC];
int en_nrx; /* # of active rx slots */
/* recv buf ctrl. (per recv slot) */
struct {
void *rxhand; /* recv. handle if doing direct delivery */
u_int32_t mode; /* saved copy of mode info */
u_int32_t start, stop; /* ends of my buffer area */
u_int32_t cur; /* where I am at */
u_int16_t atm_vci; /* backpointer to VCI */
u_int8_t atm_flags; /* copy of atm_flags from atm_ph */
u_int8_t oth_flags; /* other flags */
u_int32_t raw_threshold; /* for raw mode */
struct ifqueue indma; /* mbufs being dma'd now */
struct ifqueue q; /* mbufs waiting for dma now */
} rxslot[EN_MAXNRX]; /* recv info */
/* recv buf ctrl. (per recv slot) */
struct en_rxslot rxslot[EN_MAXNRX];
u_int8_t macaddr[6]; /* card unique mac address */
/* stats */
struct en_stats stats;
/* stats */
u_int32_t vtrash; /* sw copy of counter */
u_int32_t otrash; /* sw copy of counter */
u_int32_t ttrash; /* # of RBD's with T bit set */
u_int32_t mfix; /* # of times we had to call mfix */
u_int32_t mfixfail; /* # of times mfix failed */
u_int32_t headbyte; /* # of times we used BYTE DMA at front */
u_int32_t tailbyte; /* # of times we used BYTE DMA at end */
u_int32_t tailflush; /* # of times we had to FLUSH out DMA bytes */
u_int32_t txmbovr; /* # of times we dropped due to mbsize */
u_int32_t dmaovr; /* tx dma overflow count */
u_int32_t txoutspace; /* out of space in xmit buffer */
u_int32_t txdtqout; /* out of DTQs */
u_int32_t launch; /* total # of launches */
u_int32_t lheader; /* # of launches without OB header */
u_int32_t ltail; /* # of launches without OB tail */
u_int32_t hwpull; /* # of pulls off hardware service list */
u_int32_t swadd; /* # of pushes on sw service list */
u_int32_t rxqnotus; /* # of times we pull from rx q, but fail */
u_int32_t rxqus; /* # of good pulls from rx q */
u_int32_t rxoutboth; /* # of times out of mbufs and DRQs */
u_int32_t rxdrqout; /* # of times out of DRQs */
u_int32_t rxmbufout; /* # of time out of mbufs */
/* random stuff */
uint32_t ipl; /* sbus interrupt lvl (1 on pci?) */
uint8_t bestburstcode; /* code of best burst we can use */
uint8_t bestburstlen; /* length of best burst (bytes) */
uint8_t bestburstshift; /* (x >> shift) == (x / bestburstlen) */
uint8_t bestburstmask; /* bits to check if not multiple of burst */
uint8_t alburst; /* align dma bursts? */
uint8_t noalbursts; /* don't use unaligned > 4 byte bursts */
uint8_t is_adaptec; /* adaptec version of midway? */
struct mbuf *padbuf; /* buffer of zeros for TX padding */
/* random stuff */
u_int32_t ipl; /* sbus interrupt lvl (1 on pci?) */
u_int8_t bestburstcode; /* code of best burst we can use */
u_int8_t bestburstlen; /* length of best burst (bytes) */
u_int8_t bestburstshift; /* (x >> shift) == (x / bestburstlen) */
u_int8_t bestburstmask; /* bits to check if not multiple of burst */
u_int8_t alburst; /* align dma bursts? */
u_int8_t is_adaptec; /* adaptec version of midway? */
/* mutex to protect this structure and the associated hardware */
struct mtx en_mtx;
/* sysctl support */
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *sysctl_tree;
/* memory zones */
uma_zone_t map_zone;
/* board info */
uint8_t macaddr[6];
uint32_t serial;
#ifdef EN_DEBUG
/* debugging */
u_int debug;
#endif
};
/*
* exported functions
*/
void en_attach(struct en_softc *);
EN_INTR_TYPE en_intr(void *);
int en_attach(struct en_softc *);
void en_destroy(struct en_softc *);
void en_intr(void *);
void en_reset(struct en_softc *);

View File

@ -30,6 +30,7 @@ SUBDIR= accf_data \
de \
digi \
dummynet \
en \
fdc \
fdescfs \
firewire \

20
sys/modules/en/Makefile Normal file
View File

@ -0,0 +1,20 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../pci ${.CURDIR}/../../dev/en
KMOD= if_en
SRCS= if_en_pci.c midway.c device_if.h bus_if.h pci_if.h
SRCS+= opt_inet.h opt_natm.h opt_ddb.h
CFLAGS+= -DENABLE_BPF
# CFLAGS+= -DINVARIANTS -DEN_DEBUG=0
opt_inet.h:
echo "#define INET 1" > ${.TARGET}
opt_natm.h:
echo "#define NATM 1" > ${.TARGET}
# opt_ddb.h:
# echo "#define DDB 1" > ${.TARGET}
.include <bsd.kmod.mk>

View File

@ -44,18 +44,21 @@
* FreeBSD PCI glue for the eni155p card.
* thanks to Matt Thomas for figuring out FreeBSD vs NetBSD vs etc.. diffs.
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <vm/uma.h>
#include <net/if.h>
#include <net/if_atm.h>
#include <pci/pcivar.h>
#include <pci/pcireg.h>
@ -63,61 +66,44 @@
#include <dev/en/midwayreg.h>
#include <dev/en/midwayvar.h>
/*
* prototypes
*/
static int en_pci_probe(device_t);
static int en_pci_attach(device_t);
static int en_pci_detach(device_t);
static int en_pci_shutdown(device_t);
/*
* local structures
*/
struct en_pci_softc {
/* bus independent stuff */
struct en_softc esc; /* includes "device" structure */
/* bus independent stuff */
struct en_softc esc; /* includes "device" structure */
/* freebsd newbus glue */
struct resource *res; /* resource descriptor for registers */
struct resource *irq; /* resource descriptor for interrupt */
void *ih; /* interrupt handle */
/* freebsd newbus glue */
struct resource *res; /* resource descriptor for registers */
struct resource *irq; /* resource descriptor for interrupt */
void *ih; /* interrupt handle */
};
#if !defined(MIDWAY_ENIONLY)
static void eni_get_macaddr(device_t, struct en_pci_softc *);
#endif
#if !defined(MIDWAY_ADPONLY)
static void adp_get_macaddr(struct en_pci_softc *);
#endif
/*
* local defines (PCI specific stuff)
*/
/*
* address of config base memory address register in PCI config space
* (this is card specific)
*/
#define PCI_CBMA 0x10
/*
* tonga (pci bridge). ENI cards only!
*/
#define EN_TONGA 0x60 /* PCI config addr of tonga reg */
#define TONGA_SWAP_DMA 0x80 /* endian swap control */
#define TONGA_SWAP_BYTE 0x40
#define TONGA_SWAP_WORD 0x20
#define TONGA_READ_MULT 0x00
#define TONGA_READ_MEM 0x04
#define TONGA_READ_IVAN 0x08
#define TONGA_READ_KEN 0x0C
/*
* adaptec pci bridge. ADP cards only!
*/
#define ADP_PCIREG 0x050040 /* PCI control register */
#define ADP_PCIREG_RESET 0x1 /* reset card */
@ -134,187 +120,184 @@ static void adp_get_macaddr(struct en_pci_softc *);
#define PCI_VENDOR(x) ((x) & 0xFFFF)
#define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF)
#if !defined(MIDWAY_ENIONLY)
static void adp_busreset(void *);
/*
* bus specific reset function [ADP only!]
*/
static void adp_busreset(v)
void *v;
static void
adp_busreset(void *v)
{
struct en_softc *sc = (struct en_softc *) v;
u_int32_t dummy;
struct en_softc *sc = (struct en_softc *)v;
uint32_t dummy;
bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG, ADP_PCIREG_RESET);
DELAY(1000); /* let it reset */
dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG,
(ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA|ADP_PCIREG_IENABLE));
dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
if ((dummy & (ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA)) !=
(ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA))
printf("adp_busreset: Adaptec ATM did NOT reset!\n");
bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG,
ADP_PCIREG_RESET);
DELAY(1000); /* let it reset */
dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG,
(ADP_PCIREG_SWAP_DMA | ADP_PCIREG_IENABLE));
dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
if ((dummy & (ADP_PCIREG_SWAP_WORD | ADP_PCIREG_SWAP_DMA)) !=
ADP_PCIREG_SWAP_DMA)
if_printf(&sc->enif, "adp_busreset: Adaptec ATM did "
"NOT reset!\n");
}
#endif
/***********************************************************************/
/*
* autoconfig stuff
*/
static int
en_pci_probe(device_t dev)
{
switch (pci_get_vendor(dev)) {
#if !defined(MIDWAY_ADPONLY)
case PCI_VENDOR_EFFICIENTNETS:
switch (pci_get_device(dev)) {
case PCI_PRODUCT_EFFICIENTNETS_ENI155PF:
case PCI_PRODUCT_EFFICIENTNETS_ENI155PA:
device_set_desc(dev, "Efficient Networks ENI-155p");
return 0;
}
break;
#endif
#if !defined(MIDWAY_ENIONLY)
case PCI_VENDOR_ADP:
switch (pci_get_device(dev)) {
case PCI_PRODUCT_ADP_AIC5900:
case PCI_PRODUCT_ADP_AIC5905:
device_set_desc(dev, "Adaptec 155 ATM");
return 0;
}
break;
#endif
}
return ENXIO;
switch (pci_get_vendor(dev)) {
case PCI_VENDOR_EFFICIENTNETS:
switch (pci_get_device(dev)) {
case PCI_PRODUCT_EFFICIENTNETS_ENI155PF:
case PCI_PRODUCT_EFFICIENTNETS_ENI155PA:
device_set_desc(dev, "Efficient Networks ENI-155p");
return (0);
}
break;
case PCI_VENDOR_ADP:
switch (pci_get_device(dev)) {
case PCI_PRODUCT_ADP_AIC5900:
case PCI_PRODUCT_ADP_AIC5905:
device_set_desc(dev, "Adaptec 155 ATM");
return (0);
}
break;
}
return (ENXIO);
}
static int
en_pci_attach(device_t dev)
{
struct en_softc *sc;
struct en_pci_softc *scp;
u_long val;
int rid, s, unit, error = 0;
struct en_softc *sc;
struct en_pci_softc *scp;
u_long val;
int rid, unit, error = 0;
sc = device_get_softc(dev);
scp = (struct en_pci_softc *)sc;
bzero(scp, sizeof(*scp)); /* zero */
sc = device_get_softc(dev);
scp = (struct en_pci_softc *)sc;
s = splimp();
unit = device_get_unit(dev);
sc->enif.if_unit = unit;
sc->enif.if_name = "en";
/*
* Enable bus mastering.
*/
val = pci_read_config(dev, PCIR_COMMAND, 2);
val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
pci_write_config(dev, PCIR_COMMAND, val, 2);
/*
* Enable bus mastering.
*/
val = pci_read_config(dev, PCIR_COMMAND, 2);
val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
pci_write_config(dev, PCIR_COMMAND, val, 2);
/*
* Map control/status registers.
*/
rid = PCI_CBMA;
scp->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
0, ~0, 1, RF_ACTIVE);
if (!scp->res) {
device_printf(dev, "could not map memory\n");
error = ENXIO;
goto fail;
}
/*
* Map control/status registers.
*/
rid = PCI_CBMA;
scp->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
0, ~0, 1, RF_ACTIVE);
if (scp->res == NULL) {
device_printf(dev, "could not map memory\n");
error = ENXIO;
goto fail;
}
sc->en_memt = rman_get_bustag(scp->res);
sc->en_base = rman_get_bushandle(scp->res);
/*
* Allocate our interrupt.
*/
rid = 0;
scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
RF_SHAREABLE | RF_ACTIVE);
if (scp->irq == NULL) {
device_printf(dev, "could not map interrupt\n");
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
error = ENXIO;
goto fail;
}
sc->dev = dev;
sc->en_memt = rman_get_bustag(scp->res);
sc->en_base = rman_get_bushandle(scp->res);
error = bus_setup_intr(dev, scp->irq, INTR_TYPE_NET,
en_intr, sc, &scp->ih);
if (error) {
device_printf(dev, "could not setup irq\n");
bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
goto fail;
}
sc->ipl = 1; /* XXX (required to enable interrupt on midway) */
/*
* Allocate our interrupt.
*/
rid = 0;
scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
RF_SHAREABLE | RF_ACTIVE);
if (scp->irq == NULL) {
device_printf(dev, "could not map interrupt\n");
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
error = ENXIO;
goto fail;
}
unit = device_get_unit(dev);
snprintf(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname), "en%d", unit);
sc->enif.if_unit = unit;
sc->enif.if_name = "en";
sc->ipl = 1; /* XXX (required to enable interrupt on midway) */
/* figure out if we are an adaptec card or not */
sc->is_adaptec = (pci_get_vendor(dev) == PCI_VENDOR_ADP) ? 1 : 0;
/*
* set up pci bridge
*/
#if !defined(MIDWAY_ENIONLY)
if (sc->is_adaptec) {
adp_get_macaddr(scp);
sc->en_busreset = adp_busreset;
adp_busreset(sc);
}
#endif
/* figure out if we are an adaptec card or not */
sc->is_adaptec = (pci_get_vendor(dev) == PCI_VENDOR_ADP) ? 1 : 0;
#if !defined(MIDWAY_ADPONLY)
if (!sc->is_adaptec) {
eni_get_macaddr(dev, scp);
sc->en_busreset = NULL;
pci_write_config(dev, EN_TONGA, (TONGA_SWAP_DMA|TONGA_SWAP_WORD), 4);
}
#endif
/*
* set up pci bridge
*/
if (sc->is_adaptec) {
adp_get_macaddr(scp);
sc->en_busreset = adp_busreset;
adp_busreset(sc);
} else {
eni_get_macaddr(dev, scp);
sc->en_busreset = NULL;
pci_write_config(dev, EN_TONGA, TONGA_SWAP_DMA | TONGA_READ_IVAN, 4);
}
/*
* done PCI specific stuff
*/
/*
* Common attach stuff
*/
if ((error = en_attach(sc)) != 0) {
device_printf(dev, "attach failed\n");
bus_teardown_intr(dev, scp->irq, scp->ih);
bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
goto fail;
}
en_attach(sc);
/*
* Do the interrupt SETUP last just before returning
*/
error = bus_setup_intr(dev, scp->irq, INTR_TYPE_NET,
en_intr, sc, &scp->ih);
if (error) {
en_reset(sc);
if_detach(&sc->enif);
device_printf(dev, "could not setup irq\n");
bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
en_destroy(sc);
goto fail;
}
splx(s);
return (0);
return 0;
fail:
splx(s);
return error;
fail:
return (error);
}
/*
* Detach the adapter
*/
static int
en_pci_detach(device_t dev)
{
struct en_softc *sc = device_get_softc(dev);
struct en_pci_softc *scp = (struct en_pci_softc *)sc;
int s;
s = splimp();
/*
* Close down routes etc.
*/
if_detach(&sc->enif);
/*
* Stop DMA and drop transmit queue.
*/
if ((sc->enif.if_flags & IFF_RUNNING)) {
if_printf(&sc->enif, "still running\n");
sc->enif.if_flags &= ~IFF_RUNNING;
}
/*
* Close down routes etc.
*/
en_reset(sc);
if_detach(&sc->enif);
/*
* Deallocate resources.
@ -323,146 +306,157 @@ en_pci_detach(device_t dev)
bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
#ifdef notyet
/*
* Free all the driver internal resources
*/
#endif
en_destroy(sc);
splx(s);
return 0;
return (0);
}
static int
en_pci_shutdown(device_t dev)
{
struct en_pci_softc *psc = (struct en_pci_softc *)device_get_softc(dev);
struct en_pci_softc *psc = device_get_softc(dev);
en_reset(&psc->esc);
DELAY(10); /* is this necessary? */
return (0);
en_reset(&psc->esc);
DELAY(10); /* is this necessary? */
return (0);
}
#if !defined(MIDWAY_ENIONLY)
#if defined(sparc)
#define bus_space_read_1(t, h, o) \
((void)t, (*(volatile u_int8_t *)((h) + (o))))
#endif
/*
* Get the MAC address from an Adaptec board. No idea how to get
* serial number or other stuff, because I have no documentation for that
* card.
*/
static void
adp_get_macaddr(scp)
struct en_pci_softc *scp;
adp_get_macaddr(struct en_pci_softc *scp)
{
struct en_softc * sc = (struct en_softc *)scp;
int lcv;
struct en_softc * sc = (struct en_softc *)scp;
int lcv;
for (lcv = 0; lcv < sizeof(sc->macaddr); lcv++)
sc->macaddr[lcv] = bus_space_read_1(sc->en_memt, sc->en_base,
MID_ADPMACOFF + lcv);
for (lcv = 0; lcv < sizeof(sc->macaddr); lcv++)
sc->macaddr[lcv] = bus_space_read_1(sc->en_memt, sc->en_base,
MID_ADPMACOFF + lcv);
}
#endif /* MIDWAY_ENIONLY */
#if !defined(MIDWAY_ADPONLY)
/*
* Read station (MAC) address from serial EEPROM.
* derived from linux drivers/atm/eni.c by Werner Almesberger, EPFL LRC.
*/
#define EN_PROM_MAGIC 0x0c
#define EN_PROM_DATA 0x02
#define EN_PROM_CLK 0x01
#define EN_ESI 64
#define EN_PROM_MAGIC 0x0c
#define EN_PROM_DATA 0x02
#define EN_PROM_CLK 0x01
#define EN_ESI 64
#define EN_SERIAL 112
/*
* Read a byte from the given address in the EEPROM
*/
static uint8_t
eni_get_byte(device_t dev, uint32_t *data, u_int address)
{
int j;
uint8_t tmp;
address = (address << 1) + 1;
/* start operation */
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data &= ~EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
/* send address with serial line */
for ( j = 7 ; j >= 0 ; j --) {
*data = ((address >> j) & 1) ? (*data | EN_PROM_DATA) :
(*data & ~EN_PROM_DATA);
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
}
/* get ack */
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data = pci_read_config(dev, EN_TONGA, 4);
*data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
tmp = 0;
for ( j = 7 ; j >= 0 ; j --) {
tmp <<= 1;
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data = pci_read_config(dev, EN_TONGA, 4);
if(*data & EN_PROM_DATA) tmp |= 1;
*data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
}
/* get ack */
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data = pci_read_config(dev, EN_TONGA, 4);
*data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, *data, 4);
*data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, *data, 4);
return (tmp);
}
/*
* Get MAC address and other stuff from the EEPROM
*/
static void
eni_get_macaddr(device_t dev, struct en_pci_softc *scp)
{
struct en_softc * sc = (struct en_softc *)scp;
int i, j, address, status;
u_int32_t data, t_data;
u_int8_t tmp;
t_data = pci_read_config(dev, EN_TONGA, 4) & 0xffffff00;
struct en_softc * sc = (struct en_softc *)scp;
int i;
uint32_t data, t_data;
data = EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK;
pci_write_config(dev, EN_TONGA, data, 4);
t_data = pci_read_config(dev, EN_TONGA, 4) & 0xffffff00;
for (i = 0; i < sizeof(sc->macaddr); i ++){
/* start operation */
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data &= ~EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
/* send address with serial line */
address = ((i + EN_ESI) << 1) + 1;
for ( j = 7 ; j >= 0 ; j --){
data = (address >> j) & 1 ? data | EN_PROM_DATA :
data & ~EN_PROM_DATA;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
}
/* get ack */
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data = pci_read_config(dev, EN_TONGA, 4);
status = data & EN_PROM_DATA;
data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data = EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK;
pci_write_config(dev, EN_TONGA, data, 4);
tmp = 0;
for (i = 0; i < sizeof(sc->macaddr); i ++)
sc->macaddr[i] = eni_get_byte(dev, &data, i + EN_ESI);
for ( j = 7 ; j >= 0 ; j --){
tmp <<= 1;
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data = pci_read_config(dev, EN_TONGA, 4);
if(data & EN_PROM_DATA) tmp |= 1;
data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
}
/* get ack */
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data = pci_read_config(dev, EN_TONGA, 4);
status = data & EN_PROM_DATA;
data &= ~EN_PROM_CLK ;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_DATA ;
pci_write_config(dev, EN_TONGA, data, 4);
sc->macaddr[i] = tmp;
}
/* stop operation */
data &= ~EN_PROM_DATA;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_DATA;
pci_write_config(dev, EN_TONGA, data, 4);
pci_write_config(dev, EN_TONGA, t_data, 4);
sc->serial = 0;
for (i = 0; i < 4; i++) {
sc->serial <<= 8;
sc->serial |= eni_get_byte(dev, &data, i + EN_SERIAL);
}
/* stop operation */
data &= ~EN_PROM_DATA;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_CLK;
pci_write_config(dev, EN_TONGA, data, 4);
data |= EN_PROM_DATA;
pci_write_config(dev, EN_TONGA, data, 4);
pci_write_config(dev, EN_TONGA, t_data, 4);
}
#endif /* !MIDWAY_ADPONLY */
/*
* Driver infrastructure
*/
static device_method_t en_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, en_pci_probe),
@ -482,4 +476,3 @@ static driver_t en_driver = {
static devclass_t en_devclass;
DRIVER_MODULE(en, pci, en_driver, en_devclass, 0, 0);