diff options
Diffstat (limited to 'sys/pci')
54 files changed, 3400 insertions, 20235 deletions
diff --git a/sys/pci/adv_pci.c b/sys/pci/adv_pci.c index dd81e881d686..2f9e4e1eb712 100644 --- a/sys/pci/adv_pci.c +++ b/sys/pci/adv_pci.c @@ -47,7 +47,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: adv_pci.c,v 1.3 1998/12/14 06:32:54 dillon Exp $ + * $Id$ */ #include <pci.h> @@ -76,16 +76,16 @@ #define ADV_PCI_MAX_DMA_ADDR (0xFFFFFFFFL) #define ADV_PCI_MAX_DMA_COUNT (0xFFFFFFFFL) -static const char* advpciprobe(pcici_t tag, pcidi_t type); +static char* advpciprobe(pcici_t tag, pcidi_t type); static void advpciattach(pcici_t config_id, int unit); /* * The overrun buffer shared amongst all PCI adapters. */ static u_int8_t* overrun_buf; -static bus_dma_tag_t overrun_dmat; -static bus_dmamap_t overrun_dmamap; -static bus_addr_t overrun_physbase; +bus_dma_tag_t overrun_dmat; +bus_dmamap_t overrun_dmamap; +bus_addr_t overrun_physbase; static struct pci_device adv_pci_driver = { "adv", @@ -97,7 +97,7 @@ static struct pci_device adv_pci_driver = { DATA_SET (pcidevice_set, adv_pci_driver); -static const char* +static char* advpciprobe(pcici_t tag, pcidi_t type) { int rev = pci_conf_read(tag, PCI_CLASS_REG) & 0xff; @@ -122,6 +122,7 @@ static void advpciattach(pcici_t config_id, int unit) { u_int16_t io_port; + u_int16_t config_msw; struct adv_softc *adv; u_int32_t id; u_int32_t command; @@ -251,13 +252,9 @@ advpciattach(pcici_t config_id, int unit) adv->max_dma_addr = ADV_PCI_MAX_DMA_ADDR; #if CC_DISABLE_PCI_PARITY_INT - { - u_int16_t config_msw; - - config_msw = ADV_INW(adv, ADV_CONFIG_MSW); - config_msw &= 0xFFC0; - ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); - } + config_msw = ADV_INW(adv, ADV_CONFIG_MSW); + config_msw &= 0xFFC0; + ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); #endif if (id == PCI_DEVICE_ID_ADVANSYS_1200A diff --git a/sys/pci/adw_pci.c b/sys/pci/adw_pci.c index b65037bdba6b..2109b91d1b0f 100644 --- a/sys/pci/adw_pci.c +++ b/sys/pci/adw_pci.c @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: adw_pci.c,v 1.2 1998/12/07 21:58:45 archie Exp $ + * $Id$ */ #include <pci.h> @@ -58,7 +58,7 @@ #define ADW_PCI_MAX_DMA_ADDR (0xFFFFFFFFUL) #define ADW_PCI_MAX_DMA_COUNT (0xFFFFFFFFUL) -static const char* adwpciprobe(pcici_t tag, pcidi_t type); +static char* adwpciprobe(pcici_t tag, pcidi_t type); static void adwpciattach(pcici_t config_id, int unit); static struct pci_device adw_pci_driver = { @@ -71,7 +71,7 @@ static struct pci_device adw_pci_driver = { DATA_SET (pcidevice_set, adw_pci_driver); -static const char* +static char* adwpciprobe(pcici_t tag, pcidi_t type) { switch (type) { @@ -89,9 +89,7 @@ adwpciattach(pcici_t config_id, int unit) u_int32_t id; u_int32_t command; vm_offset_t vaddr; -#ifdef ADW_ALLOW_MEMIO vm_offset_t paddr; -#endif u_int16_t io_port; bus_space_tag_t tag; bus_space_handle_t bsh; diff --git a/sys/pci/ahc_pci.c b/sys/pci/ahc_pci.c index e7d54f913248..344658de7a13 100644 --- a/sys/pci/ahc_pci.c +++ b/sys/pci/ahc_pci.c @@ -34,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ahc_pci.c,v 1.4 1998/12/14 05:47:25 dillon Exp $ + * $Id: ahc_pci.c,v 1.1 1998/09/15 07:25:33 gibbs Exp $ */ #include <pci.h> @@ -55,7 +55,6 @@ #include <cam/cam.h> #include <cam/cam_ccb.h> #include <cam/cam_sim.h> -#include <cam/cam_xpt_sim.h> #include <cam/scsi/scsi_all.h> @@ -139,7 +138,7 @@ static u_int8_t read_brdctl(struct ahc_softc *ahc); static struct ahc_softc *first_398X; -static const char* ahc_pci_probe(pcici_t tag, pcidi_t type); +static char* ahc_pci_probe(pcici_t tag, pcidi_t type); static void ahc_pci_attach(pcici_t config_id, int unit); /* Exported for use in the ahc_intr routine */ @@ -155,7 +154,7 @@ static struct pci_device ahc_pci_driver = { DATA_SET (pcidevice_set, ahc_pci_driver); -static const char* +static char* ahc_pci_probe (pcici_t tag, pcidi_t type) { switch (type) { @@ -1173,6 +1172,7 @@ void ahc_pci_intr(struct ahc_softc *ahc) { u_int8_t status1; + pcici_t config_id; status1 = pci_cfgread(ahc->pci_config_id, PCIR_STATUS + 1, /*bytes*/1); diff --git a/sys/pci/brktree_reg.h b/sys/pci/brktree_reg.h index b3f9efd48bf3..9ef9aae3e544 100644 --- a/sys/pci/brktree_reg.h +++ b/sys/pci/brktree_reg.h @@ -28,7 +28,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Id: brktree_reg.h,v 1.22 1998/09/30 21:06:54 sos Exp $ + * $Id$ */ #ifndef PCI_LATENCY_TIMER #define PCI_LATENCY_TIMER 0x0c /* pci timer register */ @@ -369,12 +369,6 @@ struct format_params { int iform_xtsel; }; -#ifdef __FreeBSD__ -struct bktr_i2c_softc { - device_t iicbus; - device_t smbus; -}; -#endif typedef struct bktr_clip bktr_clip_t; /* @@ -387,9 +381,6 @@ struct bktr_softc { struct intrhand bktr_ih; /* interrupt vectoring */ #define pcici_t pci_devaddr_t #endif -#ifdef __FreeBSD__ - struct bktr_i2c_softc i2c_sc; /* bt848_i2c device */ -#endif bt848_ptr_t base; /* Bt848 register physical address */ vm_offset_t phys_base; /* Bt848 register physical address */ pcici_t tag; /* PCI tag, for doing PCI commands */ diff --git a/sys/pci/brooktree848.c b/sys/pci/brooktree848.c index 7ad19534854a..2801499427dd 100644 --- a/sys/pci/brooktree848.c +++ b/sys/pci/brooktree848.c @@ -1,4 +1,4 @@ -/* $Id: brooktree848.c,v 1.60 1998/12/07 21:58:45 archie Exp $ */ +/* $Id$ */ /* BT848 Driver for Brooktree's Bt848 based cards. The Brooktree BT848 Driver driver is based upon Mark Tinguely and Jim Lowe's driver for the Matrox Meteor PCI card . The @@ -353,13 +353,7 @@ #include <machine/ioctl_meteor.h> #include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */ -#include <sys/bus.h> #include <pci/brktree_reg.h> -#include <pci/bt848_i2c.h> -#include <dev/smbus/smbconf.h> -#include <dev/iicbus/iiconf.h> -#include "smbus_if.h" -#include "iicbus_if.h" #include <sys/sysctl.h> static int bt848_card = -1; static int bt848_tuner = -1; @@ -438,7 +432,7 @@ static bktr_reg_t brooktree[ NBKTR ]; #define MINOR(x) ((x >> 4) & 0x0f) #define ATTACH_ARGS pcici_t tag, int unit -static const char* bktr_probe( pcici_t tag, pcidi_t type ); +static char* bktr_probe( pcici_t tag, pcidi_t type ); static void bktr_attach( ATTACH_ARGS ); static u_long bktr_count; @@ -1123,11 +1117,10 @@ static int readEEProm( bktr_ptr_t bktr, int offset, int count, #ifdef __FreeBSD__ - /* * the boot time probe routine. */ -static const char* +static char* bktr_probe( pcici_t tag, pcidi_t type ) { switch (type) { @@ -1146,6 +1139,8 @@ bktr_probe( pcici_t tag, pcidi_t type ) #endif /* __FreeBSD__ */ + + /* * the attach routine. */ @@ -1178,9 +1173,6 @@ bktr_attach( ATTACH_ARGS ) fun = pci_conf_read(tag, 0x40); pci_conf_write(tag, 0x40, fun | 1); - /* XXX call bt848_i2c dependent attach() routine */ - if (bt848_i2c_attach(unit, bktr->base, &bktr->i2c_sc)) - printf("bktr%d: i2c_attach: can't attach\n", unit); #ifdef BROOKTREE_IRQ /* from the configuration file */ old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG); @@ -1940,6 +1932,7 @@ bktr_ioctl( dev_t dev, ioctl_cmd_t cmd, caddr_t arg, int flag, struct proc* pr ) static int video_ioctl( bktr_ptr_t bktr, int unit, int cmd, caddr_t arg, struct proc* pr ) { + int tmp_int; bt848_ptr_t bt848; volatile u_char c_temp; unsigned int temp; @@ -1950,6 +1943,7 @@ video_ioctl( bktr_ptr_t bktr, int unit, int cmd, caddr_t arg, struct proc* pr ) struct meteor_video *video; struct bktr_capture_area *cap_area; vm_offset_t buf; + struct format_params *fp; int i; char char_temp; @@ -2998,7 +2992,7 @@ common_ioctl( bktr_ptr_t bktr, bt848_ptr_t bt848, int cmd, caddr_t arg ) * */ int -bktr_mmap( dev_t dev, vm_offset_t offset, int nprot ) +bktr_mmap( dev_t dev, int offset, int nprot ) { int unit; bktr_ptr_t bktr; @@ -4167,55 +4161,6 @@ static int oformat_meteor_to_bt( u_long format ) BT848_DATA_CTL_I2CSCL | \ BT848_DATA_CTL_I2CSDA) -#if defined(__FreeBSD__) - -/* - * The hardware interface is actually SMB commands - */ -static int -i2cWrite( bktr_ptr_t bktr, int addr, int byte1, int byte2 ) -{ - char cmd; - - if (bktr->id == BROOKTREE_848_ID || - bktr->id == BROOKTREE_849_ID) - cmd = I2C_COMMAND; - else - cmd = I2C_COMMAND_878; - - if (byte2 != -1) { - if (smbus_writew(bktr->i2c_sc.smbus, addr, cmd, - (short)(((byte2 & 0xff) << 8) | (byte1 & 0xff)))) - return (-1); - } else { - if (smbus_writeb(bktr->i2c_sc.smbus, addr, cmd, - (char)(byte1 & 0xff))) - return (-1); - } - - /* return OK */ - return( 0 ); -} - -static int -i2cRead( bktr_ptr_t bktr, int addr ) -{ - char result; - char cmd; - - if (bktr->id == BROOKTREE_848_ID || - bktr->id == BROOKTREE_849_ID) - cmd = I2C_COMMAND; - else - cmd = I2C_COMMAND_878; - - if (smbus_readb(bktr->i2c_sc.smbus, addr, cmd, &result)) - return (-1); - - return ((int)result); -} - -#else /* defined(__FreeBSD__) */ /* * @@ -4300,8 +4245,6 @@ i2cRead( bktr_ptr_t bktr, int addr ) return( (bt848->i2c_data_ctl >> 8) & 0xff ); } -#endif /* !define(__FreeBSD__) */ - #if defined( I2C_SOFTWARE_PROBE ) /* @@ -4418,8 +4361,6 @@ readEEProm( bktr_ptr_t bktr, int offset, int count, u_char *data ) return( 0 ); } -#define ABSENT (-1) - /* * get a signature of the card * read all 128 possible i2c read addresses from 0x01 thru 0xff @@ -4427,6 +4368,7 @@ readEEProm( bktr_ptr_t bktr, int offset, int count, u_char *data ) * * XXX FIXME: use offset & count args */ +#define ABSENT (-1) static int signCard( bktr_ptr_t bktr, int offset, int count, u_char* sig ) { @@ -4482,6 +4424,8 @@ static int locate_tuner_address( bktr_ptr_t bktr) { if (i2cRead( bktr, 0xc7) != ABSENT) return 0xc6; return -1; /* no tuner found */ } + +#undef ABSENT /* * determine the card brand/model @@ -4489,11 +4433,12 @@ static int locate_tuner_address( bktr_ptr_t bktr) { * can be used to select a specific device, regardless of the * autodetection and i2c device checks. */ +#define ABSENT (-1) static void probeCard( bktr_ptr_t bktr, int verbose ) { int card, i,j, card_found; - int status; + int status, *test; bt848_ptr_t bt848; u_char probe_signature[128], *probe_temp; int any_i2c_devices; @@ -4735,6 +4680,7 @@ checkMSP: checkEnd: +checkPLL: #if defined( BKTR_USE_PLL ) bktr->xtal_pll_mode = BT848_USE_PLL; goto checkPLLEnd; @@ -4745,9 +4691,7 @@ checkEnd: if ((card == CARD_HAUPPAUGE) && (bktr->id==BROOKTREE_878_ID || bktr->id==BROOKTREE_879_ID) ) bktr->xtal_pll_mode = BT848_USE_PLL; -#if defined( BKTR_USE_PLL ) checkPLLEnd: -#endif bktr->card.tuner_pllAddr = tuner_i2c_address; diff --git a/sys/pci/bt848_i2c.c b/sys/pci/bt848_i2c.c deleted file mode 100644 index 176d069a837f..000000000000 --- a/sys/pci/bt848_i2c.c +++ /dev/null @@ -1,412 +0,0 @@ -/*- - * Copyright (c) 1998 Nicolas Souchu - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: bt848_i2c.c,v 1.1 1998/10/31 11:26:38 nsouch Exp $ - * - */ - -/* - * I2C support for the bti2c chipset. - * - * From brooktree848.c <fsmp@freefall.org> - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/systm.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/buf.h> -#include <sys/uio.h> -#include <sys/malloc.h> - -#include <machine/clock.h> - -#include <pci/pcivar.h> -#include <pci/pcireg.h> -#include <machine/ioctl_meteor.h> -#include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */ -#include <pci/brktree_reg.h> - -#include <pci/bt848_i2c.h> - -#include <dev/iicbus/iiconf.h> -#include <dev/iicbus/iicbus.h> - -#include <dev/smbus/smbconf.h> - -#include "iicbb_if.h" -#include "smbus_if.h" - -#include "pci.h" -#include "bktr.h" - -#if (NBKTR > 0 && NPCI > 0) - -#define I2C_DELAY 40 - -#define BTI2C_DEBUG(x) if (bti2c_debug) (x) -static int bti2c_debug = 0; - -struct bti2c_softc { - - bt848_ptr_t base; - - int iic_owned; /* 1 if we own the iicbus */ - int smb_owned; /* 1 if we own the smbbus */ - - device_t smbus; - device_t iicbus; -}; - -struct bt_data { - bt848_ptr_t base; -}; -struct bt_data btdata[NBKTR]; - -static int bti2c_probe(device_t); -static int bti2c_attach(device_t); -static void bti2c_print_child(device_t, device_t); - -static int bti2c_iic_callback(device_t, int, caddr_t *); -static void bti2c_iic_setlines(device_t, int, int); -static int bti2c_iic_getdataline(device_t); -static int bti2c_iic_reset(device_t, u_char, u_char, u_char *); - -static int bti2c_smb_callback(device_t, int, caddr_t *); -static int bti2c_smb_writeb(device_t dev, u_char slave, char cmd, char byte); -static int bti2c_smb_writew(device_t dev, u_char slave, char cmd, short word); -static int bti2c_smb_readb(device_t dev, u_char slave, char cmd, char *byte); - -static devclass_t bti2c_devclass; - -static device_method_t bti2c_methods[] = { - /* device interface */ - DEVMETHOD(device_probe, bti2c_probe), - DEVMETHOD(device_attach, bti2c_attach), - - /* bus interface */ - DEVMETHOD(bus_print_child, bti2c_print_child), - - /* iicbb interface */ - DEVMETHOD(iicbb_callback, bti2c_iic_callback), - DEVMETHOD(iicbb_setlines, bti2c_iic_setlines), - DEVMETHOD(iicbb_getdataline, bti2c_iic_getdataline), - DEVMETHOD(iicbb_reset, bti2c_iic_reset), - - /* smbus interface */ - DEVMETHOD(smbus_callback, bti2c_smb_callback), - DEVMETHOD(smbus_writeb, bti2c_smb_writeb), - DEVMETHOD(smbus_writew, bti2c_smb_writew), - DEVMETHOD(smbus_readb, bti2c_smb_readb), - - { 0, 0 } -}; - -static driver_t bti2c_driver = { - "bti2c", - bti2c_methods, - DRIVER_TYPE_MISC, - sizeof(struct bti2c_softc), -}; - -/* - * Call this to pass the base address of the bktr device to the - * bti2c_i2c layer and initialize all the I2C bus architecture - */ -int -bt848_i2c_attach(int unit, bt848_ptr_t base, struct bktr_i2c_softc *i2c_sc) -{ - device_t interface; - device_t bitbang; - - btdata[unit].base = base; - - /* XXX add the I2C interface to the root_bus until pcibus is ready */ - interface = device_add_child(root_bus, "bti2c", unit, NULL); - - /* add bit-banging generic code onto bti2c interface */ - bitbang = device_add_child(interface, "iicbb", -1, NULL); - - /* probe and attach the interface, we need it NOW - * bit-banging code is also probed and attached */ - device_probe_and_attach(interface); - device_probe_and_attach(bitbang); - - /* smb and i2c interfaces are available for the bt848 chip - * connect bit-banging generic code to an iicbus */ - if ((i2c_sc->iicbus = iicbus_alloc_bus(bitbang))) - device_probe_and_attach(i2c_sc->iicbus); - - /* hardware i2c is actually smb over the bti2c interface */ - if ((i2c_sc->smbus = smbus_alloc_bus(interface))) - device_probe_and_attach(i2c_sc->smbus); - - return (0); -}; - -/* - * Not a real probe, we know the device exists since the device has - * been added after the successfull pci probe. - */ -static int -bti2c_probe(device_t dev) -{ - device_set_desc(dev, "bt848 Hard/Soft I2C controller"); - - return (0); -} - -static int -bti2c_attach(device_t dev) -{ - struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); - - /* XXX should use ivars with pcibus or pcibus methods to access - * onboard memory */ - sc->base = btdata[device_get_unit(dev)].base; - - return (0); -} - -static void -bti2c_print_child(device_t bus, device_t dev) -{ - printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); - - return; -} - -static int -bti2c_smb_callback(device_t dev, int index, caddr_t *data) -{ - struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); - int error = 0; - int how; - - /* test each time if we already have/haven't the iicbus - * to avoid deadlocks - */ - switch (index) { - case SMB_REQUEST_BUS: - if (!sc->iic_owned) { - /* request the iicbus */ - how = *(int *)data; - error = iicbus_request_bus(sc->iicbus, dev, how); - if (!error) - sc->iic_owned = 1; - } - break; - - case SMB_RELEASE_BUS: - if (sc->iic_owned) { - /* release the iicbus */ - error = iicbus_release_bus(sc->iicbus, dev); - if (!error) - sc->iic_owned = 0; - } - break; - - default: - error = EINVAL; - } - - return (error); -} - -static int -bti2c_iic_callback(device_t dev, int index, caddr_t *data) -{ - struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); - int error = 0; - int how; - - /* test each time if we already have/haven't the smbus - * to avoid deadlocks - */ - switch (index) { - case IIC_REQUEST_BUS: - if (!sc->smb_owned) { - /* request the smbus */ - how = *(int *)data; - error = smbus_request_bus(sc->smbus, dev, how); - if (!error) - sc->smb_owned = 1; - } - break; - - case IIC_RELEASE_BUS: - if (sc->smb_owned) { - /* release the smbus */ - error = smbus_release_bus(sc->smbus, dev); - if (!error) - sc->smb_owned = 0; - } - break; - - default: - error = EINVAL; - } - - return (error); -} - -static int -bti2c_iic_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr) -{ - if (oldaddr) - *oldaddr = 0; /* XXX */ - - return (IIC_ENOADDR); -} - -static void -bti2c_iic_setlines(device_t dev, int ctrl, int data) -{ - struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); - bt848_ptr_t bti2c; - - bti2c = sc->base; - - bti2c->i2c_data_ctl = (ctrl << 1) | data; - DELAY(I2C_DELAY); - - return; -} - -static int -bti2c_iic_getdataline(device_t dev) -{ - struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); - bt848_ptr_t bti2c; - - bti2c = sc->base; - - return (bti2c->i2c_data_ctl & 0x1); -} - -static int -bti2c_write(bt848_ptr_t bti2c, u_long data) -{ - u_long x; - - /* clear status bits */ - bti2c->int_stat = (BT848_INT_RACK | BT848_INT_I2CDONE); - - BTI2C_DEBUG(printf("w%lx", data)); - - /* write the address and data */ - bti2c->i2c_data_ctl = data; - - /* wait for completion */ - for ( x = 0x7fffffff; x; --x ) { /* safety valve */ - if ( bti2c->int_stat & BT848_INT_I2CDONE ) - break; - } - - /* check for ACK */ - if ( !x || !(bti2c->int_stat & BT848_INT_RACK) ) { - BTI2C_DEBUG(printf("%c%c", (!x)?'+':'-', - (!(bti2c->int_stat & BT848_INT_RACK))?'+':'-')); - return (SMB_ENOACK); - } - BTI2C_DEBUG(printf("+")); - - /* return OK */ - return( 0 ); -} - -static int -bti2c_smb_writeb(device_t dev, u_char slave, char cmd, char byte) -{ - struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); - u_long data; - - data = ((slave & 0xff) << 24) | ((byte & 0xff) << 16) | (u_char)cmd; - - return (bti2c_write(sc->base, data)); -} - -/* - * byte1 becomes low byte of word - * byte2 becomes high byte of word - */ -static int -bti2c_smb_writew(device_t dev, u_char slave, char cmd, short word) -{ - struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); - u_long data; - char low, high; - - low = (char)(word & 0xff); - high = (char)((word & 0xff00) >> 8); - - data = ((slave & 0xff) << 24) | ((low & 0xff) << 16) | - ((high & 0xff) << 8) | BT848_DATA_CTL_I2CW3B | (u_char)cmd; - - return (bti2c_write(sc->base, data)); -} - -/* - * The Bt878 and Bt879 differed on the treatment of i2c commands - */ -static int -bti2c_smb_readb(device_t dev, u_char slave, char cmd, char *byte) -{ - struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); - bt848_ptr_t bti2c; - u_long x; - - bti2c = sc->base; - - /* clear status bits */ - bti2c->int_stat = (BT848_INT_RACK | BT848_INT_I2CDONE); - - bti2c->i2c_data_ctl = ((slave & 0xff) << 24) | (u_char)cmd; - - BTI2C_DEBUG(printf("r%lx/", (u_long)(((slave & 0xff) << 24) | (u_char)cmd))); - - /* wait for completion */ - for ( x = 0x7fffffff; x; --x ) { /* safety valve */ - if ( bti2c->int_stat & BT848_INT_I2CDONE ) - break; - } - - /* check for ACK */ - if ( !x || !(bti2c->int_stat & BT848_INT_RACK) ) { - BTI2C_DEBUG(printf("r%c%c", (!x)?'+':'-', - (!(bti2c->int_stat & BT848_INT_RACK))?'+':'-')); - return (SMB_ENOACK); - } - - *byte = (char)((bti2c->i2c_data_ctl >> 8) & 0xff); - BTI2C_DEBUG(printf("r%x+", *byte)); - - return (0); -} - -DRIVER_MODULE(bti2c, root, bti2c_driver, bti2c_devclass, 0, 0); -#endif diff --git a/sys/pci/bt848_i2c.h b/sys/pci/bt848_i2c.h deleted file mode 100644 index c7d22c50484e..000000000000 --- a/sys/pci/bt848_i2c.h +++ /dev/null @@ -1,34 +0,0 @@ -/*- - * Copyright (c) 1998 Nicolas Souchu - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - * - */ -#ifndef _BT848_I2C_H -#define _BT848_I2C_H - -extern int bt848_i2c_attach(int, bt848_ptr_t, struct bktr_i2c_softc *); - -#endif diff --git a/sys/pci/bt_pci.c b/sys/pci/bt_pci.c index 3c886d86a462..028624592c29 100644 --- a/sys/pci/bt_pci.c +++ b/sys/pci/bt_pci.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: bt_pci.c,v 1.3 1998/11/10 06:45:14 gibbs Exp $ + * $Id$ */ #include "pci.h" @@ -53,7 +53,7 @@ static int btpcideterminebusspace(pcici_t config_id, bus_space_tag_t* tagp, bus_space_handle_t* bshp); -static const char* bt_pci_probe(pcici_t tag, pcidi_t type); +static char* bt_pci_probe(pcici_t tag, pcidi_t type); static void bt_pci_attach(pcici_t config_id, int unit); static struct pci_device bt_pci_driver = { @@ -98,7 +98,7 @@ btpcideterminebusspace(pcici_t config_id, bus_space_tag_t* tagp, return (0); } -static const char* +static char* bt_pci_probe (pcici_t config_id, pcidi_t type) { switch(type) { @@ -110,6 +110,7 @@ bt_pci_probe (pcici_t config_id, pcidi_t type) bus_space_handle_t bsh; pci_info_data_t pci_info; int error; + u_int8_t new_addr; if (btpcideterminebusspace(config_id, &tag, &bsh) != 0) break; @@ -121,8 +122,7 @@ bt_pci_probe (pcici_t config_id, pcidi_t type) /* * Determine if an ISA compatible I/O port has been * enabled. If so, record the port so it will not - * be probed by our ISA probe. If the PCI I/O port - * was not set to the compatibility port, disable it. + * be probed by our ISA probe, and disable the port. */ error = bt_cmd(bt, BOP_INQUIRE_PCI_INFO, /*param*/NULL, /*paramlen*/0, @@ -131,19 +131,14 @@ bt_pci_probe (pcici_t config_id, pcidi_t type) if (error == 0 && pci_info.io_port < BIO_DISABLED) { bt_mark_probed_bio(pci_info.io_port); - if (bsh != bt_iop_from_bio(pci_info.io_port)) { - u_int8_t new_addr; - - new_addr = BIO_DISABLED; - bt_cmd(bt, BOP_MODIFY_IO_ADDR, - /*param*/&new_addr, - /*paramlen*/1, /*reply_buf*/NULL, - /*reply_len*/0, - DEFAULT_CMD_TIMEOUT); - } } + + new_addr = BIO_DISABLED; + bt_cmd(bt, BOP_MODIFY_IO_ADDR, /*param*/&new_addr, + /*paramlen*/1, /*reply_buf*/NULL, /*reply_len*/0, + DEFAULT_CMD_TIMEOUT); bt_free(bt); - return ("Buslogic Multi-Master SCSI Host Adapter"); + return ("Buslogic Multimaster SCSI host adapter"); break; } default: diff --git a/sys/pci/cy_pci.c b/sys/pci/cy_pci.c index 7113155e7cb5..ae48965f69e6 100644 --- a/sys/pci/cy_pci.c +++ b/sys/pci/cy_pci.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: cy_pci.c,v 1.9 1999/01/11 23:43:54 bde Exp $ + * $Id: cy_pci.c,v 1.5 1997/02/22 09:44:00 peter Exp $ */ /* @@ -34,11 +34,8 @@ #include "pci.h" #if NPCI > 0 -#include "opt_cy_pci_fastintr.h" - #include <sys/param.h> #include <sys/systm.h> -#include <sys/interrupt.h> #include <sys/kernel.h> #include <vm/vm.h> #include <vm/pmap.h> @@ -47,7 +44,7 @@ #include <pci/cy_pcireg.h> -static const char *cy_probe __P((pcici_t, pcidi_t)); +static char *cy_probe __P((pcici_t, pcidi_t)); static void cy_attach __P((pcici_t, int)); extern int cyattach_common(void *, int); /* Not exactly correct */ @@ -64,7 +61,7 @@ static struct pci_device cy_device = { }; DATA_SET(pcidevice_set, cy_device); -static const char * +static char * cy_probe(config_id, device_id) pcici_t config_id; pcidi_t device_id; @@ -85,7 +82,6 @@ cy_attach(config_id, unit) void *vaddr; u_int32_t ioport; int adapter; - u_char plx_ver; ioport = (u_int32_t) pci_conf_read(config_id, CY_PCI_BASE_ADDR1) & ~0x3; paddr = pci_conf_read(config_id, CY_PCI_BASE_ADDR2) & ~0xf; @@ -115,37 +111,16 @@ cy_attach(config_id, unit) * since the ISA driver must handle the interrupt anyway, we use * the unit number as the token even for PCI. */ - if ( -#ifdef CY_PCI_FASTINTR - !pci_map_int_right(config_id, (pci_inthand_t *)cyintr, - (void *)adapter, &tty_imask, - INTR_EXCL | INTR_FAST) && -#endif - !pci_map_int_right(config_id, (pci_inthand_t *)cyintr, - (void *)adapter, &tty_imask, 0)) { + if (!pci_map_int(config_id, (pci_inthand_t *)cyintr, (void *)adapter, &tty_imask)) { printf("cy%d: couldn't map interrupt\n", unit); goto fail; } - /* * Enable the "local" interrupt input to generate a * PCI interrupt. */ - plx_ver = *((u_char *)vaddr + PLX_VER) & 0x0f; - switch (plx_ver) { - case PLX_9050: - outw(ioport + CY_PLX_9050_ICS, - inw(ioport + CY_PLX_9050_ICS) | CY_PLX_9050_ICS_IENABLE | - CY_PLX_9050_ICS_LOCAL_IENABLE); - break; - case PLX_9060: - case PLX_9080: - default: /* Old board, use PLX_9060 values. */ - outw(ioport + CY_PLX_9060_ICS, - inw(ioport + CY_PLX_9060_ICS) | CY_PLX_9060_ICS_IENABLE | - CY_PLX_9060_ICS_LOCAL_IENABLE); - break; - } + outw(ioport + CY_PLX_ICS, inw(ioport + CY_PLX_ICS) | + CY_PLX_ICS_IENABLE | CY_PLX_ICS_LOCAL_IENABLE); return; diff --git a/sys/pci/cy_pcireg.h b/sys/pci/cy_pcireg.h index cc3bb60eb004..412622fe422e 100644 --- a/sys/pci/cy_pcireg.h +++ b/sys/pci/cy_pcireg.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: cy_pcireg.h,v 1.4 1999/01/11 23:35:01 bde Exp $ + * $Id$ */ #define CY_VENDORID_CYCLADES 0x120e @@ -35,15 +35,6 @@ #define CY_PCI_BASE_ADDR1 0x14 #define CY_PCI_BASE_ADDR2 0x18 -#define CY_PLX_9050_ICS 0x4c -#define CY_PLX_9060_ICS 0x68 -#define CY_PLX_9050_ICS_IENABLE 0x040 -#define CY_PLX_9050_ICS_LOCAL_IENABLE 0x001 -#define CY_PLX_9060_ICS_IENABLE 0x100 -#define CY_PLX_9060_ICS_LOCAL_IENABLE 0x800 - -/* Cyclom-Y Custom Register for PLX ID. */ -#define PLX_VER 0x3400 -#define PLX_9050 0x0b -#define PLX_9060 0x0c -#define PLX_9080 0x0d +#define CY_PLX_ICS 0x68 +#define CY_PLX_ICS_IENABLE 0x100 +#define CY_PLX_ICS_LOCAL_IENABLE 0x800 diff --git a/sys/pci/dpt_pci.c b/sys/pci/dpt_pci.c index 7bf0e26e3138..7af9a2aece84 100644 --- a/sys/pci/dpt_pci.c +++ b/sys/pci/dpt_pci.c @@ -32,7 +32,7 @@ * dptpci.c: PCI Bus Attachment for DPT SCSI HBAs */ -#ident "$Id: dpt_pci.c,v 1.10 1998/12/07 21:58:46 archie Exp $" +#ident "$Id: dpt_pci.c,v 1.8 1998/09/15 08:33:38 gibbs Exp $" #include "opt_devfs.h" #include "opt_dpt.h" @@ -64,7 +64,7 @@ /* Function Prototypes */ -static const char *dpt_pci_probe(pcici_t tag, pcidi_t type); +static char *dpt_pci_probe(pcici_t tag, pcidi_t type); static void dpt_pci_attach(pcici_t config_id, int unit); extern struct cdevsw dpt_cdevsw; @@ -86,7 +86,7 @@ DATA_SET(pcidevice_set, dpt_pci_driver); * because we do not know for sure how the two relate. */ -static const char * +static char * dpt_pci_probe(pcici_t tag, pcidi_t type) { u_int32_t class; @@ -112,13 +112,14 @@ dpt_pci_attach(pcici_t config_id, int unit) { dpt_softc_t *dpt; vm_offset_t vaddr; -#ifdef DPT_ALLOW_MEMIO vm_offset_t paddr; -#endif u_int16_t io_base; bus_space_tag_t tag; bus_space_handle_t bsh; u_int32_t command; + u_int32_t data; + int result; + int ndx; int s; vaddr = NULL; diff --git a/sys/pci/es1370.c b/sys/pci/es1370.c deleted file mode 100644 index 7277e7ab1481..000000000000 --- a/sys/pci/es1370.c +++ /dev/null @@ -1,1127 +0,0 @@ -/* - * Support the ENSONIQ AudioPCI board based on the ES1370 and Codec - * AK4531. - * - * Copyright (c) 1998 by Joachim Kuebart. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgement: - * This product includes software developed by Joachim Kuebart. - * - * 4. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ - */ - -#include "pci.h" -#include "pcm.h" - -#include <sys/param.h> -#include <sys/queue.h> -#include <sys/kernel.h> -#include <machine/bus_pio.h> -#include <machine/bus_memio.h> -#include <machine/bus.h> -#include <pci/pcireg.h> -#include <pci/pcivar.h> - -#include <pci/es1370_reg.h> -#include <i386/isa/snd/sound.h> -#include <i386/isa/snd/ulaw.h> - -#if NPCI != 0 - - -/* -------------------------------------------------------------------- */ - -/* - * #defines - */ - -#ifdef __alpha__ -#define IO_SPACE_MAPPING ALPHA_BUS_SPACE_IO -#define MEM_SPACE_MAPPING ALPHA_BUS_SPACE_MEM -#else /* not __alpha__ */ -#define IO_SPACE_MAPPING I386_BUS_SPACE_IO -#define MEM_SPACE_MAPPING I386_BUS_SPACE_MEM -#endif /* not __alpha__ */ - -#define DMA_ALIGN_THRESHOLD 4 -#define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1)) -#define DMA_READ_THRESHOLD 0x200 - -#define MEM_MAP_REG 0x14 - -#define UNIT(minor) ((minor) >> 4) -#define DEV(minor) ((minor) & 0xf) - - -/* -------------------------------------------------------------------- */ - -/* - * PCI IDs of supported chips - */ - -#define ES1370_PCI_ID 0x50001274 - - -/* -------------------------------------------------------------------- */ - -/* - * device private data - */ - -struct es_info { - bus_space_tag_t st; - bus_space_handle_t sh; - - bus_dma_tag_t parent_dmat; - bus_dmamap_t dmam_in, dmam_out; - - /* Contents of board's registers */ - u_long ctrl; - u_long sctrl; -}; - - -/* -------------------------------------------------------------------- */ - -/* - * prototypes - */ - -static void dma_wrintr(snddev_info *); -static void dma_rdintr(snddev_info *); -static int es_init(snddev_info *); -static snd_callback_t es_callback; -static d_open_t es_dsp_open; -static d_close_t es_dsp_close; -static d_ioctl_t es_dsp_ioctl; -static d_read_t es_dsp_read; -static d_write_t es_dsp_write; -static void es_intr(void *); -static int es_rdabort(snddev_info *); -static void es_rd_map(void *, bus_dma_segment_t *, int, int); -static int es_wrabort(snddev_info *); -static void es_wr_map(void *, bus_dma_segment_t *, int, int); -static char *es_pci_probe __P((pcici_t, pcidi_t)); -static void es_pci_attach __P((pcici_t, int)); -static int es_rd_dmaupdate(snddev_info *); -static d_select_t es_select; -static int es_wr_dmaupdate(snddev_info *); -static int alloc_dmabuf(snddev_info *, int); -static int write_codec(snddev_info *, u_char, u_char); - - -/* -------------------------------------------------------------------- */ - -/* - * PCI driver and PCM driver method tables - */ - -static struct pci_device es_pci_driver = { - "es", - es_pci_probe, - es_pci_attach, - &nsnd, - NULL -}; - -DATA_SET(pcidevice_set, es_pci_driver); - -static snddev_info es_op_desc = { - "ENSONIQ AudioPCI", - - 0, /* type, apparently unused */ - NULL, /* ISA probe */ - NULL, /* ISA attach */ - - es_dsp_open, - es_dsp_close, - es_dsp_read, - es_dsp_write, - es_dsp_ioctl, - es_select, - - NULL, /* Interrupt Service Routine */ - es_callback, - - ES_BUFFSIZE, - - AFMT_FULLDUPLEX | AFMT_STEREO | AFMT_U8 | AFMT_S16_LE, /* brag :-) */ -}; - - -/* -------------------------------------------------------------------- */ - -/* - * The mixer interface - */ - -static const struct { - unsigned volidx:4; - unsigned left:4; - unsigned right:4; - unsigned stereo:1; - unsigned recmask:13; - unsigned avail:1; -} mixtable[SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_VOLUME] = { 0, 0x0, 0x1, 1, 0x0000, 1 }, - [SOUND_MIXER_PCM] = { 1, 0x2, 0x3, 1, 0x0400, 1 }, - [SOUND_MIXER_SYNTH] = { 2, 0x4, 0x5, 1, 0x0060, 1 }, - [SOUND_MIXER_CD] = { 3, 0x6, 0x7, 1, 0x0006, 1 }, - [SOUND_MIXER_LINE] = { 4, 0x8, 0x9, 1, 0x0018, 1 }, - [SOUND_MIXER_LINE1] = { 5, 0xa, 0xb, 1, 0x1800, 1 }, - [SOUND_MIXER_LINE2] = { 6, 0xc, 0x0, 0, 0x0100, 1 }, - [SOUND_MIXER_LINE3] = { 7, 0xd, 0x0, 0, 0x0200, 1 }, - [SOUND_MIXER_MIC] = { 8, 0xe, 0x0, 0, 0x0001, 1 }, - [SOUND_MIXER_OGAIN] = { 9, 0xf, 0x0, 0, 0x0000, 1 } }; - -static int -mixer_ioctl(snddev_info *d, u_long cmd, caddr_t data, int fflag, struct proc *p) -{ - int i, j, *val, ret = 0; - - val = (int *)data; - i = cmd & 0xff; - - switch (cmd & IOC_DIRMASK) { - case IOC_IN | IOC_OUT: /* _IOWR */ - switch (i) { - case SOUND_MIXER_RECSRC: - for (i = j = 0; i != SOUND_MIXER_NRDEVICES; i++) - if ((*val & (1 << i)) != 0) { - if (!mixtable[i].recmask) - *val &= ~(1 << i); - else - j |= mixtable[i].recmask; - } - d->mix_recsrc = *val; - write_codec(d, CODEC_LIMIX1, j & 0x55); - write_codec(d, CODEC_RIMIX1, j & 0xaa); - write_codec(d, CODEC_LIMIX2, (j >> 8) & 0x17); - write_codec(d, CODEC_RIMIX2, (j >> 8) & 0x0f); - write_codec(d, CODEC_OMIX1, 0x7f); - write_codec(d, CODEC_OMIX2, 0x3f); - break; - - default: - if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail) - ret = EINVAL; - else { - int l, r, rl, rr; - - l = *val & 0xff; - if (l > 100) - l = 100; - if (mixtable[i].left == 0xf) { - if (l < 2) - rl = 0x80; - else - rl = 7 - (l - 2) / 14; - } else { - if (l < 10) - rl = 0x80; - else - rl = 15 - (l - 10) / 6; - } - if (mixtable[i].stereo) { - r = (*val >> 8) & 0xff; - if (r > 100) - r = 100; - if (r < 10) - rr = 0x80; - else - rr = 15 - (r - 10) / 6; - write_codec(d, mixtable[i].right, rr); - } else - r = l; - write_codec(d, mixtable[i].left, rl); - *val = d->mix_levels[i] = ((u_int) r << 8) | l; - } - break; - } - break; - - default: - ret = ENOSYS; - break; - } - - return (ret); -} - - -/* -------------------------------------------------------------------- */ - -/* - * File operations - */ - -static int -es_dsp_open(dev_t dev, int oflags, int devtype, struct proc *p) -{ - int unit = UNIT(minor(dev)); - snddev_info *d = &pcm_info[unit]; - - if (d->flags & SND_F_BUSY) - return (EBUSY); - d->flags = 0; - - d->dbuf_out.total = d->dbuf_out.prev_total = - d->dbuf_in.total = d->dbuf_in.prev_total = 0; - - switch (DEV(minor(dev))) { - case SND_DEV_DSP16: - d->play_fmt = d->rec_fmt = AFMT_S16_LE; - break; - - case SND_DEV_DSP: - d->play_fmt = d->rec_fmt = AFMT_U8; - break; - - case SND_DEV_AUDIO: - d->play_fmt = d->rec_fmt = AFMT_MU_LAW; - break; - - default: - return (ENXIO); - } - - if ((oflags & FREAD) == 0) - d->rec_fmt = 0; - else if ((oflags & FWRITE) == 0) - d->play_fmt = 0; - - d->play_speed = d->rec_speed = DSP_DEFAULT_SPEED; - - d->flags |= SND_F_BUSY; - if (oflags & O_NONBLOCK) - d->flags |= SND_F_NBIO; - - ask_init(d); - - return (0); -} - -static int -es_dsp_close(dev_t dev, int cflags, int devtype, struct proc *p) -{ - int unit = UNIT(minor(dev)); - snddev_info *d = &pcm_info[unit]; - - d->flags &= ~SND_F_BUSY; - - es_rdabort(d); - - return (0); -} - -static int -es_dsp_read(dev_t dev, struct uio *buf, int flag) -{ - int l, l1, limit, ret = 0, unit = UNIT(minor(dev)); - long s; - snddev_info *d = &pcm_info[unit]; - snd_dbuf *b = &d->dbuf_in; - - if (d->flags & SND_F_READING) { - /* This shouldn't happen and is actually silly */ - tsleep(&s, PZERO, "sndar", hz); - return (EBUSY); - } - d->flags |= SND_F_READING; - - /* - * XXX Check for SND_F_INIT. If set, wait for DMA to run empty and - * re-initialize the board - */ - - if (buf->uio_resid - d->rec_blocksize > 0) - limit = buf->uio_resid - d->rec_blocksize; - else - limit = 0; - - while ((l = buf->uio_resid) > limit) { - s = spltty(); - es_rd_dmaupdate(d); - if ((l = min(l, b->rl)) == 0) { - int timeout; - if (b->dl == 0) - dma_rdintr(d); - if (d->flags & SND_F_NBIO) { - splx(s); - break; - } - if (buf->uio_resid - limit > b->dl) - timeout = hz; - else - timeout = 1; - splx(s); - switch (ret = tsleep((caddr_t)b, PRIBIO | PCATCH, - "dsprd", timeout)) { - case EINTR: - es_rdabort(d); - /* FALLTHROUGH */ - - case ERESTART: - break; - - default: - continue; - } - break; - } - splx(s); - - if ((l1 = b->bufsize - b->rp) < l) { - if (d->flags & SND_F_XLAT8) { - translate_bytes(ulaw_dsp, b->buf + b->rp, l1); - translate_bytes(ulaw_dsp, b->buf, l - l1); - } - uiomove(b->buf + b->rp, l1, buf); - uiomove(b->buf, l - l1, buf); - } else { - if (d->flags & SND_F_XLAT8) - translate_bytes(ulaw_dsp, b->buf + b->rp, l); - uiomove(b->buf + b->rp, l, buf); - } - - s = spltty(); - b->fl += l; - b->rl -= l; - b->rp = (b->rp + l) % b->bufsize; - splx(s); - } - - d->flags &= ~SND_F_READING; - - return (ret); -} - -static int -es_dsp_write(dev_t dev, struct uio *buf, int flag) -{ - int l, l1, ret = 0, unit = UNIT(minor(dev)); - long s; - snddev_info *d = &pcm_info[unit]; - snd_dbuf *b = &d->dbuf_out; - - if (d->flags & SND_F_WRITING) { - /* This shouldn't happen and is actually silly */ - tsleep(&s, PZERO, "sndaw", hz); - return (EBUSY); - } - d->flags |= SND_F_WRITING; - - /* - * XXX Check for SND_F_INIT. If set, wait for DMA to run empty and - * re-initialize the board - */ - - while ((l = buf->uio_resid) != 0) { - s = spltty(); - es_wr_dmaupdate(d); - if ((l = min(l, b->fl)) == 0) { - int timeout; - if (d->flags & SND_F_NBIO) { - splx(s); - break; - } - if (buf->uio_resid >= b->dl) - timeout = hz; - else - timeout = 1; - splx(s); - switch (ret = tsleep((caddr_t)b, PRIBIO | PCATCH, - "dspwr", timeout)) { - case EINTR: - es_wrabort(d); - /* FALLTHROUGH */ - - case ERESTART: - break; - - default: - continue; - } - break; - } - splx(s); - - if ((l1 = b->bufsize - b->fp) < l) { - uiomove(b->buf + b->fp, l1, buf); - uiomove(b->buf, l - l1, buf); - if (d->flags & SND_F_XLAT8) { - translate_bytes(ulaw_dsp, b->buf + b->fp, l1); - translate_bytes(ulaw_dsp, b->buf, l - l1); - } - } else { - uiomove(b->buf + b->fp, l, buf); - if (d->flags & SND_F_XLAT8) - translate_bytes(ulaw_dsp, b->buf + b->fp, l); - } - - s = spltty(); - b->rl += l; - b->fl -= l; - b->fp = (b->fp + l) % b->bufsize; - if (b->dl == 0) - dma_wrintr(d); - splx(s); - } - - d->flags &= ~SND_F_WRITING; - - return (ret); -} - -static int -es_dsp_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) -{ - int ret = 0, unit = UNIT(minor(dev)); - snddev_info *d = &pcm_info[unit]; - long s; - - if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) - return mixer_ioctl(d, cmd, data, fflag, p); - - switch(cmd) { - case AIONWRITE: - if (d->dbuf_out.dl != 0) { - s = spltty(); - es_wr_dmaupdate(d); - splx(s); - } - *(int *)data = d->dbuf_out.fl; - break; - - case FIONREAD: - if (d->dbuf_in.dl != 0) { - s = spltty(); - es_rd_dmaupdate(d); - splx(s); - } - *(int *)data = d->dbuf_in.rl; - break; - - case SNDCTL_DSP_GETISPACE: - { - audio_buf_info *a = (audio_buf_info *)data; - snd_dbuf *b = &d->dbuf_in; - if (b->dl != 0) { - s = spltty(); - es_rd_dmaupdate(d); - splx(s); - } - a->bytes = b->fl; - a->fragments = b->fl / d->rec_blocksize; - a->fragstotal = b->bufsize / d->rec_blocksize; - a->fragsize = d->rec_blocksize; - } - break; - - case SNDCTL_DSP_GETOSPACE: - { - audio_buf_info *a = (audio_buf_info *)data; - snd_dbuf *b = &d->dbuf_out; - if (b->dl != 0) { - s = spltty(); - es_wr_dmaupdate(d); - splx(s); - } - a->bytes = b->fl; - a->fragments = b->fl / d->rec_blocksize; - a->fragstotal = b->bufsize / d->play_blocksize; - a->fragsize = d->play_blocksize; - } - break; - - case SNDCTL_DSP_GETIPTR: - { - count_info *c = (count_info *)data; - snd_dbuf *b = &d->dbuf_in; - if (b->dl != 0) { - s = spltty(); - es_rd_dmaupdate(d); - splx(s); - } - c->bytes = b->total; - c->blocks = (b->total - b->prev_total + - d->rec_blocksize - 1) / d->rec_blocksize; - c->ptr = b->fp; - b->prev_total = b->total; - } - break; - - case SNDCTL_DSP_GETOPTR: - { - count_info *c = (count_info *)data; - snd_dbuf *b = &d->dbuf_out; - if (b->dl != 0) { - s = spltty(); - es_wr_dmaupdate(d); - splx(s); - } - c->bytes = b->total; - c->blocks = (b->total - b->prev_total + - d->play_blocksize - 1) / d->play_blocksize; - c->ptr = b->rp; - b->prev_total = b->total; - } - break; - - case AIOSTOP: - case SNDCTL_DSP_RESET: - case SNDCTL_DSP_SYNC: - ret = EINVAL; - break; - - default: - ret = ENOSYS; - break; - } - return (ret); -} - -static int -es_select(dev_t i_dev, int rw, struct proc * p) -{ - return (ENOSYS); -} - - -/* -------------------------------------------------------------------- */ - -/* - * The interrupt handler - */ - -static void -es_intr (void *p) -{ - snddev_info *d = (snddev_info *)p; - struct es_info *es = (struct es_info *)d->device_data; - unsigned intsrc, sctrl; - - intsrc = bus_space_read_4(es->st, es->sh, ES1370_REG_STATUS); - if ((intsrc & STAT_INTR) == 0) - return; - - sctrl = es->sctrl; - if (intsrc & STAT_ADC) - sctrl &= ~SCTRL_R1INTEN; - if (intsrc & STAT_DAC1) - sctrl &= ~SCTRL_P1INTEN; - if (intsrc & STAT_DAC2) { - sctrl &= ~SCTRL_P2INTEN; - } - bus_space_write_4(es->st, es->sh, ES1370_REG_SERIAL_CONTROL, sctrl); - bus_space_write_4(es->st, es->sh, ES1370_REG_SERIAL_CONTROL, - es->sctrl); - if (intsrc & STAT_DAC2) - dma_wrintr(d); - if (intsrc & STAT_ADC) - dma_rdintr(d); -} - - -/* -------------------------------------------------------------------- */ - -/* - * DMA hassle - */ - -static int -alloc_dmabuf(snddev_info *d, int rd) -{ - struct es_info *es = (struct es_info *)d->device_data; - snd_dbuf *b = rd ? &d->dbuf_in : &d->dbuf_out; - bus_dmamap_t *dmam = rd ? &es->dmam_in : &es->dmam_out; - - if (bus_dmamem_alloc(es->parent_dmat, (void **)&b->buf, BUS_DMA_NOWAIT, - dmam) != 0 || - bus_dmamap_load(es->parent_dmat, *dmam, b->buf, d->bufsize, - rd ? es_rd_map : es_wr_map, es, 0) != 0) - return -1; - - b->rp = b->fp = b->dl = b->rl = 0; - b->fl = b->bufsize = d->bufsize; - return (0); -} - -static int -es_wr_dmaupdate(snddev_info *d) -{ - struct es_info *es = (struct es_info *)d->device_data; - unsigned hwptr, delta; - - bus_space_write_4(es->st, es->sh, ES1370_REG_MEMPAGE, - ES1370_REG_DAC2_FRAMECNT >> 8); - hwptr = (bus_space_read_4(es->st, es->sh, - ES1370_REG_DAC2_FRAMECNT & 0xff) >> 14) & 0x3fffc; - delta = (d->dbuf_out.bufsize + hwptr - d->dbuf_out.rp) % - d->dbuf_out.bufsize; - d->dbuf_out.rp = hwptr; - d->dbuf_out.rl -= delta; - d->dbuf_out.fl += delta; - d->dbuf_out.total += delta; - - return delta; -} - -static int -es_rd_dmaupdate(snddev_info *d) -{ - struct es_info *es = (struct es_info *)d->device_data; - unsigned hwptr, delta; - - bus_space_write_4(es->st, es->sh, ES1370_REG_MEMPAGE, - ES1370_REG_ADC_FRAMECNT >> 8); - hwptr = (bus_space_read_4(es->st, es->sh, - ES1370_REG_ADC_FRAMECNT & 0xff) >> 14) & 0x3fffc; - delta = (d->dbuf_in.bufsize + hwptr - d->dbuf_in.fp) % - d->dbuf_in.bufsize; - d->dbuf_in.fp = hwptr; - d->dbuf_in.rl += delta; - d->dbuf_in.fl -= delta; - d->dbuf_in.total += delta; - return delta; -} - - -/* -------------------------------------------------------------------- */ - -/* - * Hardware - */ - -static int -es_callback(snddev_info *d, int reason) -{ - struct es_info *es = (struct es_info *)d->device_data; - int rd = reason & SND_CB_RD; - - switch(reason & SND_CB_REASON_MASK) { - case SND_CB_INIT: - es->ctrl = (es->ctrl & ~CTRL_PCLKDIV) | - (DAC2_SRTODIV(d->play_speed) << CTRL_SH_PCLKDIV); - snd_set_blocksize(d); - - es->sctrl &= ~(SCTRL_R1FMT | SCTRL_P2FMT); - d->flags &= ~SND_F_XLAT8; - switch(d->play_fmt) { - case 0: - case AFMT_U8: - break; - - case AFMT_S16_LE: - es->sctrl |= SCTRL_P2SEB; - break; - - case AFMT_MU_LAW: - d->flags |= SND_F_XLAT8; - break; - - default: - return (-1); - } - - switch(d->rec_fmt) { - case 0: - case AFMT_U8: - break; - - case AFMT_S16_LE: - es->sctrl |= SCTRL_R1SEB; - break; - - case AFMT_MU_LAW: - d->flags |= SND_F_XLAT8; - break; - - default: - return (-1); - } - - if (d->flags & SND_F_STEREO) - es->sctrl |= SCTRL_P2SMB | SCTRL_R1SMB; - - bus_space_write_4(es->st, es->sh, ES1370_REG_CONTROL, - es->ctrl); - bus_space_write_4(es->st, es->sh, ES1370_REG_SERIAL_CONTROL, - es->sctrl); - break; - - case SND_CB_START: - if (rd) { - es->ctrl |= CTRL_ADC_EN; - es->sctrl = (es->sctrl & ~SCTRL_R1LOOPSEL) | - SCTRL_R1INTEN; - bus_space_write_4(es->st, es->sh, ES1370_REG_ADC_SCOUNT, - d->dbuf_in.dl / d->dbuf_in.sample_size - 1); - } else { - es->ctrl |= CTRL_DAC2_EN; - es->sctrl = (es->sctrl & ~(SCTRL_P2ENDINC | - SCTRL_P2STINC | SCTRL_P2LOOPSEL | SCTRL_P2PAUSE | - SCTRL_P2DACSEN)) | SCTRL_P2INTEN | - (((d->play_fmt == AFMT_S16_LE) ? 2 : 1) - << SCTRL_SH_P2ENDINC); - bus_space_write_4(es->st, es->sh, - ES1370_REG_DAC2_SCOUNT, - d->dbuf_out.dl / d->dbuf_out.sample_size - 1); - } - bus_space_write_4(es->st, es->sh, ES1370_REG_SERIAL_CONTROL, - es->sctrl); - bus_space_write_4(es->st, es->sh, ES1370_REG_CONTROL, es->ctrl); - break; - - case SND_CB_ABORT: - case SND_CB_STOP: - if (rd) - es->ctrl &= ~CTRL_ADC_EN; - else - es->ctrl &= ~CTRL_DAC2_EN; - bus_space_write_4(es->st, es->sh, ES1370_REG_CONTROL, es->ctrl); - break; - - default: - return (-1); - } - return (0); -} - -static int -write_codec(snddev_info *d, u_char i, u_char data) -{ - struct es_info *es = (struct es_info *)d->device_data; - int wait = 100; /* 100 msec timeout */ - - do { - if ((bus_space_read_4(es->st, es->sh, ES1370_REG_STATUS) & - STAT_CSTAT) == 0) { - bus_space_write_2(es->st, es->sh, ES1370_REG_CODEC, - ((u_short)i << CODEC_INDEX_SHIFT) | data); - return (0); - } - DELAY(1000); - /* tsleep(&wait, PZERO, "sndaw", hz / 1000); */ - } while (--wait); - printf("pcm: write_codec timed out\n"); - return (-1); -} - -static void -es_wr_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - struct es_info *es = (struct es_info *)arg; - - bus_space_write_1(es->st, es->sh, ES1370_REG_MEMPAGE, - ES1370_REG_DAC2_FRAMEADR >> 8); - bus_space_write_4(es->st, es->sh, ES1370_REG_DAC2_FRAMEADR & 0xff, - segs->ds_addr); - bus_space_write_4(es->st, es->sh, ES1370_REG_DAC2_FRAMECNT & 0xff, - (segs->ds_len >> 2) - 1); -} - -static void -es_rd_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - struct es_info *es = (struct es_info *)arg; - - bus_space_write_1(es->st, es->sh, ES1370_REG_MEMPAGE, - ES1370_REG_ADC_FRAMEADR >> 8); - bus_space_write_4(es->st, es->sh, ES1370_REG_ADC_FRAMEADR & 0xff, - segs->ds_addr); - bus_space_write_4(es->st, es->sh, ES1370_REG_ADC_FRAMECNT & 0xff, - (segs->ds_len >> 2) - 1); -} - -static void -dma_wrintr(snddev_info *d) -{ - snd_dbuf *b = &d->dbuf_out; - - /* - * According to Linux driver: - * dmaupdate() - * Bei underrun error++ - * wake_up(dac2.wait) - */ - - if (b->dl != 0) { - es_wr_dmaupdate(d); - wakeup(b); - } - - if (b->rl >= DMA_ALIGN_THRESHOLD && - !(d->flags & SND_F_ABORTING)) { - int l = min(b->rl, d->play_blocksize); - l &= DMA_ALIGN_MASK; - - if (l != b->dl) { - if (b->dl != 0) { - d->callback(d, SND_CB_WR | SND_CB_STOP); - es_wr_dmaupdate(d); - l = min(b->rl, d->play_blocksize); - l &= DMA_ALIGN_MASK; - } - b->dl = l; - d->callback(d, SND_CB_WR | SND_CB_START); - } - } else if (b->dl != 0) { - b->dl = 0; - d->callback(d, SND_CB_WR | SND_CB_STOP); - es_wr_dmaupdate(d); - } -} - -static void -dma_rdintr(snddev_info *d) -{ - snd_dbuf *b = &d->dbuf_in; - - if (b->dl != 0) { - es_rd_dmaupdate(d); - wakeup(b); - } - - if (b->fl >= DMA_READ_THRESHOLD && - !(d->flags & SND_F_ABORTING)) { - int l = min(b->fl, d->rec_blocksize); - l &= DMA_ALIGN_MASK; - - if (l != b->dl) { - if (b->dl != 0) { - d->callback(d, SND_CB_RD | SND_CB_STOP); - es_rd_dmaupdate(d); - l = min(b->fl, d->rec_blocksize); - l &= DMA_ALIGN_MASK; - } - b->dl = l; - d->callback(d, SND_CB_RD | SND_CB_START); - } - } else { - if (b->dl != 0) { - b->dl = 0; - d->callback(d, SND_CB_RD | SND_CB_STOP); - es_rd_dmaupdate(d); - } - } -} - -static int -es_wrabort(snddev_info *d) -{ - snd_dbuf *b = &d->dbuf_out; - long s; - int missing; - - s = spltty(); - if (b->dl != 0) { - wakeup(b); - b->dl = 0; - d->callback(d, SND_CB_WR | SND_CB_ABORT); - } - es_wr_dmaupdate(d); - missing = b->rl; - b->rl = 0; - b->fp = b->rp; - b->fl = b->bufsize; - splx(s); - return missing; -} - -static int -es_rdabort(snddev_info *d) -{ - snd_dbuf *b = &d->dbuf_in; - long s; - int missing; - - s = spltty(); - if (b->dl != 0) { - wakeup(b); - b->dl = 0; - d->callback(d, SND_CB_RD | SND_CB_ABORT); - es_rd_dmaupdate(d); - } - missing = b->rl; - b->rl = 0; - b->fp = b->rp; - b->fl = b->bufsize; - splx(s); - return missing; -} - - -/* -------------------------------------------------------------------- */ - -/* - * Probe and attach the card - */ - -static int -es_init(snddev_info *d) -{ - struct es_info *es = (struct es_info *)d->device_data; - u_int i; - - es->ctrl = CTRL_CDC_EN | CTRL_SERR_DIS | - (DAC2_SRTODIV(DSP_DEFAULT_SPEED) << CTRL_SH_PCLKDIV); - bus_space_write_4(es->st, es->sh, ES1370_REG_CONTROL, es->ctrl); - es->sctrl = 0; - bus_space_write_4(es->st, es->sh, ES1370_REG_SERIAL_CONTROL, es->sctrl); - write_codec(d, CODEC_RES_PD, 3);/* No RST, PD */ - write_codec(d, CODEC_CSEL, 0); /* CODEC ADC and CODEC DAC use - * {LR,B}CLK2 and run off the LRCLK2 - * PLL; program DAC_SYNC=0! */ - write_codec(d, CODEC_ADSEL, 0); /* Recording source is mixer */ - write_codec(d, CODEC_MGAIN, 0); /* MIC amp is 0db */ - - i = SOUND_MASK_MIC; - mixer_ioctl(d, SOUND_MIXER_WRITE_RECSRC, (caddr_t) &i, 0, NULL); - i = 0; - mixer_ioctl(d, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &i, 0, NULL); - mixer_ioctl(d, SOUND_MIXER_WRITE_PCM, (caddr_t) &i, 0, NULL); - mixer_ioctl(d, SOUND_MIXER_WRITE_SYNTH, (caddr_t) &i, 0, NULL); - mixer_ioctl(d, SOUND_MIXER_WRITE_CD, (caddr_t) &i, 0, NULL); - mixer_ioctl(d, SOUND_MIXER_WRITE_LINE, (caddr_t) &i, 0, NULL); - mixer_ioctl(d, SOUND_MIXER_WRITE_LINE1, (caddr_t) &i, 0, NULL); - mixer_ioctl(d, SOUND_MIXER_WRITE_LINE2, (caddr_t) &i, 0, NULL); - mixer_ioctl(d, SOUND_MIXER_WRITE_LINE3, (caddr_t) &i, 0, NULL); - mixer_ioctl(d, SOUND_MIXER_WRITE_MIC, (caddr_t) &i, 0, NULL); - - return (0); -} - -static char * -es_pci_probe(pcici_t tag, pcidi_t type) -{ - if (type == ES1370_PCI_ID) - return ("AudioPCI ES1370"); - - return (NULL); -} - -static void -es_pci_attach(pcici_t config_id, int unit) -{ - snddev_info *d; - u_int32_t data; - struct es_info *es; - pci_port_t io_port; - int i, mapped; - vm_offset_t vaddr, paddr; - - if (unit > NPCM_MAX) - return; - - d = &pcm_info[unit]; - *d = es_op_desc; - if ((es = malloc(sizeof(*es), M_DEVBUF, M_NOWAIT)) == NULL) { - printf("pcm%d: cannot allocate softc\n", unit); - return; - } - bzero(es, sizeof(*es)); - d->device_data = es; - - vaddr = paddr = NULL; - mapped = 0; - data = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - if (mapped == 0 && (data & PCI_COMMAND_MEM_ENABLE)) { - if (pci_map_mem(config_id, MEM_MAP_REG, &vaddr, &paddr)) { - es->st = MEM_SPACE_MAPPING; - es->sh = vaddr; - mapped++; - } - } - if (mapped == 0 && (data & PCI_COMMAND_IO_ENABLE)) { - if (pci_map_port(config_id, PCI_MAP_REG_START, &io_port)) { - es->st = IO_SPACE_MAPPING; - es->sh = io_port; - mapped++; - } - } - if (mapped == 0) { - printf("pcm%d: unable to map any ports\n", unit); - free(es, M_DEVBUF); - return; - } - printf("pcm%d: using %s space register mapping at %#x\n", unit, - es->st == IO_SPACE_MAPPING ? "I/O" : "Memory", es->sh); - - d->io_base = es->sh; - d->mix_devs = 0; - for (i = 0; i != SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].avail) - d->mix_devs |= (1 << i); - d->mix_rec_devs = 0; - for (i = 0; i != SOUND_MIXER_NRDEVICES; i++) - if (mixtable[i].recmask) - d->mix_rec_devs |= (1 << i); - - if (es_init(d) == -1) { - printf("pcm%d: unable to initialize the card\n", unit); - free(es, M_DEVBUF); - d->io_base = 0; - return; - } - if (pci_map_int(config_id, es_intr, d, &tty_imask) == 0) { - printf("pcm%d: unable to map interrupt\n", unit); - free(es, M_DEVBUF); - d->io_base = 0; - return; - } - if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/d->bufsize, /*nsegments*/1, /*maxsegz*/0x3ffff, - /*flags*/0, &es->parent_dmat) != 0) { - printf("pcm%d: unable to create dma tag\n", unit); - free(es, M_DEVBUF); - d->io_base = 0; - return; - } - - if (alloc_dmabuf(d, 0) == -1 || - alloc_dmabuf(d, 1) == -1) { - printf("pcm%d: unable to allocate dma buffers\n", unit); - free(es, M_DEVBUF); - d->io_base = 0; - return; - } - - pcminit(d, unit); - - return; -} - -#endif /* NPCI != 0 */ diff --git a/sys/pci/es1370_reg.h b/sys/pci/es1370_reg.h deleted file mode 100644 index 72546c61449a..000000000000 --- a/sys/pci/es1370_reg.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * This supports the ENSONIQ AudioPCI board based on the ES1370. - * - * Copyright (c) 1998 Joachim Kuebart <joki@kuebart.stuttgart.netsurf.de> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Absolutely no warranty of function or purpose is made by the author - * Joachim Kuebart. - * 4. Modifications may be freely made to this file if the above conditions - * are met. - * - * $Id$ - */ - -#ifndef _ES1370_REG_H -#define _ES1370_REG_H - -#define ES1370_REG_CONTROL 0x00 -#define ES1370_REG_STATUS 0x04 -#define ES1370_REG_UART_DATA 0x08 -#define ES1370_REG_UART_STATUS 0x09 -#define ES1370_REG_UART_CONTROL 0x09 -#define ES1370_REG_UART_TEST 0x0a -#define ES1370_REG_MEMPAGE 0x0c -#define ES1370_REG_CODEC 0x10 -#define CODEC_INDEX_SHIFT 8 -#define ES1370_REG_SERIAL_CONTROL 0x20 -#define ES1370_REG_DAC1_SCOUNT 0x24 -#define ES1370_REG_DAC2_SCOUNT 0x28 -#define ES1370_REG_ADC_SCOUNT 0x2c - -#define ES1370_REG_DAC1_FRAMEADR 0xc30 -#define ES1370_REG_DAC1_FRAMECNT 0xc34 -#define ES1370_REG_DAC2_FRAMEADR 0xc38 -#define ES1370_REG_DAC2_FRAMECNT 0xc3c -#define ES1370_REG_ADC_FRAMEADR 0xd30 -#define ES1370_REG_ADC_FRAMECNT 0xd34 - -#define DAC2_SRTODIV(x) (((1411200 + (x) / 2) / (x) - 2) & 0x1fff) -#define DAC2_DIVTOSR(x) (1411200 / ((x) + 2)) - -#define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */ -#define CTRL_XCTL1 0x40000000 /* SERR pin if enabled */ -#define CTRL_OPEN 0x20000000 /* no function, can be read and - * written */ -#define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */ -#define CTRL_SH_PCLKDIV 16 -#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 - * = I2S */ -#define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */ -#define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025, - * 2=22050, 3=44100 */ -#define CTRL_SH_WTSRSEL 12 -#define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */ -#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */ -#define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 = - * MPEG */ -#define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */ -#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */ -#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */ -#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */ -#define CTRL_ADC_EN 0x00000010 /* enable ADC */ -#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */ -#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port (presumably - * at address 0x200) */ -#define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */ -#define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */ - -#define SCTRL_P2ENDINC 0x00380000 /* */ -#define SCTRL_SH_P2ENDINC 19 -#define SCTRL_P2STINC 0x00070000 /* */ -#define SCTRL_SH_P2STINC 16 -#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */ -#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */ -#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */ -#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */ -#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */ -#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */ -#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */ -#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */ -#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for - * DAC1 */ -#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample - * when disabled */ -#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */ -#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */ -#define SCTRL_R1FMT 0x00000030 /* format mask */ -#define SCTRL_SH_R1FMT 4 -#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */ -#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */ -#define SCTRL_P2FMT 0x0000000c /* format mask */ -#define SCTRL_SH_P2FMT 2 -#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */ -#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */ -#define SCTRL_P1FMT 0x00000003 /* format mask */ -#define SCTRL_SH_P1FMT 0 - -#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */ -#define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in - * progress */ -#define STAT_CBUSY 0x00000200 /* 1 = codec busy */ -#define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */ -#define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2, - * 2=ADC, 3=undef */ -#define STAT_SH_VC 5 -#define STAT_MCCB 0x00000010 /* CCB int pending */ -#define STAT_UART 0x00000008 /* UART int pending */ -#define STAT_DAC1 0x00000004 /* DAC1 int pending */ -#define STAT_DAC2 0x00000002 /* DAC2 int pending */ -#define STAT_ADC 0x00000001 /* ADC int pending */ - -#define CODEC_OMIX1 0x10 -#define CODEC_OMIX2 0x11 -#define CODEC_LIMIX1 0x12 -#define CODEC_RIMIX1 0x13 -#define CODEC_LIMIX2 0x14 -#define CODEC_RIMIX2 0x15 -#define CODEC_RES_PD 0x16 -#define CODEC_CSEL 0x17 -#define CODEC_ADSEL 0x18 -#define CODEC_MGAIN 0x19 - -#define ES_BUFFSIZE 0x20000 /* We're PCI! Use a large buffer */ - -#endif diff --git a/sys/pci/ide_pci.c b/sys/pci/ide_pci.c index 39c53a562b32..68df969ff56b 100644 --- a/sys/pci/ide_pci.c +++ b/sys/pci/ide_pci.c @@ -26,7 +26,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ide_pci.c,v 1.27 1999/01/17 05:18:54 bde Exp $ + * $Id: ide_pci.c,v 1.13 1998/07/11 07:45:52 bde Exp $ */ #include "pci.h" @@ -120,15 +120,6 @@ via_571_dmainit(struct ide_pci_cookie *cookie, void *wdinfo); static void -acer_status(struct ide_pci_cookie *cookie); - -static int -acer_dmainit(struct ide_pci_cookie *cookie, - struct wdparams *wp, - int (*wdcmd)(int, void *), - void *wdinfo); - -static void intel_piix_dump_drive(char *ctlr, int sitre, int is_piix4, @@ -159,7 +150,7 @@ mkcookie(int iobase_wd, static void ide_pci_attach(pcici_t tag, int unit); -static void *ide_pci_candma(int, int, int); +static void *ide_pci_candma(int, int); static int ide_pci_dmainit(void *, struct wdparams *, int (*)(int, void *), @@ -276,14 +267,8 @@ generic_dmainit(struct ide_pci_cookie *cookie, printf("ide_pci: generic_dmainit %04x:%d: warning, IDE controller timing not set\n", cookie->iobase_wd, cookie->unit); - /* If we're here, then this controller is most likely not set - for UDMA, even if the drive may be. Make the drive wise - up. */ - - if(!wdcmd(WDDMA_MDMA2, wdinfo)) - printf("generic_dmainit: could not set multiword DMA mode!\n"); return 1; - } + } #ifdef IDE_PCI_DEBUG printf("pio_mode: %d, mwdma_mode(wp): %d, udma_mode(wp): %d\n", pio_mode(wp), mwdma_mode(wp), udma_mode(wp)); @@ -404,7 +389,7 @@ via_571_dmainit(struct ide_pci_cookie *cookie, /* UDMA enable by SET FEATURES, DMA cycles, cycle time 2T */ mask = 0xe3000000 >> (unitno * 8); - new = 0x40000000 >> (unitno * 8); + new = 0x80000000 >> (unitno * 8); word50 &= ~mask; word50 |= new; @@ -418,10 +403,10 @@ via_571_dmainit(struct ide_pci_cookie *cookie, */ /* Set UDMA mode 2 on drive */ if (bootverbose) - printf("via_571_dmainit: setting ultra DMA mode 2\n"); + printf("intel_piix_dmainit: setting ultra DMA mode 2\n"); r = wdcmd(WDDMA_UDMA2, wdinfo); if (!r) { - printf("via_571_dmainit: setting DMA mode failed\n"); + printf("intel_piix_dmainit: setting DMA mode failed\n"); return 0; } @@ -437,10 +422,10 @@ via_571_dmainit(struct ide_pci_cookie *cookie, /* Set multiword DMA mode 2 on drive */ if (bootverbose) - printf("via_571_dmainit: setting multiword DMA mode 2\n"); + printf("intel_piix_dmainit: setting multiword DMA mode 2\n"); r = wdcmd(WDDMA_MDMA2, wdinfo); if (!r) { - printf("via_571_dmainit: setting DMA mode failed\n"); + printf("intel_piix_dmainit: setting DMA mode failed\n"); return 0; } @@ -452,7 +437,8 @@ via_571_dmainit(struct ide_pci_cookie *cookie, * enable prefetch/postwrite-- XXX may cause problems * with CD-ROMs? */ - workword |= 0xc000 >> (cookie->ctlr * 2); + workword &= ~(3 << (cookie->ctlr * 2 + 12)); + workword |= 3 << (cookie->ctlr * 2 + 12); /* FIFO configurations-- equal split, threshold 1/2 */ workword &= 0x90ffffff; @@ -495,175 +481,6 @@ static struct vendor_fns vs_via_571 = via_571_status }; -/* Cyrix Cx5530 Courtesy of Whistle Communications */ - -/* - * Verify that controller can handle a dma request for cp. Should - * not affect any hardware or driver state. - * Special version for 5530 that allows only transfers on 16 byte boundaries.(!) - * (Yes the Cyrix 5530 can only UDMA to cache-line boundaries.(bleh!)) - * Luckily nearly all disk IO is to kernel bufers which are page alligned. - * They may fix this in some other version of the chip, but it's in the latest - * at this time (Jan 1999). - */ -static int -cyrix_5530_dmaverify(void *xcp, char *vaddr, u_long count, int dir) -{ - int badfu; - - /* - * check for nonaligned or odd-length Stuff - */ - badfu = ((unsigned int)vaddr & 0xf) || (count & 0xf); -#ifdef DIAGNOSTIC - if (badfu) { - printf("ide_pci: dmaverify odd vaddr or length, "); - printf("vaddr = %p length = %08lx\n", (void *)vaddr, count); - } -#endif - return (!badfu); -} - -/* - * XXX Unit number handling may be broken in the Cx5530 modules. - * It has only been checked with a single drive. - * 12MByte/Sec transfer rates were seen with Quantum Fireball drives - * with negligable CPU usage. - */ -static void -cyrix_5530_status(struct ide_pci_cookie *cookie) -{ - int iobase_wd; - int ctlr, unit; - int iobase_bm; - pcici_t tag; - pcidi_t type; - u_long PIO_config; - u_long DMA_config; - int unitno; - - iobase_wd = cookie->iobase_wd; - unit = cookie->unit; - ctlr = cookie->ctlr; - iobase_bm = cookie->iobase_bm; - tag = cookie->tag; - type = cookie->type; - - unitno = ctlr * 2 + unit; - - /* set some values the BIOS should have set */ - printf("Using 0x%x\n", cookie->iobase_bm); - outl(iobase_bm + (unit * 0x10) + 0x20, 0x00040010); - outl(iobase_bm + (unit * 0x10) + 0x24, 0x00911030); - /* if ((ctlr == 0) && (unit == 0)) */ /* XXX */ - /* outb(iobase_bm + (unit * 0x10) + BMISTA_PORT, 0xe6);*/ - - PIO_config = inl(iobase_bm + (unit * 0x10) + 0x20); - DMA_config = inl(iobase_bm + (unit * 0x10) + 0x24); - - - printf("cyrix_5530_status: %s:%u IDE PIO cfg: 0x%08lx\n", - (ctlr ? "Secondary" : "Primary"), unit, PIO_config); - printf("cyrix_5530_status: %s:%u IDE DMA cfg: 0x%08lx\n", - (ctlr ? "Secondary" : "Primary"), unit, DMA_config); -} - -/* - * XXX timing values set here are only good for 30/33MHz buses; should deal - * with slower ones too (BTW: you overclock-- you lose) - */ - -static int -cyrix_5530_dmainit(struct ide_pci_cookie *cookie, - struct wdparams *wp, - int(*wdcmd)(int, void *), - void *wdinfo) -{ - int r; - u_long pci_revision; - int unitno; - int iobase_bm; - int unit; - - /*cookie->unit = 0; */ /* XXX */ - unit = cookie->unit; - pci_revision = pci_conf_read(cookie->tag, PCI_CLASS_REG) & - PCI_REVISION_MASK; - - unitno = cookie->ctlr * 2 + unit; - iobase_bm = cookie->iobase_bm; - - printf("Setting using 0x%x\n", iobase_bm); - if ((cookie->ctlr == 0) && (unit == 0)) /* XXX */ - outb(iobase_bm + (unit * 0x10) + BMISTA_PORT, 0xe6); - outl(iobase_bm + (unit * 0x10) + 0x20, 0x00040010); - outl(iobase_bm + (unit * 0x10) + 0x24, 0x00911030); - /* If it's a UDMA drive on a '5530, set it up */ - /* - * depending on what the drive can do, - * set the correct modes, - */ - printf("wd%d: mw=0x%x, pio=0x%x, pcirev=0x%lx, udma=0x%x\n", - unitno, - mwdma_mode(wp), pio_mode(wp), - pci_revision, udma_mode(wp)); - if (/* pci_revision >= 1 && */ udma_mode(wp) >= 2) { - /*outl(iobase_bm + 0x20 + (cookie->unit * 16), 0x00100010);*/ - outl(iobase_bm + 0x24 + (cookie->unit * 16), 0x00911030); - - /* - * With the Cx5530, drive configuration should come *after* the - * controller configuration, to make sure the controller sees - * the command and does the right thing. - */ - /* Set UDMA mode 2 on drive */ - if (bootverbose) - printf("cyrix_5530_dmainit: setting ultra DMA mode 2\n"); - r = wdcmd(WDDMA_UDMA2, wdinfo); - if (!r) { - printf("cyrix_5530_dmainit: setting DMA mode failed\n"); - return 0; - } - - if (bootverbose) - cyrix_5530_status(cookie); - return 1; - - } - - /* otherwise, try and program it for MW DMA mode 2 */ - else if (mwdma_mode(wp) >= 2 && pio_mode(wp) >= 4) { - - /* Set multiword DMA mode 2 on drive */ - if (bootverbose) - printf("cyrix_5530_dmainit: setting multiword DMA mode 2\n"); - r = wdcmd(WDDMA_MDMA2, wdinfo); - if (!r) { - printf("cyrix_5530_dmainit: setting DMA mode failed\n"); - return 0; - } - - /* Configure the controller appropriately for MWDMA mode 2 */ - - /*outl(iobase_bm + 0x20 + (cookie->unit * 16), 0x00100010);*/ - outl(iobase_bm + 0x24 + (cookie->unit * 16), 0x00002020); - - if (bootverbose) - cyrix_5530_status(cookie); - - return 1; - - } - return 0; -} - - -static struct vendor_fns vs_cyrix_5530 = -{ - cyrix_5530_dmainit, - cyrix_5530_status -}; - static void promise_status(struct ide_pci_cookie *cookie) @@ -879,8 +696,8 @@ intel_piix_dmainit(struct ide_pci_cookie *cookie, unitno = cookie->ctlr * 2 + cookie->unit; - mask = (1 << unitno) + (3 << (16 + unitno * 4)); - new = (1 << unitno) + (2 << (16 + unitno * 4)); + mask = 1 << unitno + 3 << (16 + unitno * 4); + new = 1 << unitno + 2 << (16 + unitno * 4); pci_conf_write(cookie->tag, 0x48, (pci_conf_read(cookie->tag, 0x48) & ~mask) | new); @@ -1019,70 +836,6 @@ static struct vendor_fns vs_intel_piix = intel_piix_status }; - -static void -acer_status(struct ide_pci_cookie *cookie) { - /* XXX does not do anything right now */ -} - -static int -acer_dmainit(struct ide_pci_cookie *cookie, - struct wdparams *wp, - int(*wdcmd)(int, void *), - void *wdinfo) -{ - /* Acer Aladdin DMA setup code. UDMA looks to be sinfully easy to set - on this thing - just one register. */ - - u_long word54 = pci_conf_read(cookie->tag, 0x54); - - /* Set the default Acer FIFO settings (0x55 = 13-word depth and - slave operation mode 1) */ - - word54 |= 0x5555; - - /* Is this drive UDMA? Set it up if so... */ - if(udma_mode(wp) >= 2) { - /* This is really easy to do. Just write 0xa (enable - UDMA mode with 2T timing) into the word at the right - places. */ - word54 |= (0xA << (16 + (cookie->ctlr * 8) + (cookie->unit * 4))); - - /* Now set the drive for UDMA2. */ - if(!wdcmd(WDDMA_UDMA2, wdinfo)) { - printf("acer_dmainit: could not set UDMA2 mode on wdc%d:%d!\n", cookie->ctlr, cookie->unit); - return 0; - } - - /* Write the new config into the registers. I'm not - sure if I'm doing this in the right order. */ - - pci_conf_write(cookie->tag, 0x54, word54); - - } else if(mwdma_mode(wp) >= 2 && pio_mode(wp) >=4) { - - - /* Otherwise, we're already set for regular DMA. */ - - if(!wdcmd(WDDMA_MDMA2, wdinfo)) { - printf("acer_dmainit: could not set MWDMA2 mode on wdc%d:%d!\n", - cookie->ctlr, cookie->unit); - return 0; - } - return 1; - } - - return 0; -} - -static struct vendor_fns vs_acer = -{ - acer_dmainit, - acer_status -}; - - - /* Generic SFF-8038i code-- all code below here, except for PCI probes, * more or less conforms to the SFF-8038i spec as extended for PCI. * There should be no code that goes beyond that feature set below. @@ -1145,7 +898,7 @@ mkcookie(int iobase_wd, return cp; } -static const char * +static char * ide_pci_probe(pcici_t tag, pcidi_t type) { u_long data; @@ -1164,11 +917,7 @@ ide_pci_probe(pcici_t tag, pcidi_t type) if (type == PROMISE_ULTRA33) return ("Promise Ultra/33 IDE controller"); if (type == 0x05711106) - return ("VIA 82C586x (Apollo) Bus-master IDE controller"); - if (type == 0x01021078) - return ("Cyrix 5530 Bus-master IDE controller"); - if (type == 0x522910b9) - return ("Acer Aladdin IV/V (M5229) Bus-master IDE controller"); + return ("VIA 82C586x (Apollo) Bus-master IDE controller"); if (data & 0x8000) return ("PCI IDE controller (busmaster capable)"); #ifndef CMD640 @@ -1186,7 +935,7 @@ ide_pci_probe(pcici_t tag, pcidi_t type) static void ide_pci_attach(pcici_t tag, int unit) { - u_long class = 0, cmd; + u_long class, cmd; int bmista_1, bmista_2; int iobase_wd_1, iobase_wd_2, iobase_bm_1, iobase_bm_2; int altiobase_wd_1, altiobase_wd_2; @@ -1232,13 +981,6 @@ ide_pci_attach(pcici_t tag, int unit) vp = &vs_promise; break; - case 0x01021078: /* cyrix 5530 */ - printf("cyrix 5530\n"); - vp = &vs_cyrix_5530; - break; - case 0x522910B9: /* Acer Aladdin IV/V (M5229) */ - vp = &vs_acer; - break; default: /* everybody else */ vp = &vs_generic; @@ -1269,19 +1011,16 @@ ide_pci_attach(pcici_t tag, int unit) } iobase_bm_1 = pci_conf_read(tag, 0x20) & 0xfffc; + iobase_bm_2 = iobase_bm_1 + SFF8038_CTLR_1; if (iobase_bm_1 == 0) { - printf("ide_pci: BIOS has not configured busmaster" - "I/O address,\n ide_pci: giving up\n"); + printf("ide_pci: BIOS has not configured busmaster I/O address,\n\ +ide_pci: giving up\n"); return; } - iobase_bm_2 = iobase_bm_1 + SFF8038_CTLR_1; wddma[unit].wdd_candma = ide_pci_candma; wddma[unit].wdd_dmainit = ide_pci_dmainit; - if (type == 0x01021078 /*CYRIX_5530*/) - wddma[unit].wdd_dmaverify = cyrix_5530_dmaverify; - else - wddma[unit].wdd_dmaverify = ide_pci_dmaverify; + wddma[unit].wdd_dmaverify = ide_pci_dmaverify; wddma[unit].wdd_dmaprep = ide_pci_dmasetup; wddma[unit].wdd_dmastart = ide_pci_dmastart; wddma[unit].wdd_dmadone = ide_pci_dmadone; @@ -1331,7 +1070,7 @@ ide_pci_attach(pcici_t tag, int unit) if (dvup->id_id == 0) { iobase_wd_2 = 0; break; - } + } } if (dvup->id_unit == biotabunit + 2) { @@ -1389,8 +1128,6 @@ ide_pci_attach(pcici_t tag, int unit) if (bootverbose) { vp->vendor_status(cookie); - bmista_1 = inb(iobase_bm_1 + BMISTA_PORT); - bmista_2 = inb(iobase_bm_2 + BMISTA_PORT); printf("ide_pci: busmaster 0 status: %02x from port: %08x\n", bmista_1, iobase_bm_1+BMISTA_PORT); @@ -1401,7 +1138,9 @@ ide_pci_attach(pcici_t tag, int unit) } } - if (iobase_wd_2 != 0) { + if (bmista_1 & BMISTA_SIMPLEX || bmista_2 & BMISTA_SIMPLEX) { + printf("ide_pci: controller is simplex, no DMA on secondary channel\n"); + } else if (iobase_wd_2 != 0) { cookie = mkcookie(iobase_wd_2, ctlridx + 1, 0, @@ -1423,8 +1162,6 @@ ide_pci_attach(pcici_t tag, int unit) if (bootverbose) { vp->vendor_status(cookie); - bmista_1 = inb(iobase_bm_1 + BMISTA_PORT); - bmista_2 = inb(iobase_bm_2 + BMISTA_PORT); printf("ide_pci: busmaster 1 status: %02x from port: %08x\n", bmista_2, iobase_bm_2+BMISTA_PORT); @@ -1449,17 +1186,16 @@ static struct pci_device ide_pci_device = { DATA_SET(pcidevice_set, ide_pci_device); /* - * Return a cookie if we may be able to do DMA on the specified - * (iobase_wd, ctlr, unit). + * Return a cookie if we can do DMA on the specified (iobase_wd, unit). */ static void * -ide_pci_candma(int iobase_wd, int ctlr, int unit) +ide_pci_candma(int iobase_wd, int unit) { struct ide_pci_cookie *cp; cp = softc.cookies.lh_first; while(cp) { - if (cp->ctlr == ctlr && cp->unit == unit && + if (cp->ctlr == unit && ((iobase_wd == 0) || (cp->iobase_wd == iobase_wd))) break; cp = cp->le.le_next; @@ -1529,10 +1265,7 @@ ide_pci_dmasetup(void *xcp, char *vaddr, u_long vcount, int dir) u_long prd_base, prd_count; u_long nbase, ncount, nend; int iobase_bm; - u_long count; -#ifdef DIAGNOSTIC - u_long checkcount; -#endif + u_long count, checkcount; prd = cp->prd; @@ -1568,22 +1301,10 @@ ide_pci_dmasetup(void *xcp, char *vaddr, u_long vcount, int dir) * Coalesce if physically contiguous and not crossing * 64k boundary. */ -#if 0 - /* - * Aggregation is NOT an optimisation worth doing, - * and the Cyrix UDMA controller screws itself - * in some aggregated situations. - * We might as well just assign each 4K page a DMA entry - * as this doesn't really gain us anything to aggregate them. - * This was basically copied from my agregation code in the aha - * driver, but I doubt it helped much there either. [JRE] - */ if ((prd_base + prd_count == nbase) && ((((nend - 1) ^ prd_base) & ~0xffff) == 0)) { prd_count += ncount; - } else -#endif - { + } else { prd[i].prd_base = prd_base; prd[i].prd_count = (prd_count & 0xffff); i++; @@ -1670,10 +1391,11 @@ ide_pci_dmadone(void *xcp) static int ide_pci_status(void *xcp) { + struct ide_pci_cookie *cp = xcp; int iobase_bm, status, bmista; status = 0; - iobase_bm = ((struct ide_pci_cookie *)xcp)->iobase_bm; + iobase_bm = cp->iobase_bm; bmista = inb(iobase_bm + BMISTA_PORT); @@ -1683,6 +1405,7 @@ ide_pci_status(void *xcp) status |= WDDS_ERROR; if (bmista & BMISTA_DMA_ACTIVE) status |= WDDS_ACTIVE; + return status; } diff --git a/sys/pci/if_ax.c b/sys/pci/if_ax.c deleted file mode 100644 index 34f1e881b5be..000000000000 --- a/sys/pci/if_ax.c +++ /dev/null @@ -1,2175 +0,0 @@ -/* - * Copyright (c) 1997, 1998, 1999 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_ax.c,v 1.8 1999/01/16 20:33:34 wpaul Exp $ - */ - -/* - * ASIX AX88140A fast ethernet PCI NIC driver. - * - * Written by Bill Paul <wpaul@ctr.columbia.edu> - * Electrical Engineering Department - * Columbia University, New York City - */ - -/* - * The ASIX Electronics AX88140A is still another DEC 21x4x clone. It's - * a reasonably close copy of the tulip, except for the receiver filter - * programming. Where the DEC chip has a special setup frame that - * needs to be downloaded into the transmit DMA engine, the ASIX chip - * has a less complicated setup frame which is written into one of - * the registers. - */ - -#include "bpfilter.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/if_arp.h> -#include <net/ethernet.h> -#include <net/if_dl.h> -#include <net/if_media.h> - -#if NBPFILTER > 0 -#include <net/bpf.h> -#endif - -#include <vm/vm.h> /* for vtophys */ -#include <vm/pmap.h> /* for vtophys */ -#include <machine/clock.h> /* for DELAY */ -#include <machine/bus_pio.h> -#include <machine/bus_memio.h> -#include <machine/bus.h> - -#include <pci/pcireg.h> -#include <pci/pcivar.h> - -#define AX_USEIOSPACE - -/* #define AX_BACKGROUND_AUTONEG */ - -#include <pci/if_axreg.h> - -#ifndef lint -static const char rcsid[] = - "$Id: if_ax.c,v 1.8 1999/01/16 20:33:34 wpaul Exp $"; -#endif - -/* - * Various supported device vendors/types and their names. - */ -static struct ax_type ax_devs[] = { - { AX_VENDORID, AX_DEVICEID_AX88140A, - "ASIX AX88140A 10/100BaseTX" }, - { 0, 0, NULL } -}; - -/* - * Various supported PHY vendors/types and their names. Note that - * this driver will work with pretty much any MII-compliant PHY, - * so failure to positively identify the chip is not a fatal error. - */ - -static struct ax_type ax_phys[] = { - { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, - { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, - { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, - { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, - { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, - { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, - { 0, 0, "<MII-compliant physical interface>" } -}; - -static unsigned long ax_count = 0; -static const char *ax_probe __P((pcici_t, pcidi_t)); -static void ax_attach __P((pcici_t, int)); - -static int ax_newbuf __P((struct ax_softc *, - struct ax_chain_onefrag *)); -static int ax_encap __P((struct ax_softc *, struct ax_chain *, - struct mbuf *)); - -static void ax_rxeof __P((struct ax_softc *)); -static void ax_rxeoc __P((struct ax_softc *)); -static void ax_txeof __P((struct ax_softc *)); -static void ax_txeoc __P((struct ax_softc *)); -static void ax_intr __P((void *)); -static void ax_start __P((struct ifnet *)); -static int ax_ioctl __P((struct ifnet *, u_long, caddr_t)); -static void ax_init __P((void *)); -static void ax_stop __P((struct ax_softc *)); -static void ax_watchdog __P((struct ifnet *)); -static void ax_shutdown __P((int, void *)); -static int ax_ifmedia_upd __P((struct ifnet *)); -static void ax_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); - -static void ax_delay __P((struct ax_softc *)); -static void ax_eeprom_idle __P((struct ax_softc *)); -static void ax_eeprom_putbyte __P((struct ax_softc *, int)); -static void ax_eeprom_getword __P((struct ax_softc *, int, u_int16_t *)); -static void ax_read_eeprom __P((struct ax_softc *, caddr_t, int, - int, int)); - -static void ax_mii_writebit __P((struct ax_softc *, int)); -static int ax_mii_readbit __P((struct ax_softc *)); -static void ax_mii_sync __P((struct ax_softc *)); -static void ax_mii_send __P((struct ax_softc *, u_int32_t, int)); -static int ax_mii_readreg __P((struct ax_softc *, struct ax_mii_frame *)); -static int ax_mii_writereg __P((struct ax_softc *, struct ax_mii_frame *)); -static u_int16_t ax_phy_readreg __P((struct ax_softc *, int)); -static void ax_phy_writereg __P((struct ax_softc *, int, int)); - -static void ax_autoneg_xmit __P((struct ax_softc *)); -static void ax_autoneg_mii __P((struct ax_softc *, int, int)); -static void ax_setmode_mii __P((struct ax_softc *, int)); -static void ax_setmode __P((struct ax_softc *, int, int)); -static void ax_getmode_mii __P((struct ax_softc *)); -static void ax_setcfg __P((struct ax_softc *, int)); -static u_int32_t ax_calchash __P((caddr_t)); -static void ax_setmulti __P((struct ax_softc *)); -static void ax_reset __P((struct ax_softc *)); -static int ax_list_rx_init __P((struct ax_softc *)); -static int ax_list_tx_init __P((struct ax_softc *)); - -#define AX_SETBIT(sc, reg, x) \ - CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) | x) - -#define AX_CLRBIT(sc, reg, x) \ - CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) & ~x) - -#define SIO_SET(x) \ - CSR_WRITE_4(sc, AX_SIO, \ - CSR_READ_4(sc, AX_SIO) | x) - -#define SIO_CLR(x) \ - CSR_WRITE_4(sc, AX_SIO, \ - CSR_READ_4(sc, AX_SIO) & ~x) - -static void ax_delay(sc) - struct ax_softc *sc; -{ - int idx; - - for (idx = (300 / 33) + 1; idx > 0; idx--) - CSR_READ_4(sc, AX_BUSCTL); -} - -static void ax_eeprom_idle(sc) - struct ax_softc *sc; -{ - register int i; - - CSR_WRITE_4(sc, AX_SIO, AX_SIO_EESEL); - ax_delay(sc); - AX_SETBIT(sc, AX_SIO, AX_SIO_ROMCTL_READ); - ax_delay(sc); - AX_SETBIT(sc, AX_SIO, AX_SIO_EE_CS); - ax_delay(sc); - AX_SETBIT(sc, AX_SIO, AX_SIO_EE_CLK); - ax_delay(sc); - - for (i = 0; i < 25; i++) { - AX_CLRBIT(sc, AX_SIO, AX_SIO_EE_CLK); - ax_delay(sc); - AX_SETBIT(sc, AX_SIO, AX_SIO_EE_CLK); - ax_delay(sc); - } - - AX_CLRBIT(sc, AX_SIO, AX_SIO_EE_CLK); - ax_delay(sc); - AX_CLRBIT(sc, AX_SIO, AX_SIO_EE_CS); - ax_delay(sc); - CSR_WRITE_4(sc, AX_SIO, 0x00000000); - - return; -} - -/* - * Send a read command and address to the EEPROM, check for ACK. - */ -static void ax_eeprom_putbyte(sc, addr) - struct ax_softc *sc; - int addr; -{ - register int d, i; - - d = addr | AX_EECMD_READ; - - /* - * Feed in each bit and stobe the clock. - */ - for (i = 0x400; i; i >>= 1) { - if (d & i) { - SIO_SET(AX_SIO_EE_DATAIN); - } else { - SIO_CLR(AX_SIO_EE_DATAIN); - } - ax_delay(sc); - SIO_SET(AX_SIO_EE_CLK); - ax_delay(sc); - SIO_CLR(AX_SIO_EE_CLK); - ax_delay(sc); - } - - return; -} - -/* - * Read a word of data stored in the EEPROM at address 'addr.' - */ -static void ax_eeprom_getword(sc, addr, dest) - struct ax_softc *sc; - int addr; - u_int16_t *dest; -{ - register int i; - u_int16_t word = 0; - - /* Force EEPROM to idle state. */ - ax_eeprom_idle(sc); - - /* Enter EEPROM access mode. */ - CSR_WRITE_4(sc, AX_SIO, AX_SIO_EESEL); - ax_delay(sc); - AX_SETBIT(sc, AX_SIO, AX_SIO_ROMCTL_READ); - ax_delay(sc); - AX_SETBIT(sc, AX_SIO, AX_SIO_EE_CS); - ax_delay(sc); - AX_SETBIT(sc, AX_SIO, AX_SIO_EE_CLK); - ax_delay(sc); - - /* - * Send address of word we want to read. - */ - ax_eeprom_putbyte(sc, addr); - - /* - * Start reading bits from EEPROM. - */ - for (i = 0x8000; i; i >>= 1) { - SIO_SET(AX_SIO_EE_CLK); - ax_delay(sc); - if (CSR_READ_4(sc, AX_SIO) & AX_SIO_EE_DATAOUT) - word |= i; - ax_delay(sc); - SIO_CLR(AX_SIO_EE_CLK); - ax_delay(sc); - } - - /* Turn off EEPROM access mode. */ - ax_eeprom_idle(sc); - - *dest = word; - - return; -} - -/* - * Read a sequence of words from the EEPROM. - */ -static void ax_read_eeprom(sc, dest, off, cnt, swap) - struct ax_softc *sc; - caddr_t dest; - int off; - int cnt; - int swap; -{ - int i; - u_int16_t word = 0, *ptr; - - for (i = 0; i < cnt; i++) { - ax_eeprom_getword(sc, off + i, &word); - ptr = (u_int16_t *)(dest + (i * 2)); - if (swap) - *ptr = ntohs(word); - else - *ptr = word; - } - - return; -} - -/* - * Write a bit to the MII bus. - */ -static void ax_mii_writebit(sc, bit) - struct ax_softc *sc; - int bit; -{ - if (bit) - CSR_WRITE_4(sc, AX_SIO, AX_SIO_ROMCTL_WRITE|AX_SIO_MII_DATAOUT); - else - CSR_WRITE_4(sc, AX_SIO, AX_SIO_ROMCTL_WRITE); - - AX_SETBIT(sc, AX_SIO, AX_SIO_MII_CLK); - AX_CLRBIT(sc, AX_SIO, AX_SIO_MII_CLK); - - return; -} - -/* - * Read a bit from the MII bus. - */ -static int ax_mii_readbit(sc) - struct ax_softc *sc; -{ - CSR_WRITE_4(sc, AX_SIO, AX_SIO_ROMCTL_READ|AX_SIO_MII_DIR); - CSR_READ_4(sc, AX_SIO); - AX_SETBIT(sc, AX_SIO, AX_SIO_MII_CLK); - AX_CLRBIT(sc, AX_SIO, AX_SIO_MII_CLK); - if (CSR_READ_4(sc, AX_SIO) & AX_SIO_MII_DATAIN) - return(1); - - return(0); -} - -/* - * Sync the PHYs by setting data bit and strobing the clock 32 times. - */ -static void ax_mii_sync(sc) - struct ax_softc *sc; -{ - register int i; - - CSR_WRITE_4(sc, AX_SIO, AX_SIO_ROMCTL_WRITE); - - for (i = 0; i < 32; i++) - ax_mii_writebit(sc, 1); - - return; -} - -/* - * Clock a series of bits through the MII. - */ -static void ax_mii_send(sc, bits, cnt) - struct ax_softc *sc; - u_int32_t bits; - int cnt; -{ - int i; - - for (i = (0x1 << (cnt - 1)); i; i >>= 1) - ax_mii_writebit(sc, bits & i); -} - -/* - * Read an PHY register through the MII. - */ -static int ax_mii_readreg(sc, frame) - struct ax_softc *sc; - struct ax_mii_frame *frame; - -{ - int i, ack, s; - - s = splimp(); - - /* - * Set up frame for RX. - */ - frame->mii_stdelim = AX_MII_STARTDELIM; - frame->mii_opcode = AX_MII_READOP; - frame->mii_turnaround = 0; - frame->mii_data = 0; - - /* - * Sync the PHYs. - */ - ax_mii_sync(sc); - - /* - * Send command/address info. - */ - ax_mii_send(sc, frame->mii_stdelim, 2); - ax_mii_send(sc, frame->mii_opcode, 2); - ax_mii_send(sc, frame->mii_phyaddr, 5); - ax_mii_send(sc, frame->mii_regaddr, 5); - -#ifdef notdef - /* Idle bit */ - ax_mii_writebit(sc, 1); - ax_mii_writebit(sc, 0); -#endif - - /* Check for ack */ - ack = ax_mii_readbit(sc); - - /* - * Now try reading data bits. If the ack failed, we still - * need to clock through 16 cycles to keep the PHY(s) in sync. - */ - if (ack) { - for(i = 0; i < 16; i++) { - ax_mii_readbit(sc); - } - goto fail; - } - - for (i = 0x8000; i; i >>= 1) { - if (!ack) { - if (ax_mii_readbit(sc)) - frame->mii_data |= i; - } - } - -fail: - - ax_mii_writebit(sc, 0); - ax_mii_writebit(sc, 0); - - splx(s); - - if (ack) - return(1); - return(0); -} - -/* - * Write to a PHY register through the MII. - */ -static int ax_mii_writereg(sc, frame) - struct ax_softc *sc; - struct ax_mii_frame *frame; - -{ - int s; - - s = splimp(); - /* - * Set up frame for TX. - */ - - frame->mii_stdelim = AX_MII_STARTDELIM; - frame->mii_opcode = AX_MII_WRITEOP; - frame->mii_turnaround = AX_MII_TURNAROUND; - - /* - * Sync the PHYs. - */ - ax_mii_sync(sc); - - ax_mii_send(sc, frame->mii_stdelim, 2); - ax_mii_send(sc, frame->mii_opcode, 2); - ax_mii_send(sc, frame->mii_phyaddr, 5); - ax_mii_send(sc, frame->mii_regaddr, 5); - ax_mii_send(sc, frame->mii_turnaround, 2); - ax_mii_send(sc, frame->mii_data, 16); - - /* Idle bit. */ - ax_mii_writebit(sc, 0); - ax_mii_writebit(sc, 0); - - splx(s); - - return(0); -} - -static u_int16_t ax_phy_readreg(sc, reg) - struct ax_softc *sc; - int reg; -{ - struct ax_mii_frame frame; - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = sc->ax_phy_addr; - frame.mii_regaddr = reg; - ax_mii_readreg(sc, &frame); - - return(frame.mii_data); -} - -static void ax_phy_writereg(sc, reg, data) - struct ax_softc *sc; - int reg; - int data; -{ - struct ax_mii_frame frame; - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = sc->ax_phy_addr; - frame.mii_regaddr = reg; - frame.mii_data = data; - - ax_mii_writereg(sc, &frame); - - return; -} - -/* - * Calculate CRC of a multicast group address, return the lower 6 bits. - */ -static u_int32_t ax_calchash(addr) - caddr_t addr; -{ - u_int32_t crc, carry; - int i, j; - u_int8_t c; - - /* Compute CRC for the address value. */ - crc = 0xFFFFFFFF; /* initial value */ - - for (i = 0; i < 6; i++) { - c = *(addr + i); - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); - crc <<= 1; - c >>= 1; - if (carry) - crc = (crc ^ 0x04c11db6) | carry; - } - } - - /* return the filter bit position */ - return((crc >> 26) & 0x0000003F); -} - -static void ax_setmulti(sc) - struct ax_softc *sc; -{ - struct ifnet *ifp; - int h = 0; - u_int32_t hashes[2] = { 0, 0 }; - struct ifmultiaddr *ifma; - u_int32_t rxfilt; - - ifp = &sc->arpcom.ac_if; - - rxfilt = CSR_READ_4(sc, AX_NETCFG); - - if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { - rxfilt |= AX_NETCFG_RX_ALLMULTI; - CSR_WRITE_4(sc, AX_NETCFG, rxfilt); - return; - } else - rxfilt &= ~AX_NETCFG_RX_ALLMULTI; - - /* first, zot all the existing hash bits */ - CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR0); - CSR_WRITE_4(sc, AX_FILTDATA, 0); - CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR1); - CSR_WRITE_4(sc, AX_FILTDATA, 0); - - /* now program new ones */ - for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; - ifma = ifma->ifma_link.le_next) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ax_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - } - - CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR0); - CSR_WRITE_4(sc, AX_FILTDATA, hashes[0]); - CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_MAR1); - CSR_WRITE_4(sc, AX_FILTDATA, hashes[1]); - CSR_WRITE_4(sc, AX_NETCFG, rxfilt); - - return; -} - -/* - * Initiate an autonegotiation session. - */ -static void ax_autoneg_xmit(sc) - struct ax_softc *sc; -{ - u_int16_t phy_sts; - - ax_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(ax_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - - phy_sts = ax_phy_readreg(sc, PHY_BMCR); - phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; - ax_phy_writereg(sc, PHY_BMCR, phy_sts); - - return; -} - -/* - * Invoke autonegotiation on a PHY. - */ -static void ax_autoneg_mii(sc, flag, verbose) - struct ax_softc *sc; - int flag; - int verbose; -{ - u_int16_t phy_sts = 0, media, advert, ability; - struct ifnet *ifp; - struct ifmedia *ifm; - - ifm = &sc->ifmedia; - ifp = &sc->arpcom.ac_if; - - ifm->ifm_media = IFM_ETHER | IFM_AUTO; - - /* - * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported' - * bit cleared in the status register, but has the 'autoneg enabled' - * bit set in the control register. This is a contradiction, and - * I'm not sure how to handle it. If you want to force an attempt - * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR - * and see what happens. - */ -#ifndef FORCE_AUTONEG_TFOUR - /* - * First, see if autoneg is supported. If not, there's - * no point in continuing. - */ - phy_sts = ax_phy_readreg(sc, PHY_BMSR); - if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { - if (verbose) - printf("ax%d: autonegotiation not supported\n", - sc->ax_unit); - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - return; - } -#endif - - switch (flag) { - case AX_FLAG_FORCEDELAY: - /* - * XXX Never use this option anywhere but in the probe - * routine: making the kernel stop dead in its tracks - * for three whole seconds after we've gone multi-user - * is really bad manners. - */ - ax_autoneg_xmit(sc); - DELAY(5000000); - break; - case AX_FLAG_SCHEDDELAY: - /* - * Wait for the transmitter to go idle before starting - * an autoneg session, otherwise ax_start() may clobber - * our timeout, and we don't want to allow transmission - * during an autoneg session since that can screw it up. - */ - if (sc->ax_cdata.ax_tx_head != NULL) { - sc->ax_want_auto = 1; - return; - } - ax_autoneg_xmit(sc); - ifp->if_timer = 5; - sc->ax_autoneg = 1; - sc->ax_want_auto = 0; - return; - break; - case AX_FLAG_DELAYTIMEO: - ifp->if_timer = 0; - sc->ax_autoneg = 0; - break; - default: - printf("ax%d: invalid autoneg flag: %d\n", sc->ax_unit, flag); - return; - } - - if (ax_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { - if (verbose) - printf("ax%d: autoneg complete, ", sc->ax_unit); - phy_sts = ax_phy_readreg(sc, PHY_BMSR); - } else { - if (verbose) - printf("ax%d: autoneg not complete, ", sc->ax_unit); - } - - media = ax_phy_readreg(sc, PHY_BMCR); - - /* Link is good. Report modes and set duplex mode. */ - if (ax_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { - if (verbose) - printf("link status good "); - advert = ax_phy_readreg(sc, PHY_ANAR); - ability = ax_phy_readreg(sc, PHY_LPAR); - - if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { - ifm->ifm_media = IFM_ETHER|IFM_100_T4; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(100baseT4)\n"); - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - media |= PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - media &= ~PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 10Mbps)\n"); - } else if (advert & PHY_ANAR_10BTHALF && - ability & PHY_ANAR_10BTHALF) { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - media &= ~PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 10Mbps)\n"); - } - - media &= ~PHY_BMCR_AUTONEGENBL; - - /* Set ASIC's duplex mode to match the PHY. */ - ax_setcfg(sc, media); - ax_phy_writereg(sc, PHY_BMCR, media); - } else { - if (verbose) - printf("no carrier\n"); - } - - ax_init(sc); - - if (sc->ax_tx_pend) { - sc->ax_autoneg = 0; - sc->ax_tx_pend = 0; - ax_start(ifp); - } - - return; -} - -static void ax_getmode_mii(sc) - struct ax_softc *sc; -{ - u_int16_t bmsr; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - bmsr = ax_phy_readreg(sc, PHY_BMSR); - if (bootverbose) - printf("ax%d: PHY status word: %x\n", sc->ax_unit, bmsr); - - /* fallback */ - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - - if (bmsr & PHY_BMSR_10BTHALF) { - if (bootverbose) - printf("ax%d: 10Mbps half-duplex mode supported\n", - sc->ax_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); - } - - if (bmsr & PHY_BMSR_10BTFULL) { - if (bootverbose) - printf("ax%d: 10Mbps full-duplex mode supported\n", - sc->ax_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - } - - if (bmsr & PHY_BMSR_100BTXHALF) { - if (bootverbose) - printf("ax%d: 100Mbps half-duplex mode supported\n", - sc->ax_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - } - - if (bmsr & PHY_BMSR_100BTXFULL) { - if (bootverbose) - printf("ax%d: 100Mbps full-duplex mode supported\n", - sc->ax_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - } - - /* Some also support 100BaseT4. */ - if (bmsr & PHY_BMSR_100BT4) { - if (bootverbose) - printf("ax%d: 100baseT4 mode supported\n", sc->ax_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4; -#ifdef FORCE_AUTONEG_TFOUR - if (bootverbose) - printf("ax%d: forcing on autoneg support for BT4\n", - sc->ax_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; -#endif - } - - if (bmsr & PHY_BMSR_CANAUTONEG) { - if (bootverbose) - printf("ax%d: autoneg supported\n", sc->ax_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; - } - - return; -} - -/* - * Set speed and duplex mode. - */ -static void ax_setmode_mii(sc, media) - struct ax_softc *sc; - int media; -{ - u_int16_t bmcr; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - /* - * If an autoneg session is in progress, stop it. - */ - if (sc->ax_autoneg) { - printf("ax%d: canceling autoneg session\n", sc->ax_unit); - ifp->if_timer = sc->ax_autoneg = sc->ax_want_auto = 0; - bmcr = ax_phy_readreg(sc, PHY_BMCR); - bmcr &= ~PHY_BMCR_AUTONEGENBL; - ax_phy_writereg(sc, PHY_BMCR, bmcr); - } - - printf("ax%d: selecting MII, ", sc->ax_unit); - - bmcr = ax_phy_readreg(sc, PHY_BMCR); - - bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL| - PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); - - if (IFM_SUBTYPE(media) == IFM_100_T4) { - printf("100Mbps/T4, half-duplex\n"); - bmcr |= PHY_BMCR_SPEEDSEL; - bmcr &= ~PHY_BMCR_DUPLEX; - } - - if (IFM_SUBTYPE(media) == IFM_100_TX) { - printf("100Mbps, "); - bmcr |= PHY_BMCR_SPEEDSEL; - } - - if (IFM_SUBTYPE(media) == IFM_10_T) { - printf("10Mbps, "); - bmcr &= ~PHY_BMCR_SPEEDSEL; - } - - if ((media & IFM_GMASK) == IFM_FDX) { - printf("full duplex\n"); - bmcr |= PHY_BMCR_DUPLEX; - } else { - printf("half duplex\n"); - bmcr &= ~PHY_BMCR_DUPLEX; - } - - ax_setcfg(sc, bmcr); - ax_phy_writereg(sc, PHY_BMCR, bmcr); - - return; -} - -/* - * Set speed and duplex mode on internal transceiver. - */ -static void ax_setmode(sc, media, verbose) - struct ax_softc *sc; - int media; - int verbose; -{ - struct ifnet *ifp; - u_int32_t mode; - - ifp = &sc->arpcom.ac_if; - - if (verbose) - printf("ax%d: selecting internal xcvr, ", sc->ax_unit); - - mode = CSR_READ_4(sc, AX_NETCFG); - - mode &= ~(AX_NETCFG_FULLDUPLEX|AX_NETCFG_PORTSEL| - AX_NETCFG_PCS|AX_NETCFG_SCRAMBLER|AX_NETCFG_SPEEDSEL); - - if (IFM_SUBTYPE(media) == IFM_100_T4) { - if (verbose) - printf("100Mbps/T4, half-duplex\n"); - mode |= AX_NETCFG_PORTSEL|AX_NETCFG_PCS|AX_NETCFG_SCRAMBLER; - } - - if (IFM_SUBTYPE(media) == IFM_100_TX) { - if (verbose) - printf("100Mbps, "); - mode |= AX_NETCFG_PORTSEL|AX_NETCFG_PCS|AX_NETCFG_SCRAMBLER; - } - - if (IFM_SUBTYPE(media) == IFM_10_T) { - if (verbose) - printf("10Mbps, "); - mode &= ~AX_NETCFG_PORTSEL; - mode |= AX_NETCFG_SPEEDSEL; - } - - if ((media & IFM_GMASK) == IFM_FDX) { - if (verbose) - printf("full duplex\n"); - mode |= AX_NETCFG_FULLDUPLEX; - } else { - if (verbose) - printf("half duplex\n"); - mode &= ~AX_NETCFG_FULLDUPLEX; - } - - CSR_WRITE_4(sc, AX_NETCFG, mode); - - return; -} - -/* - * In order to fiddle with the - * 'full-duplex' and '100Mbps' bits in the netconfig register, we - * first have to put the transmit and/or receive logic in the idle state. - */ -static void ax_setcfg(sc, bmcr) - struct ax_softc *sc; - int bmcr; -{ - int i, restart = 0; - - if (CSR_READ_4(sc, AX_NETCFG) & (AX_NETCFG_TX_ON|AX_NETCFG_RX_ON)) { - restart = 1; - AX_CLRBIT(sc, AX_NETCFG, (AX_NETCFG_TX_ON|AX_NETCFG_RX_ON)); - - for (i = 0; i < AX_TIMEOUT; i++) { - DELAY(10); - if (CSR_READ_4(sc, AX_ISR) & AX_ISR_TX_IDLE) - break; - } - - if (i == AX_TIMEOUT) - printf("ax%d: failed to force tx and " - "rx to idle state\n", sc->ax_unit); - - } - - if (bmcr & PHY_BMCR_SPEEDSEL) - AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_SPEEDSEL); - else - AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_SPEEDSEL); - - if (bmcr & PHY_BMCR_DUPLEX) - AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_FULLDUPLEX); - else - AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_FULLDUPLEX); - - if (restart) - AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_TX_ON|AX_NETCFG_RX_ON); - - return; -} - -static void ax_reset(sc) - struct ax_softc *sc; -{ - register int i; - - AX_SETBIT(sc, AX_BUSCTL, AX_BUSCTL_RESET); - - for (i = 0; i < AX_TIMEOUT; i++) { - DELAY(10); - if (!(CSR_READ_4(sc, AX_BUSCTL) & AX_BUSCTL_RESET)) - break; - } -#ifdef notdef - if (i == AX_TIMEOUT) - printf("ax%d: reset never completed!\n", sc->ax_unit); -#endif - CSR_WRITE_4(sc, AX_BUSCTL, AX_BUSCTL_CONFIG); - - /* Wait a little while for the chip to get its brains in order. */ - DELAY(1000); - return; -} - -/* - * Probe for an ASIX chip. Check the PCI vendor and device - * IDs against our list and return a device name if we find a match. - */ -static const char * -ax_probe(config_id, device_id) - pcici_t config_id; - pcidi_t device_id; -{ - struct ax_type *t; - - t = ax_devs; - - while(t->ax_name != NULL) { - if ((device_id & 0xFFFF) == t->ax_vid && - ((device_id >> 16) & 0xFFFF) == t->ax_did) { - return(t->ax_name); - } - t++; - } - - return(NULL); -} - -/* - * Attach the interface. Allocate softc structures, do ifmedia - * setup and ethernet/BPF attach. - */ -static void -ax_attach(config_id, unit) - pcici_t config_id; - int unit; -{ - int s, i; -#ifndef AX_USEIOSPACE - vm_offset_t pbase, vbase; -#endif - u_char eaddr[ETHER_ADDR_LEN]; - u_int32_t command; - struct ax_softc *sc; - struct ifnet *ifp; - int media = IFM_ETHER|IFM_100_TX|IFM_FDX; - unsigned int round; - caddr_t roundptr; - struct ax_type *p; - u_int16_t phy_vid, phy_did, phy_sts; - - s = splimp(); - - sc = malloc(sizeof(struct ax_softc), M_DEVBUF, M_NOWAIT); - if (sc == NULL) { - printf("ax%d: no memory for softc struct!\n", unit); - goto fail; - } - bzero(sc, sizeof(struct ax_softc)); - - /* - * Handle power management nonsense. - */ - - command = pci_conf_read(config_id, AX_PCI_CAPID) & 0x000000FF; - if (command == 0x01) { - - command = pci_conf_read(config_id, AX_PCI_PWRMGMTCTRL); - if (command & AX_PSTATE_MASK) { - u_int32_t iobase, membase, irq; - - /* Save important PCI config data. */ - iobase = pci_conf_read(config_id, AX_PCI_LOIO); - membase = pci_conf_read(config_id, AX_PCI_LOMEM); - irq = pci_conf_read(config_id, AX_PCI_INTLINE); - - /* Reset the power state. */ - printf("ax%d: chip is in D%d power mode " - "-- setting to D0\n", unit, command & AX_PSTATE_MASK); - command &= 0xFFFFFFFC; - pci_conf_write(config_id, AX_PCI_PWRMGMTCTRL, command); - - /* Restore PCI config data. */ - pci_conf_write(config_id, AX_PCI_LOIO, iobase); - pci_conf_write(config_id, AX_PCI_LOMEM, membase); - pci_conf_write(config_id, AX_PCI_INTLINE, irq); - } - } - - /* - * Map control/status registers. - */ - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); - pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - -#ifdef AX_USEIOSPACE - if (!(command & PCIM_CMD_PORTEN)) { - printf("ax%d: failed to enable I/O ports!\n", unit); - free(sc, M_DEVBUF); - goto fail; - } - - if (!pci_map_port(config_id, AX_PCI_LOIO, - (u_short *)&(sc->ax_bhandle))) { - printf ("ax%d: couldn't map ports\n", unit); - goto fail; - } - sc->ax_btag = I386_BUS_SPACE_IO; -#else - if (!(command & PCIM_CMD_MEMEN)) { - printf("ax%d: failed to enable memory mapping!\n", unit); - goto fail; - } - - if (!pci_map_mem(config_id, AX_PCI_LOMEM, &vbase, &pbase)) { - printf ("ax%d: couldn't map memory\n", unit); - goto fail; - } - sc->ax_btag = I386_BUS_SPACE_MEM; - sc->ax_bhandle = vbase; -#endif - - /* Allocate interrupt */ - if (!pci_map_int(config_id, ax_intr, sc, &net_imask)) { - printf("ax%d: couldn't map interrupt\n", unit); - goto fail; - } - - /* Reset the adapter. */ - ax_reset(sc); - - /* - * Get station address from the EEPROM. - */ - ax_read_eeprom(sc, (caddr_t)&eaddr, AX_EE_NODEADDR, 3, 0); - - /* - * An ASIX chip was detected. Inform the world. - */ - printf("ax%d: Ethernet address: %6D\n", unit, eaddr, ":"); - - sc->ax_unit = unit; - bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); - - sc->ax_ldata_ptr = malloc(sizeof(struct ax_list_data) + 8, - M_DEVBUF, M_NOWAIT); - if (sc->ax_ldata_ptr == NULL) { - free(sc, M_DEVBUF); - printf("ax%d: no memory for list buffers!\n", unit); - goto fail; - } - - sc->ax_ldata = (struct ax_list_data *)sc->ax_ldata_ptr; - round = (unsigned int)sc->ax_ldata_ptr & 0xF; - roundptr = sc->ax_ldata_ptr; - for (i = 0; i < 8; i++) { - if (round % 8) { - round++; - roundptr++; - } else - break; - } - sc->ax_ldata = (struct ax_list_data *)roundptr; - bzero(sc->ax_ldata, sizeof(struct ax_list_data)); - - ifp = &sc->arpcom.ac_if; - ifp->if_softc = sc; - ifp->if_unit = unit; - ifp->if_name = "ax"; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = ax_ioctl; - ifp->if_output = ether_output; - ifp->if_start = ax_start; - ifp->if_watchdog = ax_watchdog; - ifp->if_init = ax_init; - ifp->if_baudrate = 10000000; - - - if (bootverbose) - printf("ax%d: probing for a PHY\n", sc->ax_unit); - for (i = AX_PHYADDR_MIN; i < AX_PHYADDR_MAX + 1; i++) { - if (bootverbose) - printf("ax%d: checking address: %d\n", - sc->ax_unit, i); - sc->ax_phy_addr = i; - ax_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(ax_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - if ((phy_sts = ax_phy_readreg(sc, PHY_BMSR))) - break; - } - if (phy_sts) { - phy_vid = ax_phy_readreg(sc, PHY_VENID); - phy_did = ax_phy_readreg(sc, PHY_DEVID); - if (bootverbose) - printf("ax%d: found PHY at address %d, ", - sc->ax_unit, sc->ax_phy_addr); - if (bootverbose) - printf("vendor id: %x device id: %x\n", - phy_vid, phy_did); - p = ax_phys; - while(p->ax_vid) { - if (phy_vid == p->ax_vid && - (phy_did | 0x000F) == p->ax_did) { - sc->ax_pinfo = p; - break; - } - p++; - } - if (sc->ax_pinfo == NULL) - sc->ax_pinfo = &ax_phys[PHY_UNKNOWN]; - if (bootverbose) - printf("ax%d: PHY type: %s\n", - sc->ax_unit, sc->ax_pinfo->ax_name); - } else { -#ifdef DIAGNOSTIC - printf("ax%d: MII without any phy!\n", sc->ax_unit); -#endif - } - - /* - * Do ifmedia setup. - */ - ifmedia_init(&sc->ifmedia, 0, ax_ifmedia_upd, ax_ifmedia_sts); - - if (sc->ax_pinfo != NULL) { - ax_getmode_mii(sc); - ax_autoneg_mii(sc, AX_FLAG_FORCEDELAY, 1); - } else { - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); - } - - media = sc->ifmedia.ifm_media; - ax_stop(sc); - - ifmedia_set(&sc->ifmedia, media); - - /* - * Call MI attach routines. - */ - if_attach(ifp); - ether_ifattach(ifp); - -#if NBPFILTER > 0 - bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif - at_shutdown(ax_shutdown, sc, SHUTDOWN_POST_SYNC); - -fail: - splx(s); - return; -} - -/* - * Initialize the transmit descriptors. - */ -static int ax_list_tx_init(sc) - struct ax_softc *sc; -{ - struct ax_chain_data *cd; - struct ax_list_data *ld; - int i; - - cd = &sc->ax_cdata; - ld = sc->ax_ldata; - for (i = 0; i < AX_TX_LIST_CNT; i++) { - cd->ax_tx_chain[i].ax_ptr = &ld->ax_tx_list[i]; - if (i == (AX_TX_LIST_CNT - 1)) - cd->ax_tx_chain[i].ax_nextdesc = - &cd->ax_tx_chain[0]; - else - cd->ax_tx_chain[i].ax_nextdesc = - &cd->ax_tx_chain[i + 1]; - } - - cd->ax_tx_free = &cd->ax_tx_chain[0]; - cd->ax_tx_tail = cd->ax_tx_head = NULL; - - return(0); -} - - -/* - * Initialize the RX descriptors and allocate mbufs for them. Note that - * we arrange the descriptors in a closed ring, so that the last descriptor - * points back to the first. - */ -static int ax_list_rx_init(sc) - struct ax_softc *sc; -{ - struct ax_chain_data *cd; - struct ax_list_data *ld; - int i; - - cd = &sc->ax_cdata; - ld = sc->ax_ldata; - - for (i = 0; i < AX_RX_LIST_CNT; i++) { - cd->ax_rx_chain[i].ax_ptr = - (struct ax_desc *)&ld->ax_rx_list[i]; - if (ax_newbuf(sc, &cd->ax_rx_chain[i]) == ENOBUFS) - return(ENOBUFS); - if (i == (AX_RX_LIST_CNT - 1)) { - cd->ax_rx_chain[i].ax_nextdesc = - &cd->ax_rx_chain[0]; - ld->ax_rx_list[i].ax_next = - vtophys(&ld->ax_rx_list[0]); - } else { - cd->ax_rx_chain[i].ax_nextdesc = - &cd->ax_rx_chain[i + 1]; - ld->ax_rx_list[i].ax_next = - vtophys(&ld->ax_rx_list[i + 1]); - } - } - - cd->ax_rx_head = &cd->ax_rx_chain[0]; - - return(0); -} - -/* - * Initialize an RX descriptor and attach an MBUF cluster. - * Note: the length fields are only 11 bits wide, which means the - * largest size we can specify is 2047. This is important because - * MCLBYTES is 2048, so we have to subtract one otherwise we'll - * overflow the field and make a mess. - */ -static int ax_newbuf(sc, c) - struct ax_softc *sc; - struct ax_chain_onefrag *c; -{ - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("ax%d: no memory for rx list -- packet dropped!\n", - sc->ax_unit); - return(ENOBUFS); - } - - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - printf("ax%d: no memory for rx list -- packet dropped!\n", - sc->ax_unit); - m_freem(m_new); - return(ENOBUFS); - } - - c->ax_mbuf = m_new; - c->ax_ptr->ax_status = AX_RXSTAT; - c->ax_ptr->ax_data = vtophys(mtod(m_new, caddr_t)); - c->ax_ptr->ax_ctl = MCLBYTES - 1; - - return(0); -} - -/* - * A frame has been uploaded: pass the resulting mbuf chain up to - * the higher level protocols. - */ -static void ax_rxeof(sc) - struct ax_softc *sc; -{ - struct ether_header *eh; - struct mbuf *m; - struct ifnet *ifp; - struct ax_chain_onefrag *cur_rx; - int total_len = 0; - u_int32_t rxstat; - - ifp = &sc->arpcom.ac_if; - - while(!((rxstat = sc->ax_cdata.ax_rx_head->ax_ptr->ax_status) & - AX_RXSTAT_OWN)) { - cur_rx = sc->ax_cdata.ax_rx_head; - sc->ax_cdata.ax_rx_head = cur_rx->ax_nextdesc; - - /* - * If an error occurs, update stats, clear the - * status word and leave the mbuf cluster in place: - * it should simply get re-used next time this descriptor - * comes up in the ring. - */ - if (rxstat & AX_RXSTAT_RXERR) { - ifp->if_ierrors++; - if (rxstat & AX_RXSTAT_COLLSEEN) - ifp->if_collisions++; - cur_rx->ax_ptr->ax_status = AX_RXSTAT; - cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1); - continue; - } - - /* No errors; receive the packet. */ - m = cur_rx->ax_mbuf; - total_len = AX_RXBYTES(cur_rx->ax_ptr->ax_status); - - total_len -= ETHER_CRC_LEN; - - if (total_len < MINCLSIZE) { - m = m_devget(mtod(cur_rx->ax_mbuf, char *), - total_len, 0, ifp, NULL); - cur_rx->ax_ptr->ax_status = AX_RXSTAT; - cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1); - if (m == NULL) { - ifp->if_ierrors++; - continue; - } - } else { - m = cur_rx->ax_mbuf; - /* - * Try to conjure up a new mbuf cluster. If that - * fails, it means we have an out of memory condition and - * should leave the buffer in place and continue. This will - * result in a lost packet, but there's little else we - * can do in this situation. - */ - if (ax_newbuf(sc, cur_rx) == ENOBUFS) { - ifp->if_ierrors++; - cur_rx->ax_ptr->ax_status = AX_RXSTAT; - cur_rx->ax_ptr->ax_ctl = (MCLBYTES - 1); - continue; - } - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = m->m_len = total_len; - } - - ifp->if_ipackets++; - eh = mtod(m, struct ether_header *); -#if NBPFILTER > 0 - /* - * Handle BPF listeners. Let the BPF user see the packet, but - * don't pass it up to the ether_input() layer unless it's - * a broadcast packet, multicast packet, matches our ethernet - * address or the interface is in promiscuous mode. - */ - if (ifp->if_bpf) { - bpf_mtap(ifp, m); - if (ifp->if_flags & IFF_PROMISC && - (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, - ETHER_ADDR_LEN) && - (eh->ether_dhost[0] & 1) == 0)) { - m_freem(m); - continue; - } - } -#endif - /* Remove header from mbuf and pass it on. */ - m_adj(m, sizeof(struct ether_header)); - ether_input(ifp, eh, m); - } - - return; -} - -void ax_rxeoc(sc) - struct ax_softc *sc; -{ - - ax_rxeof(sc); - AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_RX_ON); - CSR_WRITE_4(sc, AX_RXADDR, vtophys(sc->ax_cdata.ax_rx_head->ax_ptr)); - AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_RX_ON); - CSR_WRITE_4(sc, AX_RXSTART, 0xFFFFFFFF); - - return; -} - -/* - * A frame was downloaded to the chip. It's safe for us to clean up - * the list buffers. - */ - -static void ax_txeof(sc) - struct ax_softc *sc; -{ - struct ax_chain *cur_tx; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - /* Clear the timeout timer. */ - ifp->if_timer = 0; - - if (sc->ax_cdata.ax_tx_head == NULL) - return; - - /* - * Go through our tx list and free mbufs for those - * frames that have been transmitted. - */ - while(sc->ax_cdata.ax_tx_head->ax_mbuf != NULL) { - u_int32_t txstat; - - cur_tx = sc->ax_cdata.ax_tx_head; - txstat = AX_TXSTATUS(cur_tx); - - if (txstat & AX_TXSTAT_OWN) - break; - - if (txstat & AX_TXSTAT_ERRSUM) { - ifp->if_oerrors++; - if (txstat & AX_TXSTAT_EXCESSCOLL) - ifp->if_collisions++; - if (txstat & AX_TXSTAT_LATECOLL) - ifp->if_collisions++; - } - - ifp->if_collisions += (txstat & AX_TXSTAT_COLLCNT) >> 3; - - ifp->if_opackets++; - m_freem(cur_tx->ax_mbuf); - cur_tx->ax_mbuf = NULL; - - if (sc->ax_cdata.ax_tx_head == sc->ax_cdata.ax_tx_tail) { - sc->ax_cdata.ax_tx_head = NULL; - sc->ax_cdata.ax_tx_tail = NULL; - break; - } - - sc->ax_cdata.ax_tx_head = cur_tx->ax_nextdesc; - } - - return; -} - -/* - * TX 'end of channel' interrupt handler. - */ -static void ax_txeoc(sc) - struct ax_softc *sc; -{ - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - ifp->if_timer = 0; - - if (sc->ax_cdata.ax_tx_head == NULL) { - ifp->if_flags &= ~IFF_OACTIVE; - sc->ax_cdata.ax_tx_tail = NULL; - if (sc->ax_want_auto) - ax_autoneg_mii(sc, AX_FLAG_DELAYTIMEO, 1); - } - - return; -} - -static void ax_intr(arg) - void *arg; -{ - struct ax_softc *sc; - struct ifnet *ifp; - u_int32_t status; - - sc = arg; - ifp = &sc->arpcom.ac_if; - - /* Supress unwanted interrupts */ - if (!(ifp->if_flags & IFF_UP)) { - ax_stop(sc); - return; - } - - /* Disable interrupts. */ - CSR_WRITE_4(sc, AX_IMR, 0x00000000); - - for (;;) { - status = CSR_READ_4(sc, AX_ISR); - if (status) - CSR_WRITE_4(sc, AX_ISR, status); - - if ((status & AX_INTRS) == 0) - break; - - if ((status & AX_ISR_TX_OK) || (status & AX_ISR_TX_EARLY)) - ax_txeof(sc); - - if (status & AX_ISR_TX_NOBUF) - ax_txeoc(sc); - - if (status & AX_ISR_TX_IDLE) { - ax_txeof(sc); - if (sc->ax_cdata.ax_tx_head != NULL) { - AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_TX_ON); - CSR_WRITE_4(sc, AX_TXSTART, 0xFFFFFFFF); - } - } - - if (status & AX_ISR_TX_UNDERRUN) { - u_int32_t cfg; - cfg = CSR_READ_4(sc, AX_NETCFG); - if ((cfg & AX_NETCFG_TX_THRESH) == AX_TXTHRESH_160BYTES) - AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_STORENFWD); - else - CSR_WRITE_4(sc, AX_NETCFG, cfg + 0x4000); - } - - if (status & AX_ISR_RX_OK) - ax_rxeof(sc); - - if ((status & AX_ISR_RX_WATDOGTIMEO) - || (status & AX_ISR_RX_NOBUF)) - ax_rxeoc(sc); - - if (status & AX_ISR_BUS_ERR) { - ax_reset(sc); - ax_init(sc); - } - } - - /* Re-enable interrupts. */ - CSR_WRITE_4(sc, AX_IMR, AX_INTRS); - - if (ifp->if_snd.ifq_head != NULL) { - ax_start(ifp); - } - - return; -} - -/* - * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data - * pointers to the fragment pointers. - */ -static int ax_encap(sc, c, m_head) - struct ax_softc *sc; - struct ax_chain *c; - struct mbuf *m_head; -{ - int frag = 0; - volatile struct ax_desc *f = NULL; - int total_len; - struct mbuf *m; - - /* - * Start packing the mbufs in this chain into - * the fragment pointers. Stop when we run out - * of fragments or hit the end of the mbuf chain. - */ - m = m_head; - total_len = 0; - - for (m = m_head, frag = 0; m != NULL; m = m->m_next) { - if (m->m_len != 0) { - if (frag == AX_MAXFRAGS) - break; - total_len += m->m_len; - f = &c->ax_ptr->ax_frag[frag]; - f->ax_ctl = m->m_len; - if (frag == 0) { - f->ax_status = 0; - f->ax_ctl |= AX_TXCTL_FIRSTFRAG; - } else - f->ax_status = AX_TXSTAT_OWN; - f->ax_next = vtophys(&c->ax_ptr->ax_frag[frag + 1]); - f->ax_data = vtophys(mtod(m, vm_offset_t)); - frag++; - } - } - - /* - * Handle special case: we ran out of fragments, - * but we have more mbufs left in the chain. Copy the - * data into an mbuf cluster. Note that we don't - * bother clearing the values in the other fragment - * pointers/counters; it wouldn't gain us anything, - * and would waste cycles. - */ - if (m != NULL) { - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("ax%d: no memory for tx list", sc->ax_unit); - return(1); - } - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - printf("ax%d: no memory for tx list", - sc->ax_unit); - return(1); - } - } - m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; - m_freem(m_head); - m_head = m_new; - f = &c->ax_ptr->ax_frag[0]; - f->ax_status = 0; - f->ax_data = vtophys(mtod(m_new, caddr_t)); - f->ax_ctl = total_len = m_new->m_len; - f->ax_ctl |= AX_TXCTL_FIRSTFRAG; - frag = 1; - } - - c->ax_mbuf = m_head; - c->ax_lastdesc = frag - 1; - AX_TXCTL(c) |= AX_TXCTL_LASTFRAG|AX_TXCTL_FINT; - c->ax_ptr->ax_frag[0].ax_ctl |= AX_TXCTL_FINT; - AX_TXNEXT(c) = vtophys(&c->ax_nextdesc->ax_ptr->ax_frag[0]); - return(0); -} - -/* - * Main transmit routine. To avoid having to do mbuf copies, we put pointers - * to the mbuf data regions directly in the transmit lists. We also save a - * copy of the pointers since the transmit list fragment pointers are - * physical addresses. - */ - -static void ax_start(ifp) - struct ifnet *ifp; -{ - struct ax_softc *sc; - struct mbuf *m_head = NULL; - struct ax_chain *cur_tx = NULL, *start_tx; - - sc = ifp->if_softc; - - if (sc->ax_autoneg) { - sc->ax_tx_pend = 1; - return; - } - - /* - * Check for an available queue slot. If there are none, - * punt. - */ - if (sc->ax_cdata.ax_tx_free->ax_mbuf != NULL) { - ifp->if_flags |= IFF_OACTIVE; - return; - } - - start_tx = sc->ax_cdata.ax_tx_free; - - while(sc->ax_cdata.ax_tx_free->ax_mbuf == NULL) { - IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) - break; - - /* Pick a descriptor off the free list. */ - cur_tx = sc->ax_cdata.ax_tx_free; - sc->ax_cdata.ax_tx_free = cur_tx->ax_nextdesc; - - /* Pack the data into the descriptor. */ - ax_encap(sc, cur_tx, m_head); - if (cur_tx != start_tx) - AX_TXOWN(cur_tx) = AX_TXSTAT_OWN; - -#if NBPFILTER > 0 - /* - * If there's a BPF listener, bounce a copy of this frame - * to him. - */ - if (ifp->if_bpf) - bpf_mtap(ifp, cur_tx->ax_mbuf); -#endif - AX_TXOWN(cur_tx) = AX_TXSTAT_OWN; - CSR_WRITE_4(sc, AX_TXSTART, 0xFFFFFFFF); - } - - sc->ax_cdata.ax_tx_tail = cur_tx; - if (sc->ax_cdata.ax_tx_head == NULL) - sc->ax_cdata.ax_tx_head = start_tx; - - /* - * Set a timeout in case the chip goes out to lunch. - */ - ifp->if_timer = 5; - - return; -} - -static void ax_init(xsc) - void *xsc; -{ - struct ax_softc *sc = xsc; - struct ifnet *ifp = &sc->arpcom.ac_if; - u_int16_t phy_bmcr = 0; - int s; - - if (sc->ax_autoneg) - return; - - s = splimp(); - - if (sc->ax_pinfo != NULL) - phy_bmcr = ax_phy_readreg(sc, PHY_BMCR); - - /* - * Cancel pending I/O and free all RX/TX buffers. - */ - ax_stop(sc); - ax_reset(sc); - - /* - * Set cache alignment and burst length. - */ - CSR_WRITE_4(sc, AX_BUSCTL, AX_BUSCTL_CONFIG); - - AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_HEARTBEAT); - AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_STORENFWD); - - if (sc->ax_pinfo != NULL) { - AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_PORTSEL); - ax_setcfg(sc, ax_phy_readreg(sc, PHY_BMCR)); - } else - ax_setmode(sc, sc->ifmedia.ifm_media, 0); - - AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_TX_THRESH); - AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_SPEEDSEL); - - if (IFM_SUBTYPE(sc->ifmedia.ifm_media) == IFM_10_T) - AX_SETBIT(sc, AX_NETCFG, AX_TXTHRESH_160BYTES); - else - AX_SETBIT(sc, AX_NETCFG, AX_TXTHRESH_72BYTES); - - /* Init our MAC address */ - CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_PAR0); - CSR_WRITE_4(sc, AX_FILTDATA, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0])); - CSR_WRITE_4(sc, AX_FILTIDX, AX_FILTIDX_PAR1); - CSR_WRITE_4(sc, AX_FILTDATA, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4])); - - /* Init circular RX list. */ - if (ax_list_rx_init(sc) == ENOBUFS) { - printf("ax%d: initialization failed: no " - "memory for rx buffers\n", sc->ax_unit); - ax_stop(sc); - (void)splx(s); - return; - } - - /* - * Init tx descriptors. - */ - ax_list_tx_init(sc); - - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) { - AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_RX_PROMISC); - } else { - AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_RX_PROMISC); - } - - /* - * Set the capture broadcast bit to capture broadcast frames. - */ - if (ifp->if_flags & IFF_BROADCAST) { - AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_RX_BROAD); - } else { - AX_CLRBIT(sc, AX_NETCFG, AX_NETCFG_RX_BROAD); - } - - /* - * Load the multicast filter. - */ - ax_setmulti(sc); - - /* - * Load the address of the RX list. - */ - CSR_WRITE_4(sc, AX_RXADDR, vtophys(sc->ax_cdata.ax_rx_head->ax_ptr)); - CSR_WRITE_4(sc, AX_TXADDR, vtophys(&sc->ax_ldata->ax_tx_list[0])); - - /* - * Enable interrupts. - */ - CSR_WRITE_4(sc, AX_IMR, AX_INTRS); - CSR_WRITE_4(sc, AX_ISR, 0xFFFFFFFF); - - /* Enable receiver and transmitter. */ - AX_SETBIT(sc, AX_NETCFG, AX_NETCFG_TX_ON|AX_NETCFG_RX_ON); - CSR_WRITE_4(sc, AX_RXSTART, 0xFFFFFFFF); - - /* Restore state of BMCR */ - if (sc->ax_pinfo != NULL) - ax_phy_writereg(sc, PHY_BMCR, phy_bmcr); - - ifp->if_flags |= IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - - (void)splx(s); - - return; -} - -/* - * Set media options. - */ -static int ax_ifmedia_upd(ifp) - struct ifnet *ifp; -{ - struct ax_softc *sc; - struct ifmedia *ifm; - - sc = ifp->if_softc; - ifm = &sc->ifmedia; - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return(EINVAL); - - if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) - ax_autoneg_mii(sc, AX_FLAG_SCHEDDELAY, 1); - else { - if (sc->ax_pinfo == NULL) - ax_setmode(sc, ifm->ifm_media, 1); - else - ax_setmode_mii(sc, ifm->ifm_media); - } - - return(0); -} - -/* - * Report current media status. - */ -static void ax_ifmedia_sts(ifp, ifmr) - struct ifnet *ifp; - struct ifmediareq *ifmr; -{ - struct ax_softc *sc; - u_int16_t advert = 0, ability = 0; - u_int32_t media = 0; - - sc = ifp->if_softc; - - ifmr->ifm_active = IFM_ETHER; - - if (sc->ax_pinfo == NULL) { - media = CSR_READ_4(sc, AX_NETCFG); - if (media & AX_NETCFG_PORTSEL) - ifmr->ifm_active = IFM_ETHER|IFM_100_TX; - else - ifmr->ifm_active = IFM_ETHER|IFM_10_T; - if (media & AX_NETCFG_FULLDUPLEX) - ifmr->ifm_active |= IFM_FDX; - else - ifmr->ifm_active |= IFM_HDX; - return; - } - - if (!(ax_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { - if (ax_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) - ifmr->ifm_active = IFM_ETHER|IFM_100_TX; - else - ifmr->ifm_active = IFM_ETHER|IFM_10_T; - if (ax_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) - ifmr->ifm_active |= IFM_FDX; - else - ifmr->ifm_active |= IFM_HDX; - return; - } - - ability = ax_phy_readreg(sc, PHY_LPAR); - advert = ax_phy_readreg(sc, PHY_ANAR); - if (advert & PHY_ANAR_100BT4 && - ability & PHY_ANAR_100BT4) { - ifmr->ifm_active = IFM_ETHER|IFM_100_T4; - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX; - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX; - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX; - } else if (advert & PHY_ANAR_10BTHALF && - ability & PHY_ANAR_10BTHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX; - } - - return; -} - -static int ax_ioctl(ifp, command, data) - struct ifnet *ifp; - u_long command; - caddr_t data; -{ - struct ax_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; - int s, error = 0; - - s = splimp(); - - switch(command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; - case SIOCSIFFLAGS: - if (ifp->if_flags & IFF_UP) { - ax_init(sc); - } else { - if (ifp->if_flags & IFF_RUNNING) - ax_stop(sc); - } - error = 0; - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - ax_setmulti(sc); - error = 0; - break; - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); - break; - default: - error = EINVAL; - break; - } - - (void)splx(s); - - return(error); -} - -static void ax_watchdog(ifp) - struct ifnet *ifp; -{ - struct ax_softc *sc; - - sc = ifp->if_softc; - - if (sc->ax_autoneg) { - ax_autoneg_mii(sc, AX_FLAG_DELAYTIMEO, 1); - return; - } - - ifp->if_oerrors++; - printf("ax%d: watchdog timeout\n", sc->ax_unit); - - if (sc->ax_pinfo != NULL) { - if (!(ax_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) - printf("ax%d: no carrier - transceiver " - "cable problem?\n", sc->ax_unit); - } - - ax_stop(sc); - ax_reset(sc); - ax_init(sc); - - if (ifp->if_snd.ifq_head != NULL) - ax_start(ifp); - - return; -} - -/* - * Stop the adapter and free any mbufs allocated to the - * RX and TX lists. - */ -static void ax_stop(sc) - struct ax_softc *sc; -{ - register int i; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - ifp->if_timer = 0; - - AX_CLRBIT(sc, AX_NETCFG, (AX_NETCFG_RX_ON|AX_NETCFG_TX_ON)); - CSR_WRITE_4(sc, AX_IMR, 0x00000000); - CSR_WRITE_4(sc, AX_TXADDR, 0x00000000); - CSR_WRITE_4(sc, AX_RXADDR, 0x00000000); - - /* - * Free data in the RX lists. - */ - for (i = 0; i < AX_RX_LIST_CNT; i++) { - if (sc->ax_cdata.ax_rx_chain[i].ax_mbuf != NULL) { - m_freem(sc->ax_cdata.ax_rx_chain[i].ax_mbuf); - sc->ax_cdata.ax_rx_chain[i].ax_mbuf = NULL; - } - } - bzero((char *)&sc->ax_ldata->ax_rx_list, - sizeof(sc->ax_ldata->ax_rx_list)); - - /* - * Free the TX list buffers. - */ - for (i = 0; i < AX_TX_LIST_CNT; i++) { - if (sc->ax_cdata.ax_tx_chain[i].ax_mbuf != NULL) { - m_freem(sc->ax_cdata.ax_tx_chain[i].ax_mbuf); - sc->ax_cdata.ax_tx_chain[i].ax_mbuf = NULL; - } - } - - bzero((char *)&sc->ax_ldata->ax_tx_list, - sizeof(sc->ax_ldata->ax_tx_list)); - - ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - - return; -} - -/* - * Stop all chip I/O so that the kernel's probe routines don't - * get confused by errant DMAs when rebooting. - */ -static void ax_shutdown(howto, arg) - int howto; - void *arg; -{ - struct ax_softc *sc = (struct ax_softc *)arg; - - ax_stop(sc); - - return; -} - -static struct pci_device ax_device = { - "ax", - ax_probe, - ax_attach, - &ax_count, - NULL -}; -DATA_SET(pcidevice_set, ax_device); diff --git a/sys/pci/if_axreg.h b/sys/pci/if_axreg.h deleted file mode 100644 index 700c42ca9463..000000000000 --- a/sys/pci/if_axreg.h +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Copyright (c) 1997, 1998, 1999 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_axreg.h,v 1.4 1999/01/16 20:33:34 wpaul Exp $ - */ - -/* - * ASIX register definitions. - */ - -#define AX_BUSCTL 0x00 /* bus control */ -#define AX_TXSTART 0x08 /* tx start demand */ -#define AX_RXSTART 0x10 /* rx start demand */ -#define AX_RXADDR 0x18 /* rx descriptor list start addr */ -#define AX_TXADDR 0x20 /* tx descriptor list start addr */ -#define AX_ISR 0x28 /* interrupt status register */ -#define AX_NETCFG 0x30 /* network config register */ -#define AX_IMR 0x38 /* interrupt mask */ -#define AX_FRAMESDISCARDED 0x40 /* # of discarded frames */ -#define AX_SIO 0x48 /* MII and ROM/EEPROM access */ -#define AX_RESERVED 0x50 -#define AX_GENTIMER 0x58 /* general timer */ -#define AX_GENPORT 0x60 /* general purpose port */ -#define AX_FILTIDX 0x68 /* RX filter index */ -#define AX_FILTDATA 0x70 /* RX filter data */ - -/* - * Bus control bits. - */ -#define AX_BUSCTL_RESET 0x00000001 -#define AX_BUSCTL_ARBITRATION 0x00000002 -#define AX_BUSCTL_BIGENDIAN 0x00000080 -#define AX_BUSCTL_BURSTLEN 0x00003F00 -#define AX_BUSCTL_BUF_BIGENDIAN 0x00100000 -#define AX_BISCTL_READMULTI 0x00200000 - -#define AX_BURSTLEN_UNLIMIT 0x00000000 -#define AX_BURSTLEN_1LONG 0x00000100 -#define AX_BURSTLEN_2LONG 0x00000200 -#define AX_BURSTLEN_4LONG 0x00000400 -#define AX_BURSTLEN_8LONG 0x00000800 -#define AX_BURSTLEN_16LONG 0x00001000 -#define AX_BURSTLEN_32LONG 0x00002000 - -#define AX_BUSCTL_CONFIG (AX_BUSCTL_ARBITRATION|AX_BURSTLEN_8LONG|AX_BURSTLEN_8LONG) - -/* - * Interrupt status bits. - */ -#define AX_ISR_TX_OK 0x00000001 -#define AX_ISR_TX_IDLE 0x00000002 -#define AX_ISR_TX_NOBUF 0x00000004 -#define AX_ISR_TX_JABBERTIMEO 0x00000008 -#define AX_ISR_TX_UNDERRUN 0x00000020 -#define AX_ISR_RX_OK 0x00000040 -#define AX_ISR_RX_NOBUF 0x00000080 -#define AX_ISR_RX_IDLE 0x00000100 -#define AX_ISR_RX_WATDOGTIMEO 0x00000200 -#define AX_ISR_TX_EARLY 0x00000400 -#define AX_ISR_TIMER_EXPIRED 0x00000800 -#define AX_ISR_BUS_ERR 0x00002000 -#define AX_ISR_ABNORMAL 0x00008000 -#define AX_ISR_NORMAL 0x00010000 -#define AX_ISR_RX_STATE 0x000E0000 -#define AX_ISR_TX_STATE 0x00700000 -#define AX_ISR_BUSERRTYPE 0x03800000 - -#define AX_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */ -#define AX_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */ -#define AX_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */ -#define AX_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */ -#define AX_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */ -#define AX_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */ -#define AX_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */ -#define AX_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */ - -#define AX_TXSTATE_RESET 0x00000000 /* 000 - reset */ -#define AX_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */ -#define AX_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */ -#define AX_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */ -#define AX_TXSTATE_RSVD 0x00400000 /* 100 - reserved */ -#define AX_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */ -#define AX_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */ -#define AX_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */ - -/* - * Network config bits. - */ -#define AX_NETCFG_LINKSTAT_PCS 0x00000001 -#define AX_NETCFG_RX_ON 0x00000002 -#define AX_NETCFG_RX_BADFRAMES 0x00000008 -#define AX_NETCFG_RX_PROMISC 0x00000040 -#define AX_NETCFG_RX_ALLMULTI 0x00000080 -#define AX_NETCFG_RX_BROAD 0x00000100 -#define AX_NETCFG_FULLDUPLEX 0x00000200 -#define AX_NETCFG_LOOPBACK 0x00000C00 -#define AX_NETCFG_FORCECOLL 0x00001000 -#define AX_NETCFG_TX_ON 0x00002000 -#define AX_NETCFG_TX_THRESH 0x0000C000 -#define AX_NETCFG_PORTSEL 0x00040000 /* 0 == SRL, 1 == MII/SYM */ -#define AX_NETCFG_HEARTBEAT 0x00080000 /* 0 == ON, 1 == OFF */ -#define AX_NETCFG_STORENFWD 0x00200000 -#define AX_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10, 0 == 100 */ -#define AX_NETCFG_PCS 0x00800000 -#define AX_NETCFG_SCRAMBLER 0x01000000 -#define AX_NETCFG_RX_ALL 0x40000000 - -#define AX_OPMODE_NORM 0x00000000 -#define AX_OPMODE_INTLOOP 0x00000400 -#define AX_OPMODE_EXTLOOP 0x00000800 - -#define AX_TXTHRESH_72BYTES 0x00000000 -#define AX_TXTHRESH_96BYTES 0x00004000 -#define AX_TXTHRESH_128BYTES 0x00008000 -#define AX_TXTHRESH_160BYTES 0x0000C000 - -/* - * Interrupt mask bits. - */ -#define AX_IMR_TX_OK 0x00000001 -#define AX_IMR_TX_IDLE 0x00000002 -#define AX_IMR_TX_NOBUF 0x00000004 -#define AX_IMR_TX_JABBERTIMEO 0x00000008 -#define AX_IMR_TX_UNDERRUN 0x00000020 -#define AX_IMR_RX_OK 0x00000040 -#define AX_IMR_RX_NOBUF 0x00000080 -#define AX_IMR_RX_IDLE 0x00000100 -#define AX_IMR_RX_WATDOGTIMEO 0x00000200 -#define AX_IMR_TX_EARLY 0x00000400 -#define AX_IMR_TIMER_EXPIRED 0x00000800 -#define AX_IMR_BUS_ERR 0x00002000 -#define AX_IMR_RX_EARLY 0x00004000 -#define AX_IMR_ABNORMAL 0x00008000 -#define AX_IMR_NORMAL 0x00010000 - -#define AX_INTRS \ - (AX_IMR_RX_OK|AX_IMR_TX_OK|AX_IMR_RX_NOBUF|AX_IMR_RX_WATDOGTIMEO|\ - AX_IMR_TX_NOBUF|AX_IMR_TX_UNDERRUN|AX_IMR_BUS_ERR| \ - AX_IMR_ABNORMAL|AX_IMR_NORMAL|/*AX_IMR_TX_EARLY*/ \ - AX_IMR_TX_IDLE|AX_IMR_RX_IDLE) - -/* - * Serial I/O (EEPROM/ROM) bits. - */ -#define AX_SIO_EE_CS 0x00000001 /* EEPROM chip select */ -#define AX_SIO_EE_CLK 0x00000002 /* EEPROM clock */ -#define AX_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */ -#define AX_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */ -#define AX_SIO_EESEL 0x00000800 -#define AX_SIO_ROMSEL 0x00001000 -#define AX_SIO_ROMCTL_WRITE 0x00002000 -#define AX_SIO_ROMCTL_READ 0x00004000 -#define AX_SIO_MII_CLK 0x00010000 /* MDIO clock */ -#define AX_SIO_MII_DATAOUT 0x00020000 /* MDIO data out */ -#define AX_SIO_MII_DIR 0x00040000 /* MDIO dir */ -#define AX_SIO_MII_DATAIN 0x00080000 /* MDIO data in */ - -#define AX_EECMD_WRITE 0x140 -#define AX_EECMD_READ 0x180 -#define AX_EECMD_ERASE 0x1c0 - -#define AX_EE_NODEADDR_OFFSET 0x70 -#define AX_EE_NODEADDR 10 - -/* - * General purpose timer register - */ -#define AX_TIMER_VALUE 0x0000FFFF -#define AX_TIMER_CONTINUOUS 0x00010000 - -/* - * RX Filter Index Register values - */ -#define AX_FILTIDX_PAR0 0x00000000 -#define AX_FILTIDX_PAR1 0x00000001 -#define AX_FILTIDX_MAR0 0x00000002 -#define AX_FILTIDX_MAR1 0x00000003 - -/* - * ASIX TX/RX list structure. - */ - -struct ax_desc { - volatile u_int32_t ax_status; - volatile u_int32_t ax_ctl; - volatile u_int32_t ax_ptr1; - volatile u_int32_t ax_ptr2; -}; - -#define ax_data ax_ptr1 -#define ax_next ax_ptr2 - -#define AX_RXSTAT_FIFOOFLOW 0x00000001 -#define AX_RXSTAT_CRCERR 0x00000002 -#define AX_RXSTAT_DRIBBLE 0x00000004 -#define AX_RXSTAT_WATCHDOG 0x00000010 -#define AX_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */ -#define AX_RXSTAT_COLLSEEN 0x00000040 -#define AX_RXSTAT_GIANT 0x00000080 -#define AX_RXSTAT_LASTFRAG 0x00000100 -#define AX_RXSTAT_FIRSTFRAG 0x00000200 -#define AX_RXSTAT_MULTICAST 0x00000400 -#define AX_RXSTAT_RUNT 0x00000800 -#define AX_RXSTAT_RXTYPE 0x00003000 -#define AX_RXSTAT_RXERR 0x00008000 -#define AX_RXSTAT_RXLEN 0x3FFF0000 -#define AX_RXSTAT_OWN 0x80000000 - -#define AX_RXBYTES(x) ((x & AX_RXSTAT_RXLEN) >> 16) -#define AX_RXSTAT (AX_RXSTAT_FIRSTFRAG|AX_RXSTAT_LASTFRAG|AX_RXSTAT_OWN) - -#define AX_RXCTL_BUFLEN1 0x00000FFF -#define AX_RXCTL_BUFLEN2 0x00FFF000 -#define AX_RXCTL_RLAST 0x02000000 - -#define AX_TXSTAT_DEFER 0x00000001 -#define AX_TXSTAT_UNDERRUN 0x00000002 -#define AX_TXSTAT_LINKFAIL 0x00000003 -#define AX_TXSTAT_COLLCNT 0x00000078 -#define AX_TXSTAT_SQE 0x00000080 -#define AX_TXSTAT_EXCESSCOLL 0x00000100 -#define AX_TXSTAT_LATECOLL 0x00000200 -#define AX_TXSTAT_NOCARRIER 0x00000400 -#define AX_TXSTAT_CARRLOST 0x00000800 -#define AX_TXSTAT_JABTIMEO 0x00004000 -#define AX_TXSTAT_ERRSUM 0x00008000 -#define AX_TXSTAT_OWN 0x80000000 - -#define AX_TXCTL_BUFLEN1 0x000007FF -#define AX_TXCTL_BUFLEN2 0x003FF800 -#define AX_TXCTL_PAD 0x00800000 -#define AX_TXCTL_TLAST 0x02000000 -#define AX_TXCTL_NOCRC 0x04000000 -#define AX_TXCTL_FIRSTFRAG 0x20000000 -#define AX_TXCTL_LASTFRAG 0x40000000 -#define AX_TXCTL_FINT 0x80000000 - -#define AX_MAXFRAGS 16 -#define AX_RX_LIST_CNT 64 -#define AX_TX_LIST_CNT 64 -#define AX_MIN_FRAMELEN 60 - -/* - * A tx 'super descriptor' is actually 16 regular descriptors - * back to back. - */ -struct ax_txdesc { - volatile struct ax_desc ax_frag[AX_MAXFRAGS]; -}; - -#define AX_TXNEXT(x) x->ax_ptr->ax_frag[x->ax_lastdesc].ax_next -#define AX_TXSTATUS(x) x->ax_ptr->ax_frag[x->ax_lastdesc].ax_status -#define AX_TXCTL(x) x->ax_ptr->ax_frag[x->ax_lastdesc].ax_ctl -#define AX_TXDATA(x) x->ax_ptr->ax_frag[x->ax_lastdesc].ax_data - -#define AX_TXOWN(x) x->ax_ptr->ax_frag[0].ax_status - -#define AX_UNSENT 0x12341234 - -struct ax_list_data { - volatile struct ax_desc ax_rx_list[AX_RX_LIST_CNT]; - volatile struct ax_txdesc ax_tx_list[AX_TX_LIST_CNT]; -}; - -struct ax_chain { - volatile struct ax_txdesc *ax_ptr; - struct mbuf *ax_mbuf; - struct ax_chain *ax_nextdesc; - u_int8_t ax_lastdesc; -}; - -struct ax_chain_onefrag { - volatile struct ax_desc *ax_ptr; - struct mbuf *ax_mbuf; - struct ax_chain_onefrag *ax_nextdesc; -}; - -struct ax_chain_data { - struct ax_chain_onefrag ax_rx_chain[AX_RX_LIST_CNT]; - struct ax_chain ax_tx_chain[AX_TX_LIST_CNT]; - - struct ax_chain_onefrag *ax_rx_head; - - struct ax_chain *ax_tx_head; - struct ax_chain *ax_tx_tail; - struct ax_chain *ax_tx_free; -}; - -struct ax_type { - u_int16_t ax_vid; - u_int16_t ax_did; - char *ax_name; -}; - -struct ax_mii_frame { - u_int8_t mii_stdelim; - u_int8_t mii_opcode; - u_int8_t mii_phyaddr; - u_int8_t mii_regaddr; - u_int8_t mii_turnaround; - u_int16_t mii_data; -}; - -/* - * MII constants - */ -#define AX_MII_STARTDELIM 0x01 -#define AX_MII_READOP 0x02 -#define AX_MII_WRITEOP 0x01 -#define AX_MII_TURNAROUND 0x02 - -#define AX_FLAG_FORCEDELAY 1 -#define AX_FLAG_SCHEDDELAY 2 -#define AX_FLAG_DELAYTIMEO 3 - -struct ax_softc { - struct arpcom arpcom; /* interface info */ - struct ifmedia ifmedia; /* media info */ - bus_space_handle_t ax_bhandle; /* bus space handle */ - bus_space_tag_t ax_btag; /* bus space tag */ - struct ax_type *ax_info; /* ASIX adapter info */ - struct ax_type *ax_pinfo; /* phy info */ - u_int8_t ax_unit; /* interface number */ - u_int8_t ax_type; - u_int8_t ax_phy_addr; /* PHY address */ - u_int8_t ax_tx_pend; /* TX pending */ - u_int8_t ax_want_auto; - u_int8_t ax_autoneg; - caddr_t ax_ldata_ptr; - struct ax_list_data *ax_ldata; - struct ax_chain_data ax_cdata; -}; - -/* - * register space access macros - */ -#define CSR_WRITE_4(sc, reg, val) \ - bus_space_write_4(sc->ax_btag, sc->ax_bhandle, reg, val) -#define CSR_WRITE_2(sc, reg, val) \ - bus_space_write_2(sc->ax_btag, sc->ax_bbhandle, reg, val) -#define CSR_WRITE_1(sc, reg, val) \ - bus_space_write_1(sc->ax_btag, sc->ax_bhandle, reg, val) - -#define CSR_READ_4(sc, reg) \ - bus_space_read_4(sc->ax_btag, sc->ax_bhandle, reg) -#define CSR_READ_2(sc, reg) \ - bus_space_read_2(sc->ax_btag, sc->ax_bhandle, reg) -#define CSR_READ_1(sc, reg) \ - bus_space_read_1(sc->ax_btag, sc->ax_bhandle, reg) - -#define AX_TIMEOUT 1000 - -/* - * General constants that are fun to know. - * - * ASIX PCI vendor ID - */ -#define AX_VENDORID 0x125B - -/* - * ASIX device IDs. - */ -#define AX_DEVICEID_AX88140A 0x1400 - -/* - * Texas Instruments PHY identifiers - */ -#define TI_PHY_VENDORID 0x4000 -#define TI_PHY_10BT 0x501F -#define TI_PHY_100VGPMI 0x502F - -/* - * These ID values are for the NS DP83840A 10/100 PHY - */ -#define NS_PHY_VENDORID 0x2000 -#define NS_PHY_83840A 0x5C0F - -/* - * Level 1 10/100 PHY - */ -#define LEVEL1_PHY_VENDORID 0x7810 -#define LEVEL1_PHY_LXT970 0x000F - -/* - * Intel 82555 10/100 PHY - */ -#define INTEL_PHY_VENDORID 0x0A28 -#define INTEL_PHY_82555 0x015F - -/* - * SEEQ 80220 10/100 PHY - */ -#define SEEQ_PHY_VENDORID 0x0016 -#define SEEQ_PHY_80220 0xF83F - - -/* - * PCI low memory base and low I/O base register, and - * other PCI registers. - */ - -#define AX_PCI_VENDOR_ID 0x00 -#define AX_PCI_DEVICE_ID 0x02 -#define AX_PCI_COMMAND 0x04 -#define AX_PCI_STATUS 0x06 -#define AX_PCI_REVID 0x08 -#define AX_PCI_CLASSCODE 0x09 -#define AX_PCI_LATENCY_TIMER 0x0D -#define AX_PCI_HEADER_TYPE 0x0E -#define AX_PCI_LOIO 0x10 -#define AX_PCI_LOMEM 0x14 -#define AX_PCI_BIOSROM 0x30 -#define AX_PCI_INTLINE 0x3C -#define AX_PCI_INTPIN 0x3D -#define AX_PCI_MINGNT 0x3E -#define AX_PCI_MINLAT 0x0F -#define AX_PCI_RESETOPT 0x48 -#define AX_PCI_EEPROM_DATA 0x4C - -/* power management registers */ -#define AX_PCI_CAPID 0xDC /* 8 bits */ -#define AX_PCI_NEXTPTR 0xDD /* 8 bits */ -#define AX_PCI_PWRMGMTCAP 0xDE /* 16 bits */ -#define AX_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */ - -#define AX_PSTATE_MASK 0x0003 -#define AX_PSTATE_D0 0x0000 -#define AX_PSTATE_D1 0x0001 -#define AX_PSTATE_D2 0x0002 -#define AX_PSTATE_D3 0x0003 -#define AX_PME_EN 0x0010 -#define AX_PME_STATUS 0x8000 - -#define PHY_UNKNOWN 6 - -#define AX_PHYADDR_MIN 0x00 -#define AX_PHYADDR_MAX 0x1F - -#define PHY_BMCR 0x00 -#define PHY_BMSR 0x01 -#define PHY_VENID 0x02 -#define PHY_DEVID 0x03 -#define PHY_ANAR 0x04 -#define PHY_LPAR 0x05 -#define PHY_ANEXP 0x06 - -#define PHY_ANAR_NEXTPAGE 0x8000 -#define PHY_ANAR_RSVD0 0x4000 -#define PHY_ANAR_TLRFLT 0x2000 -#define PHY_ANAR_RSVD1 0x1000 -#define PHY_ANAR_RSVD2 0x0800 -#define PHY_ANAR_RSVD3 0x0400 -#define PHY_ANAR_100BT4 0x0200 -#define PHY_ANAR_100BTXFULL 0x0100 -#define PHY_ANAR_100BTXHALF 0x0080 -#define PHY_ANAR_10BTFULL 0x0040 -#define PHY_ANAR_10BTHALF 0x0020 -#define PHY_ANAR_PROTO4 0x0010 -#define PHY_ANAR_PROTO3 0x0008 -#define PHY_ANAR_PROTO2 0x0004 -#define PHY_ANAR_PROTO1 0x0002 -#define PHY_ANAR_PROTO0 0x0001 - -/* - * These are the register definitions for the PHY (physical layer - * interface chip). - */ -/* - * PHY BMCR Basic Mode Control Register - */ -#define PHY_BMCR_RESET 0x8000 -#define PHY_BMCR_LOOPBK 0x4000 -#define PHY_BMCR_SPEEDSEL 0x2000 -#define PHY_BMCR_AUTONEGENBL 0x1000 -#define PHY_BMCR_RSVD0 0x0800 /* write as zero */ -#define PHY_BMCR_ISOLATE 0x0400 -#define PHY_BMCR_AUTONEGRSTR 0x0200 -#define PHY_BMCR_DUPLEX 0x0100 -#define PHY_BMCR_COLLTEST 0x0080 -#define PHY_BMCR_RSVD1 0x0040 /* write as zero, don't care */ -#define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */ -#define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */ -#define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */ -#define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */ -#define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */ -#define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */ -/* - * RESET: 1 == software reset, 0 == normal operation - * Resets status and control registers to default values. - * Relatches all hardware config values. - * - * LOOPBK: 1 == loopback operation enabled, 0 == normal operation - * - * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s - * Link speed is selected byt his bit or if auto-negotiation if bit - * 12 (AUTONEGENBL) is set (in which case the value of this register - * is ignored). - * - * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled - * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13 - * determine speed and mode. Should be cleared and then set if PHY configured - * for no autoneg on startup. - * - * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation - * - * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation - * - * DUPLEX: 1 == full duplex mode, 0 == half duplex mode - * - * COLLTEST: 1 == collision test enabled, 0 == normal operation - */ - -/* - * PHY, BMSR Basic Mode Status Register - */ -#define PHY_BMSR_100BT4 0x8000 -#define PHY_BMSR_100BTXFULL 0x4000 -#define PHY_BMSR_100BTXHALF 0x2000 -#define PHY_BMSR_10BTFULL 0x1000 -#define PHY_BMSR_10BTHALF 0x0800 -#define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */ -#define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */ -#define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */ -#define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */ -#define PHY_BMSR_MFPRESUP 0x0040 -#define PHY_BMSR_AUTONEGCOMP 0x0020 -#define PHY_BMSR_REMFAULT 0x0010 -#define PHY_BMSR_CANAUTONEG 0x0008 -#define PHY_BMSR_LINKSTAT 0x0004 -#define PHY_BMSR_JABBER 0x0002 -#define PHY_BMSR_EXTENDED 0x0001 diff --git a/sys/pci/if_de.c b/sys/pci/if_de.c index 82354275e866..8b74e4358aaf 100644 --- a/sys/pci/if_de.c +++ b/sys/pci/if_de.c @@ -1,5 +1,5 @@ /* $NetBSD: if_de.c,v 1.80 1998/09/25 18:06:53 matt Exp $ */ -/* $Id: if_de.c,v 1.92 1998/12/14 05:47:26 dillon Exp $ */ +/* $Id: if_de.c,v 1.88 1998/10/13 09:05:57 peter Exp $ */ /*- * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) @@ -39,6 +39,11 @@ */ #define TULIP_HDR_DATA +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_ipx.h" +#endif + #ifdef __NetBSD__ #include "opt_inet.h" #include "opt_ns.h" @@ -57,21 +62,6 @@ #include <sys/device.h> #endif -#if defined(__FreeBSD__) -/* In case somebody is trying to run this on an older 2.2 or 3.0 */ -#ifndef __FreeBSD_version /* defined in sys/param.h on current code */ -#if __FreeBSD__ >= 3 -#define __FreeBSD_version 300000 -#else -#define __FreeBSD_version 200000 -#endif -#endif -#if __FreeBSD_version >= 300000 -#include "opt_inet.h" -#include "opt_ipx.h" -#endif -#endif - #if defined(__NetBSD__) #include "rnd.h" #if NRND > 0 @@ -123,6 +113,14 @@ #include <pci/dc21040reg.h> #define DEVAR_INCLUDE "pci/if_devar.h" #endif +/* In case somebody is trying to run this on an older 2.2 or 3.0 */ +#ifndef __FreeBSD_version /* defined in sys/param.h on current code */ +#if __FreeBSD__ >= 3 +#define __FreeBSD_version 300000 +#else +#define __FreeBSD_version 200000 +#endif +#endif #endif /* __FreeBSD__ */ #if defined(__bsdi__) @@ -2757,7 +2755,6 @@ static const struct { { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, - { tulip_identify_cogent_nic, { 0x00, 0x00, 0xD1 } }, { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } }, { NULL } }; @@ -2861,7 +2858,7 @@ tulip_read_macaddr( * Some folks don't use the standard ethernet rom format * but instead just put the address in the first 6 bytes * of the rom and let the rest be all 0xffs. (Can we say - * ZNYX?) (well sometimes they put in a checksum so we'll + * ZNYX???) (well sometimes they put in a checksum so we'll * start at 8). */ for (idx = 8; idx < 32; idx++) { @@ -5310,7 +5307,7 @@ tulip_pci_shutdown( } #endif -static const char* +static char* tulip_pci_probe( pcici_t config_id, pcidi_t device_id) diff --git a/sys/pci/if_devar.h b/sys/pci/if_devar.h index b0ec38445ca8..1f4b577a8084 100644 --- a/sys/pci/if_devar.h +++ b/sys/pci/if_devar.h @@ -1,5 +1,5 @@ /* $NetBSD: if_devar.h,v 1.31 1998/09/29 22:40:52 matt Exp $ */ -/* $Id: if_devar.h,v 1.11 1998/10/14 08:31:27 peter Exp $ */ +/* $Id: if_devar.h,v 1.10 1998/10/13 09:05:58 peter Exp $ */ /*- * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) @@ -62,16 +62,8 @@ typedef bus_addr_t tulip_csrptr_t; #define TULIP_PCI_CSRSIZE 8 #define TULIP_PCI_CSROFFSET 0 -#if !defined(__FreeBSD__) || __FreeBSD_version < 300000 -typedef u_long uintptr_t; -#endif - #if !defined(__NetBSD__) -#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 typedef pci_port_t tulip_csrptr_t; -#else -typedef u_int16_t tulip_csrptr_t; -#endif #define TULIP_CSR_READ(sc, csr) (inl((sc)->tulip_csrs.csr)) #define TULIP_CSR_WRITE(sc, csr, val) outl((sc)->tulip_csrs.csr, val) @@ -951,11 +943,7 @@ static void tulip_softintr(void); #if defined(__FreeBSD__) typedef void ifnet_ret_t; -#if __FreeBSD_version >= 300000 typedef u_long ioctl_cmd_t; -#else -typedef int ioctl_cmd_t; -#endif #if defined(TULIP_HDR_DATA) static tulip_softc_t *tulips[TULIP_MAX_DEVICES]; #endif diff --git a/sys/pci/if_ed_p.c b/sys/pci/if_ed_p.c index e14a96c50abd..d284ee6074e0 100644 --- a/sys/pci/if_ed_p.c +++ b/sys/pci/if_ed_p.c @@ -17,7 +17,7 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: if_ed_p.c,v 1.13 1998/03/17 10:54:23 danny Exp $ + * $Id: if_ed_p.c,v 1.12 1998/02/27 22:29:36 se Exp $ */ #include "pci.h" @@ -51,7 +51,7 @@ static struct _pcsid extern void *ed_attach_NE2000_pci __P((int, int)); -static const char* ed_pci_probe __P((pcici_t tag, pcidi_t type)); +static char* ed_pci_probe __P((pcici_t tag, pcidi_t type)); static void ed_pci_attach __P((pcici_t config_id, int unit)); static u_long ed_pci_count = NED; @@ -66,7 +66,7 @@ static struct pci_device ed_pci_driver = { DATA_SET (pcidevice_set, ed_pci_driver); -static const char* +static char* ed_pci_probe (pcici_t tag, pcidi_t type) { struct _pcsid *ep =pci_ids; diff --git a/sys/pci/if_en_pci.c b/sys/pci/if_en_pci.c index 3414edc489be..d1853b5748aa 100644 --- a/sys/pci/if_en_pci.c +++ b/sys/pci/if_en_pci.c @@ -50,6 +50,17 @@ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> +#ifndef SHUTDOWN_PRE_SYNC +/* + * device shutdown mechanism has been changed since 2.2-ALPHA. + * if SHUTDOWN_PRE_SYNC is defined in "sys/systm.h", use new one. + * otherwise, use old one. + * new: 2.2-ALPHA, 2.2-BETA, 2.2-GAMME, 2.2-RELEASE, 3.0 + * old: 2.1.5, 2.1.6, 2.2-SNAP + * -- kjc + */ +#include <sys/devconf.h> +#endif #include <sys/malloc.h> #include <sys/socket.h> @@ -69,8 +80,12 @@ */ static void en_pci_attach __P((pcici_t, int)); -static const char *en_pci_probe __P((pcici_t, pcidi_t)); +static char *en_pci_probe __P((pcici_t, pcidi_t)); +#ifdef SHUTDOWN_PRE_SYNC static void en_pci_shutdown __P((int, void *)); +#else +static int en_pci_shutdown __P((struct kern_devconf *, int)); +#endif /* * local structures @@ -83,15 +98,8 @@ struct en_pci_softc { /* PCI bus glue */ void *sc_ih; /* interrupt handle */ pci_chipset_tag_t en_pc; /* for PCI calls */ - pcici_t en_confid; /* config id */ -}; -#if !defined(MIDWAY_ENIONLY) -static void eni_get_macaddr __P((struct en_pci_softc *)); -#endif -#if !defined(MIDWAY_ADPONLY) -static void adp_get_macaddr __P((struct en_pci_softc *)); -#endif +}; /* * pointers to softcs (we alloc) @@ -111,7 +119,11 @@ static struct pci_device endevice = { en_pci_probe, en_pci_attach, &en_pci_count, +#ifdef SHUTDOWN_PRE_SYNC NULL, +#else + en_pci_shutdown, +#endif }; DATA_SET (pcidevice_set, endevice); @@ -191,7 +203,7 @@ void *v; * autoconfig stuff */ -static const char *en_pci_probe(config_id, device_id) +static char *en_pci_probe(config_id, device_id) pcici_t config_id; pcidi_t device_id; @@ -247,10 +259,9 @@ int unit; enpcis[unit] = scp; /* lock it in */ en_cd.cd_devs[unit] = sc; /* fake a cfdriver structure */ en_cd.cd_ndevs = NEN; - snprintf(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname), "en%d", unit); + sprintf(sc->sc_dev.dv_xname, "en%d", unit); sc->enif.if_unit = unit; sc->enif.if_name = "en"; - scp->en_confid = config_id; /* * figure out if we are an adaptec card or not. @@ -261,12 +272,14 @@ int unit; device_id = pci_conf_read(config_id, PCI_ID_REG); sc->is_adaptec = (PCI_VENDOR(device_id) == PCI_VENDOR_ADP) ? 1 : 0; +#ifdef SHUTDOWN_PRE_SYNC /* * Add shutdown hook so that DMA is disabled prior to reboot. Not * doing so could allow DMA to corrupt kernel memory during the * reboot before the driver initializes. */ at_shutdown(en_pci_shutdown, scp, SHUTDOWN_POST_SYNC); +#endif if (!pci_map_int(config_id, en_intr, (void *) sc, &net_imask)) { printf("%s: couldn't establish interrupt\n", sc->sc_dev.dv_xname); @@ -280,7 +293,6 @@ int unit; #if !defined(MIDWAY_ENIONLY) if (sc->is_adaptec) { - adp_get_macaddr(scp); sc->en_busreset = adp_busreset; adp_busreset(sc); } @@ -288,7 +300,6 @@ int unit; #if !defined(MIDWAY_ADPONLY) if (!sc->is_adaptec) { - eni_get_macaddr(scp); sc->en_busreset = NULL; pci_conf_write(config_id, EN_TONGA, (TONGA_SWAP_DMA|TONGA_SWAP_WORD)); } @@ -302,6 +313,7 @@ int unit; } +#ifdef SHUTDOWN_PRE_SYNC static void en_pci_shutdown( int howto, @@ -312,126 +324,22 @@ en_pci_shutdown( en_reset(&psc->esc); DELAY(10); } +#else /* !SHUTDOWN_PRE_SYNC */ +static int +en_pci_shutdown(kdc, force) -#if !defined(MIDWAY_ENIONLY) - -#if defined(sparc) || defined(__FreeBSD__) -#define bus_space_read_1(t, h, o) \ - ((void)t, (*(volatile u_int8_t *)((h) + (o)))) -#endif - -static void -adp_get_macaddr(scp) - struct en_pci_softc *scp; -{ - 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); -} - -#endif /* MIDWAY_ENIONLY */ - -#if !defined(MIDWAY_ADPONLY) +struct kern_devconf *kdc; +int force; -/* - * 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 - -static void -eni_get_macaddr(scp) - struct en_pci_softc *scp; { - struct en_softc * sc = (struct en_softc *)scp; - pcici_t id = scp->en_confid; - int i, j, address, status; - u_int32_t data, t_data; - u_int8_t tmp; - - t_data = pci_conf_read(id, EN_TONGA) & 0xffffff00; - - data = EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK; - pci_conf_write(id, EN_TONGA, data); - - for (i = 0; i < sizeof(sc->macaddr); i ++){ - /* start operation */ - data |= EN_PROM_DATA ; - pci_conf_write(id, EN_TONGA, data); - data |= EN_PROM_CLK ; - pci_conf_write(id, EN_TONGA, data); - data &= ~EN_PROM_DATA ; - pci_conf_write(id, EN_TONGA, data); - data &= ~EN_PROM_CLK ; - pci_conf_write(id, EN_TONGA, data); - /* 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_conf_write(id, EN_TONGA, data); - data |= EN_PROM_CLK ; - pci_conf_write(id, EN_TONGA, data); - data &= ~EN_PROM_CLK ; - pci_conf_write(id, EN_TONGA, data); - } - /* get ack */ - data |= EN_PROM_DATA ; - pci_conf_write(id, EN_TONGA, data); - data |= EN_PROM_CLK ; - pci_conf_write(id, EN_TONGA, data); - data = pci_conf_read(id, EN_TONGA); - status = data & EN_PROM_DATA; - data &= ~EN_PROM_CLK ; - pci_conf_write(id, EN_TONGA, data); - data |= EN_PROM_DATA ; - pci_conf_write(id, EN_TONGA, data); - - tmp = 0; - - for ( j = 7 ; j >= 0 ; j --){ - tmp <<= 1; - data |= EN_PROM_DATA ; - pci_conf_write(id, EN_TONGA, data); - data |= EN_PROM_CLK ; - pci_conf_write(id, EN_TONGA, data); - data = pci_conf_read(id, EN_TONGA); - if(data & EN_PROM_DATA) tmp |= 1; - data &= ~EN_PROM_CLK ; - pci_conf_write(id, EN_TONGA, data); - data |= EN_PROM_DATA ; - pci_conf_write(id, EN_TONGA, data); - } - /* get ack */ - data |= EN_PROM_DATA ; - pci_conf_write(id, EN_TONGA, data); - data |= EN_PROM_CLK ; - pci_conf_write(id, EN_TONGA, data); - data = pci_conf_read(id, EN_TONGA); - status = data & EN_PROM_DATA; - data &= ~EN_PROM_CLK ; - pci_conf_write(id, EN_TONGA, data); - data |= EN_PROM_DATA ; - pci_conf_write(id, EN_TONGA, data); - - sc->macaddr[i] = tmp; + if (kdc->kdc_unit < NEN) { + struct en_pci_softc *psc = enpcis[kdc->kdc_unit]; + if (psc) /* can it be null? */ + en_reset(&psc->esc); + DELAY(10); } - /* stop operation */ - data &= ~EN_PROM_DATA; - pci_conf_write(id, EN_TONGA, data); - data |= EN_PROM_CLK; - pci_conf_write(id, EN_TONGA, data); - data |= EN_PROM_DATA; - pci_conf_write(id, EN_TONGA, data); - pci_conf_write(id, EN_TONGA, t_data); + dev_detach(kdc); + return(0); } - -#endif /* !MIDWAY_ADPONLY */ - +#endif /* !SHUTDOWN_PRE_SYNC */ #endif /* NEN > 0 && NPCI > 0 */ diff --git a/sys/pci/if_fpa.c b/sys/pci/if_fpa.c index cff0be24ca84..8706f2a06d5c 100644 --- a/sys/pci/if_fpa.c +++ b/sys/pci/if_fpa.c @@ -21,7 +21,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: if_fpa.c,v 1.7 1998/02/20 13:11:53 bde Exp $ + * $Id: if_fpa.c,v 1.6 1998/02/09 06:10:49 eivind Exp $ * */ @@ -135,7 +135,7 @@ static void pdq_pci_shutdown(int, void *); * on both EISA and PCI boards, one must be careful in how defines the * PDQ in the config file. */ -static const char * +static char * pdq_pci_probe( pcici_t config_id, pcidi_t device_id) diff --git a/sys/pci/if_fxp.c b/sys/pci/if_fxp.c index 1908cb6eff70..750e268c8abe 100644 --- a/sys/pci/if_fxp.c +++ b/sys/pci/if_fxp.c @@ -27,7 +27,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: if_fxp.c,v 1.58 1998/10/22 02:00:49 dg Exp $ + * $Id: if_fxp.c,v 1.56 1998/10/10 19:26:40 dg Exp $ */ /* @@ -485,7 +485,7 @@ fxp_ether_ioctl(ifp, cmd, data) #else /* __FreeBSD__ */ static u_long fxp_count; -static const char *fxp_probe __P((pcici_t, pcidi_t)); +static char *fxp_probe __P((pcici_t, pcidi_t)); static void fxp_attach __P((pcici_t, int)); static void fxp_shutdown __P((int, void *)); @@ -502,7 +502,7 @@ DATA_SET(pcidevice_set, fxp_device); /* * Return identification string if this is device is ours. */ -static const char * +static char * fxp_probe(config_id, device_id) pcici_t config_id; pcidi_t device_id; @@ -1072,7 +1072,6 @@ fxp_stats_update(arg) struct fxp_softc *sc = arg; struct ifnet *ifp = &sc->sc_if; struct fxp_stats *sp = sc->fxp_stats; - struct fxp_cb_tx *txp; int s; ifp->if_opackets += sp->tx_good; @@ -1081,9 +1080,6 @@ fxp_stats_update(arg) ifp->if_ipackets += sp->rx_good; sc->rx_idle_secs = 0; } else { - /* - * Receiver's been idle for another second. - */ sc->rx_idle_secs++; } ifp->if_ierrors += @@ -1102,23 +1098,6 @@ fxp_stats_update(arg) } s = splimp(); /* - * Release any xmit buffers that have completed DMA. This isn't - * strictly necessary to do here, but it's advantagous for mbufs - * with external storage to be released in a timely manner rather - * than being defered for a potentially long time. This limits - * the delay to a maximum of one second. - */ - for (txp = sc->cbl_first; sc->tx_queued && - (txp->cb_status & FXP_CB_STATUS_C) != 0; - txp = txp->next) { - if (txp->mb_head != NULL) { - m_freem(txp->mb_head); - txp->mb_head = NULL; - } - sc->tx_queued--; - } - sc->cbl_first = txp; - /* * If we haven't received any packets in FXP_MAC_RX_IDLE seconds, * then assume the receiver has locked up and attempt to clear * the condition by reprogramming the multicast filter. This is diff --git a/sys/pci/if_lnc_p.c b/sys/pci/if_lnc_p.c index 27f2048d4377..3cffcab8030a 100644 --- a/sys/pci/if_lnc_p.c +++ b/sys/pci/if_lnc_p.c @@ -17,7 +17,7 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: if_lnc_p.c,v 1.6 1998/07/20 17:33:01 msmith Exp $ + * $Id: if_lnc_p.c,v 1.5 1997/08/02 14:33:11 bde Exp $ */ #include "pci.h" @@ -36,7 +36,7 @@ extern void *lnc_attach_ne2100_pci __P((int unit, unsigned iobase)); -static const char* lnc_pci_probe __P((pcici_t tag, pcidi_t type)); +static char* lnc_pci_probe __P((pcici_t tag, pcidi_t type)); static void lnc_pci_attach __P((pcici_t config_id, int unit)); static u_long lnc_pci_count = NLNC; @@ -51,7 +51,7 @@ static struct pci_device lnc_pci_driver = { DATA_SET (pcidevice_set, lnc_pci_driver); -static const char* +static char* lnc_pci_probe (pcici_t tag, pcidi_t type) { switch(type) { diff --git a/sys/pci/if_mx.c b/sys/pci/if_mx.c deleted file mode 100644 index 621c3c7d94f1..000000000000 --- a/sys/pci/if_mx.c +++ /dev/null @@ -1,2436 +0,0 @@ -/* - * Copyright (c) 1997, 1998 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_mx.c,v 1.33 1999/01/06 17:22:40 wpaul Exp $ - */ - -/* - * Macronix PMAC fast ethernet PCI NIC driver - * - * Written by Bill Paul <wpaul@ctr.columbia.edu> - * Electrical Engineering Department - * Columbia University, New York City - */ - -/* - * The Macronix 98713, 98715 and 98725 chips are still more tulip clones. - * The 98713 has an internal transceiver and an MII bus for external PHYs. - * The other two chips have only the internal transceiver. All have - * support for built-in autonegotiation. Additionally, there are 98713A - * and 98715A chips which support power management. The 98725 chip - * supports power management as well. - * - * Datasheets for the Macronix parts can be obtained from www.macronix.com. - * Note however that the datasheets do not describe the TX and RX - * descriptor structures or the setup frame format(s). For this, you should - * obtain a DEC 21x4x datasheet from developer.intel.com. The Macronix - * chips look to be fairly straightforward tulip clones, except for - * the NWAY support. - */ - -#include "bpfilter.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/if_arp.h> -#include <net/ethernet.h> -#include <net/if_dl.h> -#include <net/if_media.h> - -#if NBPFILTER > 0 -#include <net/bpf.h> -#endif - -#include <vm/vm.h> /* for vtophys */ -#include <vm/pmap.h> /* for vtophys */ -#include <machine/clock.h> /* for DELAY */ -#include <machine/bus_pio.h> -#include <machine/bus_memio.h> -#include <machine/bus.h> - -#include <pci/pcireg.h> -#include <pci/pcivar.h> - -#define MX_USEIOSPACE - -/* #define MX_BACKGROUND_AUTONEG */ - -#include <pci/if_mxreg.h> - -#ifndef lint -static const char rcsid[] = - "$Id: if_mx.c,v 1.33 1999/01/06 17:22:40 wpaul Exp $"; -#endif - -/* - * Various supported device vendors/types and their names. - */ -static struct mx_type mx_devs[] = { - { MX_VENDORID, MX_DEVICEID_98713, - "Macronix 98713 10/100BaseTX" }, - { MX_VENDORID, MX_DEVICEID_98713, - "Macronix 98713A 10/100BaseTX" }, - { MX_VENDORID, MX_DEVICEID_987x5, - "Macronix 98715/98715A 10/100BaseTX" }, - { MX_VENDORID, MX_DEVICEID_987x5, - "Macronix 98725 10/100BaseTX" }, - { 0, 0, NULL } -}; - -/* - * Various supported PHY vendors/types and their names. Note that - * this driver will work with pretty much any MII-compliant PHY, - * so failure to positively identify the chip is not a fatal error. - */ - -static struct mx_type mx_phys[] = { - { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, - { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, - { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, - { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, - { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, - { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, - { 0, 0, "<MII-compliant physical interface>" } -}; - -static unsigned long mx_count = 0; -static const char *mx_probe __P((pcici_t, pcidi_t)); -static void mx_attach __P((pcici_t, int)); - -static int mx_newbuf __P((struct mx_softc *, - struct mx_chain_onefrag *)); -static int mx_encap __P((struct mx_softc *, struct mx_chain *, - struct mbuf *)); - -static void mx_rxeof __P((struct mx_softc *)); -static void mx_rxeoc __P((struct mx_softc *)); -static void mx_txeof __P((struct mx_softc *)); -static void mx_txeoc __P((struct mx_softc *)); -static void mx_intr __P((void *)); -static void mx_start __P((struct ifnet *)); -static int mx_ioctl __P((struct ifnet *, u_long, caddr_t)); -static void mx_init __P((void *)); -static void mx_stop __P((struct mx_softc *)); -static void mx_watchdog __P((struct ifnet *)); -static void mx_shutdown __P((int, void *)); -static int mx_ifmedia_upd __P((struct ifnet *)); -static void mx_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); - -static void mx_delay __P((struct mx_softc *)); -static void mx_eeprom_idle __P((struct mx_softc *)); -static void mx_eeprom_putbyte __P((struct mx_softc *, u_int8_t)); -static void mx_eeprom_getword __P((struct mx_softc *, u_int8_t, u_int16_t *)); -static void mx_read_eeprom __P((struct mx_softc *, caddr_t, int, - int, int)); - -static void mx_mii_writebit __P((struct mx_softc *, int)); -static int mx_mii_readbit __P((struct mx_softc *)); -static void mx_mii_sync __P((struct mx_softc *)); -static void mx_mii_send __P((struct mx_softc *, u_int32_t, int)); -static int mx_mii_readreg __P((struct mx_softc *, struct mx_mii_frame *)); -static int mx_mii_writereg __P((struct mx_softc *, struct mx_mii_frame *)); -static u_int16_t mx_phy_readreg __P((struct mx_softc *, int)); -static void mx_phy_writereg __P((struct mx_softc *, u_int16_t, u_int16_t)); - -static void mx_autoneg_xmit __P((struct mx_softc *)); -static void mx_autoneg_mii __P((struct mx_softc *, int, int)); -static void mx_autoneg __P((struct mx_softc *, int, int)); -static void mx_setmode_mii __P((struct mx_softc *, int)); -static void mx_setmode __P((struct mx_softc *, int, int)); -static void mx_getmode_mii __P((struct mx_softc *)); -static void mx_setcfg __P((struct mx_softc *, u_int16_t)); -static u_int32_t mx_calchash __P((u_int8_t *)); -static void mx_setfilt __P((struct mx_softc *)); -static void mx_reset __P((struct mx_softc *)); -static int mx_list_rx_init __P((struct mx_softc *)); -static int mx_list_tx_init __P((struct mx_softc *)); - -#define MX_SETBIT(sc, reg, x) \ - CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) | x) - -#define MX_CLRBIT(sc, reg, x) \ - CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) & ~x) - -#define SIO_SET(x) \ - CSR_WRITE_4(sc, MX_SIO, \ - CSR_READ_4(sc, MX_SIO) | x) - -#define SIO_CLR(x) \ - CSR_WRITE_4(sc, MX_SIO, \ - CSR_READ_4(sc, MX_SIO) & ~x) - -static void mx_delay(sc) - struct mx_softc *sc; -{ - int idx; - - for (idx = (300 / 33) + 1; idx > 0; idx--) - CSR_READ_4(sc, MX_BUSCTL); -} - -static void mx_eeprom_idle(sc) - struct mx_softc *sc; -{ - register int i; - - CSR_WRITE_4(sc, MX_SIO, MX_SIO_EESEL); - mx_delay(sc); - MX_SETBIT(sc, MX_SIO, MX_SIO_ROMCTL_READ); - mx_delay(sc); - MX_SETBIT(sc, MX_SIO, MX_SIO_EE_CS); - mx_delay(sc); - MX_SETBIT(sc, MX_SIO, MX_SIO_EE_CLK); - mx_delay(sc); - - for (i = 0; i < 25; i++) { - MX_CLRBIT(sc, MX_SIO, MX_SIO_EE_CLK); - mx_delay(sc); - MX_SETBIT(sc, MX_SIO, MX_SIO_EE_CLK); - mx_delay(sc); - } - - MX_CLRBIT(sc, MX_SIO, MX_SIO_EE_CLK); - mx_delay(sc); - MX_CLRBIT(sc, MX_SIO, MX_SIO_EE_CS); - mx_delay(sc); - CSR_WRITE_4(sc, MX_SIO, 0x00000000); - - return; -} - -/* - * Send a read command and address to the EEPROM, check for ACK. - */ -static void mx_eeprom_putbyte(sc, addr) - struct mx_softc *sc; - u_int8_t addr; -{ - register int d, i; - - d = addr | MX_EECMD_READ; - - /* - * Feed in each bit and stobe the clock. - */ - for (i = 0x400; i; i >>= 1) { - if (d & i) { - SIO_SET(MX_SIO_EE_DATAIN); - } else { - SIO_CLR(MX_SIO_EE_DATAIN); - } - mx_delay(sc); - SIO_SET(MX_SIO_EE_CLK); - mx_delay(sc); - SIO_CLR(MX_SIO_EE_CLK); - mx_delay(sc); - } - - return; -} - -/* - * Read a word of data stored in the EEPROM at address 'addr.' - */ -static void mx_eeprom_getword(sc, addr, dest) - struct mx_softc *sc; - u_int8_t addr; - u_int16_t *dest; -{ - register int i; - u_int16_t word = 0; - - /* Force EEPROM to idle state. */ - mx_eeprom_idle(sc); - - /* Enter EEPROM access mode. */ - CSR_WRITE_4(sc, MX_SIO, MX_SIO_EESEL); - mx_delay(sc); - MX_SETBIT(sc, MX_SIO, MX_SIO_ROMCTL_READ); - mx_delay(sc); - MX_SETBIT(sc, MX_SIO, MX_SIO_EE_CS); - mx_delay(sc); - MX_SETBIT(sc, MX_SIO, MX_SIO_EE_CLK); - mx_delay(sc); - - /* - * Send address of word we want to read. - */ - mx_eeprom_putbyte(sc, addr); - - /* - * Start reading bits from EEPROM. - */ - for (i = 0x8000; i; i >>= 1) { - SIO_SET(MX_SIO_EE_CLK); - mx_delay(sc); - if (CSR_READ_4(sc, MX_SIO) & MX_SIO_EE_DATAOUT) - word |= i; - mx_delay(sc); - SIO_CLR(MX_SIO_EE_CLK); - mx_delay(sc); - } - - /* Turn off EEPROM access mode. */ - mx_eeprom_idle(sc); - - *dest = word; - - return; -} - -/* - * Read a sequence of words from the EEPROM. - */ -static void mx_read_eeprom(sc, dest, off, cnt, swap) - struct mx_softc *sc; - caddr_t dest; - int off; - int cnt; - int swap; -{ - int i; - u_int16_t word = 0, *ptr; - - for (i = 0; i < cnt; i++) { - mx_eeprom_getword(sc, off + i, &word); - ptr = (u_int16_t *)(dest + (i * 2)); - if (swap) - *ptr = ntohs(word); - else - *ptr = word; - } - - return; -} - -/* - * The following two routines are taken from the Macronix 98713 - * Application Notes pp.19-21. - */ -/* - * Write a bit to the MII bus. - */ -static void mx_mii_writebit(sc, bit) - struct mx_softc *sc; - int bit; -{ - if (bit) - CSR_WRITE_4(sc, MX_SIO, MX_SIO_ROMCTL_WRITE|MX_SIO_MII_DATAOUT); - else - CSR_WRITE_4(sc, MX_SIO, MX_SIO_ROMCTL_WRITE); - - MX_SETBIT(sc, MX_SIO, MX_SIO_MII_CLK); - MX_CLRBIT(sc, MX_SIO, MX_SIO_MII_CLK); - - return; -} - -/* - * Read a bit from the MII bus. - */ -static int mx_mii_readbit(sc) - struct mx_softc *sc; -{ - CSR_WRITE_4(sc, MX_SIO, MX_SIO_ROMCTL_READ|MX_SIO_MII_DIR); - CSR_READ_4(sc, MX_SIO); - MX_SETBIT(sc, MX_SIO, MX_SIO_MII_CLK); - MX_CLRBIT(sc, MX_SIO, MX_SIO_MII_CLK); - if (CSR_READ_4(sc, MX_SIO) & MX_SIO_MII_DATAIN) - return(1); - - return(0); -} - -/* - * Sync the PHYs by setting data bit and strobing the clock 32 times. - */ -static void mx_mii_sync(sc) - struct mx_softc *sc; -{ - register int i; - - CSR_WRITE_4(sc, MX_SIO, MX_SIO_ROMCTL_WRITE); - - for (i = 0; i < 32; i++) - mx_mii_writebit(sc, 1); - - return; -} - -/* - * Clock a series of bits through the MII. - */ -static void mx_mii_send(sc, bits, cnt) - struct mx_softc *sc; - u_int32_t bits; - int cnt; -{ - int i; - - for (i = (0x1 << (cnt - 1)); i; i >>= 1) - mx_mii_writebit(sc, bits & i); -} - -/* - * Read an PHY register through the MII. - */ -static int mx_mii_readreg(sc, frame) - struct mx_softc *sc; - struct mx_mii_frame *frame; - -{ - int i, ack, s; - - s = splimp(); - - /* - * Set up frame for RX. - */ - frame->mii_stdelim = MX_MII_STARTDELIM; - frame->mii_opcode = MX_MII_READOP; - frame->mii_turnaround = 0; - frame->mii_data = 0; - - /* - * Sync the PHYs. - */ - mx_mii_sync(sc); - - /* - * Send command/address info. - */ - mx_mii_send(sc, frame->mii_stdelim, 2); - mx_mii_send(sc, frame->mii_opcode, 2); - mx_mii_send(sc, frame->mii_phyaddr, 5); - mx_mii_send(sc, frame->mii_regaddr, 5); - -#ifdef notdef - /* Idle bit */ - mx_mii_writebit(sc, 1); - mx_mii_writebit(sc, 0); -#endif - - /* Check for ack */ - ack = mx_mii_readbit(sc); - - /* - * Now try reading data bits. If the ack failed, we still - * need to clock through 16 cycles to keep the PHY(s) in sync. - */ - if (ack) { - for(i = 0; i < 16; i++) { - mx_mii_readbit(sc); - } - goto fail; - } - - for (i = 0x8000; i; i >>= 1) { - if (!ack) { - if (mx_mii_readbit(sc)) - frame->mii_data |= i; - } - } - -fail: - - mx_mii_writebit(sc, 0); - mx_mii_writebit(sc, 0); - - splx(s); - - if (ack) - return(1); - return(0); -} - -/* - * Write to a PHY register through the MII. - */ -static int mx_mii_writereg(sc, frame) - struct mx_softc *sc; - struct mx_mii_frame *frame; - -{ - int s; - - s = splimp(); - /* - * Set up frame for TX. - */ - - frame->mii_stdelim = MX_MII_STARTDELIM; - frame->mii_opcode = MX_MII_WRITEOP; - frame->mii_turnaround = MX_MII_TURNAROUND; - - /* - * Sync the PHYs. - */ - mx_mii_sync(sc); - - mx_mii_send(sc, frame->mii_stdelim, 2); - mx_mii_send(sc, frame->mii_opcode, 2); - mx_mii_send(sc, frame->mii_phyaddr, 5); - mx_mii_send(sc, frame->mii_regaddr, 5); - mx_mii_send(sc, frame->mii_turnaround, 2); - mx_mii_send(sc, frame->mii_data, 16); - - /* Idle bit. */ - mx_mii_writebit(sc, 0); - mx_mii_writebit(sc, 0); - - splx(s); - - return(0); -} - -static u_int16_t mx_phy_readreg(sc, reg) - struct mx_softc *sc; - int reg; -{ - struct mx_mii_frame frame; - u_int32_t cfg; - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = sc->mx_phy_addr; - frame.mii_regaddr = reg; - cfg = CSR_READ_4(sc, MX_NETCFG); - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL); - mx_mii_readreg(sc, &frame); - CSR_WRITE_4(sc, MX_NETCFG, cfg); - - return(frame.mii_data); -} - -static void mx_phy_writereg(sc, reg, data) - struct mx_softc *sc; - u_int16_t reg; - u_int16_t data; -{ - struct mx_mii_frame frame; - u_int32_t cfg; - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = sc->mx_phy_addr; - frame.mii_regaddr = reg; - frame.mii_data = data; - - cfg = CSR_READ_4(sc, MX_NETCFG); - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL); - mx_mii_writereg(sc, &frame); - CSR_WRITE_4(sc, MX_NETCFG, cfg); - - return; -} - -#define MX_POLY 0xEDB88320 -#define MX_BITS 9 - -static u_int32_t mx_calchash(addr) - u_int8_t *addr; -{ - u_int32_t idx, bit, data, crc; - - /* Compute CRC for the address value. */ - crc = 0xFFFFFFFF; /* initial value */ - - for (idx = 0; idx < 6; idx++) { - for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) - crc = (crc >> 1) ^ (((crc ^ data) & 1) ? MX_POLY : 0); - } - - return (crc & ((1 << MX_BITS) - 1)); -} - -/* - * Initiate an autonegotiation session. - */ -static void mx_autoneg_xmit(sc) - struct mx_softc *sc; -{ - u_int16_t phy_sts; - - mx_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(mx_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - - phy_sts = mx_phy_readreg(sc, PHY_BMCR); - phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; - mx_phy_writereg(sc, PHY_BMCR, phy_sts); - - return; -} - -/* - * Invoke autonegotiation on a PHY. - */ -static void mx_autoneg_mii(sc, flag, verbose) - struct mx_softc *sc; - int flag; - int verbose; -{ - u_int16_t phy_sts = 0, media, advert, ability; - struct ifnet *ifp; - struct ifmedia *ifm; - - ifm = &sc->ifmedia; - ifp = &sc->arpcom.ac_if; - - ifm->ifm_media = IFM_ETHER | IFM_AUTO; - - /* - * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported' - * bit cleared in the status register, but has the 'autoneg enabled' - * bit set in the control register. This is a contradiction, and - * I'm not sure how to handle it. If you want to force an attempt - * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR - * and see what happens. - */ -#ifndef FORCE_AUTONEG_TFOUR - /* - * First, see if autoneg is supported. If not, there's - * no point in continuing. - */ - phy_sts = mx_phy_readreg(sc, PHY_BMSR); - if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { - if (verbose) - printf("mx%d: autonegotiation not supported\n", - sc->mx_unit); - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - return; - } -#endif - - switch (flag) { - case MX_FLAG_FORCEDELAY: - /* - * XXX Never use this option anywhere but in the probe - * routine: making the kernel stop dead in its tracks - * for three whole seconds after we've gone multi-user - * is really bad manners. - */ - mx_autoneg_xmit(sc); - DELAY(5000000); - break; - case MX_FLAG_SCHEDDELAY: - /* - * Wait for the transmitter to go idle before starting - * an autoneg session, otherwise mx_start() may clobber - * our timeout, and we don't want to allow transmission - * during an autoneg session since that can screw it up. - */ - if (sc->mx_cdata.mx_tx_head != NULL) { - sc->mx_want_auto = 1; - return; - } - mx_autoneg_xmit(sc); - ifp->if_timer = 5; - sc->mx_autoneg = 1; - sc->mx_want_auto = 0; - return; - break; - case MX_FLAG_DELAYTIMEO: - ifp->if_timer = 0; - sc->mx_autoneg = 0; - break; - default: - printf("mx%d: invalid autoneg flag: %d\n", sc->mx_unit, flag); - return; - } - - if (mx_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { - if (verbose) - printf("mx%d: autoneg complete, ", sc->mx_unit); - phy_sts = mx_phy_readreg(sc, PHY_BMSR); - } else { - if (verbose) - printf("mx%d: autoneg not complete, ", sc->mx_unit); - } - - media = mx_phy_readreg(sc, PHY_BMCR); - - /* Link is good. Report modes and set duplex mode. */ - if (mx_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { - if (verbose) - printf("link status good "); - advert = mx_phy_readreg(sc, PHY_ANAR); - ability = mx_phy_readreg(sc, PHY_LPAR); - - if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { - ifm->ifm_media = IFM_ETHER|IFM_100_T4; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(100baseT4)\n"); - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - media |= PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - media &= ~PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 10Mbps)\n"); - } else if (advert & PHY_ANAR_10BTHALF && - ability & PHY_ANAR_10BTHALF) { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - media &= ~PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 10Mbps)\n"); - } - - media &= ~PHY_BMCR_AUTONEGENBL; - - /* Set ASIC's duplex mode to match the PHY. */ - mx_setcfg(sc, media); - mx_phy_writereg(sc, PHY_BMCR, media); - } else { - if (verbose) - printf("no carrier\n"); - } - - mx_init(sc); - - if (sc->mx_tx_pend) { - sc->mx_autoneg = 0; - sc->mx_tx_pend = 0; - mx_start(ifp); - } - - return; -} - -/* - * Invoke autoneg using internal NWAY. - */ -static void mx_autoneg(sc, flag, verbose) - struct mx_softc *sc; - int flag; - int verbose; -{ - u_int32_t media, ability; - struct ifnet *ifp; - struct ifmedia *ifm; - - ifm = &sc->ifmedia; - ifp = &sc->arpcom.ac_if; - - ifm->ifm_media = IFM_ETHER | IFM_AUTO; - - switch (flag) { - case MX_FLAG_FORCEDELAY: - /* - * XXX Never use this option anywhere but in the probe - * routine: making the kernel stop dead in its tracks - * for three whole seconds after we've gone multi-user - * is really bad manners. - */ - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL); - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX); - MX_SETBIT(sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL); - MX_SETBIT(sc, MX_10BTCTRL, MX_ASTAT_TXDISABLE); - DELAY(5000000); - break; - case MX_FLAG_SCHEDDELAY: - /* - * Wait for the transmitter to go idle before starting - * an autoneg session, otherwise mx_start() may clobber - * our timeout, and we don't want to allow transmission - * during an autoneg session since that can screw it up. - */ - if (sc->mx_cdata.mx_tx_head != NULL) { - sc->mx_want_auto = 1; - return; - } - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL); - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX); - MX_SETBIT(sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL); - MX_SETBIT(sc, MX_10BTCTRL, MX_ASTAT_TXDISABLE); - ifp->if_timer = 5; - sc->mx_autoneg = 1; - sc->mx_want_auto = 0; - return; - break; - case MX_FLAG_DELAYTIMEO: - ifp->if_timer = 0; - sc->mx_autoneg = 0; - break; - default: - printf("mx%d: invalid autoneg flag: %d\n", sc->mx_unit, flag); - return; - } - - if ((CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_ANEGSTAT) == - MX_ASTAT_AUTONEGCMP) { - if (verbose) - printf("mx%d: autoneg complete, ", sc->mx_unit); - } else { - if (verbose) - printf("mx%d: autoneg not complete, ", sc->mx_unit); - } - - media = CSR_READ_4(sc, MX_NETCFG); - - /* Link is good. Report modes and set duplex mode. */ - if (!(CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_LS10) || - !(CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_LS100)) { - if (verbose) - printf("link status good "); - ability = CSR_READ_4(sc, MX_NWAYSTAT); - if (ability & MX_NWAY_100BT4) { - ifm->ifm_media = IFM_ETHER|IFM_100_T4; - media |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS| - MX_NETCFG_SCRAMBLER; - media &= ~(MX_NETCFG_FULLDUPLEX|MX_NETCFG_SPEEDSEL); - printf("(100baseT4)\n"); - } else if (ability & MX_NWAY_100BTFULL) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - media |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS| - MX_NETCFG_SCRAMBLER; - media |= MX_NETCFG_FULLDUPLEX; - media &= ~MX_NETCFG_SPEEDSEL; - printf("(full-duplex, 100Mbps)\n"); - } else if (ability & MX_NWAY_100BTHALF) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - media |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS| - MX_NETCFG_SCRAMBLER; - media &= ~(MX_NETCFG_FULLDUPLEX|MX_NETCFG_SPEEDSEL); - printf("(half-duplex, 100Mbps)\n"); - } else if (ability & MX_NWAY_10BTFULL) { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - media &= ~MX_NETCFG_PORTSEL; - media |= (MX_NETCFG_FULLDUPLEX|MX_NETCFG_SPEEDSEL); - printf("(full-duplex, 10Mbps)\n"); - } else { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - media &= ~MX_NETCFG_PORTSEL; - media &= ~MX_NETCFG_FULLDUPLEX; - media |= MX_NETCFG_SPEEDSEL; - printf("(half-duplex, 10Mbps)\n"); - } - - CSR_WRITE_4(sc, MX_NETCFG, media); - MX_CLRBIT(sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL); - } else { - if (verbose) - printf("no carrier\n"); - } - - mx_init(sc); - - if (sc->mx_tx_pend) { - sc->mx_autoneg = 0; - sc->mx_tx_pend = 0; - mx_start(ifp); - } - - return; -} - -static void mx_getmode_mii(sc) - struct mx_softc *sc; -{ - u_int16_t bmsr; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - bmsr = mx_phy_readreg(sc, PHY_BMSR); - if (bootverbose) - printf("mx%d: PHY status word: %x\n", sc->mx_unit, bmsr); - - /* fallback */ - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - - if (bmsr & PHY_BMSR_10BTHALF) { - if (bootverbose) - printf("mx%d: 10Mbps half-duplex mode supported\n", - sc->mx_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); - } - - if (bmsr & PHY_BMSR_10BTFULL) { - if (bootverbose) - printf("mx%d: 10Mbps full-duplex mode supported\n", - sc->mx_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - } - - if (bmsr & PHY_BMSR_100BTXHALF) { - if (bootverbose) - printf("mx%d: 100Mbps half-duplex mode supported\n", - sc->mx_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - } - - if (bmsr & PHY_BMSR_100BTXFULL) { - if (bootverbose) - printf("mx%d: 100Mbps full-duplex mode supported\n", - sc->mx_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - } - - /* Some also support 100BaseT4. */ - if (bmsr & PHY_BMSR_100BT4) { - if (bootverbose) - printf("mx%d: 100baseT4 mode supported\n", sc->mx_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4; -#ifdef FORCE_AUTONEG_TFOUR - if (bootverbose) - printf("mx%d: forcing on autoneg support for BT4\n", - sc->mx_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; -#endif - } - - if (bmsr & PHY_BMSR_CANAUTONEG) { - if (bootverbose) - printf("mx%d: autoneg supported\n", sc->mx_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; - } - - return; -} - -/* - * Set speed and duplex mode. - */ -static void mx_setmode_mii(sc, media) - struct mx_softc *sc; - int media; -{ - u_int16_t bmcr; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - /* - * If an autoneg session is in progress, stop it. - */ - if (sc->mx_autoneg) { - printf("mx%d: canceling autoneg session\n", sc->mx_unit); - ifp->if_timer = sc->mx_autoneg = sc->mx_want_auto = 0; - bmcr = mx_phy_readreg(sc, PHY_BMCR); - bmcr &= ~PHY_BMCR_AUTONEGENBL; - mx_phy_writereg(sc, PHY_BMCR, bmcr); - } - - printf("mx%d: selecting MII, ", sc->mx_unit); - - bmcr = mx_phy_readreg(sc, PHY_BMCR); - - bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL| - PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); - - if (IFM_SUBTYPE(media) == IFM_100_T4) { - printf("100Mbps/T4, half-duplex\n"); - bmcr |= PHY_BMCR_SPEEDSEL; - bmcr &= ~PHY_BMCR_DUPLEX; - } - - if (IFM_SUBTYPE(media) == IFM_100_TX) { - printf("100Mbps, "); - bmcr |= PHY_BMCR_SPEEDSEL; - } - - if (IFM_SUBTYPE(media) == IFM_10_T) { - printf("10Mbps, "); - bmcr &= ~PHY_BMCR_SPEEDSEL; - } - - if ((media & IFM_GMASK) == IFM_FDX) { - printf("full duplex\n"); - bmcr |= PHY_BMCR_DUPLEX; - } else { - printf("half duplex\n"); - bmcr &= ~PHY_BMCR_DUPLEX; - } - - mx_setcfg(sc, bmcr); - mx_phy_writereg(sc, PHY_BMCR, bmcr); - - return; -} - -/* - * Set speed and duplex mode on internal transceiver. - */ -static void mx_setmode(sc, media, verbose) - struct mx_softc *sc; - int media; - int verbose; -{ - struct ifnet *ifp; - u_int32_t mode; - - ifp = &sc->arpcom.ac_if; - - /* - * If an autoneg session is in progress, stop it. - */ - if (sc->mx_autoneg) { - printf("mx%d: canceling autoneg session\n", sc->mx_unit); - ifp->if_timer = sc->mx_autoneg = sc->mx_want_auto = 0; - MX_CLRBIT(sc, MX_10BTCTRL, MX_TCTL_AUTONEGENBL); - } - - if (verbose) - printf("mx%d: selecting NWAY, ", sc->mx_unit); - - mode = CSR_READ_4(sc, MX_NETCFG); - - mode &= ~(MX_NETCFG_FULLDUPLEX|MX_NETCFG_PORTSEL| - MX_NETCFG_PCS|MX_NETCFG_SCRAMBLER|MX_NETCFG_SPEEDSEL); - - if (IFM_SUBTYPE(media) == IFM_100_T4) { - if (verbose) - printf("100Mbps/T4, half-duplex\n"); - mode |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS|MX_NETCFG_SCRAMBLER; - } - - if (IFM_SUBTYPE(media) == IFM_100_TX) { - if (verbose) - printf("100Mbps, "); - mode |= MX_NETCFG_PORTSEL|MX_NETCFG_PCS|MX_NETCFG_SCRAMBLER; - } - - if (IFM_SUBTYPE(media) == IFM_10_T) { - if (verbose) - printf("10Mbps, "); - mode &= ~MX_NETCFG_PORTSEL; - mode |= MX_NETCFG_SPEEDSEL; - } - - if ((media & IFM_GMASK) == IFM_FDX) { - if (verbose) - printf("full duplex\n"); - mode |= MX_NETCFG_FULLDUPLEX; - } else { - if (verbose) - printf("half duplex\n"); - mode &= ~MX_NETCFG_FULLDUPLEX; - } - - CSR_WRITE_4(sc, MX_NETCFG, mode); - - return; -} - -/* - * Programming the receiver filter on the tulip/PMAC is gross. You - * have to construct a special setup frame and download it to the - * chip via the transmit DMA engine. This routine is also somewhat - * gross, as the setup frame is sent synchronously rather than putting - * on the transmit queue. The transmitter has to be stopped, then we - * can download the frame and wait for the 'owned' bit to clear. - * - * We always program the chip using 'hash perfect' mode, i.e. one perfect - * address (our node address) and a 512-bit hash filter for multicast - * frames. We also sneak the broadcast address into the hash filter since - * we need that too. - */ -void mx_setfilt(sc) - struct mx_softc *sc; -{ - struct mx_desc *sframe; - u_int32_t h, *sp; - struct ifmultiaddr *ifma; - struct ifnet *ifp; - int i; - - ifp = &sc->arpcom.ac_if; - - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON); - MX_SETBIT(sc, MX_ISR, MX_ISR_TX_IDLE); - - sframe = &sc->mx_cdata.mx_sframe; - sp = (u_int32_t *)&sc->mx_cdata.mx_sbuf; - bzero((char *)sp, MX_SFRAME_LEN); - - sframe->mx_next = vtophys(&sc->mx_ldata->mx_tx_list[0]); - sframe->mx_data = vtophys(&sc->mx_cdata.mx_sbuf); - sframe->mx_ctl = MX_SFRAME_LEN | MX_TXCTL_TLINK | - MX_TXCTL_SETUP | MX_FILTER_HASHPERF; - - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_RX_PROMISC); - else - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_RX_PROMISC); - - if (ifp->if_flags & IFF_ALLMULTI) - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_RX_ALLMULTI); - - for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; - ifma = ifma->ifma_link.le_next) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = mx_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - sp[h >> 4] |= 1 << (h & 0xF); - } - - if (ifp->if_flags & IFF_BROADCAST) { - h = mx_calchash(etherbroadcastaddr); - sp[h >> 4] |= 1 << (h & 0xF); - } - - sp[39] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0]; - sp[40] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1]; - sp[41] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2]; - - CSR_WRITE_4(sc, MX_TXADDR, vtophys(sframe)); - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON); - sframe->mx_status = MX_TXSTAT_OWN; - CSR_WRITE_4(sc, MX_TXSTART, 0xFFFFFFFF); - - /* - * Wait for chip to clear the 'own' bit. - */ - for (i = 0; i < MX_TIMEOUT; i++) { - DELAY(10); - if (sframe->mx_status != MX_TXSTAT_OWN) - break; - } - - if (i == MX_TIMEOUT) - printf("mx%d: failed to send setup frame\n", sc->mx_unit); - - MX_SETBIT(sc, MX_ISR, MX_ISR_TX_NOBUF|MX_ISR_TX_IDLE); - - return; -} - -/* - * In order to fiddle with the - * 'full-duplex' and '100Mbps' bits in the netconfig register, we - * first have to put the transmit and/or receive logic in the idle state. - */ -static void mx_setcfg(sc, bmcr) - struct mx_softc *sc; - u_int16_t bmcr; -{ - int i, restart = 0; - - if (CSR_READ_4(sc, MX_NETCFG) & (MX_NETCFG_TX_ON|MX_NETCFG_RX_ON)) { - restart = 1; - MX_CLRBIT(sc, MX_NETCFG, (MX_NETCFG_TX_ON|MX_NETCFG_RX_ON)); - - for (i = 0; i < MX_TIMEOUT; i++) { - DELAY(10); - if (CSR_READ_4(sc, MX_ISR) & MX_ISR_TX_IDLE) - break; - } - - if (i == MX_TIMEOUT) - printf("mx%d: failed to force tx and " - "rx to idle state\n", sc->mx_unit); - - } - - if (bmcr & PHY_BMCR_SPEEDSEL) { - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_SPEEDSEL); - if (sc->mx_phy_addr == 0) { - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_PORTSEL| - MX_NETCFG_PCS|MX_NETCFG_SCRAMBLER); - } - } else - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_SPEEDSEL); - - if (bmcr & PHY_BMCR_DUPLEX) - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX); - else - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_FULLDUPLEX); - - if (restart) - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON|MX_NETCFG_RX_ON); - - return; -} - -static void mx_reset(sc) - struct mx_softc *sc; -{ - register int i; - - MX_SETBIT(sc, MX_BUSCTL, MX_BUSCTL_RESET); - - for (i = 0; i < MX_TIMEOUT; i++) { - DELAY(10); - if (!(CSR_READ_4(sc, MX_BUSCTL) & MX_BUSCTL_RESET)) - break; - } - if (i == MX_TIMEOUT) - printf("mx%d: reset never completed!\n", sc->mx_unit); - - /* Wait a little while for the chip to get its brains in order. */ - DELAY(1000); - return; -} - -/* - * Probe for a Macronix PMAC chip. Check the PCI vendor and device - * IDs against our list and return a device name if we find a match. - * We do a little bit of extra work to identify the exact type of - * chip. The MX98713 and MX98713A have the same PCI vendor/device ID, - * but different revision IDs. The same is true for 98715/98715A - * chips and the 98725. This doesn't affect a whole lot, but it - * lets us tell the user exactly what type of device they have - * in the probe output. - */ -static const char * -mx_probe(config_id, device_id) - pcici_t config_id; - pcidi_t device_id; -{ - struct mx_type *t; - u_int32_t rev; - - t = mx_devs; - - while(t->mx_name != NULL) { - if ((device_id & 0xFFFF) == t->mx_vid && - ((device_id >> 16) & 0xFFFF) == t->mx_did) { - /* Check the PCI revision */ - rev = pci_conf_read(config_id, MX_PCI_REVID) & 0xFF; - if (t->mx_did == MX_DEVICEID_98713 && - rev >= MX_REVISION_98713A) - t++; - if (t->mx_did == MX_DEVICEID_987x5 && - rev >= MX_REVISION_98725) - t++; - return(t->mx_name); - } - t++; - } - - return(NULL); -} - -/* - * Attach the interface. Allocate softc structures, do ifmedia - * setup and ethernet/BPF attach. - */ -static void -mx_attach(config_id, unit) - pcici_t config_id; - int unit; -{ - int s, i; -#ifndef MX_USEIOSPACE - vm_offset_t pbase, vbase; -#endif - u_char eaddr[ETHER_ADDR_LEN]; - u_int32_t command; - struct mx_softc *sc; - struct ifnet *ifp; - int media = IFM_ETHER|IFM_100_TX|IFM_FDX; - unsigned int round; - caddr_t roundptr; - struct mx_type *p; - u_int16_t phy_vid, phy_did, phy_sts, mac_offset = 0; - u_int32_t revision, pci_id; - - s = splimp(); - - sc = malloc(sizeof(struct mx_softc), M_DEVBUF, M_NOWAIT); - if (sc == NULL) { - printf("mx%d: no memory for softc struct!\n", unit); - return; - } - bzero(sc, sizeof(struct mx_softc)); - - /* - * Handle power management nonsense. - */ - - command = pci_conf_read(config_id, MX_PCI_CAPID) & 0x000000FF; - if (command == 0x01) { - - command = pci_conf_read(config_id, MX_PCI_PWRMGMTCTRL); - if (command & MX_PSTATE_MASK) { - u_int32_t iobase, membase, irq; - - /* Save important PCI config data. */ - iobase = pci_conf_read(config_id, MX_PCI_LOIO); - membase = pci_conf_read(config_id, MX_PCI_LOMEM); - irq = pci_conf_read(config_id, MX_PCI_INTLINE); - - /* Reset the power state. */ - printf("mx%d: chip is in D%d power mode " - "-- setting to D0\n", unit, command & MX_PSTATE_MASK); - command &= 0xFFFFFFFC; - pci_conf_write(config_id, MX_PCI_PWRMGMTCTRL, command); - - /* Restore PCI config data. */ - pci_conf_write(config_id, MX_PCI_LOIO, iobase); - pci_conf_write(config_id, MX_PCI_LOMEM, membase); - pci_conf_write(config_id, MX_PCI_INTLINE, irq); - } - } - - /* - * Map control/status registers. - */ - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); - pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - -#ifdef MX_USEIOSPACE - if (!(command & PCIM_CMD_PORTEN)) { - printf("mx%d: failed to enable I/O ports!\n", unit); - free(sc, M_DEVBUF); - goto fail; - } - - if (!pci_map_port(config_id, MX_PCI_LOIO, - (u_short *)&(sc->mx_bhandle))) { - printf ("mx%d: couldn't map ports\n", unit); - goto fail; - } - sc->mx_btag = I386_BUS_SPACE_IO; -#else - if (!(command & PCIM_CMD_MEMEN)) { - printf("mx%d: failed to enable memory mapping!\n", unit); - goto fail; - } - - if (!pci_map_mem(config_id, MX_PCI_LOMEM, &vbase, &pbase)) { - printf ("mx%d: couldn't map memory\n", unit); - goto fail; - } - sc->mx_btag = I386_BUS_SPACE_MEM; - sc->mx_bhandle = vbase; -#endif - - /* Allocate interrupt */ - if (!pci_map_int(config_id, mx_intr, sc, &net_imask)) { - printf("mx%d: couldn't map interrupt\n", unit); - goto fail; - } - - /* Need this info to decide on a chip type. */ - revision = pci_conf_read(config_id, MX_PCI_REVID) & 0x000000FF; - pci_id = pci_conf_read(config_id, MX_PCI_VENDOR_ID) & 0x0000FFFF; - pci_id = (pci_conf_read(config_id,MX_PCI_VENDOR_ID) >> 16) & 0x0000FFFF; - - if (pci_id == MX_DEVICEID_98713 && revision < MX_REVISION_98713A) - sc->mx_type = MX_TYPE_98713; - else if (pci_id == MX_DEVICEID_98713 && revision >= MX_REVISION_98713A) - sc->mx_type = MX_TYPE_98713A; - else - sc->mx_type = MX_TYPE_987x5; - - /* Reset the adapter. */ - mx_reset(sc); - - /* - * Get station address from the EEPROM. - */ - mx_read_eeprom(sc, (caddr_t)&mac_offset, - (MX_EE_NODEADDR_OFFSET / 2), 1, 0); - mx_read_eeprom(sc, (caddr_t)&eaddr, (mac_offset / 2), 3, 0); - - /* - * A PMAC chip was detected. Inform the world. - */ - printf("mx%d: Ethernet address: %6D\n", unit, eaddr, ":"); - - sc->mx_unit = unit; - bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); - - sc->mx_ldata_ptr = malloc(sizeof(struct mx_list_data) + 8, - M_DEVBUF, M_NOWAIT); - if (sc->mx_ldata_ptr == NULL) { - free(sc, M_DEVBUF); - printf("mx%d: no memory for list buffers!\n", unit); - return; - } - - sc->mx_ldata = (struct mx_list_data *)sc->mx_ldata_ptr; - round = (unsigned int)sc->mx_ldata_ptr & 0xF; - roundptr = sc->mx_ldata_ptr; - for (i = 0; i < 8; i++) { - if (round % 8) { - round++; - roundptr++; - } - break; - } - sc->mx_ldata = (struct mx_list_data *)roundptr; - bzero(sc->mx_ldata, sizeof(struct mx_list_data)); - - ifp = &sc->arpcom.ac_if; - ifp->if_softc = sc; - ifp->if_unit = unit; - ifp->if_name = "mx"; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = mx_ioctl; - ifp->if_output = ether_output; - ifp->if_start = mx_start; - ifp->if_watchdog = mx_watchdog; - ifp->if_init = mx_init; - ifp->if_baudrate = 10000000; - - - if (sc->mx_type == MX_TYPE_98713) { - if (bootverbose) - printf("mx%d: probing for a PHY\n", sc->mx_unit); - for (i = MX_PHYADDR_MIN; i < MX_PHYADDR_MAX + 1; i++) { - if (bootverbose) - printf("mx%d: checking address: %d\n", - sc->mx_unit, i); - sc->mx_phy_addr = i; - mx_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(mx_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - if ((phy_sts = mx_phy_readreg(sc, PHY_BMSR))) - break; - } - if (phy_sts) { - phy_vid = mx_phy_readreg(sc, PHY_VENID); - phy_did = mx_phy_readreg(sc, PHY_DEVID); - if (bootverbose) - printf("mx%d: found PHY at address %d, ", - sc->mx_unit, sc->mx_phy_addr); - if (bootverbose) - printf("vendor id: %x device id: %x\n", - phy_vid, phy_did); - p = mx_phys; - while(p->mx_vid) { - if (phy_vid == p->mx_vid && - (phy_did | 0x000F) == p->mx_did) { - sc->mx_pinfo = p; - break; - } - p++; - } - if (sc->mx_pinfo == NULL) - sc->mx_pinfo = &mx_phys[PHY_UNKNOWN]; - if (bootverbose) - printf("mx%d: PHY type: %s\n", - sc->mx_unit, sc->mx_pinfo->mx_name); - } else { -#ifdef DIAGNOSTIC - printf("mx%d: MII without any phy!\n", sc->mx_unit); -#endif - } - } - - /* - * Do ifmedia setup. - */ - ifmedia_init(&sc->ifmedia, 0, mx_ifmedia_upd, mx_ifmedia_sts); - - if (sc->mx_type == MX_TYPE_98713 && sc->mx_pinfo != NULL) { - mx_getmode_mii(sc); - mx_autoneg_mii(sc, MX_FLAG_FORCEDELAY, 1); - } else { - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); - mx_autoneg(sc, MX_FLAG_FORCEDELAY, 1); - } - - media = sc->ifmedia.ifm_media; - mx_stop(sc); - - ifmedia_set(&sc->ifmedia, media); - - /* - * Call MI attach routines. - */ - if_attach(ifp); - ether_ifattach(ifp); - -#if NBPFILTER > 0 - bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif - at_shutdown(mx_shutdown, sc, SHUTDOWN_POST_SYNC); - -fail: - splx(s); - return; -} - -/* - * Initialize the transmit descriptors. - */ -static int mx_list_tx_init(sc) - struct mx_softc *sc; -{ - struct mx_chain_data *cd; - struct mx_list_data *ld; - int i; - - cd = &sc->mx_cdata; - ld = sc->mx_ldata; - for (i = 0; i < MX_TX_LIST_CNT; i++) { - cd->mx_tx_chain[i].mx_ptr = &ld->mx_tx_list[i]; - if (i == (MX_TX_LIST_CNT - 1)) - cd->mx_tx_chain[i].mx_nextdesc = - &cd->mx_tx_chain[0]; - else - cd->mx_tx_chain[i].mx_nextdesc = - &cd->mx_tx_chain[i + 1]; - } - - cd->mx_tx_free = &cd->mx_tx_chain[0]; - cd->mx_tx_tail = cd->mx_tx_head = NULL; - - return(0); -} - - -/* - * Initialize the RX descriptors and allocate mbufs for them. Note that - * we arrange the descriptors in a closed ring, so that the last descriptor - * points back to the first. - */ -static int mx_list_rx_init(sc) - struct mx_softc *sc; -{ - struct mx_chain_data *cd; - struct mx_list_data *ld; - int i; - - cd = &sc->mx_cdata; - ld = sc->mx_ldata; - - for (i = 0; i < MX_RX_LIST_CNT; i++) { - cd->mx_rx_chain[i].mx_ptr = - (struct mx_desc *)&ld->mx_rx_list[i]; - if (mx_newbuf(sc, &cd->mx_rx_chain[i]) == ENOBUFS) - return(ENOBUFS); - if (i == (MX_RX_LIST_CNT - 1)) { - cd->mx_rx_chain[i].mx_nextdesc = &cd->mx_rx_chain[0]; - ld->mx_rx_list[i].mx_next = - vtophys(&ld->mx_rx_list[0]); - } else { - cd->mx_rx_chain[i].mx_nextdesc = &cd->mx_rx_chain[i + 1]; - ld->mx_rx_list[i].mx_next = - vtophys(&ld->mx_rx_list[i + 1]); - } - } - - cd->mx_rx_head = &cd->mx_rx_chain[0]; - - return(0); -} - -/* - * Initialize an RX descriptor and attach an MBUF cluster. - * Note: the length fields are only 11 bits wide, which means the - * largest size we can specify is 2047. This is important because - * MCLBYTES is 2048, so we have to subtract one otherwise we'll - * overflow the field and make a mess. - */ -static int mx_newbuf(sc, c) - struct mx_softc *sc; - struct mx_chain_onefrag *c; -{ - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("mx%d: no memory for rx list -- packet dropped!\n", - sc->mx_unit); - return(ENOBUFS); - } - - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - printf("mx%d: no memory for rx list -- packet dropped!\n", - sc->mx_unit); - m_freem(m_new); - return(ENOBUFS); - } - - c->mx_mbuf = m_new; - c->mx_ptr->mx_status = MX_RXSTAT; - c->mx_ptr->mx_data = vtophys(mtod(m_new, caddr_t)); - c->mx_ptr->mx_ctl = MX_RXCTL_RLINK | (MCLBYTES - 1); - - return(0); -} - -/* - * A frame has been uploaded: pass the resulting mbuf chain up to - * the higher level protocols. - */ -static void mx_rxeof(sc) - struct mx_softc *sc; -{ - struct ether_header *eh; - struct mbuf *m; - struct ifnet *ifp; - struct mx_chain_onefrag *cur_rx; - int total_len = 0; - u_int32_t rxstat; - - ifp = &sc->arpcom.ac_if; - - while(!((rxstat = sc->mx_cdata.mx_rx_head->mx_ptr->mx_status) & - MX_RXSTAT_OWN)) { - cur_rx = sc->mx_cdata.mx_rx_head; - sc->mx_cdata.mx_rx_head = cur_rx->mx_nextdesc; - - /* - * If an error occurs, update stats, clear the - * status word and leave the mbuf cluster in place: - * it should simply get re-used next time this descriptor - * comes up in the ring. - */ - if (rxstat & MX_RXSTAT_RXERR) { - ifp->if_ierrors++; - if (rxstat & MX_RXSTAT_COLLSEEN) - ifp->if_collisions++; - cur_rx->mx_ptr->mx_status = MX_RXSTAT; - cur_rx->mx_ptr->mx_ctl = - MX_RXCTL_RLINK | (MCLBYTES - 1); - continue; - } - - /* No errors; receive the packet. */ - m = cur_rx->mx_mbuf; - total_len = MX_RXBYTES(cur_rx->mx_ptr->mx_status); - - /* - * XXX The Macronix chips includes the CRC with every - * received frame, and there's no way to turn this - * behavior off (at least, I can't find anything in - * the manual that explains how to do it) so we have - * to trim off the CRC manually. - */ - total_len -= ETHER_CRC_LEN; - - /* - * Try to conjure up a new mbuf cluster. If that - * fails, it means we have an out of memory condition and - * should leave the buffer in place and continue. This will - * result in a lost packet, but there's little else we - * can do in this situation. - */ - if (mx_newbuf(sc, cur_rx) == ENOBUFS) { - ifp->if_ierrors++; - cur_rx->mx_ptr->mx_status = MX_RXSTAT; - cur_rx->mx_ptr->mx_ctl = - MX_RXCTL_RLINK | (MCLBYTES - 1); - continue; - } - - ifp->if_ipackets++; - eh = mtod(m, struct ether_header *); - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = m->m_len = total_len; -#if NBPFILTER > 0 - /* - * Handle BPF listeners. Let the BPF user see the packet, but - * don't pass it up to the ether_input() layer unless it's - * a broadcast packet, multicast packet, matches our ethernet - * address or the interface is in promiscuous mode. - */ - if (ifp->if_bpf) { - bpf_mtap(ifp, m); - if (ifp->if_flags & IFF_PROMISC && - (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, - ETHER_ADDR_LEN) && - (eh->ether_dhost[0] & 1) == 0)) { - m_freem(m); - continue; - } - } -#endif - /* Remove header from mbuf and pass it on. */ - m_adj(m, sizeof(struct ether_header)); - ether_input(ifp, eh, m); - } - - return; -} - -void mx_rxeoc(sc) - struct mx_softc *sc; -{ - - mx_rxeof(sc); - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_RX_ON); - CSR_WRITE_4(sc, MX_RXADDR, vtophys(sc->mx_cdata.mx_rx_head->mx_ptr)); - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_RX_ON); - CSR_WRITE_4(sc, MX_RXSTART, 0xFFFFFFFF); - - return; -} - -/* - * A frame was downloaded to the chip. It's safe for us to clean up - * the list buffers. - */ - -static void mx_txeof(sc) - struct mx_softc *sc; -{ - struct mx_chain *cur_tx; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - /* Clear the timeout timer. */ - ifp->if_timer = 0; - - if (sc->mx_cdata.mx_tx_head == NULL) - return; - - /* - * Go through our tx list and free mbufs for those - * frames that have been transmitted. - */ - while(sc->mx_cdata.mx_tx_head->mx_mbuf != NULL) { - u_int32_t txstat; - - cur_tx = sc->mx_cdata.mx_tx_head; - txstat = MX_TXSTATUS(cur_tx); - - if ((txstat & MX_TXSTAT_OWN) || txstat == MX_UNSENT) - break; - - if (txstat & MX_TXSTAT_ERRSUM) { - ifp->if_oerrors++; - if (txstat & MX_TXSTAT_EXCESSCOLL) - ifp->if_collisions++; - if (txstat & MX_TXSTAT_LATECOLL) - ifp->if_collisions++; - } - - ifp->if_collisions += (txstat & MX_TXSTAT_COLLCNT) >> 3; - - ifp->if_opackets++; - m_freem(cur_tx->mx_mbuf); - cur_tx->mx_mbuf = NULL; - - if (sc->mx_cdata.mx_tx_head == sc->mx_cdata.mx_tx_tail) { - sc->mx_cdata.mx_tx_head = NULL; - sc->mx_cdata.mx_tx_tail = NULL; - break; - } - - sc->mx_cdata.mx_tx_head = cur_tx->mx_nextdesc; - } - - return; -} - -/* - * TX 'end of channel' interrupt handler. - */ -static void mx_txeoc(sc) - struct mx_softc *sc; -{ - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - ifp->if_timer = 0; - - if (sc->mx_cdata.mx_tx_head == NULL) { - ifp->if_flags &= ~IFF_OACTIVE; - sc->mx_cdata.mx_tx_tail = NULL; - if (sc->mx_want_auto) { - if (sc->mx_type == MX_TYPE_98713 && - sc->mx_pinfo != NULL) - mx_autoneg_mii(sc, MX_FLAG_DELAYTIMEO, 1); - else - mx_autoneg(sc, MX_FLAG_DELAYTIMEO, 1); - } - } else { - if (MX_TXOWN(sc->mx_cdata.mx_tx_head) == MX_UNSENT) { - MX_TXOWN(sc->mx_cdata.mx_tx_head) = MX_TXSTAT_OWN; - ifp->if_timer = 5; - CSR_WRITE_4(sc, MX_TXSTART, 0xFFFFFFFF); - } - } - - return; -} - -static void mx_intr(arg) - void *arg; -{ - struct mx_softc *sc; - struct ifnet *ifp; - u_int32_t status; - - sc = arg; - ifp = &sc->arpcom.ac_if; - - /* Supress unwanted interrupts */ - if (!(ifp->if_flags & IFF_UP)) { - mx_stop(sc); - return; - } - - /* Disable interrupts. */ - CSR_WRITE_4(sc, MX_IMR, 0x00000000); - - for (;;) { - status = CSR_READ_4(sc, MX_ISR); - if (status) - CSR_WRITE_4(sc, MX_ISR, status); - - if ((status & MX_INTRS) == 0) - break; - - if (status & MX_ISR_TX_OK) - mx_txeof(sc); - - if (status & MX_ISR_TX_NOBUF) - mx_txeoc(sc); - - if (status & MX_ISR_TX_IDLE) { - mx_txeof(sc); - if (sc->mx_cdata.mx_tx_head != NULL) { - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON); - CSR_WRITE_4(sc, MX_TXSTART, 0xFFFFFFFF); - } - } - - if (status & MX_ISR_TX_UNDERRUN) { - u_int32_t cfg; - cfg = CSR_READ_4(sc, MX_NETCFG); - if ((cfg & MX_NETCFG_TX_THRESH) == MX_TXTHRESH_160BYTES) - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_STORENFWD); - else - CSR_WRITE_4(sc, MX_NETCFG, cfg + 0x4000); - } - - if (status & MX_ISR_RX_OK) - mx_rxeof(sc); - - if ((status & MX_ISR_RX_WATDOGTIMEO) - || (status & MX_ISR_RX_NOBUF)) - mx_rxeoc(sc); - - if (status & MX_ISR_BUS_ERR) { - mx_reset(sc); - mx_init(sc); - } - } - - /* Re-enable interrupts. */ - CSR_WRITE_4(sc, MX_IMR, MX_INTRS); - - if (ifp->if_snd.ifq_head != NULL) { - mx_start(ifp); - } - - return; -} - -/* - * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data - * pointers to the fragment pointers. - */ -static int mx_encap(sc, c, m_head) - struct mx_softc *sc; - struct mx_chain *c; - struct mbuf *m_head; -{ - int frag = 0; - volatile struct mx_desc *f = NULL; - int total_len; - struct mbuf *m; - - /* - * Start packing the mbufs in this chain into - * the fragment pointers. Stop when we run out - * of fragments or hit the end of the mbuf chain. - */ - m = m_head; - total_len = 0; - - for (m = m_head, frag = 0; m != NULL; m = m->m_next) { - if (m->m_len != 0) { - if (frag == MX_MAXFRAGS) - break; - total_len += m->m_len; - f = &c->mx_ptr->mx_frag[frag]; - f->mx_ctl = MX_TXCTL_TLINK | m->m_len; - if (frag == 0) { - f->mx_status = 0; - f->mx_ctl |= MX_TXCTL_FIRSTFRAG; - } else - f->mx_status = MX_TXSTAT_OWN; - f->mx_next = vtophys(&c->mx_ptr->mx_frag[frag + 1]); - f->mx_data = vtophys(mtod(m, vm_offset_t)); - frag++; - } - } - - /* - * Handle special case: we ran out of fragments, - * but we have more mbufs left in the chain. Copy the - * data into an mbuf cluster. Note that we don't - * bother clearing the values in the other fragment - * pointers/counters; it wouldn't gain us anything, - * and would waste cycles. - */ - if (m != NULL) { - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("mx%d: no memory for tx list", sc->mx_unit); - return(1); - } - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - printf("mx%d: no memory for tx list", - sc->mx_unit); - return(1); - } - } - m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; - m_freem(m_head); - m_head = m_new; - f = &c->mx_ptr->mx_frag[0]; - f->mx_status = 0; - f->mx_data = vtophys(mtod(m_new, caddr_t)); - f->mx_ctl = total_len = m_new->m_len; - f->mx_ctl |= MX_TXCTL_TLINK|MX_TXCTL_FIRSTFRAG; - frag = 1; - } - - - if (total_len < MX_MIN_FRAMELEN) { - f = &c->mx_ptr->mx_frag[frag]; - f->mx_ctl = MX_MIN_FRAMELEN - total_len; - f->mx_data = vtophys(&sc->mx_cdata.mx_pad); - f->mx_ctl |= MX_TXCTL_TLINK; - f->mx_status = MX_TXSTAT_OWN; - frag++; - } - - c->mx_mbuf = m_head; - c->mx_lastdesc = frag - 1; - MX_TXCTL(c) |= MX_TXCTL_LASTFRAG; - MX_TXNEXT(c) = vtophys(&c->mx_nextdesc->mx_ptr->mx_frag[0]); - return(0); -} - -/* - * Main transmit routine. To avoid having to do mbuf copies, we put pointers - * to the mbuf data regions directly in the transmit lists. We also save a - * copy of the pointers since the transmit list fragment pointers are - * physical addresses. - */ - -static void mx_start(ifp) - struct ifnet *ifp; -{ - struct mx_softc *sc; - struct mbuf *m_head = NULL; - struct mx_chain *cur_tx = NULL, *start_tx; - - sc = ifp->if_softc; - - if (sc->mx_autoneg) { - sc->mx_tx_pend = 1; - return; - } - - /* - * Check for an available queue slot. If there are none, - * punt. - */ - if (sc->mx_cdata.mx_tx_free->mx_mbuf != NULL) { - ifp->if_flags |= IFF_OACTIVE; - return; - } - - start_tx = sc->mx_cdata.mx_tx_free; - - while(sc->mx_cdata.mx_tx_free->mx_mbuf == NULL) { - IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) - break; - - /* Pick a descriptor off the free list. */ - cur_tx = sc->mx_cdata.mx_tx_free; - sc->mx_cdata.mx_tx_free = cur_tx->mx_nextdesc; - - /* Pack the data into the descriptor. */ - mx_encap(sc, cur_tx, m_head); - if (cur_tx != start_tx) - MX_TXOWN(cur_tx) = MX_TXSTAT_OWN; - -#if NBPFILTER > 0 - /* - * If there's a BPF listener, bounce a copy of this frame - * to him. - */ - if (ifp->if_bpf) - bpf_mtap(ifp, cur_tx->mx_mbuf); -#endif - } - - /* - * If there are no frames queued, bail. - */ - if (cur_tx == NULL) - return; - - /* - * Place the request for the upload interrupt - * in the last descriptor in the chain. This way, if - * we're chaining several packets at once, we'll only - * get an interupt once for the whole chain rather than - * once for each packet. - */ - MX_TXCTL(cur_tx) |= MX_TXCTL_FINT; - sc->mx_cdata.mx_tx_tail = cur_tx; - - if (sc->mx_cdata.mx_tx_head == NULL) { - sc->mx_cdata.mx_tx_head = start_tx; - MX_TXOWN(start_tx) = MX_TXSTAT_OWN; - CSR_WRITE_4(sc, MX_TXSTART, 0xFFFFFFFF); - } else { - MX_TXOWN(start_tx) = MX_UNSENT; - } - - /* - * Set a timeout in case the chip goes out to lunch. - */ - ifp->if_timer = 5; - - return; -} - -static void mx_init(xsc) - void *xsc; -{ - struct mx_softc *sc = xsc; - struct ifnet *ifp = &sc->arpcom.ac_if; - u_int16_t phy_bmcr = 0; - int s; - - if (sc->mx_autoneg) - return; - - s = splimp(); - - if (sc->mx_pinfo != NULL) - phy_bmcr = mx_phy_readreg(sc, PHY_BMCR); - - /* - * Cancel pending I/O and free all RX/TX buffers. - */ - mx_stop(sc); - mx_reset(sc); - - /* - * Set cache alignment and burst length. - */ - CSR_WRITE_4(sc, MX_BUSCTL, MX_BUSCTL_CONFIG); - - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_NO_RXCRC); - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_HEARTBEAT); - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_STORENFWD); - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_TX_BACKOFF); - - /* - * The app notes for the 98713 and 98715A say that - * in order to have the chips operate properly, a magic - * number must be written to CSR16. Macronix does not - * document the meaning of these bits so there's no way - * to know exactly what they mean. The 98713 has a magic - * number all its own; the rest all use a different one. - */ - MX_CLRBIT(sc, MX_MAGICPACKET, 0xFFFF0000); - if (sc->mx_type == MX_TYPE_98713) - MX_SETBIT(sc, MX_MAGICPACKET, MX_MAGIC_98713); - else - MX_SETBIT(sc, MX_MAGICPACKET, MX_MAGIC_98715); - - if (sc->mx_pinfo != NULL) { - MX_SETBIT(sc, MX_WATCHDOG, MX_WDOG_JABBERDIS); - mx_setcfg(sc, mx_phy_readreg(sc, PHY_BMCR)); - } else - mx_setmode(sc, sc->ifmedia.ifm_media, 0); - - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_TX_THRESH); - MX_CLRBIT(sc, MX_NETCFG, MX_NETCFG_SPEEDSEL); - - if (IFM_SUBTYPE(sc->ifmedia.ifm_media) == IFM_10_T) - MX_SETBIT(sc, MX_NETCFG, MX_TXTHRESH_160BYTES); - else - MX_SETBIT(sc, MX_NETCFG, MX_TXTHRESH_72BYTES); - - /* Init circular RX list. */ - if (mx_list_rx_init(sc) == ENOBUFS) { - printf("mx%d: initialization failed: no " - "memory for rx buffers\n", sc->mx_unit); - mx_stop(sc); - (void)splx(s); - return; - } - - /* - * Init tx descriptors. - */ - mx_list_tx_init(sc); - - /* - * Load the address of the RX list. - */ - CSR_WRITE_4(sc, MX_RXADDR, vtophys(sc->mx_cdata.mx_rx_head->mx_ptr)); - - /* - * Load the RX/multicast filter. - */ - mx_setfilt(sc); - - /* - * Enable interrupts. - */ - CSR_WRITE_4(sc, MX_IMR, MX_INTRS); - CSR_WRITE_4(sc, MX_ISR, 0xFFFFFFFF); - - /* Enable receiver and transmitter. */ - MX_SETBIT(sc, MX_NETCFG, MX_NETCFG_TX_ON|MX_NETCFG_RX_ON); - CSR_WRITE_4(sc, MX_RXSTART, 0xFFFFFFFF); - - /* Restore state of BMCR */ - if (sc->mx_pinfo != NULL) - mx_phy_writereg(sc, PHY_BMCR, phy_bmcr); - - ifp->if_flags |= IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - - (void)splx(s); - - return; -} - -/* - * Set media options. - */ -static int mx_ifmedia_upd(ifp) - struct ifnet *ifp; -{ - struct mx_softc *sc; - struct ifmedia *ifm; - - sc = ifp->if_softc; - ifm = &sc->ifmedia; - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return(EINVAL); - - if (sc->mx_type == MX_TYPE_98713 && sc->mx_pinfo != NULL) { - if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) - mx_autoneg_mii(sc, MX_FLAG_SCHEDDELAY, 1); - else - mx_setmode_mii(sc, ifm->ifm_media); - } else { - if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) - mx_autoneg(sc, MX_FLAG_SCHEDDELAY, 1); - else - mx_setmode(sc, ifm->ifm_media, 1); - } - - return(0); -} - -/* - * Report current media status. - */ -static void mx_ifmedia_sts(ifp, ifmr) - struct ifnet *ifp; - struct ifmediareq *ifmr; -{ - struct mx_softc *sc; - u_int16_t advert = 0, ability = 0; - u_int32_t media = 0; - - sc = ifp->if_softc; - - ifmr->ifm_active = IFM_ETHER; - - if (sc->mx_type != MX_TYPE_98713 || sc->mx_pinfo == NULL) { - media = CSR_READ_4(sc, MX_NETCFG); - if (media & MX_NETCFG_PORTSEL) - ifmr->ifm_active = IFM_ETHER|IFM_100_TX; - else - ifmr->ifm_active = IFM_ETHER|IFM_10_T; - if (media & MX_NETCFG_FULLDUPLEX) - ifmr->ifm_active |= IFM_FDX; - else - ifmr->ifm_active |= IFM_HDX; - return; - } - - if (!(mx_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { - if (mx_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) - ifmr->ifm_active = IFM_ETHER|IFM_100_TX; - else - ifmr->ifm_active = IFM_ETHER|IFM_10_T; - if (mx_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) - ifmr->ifm_active |= IFM_FDX; - else - ifmr->ifm_active |= IFM_HDX; - return; - } - - ability = mx_phy_readreg(sc, PHY_LPAR); - advert = mx_phy_readreg(sc, PHY_ANAR); - if (advert & PHY_ANAR_100BT4 && - ability & PHY_ANAR_100BT4) { - ifmr->ifm_active = IFM_ETHER|IFM_100_T4; - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX; - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX; - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX; - } else if (advert & PHY_ANAR_10BTHALF && - ability & PHY_ANAR_10BTHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX; - } - - return; -} - -static int mx_ioctl(ifp, command, data) - struct ifnet *ifp; - u_long command; - caddr_t data; -{ - struct mx_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; - int s, error = 0; - - s = splimp(); - - switch(command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; - case SIOCSIFFLAGS: - if (ifp->if_flags & IFF_UP) { - mx_init(sc); - } else { - if (ifp->if_flags & IFF_RUNNING) - mx_stop(sc); - } - error = 0; - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - mx_init(sc); - error = 0; - break; - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); - break; - default: - error = EINVAL; - break; - } - - (void)splx(s); - - return(error); -} - -static void mx_watchdog(ifp) - struct ifnet *ifp; -{ - struct mx_softc *sc; - - sc = ifp->if_softc; - - if (sc->mx_autoneg) { - if (sc->mx_type == MX_TYPE_98713 && sc->mx_pinfo != NULL) - mx_autoneg_mii(sc, MX_FLAG_DELAYTIMEO, 1); - else - mx_autoneg(sc, MX_FLAG_DELAYTIMEO, 1); - return; - } - - ifp->if_oerrors++; - printf("mx%d: watchdog timeout\n", sc->mx_unit); - - if (sc->mx_pinfo == NULL) { - if (!(CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_LS10) || - !(CSR_READ_4(sc, MX_10BTSTAT) & MX_TSTAT_LS100)) - printf("mx%d: no carrier - transceiver " - "cable problem?\n", sc->mx_unit); - } else { - if (!(mx_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) - printf("mx%d: no carrier - transceiver " - "cable problem?\n", sc->mx_unit); - } - - mx_stop(sc); - mx_reset(sc); - mx_init(sc); - - if (ifp->if_snd.ifq_head != NULL) - mx_start(ifp); - - return; -} - -/* - * Stop the adapter and free any mbufs allocated to the - * RX and TX lists. - */ -static void mx_stop(sc) - struct mx_softc *sc; -{ - register int i; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - ifp->if_timer = 0; - - MX_CLRBIT(sc, MX_NETCFG, (MX_NETCFG_RX_ON|MX_NETCFG_TX_ON)); - CSR_WRITE_4(sc, MX_IMR, 0x00000000); - CSR_WRITE_4(sc, MX_TXADDR, 0x00000000); - CSR_WRITE_4(sc, MX_RXADDR, 0x00000000); - - /* - * Free data in the RX lists. - */ - for (i = 0; i < MX_RX_LIST_CNT; i++) { - if (sc->mx_cdata.mx_rx_chain[i].mx_mbuf != NULL) { - m_freem(sc->mx_cdata.mx_rx_chain[i].mx_mbuf); - sc->mx_cdata.mx_rx_chain[i].mx_mbuf = NULL; - } - } - bzero((char *)&sc->mx_ldata->mx_rx_list, - sizeof(sc->mx_ldata->mx_rx_list)); - - /* - * Free the TX list buffers. - */ - for (i = 0; i < MX_TX_LIST_CNT; i++) { - if (sc->mx_cdata.mx_tx_chain[i].mx_mbuf != NULL) { - m_freem(sc->mx_cdata.mx_tx_chain[i].mx_mbuf); - sc->mx_cdata.mx_tx_chain[i].mx_mbuf = NULL; - } - } - - bzero((char *)&sc->mx_ldata->mx_tx_list, - sizeof(sc->mx_ldata->mx_tx_list)); - - ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - - return; -} - -/* - * Stop all chip I/O so that the kernel's probe routines don't - * get confused by errant DMAs when rebooting. - */ -static void mx_shutdown(howto, arg) - int howto; - void *arg; -{ - struct mx_softc *sc = (struct mx_softc *)arg; - - mx_stop(sc); - - return; -} - -static struct pci_device mx_device = { - "mx", - mx_probe, - mx_attach, - &mx_count, - NULL -}; -DATA_SET(pcidevice_set, mx_device); diff --git a/sys/pci/if_mxreg.h b/sys/pci/if_mxreg.h deleted file mode 100644 index 8a6d0a85fe01..000000000000 --- a/sys/pci/if_mxreg.h +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright (c) 1997, 1998 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_mxreg.h,v 1.12 1998/12/04 21:34:33 wpaul Exp $ - */ - -/* - * Macronix register definitions. - */ - -#define MX_BUSCTL 0x00 /* bus control */ -#define MX_TXSTART 0x08 /* tx start demand */ -#define MX_RXSTART 0x10 /* rx start demand */ -#define MX_RXADDR 0x18 /* rx descriptor list start addr */ -#define MX_TXADDR 0x20 /* tx descriptor list start addr */ -#define MX_ISR 0x28 /* interrupt status register */ -#define MX_NETCFG 0x30 /* network config register */ -#define MX_IMR 0x38 /* interrupt mask */ -#define MX_FRAMESDISCARDED 0x40 /* # of discarded frames */ -#define MX_SIO 0x48 /* MII and ROM/EEPROM access */ -#define MX_RESERVED 0x50 -#define MX_TIMER 0x58 /* general timer */ -#define MX_10BTSTAT 0x60 -#define MX_SIARESET 0x68 -#define MX_10BTCTRL 0x70 -#define MX_WATCHDOG 0x78 -#define MX_MAGICPACKET 0x80 -#define MX_NWAYSTAT 0xA0 - -/* - * These are magic values that must be written into CSR16 - * (MX_MAGICPACKET) in order to put the chip into proper - * operating mode. The magic numbers are documented in the - * Macronix 98715 application notes. - */ -#define MX_MAGIC_98713 0x0F370000 -#define MX_MAGIC_98713A 0x0B3C0000 -#define MX_MAGIC_98715 0x0B3C0000 -#define MX_MAGIC_98725 0x0B3C0000 - -#define MX_REVISION_98713 0x00 -#define MX_REVISION_98713A 0x10 -#define MX_REVISION_98715 0x20 -#define MX_REVISION_98725 0x30 - -/* - * As far as the driver is concerned, there are two 'types' of - * chips to be concerned with. One is a 98713 with an external - * PHY on the MII. The other covers pretty much everything else, - * since all the other Macronix chips have built-in transceivers. - * This type setting governs what which mode selection routines - * we use (MII or built-in). It also govers which of the 'magic' - * numbers we write into CSR16. - */ -#define MX_TYPE_98713 0x1 -#define MX_TYPE_98713A 0x2 -#define MX_TYPE_987x5 0x3 - -/* - * Bus control bits. - */ -#define MX_BUSCTL_RESET 0x00000001 -#define MX_BUSCTL_ARBITRATION 0x00000002 -#define MX_BUSCTL_SKIPLEN 0x0000007C -#define MX_BUSCTL_BUF_BIGENDIAN 0x00000080 -#define MX_BUSCTL_BURSTLEN 0x00003F00 -#define MX_BUSCTL_CACHEALIGN 0x0000C000 -#define MX_BUSCTL_XMITPOLL 0x00060000 - -#define MX_SKIPLEN_1LONG 0x00000004 -#define MX_SKIPLEN_2LONG 0x00000008 -#define MX_SKIPLEN_3LONG 0x00000010 -#define MX_SKIPLEN_4LONG 0x00000020 -#define MX_SKIPLEN_5LONG 0x00000040 - -#define MX_CACHEALIGN_8LONG 0x00004000 -#define MX_CACHEALIGN_16LONG 0x00008000 -#define MX_CACHEALIGN_32LONG 0x0000C000 - -#define MX_BURSTLEN_USECA 0x00000000 -#define MX_BURSTLEN_1LONG 0x00000100 -#define MX_BURSTLEN_2LONG 0x00000200 -#define MX_BURSTLEN_4LONG 0x00000400 -#define MX_BURSTLEN_8LONG 0x00000800 -#define MX_BURSTLEN_16LONG 0x00001000 -#define MX_BURSTLEN_32LONG 0x00002000 - -#define MX_TXPOLL_OFF 0x00000000 -#define MX_TXPOLL_200U 0x00020000 -#define MX_TXPOLL_800U 0x00040000 -#define MX_TXPOLL_1600U 0x00060000 - -#define MX_BUSCTL_CONFIG (MX_BUSCTL_ARBITRATION|MX_CACHEALIGN_8LONG| \ - MX_BURSTLEN_8LONG) - -/* - * Interrupt status bits. - */ -#define MX_ISR_TX_OK 0x00000001 -#define MX_ISR_TX_IDLE 0x00000002 -#define MX_ISR_TX_NOBUF 0x00000004 -#define MX_ISR_TX_JABBERTIMEO 0x00000008 -#define MX_ISR_LINKGOOD 0x00000010 -#define MX_ISR_TX_UNDERRUN 0x00000020 -#define MX_ISR_RX_OK 0x00000040 -#define MX_ISR_RX_NOBUF 0x00000080 -#define MX_ISR_RX_READ 0x00000100 -#define MX_ISR_RX_WATDOGTIMEO 0x00000200 -#define MX_ISR_TX_EARLY 0x00000400 -#define MX_ISR_TIMER_EXPIRED 0x00000800 -#define MX_ISR_LINKFAIL 0x00001000 -#define MX_ISR_BUS_ERR 0x00002000 -#define MX_ISR_RX_EARLY 0x00004000 -#define MX_ISR_ABNORMAL 0x00008000 -#define MX_ISR_NORMAL 0x00010000 -#define MX_ISR_RX_STATE 0x000E0000 -#define MX_ISR_TX_STATE 0x00700000 -#define MX_ISR_BUSERRTYPE 0x03800000 -#define MX_ISR_100MBPSLINK 0x08000000 -#define MX_ISR_MAGICKPACK 0x10000000 - -#define MX_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */ -#define MX_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */ -#define MX_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */ -#define MX_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */ -#define MX_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */ -#define MX_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */ -#define MX_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */ -#define MX_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */ - -#define MX_TXSTATE_RESET 0x00000000 /* 000 - reset */ -#define MX_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */ -#define MX_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */ -#define MX_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */ -#define MX_TXSTATE_RSVD 0x00400000 /* 100 - reserved */ -#define MX_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */ -#define MX_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */ -#define MX_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */ - -/* - * Network config bits. - */ -#define MX_NETCFG_RX_HASHPERF 0x00000001 -#define MX_NETCFG_RX_ON 0x00000002 -#define MX_NETCFG_RX_HASHONLY 0x00000004 -#define MX_NETCFG_RX_BADFRAMES 0x00000008 -#define MX_NETCFG_RX_INVFILT 0x00000010 -#define MX_NETCFG_BACKOFFCNT 0x00000020 -#define MX_NETCFG_RX_PROMISC 0x00000040 -#define MX_NETCFG_RX_ALLMULTI 0x00000080 -#define MX_NETCFG_FULLDUPLEX 0x00000200 -#define MX_NETCFG_LOOPBACK 0x00000C00 -#define MX_NETCFG_FORCECOLL 0x00001000 -#define MX_NETCFG_TX_ON 0x00002000 -#define MX_NETCFG_TX_THRESH 0x0000C000 -#define MX_NETCFG_TX_BACKOFF 0x00020000 -#define MX_NETCFG_PORTSEL 0x00040000 /* 0 == 10, 1 == 100 */ -#define MX_NETCFG_HEARTBEAT 0x00080000 -#define MX_NETCFG_STORENFWD 0x00200000 -#define MX_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10, 0 == 100 */ -#define MX_NETCFG_PCS 0x00800000 -#define MX_NETCFG_SCRAMBLER 0x01000000 -#define MX_NETCFG_NO_RXCRC 0x02000000 - -#define MX_OPMODE_NORM 0x00000000 -#define MX_OPMODE_INTLOOP 0x00000400 -#define MX_OPMODE_EXTLOOP 0x00000800 - -#define MX_TXTHRESH_72BYTES 0x00000000 -#define MX_TXTHRESH_96BYTES 0x00004000 -#define MX_TXTHRESH_128BYTES 0x00008000 -#define MX_TXTHRESH_160BYTES 0x0000C000 - - -/* - * Interrupt mask bits. - */ -#define MX_IMR_TX_OK 0x00000001 -#define MX_IMR_TX_IDLE 0x00000002 -#define MX_IMR_TX_NOBUF 0x00000004 -#define MX_IMR_TX_JABBERTIMEO 0x00000008 -#define MX_IMR_LINKGOOD 0x00000010 -#define MX_IMR_TX_UNDERRUN 0x00000020 -#define MX_IMR_RX_OK 0x00000040 -#define MX_IMR_RX_NOBUF 0x00000080 -#define MX_IMR_RX_READ 0x00000100 -#define MX_IMR_RX_WATDOGTIMEO 0x00000200 -#define MX_IMR_TX_EARLY 0x00000400 -#define MX_IMR_TIMER_EXPIRED 0x00000800 -#define MX_IMR_LINKFAIL 0x00001000 -#define MX_IMR_BUS_ERR 0x00002000 -#define MX_IMR_RX_EARLY 0x00004000 -#define MX_IMR_ABNORMAL 0x00008000 -#define MX_IMR_NORMAL 0x00010000 -#define MX_IMR_100MBPSLINK 0x08000000 -#define MX_IMR_MAGICKPACK 0x10000000 - -#define MX_INTRS \ - (MX_IMR_RX_OK|MX_IMR_TX_OK|MX_IMR_RX_NOBUF|MX_IMR_RX_WATDOGTIMEO|\ - MX_IMR_TX_NOBUF|MX_IMR_TX_UNDERRUN|MX_IMR_BUS_ERR| \ - MX_IMR_ABNORMAL|MX_IMR_NORMAL/*|MX_IMR_TX_EARLY*/) -/* - * Serial I/O (EEPROM/ROM) bits. - */ -#define MX_SIO_EE_CS 0x00000001 /* EEPROM chip select */ -#define MX_SIO_EE_CLK 0x00000002 /* EEPROM clock */ -#define MX_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */ -#define MX_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */ -#define MX_SIO_ROMDATA4 0x00000010 -#define MX_SIO_ROMDATA5 0x00000020 -#define MX_SIO_ROMDATA6 0x00000040 -#define MX_SIO_ROMDATA7 0x00000080 -#define MX_SIO_EESEL 0x00000800 -#define MX_SIO_ROMSEL 0x00001000 -#define MX_SIO_ROMCTL_WRITE 0x00002000 -#define MX_SIO_ROMCTL_READ 0x00004000 -#define MX_SIO_MII_CLK 0x00010000 /* MDIO clock */ -#define MX_SIO_MII_DATAOUT 0x00020000 /* MDIO data out */ -#define MX_SIO_MII_DIR 0x00040000 /* MDIO dir */ -#define MX_SIO_MII_DATAIN 0x00080000 /* MDIO data in */ - -#define MX_EECMD_WRITE 0x140 -#define MX_EECMD_READ 0x180 -#define MX_EECMD_ERASE 0x1c0 - -#define MX_EE_NODEADDR_OFFSET 0x70 -#define MX_EE_NODEADDR 10 - -/* - * General purpose timer register - */ -#define MX_TIMER_VALUE 0x0000FFFF -#define MX_TIMER_CONTINUUS 0x00010000 - -/* - * 10baseT status register - */ -#define MX_TSTAT_LS100 0x00000002 /* link status of 100baseTX */ -#define MX_TSTAT_LS10 0x00000004 /* link status of 10baseT */ -#define MX_TSTAT_AUTOPOLARITY 0x00000008 -#define MX_TSTAT_REMFAULT 0x00000800 -#define MX_TSTAT_ANEGSTAT 0x00007000 -#define MX_TSTAT_LP_CAN_NWAY 0x00008000 /* link partner supports NWAY */ -#define MX_TSTAT_LPCODEWORD 0xFFFF0000 /* link partner's code word */ - -#define MX_ASTAT_DISABLE 0x00000000 -#define MX_ASTAT_TXDISABLE 0x00001000 -#define MX_ASTAT_ABDETECT 0x00002000 -#define MX_ASTAT_ACKDETECT 0x00003000 -#define MX_ASTAT_CMPACKDETECT 0x00004000 -#define MX_ASTAT_AUTONEGCMP 0x00005000 -#define MX_ASTAT_LINKCHECK 0x00006000 - -/* - * PHY reset register - */ -#define MX_SIA_RESET_NWAY 0x00000001 -#define MX_SIA_RESET_100TX 0x00000002 - -/* - * 10baseT control register - */ -#define MX_TCTL_LOOPBACK 0x00000002 -#define MX_TCTL_POWERDOWN 0x00000004 -#define MX_TCTL_HALFDUPLEX 0x00000040 -#define MX_TCTL_AUTONEGENBL 0x00000080 -#define MX_TCTL_RX_SQUELCH 0x00000100 -#define MX_TCTL_LINKTEST 0x00001000 -#define MX_TCTL_100BTXHALF 0x00010000 -#define MX_TCTL_100BTXFULL 0x00020000 -#define MX_TCTL_100BT4 0x00040000 - -/* - * Watchdog timer register - */ -#define MX_WDOG_JABBERDIS 0x00000001 -#define MX_WDOG_HOSTUNJAB 0x00000002 -#define MX_WDOG_JABBERCLK 0x00000004 -#define MX_WDOG_RXWDOGDIS 0x00000010 -#define MX_WDOG_RXWDOGCLK 0x00000020 -#define MX_WDOG_MUSTBEZERO 0x00000100 - -/* - * Magic packet register - */ -#define MX_MPACK_DISABLE 0x00400000 - -/* - * NWAY status register. - */ -#define MX_NWAY_10BTHALF 0x08000000 -#define MX_NWAY_10BTFULL 0x10000000 -#define MX_NWAY_100BTHALF 0x20000000 -#define MX_NWAY_100BTFULL 0x40000000 -#define MX_NWAY_100BT4 0x80000000 - -/* - * Size of a setup frame. - */ -#define MX_SFRAME_LEN 192 - -/* - * Macronix TX/RX list structure. - */ - -struct mx_desc { - volatile u_int32_t mx_status; - volatile u_int32_t mx_ctl; - volatile u_int32_t mx_ptr1; - volatile u_int32_t mx_ptr2; -}; - -#define mx_data mx_ptr1 -#define mx_next mx_ptr2 - -#define MX_RXSTAT_FIFOOFLOW 0x00000001 -#define MX_RXSTAT_CRCERR 0x00000002 -#define MX_RXSTAT_DRIBBLE 0x00000004 -#define MX_RXSTAT_WATCHDOG 0x00000010 -#define MX_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */ -#define MX_RXSTAT_COLLSEEN 0x00000040 -#define MX_RXSTAT_GIANT 0x00000080 -#define MX_RXSTAT_LASTFRAG 0x00000100 -#define MX_RXSTAT_FIRSTFRAG 0x00000200 -#define MX_RXSTAT_MULTICAST 0x00000400 -#define MX_RXSTAT_RUNT 0x00000800 -#define MX_RXSTAT_RXTYPE 0x00003000 -#define MX_RXSTAT_RXERR 0x00008000 -#define MX_RXSTAT_RXLEN 0x3FFF0000 -#define MX_RXSTAT_OWN 0x80000000 - -#define MX_RXBYTES(x) ((x & MX_RXSTAT_RXLEN) >> 16) -#define MX_RXSTAT (MX_RXSTAT_FIRSTFRAG|MX_RXSTAT_LASTFRAG|MX_RXSTAT_OWN) - -#define MX_RXCTL_BUFLEN1 0x00000FFF -#define MX_RXCTL_BUFLEN2 0x00FFF000 -#define MX_RXCTL_RLINK 0x01000000 -#define MX_RXCTL_RLAST 0x02000000 - -#define MX_TXSTAT_DEFER 0x00000001 -#define MX_TXSTAT_UNDERRUN 0x00000002 -#define MX_TXSTAT_LINKFAIl 0x00000003 -#define MX_TXSTAT_COLLCNT 0x00000078 -#define MX_TXSTAT_SQE 0x00000080 -#define MX_TXSTAT_EXCESSCOLL 0x00000100 -#define MX_TXSTAT_LATECOLL 0x00000200 -#define MX_TXSTAT_NOCARRIER 0x00000400 -#define MX_TXSTAT_CARRLOST 0x00000800 -#define MX_TXSTAT_JABTIMEO 0x00004000 -#define MX_TXSTAT_ERRSUM 0x00008000 -#define MX_TXSTAT_OWN 0x80000000 - -#define MX_TXCTL_BUFLEN1 0x000007FF -#define MX_TXCTL_BUFLEN2 0x003FF800 -#define MX_TXCTL_FILTTYPE0 0x00400000 -#define MX_TXCTL_PAD 0x00800000 -#define MX_TXCTL_TLINK 0x01000000 -#define MX_TXCTL_TLAST 0x02000000 -#define MX_TXCTL_NOCRC 0x04000000 -#define MX_TXCTL_SETUP 0x08000000 -#define MX_TXCTL_FILTTYPE1 0x10000000 -#define MX_TXCTL_FIRSTFRAG 0x20000000 -#define MX_TXCTL_LASTFRAG 0x40000000 -#define MX_TXCTL_FINT 0x80000000 - -#define MX_FILTER_PERFECT 0x00000000 -#define MX_FILTER_HASHPERF 0x00400000 -#define MX_FILTER_INVERSE 0x10000000 -#define MX_FILTER_HASHONLY 0x10400000 - -#define MX_MAXFRAGS 16 -#define MX_RX_LIST_CNT 64 -#define MX_TX_LIST_CNT 64 -#define MX_MIN_FRAMELEN 60 - -/* - * A tx 'super descriptor' is actually 16 regular descriptors - * back to back. - */ -struct mx_txdesc { - volatile struct mx_desc mx_frag[MX_MAXFRAGS]; -}; - -#define MX_TXNEXT(x) x->mx_ptr->mx_frag[x->mx_lastdesc].mx_next -#define MX_TXSTATUS(x) x->mx_ptr->mx_frag[x->mx_lastdesc].mx_status -#define MX_TXCTL(x) x->mx_ptr->mx_frag[x->mx_lastdesc].mx_ctl -#define MX_TXDATA(x) x->mx_ptr->mx_frag[x->mx_lastdesc].mx_data - -#define MX_TXOWN(x) x->mx_ptr->mx_frag[0].mx_status - -#define MX_UNSENT 0x12341234 - -struct mx_list_data { - volatile struct mx_desc mx_rx_list[MX_RX_LIST_CNT]; - volatile struct mx_txdesc mx_tx_list[MX_TX_LIST_CNT]; -}; - -struct mx_chain { - volatile struct mx_txdesc *mx_ptr; - struct mbuf *mx_mbuf; - struct mx_chain *mx_nextdesc; - u_int8_t mx_lastdesc; -}; - -struct mx_chain_onefrag { - volatile struct mx_desc *mx_ptr; - struct mbuf *mx_mbuf; - struct mx_chain_onefrag *mx_nextdesc; -}; - -struct mx_chain_data { - struct mx_desc mx_sframe; - u_int32_t mx_sbuf[MX_SFRAME_LEN/sizeof(u_int32_t)]; - u_int8_t mx_pad[MX_MIN_FRAMELEN]; - struct mx_chain_onefrag mx_rx_chain[MX_RX_LIST_CNT]; - struct mx_chain mx_tx_chain[MX_TX_LIST_CNT]; - - struct mx_chain_onefrag *mx_rx_head; - - struct mx_chain *mx_tx_head; - struct mx_chain *mx_tx_tail; - struct mx_chain *mx_tx_free; -}; - -struct mx_type { - u_int16_t mx_vid; - u_int16_t mx_did; - char *mx_name; -}; - -struct mx_mii_frame { - u_int8_t mii_stdelim; - u_int8_t mii_opcode; - u_int8_t mii_phyaddr; - u_int8_t mii_regaddr; - u_int8_t mii_turnaround; - u_int16_t mii_data; -}; - -/* - * MII constants - */ -#define MX_MII_STARTDELIM 0x01 -#define MX_MII_READOP 0x02 -#define MX_MII_WRITEOP 0x01 -#define MX_MII_TURNAROUND 0x02 - -#define MX_FLAG_FORCEDELAY 1 -#define MX_FLAG_SCHEDDELAY 2 -#define MX_FLAG_DELAYTIMEO 3 - -struct mx_softc { - struct arpcom arpcom; /* interface info */ - struct ifmedia ifmedia; /* media info */ - bus_space_handle_t mx_bhandle; /* bus space handle */ - bus_space_tag_t mx_btag; /* bus space tag */ - struct mx_type *mx_info; /* Macronix adapter info */ - struct mx_type *mx_pinfo; /* phy info */ - u_int8_t mx_unit; /* interface number */ - u_int8_t mx_type; - u_int8_t mx_phy_addr; /* PHY address */ - u_int8_t mx_tx_pend; /* TX pending */ - u_int8_t mx_want_auto; - u_int8_t mx_autoneg; - u_int8_t mx_singlebuf; - caddr_t mx_ldata_ptr; - struct mx_list_data *mx_ldata; - struct mx_chain_data mx_cdata; -}; - -/* - * register space access macros - */ -#define CSR_WRITE_4(sc, reg, val) \ - bus_space_write_4(sc->mx_btag, sc->mx_bhandle, reg, val) -#define CSR_WRITE_2(sc, reg, val) \ - bus_space_write_2(sc->mx_btag, sc->mx_bbhandle, reg, val) -#define CSR_WRITE_1(sc, reg, val) \ - bus_space_write_1(sc->mx_btag, sc->mx_bhandle, reg, val) - -#define CSR_READ_4(sc, reg) \ - bus_space_read_4(sc->mx_btag, sc->mx_bhandle, reg) -#define CSR_READ_2(sc, reg) \ - bus_space_read_2(sc->mx_btag, sc->mx_bhandle, reg) -#define CSR_READ_1(sc, reg) \ - bus_space_read_1(sc->mx_btag, sc->mx_bhandle, reg) - -#define MX_TIMEOUT 1000 - -/* - * General constants that are fun to know. - * - * Macronix PCI vendor ID - */ -#define MX_VENDORID 0x10D9 - -/* - * Macronix PMAC device IDs. - */ -#define MX_DEVICEID_98713 0x0512 -#define MX_DEVICEID_987x5 0x0531 - -/* - * Texas Instruments PHY identifiers - */ -#define TI_PHY_VENDORID 0x4000 -#define TI_PHY_10BT 0x501F -#define TI_PHY_100VGPMI 0x502F - -/* - * These ID values are for the NS DP83840A 10/100 PHY - */ -#define NS_PHY_VENDORID 0x2000 -#define NS_PHY_83840A 0x5C0F - -/* - * Level 1 10/100 PHY - */ -#define LEVEL1_PHY_VENDORID 0x7810 -#define LEVEL1_PHY_LXT970 0x000F - -/* - * Intel 82555 10/100 PHY - */ -#define INTEL_PHY_VENDORID 0x0A28 -#define INTEL_PHY_82555 0x015F - -/* - * SEEQ 80220 10/100 PHY - */ -#define SEEQ_PHY_VENDORID 0x0016 -#define SEEQ_PHY_80220 0xF83F - - -/* - * PCI low memory base and low I/O base register, and - * other PCI registers. - */ - -#define MX_PCI_VENDOR_ID 0x00 -#define MX_PCI_DEVICE_ID 0x02 -#define MX_PCI_COMMAND 0x04 -#define MX_PCI_STATUS 0x06 -#define MX_PCI_REVID 0x08 -#define MX_PCI_CLASSCODE 0x09 -#define MX_PCI_LATENCY_TIMER 0x0D -#define MX_PCI_HEADER_TYPE 0x0E -#define MX_PCI_LOIO 0x10 -#define MX_PCI_LOMEM 0x14 -#define MX_PCI_BIOSROM 0x30 -#define MX_PCI_INTLINE 0x3C -#define MX_PCI_INTPIN 0x3D -#define MX_PCI_MINGNT 0x3E -#define MX_PCI_MINLAT 0x0F -#define MX_PCI_RESETOPT 0x48 -#define MX_PCI_EEPROM_DATA 0x4C - -/* power management registers */ -#define MX_PCI_CAPID 0x44 /* 8 bits */ -#define MX_PCI_NEXTPTR 0x45 /* 8 bits */ -#define MX_PCI_PWRMGMTCAP 0x46 /* 16 bits */ -#define MX_PCI_PWRMGMTCTRL 0x48 /* 16 bits */ - -#define MX_PSTATE_MASK 0x0003 -#define MX_PSTATE_D0 0x0000 -#define MX_PSTATE_D1 0x0001 -#define MX_PSTATE_D2 0x0002 -#define MX_PSTATE_D3 0x0003 -#define MX_PME_EN 0x0010 -#define MX_PME_STATUS 0x8000 - -#define PHY_UNKNOWN 6 - -#define MX_PHYADDR_MIN 0x00 -#define MX_PHYADDR_MAX 0x1F - -#define PHY_BMCR 0x00 -#define PHY_BMSR 0x01 -#define PHY_VENID 0x02 -#define PHY_DEVID 0x03 -#define PHY_ANAR 0x04 -#define PHY_LPAR 0x05 -#define PHY_ANEXP 0x06 - -#define PHY_ANAR_NEXTPAGE 0x8000 -#define PHY_ANAR_RSVD0 0x4000 -#define PHY_ANAR_TLRFLT 0x2000 -#define PHY_ANAR_RSVD1 0x1000 -#define PHY_ANAR_RSVD2 0x0800 -#define PHY_ANAR_RSVD3 0x0400 -#define PHY_ANAR_100BT4 0x0200 -#define PHY_ANAR_100BTXFULL 0x0100 -#define PHY_ANAR_100BTXHALF 0x0080 -#define PHY_ANAR_10BTFULL 0x0040 -#define PHY_ANAR_10BTHALF 0x0020 -#define PHY_ANAR_PROTO4 0x0010 -#define PHY_ANAR_PROTO3 0x0008 -#define PHY_ANAR_PROTO2 0x0004 -#define PHY_ANAR_PROTO1 0x0002 -#define PHY_ANAR_PROTO0 0x0001 - -/* - * These are the register definitions for the PHY (physical layer - * interface chip). - */ -/* - * PHY BMCR Basic Mode Control Register - */ -#define PHY_BMCR_RESET 0x8000 -#define PHY_BMCR_LOOPBK 0x4000 -#define PHY_BMCR_SPEEDSEL 0x2000 -#define PHY_BMCR_AUTONEGENBL 0x1000 -#define PHY_BMCR_RSVD0 0x0800 /* write as zero */ -#define PHY_BMCR_ISOLATE 0x0400 -#define PHY_BMCR_AUTONEGRSTR 0x0200 -#define PHY_BMCR_DUPLEX 0x0100 -#define PHY_BMCR_COLLTEST 0x0080 -#define PHY_BMCR_RSVD1 0x0040 /* write as zero, don't care */ -#define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */ -#define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */ -#define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */ -#define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */ -#define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */ -#define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */ -/* - * RESET: 1 == software reset, 0 == normal operation - * Resets status and control registers to default values. - * Relatches all hardware config values. - * - * LOOPBK: 1 == loopback operation enabled, 0 == normal operation - * - * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s - * Link speed is selected byt his bit or if auto-negotiation if bit - * 12 (AUTONEGENBL) is set (in which case the value of this register - * is ignored). - * - * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled - * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13 - * determine speed and mode. Should be cleared and then set if PHY configured - * for no autoneg on startup. - * - * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation - * - * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation - * - * DUPLEX: 1 == full duplex mode, 0 == half duplex mode - * - * COLLTEST: 1 == collision test enabled, 0 == normal operation - */ - -/* - * PHY, BMSR Basic Mode Status Register - */ -#define PHY_BMSR_100BT4 0x8000 -#define PHY_BMSR_100BTXFULL 0x4000 -#define PHY_BMSR_100BTXHALF 0x2000 -#define PHY_BMSR_10BTFULL 0x1000 -#define PHY_BMSR_10BTHALF 0x0800 -#define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */ -#define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */ -#define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */ -#define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */ -#define PHY_BMSR_MFPRESUP 0x0040 -#define PHY_BMSR_AUTONEGCOMP 0x0020 -#define PHY_BMSR_REMFAULT 0x0010 -#define PHY_BMSR_CANAUTONEG 0x0008 -#define PHY_BMSR_LINKSTAT 0x0004 -#define PHY_BMSR_JABBER 0x0002 -#define PHY_BMSR_EXTENDED 0x0001 diff --git a/sys/pci/if_pn.c b/sys/pci/if_pn.c deleted file mode 100644 index bc413c734a33..000000000000 --- a/sys/pci/if_pn.c +++ /dev/null @@ -1,1986 +0,0 @@ -/* - * Copyright (c) 1997, 1998 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_pn.c,v 1.36 1999/01/05 00:47:25 wpaul Exp $ - */ - -/* - * 82c168/82c169 PNIC fast ethernet PCI NIC driver - * - * Supports various network adapters based on the Lite-On PNIC - * PCI network controller chip including the LinkSys LNE100TX. - * - * Written by Bill Paul <wpaul@ctr.columbia.edu> - * Electrical Engineering Department - * Columbia University, New York City - */ - -/* - * The PNIC chip is a DEC tulip clone. This driver uses much of the - * same code from the driver for the Winbond chip (which is also a - * tulip clone) except for the MII, EEPROM and filter programming. - * - * Technically we could merge support for this chip into the 'de' - * driver, but it's such a mess that I'm afraid to go near it. - * - * The PNIC appears to support both an external MII and an internal - * transceiver. I think most 100Mbps implementations use a PHY attached - * the the MII. The LinkSys board that I have uses a Myson MTD972 - * 100BaseTX PHY. - */ - -#include "bpfilter.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/if_arp.h> -#include <net/ethernet.h> -#include <net/if_dl.h> -#include <net/if_media.h> - -#if NBPFILTER > 0 -#include <net/bpf.h> -#endif - -#include <vm/vm.h> /* for vtophys */ -#include <vm/pmap.h> /* for vtophys */ -#include <machine/clock.h> /* for DELAY */ -#include <machine/bus_pio.h> -#include <machine/bus_memio.h> -#include <machine/bus.h> - -#include <pci/pcireg.h> -#include <pci/pcivar.h> - -#define PN_USEIOSPACE - -/* #define PN_BACKGROUND_AUTONEG */ - -#define PN_PROMISC_BUG_WAR - -#include <pci/if_pnreg.h> - -#ifndef lint -static const char rcsid[] = - "$Id: if_pn.c,v 1.36 1999/01/05 00:47:25 wpaul Exp $"; -#endif - -/* - * Various supported device vendors/types and their names. - */ -static struct pn_type pn_devs[] = { - { PN_VENDORID, PN_DEVICEID_PNIC, - "82c168/82c169 PNIC 10/100BaseTX" }, - { 0, 0, NULL } -}; - -/* - * Various supported PHY vendors/types and their names. Note that - * this driver will work with pretty much any MII-compliant PHY, - * so failure to positively identify the chip is not a fatal error. - */ - -static struct pn_type pn_phys[] = { - { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, - { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, - { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, - { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, - { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, - { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, - { 0, 0, "<MII-compliant physical interface>" } -}; - -static unsigned long pn_count = 0; -static const char *pn_probe __P((pcici_t, pcidi_t)); -static void pn_attach __P((pcici_t, int)); - -static int pn_newbuf __P((struct pn_softc *, - struct pn_chain_onefrag *)); -static int pn_encap __P((struct pn_softc *, struct pn_chain *, - struct mbuf *)); - -#ifdef PN_PROMISC_BUG_WAR -static void pn_promisc_bug_war __P((struct pn_softc *, - struct pn_chain_onefrag *)); -#endif -static void pn_rxeof __P((struct pn_softc *)); -static void pn_rxeoc __P((struct pn_softc *)); -static void pn_txeof __P((struct pn_softc *)); -static void pn_txeoc __P((struct pn_softc *)); -static void pn_intr __P((void *)); -static void pn_start __P((struct ifnet *)); -static int pn_ioctl __P((struct ifnet *, u_long, caddr_t)); -static void pn_init __P((void *)); -static void pn_stop __P((struct pn_softc *)); -static void pn_watchdog __P((struct ifnet *)); -static void pn_shutdown __P((int, void *)); -static int pn_ifmedia_upd __P((struct ifnet *)); -static void pn_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); - -static void pn_eeprom_getword __P((struct pn_softc *, u_int8_t, u_int16_t *)); -static void pn_read_eeprom __P((struct pn_softc *, caddr_t, int, - int, int)); -static u_int16_t pn_phy_readreg __P((struct pn_softc *, int)); -static void pn_phy_writereg __P((struct pn_softc *, u_int16_t, u_int16_t)); - -static void pn_autoneg_xmit __P((struct pn_softc *)); -static void pn_autoneg_mii __P((struct pn_softc *, int, int)); -static void pn_setmode_mii __P((struct pn_softc *, int)); -static void pn_getmode_mii __P((struct pn_softc *)); -static void pn_setcfg __P((struct pn_softc *, u_int16_t)); -static u_int32_t pn_calchash __P((u_int8_t *)); -static void pn_setfilt __P((struct pn_softc *)); -static void pn_reset __P((struct pn_softc *)); -static int pn_list_rx_init __P((struct pn_softc *)); -static int pn_list_tx_init __P((struct pn_softc *)); - -#define PN_SETBIT(sc, reg, x) \ - CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) | x) - -#define PN_CLRBIT(sc, reg, x) \ - CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) & ~x) - -/* - * Read a word of data stored in the EEPROM at address 'addr.' - */ -static void pn_eeprom_getword(sc, addr, dest) - struct pn_softc *sc; - u_int8_t addr; - u_int16_t *dest; -{ - register int i; - u_int32_t r; - - CSR_WRITE_4(sc, PN_SIOCTL, PN_EE_READ|addr); - - for (i = 0; i < PN_TIMEOUT; i++) { - DELAY(1); - r = CSR_READ_4(sc, PN_SIO); - if (!(r & PN_SIO_BUSY)) { - *dest = (u_int16_t)(r & 0x0000FFFF); - return; - } - } - - return; - -} - -/* - * Read a sequence of words from the EEPROM. - */ -static void pn_read_eeprom(sc, dest, off, cnt, swap) - struct pn_softc *sc; - caddr_t dest; - int off; - int cnt; - int swap; -{ - int i; - u_int16_t word = 0, *ptr; - - for (i = 0; i < cnt; i++) { - pn_eeprom_getword(sc, off + i, &word); - ptr = (u_int16_t *)(dest + (i * 2)); - if (swap) - *ptr = ntohs(word); - else - *ptr = word; - } - - return; -} - -static u_int16_t pn_phy_readreg(sc, reg) - struct pn_softc *sc; - int reg; -{ - int i; - u_int32_t rval; - - CSR_WRITE_4(sc, PN_MII, - PN_MII_READ | (sc->pn_phy_addr << 23) | (reg << 18)); - - for (i = 0; i < PN_TIMEOUT; i++) { - DELAY(1); - rval = CSR_READ_4(sc, PN_MII); - if (!(rval & PN_MII_BUSY)) { - if ((u_int16_t)(rval & 0x0000FFFF) == 0xFFFF) - return(0); - else - return((u_int16_t)(rval & 0x0000FFFF)); - } - } - - return(0); -} - -static void pn_phy_writereg(sc, reg, data) - struct pn_softc *sc; - u_int16_t reg; - u_int16_t data; -{ - int i; - - CSR_WRITE_4(sc, PN_MII, - PN_MII_WRITE | (sc->pn_phy_addr << 23) | (reg << 18) | data); - - - for (i = 0; i < PN_TIMEOUT; i++) { - if (!(CSR_READ_4(sc, PN_MII) & PN_MII_BUSY)) - break; - } - - return; -} - -#define PN_POLY 0xEDB88320 -#define PN_BITS 9 - -static u_int32_t pn_calchash(addr) - u_int8_t *addr; -{ - u_int32_t idx, bit, data, crc; - - /* Compute CRC for the address value. */ - crc = 0xFFFFFFFF; /* initial value */ - - for (idx = 0; idx < 6; idx++) { - for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) - crc = (crc >> 1) ^ (((crc ^ data) & 1) ? PN_POLY : 0); - } - - return (crc & ((1 << PN_BITS) - 1)); -} - -/* - * Initiate an autonegotiation session. - */ -static void pn_autoneg_xmit(sc) - struct pn_softc *sc; -{ - u_int16_t phy_sts; - - pn_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(pn_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - - phy_sts = pn_phy_readreg(sc, PHY_BMCR); - phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; - pn_phy_writereg(sc, PHY_BMCR, phy_sts); - - return; -} - -/* - * Invoke autonegotiation on a PHY. - */ -static void pn_autoneg_mii(sc, flag, verbose) - struct pn_softc *sc; - int flag; - int verbose; -{ - u_int16_t phy_sts = 0, media, advert, ability; - struct ifnet *ifp; - struct ifmedia *ifm; - - ifm = &sc->ifmedia; - ifp = &sc->arpcom.ac_if; - - ifm->ifm_media = IFM_ETHER | IFM_AUTO; - - /* - * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported' - * bit cleared in the status register, but has the 'autoneg enabled' - * bit set in the control register. This is a contradiction, and - * I'm not sure how to handle it. If you want to force an attempt - * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR - * and see what happens. - */ -#ifndef FORCE_AUTONEG_TFOUR - /* - * First, see if autoneg is supported. If not, there's - * no point in continuing. - */ - phy_sts = pn_phy_readreg(sc, PHY_BMSR); - if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { - if (verbose) - printf("pn%d: autonegotiation not supported\n", - sc->pn_unit); - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - return; - } -#endif - - switch (flag) { - case PN_FLAG_FORCEDELAY: - /* - * XXX Never use this option anywhere but in the probe - * routine: making the kernel stop dead in its tracks - * for three whole seconds after we've gone multi-user - * is really bad manners. - */ - pn_autoneg_xmit(sc); - DELAY(5000000); - break; - case PN_FLAG_SCHEDDELAY: - /* - * Wait for the transmitter to go idle before starting - * an autoneg session, otherwise pn_start() may clobber - * our timeout, and we don't want to allow transmission - * during an autoneg session since that can screw it up. - */ - if (sc->pn_cdata.pn_tx_head != NULL) { - sc->pn_want_auto = 1; - return; - } - pn_autoneg_xmit(sc); - ifp->if_timer = 5; - sc->pn_autoneg = 1; - sc->pn_want_auto = 0; - return; - break; - case PN_FLAG_DELAYTIMEO: - ifp->if_timer = 0; - sc->pn_autoneg = 0; - break; - default: - printf("pn%d: invalid autoneg flag: %d\n", sc->pn_unit, flag); - return; - } - - if (pn_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { - if (verbose) - printf("pn%d: autoneg complete, ", sc->pn_unit); - phy_sts = pn_phy_readreg(sc, PHY_BMSR); - } else { - if (verbose) - printf("pn%d: autoneg not complete, ", sc->pn_unit); - } - - media = pn_phy_readreg(sc, PHY_BMCR); - - /* Link is good. Report modes and set duplex mode. */ - if (pn_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { - if (verbose) - printf("link status good "); - advert = pn_phy_readreg(sc, PHY_ANAR); - ability = pn_phy_readreg(sc, PHY_LPAR); - - if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { - ifm->ifm_media = IFM_ETHER|IFM_100_T4; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(100baseT4)\n"); - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - media |= PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - media &= ~PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 10Mbps)\n"); - } else if (advert & PHY_ANAR_10BTHALF && - ability & PHY_ANAR_10BTHALF) { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - media &= ~PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 10Mbps)\n"); - } - - media &= ~PHY_BMCR_AUTONEGENBL; - - /* Set ASIC's duplex mode to match the PHY. */ - pn_setcfg(sc, media); - pn_phy_writereg(sc, PHY_BMCR, media); - } else { - if (verbose) - printf("no carrier\n"); - } - - pn_init(sc); - - if (sc->pn_tx_pend) { - sc->pn_autoneg = 0; - sc->pn_tx_pend = 0; - pn_start(ifp); - } - - return; -} - -static void pn_getmode_mii(sc) - struct pn_softc *sc; -{ - u_int16_t bmsr; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - bmsr = pn_phy_readreg(sc, PHY_BMSR); - if (bootverbose) - printf("pn%d: PHY status word: %x\n", sc->pn_unit, bmsr); - - /* fallback */ - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - - if (bmsr & PHY_BMSR_10BTHALF) { - if (bootverbose) - printf("pn%d: 10Mbps half-duplex mode supported\n", - sc->pn_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); - } - - if (bmsr & PHY_BMSR_10BTFULL) { - if (bootverbose) - printf("pn%d: 10Mbps full-duplex mode supported\n", - sc->pn_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - } - - if (bmsr & PHY_BMSR_100BTXHALF) { - if (bootverbose) - printf("pn%d: 100Mbps half-duplex mode supported\n", - sc->pn_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - } - - if (bmsr & PHY_BMSR_100BTXFULL) { - if (bootverbose) - printf("pn%d: 100Mbps full-duplex mode supported\n", - sc->pn_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - } - - /* Some also support 100BaseT4. */ - if (bmsr & PHY_BMSR_100BT4) { - if (bootverbose) - printf("pn%d: 100baseT4 mode supported\n", sc->pn_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4; -#ifdef FORCE_AUTONEG_TFOUR - if (bootverbose) - printf("pn%d: forcing on autoneg support for BT4\n", - sc->pn_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; -#endif - } - - if (bmsr & PHY_BMSR_CANAUTONEG) { - if (bootverbose) - printf("pn%d: autoneg supported\n", sc->pn_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; - } - - return; -} - -/* - * Set speed and duplex mode. - */ -static void pn_setmode_mii(sc, media) - struct pn_softc *sc; - int media; -{ - u_int16_t bmcr; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - /* - * If an autoneg session is in progress, stop it. - */ - if (sc->pn_autoneg) { - printf("pn%d: canceling autoneg session\n", sc->pn_unit); - ifp->if_timer = sc->pn_autoneg = sc->pn_want_auto = 0; - bmcr = pn_phy_readreg(sc, PHY_BMCR); - bmcr &= ~PHY_BMCR_AUTONEGENBL; - pn_phy_writereg(sc, PHY_BMCR, bmcr); - } - - printf("pn%d: selecting MII, ", sc->pn_unit); - - bmcr = pn_phy_readreg(sc, PHY_BMCR); - - bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL| - PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); - - if (IFM_SUBTYPE(media) == IFM_100_T4) { - printf("100Mbps/T4, half-duplex\n"); - bmcr |= PHY_BMCR_SPEEDSEL; - bmcr &= ~PHY_BMCR_DUPLEX; - } - - if (IFM_SUBTYPE(media) == IFM_100_TX) { - printf("100Mbps, "); - bmcr |= PHY_BMCR_SPEEDSEL; - } - - if (IFM_SUBTYPE(media) == IFM_10_T) { - printf("10Mbps, "); - bmcr &= ~PHY_BMCR_SPEEDSEL; - } - - if ((media & IFM_GMASK) == IFM_FDX) { - printf("full duplex\n"); - bmcr |= PHY_BMCR_DUPLEX; - } else { - printf("half duplex\n"); - bmcr &= ~PHY_BMCR_DUPLEX; - } - - pn_setcfg(sc, bmcr); - pn_phy_writereg(sc, PHY_BMCR, bmcr); - - return; -} - -/* - * Programming the receiver filter on the tulip/PNIC is gross. You - * have to construct a special setup frame and download it to the - * chip via the transmit DMA engine. This routine is also somewhat - * gross, as the setup frame is sent synchronously rather than putting - * on the transmit queue. The transmitter has to be stopped, then we - * can download the frame and wait for the 'owned' bit to clear. - * - * We always program the chip using 'hash perfect' mode, i.e. one perfect - * address (our node address) and a 512-bit hash filter for multicast - * frames. We also sneak the broadcast address into the hash filter since - * we need that too. - */ -void pn_setfilt(sc) - struct pn_softc *sc; -{ - struct pn_desc *sframe; - u_int32_t h, *sp; - struct ifmultiaddr *ifma; - struct ifnet *ifp; - int i; - - ifp = &sc->arpcom.ac_if; - - PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON); - PN_SETBIT(sc, PN_ISR, PN_ISR_TX_IDLE); - - sframe = &sc->pn_cdata.pn_sframe; - sp = (u_int32_t *)&sc->pn_cdata.pn_sbuf; - bzero((char *)sp, PN_SFRAME_LEN); - - sframe->pn_status = PN_TXSTAT_OWN; - sframe->pn_next = vtophys(&sc->pn_ldata->pn_tx_list[0]); - sframe->pn_data = vtophys(&sc->pn_cdata.pn_sbuf); - sframe->pn_ctl = PN_SFRAME_LEN | PN_TXCTL_TLINK | - PN_TXCTL_SETUP | PN_FILTER_HASHPERF; - - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) - PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_RX_PROMISC); - else - PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_RX_PROMISC); - - if (ifp->if_flags & IFF_ALLMULTI) - PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_RX_ALLMULTI); - - for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; - ifma = ifma->ifma_link.le_next) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = pn_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - sp[h >> 4] |= 1 << (h & 0xF); - } - - if (ifp->if_flags & IFF_BROADCAST) { - h = pn_calchash(etherbroadcastaddr); - sp[h >> 4] |= 1 << (h & 0xF); - } - - sp[39] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0]; - sp[40] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1]; - sp[41] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2]; - - CSR_WRITE_4(sc, PN_TXADDR, vtophys(sframe)); - PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON); - CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF); - - /* - * Wait for chip to clear the 'own' bit. - */ - for (i = 0; i < PN_TIMEOUT; i++) { - DELAY(10); - if (sframe->pn_status != PN_TXSTAT_OWN) - break; - } - - if (i == PN_TIMEOUT) - printf("pn%d: failed to send setup frame\n", sc->pn_unit); - - PN_SETBIT(sc, PN_ISR, PN_ISR_TX_NOBUF|PN_ISR_TX_IDLE); - - return; -} - -/* - * In order to fiddle with the - * 'full-duplex' and '100Mbps' bits in the netconfig register, we - * first have to put the transmit and/or receive logic in the idle state. - */ -static void pn_setcfg(sc, bmcr) - struct pn_softc *sc; - u_int16_t bmcr; -{ - int i, restart = 0; - - if (CSR_READ_4(sc, PN_NETCFG) & (PN_NETCFG_TX_ON|PN_NETCFG_RX_ON)) { - restart = 1; - PN_CLRBIT(sc, PN_NETCFG, (PN_NETCFG_TX_ON|PN_NETCFG_RX_ON)); - - for (i = 0; i < PN_TIMEOUT; i++) { - DELAY(10); - if ((CSR_READ_4(sc, PN_ISR) & PN_ISR_TX_IDLE) && - (CSR_READ_4(sc, PN_ISR) & PN_ISR_RX_IDLE)) - break; - } - - if (i == PN_TIMEOUT) - printf("pn%d: failed to force tx and " - "rx to idle state\n", sc->pn_unit); - - } - - if (bmcr & PHY_BMCR_SPEEDSEL) - PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_SPEEDSEL); - else - PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_SPEEDSEL); - - if (bmcr & PHY_BMCR_DUPLEX) - PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_FULLDUPLEX); - else - PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_FULLDUPLEX); - - if (restart) - PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON|PN_NETCFG_RX_ON); - - return; -} - -static void pn_reset(sc) - struct pn_softc *sc; -{ - register int i; - - PN_SETBIT(sc, PN_BUSCTL, PN_BUSCTL_RESET); - - for (i = 0; i < PN_TIMEOUT; i++) { - DELAY(10); - if (!(CSR_READ_4(sc, PN_BUSCTL) & PN_BUSCTL_RESET)) - break; - } - if (i == PN_TIMEOUT) - printf("pn%d: reset never completed!\n", sc->pn_unit); - - /* Wait a little while for the chip to get its brains in order. */ - DELAY(1000); - return; -} - -/* - * Probe for a Lite-On PNIC chip. Check the PCI vendor and device - * IDs against our list and return a device name if we find a match. - */ -static const char * -pn_probe(config_id, device_id) - pcici_t config_id; - pcidi_t device_id; -{ - struct pn_type *t; - - t = pn_devs; - - while(t->pn_name != NULL) { - if ((device_id & 0xFFFF) == t->pn_vid && - ((device_id >> 16) & 0xFFFF) == t->pn_did) { - return(t->pn_name); - } - t++; - } - - return(NULL); -} - -/* - * Attach the interface. Allocate softc structures, do ifmedia - * setup and ethernet/BPF attach. - */ -static void -pn_attach(config_id, unit) - pcici_t config_id; - int unit; -{ - int s, i; -#ifndef PN_USEIOSPACE - vm_offset_t pbase, vbase; -#endif - u_char eaddr[ETHER_ADDR_LEN]; - u_int32_t command; - struct pn_softc *sc; - struct ifnet *ifp; - int media = IFM_ETHER|IFM_100_TX|IFM_FDX; - unsigned int round; - caddr_t roundptr; - struct pn_type *p; - u_int16_t phy_vid, phy_did, phy_sts; -#ifdef PN_PROMISC_BUG_WAR - u_int32_t revision = 0; -#endif - - s = splimp(); - - sc = malloc(sizeof(struct pn_softc), M_DEVBUF, M_NOWAIT); - if (sc == NULL) { - printf("pn%d: no memory for softc struct!\n", unit); - return; - } - bzero(sc, sizeof(struct pn_softc)); - - /* - * Handle power management nonsense. - */ - - command = pci_conf_read(config_id, PN_PCI_CAPID) & 0x000000FF; - if (command == 0x01) { - - command = pci_conf_read(config_id, PN_PCI_PWRMGMTCTRL); - if (command & PN_PSTATE_MASK) { - u_int32_t iobase, membase, irq; - - /* Save important PCI config data. */ - iobase = pci_conf_read(config_id, PN_PCI_LOIO); - membase = pci_conf_read(config_id, PN_PCI_LOMEM); - irq = pci_conf_read(config_id, PN_PCI_INTLINE); - - /* Reset the power state. */ - printf("pn%d: chip is in D%d power mode " - "-- setting to D0\n", unit, command & PN_PSTATE_MASK); - command &= 0xFFFFFFFC; - pci_conf_write(config_id, PN_PCI_PWRMGMTCTRL, command); - - /* Restore PCI config data. */ - pci_conf_write(config_id, PN_PCI_LOIO, iobase); - pci_conf_write(config_id, PN_PCI_LOMEM, membase); - pci_conf_write(config_id, PN_PCI_INTLINE, irq); - } - } - - /* - * Map control/status registers. - */ - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); - pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - -#ifdef PN_USEIOSPACE - if (!(command & PCIM_CMD_PORTEN)) { - printf("pn%d: failed to enable I/O ports!\n", unit); - free(sc, M_DEVBUF); - goto fail; - } - - if (!pci_map_port(config_id, PN_PCI_LOIO, - (u_short *)&(sc->pn_bhandle))) { - printf ("pn%d: couldn't map ports\n", unit); - goto fail; - } - sc->pn_btag = I386_BUS_SPACE_IO; -#else - if (!(command & PCIM_CMD_MEMEN)) { - printf("pn%d: failed to enable memory mapping!\n", unit); - goto fail; - } - - if (!pci_map_mem(config_id, PN_PCI_LOMEM, &vbase, &pbase)) { - printf ("pn%d: couldn't map memory\n", unit); - goto fail; - } - sc->pn_bhandle = vbase; - sc->pn_btag = I386_BUS_SPACE_MEM; -#endif - - /* Allocate interrupt */ - if (!pci_map_int(config_id, pn_intr, sc, &net_imask)) { - printf("pn%d: couldn't map interrupt\n", unit); - goto fail; - } - - /* Reset the adapter. */ - pn_reset(sc); - - /* - * Get station address from the EEPROM. - */ - pn_read_eeprom(sc, (caddr_t)&eaddr, 0, 3, 1); - - /* - * A PNIC chip was detected. Inform the world. - */ - printf("pn%d: Ethernet address: %6D\n", unit, eaddr, ":"); - - sc->pn_unit = unit; - bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); - - sc->pn_ldata_ptr = malloc(sizeof(struct pn_list_data) + 8, - M_DEVBUF, M_NOWAIT); - if (sc->pn_ldata_ptr == NULL) { - free(sc, M_DEVBUF); - printf("pn%d: no memory for list buffers!\n", unit); - goto fail; - } - - sc->pn_ldata = (struct pn_list_data *)sc->pn_ldata_ptr; - round = (unsigned int)sc->pn_ldata_ptr & 0xF; - roundptr = sc->pn_ldata_ptr; - for (i = 0; i < 8; i++) { - if (round % 8) { - round++; - roundptr++; - } else - break; - } - sc->pn_ldata = (struct pn_list_data *)roundptr; - bzero(sc->pn_ldata, sizeof(struct pn_list_data)); - -#ifdef PN_PROMISC_BUG_WAR - revision = pci_conf_read(config_id, PN_PCI_REVISION) & 0x000000FF; - if (revision == PN_169B_REV || revision == PN_169_REV) { - sc->pn_promisc_war = 1; - sc->pn_promisc_buf = malloc(PN_RXLEN * 5, M_DEVBUF, M_NOWAIT); - if (sc->pn_promisc_buf == NULL) { - printf("pn%d: no memory for workaround buffer\n", unit); - goto fail; - } - } else { - sc->pn_promisc_war = 0; - } -#endif - - ifp = &sc->arpcom.ac_if; - ifp->if_softc = sc; - ifp->if_unit = unit; - ifp->if_name = "pn"; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = pn_ioctl; - ifp->if_output = ether_output; - ifp->if_start = pn_start; - ifp->if_watchdog = pn_watchdog; - ifp->if_init = pn_init; - ifp->if_baudrate = 10000000; - - if (bootverbose) - printf("pn%d: probing for a PHY\n", sc->pn_unit); - for (i = PN_PHYADDR_MIN; i < PN_PHYADDR_MAX + 1; i++) { - if (bootverbose) - printf("pn%d: checking address: %d\n", - sc->pn_unit, i); - sc->pn_phy_addr = i; - pn_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(pn_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - if ((phy_sts = pn_phy_readreg(sc, PHY_BMSR))) - break; - } - if (phy_sts) { - phy_vid = pn_phy_readreg(sc, PHY_VENID); - phy_did = pn_phy_readreg(sc, PHY_DEVID); - if (bootverbose) - printf("pn%d: found PHY at address %d, ", - sc->pn_unit, sc->pn_phy_addr); - if (bootverbose) - printf("vendor id: %x device id: %x\n", - phy_vid, phy_did); - p = pn_phys; - while(p->pn_vid) { - if (phy_vid == p->pn_vid && - (phy_did | 0x000F) == p->pn_did) { - sc->pn_pinfo = p; - break; - } - p++; - } - if (sc->pn_pinfo == NULL) - sc->pn_pinfo = &pn_phys[PHY_UNKNOWN]; - if (bootverbose) - printf("pn%d: PHY type: %s\n", - sc->pn_unit, sc->pn_pinfo->pn_name); - } else { - printf("pn%d: MII without any phy!\n", sc->pn_unit); - goto fail; - } - - /* - * Do ifmedia setup. - */ - ifmedia_init(&sc->ifmedia, 0, pn_ifmedia_upd, pn_ifmedia_sts); - - pn_getmode_mii(sc); - pn_autoneg_mii(sc, PN_FLAG_FORCEDELAY, 1); - media = sc->ifmedia.ifm_media; - pn_stop(sc); - - ifmedia_set(&sc->ifmedia, media); - - /* - * Call MI attach routines. - */ - if_attach(ifp); - ether_ifattach(ifp); - -#if NBPFILTER > 0 - bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif - at_shutdown(pn_shutdown, sc, SHUTDOWN_POST_SYNC); - -fail: - splx(s); - return; -} - -/* - * Initialize the transmit descriptors. - */ -static int pn_list_tx_init(sc) - struct pn_softc *sc; -{ - struct pn_chain_data *cd; - struct pn_list_data *ld; - int i; - - cd = &sc->pn_cdata; - ld = sc->pn_ldata; - for (i = 0; i < PN_TX_LIST_CNT; i++) { - cd->pn_tx_chain[i].pn_ptr = &ld->pn_tx_list[i]; - if (i == (PN_TX_LIST_CNT - 1)) - cd->pn_tx_chain[i].pn_nextdesc = - &cd->pn_tx_chain[0]; - else - cd->pn_tx_chain[i].pn_nextdesc = - &cd->pn_tx_chain[i + 1]; - } - - cd->pn_tx_free = &cd->pn_tx_chain[0]; - cd->pn_tx_tail = cd->pn_tx_head = NULL; - - return(0); -} - - -/* - * Initialize the RX descriptors and allocate mbufs for them. Note that - * we arrange the descriptors in a closed ring, so that the last descriptor - * points back to the first. - */ -static int pn_list_rx_init(sc) - struct pn_softc *sc; -{ - struct pn_chain_data *cd; - struct pn_list_data *ld; - int i; - - cd = &sc->pn_cdata; - ld = sc->pn_ldata; - - for (i = 0; i < PN_RX_LIST_CNT; i++) { - cd->pn_rx_chain[i].pn_ptr = - (struct pn_desc *)&ld->pn_rx_list[i]; - if (pn_newbuf(sc, &cd->pn_rx_chain[i]) == ENOBUFS) - return(ENOBUFS); - if (i == (PN_RX_LIST_CNT - 1)) { - cd->pn_rx_chain[i].pn_nextdesc = &cd->pn_rx_chain[0]; - ld->pn_rx_list[i].pn_next = - vtophys(&ld->pn_rx_list[0]); - } else { - cd->pn_rx_chain[i].pn_nextdesc = &cd->pn_rx_chain[i + 1]; - ld->pn_rx_list[i].pn_next = - vtophys(&ld->pn_rx_list[i + 1]); - } - } - - cd->pn_rx_head = &cd->pn_rx_chain[0]; - - return(0); -} - -/* - * Initialize an RX descriptor and attach an MBUF cluster. - * Note: the length fields are only 11 bits wide, which means the - * largest size we can specify is 2047. This is important because - * MCLBYTES is 2048, so we have to subtract one otherwise we'll - * overflow the field and make a mess. - */ -static int pn_newbuf(sc, c) - struct pn_softc *sc; - struct pn_chain_onefrag *c; -{ - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("pn%d: no memory for rx list -- packet dropped!\n", - sc->pn_unit); - return(ENOBUFS); - } - - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - printf("pn%d: no memory for rx list -- packet dropped!\n", - sc->pn_unit); - m_freem(m_new); - return(ENOBUFS); - } - - /* - * Zero the buffer. This is part of the workaround for the - * promiscuous mode bug in the revision 33 PNIC chips. - */ - bzero((char *)mtod(m_new, char *), MCLBYTES); - m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; - - c->pn_mbuf = m_new; - c->pn_ptr->pn_status = PN_RXSTAT; - c->pn_ptr->pn_data = vtophys(mtod(m_new, caddr_t)); - c->pn_ptr->pn_ctl = PN_RXCTL_RLINK | PN_RXLEN; - - return(0); -} - -#ifdef PN_PROMISC_BUG_WAR -/* - * Grrrrr. - * Revision 33 of the PNIC chip has a terrible bug in it that manifests - * itself when you enable promiscuous mode. Sometimes instead of uploading - * one complete frame, it uploads its entire FIFO memory. The frame we - * want is at the end of this whole mess, but we never know exactly - * how much data has been uploaded, so finding it can be hard. - * - * There is only one way to do it reliably, and it's disgusting. - * Here's what we know: - * - * - We know there will always be somewhere between one and three extra - * descriptors uploaded. - * - * - We know the desired received frame will always be at the end of the - * total data upload. - * - * - We know the size of the desired received frame because it will be - * provided in the length field of the status word in the last descriptor. - * - * Here's what we do: - * - * - When we allocate buffers for the receive ring, we bzero() them. - * This means that we know that the buffer contents should be all - * zeros, except for data uploaded by the chip. - * - * - We also force the PNIC chip to upload frames that include the - * ethernet CRC at the end. - * - * - We gather all of the bogus frame data into a single buffer. - * - * - We then position a pointer at the end of this buffer and scan - * backwards until we encounter the first non-zero byte of data. - * This is the end of the received frame. We know we will encounter - * some data at the end of the frame because the CRC will always be - * there, so even if the sender transmits a packet of all zeros, - * we won't be fooled. - * - * - We know the size of the actual received frame, so we subtract - * that value from the current pointer location. This brings us - * to the start of the actual received packet. - * - * - We copy this into an mbuf and pass it on, along with the actual - * frame length. - * - * The performance hit is tremendous, but it beats dropping frames all - * the time. - */ - -#define PN_WHOLEFRAME (PN_RXSTAT_FIRSTFRAG|PN_RXSTAT_LASTFRAG) -static void pn_promisc_bug_war(sc, cur_rx) - struct pn_softc *sc; - struct pn_chain_onefrag *cur_rx; -{ - struct pn_chain_onefrag *c; - unsigned char *ptr; - int total_len; - u_int32_t rxstat = 0; - - c = sc->pn_promisc_bug_save; - ptr = sc->pn_promisc_buf; - bzero(ptr, sizeof(PN_RXLEN * 5)); - - /* Copy all the bytes from the bogus buffers. */ - while ((c->pn_ptr->pn_status & PN_WHOLEFRAME) != PN_WHOLEFRAME) { - rxstat = c->pn_ptr->pn_status; - m_copydata(c->pn_mbuf, 0, PN_RXLEN, ptr); - ptr += PN_RXLEN - 2; /* round down to 32-bit boundary */ - if (c == cur_rx) - break; - if (rxstat & PN_RXSTAT_LASTFRAG) - break; - c->pn_ptr->pn_status = PN_RXSTAT; - c->pn_ptr->pn_ctl = PN_RXCTL_RLINK | PN_RXLEN; - bzero((char *)mtod(c->pn_mbuf, char *), MCLBYTES); - c = c->pn_nextdesc; - } - - - /* Find the length of the actual receive frame. */ - total_len = PN_RXBYTES(rxstat); - - /* Scan backwards until we hit a non-zero byte. */ - while(*ptr == 0x00) { - ptr--; - } - - if ((u_int32_t)(ptr) & 0x3) - ptr -= 1; - - /* Now find the start of the frame. */ - ptr -= total_len; - if (ptr < sc->pn_promisc_buf) - ptr = sc->pn_promisc_buf; - - /* - * Now copy the salvaged frame to the last mbuf and fake up - * the status word to make it look like a successful - * frame reception. - */ - m_copyback(cur_rx->pn_mbuf, 0, total_len, ptr); - cur_rx->pn_mbuf->m_len = c->pn_mbuf->m_pkthdr.len = MCLBYTES; - cur_rx->pn_ptr->pn_status |= PN_RXSTAT_FIRSTFRAG; - - return; -} -#endif - -/* - * A frame has been uploaded: pass the resulting mbuf chain up to - * the higher level protocols. - */ -static void pn_rxeof(sc) - struct pn_softc *sc; -{ - struct ether_header *eh; - struct mbuf *m; - struct ifnet *ifp; - struct pn_chain_onefrag *cur_rx; - int total_len = 0; - u_int32_t rxstat; - - ifp = &sc->arpcom.ac_if; - - while(!((rxstat = sc->pn_cdata.pn_rx_head->pn_ptr->pn_status) & - PN_RXSTAT_OWN)) { - cur_rx = sc->pn_cdata.pn_rx_head; - sc->pn_cdata.pn_rx_head = cur_rx->pn_nextdesc; - -#ifdef PN_PROMISC_BUG_WAR - /* - * XXX The PNIC seems to have a bug that manifests - * when the promiscuous mode bit is set: we have to - * watch for it and work around it. - */ - if (sc->pn_promisc_war && ifp->if_flags & IFF_PROMISC) { - if ((rxstat & PN_WHOLEFRAME) != PN_WHOLEFRAME) { - if (rxstat & PN_RXSTAT_FIRSTFRAG) - sc->pn_promisc_bug_save = cur_rx; - if ((rxstat & PN_RXSTAT_LASTFRAG) == 0) - continue; - pn_promisc_bug_war(sc, cur_rx); - rxstat = cur_rx->pn_ptr->pn_status; - } - } -#endif - - /* - * If an error occurs, update stats, clear the - * status word and leave the mbuf cluster in place: - * it should simply get re-used next time this descriptor - * comes up in the ring. - */ - if (rxstat & PN_RXSTAT_RXERR) { - ifp->if_ierrors++; - if (rxstat & PN_RXSTAT_COLLSEEN) - ifp->if_collisions++; - cur_rx->pn_ptr->pn_status = PN_RXSTAT; - cur_rx->pn_ptr->pn_ctl = PN_RXCTL_RLINK | PN_RXLEN; - bzero((char *)mtod(cur_rx->pn_mbuf, char *), MCLBYTES); - continue; - } - - /* No errors; receive the packet. */ - m = cur_rx->pn_mbuf; - total_len = PN_RXBYTES(cur_rx->pn_ptr->pn_status); - - /* Trim off the CRC. */ - total_len -= ETHER_CRC_LEN; - - /* - * Try to conjure up a new mbuf cluster. If that - * fails, it means we have an out of memory condition and - * should leave the buffer in place and continue. This will - * result in a lost packet, but there's little else we - * can do in this situation. - */ - if (pn_newbuf(sc, cur_rx) == ENOBUFS) { - ifp->if_ierrors++; - cur_rx->pn_ptr->pn_status = PN_RXSTAT; - cur_rx->pn_ptr->pn_ctl = PN_RXCTL_RLINK | PN_RXLEN; - bzero((char *)mtod(cur_rx->pn_mbuf, char *), MCLBYTES); - continue; - } - - ifp->if_ipackets++; - eh = mtod(m, struct ether_header *); - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = m->m_len = total_len; -#if NBPFILTER > 0 - /* - * Handle BPF listeners. Let the BPF user see the packet, but - * don't pass it up to the ether_input() layer unless it's - * a broadcast packet, multicast packet, matches our ethernet - * address or the interface is in promiscuous mode. - */ - if (ifp->if_bpf) { - bpf_mtap(ifp, m); - if (ifp->if_flags & IFF_PROMISC && - (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, - ETHER_ADDR_LEN) && - (eh->ether_dhost[0] & 1) == 0)) { - m_freem(m); - continue; - } - } -#endif - /* Remove header from mbuf and pass it on. */ - m_adj(m, sizeof(struct ether_header)); - ether_input(ifp, eh, m); - } - - return; -} - -void pn_rxeoc(sc) - struct pn_softc *sc; -{ - - pn_rxeof(sc); - PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_RX_ON); - CSR_WRITE_4(sc, PN_RXADDR, vtophys(sc->pn_cdata.pn_rx_head->pn_ptr)); - PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_RX_ON); - CSR_WRITE_4(sc, PN_RXSTART, 0xFFFFFFFF); - - return; -} - -/* - * A frame was downloaded to the chip. It's safe for us to clean up - * the list buffers. - */ - -static void pn_txeof(sc) - struct pn_softc *sc; -{ - struct pn_chain *cur_tx; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - /* Clear the timeout timer. */ - ifp->if_timer = 0; - - if (sc->pn_cdata.pn_tx_head == NULL) - return; - - /* - * Go through our tx list and free mbufs for those - * frames that have been transmitted. - */ - while(sc->pn_cdata.pn_tx_head->pn_mbuf != NULL) { - u_int32_t txstat; - - cur_tx = sc->pn_cdata.pn_tx_head; - txstat = PN_TXSTATUS(cur_tx); - - if ((txstat & PN_TXSTAT_OWN) || txstat == PN_UNSENT) - break; - - if (txstat & PN_TXSTAT_ERRSUM) { - ifp->if_oerrors++; - if (txstat & PN_TXSTAT_EXCESSCOLL) - ifp->if_collisions++; - if (txstat & PN_TXSTAT_LATECOLL) - ifp->if_collisions++; - } - - ifp->if_collisions += (txstat & PN_TXSTAT_COLLCNT) >> 3; - - - ifp->if_opackets++; - m_freem(cur_tx->pn_mbuf); - cur_tx->pn_mbuf = NULL; - - if (sc->pn_cdata.pn_tx_head == sc->pn_cdata.pn_tx_tail) { - sc->pn_cdata.pn_tx_head = NULL; - sc->pn_cdata.pn_tx_tail = NULL; - break; - } - - sc->pn_cdata.pn_tx_head = cur_tx->pn_nextdesc; - } - - return; -} - -/* - * TX 'end of channel' interrupt handler. - */ -static void pn_txeoc(sc) - struct pn_softc *sc; -{ - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - ifp->if_timer = 0; - - if (sc->pn_cdata.pn_tx_head == NULL) { - ifp->if_flags &= ~IFF_OACTIVE; - sc->pn_cdata.pn_tx_tail = NULL; - if (sc->pn_want_auto) - pn_autoneg_mii(sc, PN_FLAG_SCHEDDELAY, 1); - } else { - if (PN_TXOWN(sc->pn_cdata.pn_tx_head) == PN_UNSENT) { - PN_TXOWN(sc->pn_cdata.pn_tx_head) = PN_TXSTAT_OWN; - ifp->if_timer = 5; - CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF); - } - } - - return; -} - -static void pn_intr(arg) - void *arg; -{ - struct pn_softc *sc; - struct ifnet *ifp; - u_int32_t status; - - sc = arg; - ifp = &sc->arpcom.ac_if; - - /* Supress unwanted interrupts. */ - if (!(ifp->if_flags & IFF_UP)) { - pn_stop(sc); - return; - } - - /* Disable interrupts. */ - CSR_WRITE_4(sc, PN_IMR, 0x00000000); - - for (;;) { - status = CSR_READ_4(sc, PN_ISR); - if (status) - CSR_WRITE_4(sc, PN_ISR, status); - - if ((status & PN_INTRS) == 0) - break; - - if (status & PN_ISR_RX_OK) - pn_rxeof(sc); - - if ((status & PN_ISR_RX_WATCHDOG) || (status & PN_ISR_RX_IDLE) - || (status & PN_ISR_RX_NOBUF)) - pn_rxeoc(sc); - - if (status & PN_ISR_TX_OK) - pn_txeof(sc); - - if (status & PN_ISR_TX_NOBUF) - pn_txeoc(sc); - - if (status & PN_ISR_TX_IDLE) { - pn_txeof(sc); - if (sc->pn_cdata.pn_tx_head != NULL) { - PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON); - CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF); - } - } - - if (status & PN_ISR_TX_UNDERRUN) { - ifp->if_oerrors++; - pn_txeof(sc); - if (sc->pn_cdata.pn_tx_head != NULL) { - PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON); - CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF); - } - } - - if (status & PN_ISR_BUS_ERR) { - pn_reset(sc); - pn_init(sc); - } - } - - /* Re-enable interrupts. */ - CSR_WRITE_4(sc, PN_IMR, PN_INTRS); - - if (ifp->if_snd.ifq_head != NULL) { - pn_start(ifp); - } - - return; -} - -/* - * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data - * pointers to the fragment pointers. - */ -static int pn_encap(sc, c, m_head) - struct pn_softc *sc; - struct pn_chain *c; - struct mbuf *m_head; -{ - int frag = 0; - struct pn_desc *f = NULL; - int total_len; - struct mbuf *m; - - /* - * Start packing the mbufs in this chain into - * the fragment pointers. Stop when we run out - * of fragments or hit the end of the mbuf chain. - */ - m = m_head; - total_len = 0; - - for (m = m_head, frag = 0; m != NULL; m = m->m_next) { - if (m->m_len != 0) { - if (frag == PN_MAXFRAGS) - break; - total_len += m->m_len; - f = &c->pn_ptr->pn_frag[frag]; - f->pn_ctl = PN_TXCTL_TLINK | m->m_len; - if (frag == 0) { - f->pn_ctl |= PN_TXCTL_FIRSTFRAG; - f->pn_status = 0; - } else - f->pn_status = PN_TXSTAT_OWN; - f->pn_data = vtophys(mtod(m, vm_offset_t)); - f->pn_next = vtophys(&c->pn_ptr->pn_frag[frag + 1]); - frag++; - } - } - - /* - * Handle special case: we used up all 16 fragments, - * but we have more mbufs left in the chain. Copy the - * data into an mbuf cluster. Note that we don't - * bother clearing the values in the other fragment - * pointers/counters; it wouldn't gain us anything, - * and would waste cycles. - */ - if (m != NULL) { - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("pn%d: no memory for tx list", sc->pn_unit); - return(1); - } - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - printf("pn%d: no memory for tx list", - sc->pn_unit); - return(1); - } - } - m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; - m_freem(m_head); - m_head = m_new; - f = &c->pn_ptr->pn_frag[0]; - f->pn_data = vtophys(mtod(m_new, caddr_t)); - f->pn_ctl = total_len = m_new->m_len; - f->pn_ctl |= PN_TXCTL_TLINK|PN_TXCTL_FIRSTFRAG; - frag = 1; - } - - - c->pn_mbuf = m_head; - c->pn_lastdesc = frag - 1; - PN_TXCTL(c) |= PN_TXCTL_LASTFRAG; - PN_TXNEXT(c) = vtophys(&c->pn_nextdesc->pn_ptr->pn_frag[0]); - - return(0); -} - -/* - * Main transmit routine. To avoid having to do mbuf copies, we put pointers - * to the mbuf data regions directly in the transmit lists. We also save a - * copy of the pointers since the transmit list fragment pointers are - * physical addresses. - */ - -static void pn_start(ifp) - struct ifnet *ifp; -{ - struct pn_softc *sc; - struct mbuf *m_head = NULL; - struct pn_chain *cur_tx = NULL, *start_tx; - - sc = ifp->if_softc; - - if (sc->pn_autoneg) { - sc->pn_tx_pend = 1; - return; - } - - /* - * Check for an available queue slot. If there are none, - * punt. - */ - if (sc->pn_cdata.pn_tx_free->pn_mbuf != NULL) { - ifp->if_flags |= IFF_OACTIVE; - return; - } - - start_tx = sc->pn_cdata.pn_tx_free; - - while(sc->pn_cdata.pn_tx_free->pn_mbuf == NULL) { - IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) - break; - - /* Pick a descriptor off the free list. */ - cur_tx = sc->pn_cdata.pn_tx_free; - sc->pn_cdata.pn_tx_free = cur_tx->pn_nextdesc; - - /* Pack the data into the descriptor. */ - pn_encap(sc, cur_tx, m_head); - - if (cur_tx != start_tx) - PN_TXOWN(cur_tx) = PN_TXSTAT_OWN; - -#if NBPFILTER > 0 - /* - * If there's a BPF listener, bounce a copy of this frame - * to him. - */ - if (ifp->if_bpf) - bpf_mtap(ifp, cur_tx->pn_mbuf); -#endif - } - - /* - * If there are no packets queued, bail. - */ - if (cur_tx == NULL) - return; - - /* - * Place the request for the upload interrupt - * in the last descriptor in the chain. This way, if - * we're chaining several packets at once, we'll only - * get an interupt once for the whole chain rather than - * once for each packet. - */ - PN_TXCTL(cur_tx) |= PN_TXCTL_FINT; - sc->pn_cdata.pn_tx_tail = cur_tx; - - if (sc->pn_cdata.pn_tx_head == NULL) { - sc->pn_cdata.pn_tx_head = start_tx; - PN_TXOWN(start_tx) = PN_TXSTAT_OWN; - CSR_WRITE_4(sc, PN_TXSTART, 0xFFFFFFFF); - } else { - PN_TXOWN(start_tx) = PN_UNSENT; - } - - /* - * Set a timeout in case the chip goes out to lunch. - */ - ifp->if_timer = 5; - - return; -} - -static void pn_init(xsc) - void *xsc; -{ - struct pn_softc *sc = xsc; - struct ifnet *ifp = &sc->arpcom.ac_if; - u_int16_t phy_bmcr = 0; - int s; - - if (sc->pn_autoneg) - return; - - s = splimp(); - - if (sc->pn_pinfo != NULL) - phy_bmcr = pn_phy_readreg(sc, PHY_BMCR); - - /* - * Cancel pending I/O and free all RX/TX buffers. - */ - pn_stop(sc); - pn_reset(sc); - - /* - * Set cache alignment and burst length. - */ - CSR_WRITE_4(sc, PN_BUSCTL, PN_BUSCTL_CONFIG); - - PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_TX_IMMEDIATE); - PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_NO_RXCRC); - PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_HEARTBEAT); - PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_STORENFWD); - PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_TX_BACKOFF); - - PN_CLRBIT(sc, PN_NETCFG, PN_NETCFG_TX_THRESH); - PN_SETBIT(sc, PN_NETCFG, PN_TXTHRESH_72BYTES); - - pn_setcfg(sc, pn_phy_readreg(sc, PHY_BMCR)); - - if (sc->pn_pinfo != NULL) { - PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_MIIENB); - PN_SETBIT(sc, PN_ENDEC, PN_ENDEC_JABBERDIS); - } - - /* Init circular RX list. */ - if (pn_list_rx_init(sc) == ENOBUFS) { - printf("pn%d: initialization failed: no " - "memory for rx buffers\n", sc->pn_unit); - pn_stop(sc); - (void)splx(s); - return; - } - - /* - * Init tx descriptors. - */ - pn_list_tx_init(sc); - - /* - * Load the address of the RX list. - */ - CSR_WRITE_4(sc, PN_RXADDR, vtophys(sc->pn_cdata.pn_rx_head->pn_ptr)); - - /* - * Load the RX/multicast filter. - */ - pn_setfilt(sc); - - /* - * Enable interrupts. - */ - CSR_WRITE_4(sc, PN_IMR, PN_INTRS); - CSR_WRITE_4(sc, PN_ISR, 0xFFFFFFFF); - - /* Enable receiver and transmitter. */ - PN_SETBIT(sc, PN_NETCFG, PN_NETCFG_TX_ON|PN_NETCFG_RX_ON); - CSR_WRITE_4(sc, PN_RXSTART, 0xFFFFFFFF); - - /* Restore state of BMCR */ - if (sc->pn_pinfo != NULL) - pn_phy_writereg(sc, PHY_BMCR, phy_bmcr); - - ifp->if_flags |= IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - - (void)splx(s); - - return; -} - -/* - * Set media options. - */ -static int pn_ifmedia_upd(ifp) - struct ifnet *ifp; -{ - struct pn_softc *sc; - struct ifmedia *ifm; - - sc = ifp->if_softc; - ifm = &sc->ifmedia; - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return(EINVAL); - - if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) - pn_autoneg_mii(sc, PN_FLAG_SCHEDDELAY, 1); - else - pn_setmode_mii(sc, ifm->ifm_media); - - return(0); -} - -/* - * Report current media status. - */ -static void pn_ifmedia_sts(ifp, ifmr) - struct ifnet *ifp; - struct ifmediareq *ifmr; -{ - struct pn_softc *sc; - u_int16_t advert = 0, ability = 0; - - sc = ifp->if_softc; - - ifmr->ifm_active = IFM_ETHER; - - if (!(pn_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { - if (pn_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) - ifmr->ifm_active = IFM_ETHER|IFM_100_TX; - else - ifmr->ifm_active = IFM_ETHER|IFM_10_T; - if (pn_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) - ifmr->ifm_active |= IFM_FDX; - else - ifmr->ifm_active |= IFM_HDX; - return; - } - - ability = pn_phy_readreg(sc, PHY_LPAR); - advert = pn_phy_readreg(sc, PHY_ANAR); - if (advert & PHY_ANAR_100BT4 && - ability & PHY_ANAR_100BT4) { - ifmr->ifm_active = IFM_ETHER|IFM_100_T4; - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX; - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX; - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX; - } else if (advert & PHY_ANAR_10BTHALF && - ability & PHY_ANAR_10BTHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX; - } - - return; -} - -static int pn_ioctl(ifp, command, data) - struct ifnet *ifp; - u_long command; - caddr_t data; -{ - struct pn_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; - int s, error = 0; - - s = splimp(); - - switch(command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; - case SIOCSIFFLAGS: - if (ifp->if_flags & IFF_UP) { - pn_init(sc); - } else { - if (ifp->if_flags & IFF_RUNNING) - pn_stop(sc); - } - error = 0; - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - pn_init(sc); - error = 0; - break; - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); - break; - default: - error = EINVAL; - break; - } - - (void)splx(s); - - return(error); -} - -static void pn_watchdog(ifp) - struct ifnet *ifp; -{ - struct pn_softc *sc; - - sc = ifp->if_softc; - - if (sc->pn_autoneg) { - pn_autoneg_mii(sc, PN_FLAG_DELAYTIMEO, 1); - return; - } - - ifp->if_oerrors++; - printf("pn%d: watchdog timeout\n", sc->pn_unit); - - if (!(pn_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) - printf("pn%d: no carrier - transceiver cable problem?\n", - sc->pn_unit); - pn_stop(sc); - pn_reset(sc); - pn_init(sc); - - if (ifp->if_snd.ifq_head != NULL) - pn_start(ifp); - - return; -} - -/* - * Stop the adapter and free any mbufs allocated to the - * RX and TX lists. - */ -static void pn_stop(sc) - struct pn_softc *sc; -{ - register int i; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - ifp->if_timer = 0; - - PN_CLRBIT(sc, PN_NETCFG, (PN_NETCFG_RX_ON|PN_NETCFG_TX_ON)); - CSR_WRITE_4(sc, PN_IMR, 0x00000000); - CSR_WRITE_4(sc, PN_TXADDR, 0x00000000); - CSR_WRITE_4(sc, PN_RXADDR, 0x00000000); - - /* - * Free data in the RX lists. - */ - for (i = 0; i < PN_RX_LIST_CNT; i++) { - if (sc->pn_cdata.pn_rx_chain[i].pn_mbuf != NULL) { - m_freem(sc->pn_cdata.pn_rx_chain[i].pn_mbuf); - sc->pn_cdata.pn_rx_chain[i].pn_mbuf = NULL; - } - } - bzero((char *)&sc->pn_ldata->pn_rx_list, - sizeof(sc->pn_ldata->pn_rx_list)); - - /* - * Free the TX list buffers. - */ - for (i = 0; i < PN_TX_LIST_CNT; i++) { - if (sc->pn_cdata.pn_tx_chain[i].pn_mbuf != NULL) { - m_freem(sc->pn_cdata.pn_tx_chain[i].pn_mbuf); - sc->pn_cdata.pn_tx_chain[i].pn_mbuf = NULL; - } - } - - bzero((char *)&sc->pn_ldata->pn_tx_list, - sizeof(sc->pn_ldata->pn_tx_list)); - - ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - - return; -} - -/* - * Stop all chip I/O so that the kernel's probe routines don't - * get confused by errant DMAs when rebooting. - */ -static void pn_shutdown(howto, arg) - int howto; - void *arg; -{ - struct pn_softc *sc = (struct pn_softc *)arg; - - pn_stop(sc); - - return; -} - -static struct pci_device pn_device = { - "pn", - pn_probe, - pn_attach, - &pn_count, - NULL -}; -DATA_SET(pcidevice_set, pn_device); diff --git a/sys/pci/if_pnreg.h b/sys/pci/if_pnreg.h deleted file mode 100644 index e3644097985d..000000000000 --- a/sys/pci/if_pnreg.h +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Copyright (c) 1997, 1998 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_pnreg.h,v 1.16 1999/01/05 00:47:25 wpaul Exp $ - */ - -/* - * PNIC register definitions. - */ - -#define PN_BUSCTL 0x00 /* bus control */ -#define PN_TXSTART 0x08 /* tx start demand */ -#define PN_RXSTART 0x10 /* rx start demand */ -#define PN_RXADDR 0x18 /* rx descriptor list start addr */ -#define PN_TXADDR 0x20 /* tx descriptor list start addr */ -#define PN_ISR 0x28 /* interrupt status register */ -#define PN_NETCFG 0x30 /* network config register */ -#define PN_IMR 0x38 /* interrupt mask */ -#define PN_FRAMESDISCARDED 0x40 /* # of discarded frames */ -#define PN_SIO 0x48 /* MII and ROM/EEPROM access */ -#define PN_GEN 0x60 /* general purpose register */ -#define PN_ENDEC 0x78 /* ENDEC general register */ -#define PN_SIOPWR 0x90 /* serial eeprom power up */ -#define PN_SIOCTL 0x98 /* EEPROM control register */ -#define PN_MII 0xA0 /* MII access register */ -#define PN_NWAY 0xB8 /* Internal NWAY register */ - - -/* - * Bus control bits. - */ -#define PN_BUSCTL_RESET 0x00000001 -#define PN_BUSCTL_ARBITRATION 0x00000002 -#define PN_BUSCTL_SKIPLEN 0x0000007C -#define PN_BUSCTL_BUF_BIGENDIAN 0x00000080 -#define PN_BUSCTL_BURSTLEN 0x00003F00 -#define PN_BUSCTL_CACHEALIGN 0x0000C000 -#define PN_BUSCTL_TXPOLL 0x000E0000 - -#define PN_SKIPLEN_1LONG 0x00000004 -#define PN_SKIPLEN_2LONG 0x00000008 -#define PN_SKIPLEN_3LONG 0x00000010 -#define PN_SKIPLEN_4LONG 0x00000020 -#define PN_SKIPLEN_5LONG 0x00000040 - -#define PN_CACHEALIGN_8LONG 0x00004000 -#define PN_CACHEALIGN_16LONG 0x00008000 -#define PN_CACHEALIGN_32LONG 0x0000C000 - -#define PN_BURSTLEN_USECA 0x00000000 -#define PN_BURSTLEN_1LONG 0x00000100 -#define PN_BURSTLEN_2LONG 0x00000200 -#define PN_BURSTLEN_4LONG 0x00000400 -#define PN_BURSTLEN_8LONG 0x00000800 -#define PN_BURSTLEN_16LONG 0x00001000 -#define PN_BURSTLEN_32LONG 0x00002000 - -#define PN_TXPOLL_OFF 0x00000000 -#define PN_TXPOLL_200U 0x00020000 -#define PN_TXPOLL_800U 0x00040000 -#define PN_TXPOLL_1600U 0x00060000 -#define PN_TXPOLL_12_8M 0x00080000 -#define PN_TXPOLL_25_6M 0x000A0000 -#define PN_TXPOLL_51_2M 0x000C0000 -#define PN_TXPOLL_102_4M 0x000E0000 - -#define PN_BUSCTL_CONFIG \ - (PN_CACHEALIGN_8LONG|PN_BURSTLEN_8LONG) - -/* - * Interrupt status bits. - */ -#define PN_ISR_TX_OK 0x00000001 /* packet tx ok */ -#define PN_ISR_TX_IDLE 0x00000002 /* tx stopped */ -#define PN_ISR_TX_NOBUF 0x00000004 /* no tx buffer available */ -#define PN_ISR_TX_JABTIMEO 0x00000008 /* jabber timeout */ -#define PN_ISR_LINKPASS 0x00000010 /* link test pass */ -#define PN_ISR_TX_UNDERRUN 0x00000020 /* transmit underrun */ -#define PN_ISR_RX_OK 0x00000040 /* packet rx ok */ -#define PN_ISR_RX_NOBUF 0x00000080 /* rx buffer unavailable */ -#define PN_ISR_RX_IDLE 0x00000100 /* rx stopped */ -#define PN_ISR_RX_WATCHDOG 0x00000200 /* rx watchdog timeo */ -#define PN_ISR_TX_EARLY 0x00000400 /* rx watchdog timeo */ -#define PN_ISR_BUS_ERR 0x00002000 -#define PN_ISR_ABNORMAL 0x00008000 -#define PN_ISR_NORMAL 0x00010000 -#define PN_ISR_RX_STATE 0x000E0000 -#define PN_ISR_TX_STATE 0x00700000 -#define PN_ISR_BUSERRTYPE 0x03800000 -#define PN_ISR_TXABORT 0x04000000 /* tx abort */ - -#define PN_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */ -#define PN_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */ -#define PN_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */ -#define PN_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */ -#define PN_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */ -#define PN_RXSTATE_CLOSE 0x000A0000 /* 101 - close rx desc */ -#define PN_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */ -#define PN_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */ - -#define PN_TXSTATE_RESET 0x00000000 /* 000 - reset */ -#define PN_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */ -#define PN_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */ -#define PN_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */ -#define PN_TXSTATE_RSVD 0x00400000 /* 100 - reserved */ -#define PN_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */ -#define PN_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */ -#define PN_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */ - -#define PN_BUSERR_PARITY 0x00000000 -#define PN_BUSERR_MASTABRT 0x00800000 -#define PN_BUSERR_TGTABRT 0x01000000 -#define PN_BUSERR_RSVD1 0x01800000 -#define PN_BUSERR_RSVD2 0x02000000 - -/* - * Network config bits. - */ -#define PN_NETCFG_HASHPERF 0x00000001 /* 0 == perf, 1 == hash */ -#define PN_NETCFG_RX_ON 0x00000002 -#define PN_NETCFG_HASHONLY 0x00000004 /* 1 == allhash */ -#define PN_NETCFG_RX_PASSERR 0x00000008 -#define PN_NETCFG_INVERSFILT 0x00000010 -#define PN_NETCFG_BACKOFF 0x00000020 -#define PN_NETCFG_RX_PROMISC 0x00000040 -#define PN_NETCFG_RX_ALLMULTI 0x00000080 -#define PN_NETCFG_FLAKYOSC 0x00000100 -#define PN_NETCFG_FULLDUPLEX 0x00000200 -#define PN_NETCFG_OPERMODE 0x00000C00 -#define PN_NETCFG_FORCECOLL 0x00001000 -#define PN_NETCFG_TX_ON 0x00002000 -#define PN_NETCFG_TX_THRESH 0x0000C000 -#define PN_NETCFG_TX_BACKOFF 0x00020000 -#define PN_NETCFG_MIIENB 0x00040000 /* 1 == MII, 0 == internal */ -#define PN_NETCFG_HEARTBEAT 0x00080000 /* 1 == disabled */ -#define PN_NETCFG_TX_IMMEDIATE 0x00100000 -#define PN_NETCFG_STORENFWD 0x00200000 -#define PN_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10Mbps 0 == 100Mbps */ -#define PN_NETCFG_PCS 0x00800000 /* 1 == 100baseTX */ -#define PN_NETCFG_NO_RXCRC 0x20000000 -#define PN_NETCFG_EXT_ENDEC 0x40000000 /* 1 == ext, 0 == int PHY */ - -#define PN_OPMODE_NORM 0x00000000 -#define PN_OPMODE_INTLOOP 0x00000400 -#define PN_OPMODE_EXTLOOP 0x00000800 - -#define PN_TXTHRESH_72BYTES 0x00000000 -#define PN_TXTHRESH_96BYTES 0x00004000 -#define PN_TXTHRESH_128BYTES 0x00008000 -#define PN_TXTHRESH_160BYTES 0x0000C000 - -/* - * Interrupt mask bits. - */ -#define PN_IMR_TX_OK 0x00000001 /* packet tx ok */ -#define PN_IMR_TX_IDLE 0x00000002 /* tx stopped */ -#define PN_IMR_TX_NOBUF 0x00000004 /* no tx buffer available */ -#define PN_IMR_TX_JABTIMEO 0x00000008 /* jabber timeout */ -#define PN_IMR_LINKPASS 0x00000010 /* link test pass */ -#define PN_IMR_TX_UNDERRUN 0x00000020 /* transmit underrun */ -#define PN_IMR_RX_OK 0x00000040 /* packet rx ok */ -#define PN_IMR_RX_NOBUF 0x00000080 /* rx buffer unavailable */ -#define PN_IMR_RX_IDLE 0x00000100 /* rx stopped */ -#define PN_IMR_RX_WATCHDOG 0x00000200 /* rx watchdog timeo */ -#define PN_IMR_TX_EARLY 0x00000400 /* rx watchdog timeo */ -#define PN_IMR_BUS_ERR 0x00002000 -#define PN_IMR_ABNORMAL 0x00008000 -#define PN_IMR_NORMAL 0x00010000 -#define PN_ISR_TXABORT 0x04000000 /* tx abort */ - -#define PN_INTRS \ - (PN_IMR_RX_OK|PN_IMR_TX_OK|PN_IMR_RX_NOBUF| \ - PN_IMR_TX_NOBUF|PN_IMR_TX_UNDERRUN|PN_IMR_BUS_ERR| \ - PN_IMR_ABNORMAL|PN_IMR_NORMAL) - -/* - * Serial I/O (EEPROM/ROM) bits. - */ -#define PN_SIO_DATA 0x0000003F -#define PN_SIO_OPCODE 0x00000300 -#define PN_SIO_BUSY 0x80000000 - -/* - * SIOCTL/EEPROM bits - */ -#define PN_EE_READ 0x600 - -/* - * General purpose register bits. - */ -#define PN_GEN_CTL 0x000000F0 -#define PN_GEN_100TX_LINK 0x00000008 -#define PN_GEN_BNC_ENB 0x00000004 -#define PN_GEN_100TX_LOOP 0x00000002 /* 1 == normal, 0 == loop */ -#define PN_GEN_SPEEDSEL 0x00000001 /* 1 == 100Mbps, 0 == 10Mbps */ -#define PN_GEN_MUSTBEONE 0x00000030 - -/* - * General ENDEC bits. - */ -#define PN_ENDEC_JABBERDIS 0x000000001 /* 1 == disable, 0 == enable */ - -/* - * MII bits. - */ -#define PN_MII_DATA 0x0000FFFF -#define PN_MII_REGADDR 0x007C0000 -#define PN_MII_PHYADDR 0x0F800000 -#define PN_MII_OPCODE 0x30000000 -#define PN_MII_RESERVED 0x00020000 -#define PN_MII_BUSY 0x80000000 - -#define PN_MII_READ 0x60020000 /* read PHY command */ -#define PN_MII_WRITE 0x50020000 /* write PHY command */ - -/* - * Internal PHY NWAY register bits. - */ -#define PN_NWAY_RESET 0x00000001 /* reset */ -#define PN_NWAY_PDOWN 0x00000002 /* power down */ -#define PN_NWAY_BYPASS 0x00000004 /* bypass */ -#define PN_NWAY_AUILOWCUR 0x00000008 /* AUI low current */ -#define PN_NWAY_TPEXTEND 0x00000010 /* low squelch voltage */ -#define PN_NWAY_POLARITY 0x00000020 /* 0 == on, 1 == off */ -#define PN_NWAY_TP 0x00000040 /* 1 == tp, 0 == AUI */ -#define PN_NWAY_AUIVOLT 0x00000080 /* 1 == full, 0 == half */ -#define PN_NWAY_DUPLEX 0x00000100 /* 1 == full, 0 == half */ -#define PN_NWAY_LINKTEST 0x00000200 /* 1 == on, 0 == off */ -#define PN_NWAY_AUTODETECT 0x00000400 /* 1 == off, 0 == on */ -#define PN_NWAY_SPEEDSEL 0x00000800 /* 0 == 10, 1 == 100 */ -#define PN_NWAY_NWAY_ENB 0x00001000 /* 0 == off, 1 == on */ -#define PN_NWAY_CAP10HALF 0x00002000 -#define PN_NWAY_CAP10FULL 0x00004000 -#define PN_NWAY_CAP100FULL 0x00008000 -#define PN_NWAY_CAP100HALF 0x00010000 -#define PN_NWAY_CAP100T4 0x00020000 -#define PN_NWAY_AUTONEGRSTR 0x02000000 -#define PN_NWAY_REMFAULT 0x04000000 -#define PN_NWAY_LPAR10HALF 0x08000000 -#define PN_NWAY_LPAR10FULL 0x10000000 -#define PN_NWAY_LPAR100FULL 0x20000000 -#define PN_NWAY_LPAR100HALF 0x40000000 -#define PN_NWAY_LPAR100T4 0x80000000 - -/* - * Size of a setup frame. - */ -#define PN_SFRAME_LEN 192 - -/* - * PNIC TX/RX list structure. - */ - -struct pn_desc { - u_int32_t pn_status; - u_int32_t pn_ctl; - u_int32_t pn_ptr1; - u_int32_t pn_ptr2; -}; - -#define pn_data pn_ptr1 -#define pn_next pn_ptr2 - - -#define RX_RXSTAT_FIFOOFLOW 0x00000001 -#define PN_RXSTAT_CRCERR 0x00000002 -#define PN_RXSTAT_DRIBBLE 0x00000004 -#define PN_RXSTAT_WATCHDOG 0x00000010 -#define PN_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */ -#define PN_RXSTAT_COLLSEEN 0x00000040 -#define PN_RXSTAT_GIANT 0x00000080 -#define PN_RXSTAT_LASTFRAG 0x00000100 -#define PN_RXSTAT_FIRSTFRAG 0x00000200 -#define PN_RXSTAT_MULTICAST 0x00000400 -#define PN_RXSTAT_RUNT 0x00000800 -#define PN_RXSTAT_RXTYPE 0x00003000 -#define PN_RXSTAT_RXERR 0x00008000 -#define PN_RXSTAT_RXLEN 0x7FFF0000 -#define PN_RXSTAT_OWN 0x80000000 - -#define PN_RXBYTES(x) ((x & PN_RXSTAT_RXLEN) >> 16) -#define PN_RXSTAT (PN_RXSTAT_FIRSTFRAG|PN_RXSTAT_LASTFRAG|PN_RXSTAT_OWN) - -#define PN_RXCTL_BUFLEN1 0x00000FFF -#define PN_RXCTL_BUFLEN2 0x00FFF000 -#define PN_RXCTL_RLINK 0x01000000 -#define PN_RXCTL_RLAST 0x02000000 - -#define PN_TXSTAT_DEFER 0x00000001 -#define PN_TXSTAT_UNDERRUN 0x00000002 -#define PN_TXSTAT_LINKFAIL 0x00000003 -#define PN_TXSTAT_COLLCNT 0x00000078 -#define PN_TXSTAT_SQE 0x00000080 -#define PN_TXSTAT_EXCESSCOLL 0x00000100 -#define PN_TXSTAT_LATECOLL 0x00000200 -#define PN_TXSTAT_NOCARRIER 0x00000400 -#define PN_TXSTAT_CARRLOST 0x00000800 -#define PN_TXSTAT_JABTIMEO 0x00004000 -#define PN_TXSTAT_ERRSUM 0x00008000 -#define PN_TXSTAT_OWN 0x80000000 - -#define PN_TXCTL_BUFLEN1 0x000007FF -#define PN_TXCTL_BUFLEN2 0x003FF800 -#define PN_TXCTL_FILTTYPE0 0x00400000 -#define PN_TXCTL_PAD 0x00800000 -#define PN_TXCTL_TLINK 0x01000000 -#define PN_TXCTL_TLAST 0x02000000 -#define PN_TXCTL_NOCRC 0x04000000 -#define PN_TXCTL_SETUP 0x08000000 -#define PN_TXCTL_FILTTYPE1 0x10000000 -#define PN_TXCTL_FIRSTFRAG 0x20000000 -#define PN_TXCTL_LASTFRAG 0x40000000 -#define PN_TXCTL_FINT 0x80000000 - -#define PN_FILTER_PERFECT 0x00000000 -#define PN_FILTER_HASHPERF 0x00400000 -#define PN_FILTER_INVERSE 0x10000000 -#define PN_FILTER_HASHONLY 0x10400000 - -#define PN_MAXFRAGS 16 -#define PN_RX_LIST_CNT 64 -#define PN_TX_LIST_CNT 64 -#define PN_MIN_FRAMELEN 60 -#define PN_FRAMELEN 1536 -#define PN_RXLEN 1518 - -/* - * A tx 'super descriptor' is actually 16 regular descriptors - * back to back. - */ -struct pn_txdesc { - struct pn_desc pn_frag[PN_MAXFRAGS]; -}; - -#define PN_TXNEXT(x) x->pn_ptr->pn_frag[x->pn_lastdesc].pn_next -#define PN_TXSTATUS(x) x->pn_ptr->pn_frag[x->pn_lastdesc].pn_status -#define PN_TXCTL(x) x->pn_ptr->pn_frag[x->pn_lastdesc].pn_ctl -#define PN_TXDATA(x) x->pn_ptr->pn_frag[x->pn_lastdesc].pn_data - -#define PN_TXOWN(x) x->pn_ptr->pn_frag[0].pn_status - -#define PN_UNSENT 0x12344321 - -struct pn_list_data { - struct pn_desc pn_rx_list[PN_RX_LIST_CNT]; - struct pn_txdesc pn_tx_list[PN_TX_LIST_CNT]; -}; - -struct pn_chain { - struct pn_txdesc *pn_ptr; - struct mbuf *pn_mbuf; - struct pn_chain *pn_nextdesc; - u_int8_t pn_lastdesc; -}; - -struct pn_chain_onefrag { - struct pn_desc *pn_ptr; - struct mbuf *pn_mbuf; - struct pn_chain_onefrag *pn_nextdesc; -}; - -struct pn_chain_data { - struct pn_desc pn_sframe; - u_int32_t pn_sbuf[PN_SFRAME_LEN/sizeof(u_int32_t)]; - struct pn_chain_onefrag pn_rx_chain[PN_RX_LIST_CNT]; - struct pn_chain pn_tx_chain[PN_TX_LIST_CNT]; - - struct pn_chain_onefrag *pn_rx_head; - - struct pn_chain *pn_tx_head; - struct pn_chain *pn_tx_tail; - struct pn_chain *pn_tx_free; -}; - -struct pn_type { - u_int16_t pn_vid; - u_int16_t pn_did; - char *pn_name; -}; - -struct pn_mii_frame { - u_int8_t mii_stdelim; - u_int8_t mii_opcode; - u_int8_t mii_phyaddr; - u_int8_t mii_regaddr; - u_int8_t mii_turnaround; - u_int16_t mii_data; -}; - -/* - * MII constants - */ -#define PN_MII_STARTDELIM 0x01 -#define PN_MII_READOP 0x02 -#define PN_MII_WRITEOP 0x01 -#define PN_MII_TURNAROUND 0x02 - -#define PN_FLAG_FORCEDELAY 1 -#define PN_FLAG_SCHEDDELAY 2 -#define PN_FLAG_DELAYTIMEO 3 - -struct pn_softc { - struct arpcom arpcom; /* interface info */ - struct ifmedia ifmedia; /* media info */ - bus_space_handle_t pn_bhandle; /* bus space handle */ - bus_space_tag_t pn_btag; /* bus space tag */ - struct pn_type *pn_info; /* PNIC adapter info */ - struct pn_type *pn_pinfo; /* phy info */ - u_int8_t pn_unit; /* interface number */ - u_int8_t pn_type; - u_int8_t pn_phy_addr; /* PHY address */ - u_int8_t pn_tx_pend; /* TX pending */ - u_int8_t pn_want_auto; - u_int8_t pn_autoneg; - caddr_t pn_ldata_ptr; -#ifdef PN_PROMISC_BUG_WAR -#define PN_169_REV 32 -#define PN_169B_REV 33 - u_int8_t pn_promisc_war; - struct pn_chain_onefrag *pn_promisc_bug_save; - unsigned char *pn_promisc_buf; -#endif - struct pn_list_data *pn_ldata; - struct pn_chain_data pn_cdata; -}; - -/* - * register space access macros - */ -#define CSR_WRITE_4(sc, reg, val) \ - bus_space_write_4(sc->pn_btag, sc->pn_bhandle, reg, val) -#define CSR_WRITE_2(sc, reg, val) \ - bus_space_write_2(sc->pn_btag, sc->pn_bbhandle, reg, val) -#define CSR_WRITE_1(sc, reg, val) \ - bus_space_write_1(sc->pn_btag, sc->pn_bhandle, reg, val) - -#define CSR_READ_4(sc, reg) \ - bus_space_read_4(sc->pn_btag, sc->pn_bhandle, reg) -#define CSR_READ_2(sc, reg) \ - bus_space_read_2(sc->pn_btag, sc->pn_bhandle, reg) -#define CSR_READ_1(sc, reg) \ - bus_space_read_1(sc->pn_btag, sc->pn_bhandle, reg) - -#define PN_TIMEOUT 1000 - -/* - * General constants that are fun to know. - * - * Lite-On PNIC PCI vendor ID - */ -#define PN_VENDORID 0x11AD - -/* - * Lite-On PNIC PCI device ID. - */ -#define PN_DEVICEID_PNIC 0x0002 - -/* - * Texas Instruments PHY identifiers - */ -#define TI_PHY_VENDORID 0x4000 -#define TI_PHY_10BT 0x501F -#define TI_PHY_100VGPMI 0x502F - -/* - * These ID values are for the NS DP83840A 10/100 PHY - */ -#define NS_PHY_VENDORID 0x2000 -#define NS_PHY_83840A 0x5C0F - -/* - * Level 1 10/100 PHY - */ -#define LEVEL1_PHY_VENDORID 0x7810 -#define LEVEL1_PHY_LXT970 0x000F - -/* - * Intel 82555 10/100 PHY - */ -#define INTEL_PHY_VENDORID 0x0A28 -#define INTEL_PHY_82555 0x015F - -/* - * SEEQ 80220 10/100 PHY - */ -#define SEEQ_PHY_VENDORID 0x0016 -#define SEEQ_PHY_80220 0xF83F - - -/* - * PCI low memory base and low I/O base register, and - * other PCI registers. - */ - -#define PN_PCI_VENDOR_ID 0x00 -#define PN_PCI_DEVICE_ID 0x02 -#define PN_PCI_COMMAND 0x04 -#define PN_PCI_STATUS 0x06 -#define PN_PCI_REVISION 0x08 -#define PN_PCI_CLASSCODE 0x09 -#define PN_PCI_LATENCY_TIMER 0x0D -#define PN_PCI_HEADER_TYPE 0x0E -#define PN_PCI_LOIO 0x10 -#define PN_PCI_LOMEM 0x14 -#define PN_PCI_BIOSROM 0x30 -#define PN_PCI_INTLINE 0x3C -#define PN_PCI_INTPIN 0x3D -#define PN_PCI_MINGNT 0x3E -#define PN_PCI_MINLAT 0x0F -#define PN_PCI_RESETOPT 0x48 -#define PN_PCI_EEPROM_DATA 0x4C - -/* power management registers */ -#define PN_PCI_CAPID 0xDC /* 8 bits */ -#define PN_PCI_NEXTPTR 0xDD /* 8 bits */ -#define PN_PCI_PWRMGMTCAP 0xDE /* 16 bits */ -#define PN_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */ - -#define PN_PSTATE_MASK 0x0003 -#define PN_PSTATE_D0 0x0000 -#define PN_PSTATE_D1 0x0002 -#define PN_PSTATE_D2 0x0002 -#define PN_PSTATE_D3 0x0003 -#define PN_PME_EN 0x0010 -#define PN_PME_STATUS 0x8000 - -#define PHY_UNKNOWN 6 - -#define PN_PHYADDR_MIN 0x00 -#define PN_PHYADDR_MAX 0x1F - -#define PHY_BMCR 0x00 -#define PHY_BMSR 0x01 -#define PHY_VENID 0x02 -#define PHY_DEVID 0x03 -#define PHY_ANAR 0x04 -#define PHY_LPAR 0x05 -#define PHY_ANEXP 0x06 - -#define PHY_ANAR_NEXTPAGE 0x8000 -#define PHY_ANAR_RSVD0 0x4000 -#define PHY_ANAR_TLRFLT 0x2000 -#define PHY_ANAR_RSVD1 0x1000 -#define PHY_ANAR_RSVD2 0x0800 -#define PHY_ANAR_RSVD3 0x0400 -#define PHY_ANAR_100BT4 0x0200 -#define PHY_ANAR_100BTXFULL 0x0100 -#define PHY_ANAR_100BTXHALF 0x0080 -#define PHY_ANAR_10BTFULL 0x0040 -#define PHY_ANAR_10BTHALF 0x0020 -#define PHY_ANAR_PROTO4 0x0010 -#define PHY_ANAR_PROTO3 0x0008 -#define PHY_ANAR_PROTO2 0x0004 -#define PHY_ANAR_PROTO1 0x0002 -#define PHY_ANAR_PROTO0 0x0001 - -/* - * These are the register definitions for the PHY (physical layer - * interface chip). - */ -/* - * PHY BMCR Basic Mode Control Register - */ -#define PHY_BMCR_RESET 0x8000 -#define PHY_BMCR_LOOPBK 0x4000 -#define PHY_BMCR_SPEEDSEL 0x2000 -#define PHY_BMCR_AUTONEGENBL 0x1000 -#define PHY_BMCR_RSVD0 0x0800 /* write as zero */ -#define PHY_BMCR_ISOLATE 0x0400 -#define PHY_BMCR_AUTONEGRSTR 0x0200 -#define PHY_BMCR_DUPLEX 0x0100 -#define PHY_BMCR_COLLTEST 0x0080 -#define PHY_BMCR_RSVD1 0x0040 /* write as zero, don't care */ -#define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */ -#define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */ -#define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */ -#define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */ -#define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */ -#define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */ -/* - * RESET: 1 == software reset, 0 == normal operation - * Resets status and control registers to default values. - * Relatches all hardware config values. - * - * LOOPBK: 1 == loopback operation enabled, 0 == normal operation - * - * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s - * Link speed is selected byt his bit or if auto-negotiation if bit - * 12 (AUTONEGENBL) is set (in which case the value of this register - * is ignored). - * - * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled - * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13 - * determine speed and mode. Should be cleared and then set if PHY configured - * for no autoneg on startup. - * - * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation - * - * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation - * - * DUPLEX: 1 == full duplex mode, 0 == half duplex mode - * - * COLLTEST: 1 == collision test enabled, 0 == normal operation - */ - -/* - * PHY, BMSR Basic Mode Status Register - */ -#define PHY_BMSR_100BT4 0x8000 -#define PHY_BMSR_100BTXFULL 0x4000 -#define PHY_BMSR_100BTXHALF 0x2000 -#define PHY_BMSR_10BTFULL 0x1000 -#define PHY_BMSR_10BTHALF 0x0800 -#define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */ -#define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */ -#define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */ -#define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */ -#define PHY_BMSR_MFPRESUP 0x0040 -#define PHY_BMSR_AUTONEGCOMP 0x0020 -#define PHY_BMSR_REMFAULT 0x0010 -#define PHY_BMSR_CANAUTONEG 0x0008 -#define PHY_BMSR_LINKSTAT 0x0004 -#define PHY_BMSR_JABBER 0x0002 -#define PHY_BMSR_EXTENDED 0x0001 diff --git a/sys/pci/if_rl.c b/sys/pci/if_rl.c deleted file mode 100644 index 09a4a99b536b..000000000000 --- a/sys/pci/if_rl.c +++ /dev/null @@ -1,1992 +0,0 @@ -/* - * Copyright (c) 1997, 1998 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_rl.c,v 1.20 1999/01/16 20:46:24 wpaul Exp $ - */ - -/* - * RealTek 8129/8139 PCI NIC driver - * - * Supports several extremely cheap PCI 10/100 adapters based on - * the RealTek chipset. Datasheets can be obtained from - * www.realtek.com.tw. - * - * Written by Bill Paul <wpaul@ctr.columbia.edu> - * Electrical Engineering Department - * Columbia University, New York City - */ - -/* - * The RealTek 8139 PCI NIC redefines the meaning of 'low end.' This is - * probably the worst PCI ethernet controller ever made, with the possible - * exception of the FEAST chip made by SMC. The 8139 supports bus-master - * DMA, but it has a terrible interface that nullifies any performance - * gains that bus-master DMA usually offers. - * - * For transmission, the chip offers a series of four TX descriptor - * registers. Each transmit frame must be in a contiguous buffer, aligned - * on a longword (32-bit) boundary. This means we almost always have to - * do mbuf copies in order to transmit a frame, except in the unlikely - * case where a) the packet fits into a single mbuf, and b) the packet - * is 32-bit aligned within the mbuf's data area. The presence of only - * four descriptor registers means that we can never have more than four - * packets queued for transmission at any one time. - * - * Reception is not much better. The driver has to allocate a single large - * buffer area (up to 64K in size) into which the chip will DMA received - * frames. Because we don't know where within this region received packets - * will begin or end, we have no choice but to copy data from the buffer - * area into mbufs in order to pass the packets up to the higher protocol - * levels. - * - * It's impossible given this rotten design to really achieve decent - * performance at 100Mbps, unless you happen to have a 400Mhz PII or - * some equally overmuscled CPU to drive it. - * - * On the bright side, the 8139 does have a built-in PHY, although - * rather than using an MDIO serial interface like most other NICs, the - * PHY registers are directly accessible through the 8139's register - * space. The 8139 supports autonegotiation, as well as a 64-bit multicast - * filter. - * - * The 8129 chip is an older version of the 8139 that uses an external PHY - * chip. The 8129 has a serial MDIO interface for accessing the MII where - * the 8139 lets you directly access the on-board PHY registers. We need - * to select which interface to use depending on the chip type. - */ - -#include "bpfilter.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/if_arp.h> -#include <net/ethernet.h> -#include <net/if_dl.h> -#include <net/if_media.h> - -#if NBPFILTER > 0 -#include <net/bpf.h> -#endif - -#include <vm/vm.h> /* for vtophys */ -#include <vm/pmap.h> /* for vtophys */ -#include <machine/clock.h> /* for DELAY */ -#include <machine/bus_pio.h> -#include <machine/bus_memio.h> -#include <machine/bus.h> - -#include <pci/pcireg.h> -#include <pci/pcivar.h> - -/* - * Default to using PIO access for this driver. On SMP systems, - * there appear to be problems with memory mapped mode: it looks like - * doing too many memory mapped access back to back in rapid succession - * can hang the bus. I'm inclined to blame this on crummy design/construction - * on the part of RealTek. Memory mapped mode does appear to work on - * uniprocessor systems though. - */ -#define RL_USEIOSPACE - -#include <pci/if_rlreg.h> - -#ifndef lint -static const char rcsid[] = - "$Id: if_rl.c,v 1.20 1999/01/16 20:46:24 wpaul Exp $"; -#endif - -/* - * Various supported device vendors/types and their names. - */ -static struct rl_type rl_devs[] = { - { RT_VENDORID, RT_DEVICEID_8129, - "RealTek 8129 10/100BaseTX" }, - { RT_VENDORID, RT_DEVICEID_8139, - "RealTek 8139 10/100BaseTX" }, - { ACCTON_VENDORID, ACCTON_DEVICEID_5030, - "Accton MPX 5030/5038 10/100BaseTX" }, - { 0, 0, NULL } -}; - -/* - * Various supported PHY vendors/types and their names. Note that - * this driver will work with pretty much any MII-compliant PHY, - * so failure to positively identify the chip is not a fatal error. - */ - -static struct rl_type rl_phys[] = { - { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, - { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, - { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, - { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, - { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, - { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, - { 0, 0, "<MII-compliant physical interface>" } -}; - -static unsigned long rl_count = 0; -static const char *rl_probe __P((pcici_t, pcidi_t)); -static void rl_attach __P((pcici_t, int)); - -static int rl_encap __P((struct rl_softc *, struct rl_chain *, - struct mbuf * )); - -static void rl_rxeof __P((struct rl_softc *)); -static void rl_txeof __P((struct rl_softc *)); -static void rl_txeoc __P((struct rl_softc *)); -static void rl_intr __P((void *)); -static void rl_start __P((struct ifnet *)); -static int rl_ioctl __P((struct ifnet *, u_long, caddr_t)); -static void rl_init __P((void *)); -static void rl_stop __P((struct rl_softc *)); -static void rl_watchdog __P((struct ifnet *)); -static void rl_shutdown __P((int, void *)); -static int rl_ifmedia_upd __P((struct ifnet *)); -static void rl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); - -static void rl_eeprom_putbyte __P((struct rl_softc *, int)); -static void rl_eeprom_getword __P((struct rl_softc *, int, u_int16_t *)); -static void rl_read_eeprom __P((struct rl_softc *, caddr_t, - int, int, int)); -static void rl_mii_sync __P((struct rl_softc *)); -static void rl_mii_send __P((struct rl_softc *, u_int32_t, int)); -static int rl_mii_readreg __P((struct rl_softc *, struct rl_mii_frame *)); -static int rl_mii_writereg __P((struct rl_softc *, struct rl_mii_frame *)); - -static u_int16_t rl_phy_readreg __P((struct rl_softc *, int)); -static void rl_phy_writereg __P((struct rl_softc *, int, int)); - -static void rl_autoneg_xmit __P((struct rl_softc *)); -static void rl_autoneg_mii __P((struct rl_softc *, int, int)); -static void rl_setmode_mii __P((struct rl_softc *, int)); -static void rl_getmode_mii __P((struct rl_softc *)); -static u_int8_t rl_calchash __P((caddr_t)); -static void rl_setmulti __P((struct rl_softc *)); -static void rl_reset __P((struct rl_softc *)); -static int rl_list_tx_init __P((struct rl_softc *)); - -#define EE_SET(x) \ - CSR_WRITE_1(sc, RL_EECMD, \ - CSR_READ_1(sc, RL_EECMD) | x) - -#define EE_CLR(x) \ - CSR_WRITE_1(sc, RL_EECMD, \ - CSR_READ_1(sc, RL_EECMD) & ~x) - -/* - * Send a read command and address to the EEPROM, check for ACK. - */ -static void rl_eeprom_putbyte(sc, addr) - struct rl_softc *sc; - int addr; -{ - register int d, i; - - d = addr | RL_EECMD_READ; - - /* - * Feed in each bit and stobe the clock. - */ - for (i = 0x400; i; i >>= 1) { - if (d & i) { - EE_SET(RL_EE_DATAIN); - } else { - EE_CLR(RL_EE_DATAIN); - } - DELAY(100); - EE_SET(RL_EE_CLK); - DELAY(150); - EE_CLR(RL_EE_CLK); - DELAY(100); - } - - return; -} - -/* - * Read a word of data stored in the EEPROM at address 'addr.' - */ -static void rl_eeprom_getword(sc, addr, dest) - struct rl_softc *sc; - int addr; - u_int16_t *dest; -{ - register int i; - u_int16_t word = 0; - - /* Enter EEPROM access mode. */ - CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); - - /* - * Send address of word we want to read. - */ - rl_eeprom_putbyte(sc, addr); - - CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); - - /* - * Start reading bits from EEPROM. - */ - for (i = 0x8000; i; i >>= 1) { - EE_SET(RL_EE_CLK); - DELAY(100); - if (CSR_READ_1(sc, RL_EECMD) & RL_EE_DATAOUT) - word |= i; - EE_CLR(RL_EE_CLK); - DELAY(100); - } - - /* Turn off EEPROM access mode. */ - CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); - - *dest = word; - - return; -} - -/* - * Read a sequence of words from the EEPROM. - */ -static void rl_read_eeprom(sc, dest, off, cnt, swap) - struct rl_softc *sc; - caddr_t dest; - int off; - int cnt; - int swap; -{ - int i; - u_int16_t word = 0, *ptr; - - for (i = 0; i < cnt; i++) { - rl_eeprom_getword(sc, off + i, &word); - ptr = (u_int16_t *)(dest + (i * 2)); - if (swap) - *ptr = ntohs(word); - else - *ptr = word; - } - - return; -} - - -/* - * MII access routines are provided for the 8129, which - * doesn't have a built-in PHY. For the 8139, we fake things - * up by diverting rl_phy_readreg()/rl_phy_writereg() to the - * direct access PHY registers. - */ -#define MII_SET(x) \ - CSR_WRITE_1(sc, RL_MII, \ - CSR_READ_1(sc, RL_MII) | x) - -#define MII_CLR(x) \ - CSR_WRITE_1(sc, RL_MII, \ - CSR_READ_1(sc, RL_MII) & ~x) - -/* - * Sync the PHYs by setting data bit and strobing the clock 32 times. - */ -static void rl_mii_sync(sc) - struct rl_softc *sc; -{ - register int i; - - MII_SET(RL_MII_DIR|RL_MII_DATAOUT); - - for (i = 0; i < 32; i++) { - MII_SET(RL_MII_CLK); - DELAY(1); - MII_CLR(RL_MII_CLK); - DELAY(1); - } - - return; -} - -/* - * Clock a series of bits through the MII. - */ -static void rl_mii_send(sc, bits, cnt) - struct rl_softc *sc; - u_int32_t bits; - int cnt; -{ - int i; - - MII_CLR(RL_MII_CLK); - - for (i = (0x1 << (cnt - 1)); i; i >>= 1) { - if (bits & i) { - MII_SET(RL_MII_DATAOUT); - } else { - MII_CLR(RL_MII_DATAOUT); - } - DELAY(1); - MII_CLR(RL_MII_CLK); - DELAY(1); - MII_SET(RL_MII_CLK); - } -} - -/* - * Read an PHY register through the MII. - */ -static int rl_mii_readreg(sc, frame) - struct rl_softc *sc; - struct rl_mii_frame *frame; - -{ - int i, ack, s; - - s = splimp(); - - /* - * Set up frame for RX. - */ - frame->mii_stdelim = RL_MII_STARTDELIM; - frame->mii_opcode = RL_MII_READOP; - frame->mii_turnaround = 0; - frame->mii_data = 0; - - CSR_WRITE_2(sc, RL_MII, 0); - - /* - * Turn on data xmit. - */ - MII_SET(RL_MII_DIR); - - rl_mii_sync(sc); - - /* - * Send command/address info. - */ - rl_mii_send(sc, frame->mii_stdelim, 2); - rl_mii_send(sc, frame->mii_opcode, 2); - rl_mii_send(sc, frame->mii_phyaddr, 5); - rl_mii_send(sc, frame->mii_regaddr, 5); - - /* Idle bit */ - MII_CLR((RL_MII_CLK|RL_MII_DATAOUT)); - DELAY(1); - MII_SET(RL_MII_CLK); - DELAY(1); - - /* Turn off xmit. */ - MII_CLR(RL_MII_DIR); - - /* Check for ack */ - MII_CLR(RL_MII_CLK); - DELAY(1); - MII_SET(RL_MII_CLK); - DELAY(1); - ack = CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN; - - /* - * Now try reading data bits. If the ack failed, we still - * need to clock through 16 cycles to keep the PHY(s) in sync. - */ - if (ack) { - for(i = 0; i < 16; i++) { - MII_CLR(RL_MII_CLK); - DELAY(1); - MII_SET(RL_MII_CLK); - DELAY(1); - } - goto fail; - } - - for (i = 0x8000; i; i >>= 1) { - MII_CLR(RL_MII_CLK); - DELAY(1); - if (!ack) { - if (CSR_READ_2(sc, RL_MII) & RL_MII_DATAIN) - frame->mii_data |= i; - DELAY(1); - } - MII_SET(RL_MII_CLK); - DELAY(1); - } - -fail: - - MII_CLR(RL_MII_CLK); - DELAY(1); - MII_SET(RL_MII_CLK); - DELAY(1); - - splx(s); - - if (ack) - return(1); - return(0); -} - -/* - * Write to a PHY register through the MII. - */ -static int rl_mii_writereg(sc, frame) - struct rl_softc *sc; - struct rl_mii_frame *frame; - -{ - int s; - - s = splimp(); - /* - * Set up frame for TX. - */ - - frame->mii_stdelim = RL_MII_STARTDELIM; - frame->mii_opcode = RL_MII_WRITEOP; - frame->mii_turnaround = RL_MII_TURNAROUND; - - /* - * Turn on data output. - */ - MII_SET(RL_MII_DIR); - - rl_mii_sync(sc); - - rl_mii_send(sc, frame->mii_stdelim, 2); - rl_mii_send(sc, frame->mii_opcode, 2); - rl_mii_send(sc, frame->mii_phyaddr, 5); - rl_mii_send(sc, frame->mii_regaddr, 5); - rl_mii_send(sc, frame->mii_turnaround, 2); - rl_mii_send(sc, frame->mii_data, 16); - - /* Idle bit. */ - MII_SET(RL_MII_CLK); - DELAY(1); - MII_CLR(RL_MII_CLK); - DELAY(1); - - /* - * Turn off xmit. - */ - MII_CLR(RL_MII_DIR); - - splx(s); - - return(0); -} - -static u_int16_t rl_phy_readreg(sc, reg) - struct rl_softc *sc; - int reg; -{ - struct rl_mii_frame frame; - u_int16_t rval = 0; - u_int16_t rl8139_reg = 0; - - if (sc->rl_type == RL_8139) { - switch(reg) { - case PHY_BMCR: - rl8139_reg = RL_BMCR; - break; - case PHY_BMSR: - rl8139_reg = RL_BMSR; - break; - case PHY_ANAR: - rl8139_reg = RL_ANAR; - break; - case PHY_LPAR: - rl8139_reg = RL_LPAR; - break; - default: - printf("rl%d: bad phy register\n", sc->rl_unit); - return(0); - } - rval = CSR_READ_2(sc, rl8139_reg); - return(rval); - } - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = sc->rl_phy_addr; - frame.mii_regaddr = reg; - rl_mii_readreg(sc, &frame); - - return(frame.mii_data); -} - -static void rl_phy_writereg(sc, reg, data) - struct rl_softc *sc; - int reg; - int data; -{ - struct rl_mii_frame frame; - u_int16_t rl8139_reg = 0; - - if (sc->rl_type == RL_8139) { - switch(reg) { - case PHY_BMCR: - rl8139_reg = RL_BMCR; - break; - case PHY_BMSR: - rl8139_reg = RL_BMSR; - break; - case PHY_ANAR: - rl8139_reg = RL_ANAR; - break; - case PHY_LPAR: - rl8139_reg = RL_LPAR; - break; - default: - printf("rl%d: bad phy register\n", sc->rl_unit); - return; - } - CSR_WRITE_2(sc, rl8139_reg, data); - return; - } - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = sc->rl_phy_addr; - frame.mii_regaddr = reg; - frame.mii_data = data; - - rl_mii_writereg(sc, &frame); - - return; -} - -/* - * Calculate CRC of a multicast group address, return the lower 6 bits. - */ -static u_int8_t rl_calchash(addr) - caddr_t addr; -{ - u_int32_t crc, carry; - int i, j; - u_int8_t c; - - /* Compute CRC for the address value. */ - crc = 0xFFFFFFFF; /* initial value */ - - for (i = 0; i < 6; i++) { - c = *(addr + i); - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); - crc <<= 1; - c >>= 1; - if (carry) - crc = (crc ^ 0x04c11db6) | carry; - } - } - - /* return the filter bit position */ - return(crc & 0x0000003F); -} - -/* - * Program the 64-bit multicast hash filter. - */ -static void rl_setmulti(sc) - struct rl_softc *sc; -{ - struct ifnet *ifp; - int h = 0; - u_int32_t hashes[2] = { 0, 0 }; - struct ifmultiaddr *ifma; - u_int32_t rxfilt; - int mcnt = 0; - - ifp = &sc->arpcom.ac_if; - - rxfilt = CSR_READ_4(sc, RL_RXCFG); - - if (ifp->if_flags & IFF_ALLMULTI) { - rxfilt |= RL_RXCFG_RX_MULTI; - CSR_WRITE_4(sc, RL_RXCFG, rxfilt); - CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF); - CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF); - return; - } - - /* first, zot all the existing hash bits */ - CSR_WRITE_4(sc, RL_MAR0, 0); - CSR_WRITE_4(sc, RL_MAR4, 0); - - /* now program new ones */ - for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; - ifma = ifma->ifma_link.le_next) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = rl_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - mcnt++; - } - - if (mcnt) - rxfilt |= RL_RXCFG_RX_MULTI; - else - rxfilt &= ~RL_RXCFG_RX_MULTI; - - CSR_WRITE_4(sc, RL_RXCFG, rxfilt); - CSR_WRITE_4(sc, RL_MAR0, hashes[0]); - CSR_WRITE_4(sc, RL_MAR4, hashes[1]); - - return; -} - -/* - * Initiate an autonegotiation session. - */ -static void rl_autoneg_xmit(sc) - struct rl_softc *sc; -{ - u_int16_t phy_sts; - - rl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(rl_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - - phy_sts = rl_phy_readreg(sc, PHY_BMCR); - phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; - rl_phy_writereg(sc, PHY_BMCR, phy_sts); - - return; -} - -/* - * Invoke autonegotiation on a PHY. Also used with the 8139 internal - * transceiver. - */ -static void rl_autoneg_mii(sc, flag, verbose) - struct rl_softc *sc; - int flag; - int verbose; -{ - u_int16_t phy_sts = 0, media, advert, ability; - struct ifnet *ifp; - struct ifmedia *ifm; - - ifm = &sc->ifmedia; - ifp = &sc->arpcom.ac_if; - - /* - * The 100baseT4 PHY sometimes has the 'autoneg supported' - * bit cleared in the status register, but has the 'autoneg enabled' - * bit set in the control register. This is a contradiction, and - * I'm not sure how to handle it. If you want to force an attempt - * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR - * and see what happens. - */ -#ifndef FORCE_AUTONEG_TFOUR - /* - * First, see if autoneg is supported. If not, there's - * no point in continuing. - */ - phy_sts = rl_phy_readreg(sc, PHY_BMSR); - if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { - if (verbose) - printf("rl%d: autonegotiation not supported\n", - sc->rl_unit); - return; - } -#endif - - switch (flag) { - case RL_FLAG_FORCEDELAY: - /* - * XXX Never use this option anywhere but in the probe - * routine: making the kernel stop dead in its tracks - * for three whole seconds after we've gone multi-user - * is really bad manners. - */ - rl_autoneg_xmit(sc); - DELAY(5000000); - break; - case RL_FLAG_SCHEDDELAY: - /* - * Wait for the transmitter to go idle before starting - * an autoneg session, otherwise rl_start() may clobber - * our timeout, and we don't want to allow transmission - * during an autoneg session since that can screw it up. - */ - if (sc->rl_cdata.rl_tx_cnt) { - sc->rl_want_auto = 1; - return; - } - rl_autoneg_xmit(sc); - ifp->if_timer = 5; - sc->rl_autoneg = 1; - sc->rl_want_auto = 0; - return; - break; - case RL_FLAG_DELAYTIMEO: - ifp->if_timer = 0; - sc->rl_autoneg = 0; - break; - default: - printf("rl%d: invalid autoneg flag: %d\n", sc->rl_unit, flag); - return; - } - - if (rl_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { - if (verbose) - printf("rl%d: autoneg complete, ", sc->rl_unit); - phy_sts = rl_phy_readreg(sc, PHY_BMSR); - } else { - if (verbose) - printf("rl%d: autoneg not complete, ", sc->rl_unit); - } - - media = rl_phy_readreg(sc, PHY_BMCR); - - /* Link is good. Report modes and set duplex mode. */ - if (rl_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { - if (verbose) - printf("link status good "); - advert = rl_phy_readreg(sc, PHY_ANAR); - ability = rl_phy_readreg(sc, PHY_LPAR); - - if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { - ifm->ifm_media = IFM_ETHER|IFM_100_T4; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(100baseT4)\n"); - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - media |= PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - media &= ~PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 10Mbps)\n"); - } else { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - media &= ~PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 10Mbps)\n"); - } - - /* Set ASIC's duplex mode to match the PHY. */ - rl_phy_writereg(sc, PHY_BMCR, media); - } else { - if (verbose) - printf("no carrier\n"); - } - - rl_init(sc); - - if (sc->rl_tx_pend) { - sc->rl_autoneg = 0; - sc->rl_tx_pend = 0; - rl_start(ifp); - } - - return; -} - -static void rl_getmode_mii(sc) - struct rl_softc *sc; -{ - u_int16_t bmsr; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - bmsr = rl_phy_readreg(sc, PHY_BMSR); - if (bootverbose) - printf("rl%d: PHY status word: %x\n", sc->rl_unit, bmsr); - - /* fallback */ - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - - if (bmsr & PHY_BMSR_10BTHALF) { - if (bootverbose) - printf("rl%d: 10Mbps half-duplex mode supported\n", - sc->rl_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); - } - - if (bmsr & PHY_BMSR_10BTFULL) { - if (bootverbose) - printf("rl%d: 10Mbps full-duplex mode supported\n", - sc->rl_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - } - - if (bmsr & PHY_BMSR_100BTXHALF) { - if (bootverbose) - printf("rl%d: 100Mbps half-duplex mode supported\n", - sc->rl_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - } - - if (bmsr & PHY_BMSR_100BTXFULL) { - if (bootverbose) - printf("rl%d: 100Mbps full-duplex mode supported\n", - sc->rl_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - } - - /* Some also support 100BaseT4. */ - if (bmsr & PHY_BMSR_100BT4) { - if (bootverbose) - printf("rl%d: 100baseT4 mode supported\n", sc->rl_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4; -#ifdef FORCE_AUTONEG_TFOUR - if (bootverbose) - printf("rl%d: forcing on autoneg support for BT4\n", - sc->rl_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; -#endif - } - - if (bmsr & PHY_BMSR_CANAUTONEG) { - if (bootverbose) - printf("rl%d: autoneg supported\n", sc->rl_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; - } - - return; -} - -/* - * Set speed and duplex mode. - */ -static void rl_setmode_mii(sc, media) - struct rl_softc *sc; - int media; -{ - u_int16_t bmcr; - - printf("rl%d: selecting MII, ", sc->rl_unit); - - bmcr = rl_phy_readreg(sc, PHY_BMCR); - - bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL| - PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); - - if (IFM_SUBTYPE(media) == IFM_100_T4) { - printf("100Mbps/T4, half-duplex\n"); - bmcr |= PHY_BMCR_SPEEDSEL; - bmcr &= ~PHY_BMCR_DUPLEX; - } - - if (IFM_SUBTYPE(media) == IFM_100_TX) { - printf("100Mbps, "); - bmcr |= PHY_BMCR_SPEEDSEL; - } - - if (IFM_SUBTYPE(media) == IFM_10_T) { - printf("10Mbps, "); - bmcr &= ~PHY_BMCR_SPEEDSEL; - } - - if ((media & IFM_GMASK) == IFM_FDX) { - printf("full duplex\n"); - bmcr |= PHY_BMCR_DUPLEX; - } else { - printf("half duplex\n"); - bmcr &= ~PHY_BMCR_DUPLEX; - } - - rl_phy_writereg(sc, PHY_BMCR, bmcr); - - return; -} - -static void rl_reset(sc) - struct rl_softc *sc; -{ - register int i; - - CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RESET); - - for (i = 0; i < RL_TIMEOUT; i++) { - DELAY(10); - if (!(CSR_READ_1(sc, RL_COMMAND) & RL_CMD_RESET)) - break; - } - if (i == RL_TIMEOUT) - printf("rl%d: reset never completed!\n", sc->rl_unit); - - return; -} - -/* - * Probe for a RealTek 8129/8139 chip. Check the PCI vendor and device - * IDs against our list and return a device name if we find a match. - */ -static const char * -rl_probe(config_id, device_id) - pcici_t config_id; - pcidi_t device_id; -{ - struct rl_type *t; - - t = rl_devs; - - while(t->rl_name != NULL) { - if ((device_id & 0xFFFF) == t->rl_vid && - ((device_id >> 16) & 0xFFFF) == t->rl_did) { - return(t->rl_name); - } - t++; - } - - return(NULL); -} - -/* - * Attach the interface. Allocate softc structures, do ifmedia - * setup and ethernet/BPF attach. - */ -static void -rl_attach(config_id, unit) - pcici_t config_id; - int unit; -{ - int s, i; -#ifndef RL_USEIOSPACE - vm_offset_t pbase, vbase; -#endif - u_char eaddr[ETHER_ADDR_LEN]; - u_int32_t command; - struct rl_softc *sc; - struct ifnet *ifp; - int media = IFM_ETHER|IFM_100_TX|IFM_FDX; - struct rl_type *p; - u_int16_t phy_vid, phy_did, phy_sts; - u_int16_t rl_did = 0; - - s = splimp(); - - sc = malloc(sizeof(struct rl_softc), M_DEVBUF, M_NOWAIT); - if (sc == NULL) { - printf("rl%d: no memory for softc struct!\n", unit); - return; - } - bzero(sc, sizeof(struct rl_softc)); - - /* - * Handle power management nonsense. - */ - - command = pci_conf_read(config_id, RL_PCI_CAPID) & 0x000000FF; - if (command == 0x01) { - - command = pci_conf_read(config_id, RL_PCI_PWRMGMTCTRL); - if (command & RL_PSTATE_MASK) { - u_int32_t iobase, membase, irq; - - /* Save important PCI config data. */ - iobase = pci_conf_read(config_id, RL_PCI_LOIO); - membase = pci_conf_read(config_id, RL_PCI_LOMEM); - irq = pci_conf_read(config_id, RL_PCI_INTLINE); - - /* Reset the power state. */ - printf("rl%d: chip is is in D%d power mode " - "-- setting to D0\n", unit, command & RL_PSTATE_MASK); - command &= 0xFFFFFFFC; - pci_conf_write(config_id, RL_PCI_PWRMGMTCTRL, command); - - /* Restore PCI config data. */ - pci_conf_write(config_id, RL_PCI_LOIO, iobase); - pci_conf_write(config_id, RL_PCI_LOMEM, membase); - pci_conf_write(config_id, RL_PCI_INTLINE, irq); - } - } - - /* - * Map control/status registers. - */ - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); - pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - -#ifdef RL_USEIOSPACE - if (!(command & PCIM_CMD_PORTEN)) { - printf("rl%d: failed to enable I/O ports!\n", unit); - free(sc, M_DEVBUF); - goto fail; - } - - if (!pci_map_port(config_id, RL_PCI_LOIO, - (u_int16_t *)&(sc->rl_bhandle))) { - printf ("rl%d: couldn't map ports\n", unit); - goto fail; - } - sc->rl_btag = I386_BUS_SPACE_IO; -#else - if (!(command & PCIM_CMD_MEMEN)) { - printf("rl%d: failed to enable memory mapping!\n", unit); - goto fail; - } - - if (!pci_map_mem(config_id, RL_PCI_LOMEM, &vbase, &pbase)) { - printf ("rl%d: couldn't map memory\n", unit); - goto fail; - } - sc->rl_btag = I386_BUS_SPACE_MEM; - sc->rl_bhandle = vbase; -#endif - - /* Allocate interrupt */ - if (!pci_map_int(config_id, rl_intr, sc, &net_imask)) { - printf("rl%d: couldn't map interrupt\n", unit); - goto fail; - } - - /* Reset the adapter. */ - rl_reset(sc); - - /* - * Get station address from the EEPROM. - */ - rl_read_eeprom(sc, (caddr_t)&eaddr, RL_EE_EADDR, 3, 0); - - /* - * A RealTek chip was detected. Inform the world. - */ - printf("rl%d: Ethernet address: %6D\n", unit, eaddr, ":"); - - sc->rl_unit = unit; - bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); - - /* - * Now read the exact device type from the EEPROM to find - * out if it's an 8129 or 8139. - */ - rl_read_eeprom(sc, (caddr_t)&rl_did, RL_EE_PCI_DID, 1, 0); - - if (rl_did == RT_DEVICEID_8139 || rl_did == ACCTON_DEVICEID_5030) - sc->rl_type = RL_8139; - else if (rl_did == RT_DEVICEID_8129) - sc->rl_type = RL_8129; - else { - printf("rl%d: unknown device ID: %x\n", unit, rl_did); - free(sc, M_DEVBUF); - goto fail; - } - - sc->rl_cdata.rl_rx_buf = contigmalloc(RL_RXBUFLEN + 16, M_DEVBUF, - M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0); - - if (sc->rl_cdata.rl_rx_buf == NULL) { - free(sc, M_DEVBUF); - printf("rl%d: no memory for list buffers!\n", unit); - goto fail; - } - - ifp = &sc->arpcom.ac_if; - ifp->if_softc = sc; - ifp->if_unit = unit; - ifp->if_name = "rl"; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = rl_ioctl; - ifp->if_output = ether_output; - ifp->if_start = rl_start; - ifp->if_watchdog = rl_watchdog; - ifp->if_init = rl_init; - ifp->if_baudrate = 10000000; - - if (sc->rl_type == RL_8129) { - if (bootverbose) - printf("rl%d: probing for a PHY\n", sc->rl_unit); - for (i = RL_PHYADDR_MIN; i < RL_PHYADDR_MAX + 1; i++) { - if (bootverbose) - printf("rl%d: checking address: %d\n", - sc->rl_unit, i); - sc->rl_phy_addr = i; - rl_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(rl_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - if ((phy_sts = rl_phy_readreg(sc, PHY_BMSR))) - break; - } - if (phy_sts) { - phy_vid = rl_phy_readreg(sc, PHY_VENID); - phy_did = rl_phy_readreg(sc, PHY_DEVID); - if (bootverbose) - printf("rl%d: found PHY at address %d, ", - sc->rl_unit, sc->rl_phy_addr); - if (bootverbose) - printf("vendor id: %x device id: %x\n", - phy_vid, phy_did); - p = rl_phys; - while(p->rl_vid) { - if (phy_vid == p->rl_vid && - (phy_did | 0x000F) == p->rl_did) { - sc->rl_pinfo = p; - break; - } - p++; - } - if (sc->rl_pinfo == NULL) - sc->rl_pinfo = &rl_phys[PHY_UNKNOWN]; - if (bootverbose) - printf("rl%d: PHY type: %s\n", - sc->rl_unit, sc->rl_pinfo->rl_name); - } else { - printf("rl%d: MII without any phy!\n", sc->rl_unit); - } - } - - /* - * Do ifmedia setup. - */ - ifmedia_init(&sc->ifmedia, 0, rl_ifmedia_upd, rl_ifmedia_sts); - - rl_getmode_mii(sc); - - /* Choose a default media. */ - media = IFM_ETHER|IFM_AUTO; - ifmedia_set(&sc->ifmedia, media); - - rl_autoneg_mii(sc, RL_FLAG_FORCEDELAY, 1); - - /* - * Call MI attach routines. - */ - if_attach(ifp); - ether_ifattach(ifp); - -#if NBPFILTER > 0 - bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif - at_shutdown(rl_shutdown, sc, SHUTDOWN_POST_SYNC); - -fail: - splx(s); - return; -} - -/* - * Initialize the transmit descriptors. - */ -static int rl_list_tx_init(sc) - struct rl_softc *sc; -{ - struct rl_chain_data *cd; - int i; - - cd = &sc->rl_cdata; - for (i = 0; i < RL_TX_LIST_CNT; i++) { - cd->rl_tx_chain[i].rl_desc = i * 4; - CSR_WRITE_4(sc, RL_TXADDR0 + cd->rl_tx_chain[i].rl_desc, 0); - CSR_WRITE_4(sc, RL_TXSTAT0 + cd->rl_tx_chain[i].rl_desc, 0); - if (i == (RL_TX_LIST_CNT - 1)) - cd->rl_tx_chain[i].rl_next = &cd->rl_tx_chain[0]; - else - cd->rl_tx_chain[i].rl_next = &cd->rl_tx_chain[i + 1]; - } - - sc->rl_cdata.rl_tx_cnt = 0; - cd->rl_tx_cur = cd->rl_tx_free = &cd->rl_tx_chain[0]; - - return(0); -} - -/* - * A frame has been uploaded: pass the resulting mbuf chain up to - * the higher level protocols. - * - * You know there's something wrong with a PCI bus-master chip design - * when you have to use m_devget(). - * - * The receive operation is badly documented in the datasheet, so I'll - * attempt to document it here. The driver provides a buffer area and - * places its base address in the RX buffer start address register. - * The chip then begins copying frames into the RX buffer. Each frame - * is preceeded by a 32-bit RX status word which specifies the length - * of the frame and certain other status bits. Each frame (starting with - * the status word) is also 32-bit aligned. The frame length is in the - * first 16 bits of the status word; the lower 15 bits correspond with - * the 'rx status register' mentioned in the datasheet. - */ -static void rl_rxeof(sc) - struct rl_softc *sc; -{ - struct ether_header *eh; - struct mbuf *m; - struct ifnet *ifp; - int total_len = 0; - u_int32_t rxstat; - caddr_t rxbufpos; - int wrap = 0; - u_int16_t cur_rx; - u_int16_t limit; - u_int16_t rx_bytes = 0, max_bytes; - - ifp = &sc->arpcom.ac_if; - - cur_rx = (CSR_READ_2(sc, RL_CURRXADDR) + 16) % RL_RXBUFLEN; - - /* Do not try to read past this point. */ - limit = CSR_READ_2(sc, RL_CURRXBUF) % RL_RXBUFLEN; - - if (limit < cur_rx) - max_bytes = (RL_RXBUFLEN - cur_rx) + limit; - else - max_bytes = limit - cur_rx; - - while((CSR_READ_1(sc, RL_COMMAND) & RL_CMD_EMPTY_RXBUF) == 0) { - rxbufpos = sc->rl_cdata.rl_rx_buf + cur_rx; - rxstat = *(u_int32_t *)rxbufpos; - - /* - * Here's a totally undocumented fact for you. When the - * RealTek chip is in the process of copying a packet into - * RAM for you, the length will be 0xfff0. If you spot a - * packet header with this value, you need to stop. The - * datasheet makes absolutely no mention of this and - * RealTek should be shot for this. - */ - if ((u_int16_t)(rxstat >> 16) == RL_RXSTAT_UNFINISHED) - break; - - if (!(rxstat & RL_RXSTAT_RXOK)) { - ifp->if_ierrors++; - if (rxstat & (RL_RXSTAT_BADSYM|RL_RXSTAT_RUNT| - RL_RXSTAT_GIANT|RL_RXSTAT_CRCERR| - RL_RXSTAT_ALIGNERR)) { - CSR_WRITE_2(sc, RL_COMMAND, RL_CMD_TX_ENB); - CSR_WRITE_2(sc, RL_COMMAND, RL_CMD_TX_ENB| - RL_CMD_RX_ENB); - CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); - CSR_WRITE_4(sc, RL_RXADDR, - vtophys(sc->rl_cdata.rl_rx_buf)); - CSR_WRITE_2(sc, RL_CURRXADDR, cur_rx - 16); - cur_rx = 0; - } - break; - } - - /* No errors; receive the packet. */ - total_len = rxstat >> 16; - rx_bytes += total_len + 4; - - /* - * XXX The RealTek chip includes the CRC with every - * received frame, and there's no way to turn this - * behavior off (at least, I can't find anything in - * the manual that explains how to do it) so we have - * to trim off the CRC manually. - */ - total_len -= ETHER_CRC_LEN; - - /* - * Avoid trying to read more bytes than we know - * the chip has prepared for us. - */ - if (rx_bytes > max_bytes) - break; - - rxbufpos = sc->rl_cdata.rl_rx_buf + - ((cur_rx + sizeof(u_int32_t)) % RL_RXBUFLEN); - - if (rxbufpos == (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN)) - rxbufpos = sc->rl_cdata.rl_rx_buf; - - wrap = (sc->rl_cdata.rl_rx_buf + RL_RXBUFLEN) - rxbufpos; - - if (total_len > wrap) { - m = m_devget(rxbufpos, wrap, 0, ifp, NULL); - if (m == NULL) { - ifp->if_ierrors++; - printf("rl%d: out of mbufs, tried to " - "copy %d bytes\n", sc->rl_unit, wrap); - } - else - m_copyback(m, wrap, total_len - wrap, - sc->rl_cdata.rl_rx_buf); - cur_rx = (total_len - wrap + ETHER_CRC_LEN); - } else { - m = m_devget(rxbufpos, total_len, 0, ifp, NULL); - if (m == NULL) { - ifp->if_ierrors++; - printf("rl%d: out of mbufs, tried to " - "copy %d bytes\n", sc->rl_unit, total_len); - } - cur_rx += total_len + 4 + ETHER_CRC_LEN; - } - - /* - * Round up to 32-bit boundary. - */ - cur_rx = (cur_rx + 3) & ~3; - CSR_WRITE_2(sc, RL_CURRXADDR, cur_rx - 16); - - if (m == NULL) - continue; - - eh = mtod(m, struct ether_header *); - ifp->if_ipackets++; - -#if NBPFILTER > 0 - /* - * Handle BPF listeners. Let the BPF user see the packet, but - * don't pass it up to the ether_input() layer unless it's - * a broadcast packet, multicast packet, matches our ethernet - * address or the interface is in promiscuous mode. - */ - if (ifp->if_bpf) { - bpf_mtap(ifp, m); - if (ifp->if_flags & IFF_PROMISC && - (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, - ETHER_ADDR_LEN) && - (eh->ether_dhost[0] & 1) == 0)) { - m_freem(m); - continue; - } - } -#endif - /* Remove header from mbuf and pass it on. */ - m_adj(m, sizeof(struct ether_header)); - ether_input(ifp, eh, m); - } - - return; -} - -/* - * A frame was downloaded to the chip. It's safe for us to clean up - * the list buffers. - */ -static void rl_txeof(sc) - struct rl_softc *sc; -{ - struct rl_chain *cur_tx; - struct ifnet *ifp; - u_int32_t txstat; - - ifp = &sc->arpcom.ac_if; - - /* Clear the timeout timer. */ - ifp->if_timer = 0; - - /* - * Go through our tx list and free mbufs for those - * frames that have been uploaded. - */ - if (sc->rl_cdata.rl_tx_free == NULL) - return; - - while(sc->rl_cdata.rl_tx_free->rl_mbuf != NULL) { - cur_tx = sc->rl_cdata.rl_tx_free; - txstat = CSR_READ_4(sc, RL_TXSTAT0 + cur_tx->rl_desc); - - if (!(txstat & RL_TXSTAT_TX_OK)) - break; - - if (txstat & RL_TXSTAT_COLLCNT) - ifp->if_collisions += - (txstat & RL_TXSTAT_COLLCNT) >> 24; - - sc->rl_cdata.rl_tx_free = cur_tx->rl_next; - - sc->rl_cdata.rl_tx_cnt--; - m_freem(cur_tx->rl_mbuf); - cur_tx->rl_mbuf = NULL; - ifp->if_opackets++; - } - - if (!sc->rl_cdata.rl_tx_cnt) { - ifp->if_flags &= ~IFF_OACTIVE; - if (sc->rl_want_auto) - rl_autoneg_mii(sc, RL_FLAG_SCHEDDELAY, 1); - } else { - if (ifp->if_snd.ifq_head != NULL) - rl_start(ifp); - } - - return; -} - -/* - * TX error handler. - */ -static void rl_txeoc(sc) - struct rl_softc *sc; -{ - u_int32_t txstat; - struct rl_chain *cur_tx; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - if (sc->rl_cdata.rl_tx_free == NULL) - return; - - while(sc->rl_cdata.rl_tx_free->rl_mbuf != NULL) { - cur_tx = sc->rl_cdata.rl_tx_free; - txstat = CSR_READ_4(sc, RL_TXSTAT0 + cur_tx->rl_desc); - - if (!(txstat & RL_TXSTAT_OWN)) - break; - - if (!(txstat & RL_TXSTAT_TX_OK)) { - ifp->if_oerrors++; - if (txstat & RL_TXSTAT_COLLCNT) - ifp->if_collisions += - (txstat & RL_TXSTAT_COLLCNT) >> 24; - CSR_WRITE_4(sc, RL_TXADDR0 + cur_tx->rl_desc, - vtophys(mtod(cur_tx->rl_mbuf, caddr_t))); - CSR_WRITE_4(sc, RL_TXSTAT0 + cur_tx->rl_desc, - RL_TX_EARLYTHRESH | - cur_tx->rl_mbuf->m_pkthdr.len); - break; - } else { - if (txstat & RL_TXSTAT_COLLCNT) - ifp->if_collisions += - (txstat & RL_TXSTAT_COLLCNT) >> 24; - sc->rl_cdata.rl_tx_free = cur_tx->rl_next; - - sc->rl_cdata.rl_tx_cnt--; - m_freem(cur_tx->rl_mbuf); - cur_tx->rl_mbuf = NULL; - ifp->if_opackets++; - } - } - - return; -} - -static void rl_intr(arg) - void *arg; -{ - struct rl_softc *sc; - struct ifnet *ifp; - u_int16_t status; - - sc = arg; - ifp = &sc->arpcom.ac_if; - - /* Disable interrupts. */ - CSR_WRITE_2(sc, RL_IMR, 0x0000); - - for (;;) { - - status = CSR_READ_2(sc, RL_ISR); - if (status) - CSR_WRITE_2(sc, RL_ISR, status); - - if ((status & RL_INTRS) == 0) - break; - - if (status & RL_ISR_RX_OK) - rl_rxeof(sc); - - if (status & RL_ISR_RX_ERR) - rl_rxeof(sc); - - if (status & RL_ISR_TX_OK) - rl_txeof(sc); - - if (status & RL_ISR_TX_ERR) - rl_txeoc(sc); - - if (status & RL_ISR_SYSTEM_ERR) { - rl_reset(sc); - rl_init(sc); - } - - } - - /* Re-enable interrupts. */ - CSR_WRITE_2(sc, RL_IMR, RL_INTRS); - - if (ifp->if_snd.ifq_head != NULL) { - rl_start(ifp); - } - - return; -} - -/* - * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data - * pointers to the fragment pointers. - */ -static int rl_encap(sc, c, m_head) - struct rl_softc *sc; - struct rl_chain *c; - struct mbuf *m_head; -{ - struct mbuf *m; - struct mbuf *m_new = NULL; - - /* - * There are two possible encapsulation mechanisms - * that we can use: an efficient one, and a very lossy - * one. The efficient one only happens very rarely, - * whereas the lossy one can and most likely will happen - * all the time. - * The efficient case happens if: - * - the packet fits in a single mbuf - * - the packet is 32-bit aligned within the mbuf data area - * In this case, we can DMA from the mbuf directly. - * The lossy case covers everything else. Bah. - */ - - m = m_head; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("rl%d: no memory for tx list", sc->rl_unit); - return(1); - } - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - printf("rl%d: no memory for tx list", - sc->rl_unit); - return(1); - } - } - m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; - m_freem(m_head); - m_head = m_new; - - /* Pad frames to at least 60 bytes. */ - if (m_head->m_pkthdr.len < RL_MIN_FRAMELEN) { - m_head->m_pkthdr.len += - (RL_MIN_FRAMELEN - m_head->m_pkthdr.len); - m_head->m_len = m_head->m_pkthdr.len; - } - - c->rl_mbuf = m_head; - - return(0); -} - -/* - * Main transmit routine. - */ - -static void rl_start(ifp) - struct ifnet *ifp; -{ - struct rl_softc *sc; - struct mbuf *m_head = NULL; - struct rl_chain *cur_tx = NULL; - - sc = ifp->if_softc; - - if (sc->rl_autoneg) { - sc->rl_tx_pend = 1; - return; - } - - /* - * Check for an available queue slot. If there are none, - * punt. - */ - if (sc->rl_cdata.rl_tx_cur->rl_mbuf != NULL) { - ifp->if_flags |= IFF_OACTIVE; - return; - } - - while(sc->rl_cdata.rl_tx_cur->rl_mbuf == NULL) { - IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) - break; - - - /* Pick a descriptor off the free list. */ - cur_tx = sc->rl_cdata.rl_tx_cur; - sc->rl_cdata.rl_tx_cur = cur_tx->rl_next; - sc->rl_cdata.rl_tx_cnt++; - - /* Pack the data into the descriptor. */ - rl_encap(sc, cur_tx, m_head); - -#if NBPFILTER > 0 - /* - * If there's a BPF listener, bounce a copy of this frame - * to him. - */ - if (ifp->if_bpf) - bpf_mtap(ifp, cur_tx->rl_mbuf); -#endif - /* - * Transmit the frame. - */ - CSR_WRITE_4(sc, RL_TXADDR0 + cur_tx->rl_desc, - vtophys(mtod(cur_tx->rl_mbuf, caddr_t))); - CSR_WRITE_4(sc, RL_TXSTAT0 + cur_tx->rl_desc, - RL_TX_EARLYTHRESH | cur_tx->rl_mbuf->m_pkthdr.len); - } - - /* - * Set a timeout in case the chip goes out to lunch. - */ - ifp->if_timer = 5; - - return; -} - -static void rl_init(xsc) - void *xsc; -{ - struct rl_softc *sc = xsc; - struct ifnet *ifp = &sc->arpcom.ac_if; - int s, i; - u_int32_t rxcfg = 0; - u_int16_t phy_bmcr = 0; - - if (sc->rl_autoneg) - return; - - s = splimp(); - - /* - * XXX Hack for the 8139: the built-in autoneg logic's state - * gets reset by rl_init() when we don't want it to. Try - * to preserve it. (For 8129 cards with real external PHYs, - * the BMCR register doesn't change, but this doesn't hurt.) - */ - if (sc->rl_type == RL_8139) - phy_bmcr = rl_phy_readreg(sc, PHY_BMCR); - - /* - * Cancel pending I/O and free all RX/TX buffers. - */ - rl_stop(sc); - - /* Init our MAC address */ - for (i = 0; i < ETHER_ADDR_LEN; i++) { - CSR_WRITE_1(sc, RL_IDR0 + i, sc->arpcom.ac_enaddr[i]); - } - - /* Init the RX buffer pointer register. */ - CSR_WRITE_4(sc, RL_RXADDR, vtophys(sc->rl_cdata.rl_rx_buf)); - - /* Init TX descriptors. */ - rl_list_tx_init(sc); - - /* - * Enable transmit and receive. - */ - CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); - - /* - * Set the buffer size values. - */ - CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); - - /* Set the individual bit to receive frames for this host only. */ - rxcfg = CSR_READ_4(sc, RL_RXCFG); - rxcfg |= RL_RXCFG_RX_INDIV; - - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) { - rxcfg |= RL_RXCFG_RX_ALLPHYS; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } else { - rxcfg &= ~RL_RXCFG_RX_ALLPHYS; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } - - /* - * Set capture broadcast bit to capture broadcast frames. - */ - if (ifp->if_flags & IFF_BROADCAST) { - rxcfg |= RL_RXCFG_RX_BROAD; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } else { - rxcfg &= ~RL_RXCFG_RX_BROAD; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } - - /* - * Program the multicast filter, if necessary. - */ - rl_setmulti(sc); - - /* - * Enable interrupts. - */ - CSR_WRITE_2(sc, RL_IMR, RL_INTRS); - - /* Start RX/TX process. */ - CSR_WRITE_4(sc, RL_MISSEDPKT, 0); - - /* Enable receiver and transmitter. */ - CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB|RL_CMD_RX_ENB); - - /* Restore state of BMCR */ - if (sc->rl_pinfo != NULL) - rl_phy_writereg(sc, PHY_BMCR, phy_bmcr); - - CSR_WRITE_1(sc, RL_CFG1, RL_CFG1_DRVLOAD|RL_CFG1_FULLDUPLEX); - - ifp->if_flags |= IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - - (void)splx(s); - - return; -} - -/* - * Set media options. - */ -static int rl_ifmedia_upd(ifp) - struct ifnet *ifp; -{ - struct rl_softc *sc; - struct ifmedia *ifm; - - sc = ifp->if_softc; - ifm = &sc->ifmedia; - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return(EINVAL); - - if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) - rl_autoneg_mii(sc, RL_FLAG_SCHEDDELAY, 1); - else - rl_setmode_mii(sc, ifm->ifm_media); - - return(0); -} - -/* - * Report current media status. - */ -static void rl_ifmedia_sts(ifp, ifmr) - struct ifnet *ifp; - struct ifmediareq *ifmr; -{ - struct rl_softc *sc; - u_int16_t advert = 0, ability = 0; - - sc = ifp->if_softc; - - if (!(rl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { - if (rl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) - ifmr->ifm_active = IFM_ETHER|IFM_100_TX; - else - ifmr->ifm_active = IFM_ETHER|IFM_10_T; - - if (rl_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) - ifmr->ifm_active |= IFM_FDX; - else - ifmr->ifm_active |= IFM_HDX; - return; - } - - ability = rl_phy_readreg(sc, PHY_LPAR); - advert = rl_phy_readreg(sc, PHY_ANAR); - if (advert & PHY_ANAR_100BT4 && - ability & PHY_ANAR_100BT4) { - ifmr->ifm_active = IFM_ETHER|IFM_100_T4; - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX; - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX; - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX; - } else if (advert & PHY_ANAR_10BTHALF && - ability & PHY_ANAR_10BTHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX; - } - - return; -} - -static int rl_ioctl(ifp, command, data) - struct ifnet *ifp; - u_long command; - caddr_t data; -{ - struct rl_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; - int s, error = 0; - - s = splimp(); - - switch(command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; - case SIOCSIFFLAGS: - if (ifp->if_flags & IFF_UP) { - rl_init(sc); - } else { - if (ifp->if_flags & IFF_RUNNING) - rl_stop(sc); - } - error = 0; - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - rl_setmulti(sc); - error = 0; - break; - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); - break; - default: - error = EINVAL; - break; - } - - (void)splx(s); - - return(error); -} - -static void rl_watchdog(ifp) - struct ifnet *ifp; -{ - struct rl_softc *sc; - - sc = ifp->if_softc; - - if (sc->rl_autoneg) { - rl_autoneg_mii(sc, RL_FLAG_DELAYTIMEO, 1); - return; - } - - printf("rl%d: watchdog timeout\n", sc->rl_unit); - ifp->if_oerrors++; - if (!(rl_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) - printf("rl%d: no carrier - transceiver cable problem?\n", - sc->rl_unit); - rl_txeoc(sc); - rl_txeof(sc); - rl_rxeof(sc); - rl_init(sc); - - return; -} - -/* - * Stop the adapter and free any mbufs allocated to the - * RX and TX lists. - */ -static void rl_stop(sc) - struct rl_softc *sc; -{ - register int i; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - ifp->if_timer = 0; - - CSR_WRITE_1(sc, RL_COMMAND, 0x00); - CSR_WRITE_2(sc, RL_IMR, 0x0000); - - /* - * Free the TX list buffers. - */ - for (i = 0; i < RL_TX_LIST_CNT; i++) { - if (sc->rl_cdata.rl_tx_chain[i].rl_mbuf != NULL) { - m_freem(sc->rl_cdata.rl_tx_chain[i].rl_mbuf); - sc->rl_cdata.rl_tx_chain[i].rl_mbuf = NULL; - CSR_WRITE_4(sc, RL_TXADDR0 + - sc->rl_cdata.rl_tx_chain[i].rl_desc, 0x00000000); - } - } - - ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - - return; -} - -/* - * Stop all chip I/O so that the kernel's probe routines don't - * get confused by errant DMAs when rebooting. - */ -static void rl_shutdown(howto, arg) - int howto; - void *arg; -{ - struct rl_softc *sc = (struct rl_softc *)arg; - - rl_stop(sc); - - return; -} - - -static struct pci_device rl_device = { - "rl", - rl_probe, - rl_attach, - &rl_count, - NULL -}; -DATA_SET(pcidevice_set, rl_device); diff --git a/sys/pci/if_rlreg.h b/sys/pci/if_rlreg.h deleted file mode 100644 index 5263b5a82052..000000000000 --- a/sys/pci/if_rlreg.h +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright (c) 1997, 1998 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_rlreg.h,v 1.14 1998/12/07 00:16:44 wpaul Exp $ - */ - -/* - * RealTek 8129/8139 register offsets - */ -#define RL_IDR0 0x0000 /* ID register 0 (station addr) */ -#define RL_IDR1 0x0001 /* Must use 32-bit accesses (?) */ -#define RL_IDR2 0x0002 -#define RL_IDR3 0x0003 -#define RL_IDR4 0x0004 -#define RL_IDR5 0x0005 - /* 0006-0007 reserved */ -#define RL_MAR0 0x0008 /* Multicast hash table */ -#define RL_MAR1 0x0009 -#define RL_MAR2 0x000A -#define RL_MAR3 0x000B -#define RL_MAR4 0x000C -#define RL_MAR5 0x000D -#define RL_MAR6 0x000E -#define RL_MAR7 0x000F - -#define RL_TXSTAT0 0x0010 /* status of TX descriptor 0 */ -#define RL_TXSTAT1 0x0014 /* status of TX descriptor 1 */ -#define RL_TXSTAT2 0x0018 /* status of TX descriptor 2 */ -#define RL_TXSTAT3 0x001C /* status of TX descriptor 3 */ - -#define RL_TXADDR0 0x0020 /* address of TX descriptor 0 */ -#define RL_TXADDR1 0x0024 /* address of TX descriptor 1 */ -#define RL_TXADDR2 0x0028 /* address of TX descriptor 2 */ -#define RL_TXADDR3 0x002C /* address of TX descriptor 3 */ - -#define RL_RXADDR 0x0030 /* RX ring start address */ -#define RL_RX_EARLY_BYTES 0x0034 /* RX early byte count */ -#define RL_RX_EARLY_STAT 0x0036 /* RX early status */ -#define RL_COMMAND 0x0037 /* command register */ -#define RL_CURRXADDR 0x0038 /* current address of packet read */ -#define RL_CURRXBUF 0x003A /* current RX buffer address */ -#define RL_IMR 0x003C /* interrupt mask register */ -#define RL_ISR 0x003E /* interrupt status register */ -#define RL_TXCFG 0x0040 /* transmit config */ -#define RL_RXCFG 0x0044 /* receive config */ -#define RL_TIMERCNT 0x0048 /* timer count register */ -#define RL_MISSEDPKT 0x004C /* missed packet counter */ -#define RL_EECMD 0x0050 /* EEPROM command register */ -#define RL_CFG0 0x0051 /* config register #0 */ -#define RL_CFG1 0x0052 /* config register #1 */ - /* 0053-0057 reserved */ -#define RL_MEDIASTAT 0x0058 /* media status register (8139) */ - /* 0059-005A reserved */ -#define RL_MII 0x005A /* 8129 chip only */ -#define RL_HALTCLK 0x005B -#define RL_MULTIINTR 0x005C /* multiple interrupt */ -#define RL_PCIREV 0x005E /* PCI revision value */ - /* 005F reserved */ -#define RL_TXSTAT_ALL 0x0060 /* TX status of all descriptors */ - -/* Direct PHY access registers only available on 8139 */ -#define RL_BMCR 0x0062 /* PHY basic mode control */ -#define RL_BMSR 0x0064 /* PHY basic mode status */ -#define RL_ANAR 0x0066 /* PHY autoneg advert */ -#define RL_LPAR 0x0068 /* PHY link partner ability */ -#define RL_ANER 0x006A /* PHY autoneg expansion */ - -#define RL_DISCCNT 0x006C /* disconnect counter */ -#define RL_FALSECAR 0x006E /* false carrier counter */ -#define RL_NWAYTST 0x0070 /* NWAY test register */ -#define RL_RX_ER 0x0072 /* RX_ER counter */ -#define RL_CSCFG 0x0074 /* CS configuration register */ - - -/* - * TX config register bits - */ -#define RL_TXCFG_CLRABRT 0x00000001 /* retransmit aborted pkt */ -#define RL_TXCFG_MXDMA0 0x00000100 /* max DMA burst size */ -#define RL_TXCFG_MXDMA1 0x00000200 -#define RL_TXCFG_MXDMA2 0x00000400 -#define RL_TXCFG_CRCAPPEND 0x00010000 /* CRC append (0 = yes) */ -#define RL_TXCFG_LOOPBKTST0 0x00020000 /* loopback test */ -#define RL_TXCFG_LOOPBKTST1 0x00040000 /* loopback test */ -#define RL_TXCFG_IFG0 0x01000000 /* interframe gap */ -#define RL_TXCFG_IFG1 0x02000000 /* interframe gap */ - -/* - * Transmit descriptor status register bits. - */ -#define RL_TXSTAT_LENMASK 0x00001FFF -#define RL_TXSTAT_OWN 0x00002000 -#define RL_TXSTAT_TX_UNDERRUN 0x00004000 -#define RL_TXSTAT_TX_OK 0x00008000 -#define RL_TXSTAT_EARLY_THRESH 0x003F0000 -#define RL_TXSTAT_COLLCNT 0x0F000000 -#define RL_TXSTAT_CARR_HBEAT 0x10000000 -#define RL_TXSTAT_OUTOFWIN 0x20000000 -#define RL_TXSTAT_TXABRT 0x40000000 -#define RL_TXSTAT_CARRLOSS 0x80000000 - -/* - * Interrupt status register bits. - */ -#define RL_ISR_RX_OK 0x0001 -#define RL_ISR_RX_ERR 0x0002 -#define RL_ISR_TX_OK 0x0004 -#define RL_ISR_TX_ERR 0x0008 -#define RL_ISR_RX_OVERRUN 0x0010 -#define RL_ISR_PKT_UNDERRUN 0x0020 -#define RL_ISR_FIFO_OFLOW 0x0040 /* 8139 only */ -#define RL_ISR_PCS_TIMEOUT 0x4000 /* 8129 only */ -#define RL_ISR_SYSTEM_ERR 0x8000 - -#define RL_INTRS \ - (RL_ISR_TX_OK|RL_ISR_RX_OK|RL_ISR_RX_ERR|RL_ISR_TX_ERR| \ - RL_ISR_RX_OVERRUN|RL_ISR_PKT_UNDERRUN|RL_ISR_FIFO_OFLOW| \ - RL_ISR_PCS_TIMEOUT|RL_ISR_SYSTEM_ERR) - -/* - * Media status register. (8139 only) - */ -#define RL_MEDIASTAT_RXPAUSE 0x01 -#define RL_MEDIASTAT_TXPAUSE 0x02 -#define RL_MEDIASTAT_LINK 0x04 -#define RL_MEDIASTAT_SPEED10 0x08 -#define RL_MEDIASTAT_RXFLOWCTL 0x40 /* duplex mode */ -#define RL_MEDIASTAT_TXFLOWCTL 0x80 /* duplex mode */ - -/* - * Receive config register. - */ -#define RL_RXCFG_RX_ALLPHYS 0x00000001 /* accept all nodes */ -#define RL_RXCFG_RX_INDIV 0x00000002 /* match filter */ -#define RL_RXCFG_RX_MULTI 0x00000004 /* accept all multicast */ -#define RL_RXCFG_RX_BROAD 0x00000008 /* accept all broadcast */ -#define RL_RXCFG_RX_RUNT 0x00000010 -#define RL_RXCFG_RX_ERRPKT 0x00000020 -#define RL_RXCFG_WRAP 0x00000080 -#define RL_RXCFG_MAXDMA (0x00000100|0x00000200|0x00000400) -#define RL_RXCFG_BUFSZ (0x00000800|0x00001000) -#define RL_RXCFG_FIFOTHRESH (0x00002000|0x00004000|0x00008000) -#define RL_RXCFG_EARLYTHRESH (0x01000000|0x02000000|0x04000000) - -#define RL_RXBUF_8 0x00000000 -#define RL_RXBUF_16 0x00000800 -#define RL_RXBUF_32 0x00001000 -#define RL_RXBUF_64 (0x00001000|0x00000800) - -/* - * Bits in RX status header (included with RX'ed packet - * in ring buffer). - */ -#define RL_RXSTAT_RXOK 0x00000001 -#define RL_RXSTAT_ALIGNERR 0x00000002 -#define RL_RXSTAT_CRCERR 0x00000004 -#define RL_RXSTAT_GIANT 0x00000008 -#define RL_RXSTAT_RUNT 0x00000010 -#define RL_RXSTAT_BADSYM 0x00000020 -#define RL_RXSTAT_BROAD 0x00002000 -#define RL_RXSTAT_INDIV 0x00004000 -#define RL_RXSTAT_MULTI 0x00008000 -#define RL_RXSTAT_LENMASK 0xFFFF0000 - -#define RL_RXSTAT_UNFINISHED 0xFFF0 /* DMA still in progress */ -/* - * Command register. - */ -#define RL_CMD_EMPTY_RXBUF 0x0001 -#define RL_CMD_TX_ENB 0x0004 -#define RL_CMD_RX_ENB 0x0008 -#define RL_CMD_RESET 0x0010 - -/* - * EEPROM control register - */ -#define RL_EE_DATAOUT 0x01 /* Data out */ -#define RL_EE_DATAIN 0x02 /* Data in */ -#define RL_EE_CLK 0x04 /* clock */ -#define RL_EE_SEL 0x08 /* chip select */ -#define RL_EE_MODE (0x40|0x80) - -#define RL_EEMODE_OFF 0x00 -#define RL_EEMODE_AUTOLOAD 0x40 -#define RL_EEMODE_PROGRAM 0x80 -#define RL_EEMODE_WRITECFG (0x80|0x40) - -/* 9346 EEPROM commands */ -#define RL_EECMD_WRITE 0x140 -#define RL_EECMD_READ 0x180 -#define RL_EECMD_ERASE 0x1c0 - -#define RL_EE_ID 0x00 -#define RL_EE_PCI_VID 0x01 -#define RL_EE_PCI_DID 0x02 -/* Location of station address inside EEPROM */ -#define RL_EE_EADDR 0x07 - -/* - * MII register (8129 only) - */ -#define RL_MII_CLK 0x01 -#define RL_MII_DATAIN 0x02 -#define RL_MII_DATAOUT 0x04 -#define RL_MII_DIR 0x80 /* 0 == input, 1 == output */ - -/* - * Config 0 register - */ -#define RL_CFG0_ROM0 0x01 -#define RL_CFG0_ROM1 0x02 -#define RL_CFG0_ROM2 0x04 -#define RL_CFG0_PL0 0x08 -#define RL_CFG0_PL1 0x10 -#define RL_CFG0_10MBPS 0x20 /* 10 Mbps internal mode */ -#define RL_CFG0_PCS 0x40 -#define RL_CFG0_SCR 0x80 - -/* - * Config 1 register - */ -#define RL_CFG1_PWRDWN 0x01 -#define RL_CFG1_SLEEP 0x02 -#define RL_CFG1_IOMAP 0x04 -#define RL_CFG1_MEMMAP 0x08 -#define RL_CFG1_RSVD 0x10 -#define RL_CFG1_DRVLOAD 0x20 -#define RL_CFG1_LED0 0x40 -#define RL_CFG1_FULLDUPLEX 0x40 /* 8129 only */ -#define RL_CFG1_LED1 0x80 - -/* - * The RealTek doesn't use a fragment-based descriptor mechanism. - * Instead, there are only four register sets, each or which represents - * one 'descriptor.' Basically, each TX descriptor is just a contiguous - * packet buffer (32-bit aligned!) and we place the buffer addresses in - * the registers so the chip knows where they are. - * - * We can sort of kludge together the same kind of buffer management - * used in previous drivers, but we have to do buffer copies almost all - * the time, so it doesn't really buy us much. - * - * For reception, there's just one large buffer where the chip stores - * all received packets. - */ - -#define RL_RX_BUF_SZ RL_RXBUF_64 -#define RL_RXBUFLEN (1 << ((RL_RX_BUF_SZ >> 11) + 13)) -#define RL_TX_LIST_CNT 4 -#define RL_MIN_FRAMELEN 60 -#define RL_TX_EARLYTHRESH 0x80000 /* 256 << 11 */ -#define RL_RX_FIFOTHRESH 0x8000 /* 4 << 13 */ -#define RL_RX_MAXDMA 0x00000400 - -#define RL_RXCFG_CONFIG (RL_RX_FIFOTHRESH|RL_RX_BUF_SZ) - -struct rl_chain { - char rl_desc; /* descriptor register idx */ - struct mbuf *rl_mbuf; - struct rl_chain *rl_next; -}; - -struct rl_chain_data { - u_int16_t cur_rx; - caddr_t rl_rx_buf; - struct rl_chain rl_tx_chain[RL_TX_LIST_CNT]; - - int rl_tx_cnt; - struct rl_chain *rl_tx_cur; - struct rl_chain *rl_tx_free; -}; - -struct rl_type { - u_int16_t rl_vid; - u_int16_t rl_did; - char *rl_name; -}; - -struct rl_mii_frame { - u_int8_t mii_stdelim; - u_int8_t mii_opcode; - u_int8_t mii_phyaddr; - u_int8_t mii_regaddr; - u_int8_t mii_turnaround; - u_int16_t mii_data; -}; - -/* - * MII constants - */ -#define RL_MII_STARTDELIM 0x01 -#define RL_MII_READOP 0x02 -#define RL_MII_WRITEOP 0x01 -#define RL_MII_TURNAROUND 0x02 - -#define RL_FLAG_FORCEDELAY 1 -#define RL_FLAG_SCHEDDELAY 2 -#define RL_FLAG_DELAYTIMEO 3 - -#define RL_8129 1 -#define RL_8139 2 - -struct rl_softc { - struct arpcom arpcom; /* interface info */ - struct ifmedia ifmedia; /* media info */ - bus_space_handle_t rl_bhandle; /* bus space handle */ - bus_space_tag_t rl_btag; /* bus space tag */ - struct rl_type *rl_pinfo; /* phy info */ - u_int8_t rl_unit; /* interface number */ - u_int8_t rl_type; - u_int8_t rl_phy_addr; /* PHY address */ - u_int8_t rl_tx_pend; /* TX pending */ - u_int8_t rl_want_auto; - u_int8_t rl_autoneg; - u_int8_t rl_stats_no_timeout; - struct rl_chain_data rl_cdata; -}; - -/* - * register space access macros - */ -#define CSR_WRITE_4(sc, reg, val) \ - bus_space_write_4(sc->rl_btag, sc->rl_bhandle, reg, val) -#define CSR_WRITE_2(sc, reg, val) \ - bus_space_write_2(sc->rl_btag, sc->rl_bhandle, reg, val) -#define CSR_WRITE_1(sc, reg, val) \ - bus_space_write_1(sc->rl_btag, sc->rl_bhandle, reg, val) - -#define CSR_READ_4(sc, reg) \ - bus_space_read_4(sc->rl_btag, sc->rl_bhandle, reg) -#define CSR_READ_2(sc, reg) \ - bus_space_read_2(sc->rl_btag, sc->rl_bhandle, reg) -#define CSR_READ_1(sc, reg) \ - bus_space_read_1(sc->rl_btag, sc->rl_bhandle, reg) - -#define RL_TIMEOUT 1000 - -/* - * General constants that are fun to know. - * - * RealTek PCI vendor ID - */ -#define RT_VENDORID 0x10EC - -/* - * Accton PCI vendor ID - */ -#define ACCTON_VENDORID 0x1113 - -/* - * RealTek chip device IDs. - */ -#define RT_DEVICEID_8129 0x8129 -#define RT_DEVICEID_8139 0x8139 - -/* - * Accton MPX 5030/5038 device ID. - */ -#define ACCTON_DEVICEID_5030 0x1211 - -/* - * Texas Instruments PHY identifiers - */ -#define TI_PHY_VENDORID 0x4000 -#define TI_PHY_10BT 0x501F -#define TI_PHY_100VGPMI 0x502F - -/* - * These ID values are for the NS DP83840A 10/100 PHY - */ -#define NS_PHY_VENDORID 0x2000 -#define NS_PHY_83840A 0x5C0F - -/* - * Level 1 10/100 PHY - */ -#define LEVEL1_PHY_VENDORID 0x7810 -#define LEVEL1_PHY_LXT970 0x000F - -/* - * Intel 82555 10/100 PHY - */ -#define INTEL_PHY_VENDORID 0x0A28 -#define INTEL_PHY_82555 0x015F - -/* - * SEEQ 80220 10/100 PHY - */ -#define SEEQ_PHY_VENDORID 0x0016 -#define SEEQ_PHY_80220 0xF83F - - -/* - * PCI low memory base and low I/O base register, and - * other PCI registers. Note: some are only available on - * the 3c905B, in particular those that related to power management. - */ - -#define RL_PCI_VENDOR_ID 0x00 -#define RL_PCI_DEVICE_ID 0x02 -#define RL_PCI_COMMAND 0x04 -#define RL_PCI_STATUS 0x06 -#define RL_PCI_CLASSCODE 0x09 -#define RL_PCI_LATENCY_TIMER 0x0D -#define RL_PCI_HEADER_TYPE 0x0E -#define RL_PCI_LOIO 0x10 -#define RL_PCI_LOMEM 0x14 -#define RL_PCI_BIOSROM 0x30 -#define RL_PCI_INTLINE 0x3C -#define RL_PCI_INTPIN 0x3D -#define RL_PCI_MINGNT 0x3E -#define RL_PCI_MINLAT 0x0F -#define RL_PCI_RESETOPT 0x48 -#define RL_PCI_EEPROM_DATA 0x4C - -#define RL_PCI_CAPID 0xDC /* 8 bits */ -#define RL_PCI_NEXTPTR 0xDD /* 8 bits */ -#define RL_PCI_PWRMGMTCAP 0xDE /* 16 bits */ -#define RL_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */ - -#define RL_PSTATE_MASK 0x0003 -#define RL_PSTATE_D0 0x0000 -#define RL_PSTATE_D1 0x0002 -#define RL_PSTATE_D2 0x0002 -#define RL_PSTATE_D3 0x0003 -#define RL_PME_EN 0x0010 -#define RL_PME_STATUS 0x8000 - -#define PHY_UNKNOWN 6 - -#define RL_PHYADDR_MIN 0x00 -#define RL_PHYADDR_MAX 0x1F - -#define PHY_BMCR 0x00 -#define PHY_BMSR 0x01 -#define PHY_VENID 0x02 -#define PHY_DEVID 0x03 -#define PHY_ANAR 0x04 -#define PHY_LPAR 0x05 -#define PHY_ANEXP 0x06 - -#define PHY_ANAR_NEXTPAGE 0x8000 -#define PHY_ANAR_RSVD0 0x4000 -#define PHY_ANAR_TLRFLT 0x2000 -#define PHY_ANAR_RSVD1 0x1000 -#define PHY_ANAR_RSVD2 0x0800 -#define PHY_ANAR_RSVD3 0x0400 -#define PHY_ANAR_100BT4 0x0200 -#define PHY_ANAR_100BTXFULL 0x0100 -#define PHY_ANAR_100BTXHALF 0x0080 -#define PHY_ANAR_10BTFULL 0x0040 -#define PHY_ANAR_10BTHALF 0x0020 -#define PHY_ANAR_PROTO4 0x0010 -#define PHY_ANAR_PROTO3 0x0008 -#define PHY_ANAR_PROTO2 0x0004 -#define PHY_ANAR_PROTO1 0x0002 -#define PHY_ANAR_PROTO0 0x0001 - -/* - * These are the register definitions for the PHY (physical layer - * interface chip). - */ -/* - * PHY BMCR Basic Mode Control Register - */ -#define PHY_BMCR_RESET 0x8000 -#define PHY_BMCR_LOOPBK 0x4000 -#define PHY_BMCR_SPEEDSEL 0x2000 -#define PHY_BMCR_AUTONEGENBL 0x1000 -#define PHY_BMCR_RSVD0 0x0800 /* write as zero */ -#define PHY_BMCR_ISOLATE 0x0400 -#define PHY_BMCR_AUTONEGRSTR 0x0200 -#define PHY_BMCR_DUPLEX 0x0100 -#define PHY_BMCR_COLLTEST 0x0080 -#define PHY_BMCR_RSVD1 0x0040 /* write as zero, don't care */ -#define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */ -#define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */ -#define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */ -#define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */ -#define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */ -#define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */ -/* - * RESET: 1 == software reset, 0 == normal operation - * Resets status and control registers to default values. - * Relatches all hardware config values. - * - * LOOPBK: 1 == loopback operation enabled, 0 == normal operation - * - * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s - * Link speed is selected byt his bit or if auto-negotiation if bit - * 12 (AUTONEGENBL) is set (in which case the value of this register - * is ignored). - * - * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled - * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13 - * determine speed and mode. Should be cleared and then set if PHY configured - * for no autoneg on startup. - * - * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation - * - * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation - * - * DUPLEX: 1 == full duplex mode, 0 == half duplex mode - * - * COLLTEST: 1 == collision test enabled, 0 == normal operation - */ - -/* - * PHY, BMSR Basic Mode Status Register - */ -#define PHY_BMSR_100BT4 0x8000 -#define PHY_BMSR_100BTXFULL 0x4000 -#define PHY_BMSR_100BTXHALF 0x2000 -#define PHY_BMSR_10BTFULL 0x1000 -#define PHY_BMSR_10BTHALF 0x0800 -#define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */ -#define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */ -#define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */ -#define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */ -#define PHY_BMSR_MFPRESUP 0x0040 -#define PHY_BMSR_AUTONEGCOMP 0x0020 -#define PHY_BMSR_REMFAULT 0x0010 -#define PHY_BMSR_CANAUTONEG 0x0008 -#define PHY_BMSR_LINKSTAT 0x0004 -#define PHY_BMSR_JABBER 0x0002 -#define PHY_BMSR_EXTENDED 0x0001 diff --git a/sys/pci/if_sr_p.c b/sys/pci/if_sr_p.c index 41a5ec3f2cbd..02a32e089f39 100644 --- a/sys/pci/if_sr_p.c +++ b/sys/pci/if_sr_p.c @@ -27,7 +27,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: if_sr_p.c,v 1.6 1998/02/09 06:10:52 eivind Exp $ + * $Id: if_sr_p.c,v 1.5 1997/09/02 20:06:27 bde Exp $ */ #include "pci.h" @@ -54,7 +54,7 @@ extern void *srattach_pci(int unit, vm_offset_t sca_vaddr); extern void srintr_hc(void *hc); -static const char *sr_pci_probe(pcici_t tag, pcidi_t type); +static char *sr_pci_probe(pcici_t tag, pcidi_t type); static void sr_pci_attach(pcici_t config_id, int unit); static u_long src_count = NSR; @@ -69,7 +69,7 @@ static struct pci_device sr_pci_driver = DATA_SET (pcidevice_set, sr_pci_driver); -static const char * +static char * sr_pci_probe(pcici_t tag, pcidi_t type) { switch(type) { diff --git a/sys/pci/if_tl.c b/sys/pci/if_tl.c index b202fb5de8db..abf68c9e2b82 100644 --- a/sys/pci/if_tl.c +++ b/sys/pci/if_tl.c @@ -29,7 +29,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: if_tl.c,v 1.23 1998/12/14 06:32:56 dillon Exp $ + * $Id: if_tl.c,v 1.17 1998/10/04 18:47:38 wpaul Exp $ */ /* @@ -216,9 +216,9 @@ #include <pci/if_tlreg.h> -#if !defined(lint) -static const char rcsid[] = - "$Id: if_tl.c,v 1.23 1998/12/14 06:32:56 dillon Exp $"; +#ifndef lint +static char rcsid[] = + "$Id: if_tl.c,v 1.17 1998/10/04 18:47:38 wpaul Exp $"; #endif #ifdef TL_DEBUG @@ -316,7 +316,7 @@ static struct tl_type tl_phys[] = { static unsigned long tl_count; -static const char *tl_probe __P((pcici_t, pcidi_t)); +static char *tl_probe __P((pcici_t, pcidi_t)); static void tl_attach __P((pcici_t, int)); static int tl_attach_phy __P((struct tl_softc *)); static int tl_intvec_rxeoc __P((void *, u_int32_t)); @@ -342,9 +342,9 @@ static void tl_shutdown __P((int, void *)); static int tl_ifmedia_upd __P((struct ifnet *)); static void tl_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); -static u_int8_t tl_eeprom_putbyte __P((struct tl_softc *, int)); +static u_int8_t tl_eeprom_putbyte __P((struct tl_softc *, u_int8_t)); static u_int8_t tl_eeprom_getbyte __P((struct tl_softc *, - int, u_int8_t *)); + u_int8_t, u_int8_t *)); static int tl_read_eeprom __P((struct tl_softc *, caddr_t, int, int)); static void tl_mii_sync __P((struct tl_softc *)); @@ -352,57 +352,57 @@ static void tl_mii_send __P((struct tl_softc *, u_int32_t, int)); static int tl_mii_readreg __P((struct tl_softc *, struct tl_mii_frame *)); static int tl_mii_writereg __P((struct tl_softc *, struct tl_mii_frame *)); static u_int16_t tl_phy_readreg __P((struct tl_softc *, int)); -static void tl_phy_writereg __P((struct tl_softc *, int, int)); +static void tl_phy_writereg __P((struct tl_softc *, u_int16_t, u_int16_t)); static void tl_autoneg __P((struct tl_softc *, int, int)); static void tl_setmode __P((struct tl_softc *, int)); -static int tl_calchash __P((caddr_t)); +static int tl_calchash __P((unsigned char *)); static void tl_setmulti __P((struct tl_softc *)); -static void tl_setfilt __P((struct tl_softc *, caddr_t, int)); +static void tl_setfilt __P((struct tl_softc *, u_int8_t *, int)); static void tl_softreset __P((struct tl_softc *, int)); static void tl_hardreset __P((struct tl_softc *)); static int tl_list_rx_init __P((struct tl_softc *)); static int tl_list_tx_init __P((struct tl_softc *)); -static u_int8_t tl_dio_read8 __P((struct tl_softc *, int)); -static u_int16_t tl_dio_read16 __P((struct tl_softc *, int)); -static u_int32_t tl_dio_read32 __P((struct tl_softc *, int)); -static void tl_dio_write8 __P((struct tl_softc *, int, int)); -static void tl_dio_write16 __P((struct tl_softc *, int, int)); -static void tl_dio_write32 __P((struct tl_softc *, int, int)); -static void tl_dio_setbit __P((struct tl_softc *, int, int)); -static void tl_dio_clrbit __P((struct tl_softc *, int, int)); -static void tl_dio_setbit16 __P((struct tl_softc *, int, int)); -static void tl_dio_clrbit16 __P((struct tl_softc *, int, int)); +static u_int8_t tl_dio_read8 __P((struct tl_softc *, u_int8_t)); +static u_int16_t tl_dio_read16 __P((struct tl_softc *, u_int8_t)); +static u_int32_t tl_dio_read32 __P((struct tl_softc *, u_int8_t)); +static void tl_dio_write8 __P((struct tl_softc *, u_int8_t, u_int8_t)); +static void tl_dio_write16 __P((struct tl_softc *, u_int8_t, u_int16_t)); +static void tl_dio_write32 __P((struct tl_softc *, u_int8_t, u_int32_t)); +static void tl_dio_setbit __P((struct tl_softc *, u_int8_t, u_int8_t)); +static void tl_dio_clrbit __P((struct tl_softc *, u_int8_t, u_int8_t)); +static void tl_dio_setbit16 __P((struct tl_softc *, u_int8_t, u_int16_t)); +static void tl_dio_clrbit16 __P((struct tl_softc *, u_int8_t, u_int16_t)); static u_int8_t tl_dio_read8(sc, reg) - struct tl_softc *sc; - int reg; + struct tl_softc *sc; + u_int8_t reg; { CSR_WRITE_2(sc, TL_DIO_ADDR, reg); return(CSR_READ_1(sc, TL_DIO_DATA + (reg & 3))); } static u_int16_t tl_dio_read16(sc, reg) - struct tl_softc *sc; - int reg; + struct tl_softc *sc; + u_int8_t reg; { CSR_WRITE_2(sc, TL_DIO_ADDR, reg); return(CSR_READ_2(sc, TL_DIO_DATA + (reg & 3))); } static u_int32_t tl_dio_read32(sc, reg) - struct tl_softc *sc; - int reg; + struct tl_softc *sc; + u_int8_t reg; { CSR_WRITE_2(sc, TL_DIO_ADDR, reg); return(CSR_READ_4(sc, TL_DIO_DATA + (reg & 3))); } static void tl_dio_write8(sc, reg, val) - struct tl_softc *sc; - int reg; - int val; + struct tl_softc *sc; + u_int8_t reg; + u_int8_t val; { CSR_WRITE_2(sc, TL_DIO_ADDR, reg); CSR_WRITE_1(sc, TL_DIO_DATA + (reg & 3), val); @@ -410,9 +410,9 @@ static void tl_dio_write8(sc, reg, val) } static void tl_dio_write16(sc, reg, val) - struct tl_softc *sc; - int reg; - int val; + struct tl_softc *sc; + u_int8_t reg; + u_int16_t val; { CSR_WRITE_2(sc, TL_DIO_ADDR, reg); CSR_WRITE_2(sc, TL_DIO_DATA + (reg & 3), val); @@ -420,9 +420,9 @@ static void tl_dio_write16(sc, reg, val) } static void tl_dio_write32(sc, reg, val) - struct tl_softc *sc; - int reg; - int val; + struct tl_softc *sc; + u_int8_t reg; + u_int32_t val; { CSR_WRITE_2(sc, TL_DIO_ADDR, reg); CSR_WRITE_4(sc, TL_DIO_DATA + (reg & 3), val); @@ -430,9 +430,9 @@ static void tl_dio_write32(sc, reg, val) } static void tl_dio_setbit(sc, reg, bit) - struct tl_softc *sc; - int reg; - int bit; + struct tl_softc *sc; + u_int8_t reg; + u_int8_t bit; { u_int8_t f; @@ -445,9 +445,9 @@ static void tl_dio_setbit(sc, reg, bit) } static void tl_dio_clrbit(sc, reg, bit) - struct tl_softc *sc; - int reg; - int bit; + struct tl_softc *sc; + u_int8_t reg; + u_int8_t bit; { u_int8_t f; @@ -460,9 +460,9 @@ static void tl_dio_clrbit(sc, reg, bit) } static void tl_dio_setbit16(sc, reg, bit) - struct tl_softc *sc; - int reg; - int bit; + struct tl_softc *sc; + u_int8_t reg; + u_int16_t bit; { u_int16_t f; @@ -475,9 +475,9 @@ static void tl_dio_setbit16(sc, reg, bit) } static void tl_dio_clrbit16(sc, reg, bit) - struct tl_softc *sc; - int reg; - int bit; + struct tl_softc *sc; + u_int8_t reg; + u_int16_t bit; { u_int16_t f; @@ -494,7 +494,7 @@ static void tl_dio_clrbit16(sc, reg, bit) */ static u_int8_t tl_eeprom_putbyte(sc, byte) struct tl_softc *sc; - int byte; + u_int8_t byte; { register int i, ack = 0; @@ -538,7 +538,7 @@ static u_int8_t tl_eeprom_putbyte(sc, byte) */ static u_int8_t tl_eeprom_getbyte(sc, addr, dest) struct tl_softc *sc; - int addr; + u_int8_t addr; u_int8_t *dest; { register int i; @@ -827,8 +827,8 @@ static u_int16_t tl_phy_readreg(sc, reg) static void tl_phy_writereg(sc, reg, data) struct tl_softc *sc; - int reg; - int data; + u_int16_t reg; + u_int16_t data; { struct tl_mii_frame frame; @@ -1145,7 +1145,7 @@ static void tl_setmode(sc, media) * the folded 24-bit value is split into 6-bit portions and XOR'd. */ static int tl_calchash(addr) - caddr_t addr; + unsigned char *addr; { int t; @@ -1163,7 +1163,7 @@ static int tl_calchash(addr) */ static void tl_setfilt(sc, addr, slot) struct tl_softc *sc; - caddr_t addr; + u_int8_t *addr; int slot; { int i; @@ -1205,7 +1205,7 @@ static void tl_setmulti(sc) /* First, zot all the existing filters. */ for (i = 1; i < 4; i++) - tl_setfilt(sc, (caddr_t)&dummy, i); + tl_setfilt(sc, dummy, i); tl_dio_write32(sc, TL_HASH1, 0); tl_dio_write32(sc, TL_HASH2, 0); @@ -1365,7 +1365,7 @@ static void tl_softreset(sc, internal) * Probe for a ThunderLAN chip. Check the PCI vendor and device IDs * against our list and return its name if we find a match. */ -static const char * +static char * tl_probe(config_id, device_id) pcici_t config_id; pcidi_t device_id; @@ -1823,12 +1823,12 @@ static int tl_list_rx_init(sc) cd = &sc->tl_cdata; ld = sc->tl_ldata; - for (i = 0; i < TL_RX_LIST_CNT; i++) { + for (i = 0; i < TL_TX_LIST_CNT; i++) { cd->tl_rx_chain[i].tl_ptr = (struct tl_list_onefrag *)&ld->tl_rx_list[i]; if (tl_newbuf(sc, &cd->tl_rx_chain[i]) == ENOBUFS) return(ENOBUFS); - if (i == (TL_RX_LIST_CNT - 1)) { + if (i == (TL_TX_LIST_CNT - 1)) { cd->tl_rx_chain[i].tl_next = NULL; ld->tl_rx_list[i].tlist_fptr = 0; } else { @@ -2129,7 +2129,7 @@ static int tl_intvec_adchk(xsc, type) if (type) printf("tl%d: adapter check: %x\n", sc->tl_unit, - (unsigned int)CSR_READ_4(sc, TL_CH_PARM)); + CSR_READ_4(sc, TL_CH_PARM)); #ifdef TL_DEBUG evshow(sc); #endif @@ -2440,12 +2440,6 @@ static void tl_start(ifp) } /* - * If there are no packets queued, bail. - */ - if (cur_tx == NULL) - return; - - /* * That's all we can stands, we can't stands no more. * If there are no other transfers pending, then issue the * TX GO command to the adapter to start things moving. @@ -2475,7 +2469,7 @@ static void tl_start(ifp) evset(sc, EV_START_Q); #endif sc->tl_cdata.tl_tx_tail->tl_next = start_tx; - sc->tl_cdata.tl_tx_tail = cur_tx; + sc->tl_cdata.tl_tx_tail = start_tx; } /* @@ -2527,7 +2521,7 @@ static void tl_init(xsc) tl_dio_setbit(sc, TL_NETCMD, TL_CMD_NOBRX); /* Init our MAC address */ - tl_setfilt(sc, (caddr_t)&sc->arpcom.ac_enaddr, 0); + tl_setfilt(sc, sc->arpcom.ac_enaddr, 0); /* Init multicast filter, if needed. */ tl_setmulti(sc); diff --git a/sys/pci/if_tlreg.h b/sys/pci/if_tlreg.h index b8b3769f7bbf..a9b80ea64415 100644 --- a/sys/pci/if_tlreg.h +++ b/sys/pci/if_tlreg.h @@ -29,7 +29,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: if_tlreg.h,v 1.6 1998/09/23 05:08:54 wpaul Exp $ + * $Id: if_tlreg.h,v 1.12 1998/09/17 21:16:31 wpaul Exp $ */ @@ -49,8 +49,8 @@ struct tl_type { */ #define TL_MAXFRAGS 10 -#define TL_RX_LIST_CNT 20 -#define TL_TX_LIST_CNT 20 +#define TL_RX_LIST_CNT 10 +#define TL_TX_LIST_CNT 10 #define TL_MIN_FRAMELEN 64 struct tl_frag { @@ -141,7 +141,7 @@ struct tl_softc { /* * Transmit interrupt threshold. */ -#define TX_THR 0x00000004 +#define TX_THR 0x00000001 #define TL_FLAG_FORCEDELAY 1 #define TL_FLAG_SCHEDDELAY 2 diff --git a/sys/pci/if_tx.c b/sys/pci/if_tx.c index a79ebebf602c..56a176ba8f74 100644 --- a/sys/pci/if_tx.c +++ b/sys/pci/if_tx.c @@ -1,6 +1,3 @@ -/* $OpenBSD: if_tx.c,v 1.3 1998/10/10 04:30:09 jason Exp $ */ -/* $Id: if_tx.c,v 1.19 1998/12/09 01:12:18 eivind Exp $ */ - /*- * Copyright (c) 1997 Semen Ustimenko (semen@iclub.nsu.ru) * All rights reserved. @@ -26,27 +23,30 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id: if_tx.c,v 1.14 1998/07/13 09:53:07 bde Exp $ * */ /* * EtherPower II 10/100 Fast Ethernet (tx0) * (aka SMC9432TX based on SMC83c170 EPIC chip) - * - * Thanks are going to Steve Bauer and Jason Wright. * - * todo: + * TODO: + * Deal with TX threshold (probably we should calculate it depending + * on processor speed, as did the MS-DOS driver). * Deal with bus mastering, i.e. i realy don't know what to do with * it and how it can improve performance. * Implement FULL IFF_MULTICAST support. - * Test, test and test again:-( + * Calculate optimal RX and TX rings size. + * Test, test and test again:-) * */ -/* We should define compile time options before if_txvar.h included */ +/* We should define compile time options before smc83c170.h included */ /*#define EPIC_NOIFMEDIA 1*/ /*#define EPIC_USEIOSPACE 1*/ -#define EARLY_RX 1 +/*#define EARLY_RX 1*/ +/*#define EARLY_TX 1*/ /*#define EPIC_DEBUG 1*/ #if defined(EPIC_DEBUG) @@ -67,65 +67,20 @@ } \ } -#include "bpfilter.h" #include "pci.h" - #if NPCI > 0 + #include <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.h> +#include <sys/socket.h> #include <sys/malloc.h> #include <sys/kernel.h> -#include <sys/socket.h> #include <sys/sockio.h> - #include <net/if.h> -#include <net/if_dl.h> -#include <net/if_types.h> - -#if !defined(SIOCSIFMEDIA) || defined(EPIC_NOIFMEDIA) -#define EPIC_NOIFMEDIA 1 -#else +#if defined(SIOCSIFMEDIA) && !defined(EPIC_NOIFMEDIA) #include <net/if_media.h> #endif - -#ifdef INET -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> -#endif - -#ifdef IPX -#include <netipx/ipx.h> -#include <netipx/ipx_if.h> -#endif - -#ifdef NS -#include <netns/ns.h> -#include <netns/ns_if.h> -#endif - -#if NBPFILTER > 0 -#include <net/bpf.h> -#include <net/bpfdesc.h> -#endif - -#if defined(__OpenBSD__) -#include <sys/ioctl.h> -#include <sys/errno.h> -#include <sys/device.h> - -#include <netinet/if_ether.h> - -#include <vm/vm.h> - -#include <dev/pci/pcivar.h> -#include <dev/pci/pcireg.h> -#include <dev/pci/pcidevs.h> - -#include <dev/pci/if_txvar.h> -#else /* __FreeBSD__ */ #include <net/if_mib.h> #include <netinet/in.h> #include <netinet/if_ether.h> @@ -134,492 +89,51 @@ #include <machine/clock.h> #include <pci/pcivar.h> -#include <pci/if_txvar.h> -#endif - -#if defined(__FreeBSD__) -#if __FreeBSD_version >= 300000 -#define EPIC_IFIOCTL_CMD_TYPE u_long -#else -#define EPIC_IFIOCTL_CMD_TYPE int -#endif -#define EPIC_INTR_RET_TYPE void -#else /* __OpenBSD__ */ -#define EPIC_IFIOCTL_CMD_TYPE u_long -#define EPIC_INTR_RET_TYPE int -#endif - -static int epic_ifioctl __P((register struct ifnet *, EPIC_IFIOCTL_CMD_TYPE, caddr_t)); -static EPIC_INTR_RET_TYPE epic_intr __P((void *)); -static int epic_common_attach __P((epic_softc_t *)); -static void epic_ifstart __P((struct ifnet * const)); -static void epic_ifwatchdog __P((struct ifnet *)); -static int epic_init __P((epic_softc_t *)); -static void epic_stop __P((epic_softc_t *)); -static __inline void epic_rx_done __P((epic_softc_t *)); -static __inline void epic_tx_done __P((epic_softc_t *)); -static int epic_init_rings __P((epic_softc_t *)); -static void epic_free_rings __P((epic_softc_t *)); -static void epic_stop_activity __P((epic_softc_t *)); -static void epic_start_activity __P((epic_softc_t *)); -static void epic_set_rx_mode __P((epic_softc_t *)); -static void epic_set_tx_mode __P((epic_softc_t *)); -static void epic_set_mc_table __P((epic_softc_t *)); -static void epic_set_media_speed __P((epic_softc_t *)); -static void epic_init_phy __P((epic_softc_t *)); -static void epic_dump_state __P((epic_softc_t *)); -static int epic_autoneg __P((epic_softc_t *)); -static int epic_read_eeprom __P((epic_softc_t *,u_int16_t)); -static void epic_output_eepromw __P((epic_softc_t *, u_int16_t)); -static u_int16_t epic_input_eepromw __P((epic_softc_t *)); -static u_int8_t epic_eeprom_clock __P((epic_softc_t *,u_int8_t)); -static void epic_write_eepromreg __P((epic_softc_t *,u_int8_t)); -static u_int8_t epic_read_eepromreg __P((epic_softc_t *)); -static u_int16_t epic_read_phy_register __P((epic_softc_t *, u_int16_t)); -static void epic_write_phy_register __P((epic_softc_t *, u_int16_t, u_int16_t)); - -#if !defined(EPIC_NOIFMEDIA) -static int epic_ifmedia_change __P((struct ifnet *)); -static void epic_ifmedia_status __P((struct ifnet *, struct ifmediareq *)); -#endif - -/* ------------------------------------------------------------------------- - OS-specific part - ------------------------------------------------------------------------- */ - -#if defined(__OpenBSD__) -/* -----------------------------OpenBSD------------------------------------- */ - -static int epic_openbsd_probe __P((struct device *,void *,void *)); -static void epic_openbsd_attach __P((struct device *, struct device *, void *)); -static void epic_shutdown __P((void *)); - -struct cfattach tx_ca = { - sizeof(epic_softc_t), epic_openbsd_probe, epic_openbsd_attach -}; -struct cfdriver tx_cd = { - NULL,"tx",DV_IFNET -}; - -/* Synopsis: Check if device id corresponds with SMC83C170 id. */ -static int -epic_openbsd_probe( - struct device *parent, - void *match, - void *aux ) -{ - struct pci_attach_args *pa = aux; - if( PCI_VENDOR(pa->pa_id) != SMC_VENDORID ) - return 0; - - if( PCI_PRODUCT(pa->pa_id) == CHIPID_83C170 ) - return 1; - - return 0; -} - -static void -epic_openbsd_attach( - struct device *parent, - struct device *self, - void *aux ) -{ - epic_softc_t *sc = (epic_softc_t*)self; - struct pci_attach_args *pa = aux; - pci_chipset_tag_t pc = pa->pa_pc; - pci_intr_handle_t ih; - const char *intrstr = NULL; - struct ifnet *ifp; - bus_space_tag_t iot = pa->pa_iot; - bus_addr_t iobase; - bus_size_t iosize; - int i; -#if !defined(EPIC_NOIFMEDIA) - int tmp; -#endif - - if( pci_io_find(pc, pa->pa_tag, PCI_CBIO, &iobase, &iosize)) { - printf(": can't find i/o space\n"); - return; - } - if( bus_space_map(iot, iobase, iosize, 0, &sc->sc_sh)) { - printf(": can't map i/o space\n"); - return; - } - sc->sc_st = iot; - - ifp = &sc->sc_if; - bcopy(sc->sc_dev.dv_xname, ifp->if_xname,IFNAMSIZ); - ifp->if_softc = sc; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = epic_ifioctl; - ifp->if_start = epic_ifstart; - ifp->if_watchdog = epic_ifwatchdog; - - /* Do common attach procedure */ - if( epic_common_attach(sc) ) return; - - /* Map interrupt */ - if( pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin, - pa->pa_intrline, &ih)) { - printf(": can't map interrupt\n"); - return; - } - intrstr = pci_intr_string(pc, ih); - sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, epic_intr, sc, - self->dv_xname); - - if( NULL == sc->sc_ih ) { - printf(": can't establish interrupt"); - if( intrstr )printf(" at %s",intrstr); - printf("\n"); - return; - } - printf(": %s",intrstr); - - /* Display some info */ - printf(" address %s",ether_sprintf(sc->sc_macaddr)); - /* Read current media config and display it too */ - i = PHY_READ_2( sc, DP83840_BMCR ); -#if !defined(EPIC_NOIFMEDIA) - tmp = IFM_ETHER; -#endif - if( i & BMCR_AUTONEGOTIATION ){ - printf(", Auto-Neg "); +#include <pci/smc83c170.h> - /* To avoid bug in QS6612 read LPAR enstead of BMSR */ - i = PHY_READ_2( sc, DP83840_LPAR ); - if( i & (ANAR_100_TX|ANAR_100_TX_FD) ) printf("100Mbps"); - else printf("10Mbps"); - if( i & (ANAR_10_FD|ANAR_100_TX_FD) ) printf(" FD"); -#if !defined(EPIC_NOIFMEDIA) - tmp |= IFM_AUTO; -#endif - } else { -#if defined(EPIC_NOIFMEDIA) - ifp->if_flags |= IFF_LINK0; -#endif - if( i & BMCR_100MBPS ) { - printf(", 100Mbps"); -#if !defined(EPIC_NOIFMEDIA) - tmp |= IFM_100_TX; -#else - ifp->if_flags |= IFF_LINK2; -#endif - } else { - printf(", 10Mbps"); -#if !defined(EPIC_NOIFMEDIA) - tmp |= IFM_10_T; -#endif - } - if( i & BMCR_FULL_DUPLEX ) { - printf(" FD"); -#if !defined(EPIC_NOIFMEDIA) - tmp |= IFM_FDX; -#else - ifp->if_flags |= IFF_LINK1; -#endif - } - } - - /* Init ifmedia interface */ -#if !defined(EPIC_NOIFMEDIA) - ifmedia_init(&sc->ifmedia,0,epic_ifmedia_change,epic_ifmedia_status); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_LOOP,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_FDX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_LOOP,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_FDX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_AUTO,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_LOOP,0,NULL); - ifmedia_set(&sc->ifmedia, tmp); -#endif - - /* Attach os interface and bpf */ - if_attach(ifp); - ether_ifattach(ifp); +#include "bpfilter.h" #if NBPFILTER > 0 - bpfattach(&sc->sc_if.if_bpf, ifp, DLT_EN10MB, - sizeof(struct ether_header)); +#include <net/bpf.h> #endif - /* Set shutdown routine to stop DMA process */ - shutdownhook_establish(epic_shutdown, sc); - printf("\n"); -} - -/* Simple call epic_stop() */ -static void -epic_shutdown( - void *sc) -{ - epic_stop(sc); -} - -#else /* __FreeBSD__ */ -/* -----------------------------FreeBSD------------------------------------- */ - -static const char* epic_freebsd_probe __P((pcici_t, pcidi_t)); -static void epic_freebsd_attach __P((pcici_t, int)); -static void epic_shutdown __P((int, void *)); - -/* Global variables */ +/* + * Global variables + */ static u_long epic_pci_count; static struct pci_device txdevice = { "tx", - epic_freebsd_probe, - epic_freebsd_attach, + epic_pci_probe, + epic_pci_attach, &epic_pci_count, NULL }; -/* Append this driver to pci drivers list */ -DATA_SET ( pcidevice_set, txdevice ); - -/* Synopsis: Check if device id corresponds with SMC83C170 id. */ -static const char* -epic_freebsd_probe( - pcici_t config_id, - pcidi_t device_id) -{ - if( PCI_VENDORID(device_id) != SMC_VENDORID ) - return NULL; - - if( PCI_CHIPID(device_id) == CHIPID_83C170 ) - return "SMC 83c170"; - - return NULL; -} - /* - * Do FreeBSD-specific attach routine, like map registers, alloc softc - * structure and etc. + * Append this driver to pci drivers list */ -static void -epic_freebsd_attach( - pcici_t config_id, - int unit) -{ - struct ifnet *ifp; - epic_softc_t *sc; -#if defined(EPIC_USEIOSPACE) - u_int32_t iobase; -#else - caddr_t pmembase; -#endif - int i,s,tmp; - - printf("tx%d",unit); - - /* Allocate memory for softc, hardware descriptors and frag lists */ - sc = (epic_softc_t *) malloc( sizeof(epic_softc_t), M_DEVBUF, M_NOWAIT); - if (sc == NULL) return; - - /* Preinitialize softc structure */ - bzero(sc, sizeof(epic_softc_t)); - sc->unit = unit; - - /* Fill ifnet structure */ - ifp = &sc->sc_if; - ifp->if_unit = unit; - ifp->if_name = "tx"; - ifp->if_softc = sc; - ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST; - ifp->if_ioctl = epic_ifioctl; - ifp->if_start = epic_ifstart; - ifp->if_watchdog = epic_ifwatchdog; - ifp->if_init = (if_init_f_t*)epic_init; - ifp->if_timer = 0; - ifp->if_output = ether_output; - - /* Get iobase or membase */ -#if defined(EPIC_USEIOSPACE) - if (!pci_map_port(config_id, PCI_CBIO,(u_short *) &(sc->iobase))) { - printf(": cannot map port\n"); - free(sc, M_DEVBUF); - return; - } -#else - if (!pci_map_mem(config_id, PCI_CBMA,(vm_offset_t *) &(sc->csr),(vm_offset_t *) &pmembase)) { - printf(": cannot map memory\n"); - free(sc, M_DEVBUF); - return; - } -#endif - - if( epic_common_attach(sc) ) return; - - /* Display ethernet address ,... */ - printf(": address %02x:%02x:%02x:%02x:%02x:%02x,", - sc->sc_macaddr[0],sc->sc_macaddr[1],sc->sc_macaddr[2], - sc->sc_macaddr[3],sc->sc_macaddr[4],sc->sc_macaddr[5]); - - /* board type and ... */ - printf(" type "); - for(i=0x2c;i<0x32;i++) { - tmp = epic_read_eeprom( sc, i ); - if( ' ' == (u_int8_t)tmp ) break; - printf("%c",(u_int8_t)tmp); - tmp >>= 8; - if( ' ' == (u_int8_t)tmp ) break; - printf("%c",(u_int8_t)tmp); - } - - /* Read current media config and display it too */ - i = PHY_READ_2( sc, DP83840_BMCR ); -#if !defined(EPIC_NOIFMEDIA) - tmp = IFM_ETHER; -#endif - if( i & BMCR_AUTONEGOTIATION ){ - printf(", Auto-Neg "); - - /* To avoid bug in QS6612 read LPAR enstead of BMSR */ - i = PHY_READ_2( sc, DP83840_LPAR ); - if( i & (ANAR_100_TX|ANAR_100_TX_FD) ) printf("100Mbps "); - else printf("10Mbps "); - if( i & (ANAR_10_FD|ANAR_100_TX_FD) ) printf("FD"); -#if !defined(EPIC_NOIFMEDIA) - tmp |= IFM_AUTO; -#endif - } else { -#if defined(EPIC_NOIFMEDIA) - ifp->if_flags |= IFF_LINK0; -#endif - if( i & BMCR_100MBPS ) { - printf(", 100Mbps "); -#if !defined(EPIC_NOIFMEDIA) - tmp |= IFM_100_TX; -#else - ifp->if_flags |= IFF_LINK2; -#endif - } else { - printf(", 10Mbps "); -#if !defined(EPIC_NOIFMEDIA) - tmp |= IFM_10_T; -#endif - } - if( i & BMCR_FULL_DUPLEX ) { - printf("FD"); -#if !defined(EPIC_NOIFMEDIA) - tmp |= IFM_FDX; -#else - ifp->if_flags |= IFF_LINK1; -#endif - } - } - - /* Init ifmedia interface */ -#if !defined(EPIC_NOIFMEDIA) - ifmedia_init(&sc->ifmedia,0,epic_ifmedia_change,epic_ifmedia_status); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_LOOP,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_FDX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_LOOP,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_FDX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_AUTO,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_LOOP,0,NULL); - ifmedia_set(&sc->ifmedia, tmp); -#endif - - s = splimp(); - - /* Map interrupt */ - if( !pci_map_int(config_id, epic_intr, (void*)sc, &net_imask) ) { - printf(": couldn't map interrupt\n"); - free(sc, M_DEVBUF); - return; - } - - /* Set shut down routine to stop DMA processes on reboot */ - at_shutdown(epic_shutdown, sc, SHUTDOWN_POST_SYNC); - - /* Attach to if manager */ - if_attach(ifp); - ether_ifattach(ifp); - -#if NBPFILTER > 0 - bpfattach(ifp,DLT_EN10MB, sizeof(struct ether_header)); -#endif - - splx(s); - - printf("\n"); - - return; -} - -static void -epic_shutdown( - int howto, - void *sc) -{ - epic_stop(sc); -} - -#endif /* __OpenBSD__ */ - -/* ------------------------------------------------------------------------ - OS-independing part - ------------------------------------------------------------------------ */ +DATA_SET ( pcidevice_set, txdevice ); /* - * This is if_ioctl handler. + * ifioctl function + * + * splimp() invoked here */ static int epic_ifioctl __P(( register struct ifnet * ifp, - EPIC_IFIOCTL_CMD_TYPE command, - caddr_t data)) + u_long command, caddr_t data)) { epic_softc_t *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; int x, error = 0; x = splimp(); switch (command) { -#if defined(__FreeBSD__) + case SIOCSIFADDR: case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); + ether_ioctl(ifp, command, data); break; -#else /* __OpenBSD__ */ - case SIOCSIFADDR: { - struct ifaddr *ifa = (struct ifaddr *)data; - - ifp->if_flags |= IFF_UP; - switch(ifa->ifa_addr->sa_family) { -#if INET - case AF_INET: - epic_stop(sc); - epic_init(sc); - arp_ifinit(&sc->arpcom,ifa); - break; -#endif /* __FreeBSD__ */ -#if NS - case AF_NS: { - register struct ns_addr * ina = &IA_SNS(ifa)->sns_addr; - - if( ns_nullhost(*ina) ) - ina->x_host = - *(union ns_host *) LLADDR(ifp->if_sadl); - else - bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl), - ifp->if_addrlen); - - epic_stop(sc); - epic_init(sc); - break; - } -#endif - default: - epic_stop(sc); - epic_init(sc); - break; - } - } -#endif case SIOCSIFFLAGS: /* @@ -641,22 +155,24 @@ epic_ifioctl __P(( /* Handle IFF_PROMISC flag */ epic_set_rx_mode(sc); -#if defined(EPIC_NOIFMEDIA) +#if !defined(_NET_IF_MEDIA_H_) /* Handle IFF_LINKx flags */ epic_set_media_speed(sc); #endif + break; case SIOCADDMULTI: case SIOCDELMULTI: + /* Update out multicast list */ #if defined(__FreeBSD__) && __FreeBSD_version >= 300000 epic_set_mc_table(sc); error = 0; #else error = (command == SIOCADDMULTI) ? - ether_addmulti((struct ifreq *)data, &sc->arpcom) : - ether_delmulti((struct ifreq *)data, &sc->arpcom); + ether_addmulti(ifr, &sc->epic_ac) : + ether_delmulti(ifr, &sc->epic_ac); if (error == ENETRESET) { epic_set_mc_table(sc); @@ -665,11 +181,21 @@ epic_ifioctl __P(( #endif break; -#if !defined(EPIC_NOIFMEDIA) + case SIOCSIFMTU: + /* + * Set the interface MTU. + */ + if (ifr->ifr_mtu > ETHERMTU) { + error = EINVAL; + } else { + ifp->if_mtu = ifr->ifr_mtu; + } + break; + +#if defined(_NET_IF_MEDIA_H_) case SIOCSIFMEDIA: case SIOCGIFMEDIA: - error = ifmedia_ioctl(ifp, (struct ifreq *)data, - &sc->ifmedia, command); + error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); break; #endif @@ -682,65 +208,9 @@ epic_ifioctl __P(( } /* - * OS-independed part of attach process. allocate memory for descriptors - * and frag lists, wake up chip, read MAC address and PHY identyfier. - * Return -1 on failure. - */ -static int -epic_common_attach( - epic_softc_t *sc) -{ - int i; - caddr_t pool; - - i = sizeof(struct epic_frag_list)*TX_RING_SIZE + - sizeof(struct epic_rx_desc)*RX_RING_SIZE + - sizeof(struct epic_tx_desc)*TX_RING_SIZE + PAGE_SIZE, - sc->pool = (epic_softc_t *) malloc( i, M_DEVBUF, M_NOWAIT); - - if (sc->pool == NULL) { - printf(": can't allocate memory for buffers\n"); - return -1; - } - bzero(sc->pool, i); - - /* Align pool on PAGE_SIZE */ - pool = (caddr_t)sc->pool; - pool = (caddr_t)((u_int32_t)(pool + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)); - - /* Distribute memory */ - sc->tx_flist = (void *)pool; - pool += sizeof(struct epic_frag_list)*TX_RING_SIZE; - sc->rx_desc = (void *)pool; - pool += sizeof(struct epic_rx_desc)*RX_RING_SIZE; - sc->tx_desc = (void *)pool; - - /* Bring the chip out of low-power mode. */ - CSR_WRITE_4( sc, GENCTL, 0x0000 ); - - /* Magic?! If we don't set this bit the MII interface won't work. */ - CSR_WRITE_4( sc, TEST1, 0x0008 ); - - /* Read mac address from EEPROM */ - for (i = 0; i < ETHER_ADDR_LEN / sizeof(u_int16_t); i++) - ((u_int16_t *)sc->sc_macaddr)[i] = epic_read_eeprom(sc,i); - - /* Identify PHY */ - sc->phyid = PHY_READ_2(sc, DP83840_PHYIDR1 )<<6; - sc->phyid|= (PHY_READ_2( sc, DP83840_PHYIDR2 )>>10)&0x3F; - if( QS6612_OUI != sc->phyid ) - printf(": WARNING! PHY unknown (0x%x)",sc->phyid); - - sc->tx_threshold = TRANSMIT_THRESHOLD; - sc->txcon = TXCON_DEFAULT; - - return 0; -} - -/* - * This is if_start handler. It takes mbufs from if_snd queue - * and quque them for transmit, one by one, until TX ring become full - * or quque become empty. + * ifstart function + * + * splimp() assumed to be done */ static void epic_ifstart(struct ifnet * const ifp){ @@ -748,17 +218,19 @@ epic_ifstart(struct ifnet * const ifp){ struct epic_tx_buffer *buf; struct epic_tx_desc *desc; struct epic_frag_list *flist; - struct mbuf *m0; - register struct mbuf *m; - register int i; + struct mbuf *m,*m0; - /* If no link is established, simply free all mbufs in queue */ +#if defined(EPIC_DEBUG) + if( sc->epic_if.if_flags & IFF_DEBUG ) epic_dump_state(sc); +#endif + /* If no link is established, */ + /* simply free all mbufs in queue */ PHY_READ_2( sc, DP83840_BMSR ); if( !(BMSR_LINK_STATUS & PHY_READ_2( sc, DP83840_BMSR )) ){ - IF_DEQUEUE( &ifp->if_snd, m0 ); + IF_DEQUEUE( &(sc->epic_if.if_snd), m0 ); while( m0 ) { m_freem(m0); - IF_DEQUEUE( &ifp->if_snd, m0 ); + IF_DEQUEUE( &(sc->epic_if.if_snd), m0 ); } return; } @@ -770,46 +242,44 @@ epic_ifstart(struct ifnet * const ifp){ flist = sc->tx_flist + sc->cur_tx; /* Get next packet to send */ - IF_DEQUEUE( &ifp->if_snd, m0 ); + IF_DEQUEUE( &(sc->epic_if.if_snd), m0 ); /* If nothing to send, return */ if( NULL == m0 ) return; /* If descriptor is busy, set IFF_OACTIVE and exit */ if( desc->status & 0x8000 ) { - dprintf((EPIC_FORMAT ": desc is busy in ifstart, up and down interface please\n",EPIC_ARGS(sc))); + dprintf(("\ntx%d: desc is busy in ifstart, up and down interface please",sc->unit)); break; } if( buf->mbuf ) { - dprintf((EPIC_FORMAT ": mbuf not freed in ifstart, up and down interface plase\n",EPIC_ARGS(sc))); + dprintf(("\ntx%d: mbuf not freed in ifstart, up and down interface plase",sc->unit)); break; } /* Fill fragments list */ - for( m=m0, i=0; - (NULL != m) && (i < EPIC_MAX_FRAGS); - m = m->m_next, i++ ) { - flist->frag[i].fraglen = m->m_len; - flist->frag[i].fragaddr = vtophys( mtod(m, caddr_t) ); + flist->numfrags = 0; + for(m=m0;(NULL!=m)&&(flist->numfrags<63);m=m->m_next) { + flist->frag[flist->numfrags].fraglen = m->m_len; + flist->frag[flist->numfrags].fragaddr = vtophys( mtod(m, caddr_t) ); + flist->numfrags++; } - flist->numfrags = i; - /* If packet was more than EPIC_MAX_FRAGS parts, */ + /* If packet was more than 63 parts, */ /* recopy packet to new allocated mbuf cluster */ if( NULL != m ){ EPIC_MGETCLUSTER(m); if( NULL == m ){ - printf(EPIC_FORMAT ": cannot allocate mbuf cluster\n",EPIC_ARGS(sc)); + printf("\ntx%d: cannot allocate mbuf cluster",sc->unit); m_freem(m0); - ifp->if_oerrors++; + sc->epic_if.if_oerrors++; continue; } m_copydata( m0, 0, m0->m_pkthdr.len, mtod(m,caddr_t) ); - flist->frag[0].fraglen = - m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; - m->m_pkthdr.rcvif = ifp; + flist->frag[0].fraglen = m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; + m->m_pkthdr.rcvif = &sc->epic_if; flist->numfrags = 1; flist->frag[0].fragaddr = vtophys( mtod(m, caddr_t) ); @@ -817,29 +287,40 @@ epic_ifstart(struct ifnet * const ifp){ m0 = m; } + /* Save mbuf */ buf->mbuf = m0; + + /* Packet queued successful */ sc->pending_txs++; - sc->cur_tx = ( sc->cur_tx + 1 ) & TX_RING_MASK; + + /* Switch to next descriptor */ + sc->cur_tx = ( sc->cur_tx + 1 ) % TX_RING_SIZE; + + /* Does not generate TXC */ desc->control = 0x01; - desc->txlength = - max(m0->m_pkthdr.len,ETHER_MIN_LEN-ETHER_CRC_LEN); + + /* Packet should be at least ETHER_MIN_LEN */ + desc->txlength = max(m0->m_pkthdr.len,ETHER_MIN_LEN-ETHER_CRC_LEN); + + /* Pass ownership to the chip */ desc->status = 0x8000; + + /* Trigger an immediate transmit demand. */ CSR_WRITE_4( sc, COMMAND, COMMAND_TXQUEUED ); +#if defined(EPIC_DEBUG) + if( sc->epic_if.if_flags & IFF_DEBUG ) epic_dump_state(sc); +#endif + /* Set watchdog timer */ ifp->if_timer = 8; #if NBPFILTER > 0 - if( ifp->if_bpf ) -#if defined(__FreeBSD__) - bpf_mtap( ifp, m0 ); -#else /* __OpenBSD__ */ - bpf_mtap( ifp->if_bpf, m0 ); -#endif /* __FreeBSD__ */ + if( ifp->if_bpf ) bpf_mtap( ifp, m0 ); #endif } - ifp->if_flags |= IFF_OACTIVE; + sc->epic_if.if_flags |= IFF_OACTIVE; return; @@ -853,25 +334,28 @@ static __inline void epic_rx_done __P(( epic_softc_t *sc )) { + int i = 0; u_int16_t len; struct epic_rx_buffer *buf; struct epic_rx_desc *desc; struct mbuf *m; struct ether_header *eh; - while( !(sc->rx_desc[sc->cur_rx].status & 0x8000) ) { + while( !(sc->rx_desc[sc->cur_rx].status & 0x8000) && \ + i++ < RX_RING_SIZE ) { + buf = sc->rx_buffer + sc->cur_rx; desc = sc->rx_desc + sc->cur_rx; /* Switch to next descriptor */ - sc->cur_rx = (sc->cur_rx+1) & RX_RING_MASK; + sc->cur_rx = (sc->cur_rx+1) % RX_RING_SIZE; /* Check for errors, this should happend */ /* only if SAVE_ERRORED_PACKETS is set, */ /* normaly rx errors generate RXE interrupt */ if( !(desc->status & 1) ) { - dprintf((EPIC_FORMAT ": Rx error status: 0x%x\n",EPIC_ARGS(sc),desc->status)); - sc->sc_if.if_ierrors++; + dprintf(("\ntx%d: Rx error status: 0x%x",sc->unit,desc->status)); + sc->epic_if.if_ierrors++; desc->status = 0x8000; continue; } @@ -883,10 +367,10 @@ epic_rx_done __P(( /* Try to get mbuf cluster */ EPIC_MGETCLUSTER( buf->mbuf ); if( NULL == buf->mbuf ) { - printf(EPIC_FORMAT ": cannot allocate mbuf cluster\n",EPIC_ARGS(sc)); + printf("\ntx%d: cannot allocate mbuf cluster",sc->unit); buf->mbuf = m; desc->status = 0x8000; - sc->sc_if.if_ierrors++; + sc->epic_if.if_ierrors++; continue; } @@ -896,21 +380,16 @@ epic_rx_done __P(( /* First mbuf in packet holds the ethernet and packet headers */ eh = mtod( m, struct ether_header * ); - m->m_pkthdr.rcvif = &(sc->sc_if); + m->m_pkthdr.rcvif = &(sc->epic_if); m->m_pkthdr.len = m->m_len = len; #if NBPFILTER > 0 /* Give mbuf to BPFILTER */ - if( sc->sc_if.if_bpf ) -#if defined(__FreeBSD__) - bpf_mtap( &sc->sc_if, m ); -#else /* __OpenBSD__ */ - bpf_mtap( sc->sc_if.if_bpf, m ); -#endif /* __FreeBSD__ */ + if( sc->epic_if.if_bpf ) bpf_mtap( &sc->epic_if, m ); /* Accept only our packets, broadcasts and multicasts */ if( (eh->ether_dhost[0] & 1) == 0 && - bcmp(eh->ether_dhost,sc->sc_macaddr,ETHER_ADDR_LEN)){ + bcmp(eh->ether_dhost,sc->epic_ac.ac_enaddr,ETHER_ADDR_LEN)){ m_freem(m); continue; } @@ -921,10 +400,10 @@ epic_rx_done __P(( m->m_data += sizeof( struct ether_header ); /* Give mbuf to OS */ - ether_input(&sc->sc_if, eh, m); + ether_input(&sc->epic_if, eh, m); /* Successfuly received frame */ - sc->sc_if.if_ipackets++; + sc->epic_if.if_ipackets++; } return; @@ -956,22 +435,22 @@ epic_tx_done __P(( /* Packet is transmitted. Switch to next and */ /* free mbuf */ sc->pending_txs--; - sc->dirty_tx = (sc->dirty_tx + 1) & TX_RING_MASK; + sc->dirty_tx = (sc->dirty_tx + 1) % TX_RING_SIZE; m_freem( buf->mbuf ); buf->mbuf = NULL; /* Check for errors and collisions */ - if( status & 0x0001 ) sc->sc_if.if_opackets++; - else sc->sc_if.if_oerrors++; - sc->sc_if.if_collisions += (status >> 8) & 0x1F; + if( status & 0x0001 ) sc->epic_if.if_opackets++; + else sc->epic_if.if_oerrors++; + sc->epic_if.if_collisions += (status >> 8) & 0x1F; #if defined(EPIC_DEBUG) if( (status & 0x1001) == 0x1001 ) - dprintf((EPIC_FORMAT ": frame not transmitted due collisions\n",EPIC_ARGS(sc))); + dprintf(("\ntx%d: frame not transmitted due collisions",sc->unit)); #endif } if( sc->pending_txs < TX_RING_SIZE ) - sc->sc_if.if_flags &= ~IFF_OACTIVE; + sc->epic_if.if_flags &= ~IFF_OACTIVE; } /* @@ -979,137 +458,122 @@ epic_tx_done __P(( * * splimp() assumed to be done */ -static EPIC_INTR_RET_TYPE -epic_intr ( +static void +epic_intr_normal( void *arg) { - epic_softc_t * sc = (epic_softc_t *) arg; - int status,i=4; -#if defined(__OpenBSD__) - int claimed = 0; -#endif - + epic_softc_t * sc = (epic_softc_t *) arg; + int status,i=4; - while( i-- && ((status = CSR_READ_4(sc, INTSTAT)) & INTSTAT_INT_ACTV) ){ -#if defined(__OpenBSD__) - claimed = 1; -#endif +do { + status = CSR_READ_4( sc, INTSTAT ); CSR_WRITE_4( sc, INTSTAT, status ); if( status & (INTSTAT_RQE|INTSTAT_RCC|INTSTAT_OVW) ) { - epic_rx_done( sc ); - if( status & (INTSTAT_RQE|INTSTAT_OVW) ){ + epic_rx_done( sc ); + if( status & (INTSTAT_RQE|INTSTAT_OVW) ){ #if defined(EPIC_DEBUG) - if( status & INTSTAT_OVW ) - printf(EPIC_FORMAT ": RX buffer overflow\n",EPIC_ARGS(sc)); - if( status & INTSTAT_RQE ) - printf(EPIC_FORMAT ": RX FIFO overflow\n",EPIC_ARGS(sc)); - if( sc->sc_if.if_flags & IFF_DEBUG ) - epic_dump_state(sc); + if( status & INTSTAT_OVW ) + printf("\ntx%d: Rx buffer overflowed",sc->unit); + if( status & INTSTAT_RQE ) + printf("\ntx%d: Rx FIFO overflowed",sc->unit); + if( sc->epic_if.if_flags & IFF_DEBUG ) + epic_dump_state(sc); #endif - if( !(CSR_READ_4( sc, COMMAND ) & COMMAND_RXQUEUED) ) - CSR_WRITE_4( sc, COMMAND, COMMAND_RXQUEUED ); - sc->sc_if.if_ierrors++; - } - } + if( !(CSR_READ_4( sc, COMMAND ) & COMMAND_RXQUEUED) ) + CSR_WRITE_4( sc, COMMAND, COMMAND_RXQUEUED ); + sc->epic_if.if_ierrors++; + } + } - if( status & (INTSTAT_TXC|INTSTAT_TCC|INTSTAT_TQE) ) { - epic_tx_done( sc ); - if(!(sc->sc_if.if_flags & IFF_OACTIVE) && - sc->sc_if.if_snd.ifq_head ) - epic_ifstart( &sc->sc_if ); + if( status & (INTSTAT_TXC|INTSTAT_TCC|INTSTAT_TQE) ) { + epic_tx_done( sc ); +#if defined(EPIC_DEBUG) + if( (status & (INTSTAT_TQE | INTSTAT_TCC)) && (sc->pending_txs > 1) ) + printf("\ntx%d: %d packets pending after TQE/TCC",sc->unit,sc->pending_txs); +#endif + if( !(sc->epic_if.if_flags & IFF_OACTIVE) && sc->epic_if.if_snd.ifq_head ) + epic_ifstart( &sc->epic_if ); } - if( (status & INTSTAT_GP2) && (QS6612_OUI == sc->phyid) ) { - u_int32_t phystatus = PHY_READ_2( sc, QS6612_INTSTAT ); + if( (status & INTSTAT_GP2) && (QS6612_OUI == sc->phyid) ) { + u_int32_t phystatus; + + phystatus = PHY_READ_2( sc, QS6612_INTSTAT ); - if( phystatus & INTSTAT_AN_COMPLETE ) { - u_int32_t bmcr; - if( epic_autoneg(sc) == EPIC_FULL_DUPLEX ) { - bmcr = BMCR_FULL_DUPLEX | PHY_READ_2( sc, DP83840_BMCR ); - sc->txcon |= TXCON_FULL_DUPLEX; - CSR_WRITE_4( sc, TXCON, sc->txcon ); + if( phystatus & INTSTAT_AN_COMPLETE ) { + u_int32_t bmcr; + if( epic_autoneg(sc) == EPIC_FULL_DUPLEX ) { + bmcr = BMCR_FULL_DUPLEX | PHY_READ_2( sc, DP83840_BMCR ); + CSR_WRITE_4( sc, TXCON, TXCON_FULL_DUPLEX | TXCON_DEFAULT ); + } else { + /* Default to half-duplex */ + bmcr = ~BMCR_FULL_DUPLEX & PHY_READ_2( sc, DP83840_BMCR ); + CSR_WRITE_4( sc, TXCON, TXCON_DEFAULT ); + } + + /* There is apparently QS6612 chip bug: */ + /* BMCR_FULL_DUPLEX flag is not updated by */ + /* autonegotiation process, so update it by hands */ + /* so we can rely on it in epic_ifmedia_status() */ + PHY_WRITE_2( sc, DP83840_BMCR, bmcr ); + } + + PHY_READ_2(sc, DP83840_BMSR); + if( !(PHY_READ_2(sc, DP83840_BMSR) & BMSR_LINK_STATUS) ) { + dprintf(("\ntx%d: WARNING! link down",sc->unit)); + sc->flags |= EPIC_LINK_DOWN; } else { - /* Default to half-duplex */ - bmcr = ~BMCR_FULL_DUPLEX & PHY_READ_2( sc, DP83840_BMCR ); - sc->txcon &= ~TXCON_FULL_DUPLEX; - CSR_WRITE_4( sc, TXCON, sc->txcon ); + dprintf(("\ntx%d: link up",sc->unit)); + sc->flags &= ~EPIC_LINK_DOWN; } - /* There is apparently QS6612 chip bug: */ - /* BMCR_FULL_DUPLEX flag is not updated by */ - /* autonegotiation process, so update it by hands */ - /* so we can rely on it in epic_ifmedia_status() */ - PHY_WRITE_2( sc, DP83840_BMCR, bmcr ); - } - - PHY_READ_2(sc, DP83840_BMSR); - if( !(PHY_READ_2(sc, DP83840_BMSR) & BMSR_LINK_STATUS) ) { - dprintf((EPIC_FORMAT ": WARNING! link down\n",EPIC_ARGS(sc))); - sc->flags |= EPIC_LINK_DOWN; - } else { - dprintf((EPIC_FORMAT ": link up\n",EPIC_ARGS(sc))); - sc->flags &= ~EPIC_LINK_DOWN; - } - - /* We should clear GP2 int again after we clear it on PHY */ - CSR_WRITE_4( sc, INTSTAT, INTSTAT_GP2 ); + /* We should clear GP2 int again after we clear it on PHY */ + CSR_WRITE_4( sc, INTSTAT, INTSTAT_GP2 ); } /* Check for errors */ - if( status & (INTSTAT_FATAL|INTSTAT_PMA|INTSTAT_PTA| - INTSTAT_APE|INTSTAT_DPE|INTSTAT_TXU|INTSTAT_RXE) ){ - if( status & (INTSTAT_FATAL|INTSTAT_PMA|INTSTAT_PTA| - INTSTAT_APE|INTSTAT_DPE) ){ - printf(EPIC_FORMAT ": PCI fatal error occured (%s%s%s%s)\n", - EPIC_ARGS(sc), - (status&INTSTAT_PMA)?"PMA":"", - (status&INTSTAT_PTA)?" PTA":"", - (status&INTSTAT_APE)?" APE":"", - (status&INTSTAT_DPE)?" DPE":"" - ); - - epic_dump_state(sc); + if( status & (INTSTAT_FATAL|INTSTAT_PMA|INTSTAT_PTA|INTSTAT_APE|INTSTAT_DPE|INTSTAT_TXU|INTSTAT_RXE) ){ + if( status & (INTSTAT_FATAL|INTSTAT_PMA|INTSTAT_PTA|INTSTAT_APE|INTSTAT_DPE) ){ + printf("\ntx%d: PCI fatal error occured (%s%s%s%s)", + sc->unit, + (status&INTSTAT_PMA)?"PMA":"", + (status&INTSTAT_PTA)?" PTA":"", + (status&INTSTAT_APE)?" APE":"", + (status&INTSTAT_DPE)?" DPE":"" + ); + + epic_dump_state(sc); - epic_stop(sc); - epic_init(sc); + epic_stop(sc); + epic_init(sc); - break; - } - - if (status & INTSTAT_RXE) { - dprintf((EPIC_FORMAT ": CRC/Alignment error\n",EPIC_ARGS(sc))); - sc->sc_if.if_ierrors++; - } - - /* Tx FIFO underflow. Increase tx threshold, */ - /* if it grown above 2048, disable EARLY_TX */ - if (status & INTSTAT_TXU) { - if( sc->tx_threshold > 0x800 ) { - sc->txcon &= ~TXCON_EARLY_TRANSMIT_ENABLE; - dprintf((EPIC_FORMAT ": TX underrun error, early tx disabled\n",EPIC_ARGS(sc))); - } else { - sc->tx_threshold += 0x40; - dprintf((EPIC_FORMAT ": TX underrun error, tx threshold increased to %d\n",EPIC_ARGS(sc),sc->tx_threshold)); + return; } - epic_stop_activity(sc); - epic_set_tx_mode(sc); - epic_start_activity(sc); - sc->sc_if.if_oerrors++; + if (status & INTSTAT_RXE) { + dprintf(("\ntx%d: CRC/Alignment error",sc->unit)); + sc->epic_if.if_ierrors++; + } + + /* Tx FIFO underflow. Should not happend if */ + /* we don't use early tx, handle it anyway */ + if (status & INTSTAT_TXU) { + dprintf(("\ntx%d: Tx underrun error",sc->unit)); + sc->epic_if.if_oerrors++; - /* Restart the transmit process. */ - /* CSR_WRITE_4(sc, COMMAND, COMMAND_TXUGO|COMMAND_TXQUEUED); */ - } + /* Restart the transmit process. */ + CSR_WRITE_4(sc, COMMAND, COMMAND_TXUGO | COMMAND_TXQUEUED); + } } - } - /* If no packets are pending, thus no timeouts */ - if( sc->pending_txs == 0 ) sc->sc_if.if_timer = 0; +} while( i-- && (CSR_READ_4(sc, INTSTAT) & INTSTAT_INT_ACTV) ); -#if defined(__OpenBSD__) - return claimed; -#endif + /* If no packets are pending, thus no timeouts */ + if( sc->pending_txs == 0 ) + sc->epic_if.if_timer = 0; + + return; } /* @@ -1128,8 +592,7 @@ epic_ifwatchdog __P(( x = splimp(); - printf(EPIC_FORMAT ": device timeout %d packets, ", - EPIC_ARGS(sc),sc->pending_txs); + printf("\ntx%d: device timeout %d packets, ", sc->unit,sc->pending_txs); /* Try to finish queued packets */ epic_tx_done( sc ); @@ -1137,35 +600,240 @@ epic_ifwatchdog __P(( /* If not successful */ if( sc->pending_txs > 0 ){ #if defined(EPIC_DEBUG) - if( ifp->if_flags & IFF_DEBUG ) epic_dump_state(sc); + if( sc->epic_if.if_flags & IFF_DEBUG ) epic_dump_state(sc); #endif ifp->if_oerrors+=sc->pending_txs; /* Reinitialize board */ - printf("reinitialization\n"); + printf("reinitialization"); epic_stop(sc); epic_init(sc); } else - printf("seems we can continue normaly\n"); + printf("seems we can continue normaly"); /* Start output */ - if( ifp->if_snd.ifq_head ) epic_ifstart( ifp ); + if( sc->epic_if.if_snd.ifq_head ) epic_ifstart(&sc->epic_if); splx(x); } +/* + * Synopsis: Check if PCI id corresponds with board id. + */ +static char* +epic_pci_probe( + pcici_t config_id, + pcidi_t device_id) +{ + if( PCI_VENDORID(device_id) != SMC_VENDORID ) + return NULL; + + if( PCI_CHIPID(device_id) == CHIPID_83C170 ) + return "SMC 83c170"; + + return NULL; +} + +/* + * Synopsis: Allocate memory for softc, descriptors and frag lists. + * Connect to interrupt, and get memory/io address of card registers. + * Preinitialize softc structure, attach to if manager, ifmedia manager + * and bpf. Read media configuration and etc. + * + * splimp() invoked here + */ +static void +epic_pci_attach( + pcici_t config_id, + int unit) +{ + struct ifnet * ifp; + epic_softc_t *sc; +#if defined(EPIC_USEIOSPACE) + u_int32_t iobase; +#else + caddr_t pmembase; +#endif + int i,k,s,tmp; + u_int32_t pool; + + /* Allocate memory for softc, hardware descriptors and frag lists */ + sc = (epic_softc_t *) malloc( + sizeof(epic_softc_t) + + sizeof(struct epic_frag_list)*TX_RING_SIZE + + sizeof(struct epic_rx_desc)*RX_RING_SIZE + + sizeof(struct epic_tx_desc)*TX_RING_SIZE + PAGE_SIZE, + M_DEVBUF, M_NOWAIT); + + if (sc == NULL) return; + + /* Align pool on PAGE_SIZE */ + pool = ((u_int32_t)sc) + sizeof(epic_softc_t); + pool = (pool + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + /* Preinitialize softc structure */ + bzero(sc, sizeof(epic_softc_t)); + sc->unit = unit; + + /* Fill ifnet structure */ + ifp = &sc->epic_if; + ifp->if_unit = unit; + ifp->if_name = "tx"; + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST; + ifp->if_ioctl = epic_ifioctl; + ifp->if_start = epic_ifstart; + ifp->if_watchdog = epic_ifwatchdog; + ifp->if_init = (if_init_f_t*)epic_init; + ifp->if_timer = 0; + ifp->if_output = ether_output; + + /* Get iobase or membase */ +#if defined(EPIC_USEIOSPACE) + if (!pci_map_port(config_id, PCI_CBIO,(u_short *) &(sc->iobase))) { + printf("tx%d: cannot map port\n",unit); + free(sc, M_DEVBUF); + return; + } +#else + if (!pci_map_mem(config_id, PCI_CBMA,(vm_offset_t *) &(sc->csr),(vm_offset_t *) &pmembase)) { + printf("tx%d: cannot map memory\n",unit); + free(sc, M_DEVBUF); + return; + } +#endif + + sc->tx_flist = (void *)pool; + pool += sizeof(struct epic_frag_list)*TX_RING_SIZE; + sc->rx_desc = (void *)pool; + pool += sizeof(struct epic_rx_desc)*RX_RING_SIZE; + sc->tx_desc = (void *)pool; + + /* Bring the chip out of low-power mode. */ + CSR_WRITE_4( sc, GENCTL, 0x0000 ); + + /* Magic?! If we don't set this bit the MII interface won't work. */ + CSR_WRITE_4( sc, TEST1, 0x0008 ); + + /* Read mac address from EEPROM */ + for (i = 0; i < ETHER_ADDR_LEN / sizeof(u_int16_t); i++) + ((u_int16_t *)sc->epic_macaddr)[i] = epic_read_eeprom(sc,i); + + /* Display ethernet address ,... */ + printf("tx%d: address %02x:%02x:%02x:%02x:%02x:%02x,",sc->unit, + sc->epic_macaddr[0],sc->epic_macaddr[1],sc->epic_macaddr[2], + sc->epic_macaddr[3],sc->epic_macaddr[4],sc->epic_macaddr[5]); + + /* board type and ... */ + printf(" type "); + for(i=0x2c;i<0x32;i++) { + tmp = epic_read_eeprom( sc, i ); + if( ' ' == (u_int8_t)tmp ) break; + printf("%c",(u_int8_t)tmp); + tmp >>= 8; + if( ' ' == (u_int8_t)tmp ) break; + printf("%c",(u_int8_t)tmp); + } + + /* Read current media config and display it too */ + i = PHY_READ_2( sc, DP83840_BMCR ); +#if defined(_NET_IF_MEDIA_H_) + tmp = IFM_ETHER; +#endif + if( i & BMCR_AUTONEGOTIATION ){ + printf(", Auto-Neg "); + + /* To avoid bug in QS6612 read LPAR enstead of BMSR */ + i = PHY_READ_2( sc, DP83840_LPAR ); + if( i & (ANAR_100_TX|ANAR_100_TX_FD) ) printf("100Mbps "); + else printf("10Mbps "); + if( i & (ANAR_10_FD|ANAR_100_TX_FD) ) printf("FD"); +#if defined(_NET_IF_MEDIA_H_) + tmp |= IFM_AUTO; +#endif + } else { +#if !defined(_NET_IF_MEDIA_H_) + ifp->if_flags |= IFF_LINK0; +#endif + if( i & BMCR_100MBPS ) { + printf(", 100Mbps "); +#if defined(_NET_IF_MEDIA_H_) + tmp |= IFM_100_TX; +#else + ifp->if_flags |= IFF_LINK2; +#endif + } else { + printf(", 10Mbps "); +#if defined(_NET_IF_MEDIA_H_) + tmp |= IFM_10_T; +#endif + } + if( i & BMCR_FULL_DUPLEX ) { + printf("FD"); +#if defined(_NET_IF_MEDIA_H_) + tmp |= IFM_FDX; +#else + ifp->if_flags |= IFF_LINK1; +#endif + } + } + + /* Init ifmedia interface */ +#if defined(SIOCSIFMEDIA) && !defined(EPIC_NOIFMEDIA) + ifmedia_init(&sc->ifmedia,0,epic_ifmedia_change,epic_ifmedia_status); + ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T,0,NULL); + ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_LOOP,0,NULL); + ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_FDX,0,NULL); + ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX,0,NULL); + ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_LOOP,0,NULL); + ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_FDX,0,NULL); + ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_AUTO,0,NULL); + ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_LOOP,0,NULL); + ifmedia_set(&sc->ifmedia, tmp); +#endif + + /* Identify PHY */ + sc->phyid = PHY_READ_2(sc, DP83840_PHYIDR1 )<<6; + sc->phyid|= (PHY_READ_2( sc, DP83840_PHYIDR2 )>>10)&0x3F; + if( QS6612_OUI != sc->phyid ) printf("tx%d: WARNING! phy unknown (0x%x), ",sc->unit,sc->phyid); + + s = splimp(); + + /* Map interrupt */ + if( !pci_map_int(config_id, epic_intr_normal, (void*)sc, &net_imask) ) { + printf("tx%d: couldn't map interrupt\n",unit); + free(sc, M_DEVBUF); + return; + } + + /* Set shut down routine to stop DMA processes on reboot */ + at_shutdown(epic_shutdown, sc, SHUTDOWN_POST_SYNC); + + /* Attach to if manager */ + if_attach(ifp); + ether_ifattach(ifp); + +#if NBPFILTER > 0 + bpfattach(ifp,DLT_EN10MB, sizeof(struct ether_header)); +#endif + + splx(s); + + printf("\n"); + + return; +} + #if defined(SIOCSIFMEDIA) && !defined(EPIC_NOIFMEDIA) static int epic_ifmedia_change __P(( struct ifnet * ifp)) { - epic_softc_t *sc = (epic_softc_t *)(ifp->if_softc); - - if (IFM_TYPE(sc->ifmedia.ifm_media) != IFM_ETHER) + if (IFM_TYPE(((epic_softc_t *)(ifp->if_softc))->ifmedia.ifm_media) != IFM_ETHER) return (EINVAL); - epic_set_media_speed(sc); + epic_set_media_speed( ifp->if_softc ); return 0; } @@ -1176,8 +844,8 @@ epic_ifmedia_status __P(( struct ifmediareq *ifmr)) { epic_softc_t *sc = ifp->if_softc; - u_int32_t bmcr; - u_int32_t bmsr; + u_int32_t bmcr; + u_int32_t bmsr; bmcr = PHY_READ_2( sc, DP83840_BMCR ); @@ -1188,8 +856,7 @@ epic_ifmedia_status __P(( ifmr->ifm_status = IFM_AVALID; if( !(bmsr & BMSR_LINK_STATUS) ) { - ifmr->ifm_active |= - (bmcr&BMCR_AUTONEGOTIATION)?IFM_AUTO:IFM_NONE; + ifmr->ifm_active |= (bmcr&BMCR_AUTONEGOTIATION)?IFM_AUTO:IFM_NONE; return; } @@ -1209,8 +876,8 @@ static int epic_init __P(( epic_softc_t * sc)) { - struct ifnet *ifp = &sc->sc_if; - int s; + struct ifnet *ifp = &sc->epic_if; + int i,s; s = splimp(); @@ -1228,7 +895,7 @@ epic_init __P(( /* Initialize rings */ if( epic_init_rings( sc ) ) { - printf(EPIC_FORMAT ": failed to init rings\n",EPIC_ARGS(sc)); + printf("\ntx%d: failed to initialize rings",sc->unit); splx(s); return -1; } @@ -1238,12 +905,16 @@ epic_init __P(( CSR_WRITE_4( sc, PTCDAR, vtophys( sc->tx_desc ) ); /* Put node address to EPIC */ - CSR_WRITE_4( sc, LAN0, ((u_int16_t *)sc->sc_macaddr)[0] ); - CSR_WRITE_4( sc, LAN1, ((u_int16_t *)sc->sc_macaddr)[1] ); - CSR_WRITE_4( sc, LAN2, ((u_int16_t *)sc->sc_macaddr)[2] ); + CSR_WRITE_4( sc, LAN0, ((u_int16_t *)sc->epic_macaddr)[0] ); + CSR_WRITE_4( sc, LAN1, ((u_int16_t *)sc->epic_macaddr)[1] ); + CSR_WRITE_4( sc, LAN2, ((u_int16_t *)sc->epic_macaddr)[2] ); + +#if defined(EARLY_TX) + /* Set transmit threshold */ + CSR_WRITE_4( sc, ETXTHR, TRANSMIT_THRESHOLD ); +#endif - /* Set tx mode, includeing transmit threshold */ - epic_set_tx_mode(sc); + CSR_WRITE_4( sc, IPG, 0x1010 ); /* Compute and set RXCON. */ epic_set_rx_mode( sc ); @@ -1288,7 +959,7 @@ static void epic_set_rx_mode( epic_softc_t * sc) { - u_int32_t flags = sc->sc_if.if_flags; + u_int32_t flags = sc->epic_if.if_flags; u_int32_t rxcon = RXCON_DEFAULT | RXCON_RECEIVE_MULTICAST_FRAMES | RXCON_RECEIVE_BROADCAST_FRAMES; rxcon |= (flags & IFF_PROMISC)?RXCON_PROMISCUOUS_MODE:0; @@ -1313,7 +984,7 @@ epic_init_phy __P(( if( !(PHY_READ_2( sc, DP83840_BMCR ) & BMCR_RESET) ) break; if( PHY_READ_2( sc, DP83840_BMCR ) & BMCR_RESET ) - printf(EPIC_FORMAT ": WARNING! cannot reset PHY\n",EPIC_ARGS(sc)); + printf("\ntx%d: WARNING! cannot reset PHY",sc->unit); switch( sc->phyid ){ case QS6612_OUI: @@ -1340,7 +1011,7 @@ epic_set_media_speed __P(( { u_int16_t media; -#if !defined(EPIC_NOIFMEDIA) +#if defined(_NET_IF_MEDIA_H_) u_int32_t tgtmedia = sc->ifmedia.ifm_cur->ifm_media; if( IFM_SUBTYPE(tgtmedia) != IFM_AUTO ){ @@ -1348,42 +1019,40 @@ epic_set_media_speed __P(( media = (IFM_SUBTYPE(tgtmedia)==IFM_100_TX) ? BMCR_100MBPS : 0; media|= (tgtmedia&IFM_FDX) ? BMCR_FULL_DUPLEX : 0; - sc->sc_if.if_baudrate = + sc->epic_if.if_baudrate = (IFM_SUBTYPE(tgtmedia)==IFM_100_TX)?100000000:10000000; PHY_WRITE_2( sc, DP83840_BMCR, media ); - if( tgtmedia & IFM_FDX ) sc->txcon |= TXCON_FULL_DUPLEX; - else sc->txcon &= ~TXCON_FULL_DUPLEX; - if( tgtmedia & IFM_LOOP ) sc->txcon |= TXCON_LOOPBACK_MODE_INT; - else sc->txcon &= ~TXCON_LOOPBACK_MODE_INT; + media = TXCON_DEFAULT; + if( tgtmedia & IFM_FDX ) media |= TXCON_FULL_DUPLEX; + else if( tgtmedia & IFM_LOOP ) media |= TXCON_LOOPBACK_MODE_INT; - CSR_WRITE_4( sc, TXCON, sc->txcon ); + CSR_WRITE_4( sc, TXCON, media ); } -#else /* EPIC_NOIFMEDIA */ - struct ifnet *ifp = &sc->sc_if; +#else + struct ifnet *ifp = &sc->epic_if; if( ifp->if_flags & IFF_LINK0 ) { /* Set mode */ media = (ifp->if_flags & IFF_LINK2) ? BMCR_100MBPS : 0; media|= (ifp->if_flags & IFF_LINK1) ? BMCR_FULL_DUPLEX : 0; - sc->sc_if.if_baudrate = + sc->epic_if.if_baudrate = (ifp->if_flags & IFF_LINK2)?100000000:10000000; PHY_WRITE_2( sc, DP83840_BMCR, media ); - if( ifp->if_flags & IFF_LINK2 ) sc->txcon |= TXCON_FULL_DUPLEX; - else sc->txcon &= ~TXCON_FULL_DUPLEX; + media = TXCON_DEFAULT; + media |= (ifp->if_flags&IFF_LINK2)?TXCON_FULL_DUPLEX:0; - CSR_WRITE_4( sc, TXCON, sc->txcon ); + CSR_WRITE_4( sc, TXCON, media ); } -#endif /* !EPIC_NOIFMEDIA */ +#endif else { - sc->sc_if.if_baudrate = 100000000; + sc->epic_if.if_baudrate = 100000000; - sc->txcon &= ~TXCON_FULL_DUPLEX; - CSR_WRITE_4(sc, TXCON, sc->txcon); + CSR_WRITE_4( sc, TXCON, TXCON_DEFAULT ); /* Set and restart autoneg */ PHY_WRITE_2( sc, DP83840_BMCR, @@ -1397,10 +1066,8 @@ epic_set_media_speed __P(( */ DELAY(3000000); - if( epic_autoneg(sc) == EPIC_FULL_DUPLEX ) { - sc->txcon |= TXCON_FULL_DUPLEX; - CSR_WRITE_4(sc, TXCON, sc->txcon); - } + if( epic_autoneg(sc) == EPIC_FULL_DUPLEX ) + CSR_WRITE_4( sc, TXCON, TXCON_FULL_DUPLEX|TXCON_DEFAULT); } /* Else it will be done when GP2 int occured */ } @@ -1418,6 +1085,7 @@ static int epic_autoneg( epic_softc_t * sc) { + struct ifnet *ifp = &sc->epic_if; u_int16_t media; u_int16_t i; @@ -1487,19 +1155,6 @@ epic_autoneg( } /* - */ -static void -epic_set_tx_mode ( - epic_softc_t *sc ) -{ - - if( sc->txcon & TXCON_EARLY_TRANSMIT_ENABLE ) - CSR_WRITE_4( sc, ETXTHR, sc->tx_threshold ); - - CSR_WRITE_4( sc, TXCON, sc->txcon ); -} - -/* * Synopsis: This function should update multicast hash table. * I suppose there is a bug in chips MC filter so this function * only set it to receive all MC packets. The second problem is @@ -1511,7 +1166,7 @@ static void epic_set_mc_table ( epic_softc_t * sc) { - struct ifnet *ifp = &sc->sc_if; + struct ifnet *ifp = &sc->epic_if; if( ifp->if_flags & IFF_MULTICAST ){ CSR_WRITE_4( sc, MC0, 0xFFFF ); @@ -1523,16 +1178,24 @@ epic_set_mc_table ( return; } +static void +epic_shutdown( + int howto, + void *sc) +{ + epic_stop(sc); +} /* - * Synopsis: Start receive process and transmit, if need + * Synopsis: Start receive process, should check that all internal chip + * pointers are set properly. */ static void epic_start_activity __P(( epic_softc_t * sc)) { /* Start rx process */ - CSR_WRITE_4( sc, COMMAND, COMMAND_RXQUEUED | COMMAND_START_RX | (sc->pending_txs?COMMAND_TXQUEUED:0)); + CSR_WRITE_4( sc, COMMAND, COMMAND_RXQUEUED | COMMAND_START_RX ); } /* @@ -1543,56 +1206,43 @@ static void epic_stop_activity __P(( epic_softc_t * sc)) { - int i; + int i; - /* Turn it to loopback mode */ - CSR_WRITE_4( sc, TXCON, TXCON_SLOT_TIME|TXCON_LOOPBACK_MODE_INT ); + /* Stop Tx and Rx DMA */ + CSR_WRITE_4( sc, COMMAND, COMMAND_STOP_RX | COMMAND_STOP_RDMA | COMMAND_STOP_TDMA); - /* Stop Tx and Rx DMA */ - CSR_WRITE_4(sc,COMMAND,COMMAND_STOP_RX|COMMAND_STOP_RDMA|COMMAND_STOP_TDMA); + /* Wait only Rx DMA */ + dprintf(("\ntx%d: waiting Rx DMA to stop",sc->unit)); + for(i=0;i<0x100000;i++) + if( (CSR_READ_4(sc,INTSTAT)&INTSTAT_RXIDLE) == INTSTAT_RXIDLE ) break; - /* Wait only Rx DMA */ - dprintf((EPIC_FORMAT ": waiting Rx DMA to stop\n",EPIC_ARGS(sc))); - for(i=0;i<0x1000;i++) { - if( (CSR_READ_4(sc,INTSTAT) & INTSTAT_RXIDLE) == INTSTAT_RXIDLE ) - break; - DELAY(1); - } - - if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_RXIDLE) ) - printf(EPIC_FORMAT ": can't stop RX DMA\n",EPIC_ARGS(sc)); - - /* May need to queue one more packet if TQE */ - if( (CSR_READ_4( sc, INTSTAT ) & INTSTAT_TQE) && - !(CSR_READ_4( sc, INTSTAT ) & INTSTAT_TXIDLE) ){ - dprintf((EPIC_FORMAT ": queue last packet\n",EPIC_ARGS(sc))); - - sc->tx_desc[sc->cur_tx].bufaddr = vtophys( sc ); - sc->tx_desc[sc->cur_tx].buflength = ETHER_MIN_LEN-ETHER_CRC_LEN; - sc->tx_desc[sc->cur_tx].control = 0x14; - sc->tx_desc[sc->cur_tx].txlength = ETHER_MIN_LEN-ETHER_CRC_LEN; - sc->tx_desc[sc->cur_tx].status = 0x8000; - sc->cur_tx = (sc->cur_tx + 1) & TX_RING_MASK; - sc->pending_txs++; - - CSR_WRITE_4( sc, COMMAND, COMMAND_TXQUEUED ); - - dprintf((EPIC_FORMAT ": waiting Tx DMA to stop\n",EPIC_ARGS(sc))); - /* Wait TX DMA to stop */ - for(i=0;i<0x1000;i++) { - if( (CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) == INTSTAT_TXIDLE ) { - sc->pending_txs--; - break; - } - DELAY(1); - } + if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_RXIDLE) ) + printf("\ntx%d: can't stop RX DMA",sc->unit); - if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) ) - printf(EPIC_FORMAT ": can't stop TX DMA\n",EPIC_ARGS(sc)); + /* May need to queue one more packet if TQE */ + if( (CSR_READ_4( sc, INTSTAT ) & INTSTAT_TQE) && + !(CSR_READ_4( sc, INTSTAT ) & INTSTAT_TXIDLE) ){ + dprintf(("\ntx%d: queue last packet",sc->unit)); - /* Restore old TX state */ - CSR_WRITE_4( sc, TXCON, sc->txcon ); - } + /* Turn it to loopback mode */ + CSR_WRITE_4( sc, TXCON, TXCON_DEFAULT|TXCON_LOOPBACK_MODE_INT ); + + sc->tx_desc[sc->cur_tx].bufaddr = vtophys( sc ); + sc->tx_desc[sc->cur_tx].buflength = ETHER_MIN_LEN-ETHER_CRC_LEN; + sc->tx_desc[sc->cur_tx].control = 0x14; + sc->tx_desc[sc->cur_tx].txlength = ETHER_MIN_LEN-ETHER_CRC_LEN; + sc->tx_desc[sc->cur_tx].status = 0x8000; + + CSR_WRITE_4( sc, COMMAND, COMMAND_TXQUEUED ); + + dprintf(("\ntx%d: waiting Tx DMA to stop",sc->unit)); + /* Wait TX DMA to stop */ + for(i=0;i<0x100000;i++) + if( (CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) == INTSTAT_TXIDLE ) break; + + if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) ) + printf("\ntx%d: can't stop TX DMA",sc->unit); + } } /* @@ -1604,11 +1254,11 @@ static void epic_stop __P(( epic_softc_t * sc)) { - int s; + int i,s; s = splimp(); - sc->sc_if.if_timer = 0; + sc->epic_if.if_timer = 0; /* Disable interrupts */ CSR_WRITE_4( sc, INTMASK, 0 ); @@ -1619,13 +1269,13 @@ epic_stop __P(( /* Reset chip */ CSR_WRITE_4( sc, GENCTL, GENCTL_SOFT_RESET ); - DELAY(10); + DELAY(1); /* Free memory allocated for rings */ epic_free_rings(sc); /* Mark as stoped */ - sc->sc_if.if_flags &= ~IFF_RUNNING; + sc->epic_if.if_flags &= ~IFF_RUNNING; splx(s); return; @@ -1673,6 +1323,7 @@ epic_free_rings __P(( static int epic_init_rings(epic_softc_t * sc){ int i; + struct mbuf *m; sc->cur_rx = sc->cur_tx = sc->dirty_tx = sc->pending_txs = 0; @@ -1681,10 +1332,10 @@ epic_init_rings(epic_softc_t * sc){ struct epic_rx_desc *desc = sc->rx_desc + i; desc->status = 0; /* Owned by driver */ - desc->next = vtophys( sc->rx_desc + ((i+1) & RX_RING_MASK) ); + desc->next = vtophys( sc->rx_desc + ((i+1)%RX_RING_SIZE) ); if( (desc->next & 3) || ((desc->next & 0xFFF) + sizeof(struct epic_rx_desc) > 0x1000 ) ) - printf(EPIC_FORMAT ": WARNING! rx_desc is misbound or misaligned\n",EPIC_ARGS(sc)); + printf("\ntx%d: WARNING! rx_desc is misbound or misaligned",sc->unit); EPIC_MGETCLUSTER( buf->mbuf ); if( NULL == buf->mbuf ) { @@ -1703,15 +1354,15 @@ epic_init_rings(epic_softc_t * sc){ struct epic_tx_desc *desc = sc->tx_desc + i; desc->status = 0; - desc->next = vtophys( sc->tx_desc + ( (i+1) & TX_RING_MASK ) ); + desc->next = vtophys( sc->tx_desc + ( (i+1)%TX_RING_SIZE ) ); if( (desc->next & 3) || ((desc->next & 0xFFF) + sizeof(struct epic_tx_desc) > 0x1000 ) ) - printf(EPIC_FORMAT ": WARNING! tx_desc is misbound or misaligned\n",EPIC_ARGS(sc)); + printf("\ntx%d: WARNING! tx_desc is misbound or misaligned",sc->unit); buf->mbuf = NULL; desc->bufaddr = vtophys( sc->tx_flist + i ); if( (desc->bufaddr & 3) || ((desc->bufaddr & 0xFFF) + sizeof(struct epic_frag_list) > 0x1000 ) ) - printf(EPIC_FORMAT ": WARNING! frag_list is misbound or misaligned\n",EPIC_ARGS(sc)); + printf("\ntx%d: WARNING! frag_list is misbound or misaligned",sc->unit); } return 0; @@ -1787,6 +1438,7 @@ epic_read_eeprom __P(( epic_softc_t *sc, u_int16_t loc)) { + int i; u_int16_t dataval; u_int16_t read_cmd; @@ -1843,13 +1495,14 @@ epic_dump_state __P(( int j; struct epic_tx_desc *tdesc; struct epic_rx_desc *rdesc; - printf(EPIC_FORMAT ": cur_rx: %d, pending_txs: %d, dirty_tx: %d, cur_tx: %d\n", EPIC_ARGS(sc),sc->cur_rx,sc->pending_txs,sc->dirty_tx,sc->cur_tx); - printf(EPIC_FORMAT ": COMMAND: 0x%08x, INTSTAT: 0x%08x\n",EPIC_ARGS(sc),CSR_READ_4(sc,COMMAND),CSR_READ_4(sc,INTSTAT)); - printf(EPIC_FORMAT ": PRCDAR: 0x%08x, PTCDAR: 0x%08x\n",EPIC_ARGS(sc),CSR_READ_4(sc,PRCDAR),CSR_READ_4(sc,PTCDAR)); - printf(EPIC_FORMAT ": dumping rx descriptors\n",EPIC_ARGS(sc)); + printf("\ntx%d: cur_rx: %d, pending_txs: %d, dirty_tx: %d, cur_tx: %d", + sc->unit,sc->cur_rx,sc->pending_txs,sc->dirty_tx,sc->cur_tx); + printf("\ntx%d: COMMAND: 0x%08x, INTSTAT: 0x%08x",sc->unit,CSR_READ_4(sc,COMMAND),CSR_READ_4(sc,INTSTAT)); + printf("\ntx%d: PRCDAR: 0x%08x, PTCDAR: 0x%08x",sc->unit,CSR_READ_4(sc,PRCDAR),CSR_READ_4(sc,PTCDAR)); + printf("\ntx%d: dumping rx descriptors",sc->unit); for(j=0;j<RX_RING_SIZE;j++){ rdesc = sc->rx_desc + j; - printf("desc%d: %4d 0x%04x, 0x%08x, %4d, 0x%08x\n", + printf("\ndesc%d: %4d 0x%04x, 0x%08x, %4d, 0x%08x", j, rdesc->rxlength,rdesc->status, rdesc->bufaddr, @@ -1857,11 +1510,11 @@ epic_dump_state __P(( rdesc->next ); } - printf(EPIC_FORMAT ": dumping tx descriptors\n",EPIC_ARGS(sc)); + printf("\ntx%d: dumping tx descriptors",sc->unit); for(j=0;j<TX_RING_SIZE;j++){ tdesc = sc->tx_desc + j; printf( - "desc%d: %4d 0x%04x, 0x%08lx, 0x%04x %4u, 0x%08lx, mbuf: %p\n", + "\ndesc%d: %4d 0x%04x, 0x%08lx, 0x%04x %4u, 0x%08lx, mbuf: %p", j, tdesc->txlength,tdesc->status, (u_long)tdesc->bufaddr, diff --git a/sys/pci/if_vr.c b/sys/pci/if_vr.c deleted file mode 100644 index efed968177dc..000000000000 --- a/sys/pci/if_vr.c +++ /dev/null @@ -1,1957 +0,0 @@ -/* - * Copyright (c) 1997, 1998 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_vr.c,v 1.16 1999/01/10 18:06:10 wpaul Exp $ - */ - -/* - * VIA Rhine fast ethernet PCI NIC driver - * - * Supports various network adapters based on the VIA Rhine - * and Rhine II PCI controllers, including the D-Link DFE530TX. - * Datasheets are available at http://www.via.com.tw. - * - * Written by Bill Paul <wpaul@ctr.columbia.edu> - * Electrical Engineering Department - * Columbia University, New York City - */ - -/* - * The VIA Rhine controllers are similar in some respects to the - * the DEC tulip chips, except less complicated. The controller - * uses an MII bus and an external physical layer interface. The - * receiver has a one entry perfect filter and a 64-bit hash table - * multicast filter. Transmit and receive descriptors are similar - * to the tulip. - * - * The Rhine has a serious flaw in its transmit DMA mechanism: - * transmit buffers must be longword aligned. Unfortunately, - * FreeBSD doesn't guarantee that mbufs will be filled in starting - * at longword boundaries, so we have to do a buffer copy before - * transmission. - */ - -#include "bpfilter.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/if_arp.h> -#include <net/ethernet.h> -#include <net/if_dl.h> -#include <net/if_media.h> - -#if NBPFILTER > 0 -#include <net/bpf.h> -#endif - -#include <vm/vm.h> /* for vtophys */ -#include <vm/pmap.h> /* for vtophys */ -#include <machine/clock.h> /* for DELAY */ -#include <machine/bus_pio.h> -#include <machine/bus_memio.h> -#include <machine/bus.h> - -#include <pci/pcireg.h> -#include <pci/pcivar.h> - -#define VR_USEIOSPACE - -/* #define VR_BACKGROUND_AUTONEG */ - -#include <pci/if_vrreg.h> - -#ifndef lint -static const char rcsid[] = - "$Id: if_vr.c,v 1.16 1999/01/10 18:06:10 wpaul Exp $"; -#endif - -/* - * Various supported device vendors/types and their names. - */ -static struct vr_type vr_devs[] = { - { VIA_VENDORID, VIA_DEVICEID_RHINE, - "VIA VT3043 Rhine I 10/100BaseTX" }, - { VIA_VENDORID, VIA_DEVICEID_RHINE_II, - "VIA VT86C100A Rhine II 10/100BaseTX" }, - { 0, 0, NULL } -}; - -/* - * Various supported PHY vendors/types and their names. Note that - * this driver will work with pretty much any MII-compliant PHY, - * so failure to positively identify the chip is not a fatal error. - */ - -static struct vr_type vr_phys[] = { - { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, - { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, - { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, - { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, - { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, - { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, - { 0, 0, "<MII-compliant physical interface>" } -}; - -static unsigned long vr_count = 0; -static const char *vr_probe __P((pcici_t, pcidi_t)); -static void vr_attach __P((pcici_t, int)); - -static int vr_newbuf __P((struct vr_softc *, - struct vr_chain_onefrag *)); -static int vr_encap __P((struct vr_softc *, struct vr_chain *, - struct mbuf * )); - -static void vr_rxeof __P((struct vr_softc *)); -static void vr_rxeoc __P((struct vr_softc *)); -static void vr_txeof __P((struct vr_softc *)); -static void vr_txeoc __P((struct vr_softc *)); -static void vr_intr __P((void *)); -static void vr_start __P((struct ifnet *)); -static int vr_ioctl __P((struct ifnet *, u_long, caddr_t)); -static void vr_init __P((void *)); -static void vr_stop __P((struct vr_softc *)); -static void vr_watchdog __P((struct ifnet *)); -static void vr_shutdown __P((int, void *)); -static int vr_ifmedia_upd __P((struct ifnet *)); -static void vr_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); - -static void vr_mii_sync __P((struct vr_softc *)); -static void vr_mii_send __P((struct vr_softc *, u_int32_t, int)); -static int vr_mii_readreg __P((struct vr_softc *, struct vr_mii_frame *)); -static int vr_mii_writereg __P((struct vr_softc *, struct vr_mii_frame *)); -static u_int16_t vr_phy_readreg __P((struct vr_softc *, int)); -static void vr_phy_writereg __P((struct vr_softc *, u_int16_t, u_int16_t)); - -static void vr_autoneg_xmit __P((struct vr_softc *)); -static void vr_autoneg_mii __P((struct vr_softc *, int, int)); -static void vr_setmode_mii __P((struct vr_softc *, int)); -static void vr_getmode_mii __P((struct vr_softc *)); -static void vr_setcfg __P((struct vr_softc *, u_int16_t)); -static u_int8_t vr_calchash __P((u_int8_t *)); -static void vr_setmulti __P((struct vr_softc *)); -static void vr_reset __P((struct vr_softc *)); -static int vr_list_rx_init __P((struct vr_softc *)); -static int vr_list_tx_init __P((struct vr_softc *)); - -#define VR_SETBIT(sc, reg, x) \ - CSR_WRITE_1(sc, reg, \ - CSR_READ_1(sc, reg) | x) - -#define VR_CLRBIT(sc, reg, x) \ - CSR_WRITE_1(sc, reg, \ - CSR_READ_1(sc, reg) & ~x) - -#define VR_SETBIT16(sc, reg, x) \ - CSR_WRITE_2(sc, reg, \ - CSR_READ_2(sc, reg) | x) - -#define VR_CLRBIT16(sc, reg, x) \ - CSR_WRITE_2(sc, reg, \ - CSR_READ_2(sc, reg) & ~x) - -#define VR_SETBIT32(sc, reg, x) \ - CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) | x) - -#define VR_CLRBIT32(sc, reg, x) \ - CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) & ~x) - -#define SIO_SET(x) \ - CSR_WRITE_1(sc, VR_MIICMD, \ - CSR_READ_1(sc, VR_MIICMD) | x) - -#define SIO_CLR(x) \ - CSR_WRITE_1(sc, VR_MIICMD, \ - CSR_READ_1(sc, VR_MIICMD) & ~x) - -/* - * Sync the PHYs by setting data bit and strobing the clock 32 times. - */ -static void vr_mii_sync(sc) - struct vr_softc *sc; -{ - register int i; - - SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN); - - for (i = 0; i < 32; i++) { - SIO_SET(VR_MIICMD_CLK); - DELAY(1); - SIO_CLR(VR_MIICMD_CLK); - DELAY(1); - } - - return; -} - -/* - * Clock a series of bits through the MII. - */ -static void vr_mii_send(sc, bits, cnt) - struct vr_softc *sc; - u_int32_t bits; - int cnt; -{ - int i; - - SIO_CLR(VR_MIICMD_CLK); - - for (i = (0x1 << (cnt - 1)); i; i >>= 1) { - if (bits & i) { - SIO_SET(VR_MIICMD_DATAIN); - } else { - SIO_CLR(VR_MIICMD_DATAIN); - } - DELAY(1); - SIO_CLR(VR_MIICMD_CLK); - DELAY(1); - SIO_SET(VR_MIICMD_CLK); - } -} - -/* - * Read an PHY register through the MII. - */ -static int vr_mii_readreg(sc, frame) - struct vr_softc *sc; - struct vr_mii_frame *frame; - -{ - int i, ack, s; - - s = splimp(); - - /* - * Set up frame for RX. - */ - frame->mii_stdelim = VR_MII_STARTDELIM; - frame->mii_opcode = VR_MII_READOP; - frame->mii_turnaround = 0; - frame->mii_data = 0; - - CSR_WRITE_1(sc, VR_MIICMD, 0); - VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); - - /* - * Turn on data xmit. - */ - SIO_SET(VR_MIICMD_DIR); - - vr_mii_sync(sc); - - /* - * Send command/address info. - */ - vr_mii_send(sc, frame->mii_stdelim, 2); - vr_mii_send(sc, frame->mii_opcode, 2); - vr_mii_send(sc, frame->mii_phyaddr, 5); - vr_mii_send(sc, frame->mii_regaddr, 5); - - /* Idle bit */ - SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN)); - DELAY(1); - SIO_SET(VR_MIICMD_CLK); - DELAY(1); - - /* Turn off xmit. */ - SIO_CLR(VR_MIICMD_DIR); - - /* Check for ack */ - SIO_CLR(VR_MIICMD_CLK); - DELAY(1); - SIO_SET(VR_MIICMD_CLK); - DELAY(1); - ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; - - /* - * Now try reading data bits. If the ack failed, we still - * need to clock through 16 cycles to keep the PHY(s) in sync. - */ - if (ack) { - for(i = 0; i < 16; i++) { - SIO_CLR(VR_MIICMD_CLK); - DELAY(1); - SIO_SET(VR_MIICMD_CLK); - DELAY(1); - } - goto fail; - } - - for (i = 0x8000; i; i >>= 1) { - SIO_CLR(VR_MIICMD_CLK); - DELAY(1); - if (!ack) { - if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT) - frame->mii_data |= i; - DELAY(1); - } - SIO_SET(VR_MIICMD_CLK); - DELAY(1); - } - -fail: - - SIO_CLR(VR_MIICMD_CLK); - DELAY(1); - SIO_SET(VR_MIICMD_CLK); - DELAY(1); - - splx(s); - - if (ack) - return(1); - return(0); -} - -/* - * Write to a PHY register through the MII. - */ -static int vr_mii_writereg(sc, frame) - struct vr_softc *sc; - struct vr_mii_frame *frame; - -{ - int s; - - s = splimp(); - - CSR_WRITE_1(sc, VR_MIICMD, 0); - VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); - - /* - * Set up frame for TX. - */ - - frame->mii_stdelim = VR_MII_STARTDELIM; - frame->mii_opcode = VR_MII_WRITEOP; - frame->mii_turnaround = VR_MII_TURNAROUND; - - /* - * Turn on data output. - */ - SIO_SET(VR_MIICMD_DIR); - - vr_mii_sync(sc); - - vr_mii_send(sc, frame->mii_stdelim, 2); - vr_mii_send(sc, frame->mii_opcode, 2); - vr_mii_send(sc, frame->mii_phyaddr, 5); - vr_mii_send(sc, frame->mii_regaddr, 5); - vr_mii_send(sc, frame->mii_turnaround, 2); - vr_mii_send(sc, frame->mii_data, 16); - - /* Idle bit. */ - SIO_SET(VR_MIICMD_CLK); - DELAY(1); - SIO_CLR(VR_MIICMD_CLK); - DELAY(1); - - /* - * Turn off xmit. - */ - SIO_CLR(VR_MIICMD_DIR); - - splx(s); - - return(0); -} - -static u_int16_t vr_phy_readreg(sc, reg) - struct vr_softc *sc; - int reg; -{ - struct vr_mii_frame frame; - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = sc->vr_phy_addr; - frame.mii_regaddr = reg; - vr_mii_readreg(sc, &frame); - - return(frame.mii_data); -} - -static void vr_phy_writereg(sc, reg, data) - struct vr_softc *sc; - u_int16_t reg; - u_int16_t data; -{ - struct vr_mii_frame frame; - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = sc->vr_phy_addr; - frame.mii_regaddr = reg; - frame.mii_data = data; - - vr_mii_writereg(sc, &frame); - - return; -} - -/* - * Calculate CRC of a multicast group address, return the lower 6 bits. - */ -static u_int8_t vr_calchash(addr) - u_int8_t *addr; -{ - u_int32_t crc, carry; - int i, j; - u_int8_t c; - - /* Compute CRC for the address value. */ - crc = 0xFFFFFFFF; /* initial value */ - - for (i = 0; i < 6; i++) { - c = *(addr + i); - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); - crc <<= 1; - c >>= 1; - if (carry) - crc = (crc ^ 0x04c11db6) | carry; - } - } - - /* return the filter bit position */ - return((crc >> 26) & 0x0000003F); -} - -/* - * Program the 64-bit multicast hash filter. - */ -static void vr_setmulti(sc) - struct vr_softc *sc; -{ - struct ifnet *ifp; - int h = 0; - u_int32_t hashes[2] = { 0, 0 }; - struct ifmultiaddr *ifma; - u_int8_t rxfilt; - int mcnt = 0; - - ifp = &sc->arpcom.ac_if; - - rxfilt = CSR_READ_1(sc, VR_RXCFG); - - if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { - rxfilt |= VR_RXCFG_RX_MULTI; - CSR_WRITE_1(sc, VR_RXCFG, rxfilt); - CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); - CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); - return; - } - - /* first, zot all the existing hash bits */ - CSR_WRITE_4(sc, VR_MAR0, 0); - CSR_WRITE_4(sc, VR_MAR1, 0); - - /* now program new ones */ - for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; - ifma = ifma->ifma_link.le_next) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - mcnt++; - } - - if (mcnt) - rxfilt |= VR_RXCFG_RX_MULTI; - else - rxfilt &= ~VR_RXCFG_RX_MULTI; - - CSR_WRITE_4(sc, VR_MAR0, hashes[0]); - CSR_WRITE_4(sc, VR_MAR1, hashes[1]); - CSR_WRITE_1(sc, VR_RXCFG, rxfilt); - - return; -} - -/* - * Initiate an autonegotiation session. - */ -static void vr_autoneg_xmit(sc) - struct vr_softc *sc; -{ - u_int16_t phy_sts; - - vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(vr_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - - phy_sts = vr_phy_readreg(sc, PHY_BMCR); - phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; - vr_phy_writereg(sc, PHY_BMCR, phy_sts); - - return; -} - -/* - * Invoke autonegotiation on a PHY. - */ -static void vr_autoneg_mii(sc, flag, verbose) - struct vr_softc *sc; - int flag; - int verbose; -{ - u_int16_t phy_sts = 0, media, advert, ability; - struct ifnet *ifp; - struct ifmedia *ifm; - - ifm = &sc->ifmedia; - ifp = &sc->arpcom.ac_if; - - ifm->ifm_media = IFM_ETHER | IFM_AUTO; - - /* - * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported' - * bit cleared in the status register, but has the 'autoneg enabled' - * bit set in the control register. This is a contradiction, and - * I'm not sure how to handle it. If you want to force an attempt - * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR - * and see what happens. - */ -#ifndef FORCE_AUTONEG_TFOUR - /* - * First, see if autoneg is supported. If not, there's - * no point in continuing. - */ - phy_sts = vr_phy_readreg(sc, PHY_BMSR); - if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { - if (verbose) - printf("vr%d: autonegotiation not supported\n", - sc->vr_unit); - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - return; - } -#endif - - switch (flag) { - case VR_FLAG_FORCEDELAY: - /* - * XXX Never use this option anywhere but in the probe - * routine: making the kernel stop dead in its tracks - * for three whole seconds after we've gone multi-user - * is really bad manners. - */ - vr_autoneg_xmit(sc); - DELAY(5000000); - break; - case VR_FLAG_SCHEDDELAY: - /* - * Wait for the transmitter to go idle before starting - * an autoneg session, otherwise vr_start() may clobber - * our timeout, and we don't want to allow transmission - * during an autoneg session since that can screw it up. - */ - if (sc->vr_cdata.vr_tx_head != NULL) { - sc->vr_want_auto = 1; - return; - } - vr_autoneg_xmit(sc); - ifp->if_timer = 5; - sc->vr_autoneg = 1; - sc->vr_want_auto = 0; - return; - break; - case VR_FLAG_DELAYTIMEO: - ifp->if_timer = 0; - sc->vr_autoneg = 0; - break; - default: - printf("vr%d: invalid autoneg flag: %d\n", sc->vr_unit, flag); - return; - } - - if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { - if (verbose) - printf("vr%d: autoneg complete, ", sc->vr_unit); - phy_sts = vr_phy_readreg(sc, PHY_BMSR); - } else { - if (verbose) - printf("vr%d: autoneg not complete, ", sc->vr_unit); - } - - media = vr_phy_readreg(sc, PHY_BMCR); - - /* Link is good. Report modes and set duplex mode. */ - if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { - if (verbose) - printf("link status good "); - advert = vr_phy_readreg(sc, PHY_ANAR); - ability = vr_phy_readreg(sc, PHY_LPAR); - - if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { - ifm->ifm_media = IFM_ETHER|IFM_100_T4; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(100baseT4)\n"); - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - media |= PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - media &= ~PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 10Mbps)\n"); - } else { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - media &= ~PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 10Mbps)\n"); - } - - media &= ~PHY_BMCR_AUTONEGENBL; - - /* Set ASIC's duplex mode to match the PHY. */ - vr_setcfg(sc, media); - vr_phy_writereg(sc, PHY_BMCR, media); - } else { - if (verbose) - printf("no carrier\n"); - } - - vr_init(sc); - - if (sc->vr_tx_pend) { - sc->vr_autoneg = 0; - sc->vr_tx_pend = 0; - vr_start(ifp); - } - - return; -} - -static void vr_getmode_mii(sc) - struct vr_softc *sc; -{ - u_int16_t bmsr; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - bmsr = vr_phy_readreg(sc, PHY_BMSR); - if (bootverbose) - printf("vr%d: PHY status word: %x\n", sc->vr_unit, bmsr); - - /* fallback */ - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - - if (bmsr & PHY_BMSR_10BTHALF) { - if (bootverbose) - printf("vr%d: 10Mbps half-duplex mode supported\n", - sc->vr_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); - } - - if (bmsr & PHY_BMSR_10BTFULL) { - if (bootverbose) - printf("vr%d: 10Mbps full-duplex mode supported\n", - sc->vr_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - } - - if (bmsr & PHY_BMSR_100BTXHALF) { - if (bootverbose) - printf("vr%d: 100Mbps half-duplex mode supported\n", - sc->vr_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - } - - if (bmsr & PHY_BMSR_100BTXFULL) { - if (bootverbose) - printf("vr%d: 100Mbps full-duplex mode supported\n", - sc->vr_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - } - - /* Some also support 100BaseT4. */ - if (bmsr & PHY_BMSR_100BT4) { - if (bootverbose) - printf("vr%d: 100baseT4 mode supported\n", sc->vr_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4; -#ifdef FORCE_AUTONEG_TFOUR - if (bootverbose) - printf("vr%d: forcing on autoneg support for BT4\n", - sc->vr_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; -#endif - } - - if (bmsr & PHY_BMSR_CANAUTONEG) { - if (bootverbose) - printf("vr%d: autoneg supported\n", sc->vr_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; - } - - return; -} - -/* - * Set speed and duplex mode. - */ -static void vr_setmode_mii(sc, media) - struct vr_softc *sc; - int media; -{ - u_int16_t bmcr; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - /* - * If an autoneg session is in progress, stop it. - */ - if (sc->vr_autoneg) { - printf("vr%d: canceling autoneg session\n", sc->vr_unit); - ifp->if_timer = sc->vr_autoneg = sc->vr_want_auto = 0; - bmcr = vr_phy_readreg(sc, PHY_BMCR); - bmcr &= ~PHY_BMCR_AUTONEGENBL; - vr_phy_writereg(sc, PHY_BMCR, bmcr); - } - - printf("vr%d: selecting MII, ", sc->vr_unit); - - bmcr = vr_phy_readreg(sc, PHY_BMCR); - - bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL| - PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); - - if (IFM_SUBTYPE(media) == IFM_100_T4) { - printf("100Mbps/T4, half-duplex\n"); - bmcr |= PHY_BMCR_SPEEDSEL; - bmcr &= ~PHY_BMCR_DUPLEX; - } - - if (IFM_SUBTYPE(media) == IFM_100_TX) { - printf("100Mbps, "); - bmcr |= PHY_BMCR_SPEEDSEL; - } - - if (IFM_SUBTYPE(media) == IFM_10_T) { - printf("10Mbps, "); - bmcr &= ~PHY_BMCR_SPEEDSEL; - } - - if ((media & IFM_GMASK) == IFM_FDX) { - printf("full duplex\n"); - bmcr |= PHY_BMCR_DUPLEX; - } else { - printf("half duplex\n"); - bmcr &= ~PHY_BMCR_DUPLEX; - } - - vr_setcfg(sc, bmcr); - vr_phy_writereg(sc, PHY_BMCR, bmcr); - - return; -} - -/* - * In order to fiddle with the - * 'full-duplex' and '100Mbps' bits in the netconfig register, we - * first have to put the transmit and/or receive logic in the idle state. - */ -static void vr_setcfg(sc, bmcr) - struct vr_softc *sc; - u_int16_t bmcr; -{ - int restart = 0; - - if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { - restart = 1; - VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); - } - - if (bmcr & PHY_BMCR_DUPLEX) - VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); - else - VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); - - if (restart) - VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); - - return; -} - -static void vr_reset(sc) - struct vr_softc *sc; -{ - register int i; - - VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); - - for (i = 0; i < VR_TIMEOUT; i++) { - DELAY(10); - if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) - break; - } - if (i == VR_TIMEOUT) - printf("vr%d: reset never completed!\n", sc->vr_unit); - - /* Wait a little while for the chip to get its brains in order. */ - DELAY(1000); - - return; -} - -/* - * Probe for a VIA Rhine chip. Check the PCI vendor and device - * IDs against our list and return a device name if we find a match. - */ -static const char * -vr_probe(config_id, device_id) - pcici_t config_id; - pcidi_t device_id; -{ - struct vr_type *t; - - t = vr_devs; - - while(t->vr_name != NULL) { - if ((device_id & 0xFFFF) == t->vr_vid && - ((device_id >> 16) & 0xFFFF) == t->vr_did) { - return(t->vr_name); - } - t++; - } - - return(NULL); -} - -/* - * Attach the interface. Allocate softc structures, do ifmedia - * setup and ethernet/BPF attach. - */ -static void -vr_attach(config_id, unit) - pcici_t config_id; - int unit; -{ - int s, i; -#ifndef VR_USEIOSPACE - vm_offset_t pbase, vbase; -#endif - u_char eaddr[ETHER_ADDR_LEN]; - u_int32_t command; - struct vr_softc *sc; - struct ifnet *ifp; - int media = IFM_ETHER|IFM_100_TX|IFM_FDX; - unsigned int round; - caddr_t roundptr; - struct vr_type *p; - u_int16_t phy_vid, phy_did, phy_sts; - - s = splimp(); - - sc = malloc(sizeof(struct vr_softc), M_DEVBUF, M_NOWAIT); - if (sc == NULL) { - printf("vr%d: no memory for softc struct!\n", unit); - return; - } - bzero(sc, sizeof(struct vr_softc)); - - /* - * Handle power management nonsense. - */ - - command = pci_conf_read(config_id, VR_PCI_CAPID) & 0x000000FF; - if (command == 0x01) { - - command = pci_conf_read(config_id, VR_PCI_PWRMGMTCTRL); - if (command & VR_PSTATE_MASK) { - u_int32_t iobase, membase, irq; - - /* Save important PCI config data. */ - iobase = pci_conf_read(config_id, VR_PCI_LOIO); - membase = pci_conf_read(config_id, VR_PCI_LOMEM); - irq = pci_conf_read(config_id, VR_PCI_INTLINE); - - /* Reset the power state. */ - printf("vr%d: chip is in D%d power mode " - "-- setting to D0\n", unit, command & VR_PSTATE_MASK); - command &= 0xFFFFFFFC; - pci_conf_write(config_id, VR_PCI_PWRMGMTCTRL, command); - - /* Restore PCI config data. */ - pci_conf_write(config_id, VR_PCI_LOIO, iobase); - pci_conf_write(config_id, VR_PCI_LOMEM, membase); - pci_conf_write(config_id, VR_PCI_INTLINE, irq); - } - } - - /* - * Map control/status registers. - */ - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); - pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - -#ifdef VR_USEIOSPACE - if (!(command & PCIM_CMD_PORTEN)) { - printf("vr%d: failed to enable I/O ports!\n", unit); - free(sc, M_DEVBUF); - goto fail; - } - - if (!pci_map_port(config_id, VR_PCI_LOIO, - (u_int16_t *)(&sc->vr_bhandle))) { - printf ("vr%d: couldn't map ports\n", unit); - goto fail; - } - sc->vr_btag = I386_BUS_SPACE_IO; -#else - if (!(command & PCIM_CMD_MEMEN)) { - printf("vr%d: failed to enable memory mapping!\n", unit); - goto fail; - } - - if (!pci_map_mem(config_id, VR_PCI_LOMEM, &vbase, &pbase)) { - printf ("vr%d: couldn't map memory\n", unit); - goto fail; - } - - sc->vr_bhandle = vbase; - sc->vr_btag = I386_BUS_SPACE_MEM; -#endif - - /* Allocate interrupt */ - if (!pci_map_int(config_id, vr_intr, sc, &net_imask)) { - printf("vr%d: couldn't map interrupt\n", unit); - goto fail; - } - - /* Reset the adapter. */ - vr_reset(sc); - - /* - * Get station address. The way the Rhine chips work, - * you're not allowed to directly access the EEPROM once - * they've been programmed a special way. Consequently, - * we need to read the node address from the PAR0 and PAR1 - * registers. - */ - VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); - DELAY(200); - for (i = 0; i < ETHER_ADDR_LEN; i++) - eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); - - /* - * A Rhine chip was detected. Inform the world. - */ - printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":"); - - sc->vr_unit = unit; - bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); - - sc->vr_ldata_ptr = malloc(sizeof(struct vr_list_data) + 8, - M_DEVBUF, M_NOWAIT); - if (sc->vr_ldata_ptr == NULL) { - free(sc, M_DEVBUF); - printf("vr%d: no memory for list buffers!\n", unit); - return; - } - - sc->vr_ldata = (struct vr_list_data *)sc->vr_ldata_ptr; - round = (unsigned int)sc->vr_ldata_ptr & 0xF; - roundptr = sc->vr_ldata_ptr; - for (i = 0; i < 8; i++) { - if (round % 8) { - round++; - roundptr++; - } else - break; - } - sc->vr_ldata = (struct vr_list_data *)roundptr; - bzero(sc->vr_ldata, sizeof(struct vr_list_data)); - - ifp = &sc->arpcom.ac_if; - ifp->if_softc = sc; - ifp->if_unit = unit; - ifp->if_name = "vr"; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = vr_ioctl; - ifp->if_output = ether_output; - ifp->if_start = vr_start; - ifp->if_watchdog = vr_watchdog; - ifp->if_init = vr_init; - ifp->if_baudrate = 10000000; - - if (bootverbose) - printf("vr%d: probing for a PHY\n", sc->vr_unit); - for (i = VR_PHYADDR_MIN; i < VR_PHYADDR_MAX + 1; i++) { - if (bootverbose) - printf("vr%d: checking address: %d\n", - sc->vr_unit, i); - sc->vr_phy_addr = i; - vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(vr_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - if ((phy_sts = vr_phy_readreg(sc, PHY_BMSR))) - break; - } - if (phy_sts) { - phy_vid = vr_phy_readreg(sc, PHY_VENID); - phy_did = vr_phy_readreg(sc, PHY_DEVID); - if (bootverbose) - printf("vr%d: found PHY at address %d, ", - sc->vr_unit, sc->vr_phy_addr); - if (bootverbose) - printf("vendor id: %x device id: %x\n", - phy_vid, phy_did); - p = vr_phys; - while(p->vr_vid) { - if (phy_vid == p->vr_vid && - (phy_did | 0x000F) == p->vr_did) { - sc->vr_pinfo = p; - break; - } - p++; - } - if (sc->vr_pinfo == NULL) - sc->vr_pinfo = &vr_phys[PHY_UNKNOWN]; - if (bootverbose) - printf("vr%d: PHY type: %s\n", - sc->vr_unit, sc->vr_pinfo->vr_name); - } else { - printf("vr%d: MII without any phy!\n", sc->vr_unit); - goto fail; - } - - /* - * Do ifmedia setup. - */ - ifmedia_init(&sc->ifmedia, 0, vr_ifmedia_upd, vr_ifmedia_sts); - - vr_getmode_mii(sc); - vr_autoneg_mii(sc, VR_FLAG_FORCEDELAY, 1); - media = sc->ifmedia.ifm_media; - vr_stop(sc); - - ifmedia_set(&sc->ifmedia, media); - - /* - * Call MI attach routines. - */ - if_attach(ifp); - ether_ifattach(ifp); - -#if NBPFILTER > 0 - bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif - - at_shutdown(vr_shutdown, sc, SHUTDOWN_POST_SYNC); - -fail: - splx(s); - return; -} - -/* - * Initialize the transmit descriptors. - */ -static int vr_list_tx_init(sc) - struct vr_softc *sc; -{ - struct vr_chain_data *cd; - struct vr_list_data *ld; - int i; - - cd = &sc->vr_cdata; - ld = sc->vr_ldata; - for (i = 0; i < VR_TX_LIST_CNT; i++) { - cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; - if (i == (VR_TX_LIST_CNT - 1)) - cd->vr_tx_chain[i].vr_nextdesc = - &cd->vr_tx_chain[0]; - else - cd->vr_tx_chain[i].vr_nextdesc = - &cd->vr_tx_chain[i + 1]; - } - - cd->vr_tx_free = &cd->vr_tx_chain[0]; - cd->vr_tx_tail = cd->vr_tx_head = NULL; - - return(0); -} - - -/* - * Initialize the RX descriptors and allocate mbufs for them. Note that - * we arrange the descriptors in a closed ring, so that the last descriptor - * points back to the first. - */ -static int vr_list_rx_init(sc) - struct vr_softc *sc; -{ - struct vr_chain_data *cd; - struct vr_list_data *ld; - int i; - - cd = &sc->vr_cdata; - ld = sc->vr_ldata; - - for (i = 0; i < VR_RX_LIST_CNT; i++) { - cd->vr_rx_chain[i].vr_ptr = - (struct vr_desc *)&ld->vr_rx_list[i]; - if (vr_newbuf(sc, &cd->vr_rx_chain[i]) == ENOBUFS) - return(ENOBUFS); - if (i == (VR_RX_LIST_CNT - 1)) { - cd->vr_rx_chain[i].vr_nextdesc = - &cd->vr_rx_chain[0]; - ld->vr_rx_list[i].vr_next = - vtophys(&ld->vr_rx_list[0]); - } else { - cd->vr_rx_chain[i].vr_nextdesc = - &cd->vr_rx_chain[i + 1]; - ld->vr_rx_list[i].vr_next = - vtophys(&ld->vr_rx_list[i + 1]); - } - } - - cd->vr_rx_head = &cd->vr_rx_chain[0]; - - return(0); -} - -/* - * Initialize an RX descriptor and attach an MBUF cluster. - * Note: the length fields are only 11 bits wide, which means the - * largest size we can specify is 2047. This is important because - * MCLBYTES is 2048, so we have to subtract one otherwise we'll - * overflow the field and make a mess. - */ -static int vr_newbuf(sc, c) - struct vr_softc *sc; - struct vr_chain_onefrag *c; -{ - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("vr%d: no memory for rx list -- packet dropped!\n", - sc->vr_unit); - return(ENOBUFS); - } - - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - printf("vr%d: no memory for rx list -- packet dropped!\n", - sc->vr_unit); - m_freem(m_new); - return(ENOBUFS); - } - - c->vr_mbuf = m_new; - c->vr_ptr->vr_status = VR_RXSTAT; - c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); - c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; - - return(0); -} - -/* - * A frame has been uploaded: pass the resulting mbuf chain up to - * the higher level protocols. - */ -static void vr_rxeof(sc) - struct vr_softc *sc; -{ - struct ether_header *eh; - struct mbuf *m; - struct ifnet *ifp; - struct vr_chain_onefrag *cur_rx; - int total_len = 0; - u_int32_t rxstat; - - ifp = &sc->arpcom.ac_if; - - while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & - VR_RXSTAT_OWN)) { - cur_rx = sc->vr_cdata.vr_rx_head; - sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; - - /* - * If an error occurs, update stats, clear the - * status word and leave the mbuf cluster in place: - * it should simply get re-used next time this descriptor - * comes up in the ring. - */ - if (rxstat & VR_RXSTAT_RXERR) { - ifp->if_ierrors++; - printf("vr%d: rx error: ", sc->vr_unit); - switch(rxstat & 0x000000FF) { - case VR_RXSTAT_CRCERR: - printf("crc error\n"); - break; - case VR_RXSTAT_FRAMEALIGNERR: - printf("frame alignment error\n"); - break; - case VR_RXSTAT_FIFOOFLOW: - printf("FIFO overflow\n"); - break; - case VR_RXSTAT_GIANT: - printf("received giant packet\n"); - break; - case VR_RXSTAT_RUNT: - printf("received runt packet\n"); - break; - case VR_RXSTAT_BUSERR: - printf("system bus error\n"); - break; - case VR_RXSTAT_BUFFERR: - printf("rx buffer error\n"); - break; - default: - printf("unknown rx error\n"); - break; - } - cur_rx->vr_ptr->vr_status = VR_RXSTAT; - cur_rx->vr_ptr->vr_ctl = VR_RXCTL|VR_RXLEN; - continue; - } - - /* No errors; receive the packet. */ - m = cur_rx->vr_mbuf; - total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); - - /* - * XXX The VIA Rhine chip includes the CRC with every - * received frame, and there's no way to turn this - * behavior off (at least, I can't find anything in - * the manual that explains how to do it) so we have - * to trim off the CRC manually. - */ - total_len -= ETHER_CRC_LEN; - - /* - * Try to conjure up a new mbuf cluster. If that - * fails, it means we have an out of memory condition and - * should leave the buffer in place and continue. This will - * result in a lost packet, but there's little else we - * can do in this situation. - */ - if (vr_newbuf(sc, cur_rx) == ENOBUFS) { - ifp->if_ierrors++; - cur_rx->vr_ptr->vr_status = VR_RXSTAT; - cur_rx->vr_ptr->vr_ctl = VR_RXCTL|VR_RXLEN; - continue; - } - - ifp->if_ipackets++; - eh = mtod(m, struct ether_header *); - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = m->m_len = total_len; -#if NBPFILTER > 0 - /* - * Handle BPF listeners. Let the BPF user see the packet, but - * don't pass it up to the ether_input() layer unless it's - * a broadcast packet, multicast packet, matches our ethernet - * address or the interface is in promiscuous mode. - */ - if (ifp->if_bpf) { - bpf_mtap(ifp, m); - if (ifp->if_flags & IFF_PROMISC && - (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, - ETHER_ADDR_LEN) && - (eh->ether_dhost[0] & 1) == 0)) { - m_freem(m); - continue; - } - } -#endif - /* Remove header from mbuf and pass it on. */ - m_adj(m, sizeof(struct ether_header)); - ether_input(ifp, eh, m); - } - - return; -} - -void vr_rxeoc(sc) - struct vr_softc *sc; -{ - - vr_rxeof(sc); - VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); - CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); - VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); - VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); - - return; -} - -/* - * A frame was downloaded to the chip. It's safe for us to clean up - * the list buffers. - */ - -static void vr_txeof(sc) - struct vr_softc *sc; -{ - struct vr_chain *cur_tx; - struct ifnet *ifp; - register struct mbuf *n; - - ifp = &sc->arpcom.ac_if; - - /* Clear the timeout timer. */ - ifp->if_timer = 0; - - /* Sanity check. */ - if (sc->vr_cdata.vr_tx_head == NULL) - return; - - /* - * Go through our tx list and free mbufs for those - * frames that have been transmitted. - */ - while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) { - u_int32_t txstat; - - cur_tx = sc->vr_cdata.vr_tx_head; - txstat = cur_tx->vr_ptr->vr_status; - - if (txstat & VR_TXSTAT_OWN) - break; - - if (txstat & VR_TXSTAT_ERRSUM) { - ifp->if_oerrors++; - if (txstat & VR_TXSTAT_DEFER) - ifp->if_collisions++; - if (txstat & VR_TXSTAT_LATECOLL) - ifp->if_collisions++; - } - - ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; - - ifp->if_opackets++; - MFREE(cur_tx->vr_mbuf, n); - cur_tx->vr_mbuf = NULL; - - if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) { - sc->vr_cdata.vr_tx_head = NULL; - sc->vr_cdata.vr_tx_tail = NULL; - break; - } - - sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc; - } - - return; -} - -/* - * TX 'end of channel' interrupt handler. - */ -static void vr_txeoc(sc) - struct vr_softc *sc; -{ - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - ifp->if_timer = 0; - - if (sc->vr_cdata.vr_tx_head == NULL) { - ifp->if_flags &= ~IFF_OACTIVE; - sc->vr_cdata.vr_tx_tail = NULL; - if (sc->vr_want_auto) - vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1); - } - - return; -} - -static void vr_intr(arg) - void *arg; -{ - struct vr_softc *sc; - struct ifnet *ifp; - u_int16_t status; - - sc = arg; - ifp = &sc->arpcom.ac_if; - - /* Supress unwanted interrupts. */ - if (!(ifp->if_flags & IFF_UP)) { - vr_stop(sc); - return; - } - - /* Disable interrupts. */ - CSR_WRITE_2(sc, VR_IMR, 0x0000); - - for (;;) { - - status = CSR_READ_2(sc, VR_ISR); - if (status) - CSR_WRITE_2(sc, VR_ISR, status); - - if ((status & VR_INTRS) == 0) - break; - - if (status & VR_ISR_RX_OK) - vr_rxeof(sc); - - if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || - (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) || - (status & VR_ISR_RX_DROPPED)) { - vr_rxeof(sc); - vr_rxeoc(sc); - } - - if (status & VR_ISR_TX_OK) { - vr_txeof(sc); - vr_txeoc(sc); - } - - if ((status & VR_ISR_TX_UNDERRUN)||(status & VR_ISR_TX_ABRT)){ - ifp->if_oerrors++; - vr_txeof(sc); - if (sc->vr_cdata.vr_tx_head != NULL) { - VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); - VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); - } - } - - if (status & VR_ISR_BUSERR) { - vr_reset(sc); - vr_init(sc); - } - } - - /* Re-enable interrupts. */ - CSR_WRITE_2(sc, VR_IMR, VR_INTRS); - - if (ifp->if_snd.ifq_head != NULL) { - vr_start(ifp); - } - - return; -} - -/* - * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data - * pointers to the fragment pointers. - */ -static int vr_encap(sc, c, m_head) - struct vr_softc *sc; - struct vr_chain *c; - struct mbuf *m_head; -{ - int frag = 0; - struct vr_desc *f = NULL; - int total_len; - struct mbuf *m; - - m = m_head; - total_len = 0; - - /* - * The VIA Rhine wants packet buffers to be longword - * aligned, but very often our mbufs aren't. Rather than - * waste time trying to decide when to copy and when not - * to copy, just do it all the time. - */ - if (m != NULL) { - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("vr%d: no memory for tx list", sc->vr_unit); - return(1); - } - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - printf("vr%d: no memory for tx list", - sc->vr_unit); - return(1); - } - } - m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; - m_freem(m_head); - m_head = m_new; - /* - * The Rhine chip doesn't auto-pad, so we have to make - * sure to pad short frames out to the minimum frame length - * ourselves. - */ - if (m_head->m_len < VR_MIN_FRAMELEN) { - m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len; - m_new->m_len = m_new->m_pkthdr.len; - } - f = c->vr_ptr; - f->vr_data = vtophys(mtod(m_new, caddr_t)); - f->vr_ctl = total_len = m_new->m_len; - f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; - f->vr_status = 0; - frag = 1; - } - - c->vr_mbuf = m_head; - c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; - c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr); - - return(0); -} - -/* - * Main transmit routine. To avoid having to do mbuf copies, we put pointers - * to the mbuf data regions directly in the transmit lists. We also save a - * copy of the pointers since the transmit list fragment pointers are - * physical addresses. - */ - -static void vr_start(ifp) - struct ifnet *ifp; -{ - struct vr_softc *sc; - struct mbuf *m_head = NULL; - struct vr_chain *cur_tx = NULL, *start_tx; - - sc = ifp->if_softc; - - if (sc->vr_autoneg) { - sc->vr_tx_pend = 1; - return; - } - - /* - * Check for an available queue slot. If there are none, - * punt. - */ - if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) { - ifp->if_flags |= IFF_OACTIVE; - return; - } - - start_tx = sc->vr_cdata.vr_tx_free; - - while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) { - IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) - break; - - /* Pick a descriptor off the free list. */ - cur_tx = sc->vr_cdata.vr_tx_free; - sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc; - - /* Pack the data into the descriptor. */ - vr_encap(sc, cur_tx, m_head); - - if (cur_tx != start_tx) - VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; - -#if NBPFILTER > 0 - /* - * If there's a BPF listener, bounce a copy of this frame - * to him. - */ - if (ifp->if_bpf) - bpf_mtap(ifp, cur_tx->vr_mbuf); -#endif - VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; - VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_TX_GO); - } - - /* - * If there are no frames queued, bail. - */ - if (cur_tx == NULL) - return; - - sc->vr_cdata.vr_tx_tail = cur_tx; - - if (sc->vr_cdata.vr_tx_head == NULL) - sc->vr_cdata.vr_tx_head = start_tx; - - /* - * Set a timeout in case the chip goes out to lunch. - */ - ifp->if_timer = 5; - - return; -} - -static void vr_init(xsc) - void *xsc; -{ - struct vr_softc *sc = xsc; - struct ifnet *ifp = &sc->arpcom.ac_if; - u_int16_t phy_bmcr = 0; - int s; - - if (sc->vr_autoneg) - return; - - s = splimp(); - - if (sc->vr_pinfo != NULL) - phy_bmcr = vr_phy_readreg(sc, PHY_BMCR); - - /* - * Cancel pending I/O and free all RX/TX buffers. - */ - vr_stop(sc); - vr_reset(sc); - - VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); - VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_STORENFWD); - - VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); - VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); - - /* Init circular RX list. */ - if (vr_list_rx_init(sc) == ENOBUFS) { - printf("vr%d: initialization failed: no " - "memory for rx buffers\n", sc->vr_unit); - vr_stop(sc); - (void)splx(s); - return; - } - - /* - * Init tx descriptors. - */ - vr_list_tx_init(sc); - - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) - VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); - else - VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); - - /* Set capture broadcast bit to capture broadcast frames. */ - if (ifp->if_flags & IFF_BROADCAST) - VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); - else - VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); - - /* - * Program the multicast filter, if necessary. - */ - vr_setmulti(sc); - - /* - * Load the address of the RX list. - */ - CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); - - /* Enable receiver and transmitter. */ - CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| - VR_CMD_TX_ON|VR_CMD_RX_ON| - VR_CMD_RX_GO); - - vr_setcfg(sc, vr_phy_readreg(sc, PHY_BMCR)); - - CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); - - /* - * Enable interrupts. - */ - CSR_WRITE_2(sc, VR_ISR, 0xFFFF); - CSR_WRITE_2(sc, VR_IMR, VR_INTRS); - - /* Restore state of BMCR */ - if (sc->vr_pinfo != NULL) - vr_phy_writereg(sc, PHY_BMCR, phy_bmcr); - - ifp->if_flags |= IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - - (void)splx(s); - - return; -} - -/* - * Set media options. - */ -static int vr_ifmedia_upd(ifp) - struct ifnet *ifp; -{ - struct vr_softc *sc; - struct ifmedia *ifm; - - sc = ifp->if_softc; - ifm = &sc->ifmedia; - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return(EINVAL); - - if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) - vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1); - else - vr_setmode_mii(sc, ifm->ifm_media); - - return(0); -} - -/* - * Report current media status. - */ -static void vr_ifmedia_sts(ifp, ifmr) - struct ifnet *ifp; - struct ifmediareq *ifmr; -{ - struct vr_softc *sc; - u_int16_t advert = 0, ability = 0; - - sc = ifp->if_softc; - - ifmr->ifm_active = IFM_ETHER; - - if (!(vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { - if (vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) - ifmr->ifm_active = IFM_ETHER|IFM_100_TX; - else - ifmr->ifm_active = IFM_ETHER|IFM_10_T; - if (vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) - ifmr->ifm_active |= IFM_FDX; - else - ifmr->ifm_active |= IFM_HDX; - return; - } - - ability = vr_phy_readreg(sc, PHY_LPAR); - advert = vr_phy_readreg(sc, PHY_ANAR); - if (advert & PHY_ANAR_100BT4 && - ability & PHY_ANAR_100BT4) { - ifmr->ifm_active = IFM_ETHER|IFM_100_T4; - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX; - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX; - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX; - } else if (advert & PHY_ANAR_10BTHALF && - ability & PHY_ANAR_10BTHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX; - } - - return; -} - -static int vr_ioctl(ifp, command, data) - struct ifnet *ifp; - u_long command; - caddr_t data; -{ - struct vr_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; - int s, error = 0; - - s = splimp(); - - switch(command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; - case SIOCSIFFLAGS: - if (ifp->if_flags & IFF_UP) { - vr_init(sc); - } else { - if (ifp->if_flags & IFF_RUNNING) - vr_stop(sc); - } - error = 0; - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - vr_setmulti(sc); - error = 0; - break; - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); - break; - default: - error = EINVAL; - break; - } - - (void)splx(s); - - return(error); -} - -static void vr_watchdog(ifp) - struct ifnet *ifp; -{ - struct vr_softc *sc; - - sc = ifp->if_softc; - - if (sc->vr_autoneg) { - vr_autoneg_mii(sc, VR_FLAG_DELAYTIMEO, 1); - return; - } - - ifp->if_oerrors++; - printf("vr%d: watchdog timeout\n", sc->vr_unit); - - if (!(vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) - printf("vr%d: no carrier - transceiver cable problem?\n", - sc->vr_unit); - - vr_stop(sc); - vr_reset(sc); - vr_init(sc); - - if (ifp->if_snd.ifq_head != NULL) - vr_start(ifp); - - return; -} - -/* - * Stop the adapter and free any mbufs allocated to the - * RX and TX lists. - */ -static void vr_stop(sc) - struct vr_softc *sc; -{ - register int i; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - ifp->if_timer = 0; - - VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); - VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); - CSR_WRITE_2(sc, VR_IMR, 0x0000); - CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); - CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); - - /* - * Free data in the RX lists. - */ - for (i = 0; i < VR_RX_LIST_CNT; i++) { - if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { - m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); - sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; - } - } - bzero((char *)&sc->vr_ldata->vr_rx_list, - sizeof(sc->vr_ldata->vr_rx_list)); - - /* - * Free the TX list buffers. - */ - for (i = 0; i < VR_TX_LIST_CNT; i++) { - if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { - m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); - sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; - } - } - - bzero((char *)&sc->vr_ldata->vr_tx_list, - sizeof(sc->vr_ldata->vr_tx_list)); - - ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - - return; -} - -/* - * Stop all chip I/O so that the kernel's probe routines don't - * get confused by errant DMAs when rebooting. - */ -static void vr_shutdown(howto, arg) - int howto; - void *arg; -{ - struct vr_softc *sc = (struct vr_softc *)arg; - - vr_stop(sc); - - return; -} - -static struct pci_device vr_device = { - "vr", - vr_probe, - vr_attach, - &vr_count, - NULL -}; -DATA_SET(pcidevice_set, vr_device); diff --git a/sys/pci/if_vrreg.h b/sys/pci/if_vrreg.h deleted file mode 100644 index b44dcabd1316..000000000000 --- a/sys/pci/if_vrreg.h +++ /dev/null @@ -1,616 +0,0 @@ -/* - * Copyright (c) 1997, 1998 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_vrreg.h,v 1.9 1999/01/10 18:06:10 wpaul Exp $ - */ - -/* - * Rhine register definitions. - */ - -#define VR_PAR0 0x00 /* node address 0 to 4 */ -#define VR_PAR1 0x04 /* node address 2 to 6 */ -#define VR_RXCFG 0x06 /* receiver config register */ -#define VR_TXCFG 0x07 /* transmit config register */ -#define VR_COMMAND 0x08 /* command register */ -#define VR_ISR 0x0C /* interrupt/status register */ -#define VR_IMR 0x0E /* interrupt mask register */ -#define VR_MAR0 0x10 /* multicast hash 0 */ -#define VR_MAR1 0x14 /* multicast hash 1 */ -#define VR_RXADDR 0x18 /* rx descriptor list start addr */ -#define VR_TXADDR 0x1C /* tx descriptor list start addr */ -#define VR_CURRXDESC0 0x20 -#define VR_CURRXDESC1 0x24 -#define VR_CURRXDESC2 0x28 -#define VR_CURRXDESC3 0x2C -#define VR_NEXTRXDESC0 0x30 -#define VR_NEXTRXDESC1 0x34 -#define VR_NEXTRXDESC2 0x38 -#define VR_NEXTRXDESC3 0x3C -#define VR_CURTXDESC0 0x40 -#define VR_CURTXDESC1 0x44 -#define VR_CURTXDESC2 0x48 -#define VR_CURTXDESC3 0x4C -#define VR_NEXTTXDESC0 0x50 -#define VR_NEXTTXDESC1 0x54 -#define VR_NEXTTXDESC2 0x58 -#define VR_NEXTTXDESC3 0x5C -#define VR_CURRXDMA 0x60 /* current RX DMA address */ -#define VR_CURTXDMA 0x64 /* current TX DMA address */ -#define VR_TALLYCNT 0x68 /* tally counter test register */ -#define VR_PHYADDR 0x6C -#define VR_MIISTAT 0x6D -#define VR_BCR0 0x6E -#define VR_BCR1 0x6F -#define VR_MIICMD 0x70 -#define VR_MIIADDR 0x71 -#define VR_MIIDATA 0x72 -#define VR_EECSR 0x74 -#define VR_TEST 0x75 -#define VR_GPIO 0x76 -#define VR_CONFIG 0x78 -#define VR_MPA_CNT 0x7C -#define VR_CRC_CNT 0x7E - -/* - * RX config bits. - */ -#define VR_RXCFG_RX_ERRPKTS 0x01 -#define VR_RXCFG_RX_RUNT 0x02 -#define VR_RXCFG_RX_MULTI 0x04 -#define VR_RXCFG_RX_BROAD 0x08 -#define VR_RXCFG_RX_PROMISC 0x10 -#define VR_RXCFG_RX_THRESH 0xE0 - -#define VR_RXTHRESH_32BYTES 0x00 -#define VR_RXTHRESH_64BYTES 0x20 -#define VR_RXTHRESH_128BYTES 0x40 -#define VR_RXTHRESH_256BYTES 0x60 -#define VR_RXTHRESH_512BYTES 0x80 -#define VR_RXTHRESH_768BYTES 0xA0 -#define VR_RXTHRESH_1024BYTES 0xC0 -#define VR_RXTHRESH_STORENFWD 0xE0 - -/* - * TX config bits. - */ -#define VR_TXCFG_RSVD0 0x01 -#define VR_TXCFG_LOOPBKMODE 0x06 -#define VR_TXCFG_BACKOFF 0x08 -#define VR_TXCFG_RSVD1 0x10 -#define VR_TXCFG_TX_THRESH 0xE0 - -#define VR_TXTHRESH_32BYTES 0x00 -#define VR_TXTHRESH_64BYTES 0x20 -#define VR_TXTHRESH_128BYTES 0x40 -#define VR_TXTHRESH_256BYTES 0x60 -#define VR_TXTHRESH_512BYTES 0x80 -#define VR_TXTHRESH_768BYTES 0xA0 -#define VR_TXTHRESH_1024BYTES 0xC0 -#define VR_TXTHRESH_STORENFWD 0xE0 - -/* - * Command register bits. - */ -#define VR_CMD_INIT 0x0001 -#define VR_CMD_START 0x0002 -#define VR_CMD_STOP 0x0004 -#define VR_CMD_RX_ON 0x0008 -#define VR_CMD_TX_ON 0x0010 -#define VR_CMD_TX_GO 0x0020 -#define VR_CMD_RX_GO 0x0040 -#define VR_CMD_RSVD 0x0080 -#define VR_CMD_RX_EARLY 0x0100 -#define VR_CMD_TX_EARLY 0x0200 -#define VR_CMD_FULLDUPLEX 0x0400 -#define VR_CMD_TX_NOPOLL 0x0800 - -#define VR_CMD_RESET 0x8000 - -/* - * Interrupt status bits. - */ -#define VR_ISR_RX_OK 0x0001 /* packet rx ok */ -#define VR_ISR_TX_OK 0x0002 /* packet tx ok */ -#define VR_ISR_RX_ERR 0x0004 /* packet rx with err */ -#define VR_ISR_TX_ABRT 0x0008 /* tx aborted due to excess colls */ -#define VR_ISR_TX_UNDERRUN 0x0010 /* tx buffer underflow */ -#define VR_ISR_RX_NOBUF 0x0020 /* no rx buffer available */ -#define VR_ISR_BUSERR 0x0040 /* PCI bus error */ -#define VR_ISR_STATSOFLOW 0x0080 /* stats counter oflow */ -#define VR_ISR_RX_EARLY 0x0100 /* rx early */ -#define VR_ISR_LINKSTAT 0x0200 /* MII status change */ -#define VR_ISR_RX_OFLOW 0x0400 /* rx FIFO overflow */ -#define VR_ISR_RX_DROPPED 0x0800 -#define VR_ISR_RX_NOBUF2 0x1000 -#define VR_ISR_TX_ABRT2 0x2000 -#define VR_ISR_LINKSTAT2 0x4000 -#define VR_ISR_MAGICPACKET 0x8000 - -/* - * Interrupt mask bits. - */ -#define VR_IMR_RX_OK 0x0001 /* packet rx ok */ -#define VR_IMR_TX_OK 0x0002 /* packet tx ok */ -#define VR_IMR_RX_ERR 0x0004 /* packet rx with err */ -#define VR_IMR_TX_ABRT 0x0008 /* tx aborted due to excess colls */ -#define VR_IMR_TX_UNDERRUN 0x0010 /* tx buffer underflow */ -#define VR_IMR_RX_NOBUF 0x0020 /* no rx buffer available */ -#define VR_IMR_BUSERR 0x0040 /* PCI bus error */ -#define VR_IMR_STATSOFLOW 0x0080 /* stats counter oflow */ -#define VR_IMR_RX_EARLY 0x0100 /* rx early */ -#define VR_IMR_LINKSTAT 0x0200 /* MII status change */ -#define VR_IMR_RX_OFLOW 0x0400 /* rx FIFO overflow */ -#define VR_IMR_RX_DROPPED 0x0800 -#define VR_IMR_RX_NOBUF2 0x1000 -#define VR_IMR_TX_ABRT2 0x2000 -#define VR_IMR_LINKSTAT2 0x4000 -#define VR_IMR_MAGICPACKET 0x8000 - -#define VR_INTRS \ - (VR_IMR_RX_OK|VR_IMR_TX_OK|VR_IMR_RX_NOBUF| \ - VR_IMR_TX_ABRT|VR_IMR_TX_UNDERRUN|VR_IMR_BUSERR| \ - VR_IMR_RX_ERR|VR_ISR_RX_DROPPED) - -/* - * MII status register. - */ - -#define VR_MIISTAT_SPEED 0x01 -#define VR_MIISTAT_LINKFAULT 0x02 -#define VR_MIISTAT_MGTREADERR 0x04 -#define VR_MIISTAT_MIIERR 0x08 -#define VR_MIISTAT_PHYOPT 0x10 -#define VR_MIISTAT_MDC_SPEED 0x20 -#define VR_MIISTAT_RSVD 0x40 -#define VR_MIISTAT_GPIO1POLL 0x80 - -/* - * MII command register bits. - */ -#define VR_MIICMD_CLK 0x01 -#define VR_MIICMD_DATAOUT 0x02 -#define VR_MIICMD_DATAIN 0x04 -#define VR_MIICMD_DIR 0x08 -#define VR_MIICMD_DIRECTPGM 0x10 -#define VR_MIICMD_WRITE_ENB 0x20 -#define VR_MIICMD_READ_ENB 0x40 -#define VR_MIICMD_AUTOPOLL 0x80 - -/* - * EEPROM control bits. - */ -#define VR_EECSR_DATAIN 0x01 /* data out */ -#define VR_EECSR_DATAOUT 0x02 /* data in */ -#define VR_EECSR_CLK 0x04 /* clock */ -#define VR_EECSR_CS 0x08 /* chip select */ -#define VR_EECSR_DPM 0x10 -#define VR_EECSR_LOAD 0x20 -#define VR_EECSR_EMBP 0x40 -#define VR_EECSR_EEPR 0x80 - -#define VR_EECMD_WRITE 0x140 -#define VR_EECMD_READ 0x180 -#define VR_EECMD_ERASE 0x1c0 - -/* - * Test register bits. - */ -#define VR_TEST_TEST0 0x01 -#define VR_TEST_TEST1 0x02 -#define VR_TEST_TEST2 0x04 -#define VR_TEST_TSTUD 0x08 -#define VR_TEST_TSTOV 0x10 -#define VR_TEST_BKOFF 0x20 -#define VR_TEST_FCOL 0x40 -#define VR_TEST_HBDES 0x80 - -/* - * Config register bits. - */ -#define VR_CFG_GPIO2OUTENB 0x00000001 -#define VR_CFG_GPIO2OUT 0x00000002 /* gen. purp. pin */ -#define VR_CFG_GPIO2IN 0x00000004 /* gen. purp. pin */ -#define VR_CFG_AUTOOPT 0x00000008 /* enable rx/tx autopoll */ -#define VR_CFG_MIIOPT 0x00000010 -#define VR_CFG_MMIENB 0x00000020 /* memory mapped mode enb */ -#define VR_CFG_JUMPER 0x00000040 /* PHY and oper. mode select */ -#define VR_CFG_EELOAD 0x00000080 /* enable EEPROM programming */ -#define VR_CFG_LATMENB 0x00000100 /* larency timer effect enb. */ -#define VR_CFG_MRREADWAIT 0x00000200 -#define VR_CFG_MRWRITEWAIT 0x00000400 -#define VR_CFG_RX_ARB 0x00000800 -#define VR_CFG_TX_ARB 0x00001000 -#define VR_CFG_READMULTI 0x00002000 -#define VR_CFG_TX_PACE 0x00004000 -#define VR_CFG_TX_QDIS 0x00008000 -#define VR_CFG_ROMSEL0 0x00010000 -#define VR_CFG_ROMSEL1 0x00020000 -#define VR_CFG_ROMSEL2 0x00040000 -#define VR_CFG_ROMTIMESEL 0x00080000 -#define VR_CFG_RSVD0 0x00100000 -#define VR_CFG_ROMDLY 0x00200000 -#define VR_CFG_ROMOPT 0x00400000 -#define VR_CFG_RSVD1 0x00800000 -#define VR_CFG_BACKOFFOPT 0x01000000 -#define VR_CFG_BACKOFFMOD 0x02000000 -#define VR_CFG_CAPEFFECT 0x04000000 -#define VR_CFG_BACKOFFRAND 0x08000000 -#define VR_CFG_MAGICKPACKET 0x10000000 -#define VR_CFG_PCIREADLINE 0x20000000 -#define VR_CFG_DIAG 0x40000000 -#define VR_CFG_GPIOEN 0x80000000 - -/* - * Rhine TX/RX list structure. - */ - -struct vr_desc { - u_int32_t vr_status; - u_int32_t vr_ctl; - u_int32_t vr_ptr1; - u_int32_t vr_ptr2; -}; - -#define vr_data vr_ptr1 -#define vr_next vr_ptr2 - - -#define VR_RXSTAT_RXERR 0x00000001 -#define VR_RXSTAT_CRCERR 0x00000002 -#define VR_RXSTAT_FRAMEALIGNERR 0x00000004 -#define VR_RXSTAT_FIFOOFLOW 0x00000008 -#define VR_RXSTAT_GIANT 0x00000010 -#define VR_RXSTAT_RUNT 0x00000020 -#define VR_RXSTAT_BUSERR 0x00000040 -#define VR_RXSTAT_BUFFERR 0x00000080 -#define VR_RXSTAT_LASTFRAG 0x00000100 -#define VR_RXSTAT_FIRSTFRAG 0x00000200 -#define VR_RXSTAT_RLINK 0x00000400 -#define VR_RXSTAT_RX_PHYS 0x00000800 -#define VR_RXSTAT_RX_BROAD 0x00001000 -#define VR_RXSTAT_RX_MULTI 0x00002000 -#define VR_RXSTAT_RX_OK 0x00004000 -#define VR_RXSTAT_RXLEN 0x07FF0000 -#define VR_RXSTAT_RXLEN_EXT 0x78000000 -#define VR_RXSTAT_OWN 0x80000000 - -#define VR_RXBYTES(x) ((x & VR_RXSTAT_RXLEN) >> 16) -#define VR_RXSTAT (VR_RXSTAT_FIRSTFRAG|VR_RXSTAT_LASTFRAG|VR_RXSTAT_OWN) - -#define VR_RXCTL_BUFLEN 0x000007FF -#define VR_RXCTL_BUFLEN_EXT 0x00007800 -#define VR_RXCTL_CHAIN 0x00008000 -#define VR_RXCTL_RX_INTR 0x00800000 - -#define VR_RXCTL (VR_RXCTL_CHAIN|VR_RXCTL_RX_INTR) - -#define VR_TXSTAT_DEFER 0x00000001 -#define VR_TXSTAT_UNDERRUN 0x00000002 -#define VR_TXSTAT_COLLCNT 0x00000078 -#define VR_TXSTAT_SQE 0x00000080 -#define VR_TXSTAT_ABRT 0x00000100 -#define VR_TXSTAT_LATECOLL 0x00000200 -#define VR_TXSTAT_CARRLOST 0x00000400 -#define VR_TXSTAT_BUSERR 0x00002000 -#define VR_TXSTAT_JABTIMEO 0x00004000 -#define VR_TXSTAT_ERRSUM 0x00008000 -#define VR_TXSTAT_OWN 0x80000000 - -#define VR_TXCTL_BUFLEN 0x000007FF -#define VR_TXCTL_BUFLEN_EXT 0x00007800 -#define VR_TXCTL_TLINK 0x00008000 -#define VR_TXCTL_FIRSTFRAG 0x00200000 -#define VR_TXCTL_LASTFRAG 0x00400000 -#define VR_TXCTL_FINT 0x00800000 - - -#define VR_MAXFRAGS 16 -#define VR_RX_LIST_CNT 64 -#define VR_TX_LIST_CNT 64 -#define VR_MIN_FRAMELEN 60 -#define VR_FRAMELEN 1536 -#define VR_RXLEN 1520 - -#define VR_TXOWN(x) x->vr_ptr->vr_status - -struct vr_list_data { - struct vr_desc vr_rx_list[VR_RX_LIST_CNT]; - struct vr_desc vr_tx_list[VR_TX_LIST_CNT]; -}; - -struct vr_chain { - struct vr_desc *vr_ptr; - struct mbuf *vr_mbuf; - struct vr_chain *vr_nextdesc; -}; - -struct vr_chain_onefrag { - struct vr_desc *vr_ptr; - struct mbuf *vr_mbuf; - struct vr_chain_onefrag *vr_nextdesc; -}; - -struct vr_chain_data { - struct vr_chain_onefrag vr_rx_chain[VR_RX_LIST_CNT]; - struct vr_chain vr_tx_chain[VR_TX_LIST_CNT]; - - struct vr_chain_onefrag *vr_rx_head; - - struct vr_chain *vr_tx_head; - struct vr_chain *vr_tx_tail; - struct vr_chain *vr_tx_free; -}; - -struct vr_type { - u_int16_t vr_vid; - u_int16_t vr_did; - char *vr_name; -}; - -struct vr_mii_frame { - u_int8_t mii_stdelim; - u_int8_t mii_opcode; - u_int8_t mii_phyaddr; - u_int8_t mii_regaddr; - u_int8_t mii_turnaround; - u_int16_t mii_data; -}; - -/* - * MII constants - */ -#define VR_MII_STARTDELIM 0x01 -#define VR_MII_READOP 0x02 -#define VR_MII_WRITEOP 0x01 -#define VR_MII_TURNAROUND 0x02 - -#define VR_FLAG_FORCEDELAY 1 -#define VR_FLAG_SCHEDDELAY 2 -#define VR_FLAG_DELAYTIMEO 3 - -struct vr_softc { - struct arpcom arpcom; /* interface info */ - struct ifmedia ifmedia; /* media info */ - bus_space_handle_t vr_bhandle; /* bus space handle */ - bus_space_tag_t vr_btag; /* bus space tag */ - struct vr_type *vr_info; /* Rhine adapter info */ - struct vr_type *vr_pinfo; /* phy info */ - u_int8_t vr_unit; /* interface number */ - u_int8_t vr_type; - u_int8_t vr_phy_addr; /* PHY address */ - u_int8_t vr_tx_pend; /* TX pending */ - u_int8_t vr_want_auto; - u_int8_t vr_autoneg; - caddr_t vr_ldata_ptr; - struct vr_list_data *vr_ldata; - struct vr_chain_data vr_cdata; -}; - -/* - * register space access macros - */ -#define CSR_WRITE_4(sc, reg, val) \ - bus_space_write_4(sc->vr_btag, sc->vr_bhandle, reg, val) -#define CSR_WRITE_2(sc, reg, val) \ - bus_space_write_2(sc->vr_btag, sc->vr_bhandle, reg, val) -#define CSR_WRITE_1(sc, reg, val) \ - bus_space_write_1(sc->vr_btag, sc->vr_bhandle, reg, val) - -#define CSR_READ_4(sc, reg) \ - bus_space_read_4(sc->vr_btag, sc->vr_bhandle, reg) -#define CSR_READ_2(sc, reg) \ - bus_space_read_2(sc->vr_btag, sc->vr_bhandle, reg) -#define CSR_READ_1(sc, reg) \ - bus_space_read_1(sc->vr_btag, sc->vr_bhandle, reg) - -#define VR_TIMEOUT 1000 - -/* - * General constants that are fun to know. - * - * VIA vendor ID - */ -#define VIA_VENDORID 0x1106 - -/* - * VIA Rhine device IDs. - */ -#define VIA_DEVICEID_RHINE 0x3043 -#define VIA_DEVICEID_RHINE_II 0x6100 - - -/* - * Texas Instruments PHY identifiers - */ -#define TI_PHY_VENDORID 0x4000 -#define TI_PHY_10BT 0x501F -#define TI_PHY_100VGPMI 0x502F - -/* - * These ID values are for the NS DP83840A 10/100 PHY - */ -#define NS_PHY_VENDORID 0x2000 -#define NS_PHY_83840A 0x5C0F - -/* - * Level 1 10/100 PHY - */ -#define LEVEL1_PHY_VENDORID 0x7810 -#define LEVEL1_PHY_LXT970 0x000F - -/* - * Intel 82555 10/100 PHY - */ -#define INTEL_PHY_VENDORID 0x0A28 -#define INTEL_PHY_82555 0x015F - -/* - * SEEQ 80220 10/100 PHY - */ -#define SEEQ_PHY_VENDORID 0x0016 -#define SEEQ_PHY_80220 0xF83F - - -/* - * PCI low memory base and low I/O base register, and - * other PCI registers. - */ - -#define VR_PCI_VENDOR_ID 0x00 -#define VR_PCI_DEVICE_ID 0x02 -#define VR_PCI_COMMAND 0x04 -#define VR_PCI_STATUS 0x06 -#define VR_PCI_CLASSCODE 0x09 -#define VR_PCI_LATENCY_TIMER 0x0D -#define VR_PCI_HEADER_TYPE 0x0E -#define VR_PCI_LOIO 0x10 -#define VR_PCI_LOMEM 0x14 -#define VR_PCI_BIOSROM 0x30 -#define VR_PCI_INTLINE 0x3C -#define VR_PCI_INTPIN 0x3D -#define VR_PCI_MINGNT 0x3E -#define VR_PCI_MINLAT 0x0F -#define VR_PCI_RESETOPT 0x48 -#define VR_PCI_EEPROM_DATA 0x4C - -/* power management registers */ -#define VR_PCI_CAPID 0xDC /* 8 bits */ -#define VR_PCI_NEXTPTR 0xDD /* 8 bits */ -#define VR_PCI_PWRMGMTCAP 0xDE /* 16 bits */ -#define VR_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */ - -#define VR_PSTATE_MASK 0x0003 -#define VR_PSTATE_D0 0x0000 -#define VR_PSTATE_D1 0x0002 -#define VR_PSTATE_D2 0x0002 -#define VR_PSTATE_D3 0x0003 -#define VR_PME_EN 0x0010 -#define VR_PME_STATUS 0x8000 - -#define PHY_UNKNOWN 6 - -#define VR_PHYADDR_MIN 0x00 -#define VR_PHYADDR_MAX 0x1F - -#define PHY_BMCR 0x00 -#define PHY_BMSR 0x01 -#define PHY_VENID 0x02 -#define PHY_DEVID 0x03 -#define PHY_ANAR 0x04 -#define PHY_LPAR 0x05 -#define PHY_ANEXP 0x06 - -#define PHY_ANAR_NEXTPAGE 0x8000 -#define PHY_ANAR_RSVD0 0x4000 -#define PHY_ANAR_TLRFLT 0x2000 -#define PHY_ANAR_RSVD1 0x1000 -#define PHY_ANAR_RSVD2 0x0800 -#define PHY_ANAR_RSVD3 0x0400 -#define PHY_ANAR_100BT4 0x0200 -#define PHY_ANAR_100BTXFULL 0x0100 -#define PHY_ANAR_100BTXHALF 0x0080 -#define PHY_ANAR_10BTFULL 0x0040 -#define PHY_ANAR_10BTHALF 0x0020 -#define PHY_ANAR_PROTO4 0x0010 -#define PHY_ANAR_PROTO3 0x0008 -#define PHY_ANAR_PROTO2 0x0004 -#define PHY_ANAR_PROTO1 0x0002 -#define PHY_ANAR_PROTO0 0x0001 - -/* - * These are the register definitions for the PHY (physical layer - * interface chip). - */ -/* - * PHY BMCR Basic Mode Control Register - */ -#define PHY_BMCR_RESET 0x8000 -#define PHY_BMCR_LOOPBK 0x4000 -#define PHY_BMCR_SPEEDSEL 0x2000 -#define PHY_BMCR_AUTONEGENBL 0x1000 -#define PHY_BMCR_RSVD0 0x0800 /* write as zero */ -#define PHY_BMCR_ISOLATE 0x0400 -#define PHY_BMCR_AUTONEGRSTR 0x0200 -#define PHY_BMCR_DUPLEX 0x0100 -#define PHY_BMCR_COLLTEST 0x0080 -#define PHY_BMCR_RSVD1 0x0040 /* write as zero, don't care */ -#define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */ -#define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */ -#define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */ -#define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */ -#define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */ -#define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */ -/* - * RESET: 1 == software reset, 0 == normal operation - * Resets status and control registers to default values. - * Relatches all hardware config values. - * - * LOOPBK: 1 == loopback operation enabled, 0 == normal operation - * - * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s - * Link speed is selected byt his bit or if auto-negotiation if bit - * 12 (AUTONEGENBL) is set (in which case the value of this register - * is ignored). - * - * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled - * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13 - * determine speed and mode. Should be cleared and then set if PHY configured - * for no autoneg on startup. - * - * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation - * - * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation - * - * DUPLEX: 1 == full duplex mode, 0 == half duplex mode - * - * COLLTEST: 1 == collision test enabled, 0 == normal operation - */ - -/* - * PHY, BMSR Basic Mode Status Register - */ -#define PHY_BMSR_100BT4 0x8000 -#define PHY_BMSR_100BTXFULL 0x4000 -#define PHY_BMSR_100BTXHALF 0x2000 -#define PHY_BMSR_10BTFULL 0x1000 -#define PHY_BMSR_10BTHALF 0x0800 -#define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */ -#define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */ -#define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */ -#define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */ -#define PHY_BMSR_MFPRESUP 0x0040 -#define PHY_BMSR_AUTONEGCOMP 0x0020 -#define PHY_BMSR_REMFAULT 0x0010 -#define PHY_BMSR_CANAUTONEG 0x0008 -#define PHY_BMSR_LINKSTAT 0x0004 -#define PHY_BMSR_JABBER 0x0002 -#define PHY_BMSR_EXTENDED 0x0001 diff --git a/sys/pci/if_vx_pci.c b/sys/pci/if_vx_pci.c index ab02693e270d..f4e98ac0a3ff 100644 --- a/sys/pci/if_vx_pci.c +++ b/sys/pci/if_vx_pci.c @@ -47,7 +47,7 @@ #include <dev/vx/if_vxreg.h> static void vx_pci_shutdown(int, void *); -static const char *vx_pci_probe(pcici_t, pcidi_t); +static char *vx_pci_probe(pcici_t, pcidi_t); static void vx_pci_attach(pcici_t, int unit); static void @@ -59,7 +59,7 @@ vx_pci_shutdown( vxfree(sc); } -static const char* +static char* vx_pci_probe( pcici_t config_id, pcidi_t device_id) @@ -96,9 +96,7 @@ vx_pci_attach( return; } - if ((sc = vxalloc(unit)) == NULL) { - return; - } + sc = vxalloc(unit); sc->vx_io_addr = pci_conf_read(config_id, 0x10) & 0xffffffe0; diff --git a/sys/pci/if_wb.c b/sys/pci/if_wb.c deleted file mode 100644 index 01cbc3c72c2d..000000000000 --- a/sys/pci/if_wb.c +++ /dev/null @@ -1,2151 +0,0 @@ -/* - * Copyright (c) 1997, 1998 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_wb.c,v 1.36 1999/01/16 05:28:52 wpaul Exp $ - */ - -/* - * Winbond fast ethernet PCI NIC driver - * - * Supports various cheap network adapters based on the Winbond W89C840F - * fast ethernet controller chip. This includes adapters manufactured by - * Winbond itself and some made by Linksys. - * - * Written by Bill Paul <wpaul@ctr.columbia.edu> - * Electrical Engineering Department - * Columbia University, New York City - */ - -/* - * The Winbond W89C840F chip is a bus master; in some ways it resembles - * a DEC 'tulip' chip, only not as complicated. Unfortunately, it has - * one major difference which is that while the registers do many of - * the same things as a tulip adapter, the offsets are different: where - * tulip registers are typically spaced 8 bytes apart, the Winbond - * registers are spaced 4 bytes apart. The receiver filter is also - * programmed differently. - * - * Like the tulip, the Winbond chip uses small descriptors containing - * a status word, a control word and 32-bit areas that can either be used - * to point to two external data blocks, or to point to a single block - * and another descriptor in a linked list. Descriptors can be grouped - * together in blocks to form fixed length rings or can be chained - * together in linked lists. A single packet may be spread out over - * several descriptors if necessary. - * - * For the receive ring, this driver uses a linked list of descriptors, - * each pointing to a single mbuf cluster buffer, which us large enough - * to hold an entire packet. The link list is looped back to created a - * closed ring. - * - * For transmission, the driver creates a linked list of 'super descriptors' - * which each contain several individual descriptors linked toghether. - * Each 'super descriptor' contains WB_MAXFRAGS descriptors, which we - * abuse as fragment pointers. This allows us to use a buffer managment - * scheme very similar to that used in the ThunderLAN and Etherlink XL - * drivers. - * - * Autonegotiation is performed using the external PHY via the MII bus. - * The sample boards I have all use a Davicom PHY. - * - * Note: the author of the Linux driver for the Winbond chip alludes - * to some sort of flaw in the chip's design that seems to mandate some - * drastic workaround which signigicantly impairs transmit performance. - * I have no idea what he's on about: transmit performance with all - * three of my test boards seems fine. - */ - -#include "bpfilter.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/if_arp.h> -#include <net/ethernet.h> -#include <net/if_dl.h> -#include <net/if_media.h> - -#if NBPFILTER > 0 -#include <net/bpf.h> -#endif - -#include <vm/vm.h> /* for vtophys */ -#include <vm/pmap.h> /* for vtophys */ -#include <machine/clock.h> /* for DELAY */ -#include <machine/bus_memio.h> -#include <machine/bus_pio.h> -#include <machine/bus.h> - -#include <pci/pcireg.h> -#include <pci/pcivar.h> - -#define WB_USEIOSPACE - -/* #define WB_BACKGROUND_AUTONEG */ - -#include <pci/if_wbreg.h> - -#ifndef lint -static const char rcsid[] = - "$Id: if_wb.c,v 1.36 1999/01/16 05:28:52 wpaul Exp $"; -#endif - -/* - * Various supported device vendors/types and their names. - */ -static struct wb_type wb_devs[] = { - { WB_VENDORID, WB_DEVICEID_840F, - "Winbond W89C840F 10/100BaseTX" }, - { CP_VENDORID, CP_DEVICEID_RL100, - "Compex RL100-ATX 10/100baseTX" }, - { 0, 0, NULL } -}; - -/* - * Various supported PHY vendors/types and their names. Note that - * this driver will work with pretty much any MII-compliant PHY, - * so failure to positively identify the chip is not a fatal error. - */ - -static struct wb_type wb_phys[] = { - { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, - { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, - { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, - { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, - { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, - { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, - { 0, 0, "<MII-compliant physical interface>" } -}; - -static unsigned long wb_count = 0; -static const char *wb_probe __P((pcici_t, pcidi_t)); -static void wb_attach __P((pcici_t, int)); - -static int wb_newbuf __P((struct wb_softc *, - struct wb_chain_onefrag *)); -static int wb_encap __P((struct wb_softc *, struct wb_chain *, - struct mbuf *)); - -static void wb_rxeof __P((struct wb_softc *)); -static void wb_rxeoc __P((struct wb_softc *)); -static void wb_txeof __P((struct wb_softc *)); -static void wb_txeoc __P((struct wb_softc *)); -static void wb_intr __P((void *)); -static void wb_start __P((struct ifnet *)); -static int wb_ioctl __P((struct ifnet *, u_long, caddr_t)); -static void wb_init __P((void *)); -static void wb_stop __P((struct wb_softc *)); -static void wb_watchdog __P((struct ifnet *)); -static void wb_shutdown __P((int, void *)); -static int wb_ifmedia_upd __P((struct ifnet *)); -static void wb_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); - -static void wb_eeprom_putbyte __P((struct wb_softc *, int)); -static void wb_eeprom_getword __P((struct wb_softc *, int, u_int16_t *)); -static void wb_read_eeprom __P((struct wb_softc *, caddr_t, int, - int, int)); -static void wb_mii_sync __P((struct wb_softc *)); -static void wb_mii_send __P((struct wb_softc *, u_int32_t, int)); -static int wb_mii_readreg __P((struct wb_softc *, struct wb_mii_frame *)); -static int wb_mii_writereg __P((struct wb_softc *, struct wb_mii_frame *)); -static u_int16_t wb_phy_readreg __P((struct wb_softc *, int)); -static void wb_phy_writereg __P((struct wb_softc *, int, int)); - -static void wb_autoneg_xmit __P((struct wb_softc *)); -static void wb_autoneg_mii __P((struct wb_softc *, int, int)); -static void wb_setmode_mii __P((struct wb_softc *, int)); -static void wb_getmode_mii __P((struct wb_softc *)); -static void wb_setcfg __P((struct wb_softc *, int)); -static u_int8_t wb_calchash __P((caddr_t)); -static void wb_setmulti __P((struct wb_softc *)); -static void wb_reset __P((struct wb_softc *)); -static int wb_list_rx_init __P((struct wb_softc *)); -static int wb_list_tx_init __P((struct wb_softc *)); - -#define WB_SETBIT(sc, reg, x) \ - CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) | x) - -#define WB_CLRBIT(sc, reg, x) \ - CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) & ~x) - -#define SIO_SET(x) \ - CSR_WRITE_4(sc, WB_SIO, \ - CSR_READ_4(sc, WB_SIO) | x) - -#define SIO_CLR(x) \ - CSR_WRITE_4(sc, WB_SIO, \ - CSR_READ_4(sc, WB_SIO) & ~x) - -/* - * Send a read command and address to the EEPROM, check for ACK. - */ -static void wb_eeprom_putbyte(sc, addr) - struct wb_softc *sc; - int addr; -{ - register int d, i; - - d = addr | WB_EECMD_READ; - - /* - * Feed in each bit and stobe the clock. - */ - for (i = 0x400; i; i >>= 1) { - if (d & i) { - SIO_SET(WB_SIO_EE_DATAIN); - } else { - SIO_CLR(WB_SIO_EE_DATAIN); - } - DELAY(100); - SIO_SET(WB_SIO_EE_CLK); - DELAY(150); - SIO_CLR(WB_SIO_EE_CLK); - DELAY(100); - } - - return; -} - -/* - * Read a word of data stored in the EEPROM at address 'addr.' - */ -static void wb_eeprom_getword(sc, addr, dest) - struct wb_softc *sc; - int addr; - u_int16_t *dest; -{ - register int i; - u_int16_t word = 0; - - /* Enter EEPROM access mode. */ - CSR_WRITE_4(sc, WB_SIO, WB_SIO_EESEL|WB_SIO_EE_CS); - - /* - * Send address of word we want to read. - */ - wb_eeprom_putbyte(sc, addr); - - CSR_WRITE_4(sc, WB_SIO, WB_SIO_EESEL|WB_SIO_EE_CS); - - /* - * Start reading bits from EEPROM. - */ - for (i = 0x8000; i; i >>= 1) { - SIO_SET(WB_SIO_EE_CLK); - DELAY(100); - if (CSR_READ_4(sc, WB_SIO) & WB_SIO_EE_DATAOUT) - word |= i; - SIO_CLR(WB_SIO_EE_CLK); - DELAY(100); - } - - /* Turn off EEPROM access mode. */ - CSR_WRITE_4(sc, WB_SIO, 0); - - *dest = word; - - return; -} - -/* - * Read a sequence of words from the EEPROM. - */ -static void wb_read_eeprom(sc, dest, off, cnt, swap) - struct wb_softc *sc; - caddr_t dest; - int off; - int cnt; - int swap; -{ - int i; - u_int16_t word = 0, *ptr; - - for (i = 0; i < cnt; i++) { - wb_eeprom_getword(sc, off + i, &word); - ptr = (u_int16_t *)(dest + (i * 2)); - if (swap) - *ptr = ntohs(word); - else - *ptr = word; - } - - return; -} - -/* - * Sync the PHYs by setting data bit and strobing the clock 32 times. - */ -static void wb_mii_sync(sc) - struct wb_softc *sc; -{ - register int i; - - SIO_SET(WB_SIO_MII_DIR|WB_SIO_MII_DATAIN); - - for (i = 0; i < 32; i++) { - SIO_SET(WB_SIO_MII_CLK); - DELAY(1); - SIO_CLR(WB_SIO_MII_CLK); - DELAY(1); - } - - return; -} - -/* - * Clock a series of bits through the MII. - */ -static void wb_mii_send(sc, bits, cnt) - struct wb_softc *sc; - u_int32_t bits; - int cnt; -{ - int i; - - SIO_CLR(WB_SIO_MII_CLK); - - for (i = (0x1 << (cnt - 1)); i; i >>= 1) { - if (bits & i) { - SIO_SET(WB_SIO_MII_DATAIN); - } else { - SIO_CLR(WB_SIO_MII_DATAIN); - } - DELAY(1); - SIO_CLR(WB_SIO_MII_CLK); - DELAY(1); - SIO_SET(WB_SIO_MII_CLK); - } -} - -/* - * Read an PHY register through the MII. - */ -static int wb_mii_readreg(sc, frame) - struct wb_softc *sc; - struct wb_mii_frame *frame; - -{ - int i, ack, s; - - s = splimp(); - - /* - * Set up frame for RX. - */ - frame->mii_stdelim = WB_MII_STARTDELIM; - frame->mii_opcode = WB_MII_READOP; - frame->mii_turnaround = 0; - frame->mii_data = 0; - - CSR_WRITE_4(sc, WB_SIO, 0); - - /* - * Turn on data xmit. - */ - SIO_SET(WB_SIO_MII_DIR); - - wb_mii_sync(sc); - - /* - * Send command/address info. - */ - wb_mii_send(sc, frame->mii_stdelim, 2); - wb_mii_send(sc, frame->mii_opcode, 2); - wb_mii_send(sc, frame->mii_phyaddr, 5); - wb_mii_send(sc, frame->mii_regaddr, 5); - - /* Idle bit */ - SIO_CLR((WB_SIO_MII_CLK|WB_SIO_MII_DATAIN)); - DELAY(1); - SIO_SET(WB_SIO_MII_CLK); - DELAY(1); - - /* Turn off xmit. */ - SIO_CLR(WB_SIO_MII_DIR); - /* Check for ack */ - SIO_CLR(WB_SIO_MII_CLK); - DELAY(1); - SIO_SET(WB_SIO_MII_CLK); - DELAY(1); - ack = CSR_READ_4(sc, WB_SIO) & WB_SIO_MII_DATAOUT; - SIO_CLR(WB_SIO_MII_CLK); - DELAY(1); - SIO_SET(WB_SIO_MII_CLK); - DELAY(1); - - /* - * Now try reading data bits. If the ack failed, we still - * need to clock through 16 cycles to keep the PHY(s) in sync. - */ - if (ack) { - for(i = 0; i < 16; i++) { - SIO_CLR(WB_SIO_MII_CLK); - DELAY(1); - SIO_SET(WB_SIO_MII_CLK); - DELAY(1); - } - goto fail; - } - - for (i = 0x8000; i; i >>= 1) { - SIO_CLR(WB_SIO_MII_CLK); - DELAY(1); - if (!ack) { - if (CSR_READ_4(sc, WB_SIO) & WB_SIO_MII_DATAOUT) - frame->mii_data |= i; - DELAY(1); - } - SIO_SET(WB_SIO_MII_CLK); - DELAY(1); - } - -fail: - - SIO_CLR(WB_SIO_MII_CLK); - DELAY(1); - SIO_SET(WB_SIO_MII_CLK); - DELAY(1); - - splx(s); - - if (ack) - return(1); - return(0); -} - -/* - * Write to a PHY register through the MII. - */ -static int wb_mii_writereg(sc, frame) - struct wb_softc *sc; - struct wb_mii_frame *frame; - -{ - int s; - - s = splimp(); - /* - * Set up frame for TX. - */ - - frame->mii_stdelim = WB_MII_STARTDELIM; - frame->mii_opcode = WB_MII_WRITEOP; - frame->mii_turnaround = WB_MII_TURNAROUND; - - /* - * Turn on data output. - */ - SIO_SET(WB_SIO_MII_DIR); - - wb_mii_sync(sc); - - wb_mii_send(sc, frame->mii_stdelim, 2); - wb_mii_send(sc, frame->mii_opcode, 2); - wb_mii_send(sc, frame->mii_phyaddr, 5); - wb_mii_send(sc, frame->mii_regaddr, 5); - wb_mii_send(sc, frame->mii_turnaround, 2); - wb_mii_send(sc, frame->mii_data, 16); - - /* Idle bit. */ - SIO_SET(WB_SIO_MII_CLK); - DELAY(1); - SIO_CLR(WB_SIO_MII_CLK); - DELAY(1); - - /* - * Turn off xmit. - */ - SIO_CLR(WB_SIO_MII_DIR); - - splx(s); - - return(0); -} - -static u_int16_t wb_phy_readreg(sc, reg) - struct wb_softc *sc; - int reg; -{ - struct wb_mii_frame frame; - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = sc->wb_phy_addr; - frame.mii_regaddr = reg; - wb_mii_readreg(sc, &frame); - - return(frame.mii_data); -} - -static void wb_phy_writereg(sc, reg, data) - struct wb_softc *sc; - int reg; - int data; -{ - struct wb_mii_frame frame; - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = sc->wb_phy_addr; - frame.mii_regaddr = reg; - frame.mii_data = data; - - wb_mii_writereg(sc, &frame); - - return; -} - -static u_int8_t wb_calchash(addr) - caddr_t addr; -{ - u_int32_t crc, carry; - int i, j; - u_int8_t c; - - /* Compute CRC for the address value. */ - crc = 0xFFFFFFFF; /* initial value */ - - for (i = 0; i < 6; i++) { - c = *(addr + i); - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); - crc <<= 1; - c >>= 1; - if (carry) - crc = (crc ^ 0x04c11db6) | carry; - } - } - - /* - * return the filter bit position - * Note: I arrived at the following nonsense - * through experimentation. It's not the usual way to - * generate the bit position but it's the only thing - * I could come up with that works. - */ - return(~(crc >> 26) & 0x0000003F); -} - -/* - * Program the 64-bit multicast hash filter. - */ -static void wb_setmulti(sc) - struct wb_softc *sc; -{ - struct ifnet *ifp; - int h = 0; - u_int32_t hashes[2] = { 0, 0 }; - struct ifmultiaddr *ifma; - u_int32_t rxfilt; - int mcnt = 0; - - ifp = &sc->arpcom.ac_if; - - rxfilt = CSR_READ_4(sc, WB_NETCFG); - - if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { - rxfilt |= WB_NETCFG_RX_MULTI; - CSR_WRITE_4(sc, WB_NETCFG, rxfilt); - CSR_WRITE_4(sc, WB_MAR0, 0xFFFFFFFF); - CSR_WRITE_4(sc, WB_MAR1, 0xFFFFFFFF); - return; - } - - /* first, zot all the existing hash bits */ - CSR_WRITE_4(sc, WB_MAR0, 0); - CSR_WRITE_4(sc, WB_MAR1, 0); - - /* now program new ones */ - for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; - ifma = ifma->ifma_link.le_next) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = wb_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - mcnt++; - } - - if (mcnt) - rxfilt |= WB_NETCFG_RX_MULTI; - else - rxfilt &= ~WB_NETCFG_RX_MULTI; - - CSR_WRITE_4(sc, WB_MAR0, hashes[0]); - CSR_WRITE_4(sc, WB_MAR1, hashes[1]); - CSR_WRITE_4(sc, WB_NETCFG, rxfilt); - - return; -} - -/* - * Initiate an autonegotiation session. - */ -static void wb_autoneg_xmit(sc) - struct wb_softc *sc; -{ - u_int16_t phy_sts; - - wb_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(wb_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - - phy_sts = wb_phy_readreg(sc, PHY_BMCR); - phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; - wb_phy_writereg(sc, PHY_BMCR, phy_sts); - - return; -} - -/* - * Invoke autonegotiation on a PHY. - */ -static void wb_autoneg_mii(sc, flag, verbose) - struct wb_softc *sc; - int flag; - int verbose; -{ - u_int16_t phy_sts = 0, media, advert, ability; - struct ifnet *ifp; - struct ifmedia *ifm; - - ifm = &sc->ifmedia; - ifp = &sc->arpcom.ac_if; - - ifm->ifm_media = IFM_ETHER | IFM_AUTO; - - /* - * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported' - * bit cleared in the status register, but has the 'autoneg enabled' - * bit set in the control register. This is a contradiction, and - * I'm not sure how to handle it. If you want to force an attempt - * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR - * and see what happens. - */ -#ifndef FORCE_AUTONEG_TFOUR - /* - * First, see if autoneg is supported. If not, there's - * no point in continuing. - */ - phy_sts = wb_phy_readreg(sc, PHY_BMSR); - if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { - if (verbose) - printf("wb%d: autonegotiation not supported\n", - sc->wb_unit); - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - return; - } -#endif - - switch (flag) { - case WB_FLAG_FORCEDELAY: - /* - * XXX Never use this option anywhere but in the probe - * routine: making the kernel stop dead in its tracks - * for three whole seconds after we've gone multi-user - * is really bad manners. - */ - wb_autoneg_xmit(sc); - DELAY(5000000); - break; - case WB_FLAG_SCHEDDELAY: - /* - * Wait for the transmitter to go idle before starting - * an autoneg session, otherwise wb_start() may clobber - * our timeout, and we don't want to allow transmission - * during an autoneg session since that can screw it up. - */ - if (sc->wb_cdata.wb_tx_head != NULL) { - sc->wb_want_auto = 1; - return; - } - wb_autoneg_xmit(sc); - ifp->if_timer = 5; - sc->wb_autoneg = 1; - sc->wb_want_auto = 0; - return; - break; - case WB_FLAG_DELAYTIMEO: - ifp->if_timer = 0; - sc->wb_autoneg = 0; - break; - default: - printf("wb%d: invalid autoneg flag: %d\n", sc->wb_unit, flag); - return; - } - - if (wb_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { - if (verbose) - printf("wb%d: autoneg complete, ", sc->wb_unit); - phy_sts = wb_phy_readreg(sc, PHY_BMSR); - } else { - if (verbose) - printf("wb%d: autoneg not complete, ", sc->wb_unit); - } - - media = wb_phy_readreg(sc, PHY_BMCR); - - /* Link is good. Report modes and set duplex mode. */ - if (wb_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { - if (verbose) - printf("link status good "); - advert = wb_phy_readreg(sc, PHY_ANAR); - ability = wb_phy_readreg(sc, PHY_LPAR); - - if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { - ifm->ifm_media = IFM_ETHER|IFM_100_T4; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(100baseT4)\n"); - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - media |= PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - media |= PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 100Mbps)\n"); - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - media &= ~PHY_BMCR_SPEEDSEL; - media |= PHY_BMCR_DUPLEX; - printf("(full-duplex, 10Mbps)\n"); - } else /* if (advert & PHY_ANAR_10BTHALF && - ability & PHY_ANAR_10BTHALF) */ { - ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - media &= ~PHY_BMCR_SPEEDSEL; - media &= ~PHY_BMCR_DUPLEX; - printf("(half-duplex, 10Mbps)\n"); - } - - media &= ~PHY_BMCR_AUTONEGENBL; - - /* Set ASIC's duplex mode to match the PHY. */ - wb_setcfg(sc, media); - wb_phy_writereg(sc, PHY_BMCR, media); - } else { - if (verbose) - printf("no carrier\n"); - } - - wb_init(sc); - - if (sc->wb_tx_pend) { - sc->wb_autoneg = 0; - sc->wb_tx_pend = 0; - wb_start(ifp); - } - - return; -} - -static void wb_getmode_mii(sc) - struct wb_softc *sc; -{ - u_int16_t bmsr; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - bmsr = wb_phy_readreg(sc, PHY_BMSR); - if (bootverbose) - printf("wb%d: PHY status word: %x\n", sc->wb_unit, bmsr); - - /* fallback */ - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; - - if (bmsr & PHY_BMSR_10BTHALF) { - if (bootverbose) - printf("wb%d: 10Mbps half-duplex mode supported\n", - sc->wb_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); - } - - if (bmsr & PHY_BMSR_10BTFULL) { - if (bootverbose) - printf("wb%d: 10Mbps full-duplex mode supported\n", - sc->wb_unit); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; - } - - if (bmsr & PHY_BMSR_100BTXHALF) { - if (bootverbose) - printf("wb%d: 100Mbps half-duplex mode supported\n", - sc->wb_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; - } - - if (bmsr & PHY_BMSR_100BTXFULL) { - if (bootverbose) - printf("wb%d: 100Mbps full-duplex mode supported\n", - sc->wb_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, - IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; - } - - /* Some also support 100BaseT4. */ - if (bmsr & PHY_BMSR_100BT4) { - if (bootverbose) - printf("wb%d: 100baseT4 mode supported\n", sc->wb_unit); - ifp->if_baudrate = 100000000; - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4; -#ifdef FORCE_AUTONEG_TFOUR - if (bootverbose) - printf("wb%d: forcing on autoneg support for BT4\n", - sc->wb_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; -#endif - } - - if (bmsr & PHY_BMSR_CANAUTONEG) { - if (bootverbose) - printf("wb%d: autoneg supported\n", sc->wb_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); - sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; - } - - return; -} - -/* - * Set speed and duplex mode. - */ -static void wb_setmode_mii(sc, media) - struct wb_softc *sc; - int media; -{ - u_int16_t bmcr; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - /* - * If an autoneg session is in progress, stop it. - */ - if (sc->wb_autoneg) { - printf("wb%d: canceling autoneg session\n", sc->wb_unit); - ifp->if_timer = sc->wb_autoneg = sc->wb_want_auto = 0; - bmcr = wb_phy_readreg(sc, PHY_BMCR); - bmcr &= ~PHY_BMCR_AUTONEGENBL; - wb_phy_writereg(sc, PHY_BMCR, bmcr); - } - - printf("wb%d: selecting MII, ", sc->wb_unit); - - bmcr = wb_phy_readreg(sc, PHY_BMCR); - - bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL| - PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); - - if (IFM_SUBTYPE(media) == IFM_100_T4) { - printf("100Mbps/T4, half-duplex\n"); - bmcr |= PHY_BMCR_SPEEDSEL; - bmcr &= ~PHY_BMCR_DUPLEX; - } - - if (IFM_SUBTYPE(media) == IFM_100_TX) { - printf("100Mbps, "); - bmcr |= PHY_BMCR_SPEEDSEL; - } - - if (IFM_SUBTYPE(media) == IFM_10_T) { - printf("10Mbps, "); - bmcr &= ~PHY_BMCR_SPEEDSEL; - } - - if ((media & IFM_GMASK) == IFM_FDX) { - printf("full duplex\n"); - bmcr |= PHY_BMCR_DUPLEX; - } else { - printf("half duplex\n"); - bmcr &= ~PHY_BMCR_DUPLEX; - } - - wb_setcfg(sc, bmcr); - wb_phy_writereg(sc, PHY_BMCR, bmcr); - - return; -} - -/* - * The Winbond manual states that in order to fiddle with the - * 'full-duplex' and '100Mbps' bits in the netconfig register, we - * first have to put the transmit and/or receive logic in the idle state. - */ -static void wb_setcfg(sc, bmcr) - struct wb_softc *sc; - int bmcr; -{ - int i, restart = 0; - - if (CSR_READ_4(sc, WB_NETCFG) & (WB_NETCFG_TX_ON|WB_NETCFG_RX_ON)) { - restart = 1; - WB_CLRBIT(sc, WB_NETCFG, (WB_NETCFG_TX_ON|WB_NETCFG_RX_ON)); - - for (i = 0; i < WB_TIMEOUT; i++) { - DELAY(10); - if ((CSR_READ_4(sc, WB_ISR) & WB_ISR_TX_IDLE) && - (CSR_READ_4(sc, WB_ISR) & WB_ISR_RX_IDLE)) - break; - } - - if (i == WB_TIMEOUT) - printf("wb%d: failed to force tx and " - "rx to idle state\n", sc->wb_unit); - } - - if (bmcr & PHY_BMCR_SPEEDSEL) - WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_100MBPS); - else - WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_100MBPS); - - if (bmcr & PHY_BMCR_DUPLEX) - WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_FULLDUPLEX); - else - WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_FULLDUPLEX); - - if (restart) - WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON|WB_NETCFG_RX_ON); - - return; -} - -static void wb_reset(sc) - struct wb_softc *sc; -{ - register int i; - - WB_SETBIT(sc, WB_BUSCTL, WB_BUSCTL_RESET); - - for (i = 0; i < WB_TIMEOUT; i++) { - DELAY(10); - if (!(CSR_READ_4(sc, WB_BUSCTL) & WB_BUSCTL_RESET)) - break; - } - if (i == WB_TIMEOUT) - printf("wb%d: reset never completed!\n", sc->wb_unit); - - /* Wait a little while for the chip to get its brains in order. */ - DELAY(1000); - - /* Reset the damn PHY too. */ - if (sc->wb_pinfo != NULL) - wb_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - - return; -} - -/* - * Probe for a Winbond chip. Check the PCI vendor and device - * IDs against our list and return a device name if we find a match. - */ -static const char * -wb_probe(config_id, device_id) - pcici_t config_id; - pcidi_t device_id; -{ - struct wb_type *t; - - t = wb_devs; - - while(t->wb_name != NULL) { - if ((device_id & 0xFFFF) == t->wb_vid && - ((device_id >> 16) & 0xFFFF) == t->wb_did) { - return(t->wb_name); - } - t++; - } - - return(NULL); -} - -/* - * Attach the interface. Allocate softc structures, do ifmedia - * setup and ethernet/BPF attach. - */ -static void -wb_attach(config_id, unit) - pcici_t config_id; - int unit; -{ - int s, i; -#ifndef WB_USEIOSPACE - vm_offset_t pbase, vbase; -#endif - u_char eaddr[ETHER_ADDR_LEN]; - u_int32_t command; - struct wb_softc *sc; - struct ifnet *ifp; - int media = IFM_ETHER|IFM_100_TX|IFM_FDX; - unsigned int round; - caddr_t roundptr; - struct wb_type *p; - u_int16_t phy_vid, phy_did, phy_sts; - - s = splimp(); - - sc = malloc(sizeof(struct wb_softc), M_DEVBUF, M_NOWAIT); - if (sc == NULL) { - printf("wb%d: no memory for softc struct!\n", unit); - return; - } - bzero(sc, sizeof(struct wb_softc)); - - /* - * Handle power management nonsense. - */ - - command = pci_conf_read(config_id, WB_PCI_CAPID) & 0x000000FF; - if (command == 0x01) { - - command = pci_conf_read(config_id, WB_PCI_PWRMGMTCTRL); - if (command & WB_PSTATE_MASK) { - u_int32_t iobase, membase, irq; - - /* Save important PCI config data. */ - iobase = pci_conf_read(config_id, WB_PCI_LOIO); - membase = pci_conf_read(config_id, WB_PCI_LOMEM); - irq = pci_conf_read(config_id, WB_PCI_INTLINE); - - /* Reset the power state. */ - printf("wb%d: chip is in D%d power mode " - "-- setting to D0\n", unit, command & WB_PSTATE_MASK); - command &= 0xFFFFFFFC; - pci_conf_write(config_id, WB_PCI_PWRMGMTCTRL, command); - - /* Restore PCI config data. */ - pci_conf_write(config_id, WB_PCI_LOIO, iobase); - pci_conf_write(config_id, WB_PCI_LOMEM, membase); - pci_conf_write(config_id, WB_PCI_INTLINE, irq); - } - } - - /* - * Map control/status registers. - */ - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); - pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); - command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); - -#ifdef WB_USEIOSPACE - if (!(command & PCIM_CMD_PORTEN)) { - printf("wb%d: failed to enable I/O ports!\n", unit); - free(sc, M_DEVBUF); - goto fail; - } - - if (!pci_map_port(config_id, WB_PCI_LOIO, - (u_int16_t *)&(sc->wb_bhandle))) { - printf ("wb%d: couldn't map ports\n", unit); - goto fail; - } - sc->wb_btag = I386_BUS_SPACE_IO; -#else - if (!(command & PCIM_CMD_MEMEN)) { - printf("wb%d: failed to enable memory mapping!\n", unit); - goto fail; - } - - if (!pci_map_mem(config_id, WB_PCI_LOMEM, &vbase, &pbase)) { - printf ("wb%d: couldn't map memory\n", unit); - goto fail; - } - sc->csr = (volatile caddr_t)vbase; - sc->wb_btag = I386_BUS_SPACE_MEM; - sc->wb_bhandle = vbase; -#endif - - /* Allocate interrupt */ - if (!pci_map_int(config_id, wb_intr, sc, &net_imask)) { - printf("wb%d: couldn't map interrupt\n", unit); - goto fail; - } - - /* Reset the adapter. */ - wb_reset(sc); - - /* - * Get station address from the EEPROM. - */ - wb_read_eeprom(sc, (caddr_t)&eaddr, 0, 3, 0); - - /* - * A Winbond chip was detected. Inform the world. - */ - printf("wb%d: Ethernet address: %6D\n", unit, eaddr, ":"); - - sc->wb_unit = unit; - bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); - - sc->wb_ldata_ptr = malloc(sizeof(struct wb_list_data) + 8, - M_DEVBUF, M_NOWAIT); - if (sc->wb_ldata_ptr == NULL) { - free(sc, M_DEVBUF); - printf("wb%d: no memory for list buffers!\n", unit); - return; - } - - sc->wb_ldata = (struct wb_list_data *)sc->wb_ldata_ptr; - round = (unsigned int)sc->wb_ldata_ptr & 0xF; - roundptr = sc->wb_ldata_ptr; - for (i = 0; i < 8; i++) { - if (round % 8) { - round++; - roundptr++; - } else - break; - } - sc->wb_ldata = (struct wb_list_data *)roundptr; - bzero(sc->wb_ldata, sizeof(struct wb_list_data)); - - ifp = &sc->arpcom.ac_if; - ifp->if_softc = sc; - ifp->if_unit = unit; - ifp->if_name = "wb"; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = wb_ioctl; - ifp->if_output = ether_output; - ifp->if_start = wb_start; - ifp->if_watchdog = wb_watchdog; - ifp->if_init = wb_init; - ifp->if_baudrate = 10000000; - - if (bootverbose) - printf("wb%d: probing for a PHY\n", sc->wb_unit); - for (i = WB_PHYADDR_MIN; i < WB_PHYADDR_MAX + 1; i++) { - if (bootverbose) - printf("wb%d: checking address: %d\n", - sc->wb_unit, i); - sc->wb_phy_addr = i; - wb_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(wb_phy_readreg(sc, PHY_BMCR) - & PHY_BMCR_RESET); - if ((phy_sts = wb_phy_readreg(sc, PHY_BMSR))) - break; - } - if (phy_sts) { - phy_vid = wb_phy_readreg(sc, PHY_VENID); - phy_did = wb_phy_readreg(sc, PHY_DEVID); - if (bootverbose) - printf("wb%d: found PHY at address %d, ", - sc->wb_unit, sc->wb_phy_addr); - if (bootverbose) - printf("vendor id: %x device id: %x\n", - phy_vid, phy_did); - p = wb_phys; - while(p->wb_vid) { - if (phy_vid == p->wb_vid && - (phy_did | 0x000F) == p->wb_did) { - sc->wb_pinfo = p; - break; - } - p++; - } - if (sc->wb_pinfo == NULL) - sc->wb_pinfo = &wb_phys[PHY_UNKNOWN]; - if (bootverbose) - printf("wb%d: PHY type: %s\n", - sc->wb_unit, sc->wb_pinfo->wb_name); - } else { - printf("wb%d: MII without any phy!\n", sc->wb_unit); - goto fail; - } - - /* - * Do ifmedia setup. - */ - ifmedia_init(&sc->ifmedia, 0, wb_ifmedia_upd, wb_ifmedia_sts); - - wb_getmode_mii(sc); - wb_autoneg_mii(sc, WB_FLAG_FORCEDELAY, 1); - media = sc->ifmedia.ifm_media; - wb_stop(sc); - - ifmedia_set(&sc->ifmedia, media); - - /* - * Call MI attach routines. - */ - if_attach(ifp); - ether_ifattach(ifp); - -#if NBPFILTER > 0 - bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif - at_shutdown(wb_shutdown, sc, SHUTDOWN_POST_SYNC); - -fail: - splx(s); - return; -} - -/* - * Initialize the transmit descriptors. - */ -static int wb_list_tx_init(sc) - struct wb_softc *sc; -{ - struct wb_chain_data *cd; - struct wb_list_data *ld; - int i; - - cd = &sc->wb_cdata; - ld = sc->wb_ldata; - - for (i = 0; i < WB_TX_LIST_CNT; i++) { - cd->wb_tx_chain[i].wb_ptr = &ld->wb_tx_list[i]; - if (i == (WB_TX_LIST_CNT - 1)) { - cd->wb_tx_chain[i].wb_nextdesc = - &cd->wb_tx_chain[0]; - } else { - cd->wb_tx_chain[i].wb_nextdesc = - &cd->wb_tx_chain[i + 1]; - } - } - - cd->wb_tx_free = &cd->wb_tx_chain[0]; - cd->wb_tx_tail = cd->wb_tx_head = NULL; - - return(0); -} - - -/* - * Initialize the RX descriptors and allocate mbufs for them. Note that - * we arrange the descriptors in a closed ring, so that the last descriptor - * points back to the first. - */ -static int wb_list_rx_init(sc) - struct wb_softc *sc; -{ - struct wb_chain_data *cd; - struct wb_list_data *ld; - int i; - - cd = &sc->wb_cdata; - ld = sc->wb_ldata; - - for (i = 0; i < WB_RX_LIST_CNT; i++) { - cd->wb_rx_chain[i].wb_ptr = - (struct wb_desc *)&ld->wb_rx_list[i]; - if (wb_newbuf(sc, &cd->wb_rx_chain[i]) == ENOBUFS) - return(ENOBUFS); - if (i == (WB_RX_LIST_CNT - 1)) { - cd->wb_rx_chain[i].wb_nextdesc = &cd->wb_rx_chain[0]; - ld->wb_rx_list[i].wb_next = - vtophys(&ld->wb_rx_list[0]); - } else { - cd->wb_rx_chain[i].wb_nextdesc = - &cd->wb_rx_chain[i + 1]; - ld->wb_rx_list[i].wb_next = - vtophys(&ld->wb_rx_list[i + 1]); - } - } - - cd->wb_rx_head = &cd->wb_rx_chain[0]; - - return(0); -} - -/* - * Initialize an RX descriptor and attach an MBUF cluster. - */ -static int wb_newbuf(sc, c) - struct wb_softc *sc; - struct wb_chain_onefrag *c; -{ - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("wb%d: no memory for rx list -- packet dropped!\n", - sc->wb_unit); - return(ENOBUFS); - } - - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - printf("wb%d: no memory for rx list -- packet dropped!\n", - sc->wb_unit); - m_freem(m_new); - return(ENOBUFS); - } - - c->wb_mbuf = m_new; - c->wb_ptr->wb_data = vtophys(mtod(m_new, caddr_t)); - c->wb_ptr->wb_ctl = WB_RXCTL_RLINK | (MCLBYTES - 1); - c->wb_ptr->wb_status = WB_RXSTAT; - - return(0); -} - -/* - * A frame has been uploaded: pass the resulting mbuf chain up to - * the higher level protocols. - */ -static void wb_rxeof(sc) - struct wb_softc *sc; -{ - struct ether_header *eh; - struct mbuf *m; - struct ifnet *ifp; - struct wb_chain_onefrag *cur_rx; - int total_len = 0; - u_int32_t rxstat; - - ifp = &sc->arpcom.ac_if; - - while(!((rxstat = sc->wb_cdata.wb_rx_head->wb_ptr->wb_status) & - WB_RXSTAT_OWN)) { - cur_rx = sc->wb_cdata.wb_rx_head; - sc->wb_cdata.wb_rx_head = cur_rx->wb_nextdesc; - - if ((rxstat & WB_RXSTAT_MIIERR) - || WB_RXBYTES(cur_rx->wb_ptr->wb_status) == 0) { - ifp->if_ierrors++; - wb_reset(sc); - printf("wb%x: receiver babbling: possible chip " - "bug, forcing reset\n", sc->wb_unit); - ifp->if_flags |= IFF_OACTIVE; - ifp->if_timer = 2; - return; - } - - if (rxstat & WB_RXSTAT_RXERR) { - ifp->if_ierrors++; - cur_rx->wb_ptr->wb_ctl = - WB_RXCTL_RLINK | (MCLBYTES - 1); - cur_rx->wb_ptr->wb_status = WB_RXSTAT; - continue; - } - - /* No errors; receive the packet. */ - total_len = WB_RXBYTES(cur_rx->wb_ptr->wb_status); - - /* - * XXX The Winbond chip includes the CRC with every - * received frame, and there's no way to turn this - * behavior off (at least, I can't find anything in - * the manual that explains how to do it) so we have - * to trim off the CRC manually. - */ - total_len -= ETHER_CRC_LEN; - - if (total_len < MINCLSIZE) { - m = m_devget(mtod(cur_rx->wb_mbuf, char *), - total_len, 0, ifp, NULL); - cur_rx->wb_ptr->wb_ctl = - WB_RXCTL_RLINK | (MCLBYTES - 1); - cur_rx->wb_ptr->wb_status = WB_RXSTAT; - if (m == NULL) { - ifp->if_ierrors++; - continue; - } - } else { - m = cur_rx->wb_mbuf; - /* - * Try to conjure up a new mbuf cluster. If that - * fails, it means we have an out of memory condition and - * should leave the buffer in place and continue. This will - * result in a lost packet, but there's little else we - * can do in this situation. - */ - if (wb_newbuf(sc, cur_rx) == ENOBUFS) { - ifp->if_ierrors++; - cur_rx->wb_ptr->wb_ctl = - WB_RXCTL_RLINK | (MCLBYTES - 1); - cur_rx->wb_ptr->wb_status = WB_RXSTAT; - continue; - } - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = m->m_len = total_len; - } - - ifp->if_ipackets++; - eh = mtod(m, struct ether_header *); - -#if NBPFILTER > 0 - /* - * Handle BPF listeners. Let the BPF user see the packet, but - * don't pass it up to the ether_input() layer unless it's - * a broadcast packet, multicast packet, matches our ethernet - * address or the interface is in promiscuous mode. - */ - if (ifp->if_bpf) { - bpf_mtap(ifp, m); - if (ifp->if_flags & IFF_PROMISC && - (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, - ETHER_ADDR_LEN) && - (eh->ether_dhost[0] & 1) == 0)) { - m_freem(m); - continue; - } - } -#endif - /* Remove header from mbuf and pass it on. */ - m_adj(m, sizeof(struct ether_header)); - ether_input(ifp, eh, m); - } - - return; -} - -void wb_rxeoc(sc) - struct wb_softc *sc; -{ - wb_rxeof(sc); - - WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_RX_ON); - CSR_WRITE_4(sc, WB_RXADDR, vtophys(&sc->wb_ldata->wb_rx_list[0])); - WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_RX_ON); - if (CSR_READ_4(sc, WB_ISR) & WB_RXSTATE_SUSPEND) - CSR_WRITE_4(sc, WB_RXSTART, 0xFFFFFFFF); - - return; -} - -/* - * A frame was downloaded to the chip. It's safe for us to clean up - * the list buffers. - */ -static void wb_txeof(sc) - struct wb_softc *sc; -{ - struct wb_chain *cur_tx; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - /* Clear the timeout timer. */ - ifp->if_timer = 0; - - if (sc->wb_cdata.wb_tx_head == NULL) - return; - - /* - * Go through our tx list and free mbufs for those - * frames that have been transmitted. - */ - while(sc->wb_cdata.wb_tx_head->wb_mbuf != NULL) { - u_int32_t txstat; - - cur_tx = sc->wb_cdata.wb_tx_head; - txstat = WB_TXSTATUS(cur_tx); - - if ((txstat & WB_TXSTAT_OWN) || txstat == WB_UNSENT) - break; - - if (txstat & WB_TXSTAT_TXERR) { - ifp->if_oerrors++; - if (txstat & WB_TXSTAT_ABORT) - ifp->if_collisions++; - if (txstat & WB_TXSTAT_LATECOLL) - ifp->if_collisions++; - } - - ifp->if_collisions += (txstat & WB_TXSTAT_COLLCNT) >> 3; - - ifp->if_opackets++; - m_freem(cur_tx->wb_mbuf); - cur_tx->wb_mbuf = NULL; - - if (sc->wb_cdata.wb_tx_head == sc->wb_cdata.wb_tx_tail) { - sc->wb_cdata.wb_tx_head = NULL; - sc->wb_cdata.wb_tx_tail = NULL; - break; - } - - sc->wb_cdata.wb_tx_head = cur_tx->wb_nextdesc; - } - - return; -} - -/* - * TX 'end of channel' interrupt handler. - */ -static void wb_txeoc(sc) - struct wb_softc *sc; -{ - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - ifp->if_timer = 0; - - if (sc->wb_cdata.wb_tx_head == NULL) { - ifp->if_flags &= ~IFF_OACTIVE; - sc->wb_cdata.wb_tx_tail = NULL; - if (sc->wb_want_auto) - wb_autoneg_mii(sc, WB_FLAG_SCHEDDELAY, 1); - } else { - if (WB_TXOWN(sc->wb_cdata.wb_tx_head) == WB_UNSENT) { - WB_TXOWN(sc->wb_cdata.wb_tx_head) = WB_TXSTAT_OWN; - ifp->if_timer = 5; - CSR_WRITE_4(sc, WB_TXSTART, 0xFFFFFFFF); - } - } - - return; -} - -static void wb_intr(arg) - void *arg; -{ - struct wb_softc *sc; - struct ifnet *ifp; - u_int32_t status; - - sc = arg; - ifp = &sc->arpcom.ac_if; - - if (!(ifp->if_flags & IFF_UP)) - return; - - /* Disable interrupts. */ - CSR_WRITE_4(sc, WB_IMR, 0x00000000); - - for (;;) { - - status = CSR_READ_4(sc, WB_ISR); - if (status) - CSR_WRITE_4(sc, WB_ISR, status); - - if ((status & WB_INTRS) == 0) - break; - - if (status & WB_ISR_RX_OK) - wb_rxeof(sc); - - if (status & WB_ISR_RX_IDLE) - wb_rxeoc(sc); - - if ((status & WB_ISR_RX_NOBUF) || (status & WB_ISR_RX_ERR)) { - ifp->if_ierrors++; -#ifdef foo - wb_stop(sc); - wb_reset(sc); - wb_init(sc); -#endif - } - - if (status & WB_ISR_TX_OK) - wb_txeof(sc); - - if (status & WB_ISR_TX_NOBUF) - wb_txeoc(sc); - - if (status & WB_ISR_TX_IDLE) { - wb_txeof(sc); - if (sc->wb_cdata.wb_tx_head != NULL) { - WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON); - CSR_WRITE_4(sc, WB_TXSTART, 0xFFFFFFFF); - } - } - - if (status & WB_ISR_TX_UNDERRUN) { - ifp->if_oerrors++; - wb_txeof(sc); - WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON); - /* Jack up TX threshold */ - sc->wb_txthresh += WB_TXTHRESH_CHUNK; - WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_TX_THRESH); - WB_SETBIT(sc, WB_NETCFG, WB_TXTHRESH(sc->wb_txthresh)); - WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON); - } - - if (status & WB_ISR_BUS_ERR) { - wb_reset(sc); - wb_init(sc); - } - - } - - /* Re-enable interrupts. */ - CSR_WRITE_4(sc, WB_IMR, WB_INTRS); - - if (ifp->if_snd.ifq_head != NULL) { - wb_start(ifp); - } - - return; -} - -/* - * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data - * pointers to the fragment pointers. - */ -static int wb_encap(sc, c, m_head) - struct wb_softc *sc; - struct wb_chain *c; - struct mbuf *m_head; -{ - int frag = 0; - struct wb_desc *f = NULL; - int total_len; - struct mbuf *m; - - /* - * Start packing the mbufs in this chain into - * the fragment pointers. Stop when we run out - * of fragments or hit the end of the mbuf chain. - */ - m = m_head; - total_len = 0; - - for (m = m_head, frag = 0; m != NULL; m = m->m_next) { - if (m->m_len != 0) { - if (frag == WB_MAXFRAGS) - break; - total_len += m->m_len; - f = &c->wb_ptr->wb_frag[frag]; - f->wb_ctl = WB_TXCTL_TLINK | m->m_len; - if (frag == 0) { - f->wb_ctl |= WB_TXCTL_FIRSTFRAG; - f->wb_status = 0; - } else - f->wb_status = WB_TXSTAT_OWN; - f->wb_next = vtophys(&c->wb_ptr->wb_frag[frag + 1]); - f->wb_data = vtophys(mtod(m, vm_offset_t)); - frag++; - } - } - - /* - * Handle special case: we used up all 16 fragments, - * but we have more mbufs left in the chain. Copy the - * data into an mbuf cluster. Note that we don't - * bother clearing the values in the other fragment - * pointers/counters; it wouldn't gain us anything, - * and would waste cycles. - */ - if (m != NULL) { - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - printf("wb%d: no memory for tx list", sc->wb_unit); - return(1); - } - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - printf("wb%d: no memory for tx list", - sc->wb_unit); - return(1); - } - } - m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; - m_freem(m_head); - m_head = m_new; - f = &c->wb_ptr->wb_frag[0]; - f->wb_status = 0; - f->wb_data = vtophys(mtod(m_new, caddr_t)); - f->wb_ctl = total_len = m_new->m_len; - f->wb_ctl |= WB_TXCTL_TLINK|WB_TXCTL_FIRSTFRAG; - frag = 1; - } - - if (total_len < WB_MIN_FRAMELEN) { - f = &c->wb_ptr->wb_frag[frag]; - f->wb_ctl = WB_MIN_FRAMELEN - total_len; - f->wb_data = vtophys(&sc->wb_cdata.wb_pad); - f->wb_ctl |= WB_TXCTL_TLINK; - f->wb_status = WB_TXSTAT_OWN; - frag++; - } - - c->wb_mbuf = m_head; - c->wb_lastdesc = frag - 1; - WB_TXCTL(c) |= WB_TXCTL_LASTFRAG; - WB_TXNEXT(c) = vtophys(&c->wb_nextdesc->wb_ptr->wb_frag[0]); - - return(0); -} - -/* - * Main transmit routine. To avoid having to do mbuf copies, we put pointers - * to the mbuf data regions directly in the transmit lists. We also save a - * copy of the pointers since the transmit list fragment pointers are - * physical addresses. - */ - -static void wb_start(ifp) - struct ifnet *ifp; -{ - struct wb_softc *sc; - struct mbuf *m_head = NULL; - struct wb_chain *cur_tx = NULL, *start_tx; - - sc = ifp->if_softc; - - if (sc->wb_autoneg) { - sc->wb_tx_pend = 1; - return; - } - - /* - * Check for an available queue slot. If there are none, - * punt. - */ - if (sc->wb_cdata.wb_tx_free->wb_mbuf != NULL) { - ifp->if_flags |= IFF_OACTIVE; - return; - } - - start_tx = sc->wb_cdata.wb_tx_free; - - while(sc->wb_cdata.wb_tx_free->wb_mbuf == NULL) { - IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) - break; - - /* Pick a descriptor off the free list. */ - cur_tx = sc->wb_cdata.wb_tx_free; - sc->wb_cdata.wb_tx_free = cur_tx->wb_nextdesc; - - /* Pack the data into the descriptor. */ - wb_encap(sc, cur_tx, m_head); - - if (cur_tx != start_tx) - WB_TXOWN(cur_tx) = WB_TXSTAT_OWN; - -#if NBPFILTER > 0 - /* - * If there's a BPF listener, bounce a copy of this frame - * to him. - */ - if (ifp->if_bpf) - bpf_mtap(ifp, cur_tx->wb_mbuf); -#endif - } - - /* - * If there are no packets queued, bail. - */ - if (cur_tx == NULL) - return; - - /* - * Place the request for the upload interrupt - * in the last descriptor in the chain. This way, if - * we're chaining several packets at once, we'll only - * get an interupt once for the whole chain rather than - * once for each packet. - */ - WB_TXCTL(cur_tx) |= WB_TXCTL_FINT; - cur_tx->wb_ptr->wb_frag[0].wb_ctl |= WB_TXCTL_FINT; - sc->wb_cdata.wb_tx_tail = cur_tx; - - if (sc->wb_cdata.wb_tx_head == NULL) { - sc->wb_cdata.wb_tx_head = start_tx; - WB_TXOWN(start_tx) = WB_TXSTAT_OWN; - CSR_WRITE_4(sc, WB_TXSTART, 0xFFFFFFFF); - } else { - /* - * We need to distinguish between the case where - * the own bit is clear because the chip cleared it - * and where the own bit is clear because we haven't - * set it yet. The magic value WB_UNSET is just some - * ramdomly chosen number which doesn't have the own - * bit set. When we actually transmit the frame, the - * status word will have _only_ the own bit set, so - * the txeoc handler will be able to tell if it needs - * to initiate another transmission to flush out pending - * frames. - */ - WB_TXOWN(start_tx) = WB_UNSENT; - } - - /* - * Set a timeout in case the chip goes out to lunch. - */ - ifp->if_timer = 5; - - return; -} - -static void wb_init(xsc) - void *xsc; -{ - struct wb_softc *sc = xsc; - struct ifnet *ifp = &sc->arpcom.ac_if; - int s, i; - u_int16_t phy_bmcr = 0; - - if (sc->wb_autoneg) - return; - - s = splimp(); - - if (sc->wb_pinfo != NULL) - phy_bmcr = wb_phy_readreg(sc, PHY_BMCR); - - /* - * Cancel pending I/O and free all RX/TX buffers. - */ - wb_stop(sc); - wb_reset(sc); - - sc->wb_txthresh = WB_TXTHRESH_INIT; - - /* - * Set cache alignment and burst length. - */ - CSR_WRITE_4(sc, WB_BUSCTL, WB_BUSCTL_CONFIG); - WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_TX_THRESH); - WB_SETBIT(sc, WB_NETCFG, WB_TXTHRESH(sc->wb_txthresh)); - - /* This doesn't tend to work too well at 100Mbps. */ - WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_TX_EARLY_ON); - - wb_setcfg(sc, phy_bmcr); - - /* Init our MAC address */ - for (i = 0; i < ETHER_ADDR_LEN; i++) { - CSR_WRITE_1(sc, WB_NODE0 + i, sc->arpcom.ac_enaddr[i]); - } - - /* Init circular RX list. */ - if (wb_list_rx_init(sc) == ENOBUFS) { - printf("wb%d: initialization failed: no " - "memory for rx buffers\n", sc->wb_unit); - wb_stop(sc); - (void)splx(s); - return; - } - - /* Init TX descriptors. */ - wb_list_tx_init(sc); - - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) { - WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_RX_ALLPHYS); - } else { - WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_RX_ALLPHYS); - } - - /* - * Set capture broadcast bit to capture broadcast frames. - */ - if (ifp->if_flags & IFF_BROADCAST) { - WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_RX_BROAD); - } else { - WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_RX_BROAD); - } - - /* - * Program the multicast filter, if necessary. - */ - wb_setmulti(sc); - - /* - * Load the address of the RX list. - */ - WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_RX_ON); - CSR_WRITE_4(sc, WB_RXADDR, vtophys(&sc->wb_ldata->wb_rx_list[0])); - - /* - * Enable interrupts. - */ - CSR_WRITE_4(sc, WB_IMR, WB_INTRS); - CSR_WRITE_4(sc, WB_ISR, 0xFFFFFFFF); - - /* Enable receiver and transmitter. */ - WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_RX_ON); - CSR_WRITE_4(sc, WB_RXSTART, 0xFFFFFFFF); - - WB_CLRBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON); - CSR_WRITE_4(sc, WB_TXADDR, vtophys(&sc->wb_ldata->wb_tx_list[0])); - WB_SETBIT(sc, WB_NETCFG, WB_NETCFG_TX_ON); - - /* Restore state of BMCR */ - if (sc->wb_pinfo != NULL) - wb_phy_writereg(sc, PHY_BMCR, phy_bmcr); - - ifp->if_flags |= IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - - (void)splx(s); - - return; -} - -/* - * Set media options. - */ -static int wb_ifmedia_upd(ifp) - struct ifnet *ifp; -{ - struct wb_softc *sc; - struct ifmedia *ifm; - - sc = ifp->if_softc; - ifm = &sc->ifmedia; - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return(EINVAL); - - if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) - wb_autoneg_mii(sc, WB_FLAG_SCHEDDELAY, 1); - else - wb_setmode_mii(sc, ifm->ifm_media); - - return(0); -} - -/* - * Report current media status. - */ -static void wb_ifmedia_sts(ifp, ifmr) - struct ifnet *ifp; - struct ifmediareq *ifmr; -{ - struct wb_softc *sc; - u_int16_t advert = 0, ability = 0; - - sc = ifp->if_softc; - - ifmr->ifm_active = IFM_ETHER; - - if (!(wb_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { - if (wb_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) - ifmr->ifm_active = IFM_ETHER|IFM_100_TX; - else - ifmr->ifm_active = IFM_ETHER|IFM_10_T; - if (wb_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) - ifmr->ifm_active |= IFM_FDX; - else - ifmr->ifm_active |= IFM_HDX; - return; - } - - ability = wb_phy_readreg(sc, PHY_LPAR); - advert = wb_phy_readreg(sc, PHY_ANAR); - if (advert & PHY_ANAR_100BT4 && - ability & PHY_ANAR_100BT4) { - ifmr->ifm_active = IFM_ETHER|IFM_100_T4; - } else if (advert & PHY_ANAR_100BTXFULL && - ability & PHY_ANAR_100BTXFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX; - } else if (advert & PHY_ANAR_100BTXHALF && - ability & PHY_ANAR_100BTXHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX; - } else if (advert & PHY_ANAR_10BTFULL && - ability & PHY_ANAR_10BTFULL) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX; - } else if (advert & PHY_ANAR_10BTHALF && - ability & PHY_ANAR_10BTHALF) { - ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX; - } - - return; -} - -static int wb_ioctl(ifp, command, data) - struct ifnet *ifp; - u_long command; - caddr_t data; -{ - struct wb_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; - int s, error = 0; - - s = splimp(); - - switch(command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; - case SIOCSIFFLAGS: - if (ifp->if_flags & IFF_UP) { - wb_init(sc); - } else { - if (ifp->if_flags & IFF_RUNNING) - wb_stop(sc); - } - error = 0; - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - wb_setmulti(sc); - error = 0; - break; - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); - break; - default: - error = EINVAL; - break; - } - - (void)splx(s); - - return(error); -} - -static void wb_watchdog(ifp) - struct ifnet *ifp; -{ - struct wb_softc *sc; - - sc = ifp->if_softc; - - if (sc->wb_autoneg) { - wb_autoneg_mii(sc, WB_FLAG_DELAYTIMEO, 1); - return; - } - - ifp->if_oerrors++; - printf("wb%d: watchdog timeout\n", sc->wb_unit); - - if (!(wb_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) - printf("wb%d: no carrier - transceiver cable problem?\n", - sc->wb_unit); - - wb_stop(sc); - wb_reset(sc); - wb_init(sc); - - if (ifp->if_snd.ifq_head != NULL) - wb_start(ifp); - - return; -} - -/* - * Stop the adapter and free any mbufs allocated to the - * RX and TX lists. - */ -static void wb_stop(sc) - struct wb_softc *sc; -{ - register int i; - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - ifp->if_timer = 0; - - WB_CLRBIT(sc, WB_NETCFG, (WB_NETCFG_RX_ON|WB_NETCFG_TX_ON)); - CSR_WRITE_4(sc, WB_IMR, 0x00000000); - CSR_WRITE_4(sc, WB_TXADDR, 0x00000000); - CSR_WRITE_4(sc, WB_RXADDR, 0x00000000); - - /* - * Free data in the RX lists. - */ - for (i = 0; i < WB_RX_LIST_CNT; i++) { - if (sc->wb_cdata.wb_rx_chain[i].wb_mbuf != NULL) { - m_freem(sc->wb_cdata.wb_rx_chain[i].wb_mbuf); - sc->wb_cdata.wb_rx_chain[i].wb_mbuf = NULL; - } - } - bzero((char *)&sc->wb_ldata->wb_rx_list, - sizeof(sc->wb_ldata->wb_rx_list)); - - /* - * Free the TX list buffers. - */ - for (i = 0; i < WB_TX_LIST_CNT; i++) { - if (sc->wb_cdata.wb_tx_chain[i].wb_mbuf != NULL) { - m_freem(sc->wb_cdata.wb_tx_chain[i].wb_mbuf); - sc->wb_cdata.wb_tx_chain[i].wb_mbuf = NULL; - } - } - - bzero((char *)&sc->wb_ldata->wb_tx_list, - sizeof(sc->wb_ldata->wb_tx_list)); - - ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - - return; -} - -/* - * Stop all chip I/O so that the kernel's probe routines don't - * get confused by errant DMAs when rebooting. - */ -static void wb_shutdown(howto, arg) - int howto; - void *arg; -{ - struct wb_softc *sc = (struct wb_softc *)arg; - - wb_stop(sc); - - return; -} - -static struct pci_device wb_device = { - "wb", - wb_probe, - wb_attach, - &wb_count, - NULL -}; -DATA_SET(pcidevice_set, wb_device); diff --git a/sys/pci/if_wbreg.h b/sys/pci/if_wbreg.h deleted file mode 100644 index 17c55d8ce36e..000000000000 --- a/sys/pci/if_wbreg.h +++ /dev/null @@ -1,583 +0,0 @@ -/* - * Copyright (c) 1997, 1998 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_wbreg.h,v 1.12 1998/11/29 06:40:50 wpaul Exp wpaul $ - */ - -/* - * Winbond register definitions. - */ - -#define WB_BUSCTL 0x00 /* bus control */ -#define WB_TXSTART 0x04 /* tx start demand */ -#define WB_RXSTART 0x08 /* rx start demand */ -#define WB_RXADDR 0x0C /* rx descriptor list start addr */ -#define WB_TXADDR 0x10 /* tx descriptor list start addr */ -#define WB_ISR 0x14 /* interrupt status register */ -#define WB_NETCFG 0x18 /* network config register */ -#define WB_IMR 0x1C /* interrupt mask */ -#define WB_FRAMESDISCARDED 0x20 /* # of discarded frames */ -#define WB_SIO 0x24 /* MII and ROM/EEPROM access */ -#define WB_BOOTROMADDR 0x28 -#define WB_TIMER 0x2C /* general timer */ -#define WB_CURRXCTL 0x30 /* current RX descriptor */ -#define WB_CURRXBUF 0x34 /* current RX buffer */ -#define WB_MAR0 0x38 /* multicast filter 0 */ -#define WB_MAR1 0x3C /* multicast filter 1 */ -#define WB_NODE0 0x40 /* station address 0 */ -#define WB_NODE1 0x44 /* station address 1 */ -#define WB_BOOTROMSIZE 0x48 /* boot ROM size */ -#define WB_CURTXCTL 0x4C /* current TX descriptor */ -#define WB_CURTXBUF 0x50 /* current TX buffer */ - -/* - * Bus control bits. - */ -#define WB_BUSCTL_RESET 0x00000001 -#define WB_BUSCTL_ARBITRATION 0x00000002 -#define WB_BUSCTL_SKIPLEN 0x0000007C -#define WB_BUSCTL_BUF_BIGENDIAN 0x00000080 -#define WB_BUSCTL_BURSTLEN 0x00003F00 -#define WB_BUSCTL_CACHEALIGN 0x0000C000 -#define WB_BUSCTL_DES_BIGENDIAN 0x00100000 -#define WB_BUSCTL_WAIT 0x00200000 - -#define WB_SKIPLEN_1LONG 0x00000004 -#define WB_SKIPLEN_2LONG 0x00000008 -#define WB_SKIPLEN_3LONG 0x00000010 -#define WB_SKIPLEN_4LONG 0x00000020 -#define WB_SKIPLEN_5LONG 0x00000040 - -#define WB_CACHEALIGN_8LONG 0x00004000 -#define WB_CACHEALIGN_16LONG 0x00008000 -#define WB_CACHEALIGN_32LONG 0x0000C000 - -#define WB_BURSTLEN_USECA 0x00000000 -#define WB_BURSTLEN_1LONG 0x00000100 -#define WB_BURSTLEN_2LONG 0x00000200 -#define WB_BURSTLEN_4LONG 0x00000400 -#define WB_BURSTLEN_8LONG 0x00000800 -#define WB_BURSTLEN_16LONG 0x00001000 -#define WB_BURSTLEN_32LONG 0x00002000 - -#define WB_BUSCTL_CONFIG (WB_CACHEALIGN_8LONG|WB_SKIPLEN_3LONG| \ - WB_BURSTLEN_8LONG) - -/* - * Interrupt status bits. - */ -#define WB_ISR_TX_OK 0x00000001 -#define WB_ISR_TX_IDLE 0x00000002 -#define WB_ISR_TX_NOBUF 0x00000004 -#define WB_ISR_RX_EARLY 0x00000008 -#define WB_ISR_RX_ERR 0x00000010 -#define WB_ISR_TX_UNDERRUN 0x00000020 -#define WB_ISR_RX_OK 0x00000040 -#define WB_ISR_RX_NOBUF 0x00000080 -#define WB_ISR_RX_IDLE 0x00000100 -#define WB_ISR_TX_EARLY 0x00000400 -#define WB_ISR_TIMER_EXPIRED 0x00000800 -#define WB_ISR_BUS_ERR 0x00002000 -#define WB_ISR_ABNORMAL 0x00008000 -#define WB_ISR_NORMAL 0x00010000 -#define WB_ISR_RX_STATE 0x000E0000 -#define WB_ISR_TX_STATE 0x00700000 -#define WB_ISR_BUSERRTYPE 0x03800000 - -/* - * The RX_STATE and TX_STATE fields are not described anywhere in the - * Winbond datasheet, however it appears that the Winbond chip is an - * attempt at a DEC 'tulip' clone, hence the ISR register is identical - * to that of the tulip chip and we can steal the bit definitions from - * the tulip documentation. - */ -#define WB_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */ -#define WB_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */ -#define WB_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */ -#define WB_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */ -#define WB_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */ -#define WB_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */ -#define WB_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */ -#define WB_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */ - -#define WB_TXSTATE_RESET 0x00000000 /* 000 - reset */ -#define WB_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */ -#define WB_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */ -#define WB_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */ -#define WB_TXSTATE_RSVD 0x00400000 /* 100 - reserved */ -#define WB_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */ -#define WB_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */ -#define WB_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */ - -/* - * Network config bits. - */ -#define WB_NETCFG_RX_ON 0x00000002 -#define WB_NETCFG_RX_ALLPHYS 0x00000008 -#define WB_NETCFG_RX_MULTI 0x00000010 -#define WB_NETCFG_RX_BROAD 0x00000020 -#define WB_NETCFG_RX_RUNT 0x00000040 -#define WB_NETCFG_RX_ERR 0x00000080 -#define WB_NETCFG_FULLDUPLEX 0x00000200 -#define WB_NETCFG_LOOPBACK 0x00000C00 -#define WB_NETCFG_TX_ON 0x00002000 -#define WB_NETCFG_TX_THRESH 0x001FC000 -#define WB_NETCFG_RX_EARLYTHRSH 0x1FE00000 -#define WB_NETCFG_100MBPS 0x20000000 -#define WB_NETCFG_TX_EARLY_ON 0x40000000 -#define WB_NETCFG_RX_EARLY_ON 0x80000000 - -/* - * The tx threshold can be adjusted in increments of 32 bytes. - */ -#define WB_TXTHRESH(x) ((x >> 5) << 14) -#define WB_TXTHRESH_CHUNK 32 -#define WB_TXTHRESH_INIT 0 /*72*/ - -/* - * Interrupt mask bits. - */ -#define WB_IMR_TX_OK 0x00000001 -#define WB_IMR_TX_IDLE 0x00000002 -#define WB_IMR_TX_NOBUF 0x00000004 -#define WB_IMR_RX_EARLY 0x00000008 -#define WB_IMR_RX_ERR 0x00000010 -#define WB_IMR_TX_UNDERRUN 0x00000020 -#define WB_IMR_RX_OK 0x00000040 -#define WB_IMR_RX_NOBUF 0x00000080 -#define WB_IMR_RX_IDLE 0x00000100 -#define WB_IMR_TX_EARLY 0x00000400 -#define WB_IMR_TIMER_EXPIRED 0x00000800 -#define WB_IMR_BUS_ERR 0x00002000 -#define WB_IMR_ABNORMAL 0x00008000 -#define WB_IMR_NORMAL 0x00010000 - -#define WB_INTRS \ - (WB_IMR_RX_OK|WB_IMR_TX_OK|WB_IMR_RX_NOBUF|WB_IMR_RX_ERR| \ - WB_IMR_TX_NOBUF|WB_IMR_TX_UNDERRUN|WB_IMR_BUS_ERR| \ - WB_IMR_ABNORMAL|WB_IMR_NORMAL|WB_IMR_TX_EARLY) -/* - * Serial I/O (EEPROM/ROM) bits. - */ -#define WB_SIO_EE_CS 0x00000001 /* EEPROM chip select */ -#define WB_SIO_EE_CLK 0x00000002 /* EEPROM clock */ -#define WB_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */ -#define WB_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */ -#define WB_SIO_ROMDATA4 0x00000010 -#define WB_SIO_ROMDATA5 0x00000020 -#define WB_SIO_ROMDATA6 0x00000040 -#define WB_SIO_ROMDATA7 0x00000080 -#define WB_SIO_ROMCTL_WRITE 0x00000200 -#define WB_SIO_ROMCTL_READ 0x00000400 -#define WB_SIO_EESEL 0x00000800 -#define WB_SIO_MII_CLK 0x00010000 /* MDIO clock */ -#define WB_SIO_MII_DATAIN 0x00020000 /* MDIO data out */ -#define WB_SIO_MII_DIR 0x00040000 /* MDIO dir */ -#define WB_SIO_MII_DATAOUT 0x00080000 /* MDIO data in */ - -#define WB_EECMD_WRITE 0x140 -#define WB_EECMD_READ 0x180 -#define WB_EECMD_ERASE 0x1c0 - -/* - * Winbond TX/RX descriptor structure. - */ - -struct wb_desc { - u_int32_t wb_status; - u_int32_t wb_ctl; - u_int32_t wb_ptr1; - u_int32_t wb_ptr2; -}; - -#define wb_data wb_ptr1 -#define wb_next wb_ptr2 - -#define WB_RXSTAT_CRCERR 0x00000002 -#define WB_RXSTAT_DRIBBLE 0x00000004 -#define WB_RXSTAT_MIIERR 0x00000008 -#define WB_RXSTAT_LATEEVENT 0x00000040 -#define WB_RXSTAT_GIANT 0x00000080 -#define WB_RXSTAT_LASTFRAG 0x00000100 -#define WB_RXSTAT_FIRSTFRAG 0x00000200 -#define WB_RXSTAT_MULTICAST 0x00000400 -#define WB_RXSTAT_RUNT 0x00000800 -#define WB_RXSTAT_RXTYPE 0x00003000 -#define WB_RXSTAT_RXERR 0x00008000 -#define WB_RXSTAT_RXLEN 0x3FFF0000 -#define WB_RXSTAT_RXCMP 0x40000000 -#define WB_RXSTAT_OWN 0x80000000 - -#define WB_RXBYTES(x) ((x & WB_RXSTAT_RXLEN) >> 16) -#define WB_RXSTAT (WB_RXSTAT_FIRSTFRAG|WB_RXSTAT_LASTFRAG|WB_RXSTAT_OWN) - -#define WB_RXCTL_BUFLEN1 0x00000FFF -#define WB_RXCTL_BUFLEN2 0x00FFF000 -#define WB_RXCTL_RLINK 0x01000000 -#define WB_RXCTL_RLAST 0x02000000 - -#define WB_TXSTAT_DEFER 0x00000001 -#define WB_TXSTAT_UNDERRUN 0x00000002 -#define WB_TXSTAT_COLLCNT 0x00000078 -#define WB_TXSTAT_SQE 0x00000080 -#define WB_TXSTAT_ABORT 0x00000100 -#define WB_TXSTAT_LATECOLL 0x00000200 -#define WB_TXSTAT_NOCARRIER 0x00000400 -#define WB_TXSTAT_CARRLOST 0x00000800 -#define WB_TXSTAT_TXERR 0x00001000 -#define WB_TXSTAT_OWN 0x80000000 - -#define WB_TXCTL_BUFLEN1 0x000007FF -#define WB_TXCTL_BUFLEN2 0x003FF800 -#define WB_TXCTL_PAD 0x00800000 -#define WB_TXCTL_TLINK 0x01000000 -#define WB_TXCTL_TLAST 0x02000000 -#define WB_TXCTL_NOCRC 0x08000000 -#define WB_TXCTL_FIRSTFRAG 0x20000000 -#define WB_TXCTL_LASTFRAG 0x40000000 -#define WB_TXCTL_FINT 0x80000000 - -#define WB_MAXFRAGS 16 -#define WB_RX_LIST_CNT 64 -#define WB_TX_LIST_CNT 64 -#define WB_MIN_FRAMELEN 60 - -/* - * A transmit 'super descriptor' is actually WB_MAXFRAGS regular - * descriptors clumped together. The idea here is to emulate the - * multi-fragment descriptor layout found in devices such as the - * Texas Instruments ThunderLAN and 3Com boomerang and cylone chips. - * The advantage to using this scheme is that it avoids buffer copies. - * The disadvantage is that there's a certain amount of overhead due - * to the fact that each 'fragment' is 16 bytes long. In my tests, - * this limits top speed to about 10.5MB/sec. It should be more like - * 11.5MB/sec. However, the upshot is that you can achieve better - * results on slower machines: a Pentium 200 can pump out packets at - * same speed as a PII 400. - */ -struct wb_txdesc { - struct wb_desc wb_frag[WB_MAXFRAGS]; -}; - -#define WB_TXNEXT(x) x->wb_ptr->wb_frag[x->wb_lastdesc].wb_next -#define WB_TXSTATUS(x) x->wb_ptr->wb_frag[x->wb_lastdesc].wb_status -#define WB_TXCTL(x) x->wb_ptr->wb_frag[x->wb_lastdesc].wb_ctl -#define WB_TXDATA(x) x->wb_ptr->wb_frag[x->wb_lastdesc].wb_data - -#define WB_TXOWN(x) x->wb_ptr->wb_frag[0].wb_status - -#define WB_UNSENT 0x1234 - -struct wb_list_data { - struct wb_desc wb_rx_list[WB_RX_LIST_CNT]; - struct wb_txdesc wb_tx_list[WB_TX_LIST_CNT]; -}; - -struct wb_chain { - struct wb_txdesc *wb_ptr; - struct mbuf *wb_mbuf; - struct wb_chain *wb_nextdesc; - u_int8_t wb_lastdesc; -}; - -struct wb_chain_onefrag { - struct wb_desc *wb_ptr; - struct mbuf *wb_mbuf; - struct wb_chain_onefrag *wb_nextdesc; - u_int8_t wb_rlast; -}; - -struct wb_chain_data { - u_int8_t wb_pad[WB_MIN_FRAMELEN]; - struct wb_chain_onefrag wb_rx_chain[WB_RX_LIST_CNT]; - struct wb_chain wb_tx_chain[WB_TX_LIST_CNT]; - - struct wb_chain_onefrag *wb_rx_head; - - struct wb_chain *wb_tx_head; - struct wb_chain *wb_tx_tail; - struct wb_chain *wb_tx_free; -}; - -struct wb_type { - u_int16_t wb_vid; - u_int16_t wb_did; - char *wb_name; -}; - -struct wb_mii_frame { - u_int8_t mii_stdelim; - u_int8_t mii_opcode; - u_int8_t mii_phyaddr; - u_int8_t mii_regaddr; - u_int8_t mii_turnaround; - u_int16_t mii_data; -}; - -/* - * MII constants - */ -#define WB_MII_STARTDELIM 0x01 -#define WB_MII_READOP 0x02 -#define WB_MII_WRITEOP 0x01 -#define WB_MII_TURNAROUND 0x02 - -#define WB_FLAG_FORCEDELAY 1 -#define WB_FLAG_SCHEDDELAY 2 -#define WB_FLAG_DELAYTIMEO 3 - -struct wb_softc { - struct arpcom arpcom; /* interface info */ - struct ifmedia ifmedia; /* media info */ - bus_space_handle_t wb_bhandle; - bus_space_tag_t wb_btag; - struct wb_type *wb_info; /* 3Com adapter info */ - struct wb_type *wb_pinfo; /* phy info */ - u_int8_t wb_unit; /* interface number */ - u_int8_t wb_type; - u_int8_t wb_phy_addr; /* PHY address */ - u_int8_t wb_tx_pend; /* TX pending */ - u_int8_t wb_want_auto; - u_int8_t wb_autoneg; - u_int16_t wb_txthresh; - caddr_t wb_ldata_ptr; - struct wb_list_data *wb_ldata; - struct wb_chain_data wb_cdata; -}; - -/* - * register space access macros - */ -#define CSR_WRITE_4(sc, reg, val) \ - bus_space_write_4(sc->wb_btag, sc->wb_bhandle, reg, val) -#define CSR_WRITE_2(sc, reg, val) \ - bus_space_write_2(sc->wb_btag, sc->wb_bhandle, reg, val) -#define CSR_WRITE_1(sc, reg, val) \ - bus_space_write_1(sc->wb_btag, sc->wb_bhandle, reg, val) - -#define CSR_READ_4(sc, reg) \ - bus_space_read_4(sc->wb_btag, sc->wb_bhandle, reg) -#define CSR_READ_2(sc, reg) \ - bus_space_read_2(sc->wb_btag, sc->wb_bhandle, reg) -#define CSR_READ_1(sc, reg) \ - bus_space_read_1(sc->wb_btag, sc->wb_bhandle, reg) - -#define WB_TIMEOUT 1000 - -/* - * General constants that are fun to know. - * - * Winbond PCI vendor ID - */ -#define WB_VENDORID 0x1050 - -/* - * Winbond device IDs. - */ -#define WB_DEVICEID_840F 0x0840 - -/* - * Compex vendor ID. - */ -#define CP_VENDORID 0x11F6 - -/* - * Compex device IDs. - */ -#define CP_DEVICEID_RL100 0x2011 - -/* - * Texas Instruments PHY identifiers - */ -#define TI_PHY_VENDORID 0x4000 -#define TI_PHY_10BT 0x501F -#define TI_PHY_100VGPMI 0x502F - -/* - * These ID values are for the NS DP83840A 10/100 PHY - */ -#define NS_PHY_VENDORID 0x2000 -#define NS_PHY_83840A 0x5C0F - -/* - * Level 1 10/100 PHY - */ -#define LEVEL1_PHY_VENDORID 0x7810 -#define LEVEL1_PHY_LXT970 0x000F - -/* - * Intel 82555 10/100 PHY - */ -#define INTEL_PHY_VENDORID 0x0A28 -#define INTEL_PHY_82555 0x015F - -/* - * SEEQ 80220 10/100 PHY - */ -#define SEEQ_PHY_VENDORID 0x0016 -#define SEEQ_PHY_80220 0xF83F - - -/* - * PCI low memory base and low I/O base register, and - * other PCI registers. Note: some are only available on - * the 3c905B, in particular those that related to power management. - */ - -#define WB_PCI_VENDOR_ID 0x00 -#define WB_PCI_DEVICE_ID 0x02 -#define WB_PCI_COMMAND 0x04 -#define WB_PCI_STATUS 0x06 -#define WB_PCI_CLASSCODE 0x09 -#define WB_PCI_LATENCY_TIMER 0x0D -#define WB_PCI_HEADER_TYPE 0x0E -#define WB_PCI_LOIO 0x10 -#define WB_PCI_LOMEM 0x14 -#define WB_PCI_BIOSROM 0x30 -#define WB_PCI_INTLINE 0x3C -#define WB_PCI_INTPIN 0x3D -#define WB_PCI_MINGNT 0x3E -#define WB_PCI_MINLAT 0x0F -#define WB_PCI_RESETOPT 0x48 -#define WB_PCI_EEPROM_DATA 0x4C - -/* power management registers */ -#define WB_PCI_CAPID 0xDC /* 8 bits */ -#define WB_PCI_NEXTPTR 0xDD /* 8 bits */ -#define WB_PCI_PWRMGMTCAP 0xDE /* 16 bits */ -#define WB_PCI_PWRMGMTCTRL 0xE0 /* 16 bits */ - -#define WB_PSTATE_MASK 0x0003 -#define WB_PSTATE_D0 0x0000 -#define WB_PSTATE_D1 0x0002 -#define WB_PSTATE_D2 0x0002 -#define WB_PSTATE_D3 0x0003 -#define WB_PME_EN 0x0010 -#define WB_PME_STATUS 0x8000 - -#define PHY_UNKNOWN 6 - -#define WB_PHYADDR_MIN 0x00 -#define WB_PHYADDR_MAX 0x1F - -#define PHY_BMCR 0x00 -#define PHY_BMSR 0x01 -#define PHY_VENID 0x02 -#define PHY_DEVID 0x03 -#define PHY_ANAR 0x04 -#define PHY_LPAR 0x05 -#define PHY_ANEXP 0x06 - -#define PHY_ANAR_NEXTPAGE 0x8000 -#define PHY_ANAR_RSVD0 0x4000 -#define PHY_ANAR_TLRFLT 0x2000 -#define PHY_ANAR_RSVD1 0x1000 -#define PHY_ANAR_RSVD2 0x0800 -#define PHY_ANAR_RSVD3 0x0400 -#define PHY_ANAR_100BT4 0x0200 -#define PHY_ANAR_100BTXFULL 0x0100 -#define PHY_ANAR_100BTXHALF 0x0080 -#define PHY_ANAR_10BTFULL 0x0040 -#define PHY_ANAR_10BTHALF 0x0020 -#define PHY_ANAR_PROTO4 0x0010 -#define PHY_ANAR_PROTO3 0x0008 -#define PHY_ANAR_PROTO2 0x0004 -#define PHY_ANAR_PROTO1 0x0002 -#define PHY_ANAR_PROTO0 0x0001 - -/* - * These are the register definitions for the PHY (physical layer - * interface chip). - */ -/* - * PHY BMCR Basic Mode Control Register - */ -#define PHY_BMCR_RESET 0x8000 -#define PHY_BMCR_LOOPBK 0x4000 -#define PHY_BMCR_SPEEDSEL 0x2000 -#define PHY_BMCR_AUTONEGENBL 0x1000 -#define PHY_BMCR_RSVD0 0x0800 /* write as zero */ -#define PHY_BMCR_ISOLATE 0x0400 -#define PHY_BMCR_AUTONEGRSTR 0x0200 -#define PHY_BMCR_DUPLEX 0x0100 -#define PHY_BMCR_COLLTEST 0x0080 -#define PHY_BMCR_RSVD1 0x0040 /* write as zero, don't care */ -#define PHY_BMCR_RSVD2 0x0020 /* write as zero, don't care */ -#define PHY_BMCR_RSVD3 0x0010 /* write as zero, don't care */ -#define PHY_BMCR_RSVD4 0x0008 /* write as zero, don't care */ -#define PHY_BMCR_RSVD5 0x0004 /* write as zero, don't care */ -#define PHY_BMCR_RSVD6 0x0002 /* write as zero, don't care */ -#define PHY_BMCR_RSVD7 0x0001 /* write as zero, don't care */ -/* - * RESET: 1 == software reset, 0 == normal operation - * Resets status and control registers to default values. - * Relatches all hardware config values. - * - * LOOPBK: 1 == loopback operation enabled, 0 == normal operation - * - * SPEEDSEL: 1 == 100Mb/s, 0 == 10Mb/s - * Link speed is selected byt his bit or if auto-negotiation if bit - * 12 (AUTONEGENBL) is set (in which case the value of this register - * is ignored). - * - * AUTONEGENBL: 1 == Autonegotiation enabled, 0 == Autonegotiation disabled - * Bits 8 and 13 are ignored when autoneg is set, otherwise bits 8 and 13 - * determine speed and mode. Should be cleared and then set if PHY configured - * for no autoneg on startup. - * - * ISOLATE: 1 == isolate PHY from MII, 0 == normal operation - * - * AUTONEGRSTR: 1 == restart autonegotiation, 0 = normal operation - * - * DUPLEX: 1 == full duplex mode, 0 == half duplex mode - * - * COLLTEST: 1 == collision test enabled, 0 == normal operation - */ - -/* - * PHY, BMSR Basic Mode Status Register - */ -#define PHY_BMSR_100BT4 0x8000 -#define PHY_BMSR_100BTXFULL 0x4000 -#define PHY_BMSR_100BTXHALF 0x2000 -#define PHY_BMSR_10BTFULL 0x1000 -#define PHY_BMSR_10BTHALF 0x0800 -#define PHY_BMSR_RSVD1 0x0400 /* write as zero, don't care */ -#define PHY_BMSR_RSVD2 0x0200 /* write as zero, don't care */ -#define PHY_BMSR_RSVD3 0x0100 /* write as zero, don't care */ -#define PHY_BMSR_RSVD4 0x0080 /* write as zero, don't care */ -#define PHY_BMSR_MFPRESUP 0x0040 -#define PHY_BMSR_AUTONEGCOMP 0x0020 -#define PHY_BMSR_REMFAULT 0x0010 -#define PHY_BMSR_CANAUTONEG 0x0008 -#define PHY_BMSR_LINKSTAT 0x0004 -#define PHY_BMSR_JABBER 0x0002 -#define PHY_BMSR_EXTENDED 0x0001 diff --git a/sys/pci/if_xl.c b/sys/pci/if_xl.c index 26c528457240..aede51e4c831 100644 --- a/sys/pci/if_xl.c +++ b/sys/pci/if_xl.c @@ -29,7 +29,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: if_xl.c,v 1.21 1998/12/14 06:32:57 dillon Exp $ + * $Id: if_xl.c,v 1.54 1998/09/25 17:43:57 wpaul Exp wpaul $ */ /* @@ -145,9 +145,9 @@ #include <pci/if_xlreg.h> -#if !defined(lint) -static const char rcsid[] = - "$Id: if_xl.c,v 1.21 1998/12/14 06:32:57 dillon Exp $"; +#ifndef lint +static char rcsid[] = + "$Id: if_xl.c,v 1.54 1998/09/25 17:43:57 wpaul Exp wpaul $"; #endif /* @@ -194,7 +194,7 @@ static struct xl_type xl_phys[] = { }; static unsigned long xl_count = 0; -static const char *xl_probe __P((pcici_t, pcidi_t)); +static char *xl_probe __P((pcici_t, pcidi_t)); static void xl_attach __P((pcici_t, int)); static int xl_newbuf __P((struct xl_softc *, @@ -224,14 +224,14 @@ static void xl_mii_send __P((struct xl_softc *, u_int32_t, int)); static int xl_mii_readreg __P((struct xl_softc *, struct xl_mii_frame *)); static int xl_mii_writereg __P((struct xl_softc *, struct xl_mii_frame *)); static u_int16_t xl_phy_readreg __P((struct xl_softc *, int)); -static void xl_phy_writereg __P((struct xl_softc *, int, int)); +static void xl_phy_writereg __P((struct xl_softc *, u_int16_t, u_int16_t)); static void xl_autoneg_xmit __P((struct xl_softc *)); static void xl_autoneg_mii __P((struct xl_softc *, int, int)); static void xl_setmode_mii __P((struct xl_softc *, int)); static void xl_getmode_mii __P((struct xl_softc *)); static void xl_setmode __P((struct xl_softc *, int)); -static u_int8_t xl_calchash __P((caddr_t)); +static u_int8_t xl_calchash __P((u_int8_t *)); static void xl_setmulti __P((struct xl_softc *)); static void xl_setmulti_hash __P((struct xl_softc *)); static void xl_reset __P((struct xl_softc *)); @@ -502,8 +502,8 @@ static u_int16_t xl_phy_readreg(sc, reg) static void xl_phy_writereg(sc, reg, data) struct xl_softc *sc; - int reg; - int data; + u_int16_t reg; + u_int16_t data; { struct xl_mii_frame frame; @@ -592,7 +592,7 @@ static int xl_read_eeprom(sc, dest, off, cnt, swap) * On older cards, the upper 2 bits will be ignored. Grrrr.... */ static u_int8_t xl_calchash(addr) - caddr_t addr; + u_int8_t *addr; { u_int32_t crc, carry; int i, j; @@ -983,7 +983,7 @@ static void xl_getmode_mii(sc) if (bootverbose) printf("xl%d: forcing on autoneg support for BT4\n", sc->xl_unit); - ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); + ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; #endif } @@ -1185,7 +1185,7 @@ static void xl_reset(sc) * Probe for a 3Com Etherlink XL chip. Check the PCI vendor and device * IDs against our list and return a device name if we find a match. */ -static const char * +static char * xl_probe(config_id, device_id) pcici_t config_id; pcidi_t device_id; @@ -1444,7 +1444,7 @@ xl_attach(config_id, unit) if (round % 8) { round++; roundptr++; - } else + } break; } sc->xl_ldata = (struct xl_list_data *)roundptr; @@ -1932,6 +1932,8 @@ static void xl_txeof(sc) cur_tx->xl_next = sc->xl_cdata.xl_tx_free; sc->xl_cdata.xl_tx_free = cur_tx; + if (!cur_tx->xl_ptr->xl_next); + break; } if (sc->xl_cdata.xl_tx_head == NULL) { @@ -1977,10 +1979,6 @@ static void xl_txeoc(sc) * first generation 3c90X chips. */ CSR_WRITE_1(sc, XL_TX_FREETHRESH, XL_PACKET_SIZE >> 8); - if (sc->xl_type == XL_TYPE_905B) { - CSR_WRITE_2(sc, XL_COMMAND, - XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4)); - } CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_ENABLE); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_DOWN_UNSTALL); } else { @@ -2259,12 +2257,6 @@ static void xl_start(ifp) } /* - * If there are no packets queued, bail. - */ - if (cur_tx == NULL) - return; - - /* * Place the request for the upload interrupt * in the last descriptor in the chain. This way, if * we're chaining several packets at once, we'll only @@ -2286,7 +2278,6 @@ static void xl_start(ifp) vtophys(start_tx->xl_ptr); sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status &= ~XL_TXSTAT_DL_INTR; - sc->xl_cdata.xl_tx_tail = cur_tx; } else { sc->xl_cdata.xl_tx_head = start_tx; sc->xl_cdata.xl_tx_tail = cur_tx; @@ -2387,20 +2378,6 @@ static void xl_init(xsc) */ CSR_WRITE_1(sc, XL_TX_FREETHRESH, XL_PACKET_SIZE >> 8); - /* - * If this is a 3c905B, also set the tx reclaim threshold. - * This helps cut down on the number of tx reclaim errors - * that could happen on a busy network. The chip multiplies - * the register value by 16 to obtain the actual threshold - * in bytes, so we divide by 16 when setting the value here. - * The existing threshold value can be examined by reading - * the register at offset 9 in window 5. - */ - if (sc->xl_type == XL_TYPE_905B) { - CSR_WRITE_2(sc, XL_COMMAND, - XL_CMD_SET_TX_RECLAIM|(XL_PACKET_SIZE >> 4)); - } - /* Set RX filter bits. */ XL_SEL_WIN(5); rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER); diff --git a/sys/pci/if_xlreg.h b/sys/pci/if_xlreg.h index c45914f57fbb..b2604737c68f 100644 --- a/sys/pci/if_xlreg.h +++ b/sys/pci/if_xlreg.h @@ -29,7 +29,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: if_xlreg.h,v 1.19 1998/10/22 15:35:06 wpaul Exp $ + * $Id: if_xlreg.h,v 1.16 1998/09/25 17:43:57 wpaul Exp wpaul $ */ #define XL_EE_READ 0x0080 /* read, 5 bit address */ @@ -361,7 +361,6 @@ */ #define XL_W5_STAT_ENB 0x0C #define XL_W5_INTR_ENB 0x0A -#define XL_W5_RECLAIM_THRESH 0x09 /* 3c905B only */ #define XL_W5_RX_FILTER 0x08 #define XL_W5_RX_EARLYTHRESH 0x06 #define XL_W5_TX_AVAILTHRESH 0x02 diff --git a/sys/pci/isp_pci.c b/sys/pci/isp_pci.c index 84960d8f1e2d..ae7842b2e079 100644 --- a/sys/pci/isp_pci.c +++ b/sys/pci/isp_pci.c @@ -1,5 +1,4 @@ -/* $Id: isp_pci.c,v 1.12 1998/12/28 19:24:23 mjacob Exp $ */ -/* release_12_28_98_A+ */ +/* $FreeBSD$ */ /* * PCI specific probe and attach routines for Qlogic ISP SCSI adapters. * FreeBSD Version. @@ -79,7 +78,7 @@ static struct ispmdvec mdvec = { ISP_CODE_LENGTH, ISP_CODE_ORG, ISP_CODE_VERSION, - BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64, + BIU_BURST_ENABLE, 0 }; @@ -96,7 +95,7 @@ static struct ispmdvec mdvec_2100 = { ISP2100_CODE_LENGTH, ISP2100_CODE_ORG, ISP2100_CODE_VERSION, - 0, /* Irrelevant to the 2100 */ + BIU_BURST_ENABLE, 0 }; @@ -129,7 +128,7 @@ static struct ispmdvec mdvec_2100 = { #define MEM_MAP_REG 0x14 -static const char *isp_pci_probe __P((pcici_t tag, pcidi_t type)); +static char *isp_pci_probe __P((pcici_t tag, pcidi_t type)); static void isp_pci_attach __P((pcici_t config_d, int unit)); /* This distinguishing define is not right, but it does work */ @@ -196,8 +195,10 @@ struct pci_device isp_pci_driver = { DATA_SET (pcidevice_set, isp_pci_driver); -static const char * -isp_pci_probe(pcici_t tag, pcidi_t type) +static char * +isp_pci_probe(tag, type) + pcici_t tag; + pcidi_t type; { static int oneshot = 1; char *x; @@ -223,7 +224,9 @@ isp_pci_probe(pcici_t tag, pcidi_t type) static void -isp_pci_attach(pcici_t config_id, int unit) +isp_pci_attach(config_id, unit) + pcici_t config_id; + int unit; { int mapped; pci_port_t io_port; @@ -267,11 +270,7 @@ isp_pci_attach(pcici_t config_id, int unit) pcs->pci_st == IO_SPACE_MAPPING? "I/O" : "Memory"); isp = &pcs->pci_isp; -#if __FreeBSD_version >= 300006 - (void) snprintf(isp->isp_name, sizeof(isp->isp_name), "isp%d", unit); -#else (void) sprintf(isp->isp_name, "isp%d", unit); -#endif isp->isp_osinfo.unit = unit; data = pci_conf_read(config_id, PCI_ID_REG); @@ -288,7 +287,7 @@ isp_pci_attach(pcici_t config_id, int unit) data = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); data |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN; pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, data); -#if 0 + /* * Wierd- we need to clear the lsb in offset 0x30 to take the * chip out of reset state. @@ -296,7 +295,6 @@ isp_pci_attach(pcici_t config_id, int unit) data = pci_conf_read(config_id, 0x30); data &= ~1; pci_conf_write(config_id, 0x30, data); -#endif ISP_UNLOCK(isp); } else { printf("%s: unknown dev (%x)- punting\n", isp->isp_name, data); @@ -349,7 +347,9 @@ isp_pci_attach(pcici_t config_id, int unit) #define PCI_BIU_REGS_OFF BIU_REGS_OFF static u_int16_t -isp_pci_rd_reg(struct ispsoftc *isp, int regoff) +isp_pci_rd_reg(isp, regoff) + struct ispsoftc *isp; + int regoff; { u_int16_t rv; struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; @@ -382,7 +382,10 @@ isp_pci_rd_reg(struct ispsoftc *isp, int regoff) } static void -isp_pci_wr_reg(struct ispsoftc *isp, int regoff, u_int16_t val) +isp_pci_wr_reg(isp, regoff, val) + struct ispsoftc *isp; + int regoff; + u_int16_t val; { struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; int offset, oldsxp = 0; @@ -417,21 +420,33 @@ static void isp_map_result __P((void *, bus_dma_segment_t *, int, int)); static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int)); static void -isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error) +isp_map_rquest(arg, segs, nseg, error) + void *arg; + bus_dma_segment_t *segs; + int nseg; + int error; { struct ispsoftc *isp = (struct ispsoftc *) arg; isp->isp_rquest_dma = segs->ds_addr; } static void -isp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error) +isp_map_result(arg, segs, nseg, error) + void *arg; + bus_dma_segment_t *segs; + int nseg; + int error; { struct ispsoftc *isp = (struct ispsoftc *) arg; isp->isp_result_dma = segs->ds_addr; } static void -isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error) +isp_map_fcscrt(arg, segs, nseg, error) + void *arg; + bus_dma_segment_t *segs; + int nseg; + int error; { struct ispsoftc *isp = (struct ispsoftc *) arg; fcparam *fcp = isp->isp_param; @@ -439,7 +454,8 @@ isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error) } static int -isp_pci_mbxdma(struct ispsoftc *isp) +isp_pci_mbxdma(isp) + struct ispsoftc *isp; { struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; caddr_t base; @@ -511,7 +527,11 @@ typedef struct { #define MUSHERR_NOQENTRIES -2 static void -dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) +dma2(arg, dm_segs, nseg, error) + void *arg; + bus_dma_segment_t *dm_segs; + int nseg; + int error; { mush_t *mp; ISP_SCSI_XFER_T *ccb; @@ -632,8 +652,12 @@ dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) } static int -isp_pci_dmasetup(struct ispsoftc *isp, ISP_SCSI_XFER_T *ccb, ispreq_t *rq, - u_int8_t *iptrp, u_int8_t optr) +isp_pci_dmasetup(isp, ccb, rq, iptrp, optr) + struct ispsoftc *isp; + ISP_SCSI_XFER_T *ccb; + ispreq_t *rq; + u_int8_t *iptrp; + u_int8_t optr; { struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; struct ccb_hdr *ccb_h; @@ -721,8 +745,10 @@ isp_pci_dmasetup(struct ispsoftc *isp, ISP_SCSI_XFER_T *ccb, ispreq_t *rq, } static void -isp_pci_dmateardown(struct ispsoftc *isp, ISP_SCSI_XFER_T *ccb, - u_int32_t handle) +isp_pci_dmateardown(isp, ccb, handle) + struct ispsoftc *isp; + ISP_SCSI_XFER_T *ccb; + u_int32_t handle; { struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; bus_dmamap_t *dp = &pci->dmaps[handle]; @@ -739,7 +765,8 @@ isp_pci_dmateardown(struct ispsoftc *isp, ISP_SCSI_XFER_T *ccb, static int -isp_pci_mbxdma(struct ispsoftc *isp) +isp_pci_mbxdma(isp) + struct ispsoftc *isp; { struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; u_int32_t len; @@ -785,8 +812,12 @@ isp_pci_mbxdma(struct ispsoftc *isp) } static int -isp_pci_dmasetup(struct ispsoftc *isp, ISP_SCSI_XFER_T *xs, - ispreq_t *rq, u_int8_t *iptrp, u_int8_t optr) +isp_pci_dmasetup(isp, xs, rq, iptrp, optr) + struct ispsoftc *isp; + ISP_SCSI_XFER_T *xs; + ispreq_t *rq; + u_int8_t *iptrp; + u_int8_t optr; { struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; ispcontreq_t *crq; @@ -911,14 +942,16 @@ isp_pci_dmasetup(struct ispsoftc *isp, ISP_SCSI_XFER_T *xs, #endif static void -isp_pci_reset1(struct ispsoftc *isp) +isp_pci_reset1(isp) + struct ispsoftc *isp; { /* Make sure the BIOS is disabled */ isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS); } static void -isp_pci_dumpregs(struct ispsoftc *isp) +isp_pci_dumpregs(isp) + struct ispsoftc *isp; { struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; printf("%s: PCI Status Command/Status=%lx\n", pci->pci_isp.isp_name, diff --git a/sys/pci/meteor.c b/sys/pci/meteor.c index f81578d9496e..c65860beb084 100644 --- a/sys/pci/meteor.c +++ b/sys/pci/meteor.c @@ -197,7 +197,7 @@ static meteor_reg_t meteor[NMETEOR]; #define METPRI (PZERO+8)|PCATCH -static const char* met_probe (pcici_t tag, pcidi_t type); +static char* met_probe (pcici_t tag, pcidi_t type); static void met_attach(pcici_t tag, int unit); static u_long met_count; @@ -517,7 +517,7 @@ register int err = 0; } #undef i2c_print -static const char * +static char * met_probe (pcici_t tag, pcidi_t type) { @@ -2054,7 +2054,7 @@ meteor_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *pr) } int -meteor_mmap(dev_t dev, vm_offset_t offset, int nprot) +meteor_mmap(dev_t dev, int offset, int nprot) { int unit; diff --git a/sys/pci/ncr.c b/sys/pci/ncr.c index 79d8eaefe053..37033226272c 100644 --- a/sys/pci/ncr.c +++ b/sys/pci/ncr.c @@ -1,6 +1,6 @@ /************************************************************************** ** -** $Id: ncr.c,v 1.140 1998/12/14 05:47:27 dillon Exp $ +** $Id: ncr.c,v 1.136 1998/09/29 09:14:52 bde Exp $ ** ** Device driver for the NCR 53C8XX PCI-SCSI-Controller Family. ** @@ -1333,6 +1333,7 @@ static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p); static void ncr_setsync (ncb_p np, nccb_p cp,u_char scntl3,u_char sxfer, u_char period); +static void ncr_settags (tcb_p tp, lcb_p lp, u_long usrtag); static void ncr_setwide (ncb_p np, nccb_p cp, u_char wide, u_char ack); static int ncr_show_msg (u_char * msg); static int ncr_snooptest (ncb_p np); @@ -1340,7 +1341,7 @@ static void ncr_action (struct cam_sim *sim, union ccb *ccb); static void ncr_timeout (void *arg); static void ncr_wakeup (ncb_p np, u_long code); -static const char* ncr_probe (pcici_t tag, pcidi_t type); +static char* ncr_probe (pcici_t tag, pcidi_t type); static void ncr_attach (pcici_t tag, int unit); #endif /* KERNEL */ @@ -1355,10 +1356,8 @@ static void ncr_attach (pcici_t tag, int unit); */ -#if !defined(lint) -static const char ident[] = - "\n$Id: ncr.c,v 1.140 1998/12/14 05:47:27 dillon Exp $\n"; -#endif +static char ident[] = + "\n$Id: ncr.c,v 1.136 1998/09/29 09:14:52 bde Exp $\n"; static const u_long ncr_version = NCR_VERSION * 11 + (u_long) sizeof (struct ncb) * 7 @@ -1411,7 +1410,7 @@ DATA_SET (pcidevice_set, ncr_device); static char *ncr_name (ncb_p np) { static char name[10]; - snprintf(name, sizeof(name), "ncr%d", np->unit); + sprintf(name, "ncr%d", np->unit); return (name); } @@ -3357,7 +3356,7 @@ static int ncr_chip_lookup(u_long device_id, u_char revision_id) -static const char* ncr_probe (pcici_t tag, pcidi_t type) +static char* ncr_probe (pcici_t tag, pcidi_t type) { u_char rev = pci_conf_read (tag, PCI_CLASS_REG) & 0xff; int i; @@ -5014,6 +5013,8 @@ ncr_setsync(ncb_p np, nccb_p cp, u_char scntl3, u_char sxfer, u_char period) tp->tinfo.wval = scntl3; if (sxfer & 0x1f) { + unsigned f10 = 100000 << tp->tinfo.current.width; + unsigned mb10 = (f10 + period_10ns/2) / period_10ns; /* ** Disable extended Sreq/Sack filtering */ @@ -7115,7 +7116,7 @@ struct tekram_eeprom { #define TKR_ADPT_ACTNEG 0x08 #define TKR_ADPT_NOSEEK 0x10 #define TKR_ADPT_MORLUN 0x20 - u_char delay; /* unit ? ( table ??? ) */ + u_char delay; /* unit ? (table ???) */ u_char tags; /* use 4 times as many ... */ u_char filler[60]; }; diff --git a/sys/pci/pci.c b/sys/pci/pci.c index 73b8142a89c0..8d5fd193fe2e 100644 --- a/sys/pci/pci.c +++ b/sys/pci/pci.c @@ -23,7 +23,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: pci.c,v 1.92 1999/01/12 01:44:42 eivind Exp $ + * $Id: pci.c,v 1.88 1998/09/15 22:05:37 gibbs Exp $ * */ @@ -148,10 +148,9 @@ pci_maprange(unsigned mapreg) static pcimap * pci_readmaps(pcicfgregs *cfg, int maxmaps) { - int i, j = 0; + int i; pcimap *map; int map64 = 0; - int reg = PCIR_MAPS; for (i = 0; i < maxmaps; i++) { int reg = PCIR_MAPS + i*4; @@ -161,48 +160,40 @@ pci_readmaps(pcicfgregs *cfg, int maxmaps) base = pci_cfgread(cfg, reg, 4); ln2range = pci_maprange(base); - if (base == 0 || ln2range == 0 || base == 0xffffffff) - continue; /* skip invalid entry */ - else { - j++; - if (ln2range > 32) { - i++; - j++; - } - } + if (base == 0 || ln2range == 0) + maxmaps = i; + else if (ln2range > 32) + i++; } - map = malloc(j * sizeof (pcimap), M_DEVBUF, M_WAITOK); + map = malloc(maxmaps * sizeof (pcimap), M_DEVBUF, M_WAITOK); if (map != NULL) { - bzero(map, sizeof(pcimap) * j); - cfg->nummaps = j; + bzero(map, sizeof(pcimap) * maxmaps); - for (i = 0, j = 0; i < maxmaps; i++, reg += 4) { + for (i = 0; i < maxmaps; i++) { + int reg = PCIR_MAPS + i*4; u_int32_t base; u_int32_t testval; base = pci_cfgread(cfg, reg, 4); if (map64 == 0) { - if (base == 0 || base == 0xffffffff) - continue; /* skip invalid entry */ pci_cfgwrite(cfg, reg, 0xffffffff, 4); testval = pci_cfgread(cfg, reg, 4); pci_cfgwrite(cfg, reg, base, 4); - map[j].reg = reg; - map[j].base = pci_mapbase(base); - map[j].type = pci_maptype(base); - map[j].ln2size = pci_mapsize(testval); - map[j].ln2range = pci_maprange(testval); - map64 = map[j].ln2range == 64; + map[i].base = pci_mapbase(base); + map[i].type = pci_maptype(base); + map[i].ln2size = pci_mapsize(testval); + map[i].ln2range = pci_maprange(testval); + map64 = map[i].ln2range == 64; } else { /* only fill in base, other fields are 0 */ - map[j].base = base; + map[i].base = base; map64 = 0; } - j++; } + cfg->nummaps = maxmaps; } return (map); } @@ -483,6 +474,14 @@ pci_addcfg(struct pci_devinfo *dinfo) pci_drvattach(dinfo); /* XXX currently defined in pci_compat.c */ } +/* return pointer to device that is a bridge to this bus */ + +static pcicfgregs * +pci_bridgeto(int bus) +{ + return (NULL); /* XXX not yet implemented */ +} + /* scan one PCI bus for devices */ static int @@ -765,7 +764,7 @@ pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) */ if ((error = useracc((caddr_t)cio->patterns, cio->pat_buf_len, B_READ)) != 1){ - printf("pci_ioctl: pattern buffer %p, " + printf("pci_ioctl: pattern buffer %#p, " "length %u isn't user accessible for" " READ\n", cio->patterns, cio->pat_buf_len); @@ -801,7 +800,7 @@ pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) */ if ((error = useracc((caddr_t)cio->matches, cio->match_buf_len, B_WRITE)) != 1) { - printf("pci_ioctl: match buffer %p, length %u " + printf("pci_ioctl: match buffer %#p, length %u " "isn't user accessible for WRITE\n", cio->matches, cio->match_buf_len); error = EACCES; diff --git a/sys/pci/pci_compat.c b/sys/pci/pci_compat.c index 9f4c612b161f..c08231820733 100644 --- a/sys/pci/pci_compat.c +++ b/sys/pci/pci_compat.c @@ -23,7 +23,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: pci_compat.c,v 1.19 1999/01/14 06:22:10 jdp Exp $ + * $Id: pci_compat.c,v 1.11 1998/09/15 08:21:09 gibbs Exp $ * */ @@ -35,7 +35,7 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> -#include <sys/linker_set.h> +#include <sys/kernel.h> /* for DATA_SET support */ #include <vm/vm.h> #include <vm/pmap.h> @@ -48,10 +48,6 @@ #include <sys/drvresource.h> #endif -#ifdef APIC_IO -#include <machine/smp.h> -#endif - #ifdef PCI_COMPAT /* ------------------------------------------------------------------------- */ @@ -59,16 +55,13 @@ static int pci_mapno(pcicfgregs *cfg, int reg) { - int i, nummaps; - pcimap *map; - - nummaps = cfg->nummaps; - map = cfg->map; - - for (i = 0; i < nummaps; i++) - if (map[i].reg == reg) - return (i); - return (-1); + int map = -1; + if ((reg & 0x03) == 0) { + map = (reg -0x10) / 4; + if (map < 0 || map >= cfg->nummaps) + map = -1; + } + return (map); } static int @@ -175,10 +168,11 @@ int pci_map_mem(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa) int pci_map_dense(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa) { + vm_offset_t dense; + int retval = 0; + if(pci_map_mem(cfg, reg, va, pa)){ #ifdef __alpha__ - vm_offset_t dense; - if(dense = pci_cvt_to_dense(*pa)){ *pa = dense; *va = ALPHA_PHYS_TO_K0SEG(*pa); @@ -195,10 +189,11 @@ pci_map_dense(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa) int pci_map_bwx(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa) { + vm_offset_t bwx; + int retval = 0; + if(pci_map_mem(cfg, reg, va, pa)){ #ifdef __alpha__ - vm_offset_t bwx; - if(bwx = pci_cvt_to_bwx(*pa)){ *pa = bwx; *va = ALPHA_PHYS_TO_K0SEG(*pa); @@ -212,15 +207,9 @@ pci_map_bwx(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa) return (0); } -int -pci_map_int(pcici_t cfg, pci_inthand_t *handler, void *arg, intrmask_t *maskptr) -{ - return (pci_map_int_right(cfg, handler, arg, maskptr, 0)); -} int -pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg, - intrmask_t *maskptr, u_int flags) +pci_map_int(pcici_t cfg, pci_inthand_t *func, void *arg, unsigned *maskptr) { int error; #ifdef APIC_IO @@ -231,8 +220,7 @@ pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg, void *dev_instance = (void *)-1; /* XXX use cfg->devdata */ void *idesc; - idesc = intr_create(dev_instance, irq, handler, arg, maskptr, - flags); + idesc = intr_create(dev_instance, irq, func, arg, maskptr, 0); error = intr_connect(idesc); if (error != 0) return 0; @@ -265,8 +253,8 @@ pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg, nextpin = next_apic_irq(irq); while (nextpin >= 0) { - idesc = intr_create(dev_instance, nextpin, handler, - arg, maskptr, flags); + idesc = intr_create(dev_instance, nextpin, func, arg, + maskptr, 0); error = intr_connect(idesc); if (error != 0) return 0; @@ -355,9 +343,9 @@ pci_freeunit(pcicfgregs *cfg, char *name, int unit) return (unit); } -static const char *drvname; +static char *drvname; -static const char* +static char* pci_probedrv(pcicfgregs *cfg, struct pci_device *dvp) { if (dvp && dvp->pd_probe) { @@ -435,7 +423,6 @@ pci_drvattach(struct pci_devinfo *dinfo) else strncpy(dinfo->conf.pd_name, "????", sizeof(dinfo->conf.pd_name)); - dinfo->conf.pd_name[sizeof(dinfo->conf.pd_name) - 1] = 0; dinfo->conf.pd_unit = unit; @@ -461,7 +448,7 @@ int pci_register_lkm (struct pci_device *dvp, int if_revision) return (-1); } lkm = malloc (sizeof (*lkm), M_DEVBUF, M_WAITOK); - if (lkm == NULL) { + if (lkm != NULL) { return (-1); } diff --git a/sys/pci/pcic_p.c b/sys/pci/pcic_p.c index fd8b40b2ceef..4c667f223d0d 100644 --- a/sys/pci/pcic_p.c +++ b/sys/pci/pcic_p.c @@ -26,7 +26,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: pcic_p.c,v 1.6 1998/08/18 00:32:48 bde Exp $ + * $Id: pcic_p.c,v 1.5 1998/02/07 20:41:20 nate Exp $ */ #include "pci.h" @@ -44,7 +44,7 @@ static u_long pcic_pci_count = 0; -static const char *pcic_pci_probe(pcici_t, pcidi_t); +static char *pcic_pci_probe(pcici_t, pcidi_t); static void pcic_pci_attach(pcici_t, int); static void pd6832_legacy_init(pcici_t tag, int unit); @@ -63,7 +63,7 @@ DATA_SET(pcidevice_set, pcic_pci_driver); * Return the ID string for the controller if the vendor/product id * matches, NULL otherwise. */ -static const char * +static char * pcic_pci_probe(pcici_t tag, pcidi_t type) { switch (type) { diff --git a/sys/pci/pcisupport.c b/sys/pci/pcisupport.c index b502bbf7b864..b78ac652d8b0 100644 --- a/sys/pci/pcisupport.c +++ b/sys/pci/pcisupport.c @@ -1,6 +1,6 @@ /************************************************************************** ** -** $Id: pcisupport.c,v 1.85 1998/12/23 14:28:37 foxfair Exp $ +** $Id: pcisupport.c,v 1.71 1998/07/07 05:00:09 bde Exp $ ** ** Device driver for DEC/INTEL PCI chipsets. ** @@ -42,7 +42,6 @@ */ #include "opt_pci.h" -#include "opt_smp.h" #include <sys/param.h> #include <sys/systm.h> @@ -63,7 +62,7 @@ **--------------------------------------------------------- */ -static const char* chipset_probe (pcici_t tag, pcidi_t type); +static char* chipset_probe (pcici_t tag, pcidi_t type); static void chipset_attach(pcici_t tag, int unit); static u_long chipset_count; @@ -103,12 +102,10 @@ generic_pci_bridge (pcici_t tag) case 5: strcpy(tmpbuf, "PCI to PCMCIA"); break; case 7: strcpy(tmpbuf, "PCI to CardBus"); break; default: - snprintf(tmpbuf, sizeof(tmpbuf), - "PCI to 0x%x", classreg>>16 & 0xff); + sprintf(tmpbuf, "PCI to 0x%x", classreg>>16 & 0xff); break; } - snprintf(tmpbuf+strlen(tmpbuf), sizeof(tmpbuf)-strlen(tmpbuf), - " bridge (vendor=%04x device=%04x)", + sprintf(tmpbuf+strlen(tmpbuf), " bridge (vendor=%04x device=%04x)", id & 0xffff, (id >> 16) & 0xffff); descr = malloc (strlen(tmpbuf) +1, M_DEVBUF, M_WAITOK); strcpy(descr, tmpbuf); @@ -121,7 +118,6 @@ generic_pci_bridge (pcici_t tag) * XXX Both fixbushigh_orion() and fixbushigh_i1225() are bogus in that way, * that they store the highest bus number to scan in this device's config * data, though it is about PCI buses attached to the CPU independently! - * The same goes for fixbushigh_450nx. */ static void @@ -141,68 +137,6 @@ fixbushigh_i1225(pcici_t tag) tag->secondarybus = tag->subordinatebus = sublementarybus +1; } - -/* - * This reads the PCI config space for the 82451NX MIOC in the 450NX - * chipset to determine the PCI bus configuration. - * - * Assuming the BIOS has set up the MIOC properly, this will correctly - * report the number of PCI busses in the system. - * - * A small problem is that the Host to PCI bridge control is in the MIOC, - * while the host-pci bridges are separate PCI devices. So it really - * isn't easily possible to set up the subordinatebus mappings as the - * 82454NX PCI expander bridges are probed, although that makes the - * most sense. - */ -static void -fixbushigh_450nx(pcici_t tag) -{ - int subordinatebus; - unsigned long devmap; - - /* - * Read the DEVMAP field, so we know which fields to check. - * If the Host-PCI bridge isn't marked as present by the BIOS, - * we have to assume it doesn't exist. - * If this doesn't find all the PCI busses, complain to the - * BIOS vendor. There is nothing more we can do. - */ - devmap = pci_cfgread(tag, 0xd6, 2) & 0x3c; - if (!devmap) - panic("450NX MIOC: No host to PCI bridges marked present.\n"); - /* - * Since the buses are configured in order, we just have to - * find the highest bus, and use those numbers. - */ - if (devmap & 0x20) { /* B1 */ - subordinatebus = pci_cfgread(tag, 0xd5, 1); - } else if (devmap & 0x10) { /* A1 */ - subordinatebus = pci_cfgread(tag, 0xd4, 1); - } else if (devmap & 0x8) { /* B0 */ - subordinatebus = pci_cfgread(tag, 0xd2, 1); - } else /* if (devmap & 0x4) */ { /* A0 */ - subordinatebus = pci_cfgread(tag, 0xd1, 1); - } - if (subordinatebus == 255) { - printf("fixbushigh_450nx: bogus highest PCI bus %d", - subordinatebus); -#ifdef NBUS - subordinatebus = NBUS - 2; -#else - subordinatebus = 10; -#endif - printf(", reduced to %d\n", subordinatebus); - } - - if (bootverbose) - printf("fixbushigh_450nx: subordinatebus is %d\n", - subordinatebus); - - tag->secondarybus = tag->subordinatebus = subordinatebus; -} - - static void fixwsc_natoma(pcici_t tag) { @@ -225,7 +159,7 @@ fixwsc_natoma(pcici_t tag) } -static const char* +static char* chipset_probe (pcici_t tag, pcidi_t type) { unsigned rev; @@ -246,6 +180,8 @@ chipset_probe (pcici_t tag, pcidi_t type) return ("Intel 82424ZX (Saturn) cache DRAM controller"); case 0x04828086: return ("Intel 82375EB PCI-EISA bridge"); + case 0x04961039: + return ("SiS 85c496"); case 0x04a38086: rev = (unsigned) pci_conf_read (tag, PCI_CLASS_REG) & 0xff; if (rev == 16 || rev == 17) @@ -264,14 +200,24 @@ chipset_probe (pcici_t tag, pcidi_t type) return ("Intel 82437MX mobile PCI cache memory controller"); case 0x12508086: return ("Intel 82439"); + case 0x04061039: + return ("SiS 85c501"); + case 0x00081039: + return ("SiS 85c503"); + case 0x06011039: + return ("SiS 85c601"); case 0x70008086: return ("Intel 82371SB PCI to ISA bridge"); + case 0x70208086: + return ("Intel 82371SB USB host controller"); case 0x70308086: return ("Intel 82437VX PCI cache memory controller"); case 0x71008086: return ("Intel 82439TX System Controller (MTXC)"); case 0x71108086: return ("Intel 82371AB PCI to ISA bridge"); + case 0x71128086: + return ("Intel 82371AB USB host controller"); case 0x71138086: return ("Intel 82371AB Power management controller"); case 0x71908086: @@ -289,7 +235,6 @@ chipset_probe (pcici_t tag, pcidi_t type) case 0x84c58086: return ("Intel 82453KX/GX (Orion) PCI memory controller"); case 0x84ca8086: - fixbushigh_450nx(tag); return ("Intel 82451NX Memory and I/O Controller"); case 0x84cb8086: return ("Intel 82454NX PCI Expander Bridge"); @@ -299,16 +244,6 @@ chipset_probe (pcici_t tag, pcidi_t type) return ("DEC 21050 PCI-PCI bridge"); case 0x124b8086: return ("Intel 82380FB mobile PCI to PCI bridge"); - /* SiS -- vendor 0x1039 */ - case 0x04961039: - return ("SiS 85c496"); - case 0x04061039: - return ("SiS 85c501"); - case 0x00081039: - return ("SiS 85c503"); - case 0x06011039: - return ("SiS 85c601"); - /* VLSI -- vendor 0x1004 */ case 0x00051004: return ("VLSI 82C592 Host to PCI bridge"); @@ -340,29 +275,10 @@ chipset_probe (pcici_t tag, pcidi_t type) case 0x05971106: return("VIA 82C597 (Apollo VP3) system controller"); /* XXX need info on the MVP3 -- any takers? */ + case 0x30381106: + return("VIA 82C586B USB host controller"); case 0x30401106: return("VIA 82C586B ACPI interface"); - /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */ - /* totally. Please let me know if anything wrong. -F */ - case 0x05981106: - return("VIA 82C598MVP (Apollo MVP3) host bridge"); - case 0x85981106: - return("VIA 82C598MVP (Apollo MVP3) PCI-PCI bridge"); - - /* AcerLabs -- vendor 0x10b9 */ - /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */ - /* id is '10b9" but the register always shows "10b9". -Foxfair */ - case 0x154110b9: - return("AcerLabs M1541 (Aladdin-V) PCI host bridge"); - case 0x153310b9: - return("AcerLabs M1533 portable PCI-ISA bridge"); - case 0x154310b9: - return("AcerLabs M1543 desktop PCI-ISA bridge"); - case 0x524710b9: - return("AcerLabs M5247 PCI-PCI(AGP Supported) bridge"); - case 0x524310b9:/* 5243 seems like 5247, need more info to divide*/ - return("AcerLabs M5243 PCI-PCI bridge"); - /* NEC -- vendor 0x1033 */ case 0x00011033: @@ -931,7 +847,7 @@ chipset_attach (pcici_t config_id, int unit) **--------------------------------------------------------- */ -static const char* vga_probe (pcici_t tag, pcidi_t type); +static char* vga_probe (pcici_t tag, pcidi_t type); static void vga_attach (pcici_t tag, int unit); static u_long vga_count; @@ -945,7 +861,7 @@ static struct pci_device vga_device = { DATA_SET (pcidevice_set, vga_device); -static const char* vga_probe (pcici_t tag, pcidi_t typea) +static char* vga_probe (pcici_t tag, pcidi_t typea) { int data = pci_conf_read(tag, PCI_CLASS_REG); u_int id = pci_conf_read(tag, PCI_ID_REG); @@ -958,7 +874,7 @@ static const char* vga_probe (pcici_t tag, pcidi_t typea) vendor = "NeoMagic"; switch (id >> 16) { case 0x0004: - chip = "NM2160 laptop"; break; + chip = "NM3160 laptop"; break; } break; case 0x102b: @@ -970,7 +886,7 @@ static const char* vga_probe (pcici_t tag, pcidi_t typea) case 0x0519: chip = "MGA 2064W"; break; case 0x051a: - chip = "MGA 1024SG/1064SG/1164SG"; break; + chip = "MGA 1024SG"; break; case 0x051b: chip = "MGA 2164W"; break; } @@ -1171,10 +1087,8 @@ static const char* vga_probe (pcici_t tag, pcidi_t typea) if (vendor && chip) { char *buf; int len; -#if 0 int i; int reqmapmem; -#endif if (type == 0) { type = "SVGA controller"; @@ -1204,8 +1118,7 @@ static const char* vga_probe (pcici_t tag, pcidi_t typea) len = strlen(vendor) + strlen(chip) + strlen(type) + 4; MALLOC(buf, char *, len, M_TEMP, M_NOWAIT); - if (buf) - sprintf(buf, "%s %s %s", vendor, chip, type); + sprintf(buf, "%s %s %s", vendor, chip, type); return buf; } @@ -1224,14 +1137,8 @@ static const char* vga_probe (pcici_t tag, pcidi_t typea) if ((data & PCI_SUBCLASS_MASK) == PCI_SUBCLASS_DISPLAY_VGA) type = "VGA-compatible display device"; - else { - /* - * If it isn't a vga display device, - * don't pretend we found one. - */ + else type = "Display device"; - return 0; - } } break; @@ -1253,8 +1160,7 @@ static const char* vga_probe (pcici_t tag, pcidi_t typea) len = strlen(vendor) + strlen(type) + 2 + 6 + 4 + 1; MALLOC(buf, char *, len, M_TEMP, M_NOWAIT); - if (buf) - sprintf(buf, "%s model %04x %s", vendor, id >> 16, type); + sprintf(buf, "%s model %04x %s", vendor, id >> 16, type); return buf; } return type; @@ -1282,7 +1188,7 @@ static void vga_attach (pcici_t tag, int unit) **--------------------------------------------------------- */ -static const char* lkm_probe (pcici_t tag, pcidi_t type); +static char* lkm_probe (pcici_t tag, pcidi_t type); static void lkm_attach (pcici_t tag, int unit); static u_long lkm_count; @@ -1296,7 +1202,7 @@ static struct pci_device lkm_device = { DATA_SET (pcidevice_set, lkm_device); -static const char* +static char* lkm_probe (pcici_t tag, pcidi_t type) { /* @@ -1317,7 +1223,7 @@ lkm_attach (pcici_t tag, int unit) **--------------------------------------------------------- */ -static const char* ign_probe (pcici_t tag, pcidi_t type); +static char* ign_probe (pcici_t tag, pcidi_t type); static void ign_attach (pcici_t tag, int unit); static u_long ign_count; @@ -1331,7 +1237,7 @@ static struct pci_device ign_device = { DATA_SET (pcidevice_set, ign_device); -static const char* +static char* ign_probe (pcici_t tag, pcidi_t type) { switch (type) { diff --git a/sys/pci/pcivar.h b/sys/pci/pcivar.h index 7843e3a6d656..13e9991eefc3 100644 --- a/sys/pci/pcivar.h +++ b/sys/pci/pcivar.h @@ -23,7 +23,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: pcivar.h,v 1.24 1999/01/13 04:59:19 bde Exp $ + * $Id: pcivar.h,v 1.21 1998/09/15 08:21:09 gibbs Exp $ * */ @@ -66,7 +66,7 @@ typedef struct { #define PCI_MAPPORT 0x04 /* port map */ u_int8_t ln2size; u_int8_t ln2range; - u_int8_t reg; /* offset of map register in config space */ +/* u_int8_t dummy;*/ } pcimap; /* config header information common to all header types */ @@ -199,7 +199,7 @@ extern int pci_mechanism; struct pci_device { char* pd_name; - const char* (*pd_probe ) (pcici_t tag, pcidi_t type); + char* (*pd_probe ) (pcici_t tag, pcidi_t type); void (*pd_attach) (pcici_t tag, int unit); u_long *pd_count; int (*pd_shutdown) (int, int); @@ -223,10 +223,7 @@ int pci_map_port (pcici_t tag, u_long reg, pci_port_t* pa); int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa); int pci_map_dense (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa); int pci_map_bwx (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa); -int pci_map_int (pcici_t tag, pci_inthand_t *handler, void *arg, - intrmask_t *maskptr); -int pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg, - intrmask_t *maskptr, u_int flags); +int pci_map_int (pcici_t tag, pci_inthand_t *func, void *arg, unsigned *maskptr); int pci_unmap_int (pcici_t tag); int pci_register_lkm (struct pci_device *dvp, int if_revision); diff --git a/sys/pci/simos.c b/sys/pci/simos.c index 85642b814b3f..0be0397f52e2 100644 --- a/sys/pci/simos.c +++ b/sys/pci/simos.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: simos.c,v 1.2 1998/09/26 14:49:26 dfr Exp $ + * $Id: simos.c,v 1.1 1998/06/10 10:57:14 dfr Exp $ */ #include <sys/param.h> @@ -70,7 +70,7 @@ struct simos_softc* simosp[10]; static u_long simos_unit; -static const char *simos_probe __P((pcici_t tag, pcidi_t type)); +static char *simos_probe __P((pcici_t tag, pcidi_t type)); static void simos_attach __P((pcici_t config_d, int unit)); static void simos_action __P((struct cam_sim *sim, union ccb *ccb)); static void simos_poll __P((struct cam_sim *sim)); @@ -84,7 +84,7 @@ struct pci_device simos_driver = { }; DATA_SET (pcidevice_set, simos_driver); -static const char * +static char * simos_probe(pcici_t tag, pcidi_t type) { switch (type) { diff --git a/sys/pci/if_txvar.h b/sys/pci/smc83c170.h index efa282c247aa..737eac398c6e 100644 --- a/sys/pci/if_txvar.h +++ b/sys/pci/smc83c170.h @@ -1,6 +1,3 @@ -/* $OpenBSD: if_txvar.h,v 1.3 1998/10/10 04:30:09 jason Exp $ */ -/* $Id: if_txvar.h,v 1.3 1998/10/10 04:30:09 jason Exp $ */ - /*- * Copyright (c) 1997 Semen Ustimenko * All rights reserved. @@ -26,26 +23,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id: smc83c170.h,v 1.14 1998/07/03 23:59:09 galv Exp $ * */ /* * Configuration */ -#ifndef ETHER_MAX_LEN -#define ETHER_MAX_LEN 1518 -#endif -#ifndef ETHER_MIN_LEN -#define ETHER_MIN_LEN 64 -#endif -#ifndef ETHER_CRC_LEN -#define ETHER_CRC_LEN 4 -#endif -#define TX_RING_SIZE 16 /* Leave this a power of 2 */ -#define RX_RING_SIZE 16 /* And this too, to do not */ - /* confuse RX(TX)_RING_MASK */ -#define TX_RING_MASK (TX_RING_SIZE - 1) -#define RX_RING_MASK (RX_RING_SIZE - 1) +#define TX_RING_SIZE 8 +#define RX_RING_SIZE 8 #define EPIC_FULL_DUPLEX 1 #define EPIC_HALF_DUPLEX 0 #define ETHER_MAX_FRAME_LEN (ETHER_MAX_LEN + ETHER_CRC_LEN) @@ -192,9 +178,12 @@ #define TXCON_FULL_DUPLEX 0x00000006 #define TXCON_SLOT_TIME 0x00000078 -#define TXCON_DEFAULT (TXCON_SLOT_TIME | TXCON_EARLY_TRANSMIT_ENABLE) -#define TRANSMIT_THRESHOLD 0x80 - +#if defined(EARLY_TX) + #define TXCON_DEFAULT (TXCON_SLOT_TIME | TXCON_EARLY_TRANSMIT_ENABLE) + #define TRANSMIT_THRESHOLD 0x40 +#else + #define TXCON_DEFAULT (TXCON_SLOT_TIME) +#endif #if defined(EARLY_RX) #define RXCON_DEFAULT (RXCON_EARLY_RECEIVE_ENABLE | RXCON_SAVE_ERRORED_PACKETS) #else @@ -288,13 +277,12 @@ struct epic_rx_desc { /* This structure defines EPIC's fragment list, maximum number of frags */ /* is 63. Let use maximum, becouse size of struct MUST be divisor of */ /* PAGE_SIZE, and sometimes come mbufs with more then 30 frags */ -#define EPIC_MAX_FRAGS 63 struct epic_frag_list { volatile u_int32_t numfrags; struct { volatile u_int32_t fragaddr; volatile u_int32_t fraglen; - } frag[EPIC_MAX_FRAGS]; + } frag[63]; volatile u_int32_t pad; /* align on 256 bytes */ }; @@ -314,22 +302,6 @@ struct epic_tx_buffer { /* Driver status structure */ typedef struct { -#if defined(__OpenBSD__) - struct device sc_dev; - void *sc_ih; - bus_space_tag_t sc_st; - bus_space_handle_t sc_sh; -#else /* __FreeBSD__ */ -#if defined(EPIC_USEIOSPACE) - u_int32_t iobase; -#else - caddr_t csr; -#endif -#endif -#if !defined(EPIC_NOIFMEDIA) - struct ifmedia ifmedia; -#endif - struct arpcom arpcom; u_int32_t unit; struct epic_rx_buffer rx_buffer[RX_RING_SIZE]; struct epic_tx_buffer tx_buffer[TX_RING_SIZE]; @@ -339,68 +311,79 @@ typedef struct { struct epic_rx_desc *rx_desc; struct epic_tx_desc *tx_desc; struct epic_frag_list *tx_flist; +#if defined(_NET_IF_MEDIA_H_) + struct ifmedia ifmedia; +#endif + struct arpcom epic_ac; u_int32_t flags; - u_int32_t tx_threshold; - u_int32_t txcon; u_int32_t phyid; u_int32_t cur_tx; u_int32_t cur_rx; u_int32_t dirty_tx; u_int32_t pending_txs; - void *pool; +#if defined(EPIC_USEIOSPACE) + u_int32_t iobase; +#else + caddr_t csr; +#endif } epic_softc_t; -#if defined(__FreeBSD__) -#define EPIC_FORMAT "tx%d" -#define EPIC_ARGS(sc) (sc->unit) -#define sc_if arpcom.ac_if -#define sc_macaddr arpcom.ac_enaddr +#define epic_if epic_ac.ac_if +#define epic_macaddr epic_ac.ac_enaddr #if defined(EPIC_USEIOSPACE) -#define CSR_WRITE_4(sc,reg,val) \ - outl( (sc)->iobase + (u_int32_t)(reg), (val) ) -#define CSR_WRITE_2(sc,reg,val) \ - outw( (sc)->iobase + (u_int32_t)(reg), (val) ) -#define CSR_WRITE_1(sc,reg,val) \ - outb( (sc)->iobase + (u_int32_t)(reg), (val) ) -#define CSR_READ_4(sc,reg) \ - inl( (sc)->iobase + (u_int32_t)(reg) ) -#define CSR_READ_2(sc,reg) \ - inw( (sc)->iobase + (u_int32_t)(reg) ) -#define CSR_READ_1(sc,reg) \ - inb( (sc)->iobase + (u_int32_t)(reg) ) + #define CSR_WRITE_4(sc,reg,val) outl( (sc)->iobase + (u_int32_t)(reg), (val) ) + #define CSR_WRITE_2(sc,reg,val) outw( (sc)->iobase + (u_int32_t)(reg), (val) ) + #define CSR_WRITE_1(sc,reg,val) outb( (sc)->iobase + (u_int32_t)(reg), (val) ) + #define CSR_READ_4(sc,reg) inl( (sc)->iobase + (u_int32_t)(reg) ) + #define CSR_READ_2(sc,reg) inw( (sc)->iobase + (u_int32_t)(reg) ) + #define CSR_READ_1(sc,reg) inb( (sc)->iobase + (u_int32_t)(reg) ) #else -#define CSR_WRITE_1(sc,reg,val) \ - ((*(u_int8_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int8_t)(val)) -#define CSR_WRITE_2(sc,reg,val) \ - ((*(u_int16_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int16_t)(val)) -#define CSR_WRITE_4(sc,reg,val) \ - ((*(u_int32_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int32_t)(val)) -#define CSR_READ_1(sc,reg) \ - (*(u_int8_t*)((sc)->csr + (u_int32_t)(reg))) -#define CSR_READ_2(sc,reg) \ - (*(u_int16_t*)((sc)->csr + (u_int32_t)(reg))) -#define CSR_READ_4(sc,reg) \ - (*(u_int32_t*)((sc)->csr + (u_int32_t)(reg))) -#endif -#else /* __OpenBSD__ */ -#define EPIC_FORMAT "%s" -#define EPIC_ARGS(sc) (sc->sc_dev.dv_xname) -#define sc_if arpcom.ac_if -#define sc_macaddr arpcom.ac_enaddr -#define CSR_WRITE_4(sc,reg,val) \ - bus_space_write_4( (sc)->sc_st, (sc)->sc_sh, (reg), (val) ) -#define CSR_WRITE_2(sc,reg,val) \ - bus_space_write_2( (sc)->sc_st, (sc)->sc_sh, (reg), (val) ) -#define CSR_WRITE_1(sc,reg,val) \ - bus_space_write_1( (sc)->sc_st, (sc)->sc_sh, (reg), (val) ) -#define CSR_READ_4(sc,reg) \ - bus_space_read_4( (sc)->sc_st, (sc)->sc_sh, (reg) ) -#define CSR_READ_2(sc,reg) \ - bus_space_read_2( (sc)->sc_st, (sc)->sc_sh, (reg) ) -#define CSR_READ_1(sc,reg) \ - bus_space_read_1( (sc)->sc_st, (sc)->sc_sh, (reg) ) + #define CSR_WRITE_1(sc,reg,val) ((*(u_int8_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int8_t)(val)) + #define CSR_WRITE_2(sc,reg,val) ((*(u_int16_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int16_t)(val)) + #define CSR_WRITE_4(sc,reg,val) ((*(u_int32_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int32_t)(val)) + #define CSR_READ_1(sc,reg) (*(u_int8_t*)((sc)->csr + (u_int32_t)(reg))) + #define CSR_READ_2(sc,reg) (*(u_int16_t*)((sc)->csr + (u_int32_t)(reg))) + #define CSR_READ_4(sc,reg) (*(u_int32_t*)((sc)->csr + (u_int32_t)(reg))) #endif - #define PHY_READ_2(sc,reg) epic_read_phy_register(sc,reg) #define PHY_WRITE_2(sc,reg,val) epic_write_phy_register(sc,reg,val) +static char* epic_pci_probe __P((pcici_t, pcidi_t)); + +/* Folowing functions calls splimp() */ +static int epic_ifioctl __P((register struct ifnet *, u_long, caddr_t)); +static void epic_ifstart __P((struct ifnet *)); +static void epic_ifwatchdog __P((struct ifnet *)); +static void epic_pci_attach __P((pcici_t, int)); +static int epic_init __P((epic_softc_t *)); +static void epic_stop __P((epic_softc_t *)); + +static int epic_ifmedia_change __P((struct ifnet *)); +static void epic_ifmedia_status __P((struct ifnet *, struct ifmediareq *)); + +/* Following functions doesn't call splimp() */ +static void epic_intr_normal __P((void *)); +static __inline void epic_rx_done __P((epic_softc_t *)); +static __inline void epic_tx_done __P((epic_softc_t *)); +static void epic_shutdown __P((int, void *)); + +static int epic_init_rings __P((epic_softc_t *)); +static void epic_free_rings __P((epic_softc_t *)); +static void epic_stop_activity __P((epic_softc_t *)); +static void epic_start_activity __P((epic_softc_t *)); +static void epic_set_rx_mode __P((epic_softc_t *)); +static void epic_set_mc_table __P((epic_softc_t *)); +static void epic_set_media_speed __P((epic_softc_t *)); +static void epic_init_phy __P((epic_softc_t *)); +static void epic_dump_state __P((epic_softc_t *)); +static int epic_autoneg __P((epic_softc_t *)); + +static int epic_read_eeprom __P((epic_softc_t *,u_int16_t)); +static void epic_output_eepromw __P((epic_softc_t *, u_int16_t)); +static u_int16_t epic_input_eepromw __P((epic_softc_t *)); +static u_int8_t epic_eeprom_clock __P((epic_softc_t *,u_int8_t)); +static void epic_write_eepromreg __P((epic_softc_t *,u_int8_t)); +static u_int8_t epic_read_eepromreg __P((epic_softc_t *)); + +static u_int16_t epic_read_phy_register __P((epic_softc_t *, u_int16_t)); +static void epic_write_phy_register __P((epic_softc_t *, u_int16_t, u_int16_t)); diff --git a/sys/pci/tek390.c b/sys/pci/tek390.c new file mode 100644 index 000000000000..9be42e23bba1 --- /dev/null +++ b/sys/pci/tek390.c @@ -0,0 +1,1709 @@ +/*********************************************************************** + * FILE NAME : TEK390.C * + * BY : C.L. Huang (ching@tekram.com.tw) * + * Description: Device Driver for Tekram DC-390(T) PCI SCSI * + * Bus Master Host Adapter * + * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. * + ***********************************************************************/ +/*********************************************************************** + * HISTORY: * + * * + * REV# DATE NAME DESCRIPTION * + * 1.00 07/02/96 CLH First release for RELEASE-2.1.0 * + * 1.01 08/20/96 CLH Update for RELEASE-2.1.5 * + * * + ***********************************************************************/ + +/************************************************************************** + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/**************************************************************************/ +/* Imported into FreeBSD source repository, and updated to compile under */ +/* FreeBSD-3.0-DEVELOPMENT, by Stefan Esser <se@FreeBSD.Org>, 1996-12-17 */ +/**************************************************************************/ + +/* #define REL_2_1_0 */ +#define REL_2_1_5 + +#define DC390_DEBUG + +#include <sys/param.h> + +/* XXX this doesn't actually compile unless KERNEL is defined. */ +#ifdef KERNEL +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/kernel.h> + +#include <vm/vm.h> +#include <vm/pmap.h> +#endif /* KERNEL */ + +#include <pci/pcivar.h> +#include <pci/pcireg.h> + +#include <scsi/scsiconf.h> + +#include <machine/clock.h> + +#include <pci/tek390.h> + +#define INT32 int32 +#define U_INT32 u_int32 + + +#define OutB(val, port) outb(port, val) +#define OutW(val, port) outw(port, val) +#define OutL(val, port) outl(port, val) + +#define PCI_DEVICE_ID_AMD53C974 0x20201022ul +#define PCI_BASE_ADDR0 0x10 + + +#ifdef REL_2_1_0 +static int DC390_Interrupt (PACB pACB); +#endif +#ifdef REL_2_1_5 +static void DC390_Interrupt (PACB pACB); +#endif +static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus); + +static void SetXferRate( PACB pACB, PDCB pDCB ); +static void DC390_Disconnect( PACB pACB ); +static void DC390_Reselect( PACB pACB ); +static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void DoingSRB_Done( PACB pACB ); +static void DC390_ScsiRstDetect( PACB pACB ); +static void DC390_ResetSCSIBus( PACB pACB ); +static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void EnableMsgOut2( PACB pACB, PSRB pSRB ); +static void EnableMsgOut( PACB pACB, PSRB pSRB ); +static void DC390_InvalidCmd( PACB pACB ); + +/* + * XXX No timeouts are scheduled in this driver as the timeout handler + * doesn't do anything yet!!! + */ +static void DC390_reset (PACB pACB); +static PUCHAR phystovirt( PSRB pSRB, ULONG xferCnt ); + +static void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ); +static void DC390_initSRB( PSRB psrb ); +static void DC390_linkSRB( PACB pACB ); +static void DC390_initACB( PACB pACB, ULONG io_port, UCHAR Irq, + USHORT index ); +static int DC390_initAdapter( PACB pACB, ULONG io_port, UCHAR Irq, + USHORT index, pcici_t config_id ); +void DC390_EnableCfg( USHORT mechnum, UCHAR regval ); +void DC390_DisableCfg( USHORT mechnum ); +UCHAR DC390_inByte( USHORT mechnum, UCHAR regval ); +USHORT DC390_inWord( USHORT mechnum, UCHAR regval ); +ULONG DC390_inDword(USHORT mechnum, UCHAR regval ); +void DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval ); +static void DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval ); +static void DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry ); +static UCHAR DC390_EEpromInDO( USHORT mechnum ); +static USHORT EEpromGetData1( USHORT mechnum ); +static void DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd ); +static void DC390_ReadEEprom( USHORT mechnum, USHORT index ); +static USHORT DC390_DefaultEEprom( USHORT mechnum, USHORT index ); +static USHORT DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index ); +static USHORT DC390_ToMech( USHORT Mechnum, pcici_t config_id ); + + +#ifdef KERNEL + +static char* trmamd_probe( pcici_t tag, pcidi_t type); +static void trmamd_attach( pcici_t tag, int unit); + +#ifdef REL_2_1_0 +static int32 trmamd_scsi_cmd( struct scsi_xfer *sx); +#endif + +#ifdef REL_2_1_5 +static int32_t trmamd_scsi_cmd( struct scsi_xfer *sx); +#endif + +static void trmamd_min_phys( struct buf *pbuf); + +#ifdef REL_2_1_0 +static u_int32 trmamd_info( int unit ); +#endif + +#endif /* KERNEL */ + + +static u_long trmamd_count; + +static struct pci_device trmamd_device = { + "amd", + trmamd_probe, + trmamd_attach, + &trmamd_count, + NULL +}; + +DATA_SET (pcidevice_set, trmamd_device); + + + +static struct scsi_adapter trmamd_switch = +{ + trmamd_scsi_cmd, + trmamd_min_phys, + 0, + 0, +#ifdef REL_2_1_0 + trmamd_info, +#endif +#ifdef REL_2_1_5 + 0, +#endif + "amd", +}; + +static struct scsi_device trmamd_dev = +{ + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "amd", +}; + + +static PACB pACB0[MAX_ADAPTER_NUM]={0}; +static PACB pACB_start= NULL; +static PACB pACB_current = NULL; +static PDCB pPrevDCB = NULL; +static USHORT adapterCnt = 0; +static USHORT CurrSyncOffset = 0; +static UCHAR CurrentID, CurrentLUN; + +static PVOID DC390_phase0[]={ + DC390_DataOut_0, + DC390_DataIn_0, + DC390_Command_0, + DC390_Status_0, + DC390_Nop_0, + DC390_Nop_0, + DC390_MsgOut_0, + DC390_MsgIn_0, + DC390_Nop_1 + }; + +static PVOID DC390_phase1[]={ + DC390_DataOutPhase, + DC390_DataInPhase, + DC390_CommandPhase, + DC390_StatusPhase, + DC390_Nop_0, + DC390_Nop_0, + DC390_MsgOutPhase, + DC390_MsgInPhase, + DC390_Nop_1, + }; + +static UCHAR eepromBuf[MAX_ADAPTER_NUM][128]; + + +static UCHAR clock_period1[] = {4, 5, 6, 7 ,8, 10, 13, 20}; + +static UCHAR baddevname1[2][28] ={ + "SEAGATE ST3390N ??? 9546", + "HP C3323-300 4269"}; + +#define BADDEVCNT 2 + + +/*********************************************************************** + * + * + * + **********************************************************************/ +static PSRB +GetSRB( PACB pACB ) +{ + int flags; + PSRB pSRB; + + flags = splbio(); + + pSRB = pACB->pFreeSRB; + if( pSRB ) + { + pACB->pFreeSRB = pSRB->pNextSRB; + pSRB->pNextSRB = NULL; + } + splx(flags); + return( pSRB ); +} + + +static void +RewaitSRB0( PDCB pDCB, PSRB pSRB ) +{ + PSRB psrb1; + int flags; + + flags = splbio(); + + if( (psrb1 = pDCB->pWaitingSRB) ) + { + pSRB->pNextSRB = psrb1; + pDCB->pWaitingSRB = pSRB; + } + else + { + pSRB->pNextSRB = NULL; + pDCB->pWaitingSRB = pSRB; + pDCB->pWaitLast = pSRB; + } + splx(flags); +} + + +static void +RewaitSRB( PDCB pDCB, PSRB pSRB ) +{ + PSRB psrb1; + int flags; + UCHAR bval; + + flags = splbio(); + + pDCB->GoingSRBCnt--; + psrb1 = pDCB->pGoingSRB; + if( pSRB == psrb1 ) + { + pDCB->pGoingSRB = psrb1->pNextSRB; + } + else + { + while( pSRB != psrb1->pNextSRB ) + psrb1 = psrb1->pNextSRB; + psrb1->pNextSRB = pSRB->pNextSRB; + if( pSRB == pDCB->pGoingLast ) + pDCB->pGoingLast = psrb1; + } + if( (psrb1 = pDCB->pWaitingSRB) ) + { + pSRB->pNextSRB = psrb1; + pDCB->pWaitingSRB = pSRB; + } + else + { + pSRB->pNextSRB = NULL; + pDCB->pWaitingSRB = pSRB; + pDCB->pWaitLast = pSRB; + } + + bval = pSRB->TagNumber; + pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */ + splx(flags); +} + + +static void +DoWaitingSRB( PACB pACB ) +{ + int flags; + PDCB ptr, ptr1; + PSRB pSRB; + + flags = splbio(); + + if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) + { + ptr = pACB->pDCBRunRobin; + if( !ptr ) + { + ptr = pACB->pLinkDCB; + pACB->pDCBRunRobin = ptr; + } + ptr1 = ptr; + for( ;ptr1; ) + { + pACB->pDCBRunRobin = ptr1->pNextDCB; + if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) || + !( pSRB = ptr1->pWaitingSRB ) ) + { + if(pACB->pDCBRunRobin == ptr) + break; + ptr1 = ptr1->pNextDCB; + } + else + { + if( !DC390_StartSCSI(pACB, ptr1, pSRB) ) + { + ptr1->GoingSRBCnt++; + if( ptr1->pWaitLast == pSRB ) + { + ptr1->pWaitingSRB = NULL; + ptr1->pWaitLast = NULL; + } + else + { + ptr1->pWaitingSRB = pSRB->pNextSRB; + } + pSRB->pNextSRB = NULL; + + if( ptr1->pGoingSRB ) + ptr1->pGoingLast->pNextSRB = pSRB; + else + ptr1->pGoingSRB = pSRB; + ptr1->pGoingLast = pSRB; + } + break; + } + } + } + splx(flags); + return; +} + + +static void +SRBwaiting( PDCB pDCB, PSRB pSRB) +{ + if( pDCB->pWaitingSRB ) + { + pDCB->pWaitLast->pNextSRB = pSRB; + pDCB->pWaitLast = pSRB; + pSRB->pNextSRB = NULL; + } + else + { + pDCB->pWaitingSRB = pSRB; + pDCB->pWaitLast = pSRB; + } +} + + +static void +SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB ) +{ + int flags; + PDCB pDCB; + + flags = splbio(); + + pDCB = pSRB->pSRBDCB; + if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || + (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) + { + SRBwaiting(pDCB, pSRB); + goto SND_EXIT; + } + + if( pDCB->pWaitingSRB ) + { + SRBwaiting(pDCB, pSRB); +/* pSRB = GetWaitingSRB(pDCB); */ + pSRB = pDCB->pWaitingSRB; + pDCB->pWaitingSRB = pSRB->pNextSRB; + pSRB->pNextSRB = NULL; + } + + if( !DC390_StartSCSI(pACB, pDCB, pSRB) ) + { + pDCB->GoingSRBCnt++; + if( pDCB->pGoingSRB ) + { + pDCB->pGoingLast->pNextSRB = pSRB; + pDCB->pGoingLast = pSRB; + } + else + { + pDCB->pGoingSRB = pSRB; + pDCB->pGoingLast = pSRB; + } + } + else + RewaitSRB0( pDCB, pSRB ); + +SND_EXIT: + splx(flags); + return; +} + + +/*********************************************************************** + * Function : static int32 dc390_scsi_cmd (struct scsi_xfer *cmd) + * Purpose : enqueues a SCSI command + ***********************************************************************/ + +#ifdef REL_2_1_0 +int32 +#endif +#ifdef REL_2_1_5 +int32_t +#endif +trmamd_scsi_cmd ( PSCSICMD cmd ) +{ + USHORT ioport, i; + PSCSICMD pcmd; + PSCLINK plink; + PACB pACB; + PDCB pDCB; + PSRB pSRB; + int flags, cflags, unit, CurrPgVaddr; + ULONG sglen, pglen, datalen, CurrPgPaddr, NextPgPaddr; + PUCHAR ptr,ptr1; + PSEG psg; + UCHAR sgc, sstatus; + + plink = cmd->sc_link; + unit = plink->adapter_unit; + pACB = pACB0[unit]; + ioport = pACB->IOPortBase; + +#ifdef DC390_DEBUG0 + printf("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmd->opcode, + plink->target, plink->lun); +#endif + + if( pACB->scan_devices ) + { + if( (plink->target > CurrentID) || + (plink->target == CurrentID) && (plink->lun >= CurrentLUN) ) + { + CurrentID = plink->target; + CurrentLUN = plink->lun; + } + else + { + pACB->scan_devices = 0; + pPrevDCB->pNextDCB = pACB->pLinkDCB; + } + } + + if ( ( plink->target > pACB->max_id ) || ( plink->lun > pACB->max_lun ) ) + { +#ifdef DC390_DEBUG0 + printf("DC390: Ignore target %d lun %d\n", + plink->target, plink->lun); +#endif + cmd->error = XS_DRIVER_STUFFUP; + return( COMPLETE ); + } + + if( (pACB->scan_devices) && !(pACB->DCBmap[plink->target] & (1 << plink->lun)) ) + { + if( pACB->DeviceCnt < MAX_DEVICES ) + { + pACB->DCBmap[plink->target] |= (1 << plink->lun); + pDCB = pACB->pDCB_free; +#ifdef DC390_DEBUG0 + printf("pDCB=%8x,ID=%2x,", (UINT) pDCB, plink->target); +#endif + DC390_initDCB( pACB, pDCB, cmd ); + } + else /* ???? */ + { +#ifdef DC390_DEBUG0 + printf("DC390: Ignore target %d lun %d\n", + plink->target, plink->lun); +#endif + cmd->error = XS_DRIVER_STUFFUP; + return( COMPLETE ); + } + } + else if( !(pACB->scan_devices) && !(pACB->DCBmap[plink->target] & (1 << plink->lun)) ) + { +#ifdef DC390_DEBUG0 + printf("DC390: Ignore target %d lun %d\n", + plink->target, plink->lun); +#endif + cmd->error = XS_DRIVER_STUFFUP; + return( COMPLETE ); + } + else + { + pDCB = pACB->pLinkDCB; + while( (pDCB->UnitSCSIID != plink->target) || + (pDCB->UnitSCSILUN != plink->lun) ) + { + pDCB = pDCB->pNextDCB; + } +#ifdef DC390_DEBUG0 + printf("pDCB=%8x,ID=%2x,", (UINT) pDCB, plink->target); +#endif + } + + cflags = cmd->flags; + if(cflags & SCSI_RESET) + { + DC390_reset (pACB); + cmd->error = XS_NOERROR; + return(COMPLETE); + } + + if( cflags & ITSDONE ) + { + printf("DC390: Is it done?\n"); + cmd->flags &= ~ITSDONE; + } + if( !(cflags & INUSE) ) + { + printf("DC390: In Use?\n"); + cmd->flags |= INUSE; + } + + cmd->error = 0; + cmd->resid = 0; + + flags = splbio(); + + pcmd = cmd; + + pSRB = GetSRB( pACB ); + + if( !pSRB ) + { + pcmd->error = XS_DRIVER_STUFFUP; + splx(flags); + return( TRY_AGAIN_LATER); + } + +/* BuildSRB(pSRB); */ + + pSRB->pSRBDCB = pDCB; + pSRB->pcmd = pcmd; + ptr = (PUCHAR) pSRB->CmdBlock; + ptr1 = (PUCHAR) pcmd->cmd; + pSRB->ScsiCmdLen = pcmd->cmdlen; + for(i=0; i< pcmd->cmdlen; i++) + { + *ptr = *ptr1; + ptr++; + ptr1++; + } + if( pcmd->datalen ) + { + psg = (PSEG) &pSRB->SGsegment[0]; + pSRB->pSegmentList = psg; + sgc = 0; + + /* Set up the scatter gather list */ + datalen = pcmd->datalen; + CurrPgVaddr = (int) pcmd->data; + CurrPgPaddr = vtophys(CurrPgVaddr); + + while ((datalen) && (sgc < MAX_SG_ENTRY)) + { + sglen = 0; + psg->SGXPtr = CurrPgPaddr; + NextPgPaddr = CurrPgPaddr; + while ((datalen) && (CurrPgPaddr == NextPgPaddr)) + { + /* + * This page is contiguous (physically) with the the last, + * just extend the length + */ + + NextPgPaddr = (CurrPgPaddr & (~(PAGELEN - 1))) + PAGELEN; + pglen = NextPgPaddr - CurrPgPaddr; + + if( datalen < pglen ) + pglen = datalen; + sglen += pglen; + datalen -= pglen; + CurrPgVaddr = (CurrPgVaddr & (~(PAGELEN - 1))) + PAGELEN; + if( datalen ) + CurrPgPaddr = vtophys(CurrPgVaddr); + } + /* + next page isn't contiguous, finish this segment + */ + psg->SGXLen = sglen; + psg++; + sgc++; + } + pSRB->SGcount = sgc; + + if (datalen) + { + printf("DC390: Out Of Segment Buffer!\n"); + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + pcmd->error = XS_DRIVER_STUFFUP; + splx(flags); + return (HAD_ERROR); + } + } + else + pSRB->SGcount = 0; + + pSRB->SGIndex = 0; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + pSRB->MsgCnt = 0; + if( pDCB->DevType != SCSI_SEQACESS ) + pSRB->RetryCnt = 1; + else + pSRB->RetryCnt = 0; + pSRB->SRBStatus = 0; + pSRB->SRBFlag = 0; + pSRB->SRBState = 0; + pSRB->TotalXferredLen = 0; + pSRB->SGPhysAddr = 0; + pSRB->SGToBeXferLen = 0; + pSRB->ScsiPhase = 0; + pSRB->EndMessage = 0; + splx(flags); + + if( !(cflags & SCSI_NOMASK) ) + { + flags = splbio(); + SendSRB( pcmd, pACB, pSRB ); + splx(flags); + return( SUCCESSFULLY_QUEUED); + } + else + { + SendSRB( pcmd, pACB, pSRB ); + do + { + while(--pcmd->timeout) + { + DELAY(1000); + sstatus = inb( ioport+Scsi_Status ); + if( sstatus & INTERRUPT ) + break; + } + if( pcmd->timeout == 0 ) + { + return(HAD_ERROR); + } + else + { + DC390_Interrupt( pACB ); + } + } + while( !(pcmd->flags & ITSDONE) ); + if( pcmd->error == XS_TIMEOUT) + return(HAD_ERROR); + else + return(COMPLETE); + } +} + + +void +trmamd_min_phys( struct buf *bp ) +{ + if (bp->b_bcount > ((MAX_SG_ENTRY - 1) * PAGELEN)) + bp->b_bcount = ((MAX_SG_ENTRY - 1) * PAGELEN); +} + + +#ifdef REL_2_1_0 +u_int32 +trmamd_info( int unit ) +{ + return (MAX_CMD_PER_LUN); /* outstanding requests at a time per device */ +} +#endif + + +static PUCHAR phystovirt( PSRB pSRB, ULONG xferCnt ) +{ + int dataPtr; + PSCSICMD pcmd; + UCHAR i; + PSEG pseg; + + pcmd = pSRB->pcmd; + dataPtr = (int) pcmd->data; + pseg = pSRB->SGsegment; + for(i=0; i < pSRB->SGIndex; i++) + { + dataPtr += (int) pseg->SGXLen; + pseg++; + } + dataPtr += (int) xferCnt; + return( (PUCHAR) dataPtr); +} + + +/*********************************************************************** + * Function : int DC390_abort (SCSICMD *cmd) + * + * Purpose : Abort an errant SCSI command + * + * Inputs : cmd - command to abort + * + * Returns : 0 on success, -1 on failure. + ***********************************************************************/ +/* +int +DC390_abort (SCSICMD *cmd) +{ + int flags; + PACB pACB; + PDCB pDCB, pdcb; + PSRB pSRB, psrb; + USHORT count, i; + PSCSICMD pcmd, pcmd1; + int status; + + +#ifdef DC390_DEBUG0 + printf("DC390 : Abort Cmd."); +#endif + + flags = splbio(); + + pACB = (PACB) cmd->host->hostdata; + pDCB = pACB->pLinkDCB; + pdcb = pDCB; + while( (pDCB->UnitSCSIID != cmd->sc_link->target) || + (pDCB->UnitSCSILUN != cmd->sc_link->lun) ) + { + pDCB = pDCB->pNextDCB; + if( pDCB == pdcb ) + goto NOT_RUN; + } + + + pSRB = pDCB->pWaitingSRB; + if( !pSRB ) + goto ON_GOING; + if( pSRB->pcmd == cmd ) + { + pDCB->pWaitingSRB = pSRB->pNextSRB; + goto IN_WAIT; + } + else + { + psrb = pSRB; + while( psrb->pNextSRB->pcmd != cmd ) + { + psrb = psrb->pNextSRB; + if( !psrb ) + goto ON_GOING; + } + pSRB = psrb->pNextSRB; + psrb->pNextSRB = pSRB->pNextSRB; + if( pSRB == pDCB->pWaitLast ) + pDCB->pWaitLast = psrb; +IN_WAIT: + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + cmd->next = NULL; + status = SCSI_ABORT_SUCCESS; + goto ABO_X; + } + +ON_GOING: + pSRB = pDCB->pGoingSRB; + for( count = pDCB->GoingSRBCnt, i=0; i<count; i++) + { + if( pSRB->pcmd != cmd ) + pSRB = pSRB->pNextSRB; + else + { + if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) ) + { + status = SCSI_ABORT_BUSY; + goto ABO_X; + } + else + { + status = SCSI_ABORT_SNOOZE; + goto ABO_X; + } + } + } + +NOT_RUN: + status = SCSI_ABORT_NOT_RUNNING; + +ABO_X: + cmd->error = XS_NOERROR; + scsi_done(cmd); + splx(flags); + return( status ); +} +*/ + +static void +ResetDevParam( PACB pACB ) +{ + PDCB pDCB, pdcb; + + pDCB = pACB->pLinkDCB; + if( pDCB == NULL ) + return; + pdcb = pDCB; + do + { + pDCB->SyncMode &= ~SYNC_NEGO_DONE; + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + pDCB->CtrlR3 = FAST_CLK; + pDCB->CtrlR4 &= NEGATE_REQACKDATA; + pDCB->CtrlR4 |= EATER_25NS; + pDCB = pDCB->pNextDCB; + } + while( pdcb != pDCB ); +} + + +static void +RecoverSRB( PACB pACB ) +{ + PDCB pDCB, pdcb; + PSRB psrb, psrb2; + USHORT cnt, i; + + pDCB = pACB->pLinkDCB; + if( pDCB == NULL ) + return; + pdcb = pDCB; + do + { + cnt = pdcb->GoingSRBCnt; + psrb = pdcb->pGoingSRB; + for (i=0; i<cnt; i++) + { + psrb2 = psrb; + psrb = psrb->pNextSRB; +/* RewaitSRB( pDCB, psrb ); */ + if( pdcb->pWaitingSRB ) + { + psrb2->pNextSRB = pdcb->pWaitingSRB; + pdcb->pWaitingSRB = psrb2; + } + else + { + pdcb->pWaitingSRB = psrb2; + pdcb->pWaitLast = psrb2; + psrb2->pNextSRB = NULL; + } + } + pdcb->GoingSRBCnt = 0; + pdcb->pGoingSRB = NULL; + pdcb->TagMask = 0; + pdcb = pdcb->pNextDCB; + } + while( pdcb != pDCB ); +} + + +/*********************************************************************** + * Function : DC390_reset (PACB pACB) + * + * Purpose : perform a hard reset on the SCSI bus( and AMD chip). + * + * Inputs : cmd - command which caused the SCSI RESET + * + ***********************************************************************/ + +static void +DC390_reset (PACB pACB) +{ + USHORT ioport; + int flags; + UCHAR bval; + USHORT i; + + +#ifdef DC390_DEBUG0 + printf("DC390: RESET,"); +#endif + + flags = splbio(); + + ioport = pACB->IOPortBase; + bval = inb(ioport+CtrlReg1); + bval |= DIS_INT_ON_SCSI_RST; + OutB(bval,ioport+CtrlReg1); /* disable interrupt */ + DC390_ResetSCSIBus( pACB ); + for( i=0; i<500; i++ ) + DELAY(1000); + bval = inb(ioport+CtrlReg1); + bval &= ~DIS_INT_ON_SCSI_RST; + OutB(bval,ioport+CtrlReg1); /* re-enable interrupt */ + + bval = DMA_IDLE_CMD; + OutB(bval,ioport+DMA_Cmd); + bval = CLEAR_FIFO_CMD; + OutB(bval,ioport+ScsiCmd); + + ResetDevParam( pACB ); + DoingSRB_Done( pACB ); + pACB->pActiveDCB = NULL; + + pACB->ACBFlag = 0; + DoWaitingSRB( pACB ); + splx(flags); + return; +} + + +#include <pci/scsiiom.c> + + +/*********************************************************************** + * Function : static void DC390_initDCB + * + * Purpose : initialize the internal structures for a given DCB + * + * Inputs : cmd - pointer to this scsi cmd request block structure + * + ***********************************************************************/ +static void +DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ) +{ + PEEprom prom; + UCHAR bval; + USHORT index; + PSCLINK plink; + + if( pACB->DeviceCnt == 0 ) + { + pACB->pLinkDCB = pDCB; + pACB->pDCBRunRobin = pDCB; + pDCB->pNextDCB = pDCB; + pPrevDCB = pDCB; + } + else + pPrevDCB->pNextDCB = pDCB; + + plink = cmd->sc_link; + pDCB->pDCBACB = pACB; + pDCB->UnitSCSIID = plink->target; + pDCB->UnitSCSILUN = plink->lun; + pDCB->pWaitingSRB = NULL; + pDCB->pGoingSRB = NULL; + pDCB->GoingSRBCnt = 0; + pDCB->pActiveSRB = NULL; + pDCB->TagMask = 0; + pDCB->MaxCommand = 1; + pDCB->AdaptIndex = pACB->AdapterIndex; + index = pACB->AdapterIndex; + pDCB->DCBFlag = 0; + + prom = (PEEprom) &eepromBuf[index][plink->target << 2]; + pDCB->DevMode = prom->EE_MODE1; + pDCB->AdpMode = eepromBuf[index][EE_MODE2]; + + if( pDCB->DevMode & EN_DISCONNECT_ ) + bval = 0xC0; + else + bval = 0x80; + bval |= plink->lun; + pDCB->IdentifyMsg = bval; + + pDCB->SyncMode = 0; + if( pDCB->DevMode & SYNC_NEGO_ ) + { + if( !(plink->lun) || CurrSyncOffset ) + pDCB->SyncMode = SYNC_ENABLE; + } + + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2; + + pDCB->CtrlR1 = pACB->AdaptSCSIID; + if( pDCB->DevMode & PARITY_CHK_ ) + pDCB->CtrlR1 |= PARITY_ERR_REPO; + + pDCB->CtrlR3 = FAST_CLK; + + pDCB->CtrlR4 = EATER_25NS; + if( pDCB->AdpMode & ACTIVE_NEGATION) + pDCB->CtrlR4 |= NEGATE_REQACKDATA; +} + + +/*********************************************************************** + * Function : static void DC390_initSRB + * + * Purpose : initialize the internal structures for a given SRB + * + * Inputs : psrb - pointer to this scsi request block structure + * + ***********************************************************************/ +static void +DC390_initSRB( PSRB psrb ) +{ + psrb->PhysSRB = vtophys( psrb ); +} + + +static void +DC390_linkSRB( PACB pACB ) +{ + USHORT count, i; + PSRB psrb; + + count = pACB->SRBCount; + + for( i=0; i< count; i++) + { + if( i != count - 1) + pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1]; + else + pACB->SRB_array[i].pNextSRB = NULL; + psrb = (PSRB) &pACB->SRB_array[i]; + DC390_initSRB( psrb ); + } +} + + +/*********************************************************************** + * Function : static void DC390_initACB + * + * Purpose : initialize the internal structures for a given SCSI host + * + * Inputs : psh - pointer to this host adapter's structure + * + ***********************************************************************/ +static void +DC390_initACB( PACB pACB, ULONG io_port, UCHAR Irq, USHORT index ) +{ + USHORT i; + + + pACB->max_id = 7; + if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] ) + pACB->max_id--; + if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) + pACB->max_lun = 7; + else + pACB->max_lun = 0; + + pACB->IOPortBase = (USHORT) io_port; + pACB->pLinkDCB = NULL; + pACB->pDCBRunRobin = NULL; + pACB->pActiveDCB = NULL; + pACB->pFreeSRB = pACB->SRB_array; + pACB->SRBCount = MAX_SRB_CNT; + pACB->AdapterIndex = index; + pACB->status = 0; + pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID]; + pACB->HostID_Bit = (1 << pACB->AdaptSCSIID); + pACB->AdaptSCSILUN = 0; + pACB->DeviceCnt = 0; + pACB->IRQLevel = Irq; + pACB->TagMaxNum = (eepromBuf[index][EE_TAG_CMD_NUM]) << 2; + pACB->ACBFlag = 0; + pACB->scan_devices = 1; + pACB->Gmode2 = eepromBuf[index][EE_MODE2]; + if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) + pACB->LUNchk = 1; + pACB->pDCB_free = &pACB->DCB_array[0]; + DC390_linkSRB( pACB ); + pACB->pTmpSRB = &pACB->TmpSRB; + DC390_initSRB( pACB->pTmpSRB ); + for(i=0; i<MAX_SCSI_ID; i++) + pACB->DCBmap[i] = 0; + + pACB->ScsiLink.adapter_unit = index; + pACB->ScsiLink.adapter_targ = pACB->AdaptSCSIID; + pACB->ScsiLink.fordriver = 0; + pACB->ScsiLink.opennings = 2; + pACB->ScsiLink.adapter = &trmamd_switch; + pACB->ScsiLink.device = &trmamd_dev; + pACB->ScsiLink.flags = 0; +} + + +/*********************************************************************** + * Function : static int DC390_initAdapter + * + * Purpose : initialize the SCSI chip ctrl registers + * + * Inputs : psh - pointer to this host adapter's structure + * + ***********************************************************************/ +static int DC390_initAdapter( PACB pACB, ULONG io_port, UCHAR Irq, + USHORT index, + pcici_t config_id ) +{ + USHORT ioport; + UCHAR bval; + +#ifdef CHECK_SHARE_INT + PACB pacb; + USHORT used_irq = 0; + + pacb = pACB_start; + if( pacb != NULL ) + { + for ( ; (pacb != (PACB) -1) ; ) + { + if( pacb->IRQLevel == Irq ) + { + used_irq = 1; + break; + } + else + pacb = pacb->pNextACB; + } + } + + if( !used_irq ) + { +#endif + if( !pci_map_int (config_id, (PVOID)DC390_Interrupt, pACB, &bio_imask) ) + { + if(bootverbose) + printf("DC390: register Interrupt handler error!\n"); + return( -1 ); + } + +#ifdef CHECK_SHARE_INT + } +#endif + + ioport = (USHORT) io_port; + bval = 153; /* 250ms selection timeout */ + OutB(bval,ioport+Scsi_TimeOut); + + bval = CLK_FREQ_40MHZ; /* Conversion factor = 0 , 40MHz clock */ + OutB(bval,ioport+Clk_Factor); + + bval = NOP_CMD; /* NOP cmd - clear command register */ + OutB(bval,ioport+ScsiCmd); + + bval = EN_FEATURE+EN_SCSI2_CMD; /* Enable Feature and SCSI-2 */ + OutB(bval,ioport+CtrlReg2); + + bval = FAST_CLK; /* fast clock */ + OutB(bval,ioport+CtrlReg3); + + bval = EATER_25NS; + if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION ) + bval |= NEGATE_REQACKDATA; + OutB(bval,ioport+CtrlReg4); + + bval = DIS_INT_ON_SCSI_RST; /* Disable SCSI bus reset interrupt */ + OutB(bval,ioport+CtrlReg1); + + return(0); +} + + +#ifdef PCI_COMPAT +static pcicfgregs *cfg; +#define DC390_EnableCfg(a,b) +#define DC390_DisableCfg(a) +#define DC390_inByte(a,reg) pci_cfgread(cfg,reg,1) +#define DC390_inWord(a,reg) pci_cfgread(cfg,reg,2) +#define DC390_inDword(a,reg) pci_cfgread(cfg,reg,4) +#define DC390_OutB(a,reg,val) pci_cfgwrite(cfg,reg,val,1) +#else + +void +DC390_EnableCfg( USHORT mechnum, UCHAR regval ) +{ + ULONG wlval; + + if(mechnum == 2) + { + OutB(mech2bus, PCI_CFG2_FORWARD_REG); + OutB(mech2CfgSPenR, PCI_CFG2_ENABLE_REG); + } + else + { + regval &= 0xFC; + wlval = mech1addr; + wlval |= (((ULONG)regval) & 0xff); + OutL(wlval, PCI_CFG1_ADDRESS_REG); + } +} + + +void +DC390_DisableCfg( USHORT mechnum ) +{ + + if(mechnum == 2) + OutB(0, PCI_CFG2_ENABLE_REG); + else + OutL(0, PCI_CFG1_ADDRESS_REG); +} + + +UCHAR +DC390_inByte( USHORT mechnum, UCHAR regval ) +{ + UCHAR bval; + USHORT wval; + int flags; + + flags = splbio(); + DC390_EnableCfg( mechnum, regval ); + if(mechnum == 2) + { + wval = mech2Agent; + wval <<= 8; + wval |= ((USHORT) regval) & 0xff; + bval = inb(wval); + } + else + { + regval &= 3; + bval = inb(PCI_CFG1_DATA_REG | regval); + } + DC390_DisableCfg(mechnum); + splx(flags); + return(bval); +} + + +USHORT +DC390_inWord( USHORT mechnum, UCHAR regval ) +{ + USHORT wval; + int flags; + + flags = splbio(); + DC390_EnableCfg(mechnum,regval); + if(mechnum == 2) + { + wval = mech2Agent; + wval <<= 8; + wval |= regval; + wval = inw(wval); + } + else + { + regval &= 3; + wval = inw(PCI_CFG1_DATA_REG | regval); + } + DC390_DisableCfg(mechnum); + splx(flags); + return(wval); +} + + +ULONG +DC390_inDword(USHORT mechnum, UCHAR regval ) +{ + ULONG wlval; + int flags; + USHORT wval; + + flags = splbio(); + DC390_EnableCfg(mechnum,regval); + if(mechnum == 2) + { + wval = mech2Agent; + wval <<= 8; + wval |= regval; + wlval = inl(wval); + } + else + { + wlval = inl(PCI_CFG1_DATA_REG); + } + DC390_DisableCfg(mechnum); + splx(flags); + return(wlval); +} + + +void +DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval ) +{ + + USHORT wval; + int flags; + + flags = splbio(); + DC390_EnableCfg(mechnum,regval); + if(mechnum == 2) + { + wval = mech2Agent; + wval <<= 8; + wval |= regval; + OutB(bval, wval); + } + else + { + regval &= 3; + OutB(bval, PCI_CFG1_DATA_REG | regval); + } + DC390_DisableCfg(mechnum); + splx(flags); +} + +#endif /PCI_COMPAT */ + +static void +DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval ) +{ + + UCHAR bval; + + bval = 0; + if(mode == ENABLE_CE) + *regval = 0xc0; + else + *regval = 0x80; + DC390_OutB(mechnum,*regval,bval); + if(mode == DISABLE_CE) + DC390_OutB(mechnum,*regval,bval); + DELAY(160); +} + + +static void +DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry ) +{ + UCHAR bval; + + bval = 0; + if(Carry) + { + bval = 0x40; + *regval = 0x80; + DC390_OutB(mechnum,*regval,bval); + } + DELAY(160); + bval |= 0x80; + DC390_OutB(mechnum,*regval,bval); + DELAY(160); + bval = 0; + DC390_OutB(mechnum,*regval,bval); + DELAY(160); +} + + +static UCHAR +DC390_EEpromInDO( USHORT mechnum ) +{ + UCHAR bval,regval; + + regval = 0x80; + bval = 0x80; + DC390_OutB(mechnum,regval,bval); + DELAY(160); + bval = 0x40; + DC390_OutB(mechnum,regval,bval); + DELAY(160); + regval = 0x0; + bval = DC390_inByte(mechnum,regval); + if(bval == 0x22) + return(1); + else + return(0); +} + + +static USHORT +EEpromGetData1( USHORT mechnum ) +{ + UCHAR i; + UCHAR carryFlag; + USHORT wval; + + wval = 0; + for(i=0; i<16; i++) + { + wval <<= 1; + carryFlag = DC390_EEpromInDO(mechnum); + wval |= carryFlag; + } + return(wval); +} + + +static void +DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd ) +{ + UCHAR i,j; + USHORT carryFlag; + + carryFlag = 1; + j = 0x80; + for(i=0; i<9; i++) + { + DC390_EEpromOutDI(mechnum,regval,carryFlag); + carryFlag = (EEpromCmd & j) ? 1 : 0; + j >>= 1; + } +} + + +static void +DC390_ReadEEprom( USHORT mechnum, USHORT index ) +{ + UCHAR regval,cmd; + PUSHORT ptr; + USHORT i; + + ptr = (PUSHORT) &eepromBuf[index][0]; + cmd = EEPROM_READ; + for(i=0; i<0x40; i++) + { + DC390_EnDisableCE(ENABLE_CE, mechnum, ®val); + DC390_Prepare(mechnum, ®val, cmd); + *ptr = EEpromGetData1(mechnum); + ptr++; + cmd++; + DC390_EnDisableCE(DISABLE_CE,mechnum,®val); + } +} + + +static USHORT +DC390_DefaultEEprom( USHORT mechnum, USHORT index ) +{ + PUCHAR ptr; + USHORT i; + + ptr = (PUCHAR) &eepromBuf[index][0]; + bzero (ptr, sizeof eepromBuf[index]); + for(i=0; i<0x40; i++) + { + *ptr = (TAG_QUEUING_|EN_DISCONNECT_|SYNC_NEGO_|PARITY_CHK_); + ptr += 4; + } + eepromBuf[index][EE_ADAPT_SCSI_ID] = 7; + eepromBuf[index][EE_MODE2] = (LUN_CHECK|ACTIVE_NEGATION); + eepromBuf[index][EE_TAG_CMD_NUM] = 4; + return 0; +} + + +static USHORT +DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index ) +{ + USHORT wval, rc, *ptr; + UCHAR i; + + DC390_ReadEEprom( MechNum, index ); + wval = 0; + ptr = (PUSHORT) &eepromBuf[index][0]; + for(i=0; i<128 ;i+=2, ptr++) + wval += *ptr; + if( wval == 0x1234 ) + rc = 0; + else + rc = DC390_DefaultEEprom( MechNum, index); + return( rc ); +} + + +static USHORT +DC390_ToMech( USHORT Mechnum, pcici_t config_id ) +{ + +#ifdef PCI_COMPAT + cfg = config_id; +#else + if(Mechnum == 2) + { + mech2bus = config_id.cfg2.forward; /* Bus num */ + mech2Agent = config_id.cfg2.port >> 8; /* Dev num */ + mech2CfgSPenR = config_id.cfg2.enable; /* Fun num */ + } + else /* use mech #1 method */ + { + mech1addr = config_id.cfg1; + } +#endif /* PCI_COMPAT */ + return(0); +} + +/*********************************************************************** + * Function : static int DC390_init (struct Scsi_Host *host) + * + * Purpose : initialize the internal structures for a given SCSI host + * + * Inputs : host - pointer to this host adapter's structure/ + * + * Preconditions : when this function is called, the chip_type + * field of the pACB structure MUST have been set. + ***********************************************************************/ + +static int +DC390_init( ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum, + pcici_t config_id) +{ + PACB pACB; + + if( !DC390_CheckEEpromCheckSum( MechNum, index) ) + { + pACB = (PACB) malloc (sizeof (struct _ACB), M_DEVBUF, M_WAITOK); + if( !pACB ) + { + printf("DC390%d: cannot allocate ACB !\n", index); + return( -1 ); + } + bzero (pACB, sizeof (struct _ACB)); + DC390_initACB( pACB, io_port, Irq, index ); + if( !DC390_initAdapter( pACB, io_port, Irq, index, config_id) ) + { + if( !pACB_start ) + { + pACB_start = pACB; + pACB_current = pACB; + pACB->pNextACB = (PACB) -1; + } + else + { + pACB_current->pNextACB = pACB; + pACB_current = pACB; + pACB->pNextACB = (PACB) -1; + } + pACB0[index] = pACB; + +#ifdef DC390_DEBUG0 + printf("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n", + (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array); + printf("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n", + sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) ); +#endif + + return( 0 ); + } + else + { + free( pACB, M_DEVBUF); + return( -1 ); + } + } + else + { + printf("DC390_init: EEPROM reading error!\n"); + return( -1 ); + } +} + + + +void +trmamd_attach (pcici_t config_id, int unit) +{ + struct scsibus_data *scbus; + UCHAR irq; + USHORT MechNum; + ULONG io_port, wlval; + PACB pACB = 0; + int flags; + + if( unit >= MAX_ADAPTER_NUM ) + return; + + if( pACB0[unit] ) + return; + + CurrentID = 0; + CurrentLUN = 0; + MechNum = pci_mechanism; + +#ifdef DC390_DEBUG0 + if(bootverbose) + printf("DC390: Mech=%2x,\n",(UCHAR) MechNum); +#endif + + if( !DC390_ToMech( MechNum, config_id ) ) + { + wlval = DC390_inDword( MechNum, PCI_ID_REG); + if(wlval == PCI_DEVICE_ID_AMD53C974 ) + { + io_port =DC390_inDword(MechNum,PCI_BASE_ADDR0) & 0xFFFE; + irq = DC390_inByte( MechNum, PCI_INTERRUPT_REG); +#ifdef DC390_DEBUG0 + if(bootverbose) + printf("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq); +#endif + if( !DC390_init( io_port, irq, (USHORT) unit, MechNum, config_id) ) + { + adapterCnt++; + } + else + return; + } + } + + pACB = pACB0[unit]; + +/* + Now let the generic SCSI driver look for the SCSI devices on the bus +*/ + + flags = splbio(); + + scbus = scsi_alloc_bus(); + if(!scbus) + { + splx(flags); + return; + } + scbus->adapter_link = &pACB->ScsiLink; + scbus->maxtarg = pACB->max_id; + +#ifdef DC390_DEBUG + if(bootverbose) + printf("\nDC390: scanning for devices ...\n\n"); +#endif + + scsi_attachdevs (scbus); + scbus = NULL; /* Upper-level SCSI code owns this now */ + +#ifdef DC390_DEBUG + if(bootverbose) + printf("\n\nDC390: Attach devices return\n"); +#endif + + splx(flags); +} + + +static char* +trmamd_probe (pcici_t tag, pcidi_t type) +{ + if( type == PCI_DEVICE_ID_AMD53C974 ) + return ("amd 53c974 scsi"); + else + return (NULL); +} + diff --git a/sys/pci/tek390.h b/sys/pci/tek390.h new file mode 100644 index 000000000000..c8de8cee0d1a --- /dev/null +++ b/sys/pci/tek390.h @@ -0,0 +1,667 @@ +/*********************************************************************** +;* File Name : TEK390.H * +;* TEKRAM DC-390 PCI SCSI Bus Master Host Adapter * +;* Device Driver * +;***********************************************************************/ + +#ifndef TEK390_H +#define TEK390_H + +typedef unsigned char UCHAR; +typedef unsigned short USHORT; +typedef unsigned long ULONG; +typedef unsigned int UINT; + +typedef UCHAR *PUCHAR; +typedef USHORT *PUSHORT; +typedef ULONG *PULONG; +typedef struct scsi_link *PSCLINK, SCSILINK; +typedef struct scsi_xfer *PSCSICMD, SCSICMD; +typedef void *PVOID; + + +/*;-----------------------------------------------------------------------*/ +typedef struct _SyncMsg +{ +UCHAR ExtendMsg; +UCHAR ExtMsgLen; +UCHAR SyncXferReq; +UCHAR Period; +UCHAR ReqOffset; +} SyncMsg; +/*;-----------------------------------------------------------------------*/ +typedef struct _Capacity +{ +ULONG BlockCount; +ULONG BlockLength; +} Capacity; +/*;-----------------------------------------------------------------------*/ +typedef struct _SGentry +{ +ULONG SGXLen; +ULONG SGXPtr; +} SGentry, *PSEG; + +typedef struct _SGentry1 +{ +ULONG SGXPtr1; +ULONG SGXLen1; +} SGentry1, *PSEG1; + + +#define MAX_ADAPTER_NUM 4 +#define MAX_SCSI_ID 8 +#define MAX_SG_ENTRY 33 +#define MAX_DEVICES 10 +#define MAX_CMD_QUEUE 20 +#define MAX_CMD_PER_LUN 6 +#define MAX_SRB_CNT MAX_CMD_PER_LUN*4 +#define PAGELEN 4096 + +/* +;----------------------------------------------------------------------- +; SCSI Request Block +;----------------------------------------------------------------------- +*/ +struct _SRB +{ +UCHAR CmdBlock[12]; + +struct _SRB *pNextSRB; +struct _DCB *pSRBDCB; +PSCSICMD pcmd; +PSEG pSegmentList; + +ULONG PhysSRB; +ULONG TotalXferredLen; +ULONG SGPhysAddr; /*;a segment starting address */ +ULONG SGToBeXferLen; /*; to be xfer length */ +ULONG Segment0[2]; +ULONG Segment1[2]; + +SGentry SGsegment[MAX_SG_ENTRY]; +SGentry Segmentx; /* make a one entry of S/G list table */ + +PUCHAR pMsgPtr; +USHORT SRBState; +USHORT Revxx2; /* ??? */ + +UCHAR MsgInBuf[6]; +UCHAR MsgOutBuf[6]; + +UCHAR AdaptStatus; +UCHAR TargetStatus; +UCHAR MsgCnt; +UCHAR EndMessage; +UCHAR TagNumber; +UCHAR SGcount; +UCHAR SGIndex; +UCHAR IORBFlag; /*;81h-Reset, 2-retry */ + +UCHAR SRBStatus; +UCHAR RetryCnt; +UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ + /*; b4-settimeout,b5-Residual valid */ +UCHAR ScsiCmdLen; +UCHAR ScsiPhase; +UCHAR Reserved3[3]; /*;for dword alignment */ +}; + +typedef struct _SRB DC390_SRB, *PSRB; + +/* +;----------------------------------------------------------------------- +; Device Control Block +;----------------------------------------------------------------------- +*/ +struct _DCB +{ +struct _DCB *pNextDCB; +struct _ACB *pDCBACB; + +PSRB pWaitingSRB; +PSRB pWaitLast; +PSRB pGoingSRB; +PSRB pGoingLast; +PSRB pActiveSRB; +USHORT GoingSRBCnt; +USHORT WaitSRBCnt; /* ??? */ + +ULONG TagMask; + +USHORT MaxCommand; +USHORT AdaptIndex; /*; UnitInfo struc start */ +USHORT UnitIndex; /*; nth Unit on this card */ +UCHAR UnitSCSIID; /*; SCSI Target ID (SCSI Only) */ +UCHAR UnitSCSILUN; /*; SCSI Log. Unit (SCSI Only) */ + +UCHAR IdentifyMsg; +UCHAR CtrlR1; +UCHAR CtrlR3; +UCHAR CtrlR4; + +UCHAR InqDataBuf[8]; +UCHAR CapacityBuf[8]; +UCHAR DevMode; +UCHAR AdpMode; +UCHAR SyncMode; /*; 0:async mode */ +UCHAR NegoPeriod; /*;for nego. */ +UCHAR SyncPeriod; /*;for reg. */ +UCHAR SyncOffset; /*;for reg. and nego.(low nibble) */ +UCHAR UnitCtrlFlag; +UCHAR DCBFlag; +UCHAR DevType; +UCHAR Reserved2[3]; /*;for dword alignment */ +}; + +typedef struct _DCB DC390_DCB, *PDCB; +/* +;----------------------------------------------------------------------- +; Adapter Control Block +;----------------------------------------------------------------------- +*/ +struct _ACB +{ +ULONG PhysACB; +struct _ACB *pNextACB; +USHORT IOPortBase; +USHORT Revxx1; /* ??? */ + +PDCB pLinkDCB; +PDCB pDCBRunRobin; +PDCB pActiveDCB; +PDCB pDCB_free; +PSRB pFreeSRB; +PSRB pTmpSRB; +USHORT SRBCount; +USHORT AdapterIndex; /*; nth Adapter this driver */ +USHORT max_id; +USHORT max_lun; +SCSILINK ScsiLink; + +UCHAR msgin123[4]; +UCHAR status; +UCHAR AdaptSCSIID; /*; Adapter SCSI Target ID */ +UCHAR AdaptSCSILUN; /*; Adapter SCSI LUN */ +UCHAR DeviceCnt; +UCHAR IRQLevel; +UCHAR TagMaxNum; +UCHAR ACBFlag; +UCHAR Gmode2; +UCHAR LUNchk; +UCHAR scan_devices; +UCHAR HostID_Bit; +UCHAR Reserved1[1]; /*;for dword alignment */ +UCHAR DCBmap[MAX_SCSI_ID]; +DC390_DCB DCB_array[MAX_DEVICES]; /* +74h, Len=3E8 */ +DC390_SRB SRB_array[MAX_SRB_CNT]; /* +45Ch, Len= */ +DC390_SRB TmpSRB; +}; + +typedef struct _ACB DC390_ACB, *PACB; + +/*;-----------------------------------------------------------------------*/ + + +#define BIT31 0x80000000 +#define BIT30 0x40000000 +#define BIT29 0x20000000 +#define BIT28 0x10000000 +#define BIT27 0x08000000 +#define BIT26 0x04000000 +#define BIT25 0x02000000 +#define BIT24 0x01000000 +#define BIT23 0x00800000 +#define BIT22 0x00400000 +#define BIT21 0x00200000 +#define BIT20 0x00100000 +#define BIT19 0x00080000 +#define BIT18 0x00040000 +#define BIT17 0x00020000 +#define BIT16 0x00010000 +#define BIT15 0x00008000 +#define BIT14 0x00004000 +#define BIT13 0x00002000 +#define BIT12 0x00001000 +#define BIT11 0x00000800 +#define BIT10 0x00000400 +#define BIT9 0x00000200 +#define BIT8 0x00000100 +#define BIT7 0x00000080 +#define BIT6 0x00000040 +#define BIT5 0x00000020 +#define BIT4 0x00000010 +#define BIT3 0x00000008 +#define BIT2 0x00000004 +#define BIT1 0x00000002 +#define BIT0 0x00000001 + +/*;---UnitCtrlFlag */ +#define UNIT_ALLOCATED BIT0 +#define UNIT_INFO_CHANGED BIT1 +#define FORMATING_MEDIA BIT2 +#define UNIT_RETRY BIT3 + +/*;---UnitFlags */ +#define DASD_SUPPORT BIT0 +#define SCSI_SUPPORT BIT1 +#define ASPI_SUPPORT BIT2 + +/*;----SRBState machine definition */ +#define SRB_FREE 0 +#define SRB_WAIT BIT0 +#define SRB_READY BIT1 +#define SRB_MSGOUT BIT2 /*;arbitration+msg_out 1st byte*/ +#define SRB_MSGIN BIT3 +#define SRB_MSGIN_MULTI BIT4 +#define SRB_COMMAND BIT5 +#define SRB_START_ BIT6 /*;arbitration+msg_out+command_out*/ +#define SRB_DISCONNECT BIT7 +#define SRB_DATA_XFER BIT8 +#define SRB_XFERPAD BIT9 +#define SRB_STATUS BIT10 +#define SRB_COMPLETED BIT11 +#define SRB_ABORT_SENT BIT12 +#define DO_SYNC_NEGO BIT13 +#define SRB_UNEXPECT_RESEL BIT14 + +/*;---ACBFlag */ +#define RESET_DEV BIT0 +#define RESET_DETECT BIT1 +#define RESET_DONE BIT2 + +/*;---DCBFlag */ +#define ABORT_DEV_ BIT0 + +/*;---SRBstatus */ +#define SRB_OK BIT0 +#define ABORTION BIT1 +#define OVER_RUN BIT2 +#define UNDER_RUN BIT3 +#define PARITY_ERROR BIT4 +#define SRB_ERROR BIT5 + +/*;---SRBFlag */ +#define DATAOUT BIT7 +#define DATAIN BIT6 +#define RESIDUAL_VALID BIT5 +#define ENABLE_TIMER BIT4 +#define RESET_DEV0 BIT2 +#define ABORT_DEV BIT1 +#define AUTO_REQSENSE BIT0 + +/*;---Adapter status */ +#define H_STATUS_GOOD 0 +#define H_SEL_TIMEOUT 0x11 +#define H_OVER_UNDER_RUN 0x12 +#define H_UNEXP_BUS_FREE 0x13 +#define H_TARGET_PHASE_F 0x14 +#define H_INVALID_CCB_OP 0x16 +#define H_LINK_CCB_BAD 0x17 +#define H_BAD_TARGET_DIR 0x18 +#define H_DUPLICATE_CCB 0x19 +#define H_BAD_CCB_OR_SG 0x1A +#define H_ABORT 0x0FF + +/*; SCSI Status byte codes*/ +#define SCSI_STAT_GOOD 0x0 /*; Good status */ +#define SCSI_STAT_CHECKCOND 0x02 /*; SCSI Check Condition */ +#define SCSI_STAT_CONDMET 0x04 /*; Condition Met */ +#define SCSI_STAT_BUSY 0x08 /*; Target busy status */ +#define SCSI_STAT_INTER 0x10 /*; Intermediate status */ +#define SCSI_STAT_INTERCONDMET 0x14 /*; Intermediate condition met */ +#define SCSI_STAT_RESCONFLICT 0x18 /*; Reservation conflict */ +#define SCSI_STAT_CMDTERM 0x22 /*; Command Terminated */ +#define SCSI_STAT_QUEUEFULL 0x28 /*; Queue Full */ + +#define SCSI_STAT_UNEXP_BUS_F 0xFD /*; Unexpect Bus Free */ +#define SCSI_STAT_BUS_RST_DETECT 0xFE /*; Scsi Bus Reset detected */ +#define SCSI_STAT_SEL_TIMEOUT 0xFF /*; Selection Time out */ + +/*;---Sync_Mode */ +#define SYNC_DISABLE 0 +#define SYNC_ENABLE BIT0 +#define SYNC_NEGO_DONE BIT1 +#define WIDE_ENABLE BIT2 +#define WIDE_NEGO_DONE BIT3 +#define EN_TAG_QUEUING BIT4 +#define EN_ATN_STOP BIT5 + +#define SYNC_NEGO_OFFSET 15 + +/*;---SCSI bus phase*/ +#define SCSI_DATA_OUT_ 0 +#define SCSI_DATA_IN_ 1 +#define SCSI_COMMAND 2 +#define SCSI_STATUS_ 3 +#define SCSI_NOP0 4 +#define SCSI_NOP1 5 +#define SCSI_MSG_OUT 6 +#define SCSI_MSG_IN 7 + +/*;----SCSI MSG BYTE*/ +#define MSG_COMPLETE 0x00 +#define MSG_EXTENDED 0x01 +#define MSG_SAVE_PTR 0x02 +#define MSG_RESTORE_PTR 0x03 +#define MSG_DISCONNECT 0x04 +#define MSG_INITIATOR_ERROR 0x05 +#define MSG_ABORT 0x06 +#define MSG_REJECT_ 0x07 +#define MSG_NOP 0x08 +#define MSG_PARITY_ERROR 0x09 +#define MSG_LINK_CMD_COMPL 0x0A +#define MSG_LINK_CMD_COMPL_FLG 0x0B +#define MSG_BUS_RESET 0x0C +#define MSG_ABORT_TAG 0x0D +#define MSG_SIMPLE_QTAG 0x20 +#define MSG_HEAD_QTAG 0x21 +#define MSG_ORDER_QTAG 0x22 +#define MSG_IDENTIFY 0x80 +#define MSG_HOST_ID 0x0C0 + +/*;----SCSI STATUS BYTE*/ +#define STATUS_GOOD 0x00 +#define CHECK_CONDITION_ 0x02 +#define STATUS_BUSY 0x08 +#define STATUS_INTERMEDIATE 0x10 +#define RESERVE_CONFLICT 0x18 + +/* cmd->result */ +#define STATUS_MASK_ 0xFF +#define MSG_MASK 0xFF00 +#define RETURN_MASK 0xFF0000 + +/* +** Inquiry Data format +*/ + +typedef struct _SCSIInqData { /* INQ */ + + UCHAR DevType; /* Periph Qualifier & Periph Dev Type*/ + UCHAR RMB_TypeMod; /* rem media bit & Dev Type Modifier */ + UCHAR Vers; /* ISO, ECMA, & ANSI versions */ + UCHAR RDF; /* AEN, TRMIOP, & response data format*/ + UCHAR AddLen; /* length of additional data */ + UCHAR Res1; /* reserved */ + UCHAR Res2; /* reserved */ + UCHAR Flags; /* RelADr,Wbus32,Wbus16,Sync,etc. */ + UCHAR VendorID[8]; /* Vendor Identification */ + UCHAR ProductID[16]; /* Product Identification */ + UCHAR ProductRev[4]; /* Product Revision */ + + +} SCSI_INQDATA, *PSCSI_INQDATA; + + +/* Inquiry byte 0 masks */ + + +#define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */ +#define SCSI_PERIPHQUAL 0xE0 /* Peripheral Qualifier */ + + +/* Inquiry byte 1 mask */ + +#define SCSI_REMOVABLE_MEDIA 0x80 /* Removable Media bit (1=removable) */ + + +/* Peripheral Device Type definitions */ + +#define SCSI_DASD 0x00 /* Direct-access Device */ +#define SCSI_SEQACESS 0x01 /* Sequential-access device */ +#define SCSI_PRINTER 0x02 /* Printer device */ +#define SCSI_PROCESSOR 0x03 /* Processor device */ +#define SCSI_WRITEONCE 0x04 /* Write-once device */ +#define SCSI_CDROM 0x05 /* CD-ROM device */ +#define SCSI_SCANNER 0x06 /* Scanner device */ +#define SCSI_OPTICAL 0x07 /* Optical memory device */ +#define SCSI_MEDCHGR 0x08 /* Medium changer device */ +#define SCSI_COMM 0x09 /* Communications device */ +#define SCSI_NODEV 0x1F /* Unknown or no device type */ + +/* +** Inquiry flag definitions (Inq data byte 7) +*/ + +#define SCSI_INQ_RELADR 0x80 /* device supports relative addressing*/ +#define SCSI_INQ_WBUS32 0x40 /* device supports 32 bit data xfers */ +#define SCSI_INQ_WBUS16 0x20 /* device supports 16 bit data xfers */ +#define SCSI_INQ_SYNC 0x10 /* device supports synchronous xfer */ +#define SCSI_INQ_LINKED 0x08 /* device supports linked commands */ +#define SCSI_INQ_CMDQUEUE 0x02 /* device supports command queueing */ +#define SCSI_INQ_SFTRE 0x01 /* device supports soft resets */ + + +/* +;========================================================== +; EEPROM byte offset +;========================================================== +*/ +typedef struct _EEprom +{ +UCHAR EE_MODE1; +UCHAR EE_SPEED; +UCHAR xx1; +UCHAR xx2; +} EEprom, *PEEprom; + +#define EE_ADAPT_SCSI_ID 64 +#define EE_MODE2 65 +#define EE_DELAY 66 +#define EE_TAG_CMD_NUM 67 + +/*; EE_MODE1 bits definition*/ +#define PARITY_CHK_ BIT0 +#define SYNC_NEGO_ BIT1 +#define EN_DISCONNECT_ BIT2 +#define SEND_START_ BIT3 +#define TAG_QUEUING_ BIT4 + +/*; EE_MODE2 bits definition*/ +#define MORE2_DRV BIT0 +#define GREATER_1G BIT1 +#define RST_SCSI_BUS BIT2 +#define ACTIVE_NEGATION BIT3 +#define NO_SEEK BIT4 +#define LUN_CHECK BIT5 + +#define ENABLE_CE 1 +#define DISABLE_CE 0 +#define EEPROM_READ 0x80 + +/* +;========================================================== +; AMD 53C974 Registers bit Definition +;========================================================== +*/ +/* +;==================== +; SCSI Register +;==================== +*/ + +/*; Command Reg.(+0CH) */ +#define DMA_COMMAND BIT7 +#define NOP_CMD 0 +#define CLEAR_FIFO_CMD 1 +#define RST_DEVICE_CMD 2 +#define RST_SCSI_BUS_CMD 3 +#define INFO_XFER_CMD 0x10 +#define INITIATOR_CMD_CMPLTE 0x11 +#define MSG_ACCEPTED_CMD 0x12 +#define XFER_PAD_BYTE 0x18 +#define SET_ATN_CMD 0x1A +#define RESET_ATN_CMD 0x1B +#define SELECT_W_ATN 0x42 +#define SEL_W_ATN_STOP 0x43 +#define EN_SEL_RESEL 0x44 +#define SEL_W_ATN2 0x46 +#define DATA_XFER_CMD INFO_XFER_CMD + + +/*; SCSI Status Reg.(+10H) */ +#define INTERRUPT BIT7 +#define ILLEGAL_OP_ERR BIT6 +#define PARITY_ERR BIT5 +#define COUNT_2_ZERO BIT4 +#define GROUP_CODE_VALID BIT3 +#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0) + +/*; Interrupt Status Reg.(+14H) */ +#define SCSI_RESET_ BIT7 +#define INVALID_CMD BIT6 +#define DISCONNECTED BIT5 +#define SERVICE_REQUEST BIT4 +#define SUCCESSFUL_OP BIT3 +#define RESELECTED BIT2 +#define SEL_ATTENTION BIT1 +#define SELECTED BIT0 + +/*; Internal State Reg.(+18H) */ +#define SYNC_OFFSET_FLAG BIT3 +#define INTRN_STATE_MASK (BIT2+BIT1+BIT0) + +/*; Clock Factor Reg.(+24H) */ +#define CLK_FREQ_40MHZ 0 +#define CLK_FREQ_35MHZ (BIT2+BIT1+BIT0) +#define CLK_FREQ_30MHZ (BIT2+BIT1) +#define CLK_FREQ_25MHZ (BIT2+BIT0) +#define CLK_FREQ_20MHZ BIT2 +#define CLK_FREQ_15MHZ (BIT1+BIT0) +#define CLK_FREQ_10MHZ BIT1 + +/*; Control Reg. 1(+20H) */ +#define EXTENDED_TIMING BIT7 +#define DIS_INT_ON_SCSI_RST BIT6 +#define PARITY_ERR_REPO BIT4 +#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0) + +/*; Control Reg. 2(+2CH) */ +#define EN_FEATURE BIT6 +#define EN_SCSI2_CMD BIT3 + +/*; Control Reg. 3(+30H) */ +#define ID_MSG_CHECK BIT7 +#define EN_QTAG_MSG BIT6 +#define EN_GRP2_CMD BIT5 +#define FAST_SCSI BIT4 /* ;10MB/SEC */ +#define FAST_CLK BIT3 /* ;25 - 40 MHZ */ + +/*; Control Reg. 4(+34H) */ +#define EATER_12NS 0 +#define EATER_25NS BIT7 +#define EATER_35NS BIT6 +#define EATER_0NS (BIT7+BIT6) +#define NEGATE_REQACKDATA BIT2 +#define NEGATE_REQACK BIT3 +/* +;==================== +; DMA Register +;==================== +*/ +/*; DMA Command Reg.(+40H) */ +#define READ_DIRECTION BIT7 +#define WRITE_DIRECTION 0 +#define EN_DMA_INT BIT6 +#define MAP_TO_MDL BIT5 +#define DMA_DIAGNOSTIC BIT4 +#define DMA_IDLE_CMD 0 +#define DMA_BLAST_CMD BIT0 +#define DMA_ABORT_CMD BIT1 +#define DMA_START_CMD (BIT1+BIT0) + +/*; DMA Status Reg.(+54H) */ +#define PCI_MS_ABORT BIT6 +#define BLAST_COMPLETE BIT5 +#define SCSI_INTERRUPT BIT4 +#define DMA_XFER_DONE BIT3 +#define DMA_XFER_ABORT BIT2 +#define DMA_XFER_ERROR BIT1 +#define POWER_DOWN BIT0 + +/* +; DMA SCSI Bus and Ctrl.(+70H) +;EN_INT_ON_PCI_ABORT +*/ + +/* +;========================================================== +; SCSI Chip register address offset +;========================================================== +*/ +#define CtcReg_Low 0x00 +#define CtcReg_Mid 0x04 +#define ScsiFifo 0x08 +#define ScsiCmd 0x0C +#define Scsi_Status 0x10 +#define INT_Status 0x14 +#define Sync_Period 0x18 +#define Sync_Offset 0x1C +#define CtrlReg1 0x20 +#define Clk_Factor 0x24 +#define CtrlReg2 0x2C +#define CtrlReg3 0x30 +#define CtrlReg4 0x34 +#define CtcReg_High 0x38 +#define DMA_Cmd 0x40 +#define DMA_XferCnt 0x44 +#define DMA_XferAddr 0x48 +#define DMA_Wk_ByteCntr 0x4C +#define DMA_Wk_AddrCntr 0x50 +#define DMA_Status 0x54 +#define DMA_MDL_Addr 0x58 +#define DMA_Wk_MDL_Cntr 0x5C +#define DMA_ScsiBusCtrl 0x70 + +#define StcReg_Low CtcReg_Low +#define StcReg_Mid CtcReg_Mid +#define Scsi_Dest_ID Scsi_Status +#define Scsi_TimeOut INT_Status +#define Intern_State Sync_Period +#define Current_Fifo Sync_Offset +#define StcReg_High CtcReg_High + +#define am_target Scsi_Status +#define am_timeout INT_Status +#define am_seq_step Sync_Period +#define am_fifo_count Sync_Offset + + +#define DC390_read8(address) \ + inb(DC390_ioport + (address))) + +#define DC390_read16(address) \ + inw(DC390_ioport + (address))) + +#define DC390_read32(address) \ + inl(DC390_ioport + (address))) + +#define DC390_write8(address,value) \ + outb((value), DC390_ioport + (address))) + +#define DC390_write16(address,value) \ + outw((value), DC390_ioport + (address))) + +#define DC390_write32(address,value) \ + outl((value), DC390_ioport + (address))) + + +/* Configuration method #1 */ +#define PCI_CFG1_ADDRESS_REG 0xcf8 +#define PCI_CFG1_DATA_REG 0xcfc +#define PCI_CFG1_ENABLE 0x80000000 +#define PCI_CFG1_TUPPLE(bus, device, function, register) \ + (PCI_CFG1_ENABLE | (((bus) << 16) & 0xff0000) | \ + (((device) << 11) & 0xf800) | (((function) << 8) & 0x700)| \ + (((register) << 2) & 0xfc)) + +/* Configuration method #2 */ +#define PCI_CFG2_ENABLE_REG 0xcf8 +#define PCI_CFG2_FORWARD_REG 0xcfa +#define PCI_CFG2_ENABLE 0x0f0 +#define PCI_CFG2_TUPPLE(function) \ + (PCI_CFG2_ENABLE | (((function) << 1) & 0xe)) + + +#endif /* TEK390_H */ diff --git a/sys/pci/wdc_p.c b/sys/pci/wdc_p.c index f8ca641b72e2..67d9de617112 100644 --- a/sys/pci/wdc_p.c +++ b/sys/pci/wdc_p.c @@ -16,7 +16,7 @@ * 4. Modifications may be freely made to this file if the above conditions * are met. * - * $Id: wdc_p.c,v 1.3 1997/08/02 14:33:14 bde Exp $ + * $Id: wdc_p.c,v 1.2 1997/04/28 19:26:18 se Exp $ */ /* @@ -41,7 +41,7 @@ #define CMD640B_PCI_ID 0x06401095 -static const char* wdc_pci_probe __P((pcici_t tag, pcidi_t type)); +static char* wdc_pci_probe __P((pcici_t tag, pcidi_t type)); static void wdc_pci_attach __P((pcici_t config_id, int unit)); static u_long wdc_pci_count = 0; @@ -56,7 +56,7 @@ static struct pci_device wdc_pci_driver = { DATA_SET (pcidevice_set, wdc_pci_driver); -static const char* +static char* wdc_pci_probe (pcici_t tag, pcidi_t type) { if (type == CMD640B_PCI_ID) diff --git a/sys/pci/xrpu.c b/sys/pci/xrpu.c index 25a90a471d8f..b46a3952dbcd 100644 --- a/sys/pci/xrpu.c +++ b/sys/pci/xrpu.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: xrpu.c,v 1.5 1998/12/14 06:32:58 dillon Exp $ + * $Id: xrpu.c,v 1.1 1998/05/30 18:28:11 phk Exp $ * * A very simple device driver for PCI cards based on Xilinx 6200 series * FPGA/RPU devices. Current Functionality is to allow you to open and @@ -17,199 +17,52 @@ * */ -#include "xrpu.h" +#ifndef DEVFS #include <sys/param.h> #include <sys/systm.h> #include <sys/conf.h> #include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/timepps.h> #include <sys/devfsext.h> -#include <sys/xrpuio.h> #include <pci/pcireg.h> #include <pci/pcivar.h> -static const char* xrpu_probe (pcici_t tag, pcidi_t type); +static char* xrpu_probe (pcici_t tag, pcidi_t type); static void xrpu_attach (pcici_t tag, int unit); static u_long xrpu_count; -static void xrpu_poll_pps(struct timecounter *tc); - -/* - * Device driver initialization stuff - */ - -static d_open_t xrpu_open; -static d_close_t xrpu_close; -static d_ioctl_t xrpu_ioctl; -static d_mmap_t xrpu_mmap; - -#define CDEV_MAJOR 100 -static struct cdevsw xrpudevsw = { - xrpu_open, xrpu_close, noread, nowrite, - xrpu_ioctl, nullstop, noreset, nodevtotty, - seltrue, xrpu_mmap, nostrategy, "xrpu", - NULL, -1 -}; - -static MALLOC_DEFINE(M_XRPU, "xrpu", "XRPU related"); - -#define dev2unit(devt) (minor(devt) & 0xff) -#define dev2pps(devt) ((minor(devt) >> 16)-1) - -static struct softc { - pcici_t tag; - enum { NORMAL, TIMECOUNTER } mode; - vm_offset_t virbase, physbase; - u_int *virbase62; - struct timecounter tc; - u_int *trigger, *latch, dummy; - struct { - pps_params_t params; - pps_info_t info; - int cap; - u_int *assert, last_assert; - u_int *clear, last_clear; - } pps[XRPU_MAX_PPS]; -} *softc[NXRPU]; - -static unsigned -xrpu_get_timecount(struct timecounter *tc) -{ - struct softc *sc = tc->tc_priv; - - sc->dummy += *sc->trigger; - return (*sc->latch & tc->tc_counter_mask); -} - -void -xrpu_poll_pps(struct timecounter *tc) -{ - struct softc *sc = tc->tc_priv; - int i; - unsigned count1, ppscount; - - for (i = 0; i < XRPU_MAX_PPS; i++) { - if (sc->pps[i].assert) { - ppscount = *(sc->pps[i].assert) & tc->tc_counter_mask; - do { - count1 = ppscount; - ppscount = *(sc->pps[i].assert) & tc->tc_counter_mask; - } while (ppscount != count1); - if (ppscount != sc->pps[i].last_assert) { - timecounter_timespec(ppscount, &sc->pps[i].info.assert_timestamp); - if (sc->pps[i].params.mode & PPS_OFFSETASSERT) { - timespecadd(&sc->pps[i].info.assert_timestamp, - &sc->pps[i].params.assert_offset); - if (sc->pps[i].info.assert_timestamp.tv_nsec < 0) { - sc->pps[i].info.assert_timestamp.tv_nsec += 1000000000; - sc->pps[i].info.assert_timestamp.tv_sec -= 1; - } - } - sc->pps[i].info.assert_sequence++; - sc->pps[i].last_assert = ppscount; - } - } - if (sc->pps[i].clear) { - ppscount = *(sc->pps[i].clear) & tc->tc_counter_mask; - do { - count1 = ppscount; - ppscount = *(sc->pps[i].clear) & tc->tc_counter_mask; - } while (ppscount != count1); - if (ppscount != sc->pps[i].last_clear) { - timecounter_timespec(ppscount, &sc->pps[i].info.clear_timestamp); - if (sc->pps[i].params.mode & PPS_OFFSETASSERT) { - timespecadd(&sc->pps[i].info.clear_timestamp, - &sc->pps[i].params.clear_offset); - if (sc->pps[i].info.clear_timestamp.tv_nsec < 0) { - sc->pps[i].info.clear_timestamp.tv_nsec += 1000000000; - sc->pps[i].info.clear_timestamp.tv_sec -= 1; - } - } - sc->pps[i].info.clear_sequence++; - sc->pps[i].last_clear = ppscount; - } - } - } -} +static vm_offset_t virbase, physbase; static int -xrpu_open(dev_t dev, int flag, int mode, struct proc *p) +xrpuopen(dev_t dev, int flag, int mode, struct proc *p) { return (0); } static int -xrpu_close(dev_t dev, int flag, int mode, struct proc *p) +xrpuclose(dev_t dev, int flag, int mode, struct proc *p) { return (0); } static int -xrpu_mmap(dev_t dev, vm_offset_t offset, int nprot) +xrpummap(dev_t dev, int offset, int nprot) { - struct softc *sc = softc[dev2unit(dev)]; if (offset >= 0x1000000) return (-1); - return (i386_btop(sc->physbase + offset)); + return (i386_btop(physbase + offset)); } -static int -xrpu_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *pr) -{ - struct softc *sc = softc[dev2unit(dev)]; - int i, error; - - if (sc->mode == TIMECOUNTER) { - i = dev2pps(dev); - if (i < 0 || i >= XRPU_MAX_PPS) - return ENODEV; - if (!sc->pps[i].cap) - return ENODEV; - error = std_pps_ioctl(cmd, arg, &sc->pps[i].params, - &sc->pps[i].info, sc->pps[i].cap); - return (error); - } - - if (cmd == XRPU_IOC_TIMECOUNTING) { - struct xrpu_timecounting *xt = (struct xrpu_timecounting *)arg; - - /* Name SHALL be zero terminated */ - xt->xt_name[sizeof xt->xt_name - 1] = '\0'; - i = strlen(xt->xt_name); - sc->tc.tc_name = (char *)malloc(i + 1, M_XRPU, M_WAITOK); - strcpy(sc->tc.tc_name, xt->xt_name); - sc->tc.tc_frequency = xt->xt_frequency; - sc->tc.tc_get_timecount = xrpu_get_timecount; - sc->tc.tc_poll_pps = xrpu_poll_pps; - sc->tc.tc_priv = sc; - sc->tc.tc_counter_mask = xt->xt_mask; - sc->trigger = sc->virbase62 + xt->xt_addr_trigger; - sc->latch = sc->virbase62 + xt->xt_addr_latch; +/* + * Device driver initialization stuff + */ - for (i = 0; i < XRPU_MAX_PPS; i++) { - if (xt->xt_pps[i].xt_addr_assert == 0 - && xt->xt_pps[i].xt_addr_clear == 0) - continue; - devfs_add_devswf(&xrpudevsw, (i+1)<<16, DV_CHR, UID_ROOT, GID_WHEEL, 0600, - "xpps%d", i); - /* DEVFS */ - if (xt->xt_pps[i].xt_addr_assert) { - sc->pps[i].assert = sc->virbase62 + xt->xt_pps[i].xt_addr_assert; - sc->pps[i].cap |= PPS_CAPTUREASSERT | PPS_OFFSETASSERT; - } - if (xt->xt_pps[i].xt_addr_clear) { - sc->pps[i].clear = sc->virbase62 + xt->xt_pps[i].xt_addr_clear; - sc->pps[i].cap |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR; - } - } - sc->mode = TIMECOUNTER; - init_timecounter(&sc->tc); - return (0); - } - error = ENOTTY; - return (error); -} +#define CDEV_MAJOR 100 +static struct cdevsw xrpudevsw = { + xrpuopen, xrpuclose, noread, nowrite, + noioctl, nullstop, noreset, nodevtotty, + seltrue, xrpummap, nostrategy, "xrpu", + NULL, -1 +}; /* * PCI initialization stuff @@ -225,15 +78,13 @@ static struct pci_device xrpu_device = { DATA_SET (pcidevice_set, xrpu_device); -static const char* +static char* xrpu_probe (pcici_t tag, pcidi_t typea) { - u_int id; + int data = pci_conf_read(tag, PCI_CLASS_REG); + u_int id = pci_conf_read(tag, PCI_ID_REG); const char *vendor, *chip, *type; - (void)pci_conf_read(tag, PCI_CLASS_REG); - id = pci_conf_read(tag, PCI_ID_REG); - vendor = chip = type = 0; if (id == 0x6216133e) { @@ -245,27 +96,16 @@ xrpu_probe (pcici_t tag, pcidi_t typea) static void xrpu_attach (pcici_t tag, int unit) { - struct softc *sc; - dev_t cdev = makedev(CDEV_MAJOR, unit); - - sc = (struct softc *)malloc(sizeof *sc, M_XRPU, M_WAITOK); - softc[unit] = sc; - bzero(sc, sizeof *sc); - - sc->tag = tag; - sc->mode = NORMAL; - - pci_map_mem(tag, PCI_MAP_REG_START, &sc->virbase, &sc->physbase); + dev_t cdev = makedev(CDEV_MAJOR, 0); - sc->virbase62 = (u_int *)(sc->virbase + 0x800000); + pci_map_mem(tag, PCI_MAP_REG_START, &virbase, &physbase); - if (bootverbose) - printf("Mapped physbase %#lx to virbase %#lx\n", - (u_long)sc->physbase, (u_long)sc->virbase); + printf("Mapped physbase %#lx to virbase %#lx\n", + (u_long)physbase, (u_long)virbase); - if (!unit) - cdevsw_add(&cdev, &xrpudevsw, NULL); + cdevsw_add(&cdev, &xrpudevsw, NULL); devfs_add_devswf(&xrpudevsw, 0, DV_CHR, UID_ROOT, GID_WHEEL, 0600, - "xrpu%d", unit); + "xrpu0"); } +#endif /* DEVFS */ |