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:
parent
d8ca78d02f
commit
33cfde03bc
@ -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);
|
||||
|
||||
|
5679
sys/dev/en/midway.c
5679
sys/dev/en/midway.c
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
|
@ -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 *);
|
||||
|
@ -30,6 +30,7 @@ SUBDIR= accf_data \
|
||||
de \
|
||||
digi \
|
||||
dummynet \
|
||||
en \
|
||||
fdc \
|
||||
fdescfs \
|
||||
firewire \
|
||||
|
20
sys/modules/en/Makefile
Normal file
20
sys/modules/en/Makefile
Normal 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>
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user