freebsd-dev/sys/dev/lmc/if_lmc_fbsd3.c
Poul-Henning Kamp 2a25c339c3 LanMedias driver sources for the LMC1000 and similar cards.
Does not yet compile yet.
2000-04-26 06:02:13 +00:00

275 lines
7.4 KiB
C

/* $FreeBSD$ */
/* $Id: if_lmc_fbsd.c,v 1.3 1999/01/12 13:27:42 explorer Exp $ */
/*-
* Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com)
* Copyright (c) LAN Media Corporation 1998, 1999.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software withough 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.
*/
/*
* This file is INCLUDED (gross, I know, but...)
*/
#define PCI_CONF_WRITE(r, v) pci_conf_write(config_id, (r), (v))
#define PCI_CONF_READ(r) pci_conf_read(config_id, (r))
#define PCI_GETBUSDEVINFO(sc) (sc)->lmc_pci_busno = (config_id->bus), \
(sc)->lmc_pci_devno = (config_id->slot)
static void lmc_shutdown(int howto, void * arg);
#if defined(LMC_DEVCONF)
static int
lmc_pci_shutdown(struct kern_devconf * const kdc, int force)
{
if (kdc->kdc_unit < LMC_MAX_DEVICES) {
lmc_softc_t * const sc = LMC_UNIT_TO_SOFTC(kdc->kdc_unit);
if (sc != NULL)
lmc_shutdown(0, sc);
}
(void) dev_detach(kdc);
return 0;
}
#endif
static char*
lmc_pci_probe(pcici_t config_id, pcidi_t device_id)
{
u_int32_t id;
/*
* check first for the DEC chip we expect to find. We expect
* 21140A, pass 2.2 or higher.
*/
if (PCI_VENDORID(device_id) != DEC_VENDORID)
return NULL;
if (PCI_CHIPID(device_id) != CHIPID_21140)
return NULL;
id = pci_conf_read(config_id, PCI_CFRV) & 0xff;
if (id < 0x22)
return NULL;
/*
* Next, check the subsystem ID and see if it matches what we
* expect.
*/
id = pci_conf_read(config_id, PCI_SSID);
if (PCI_VENDORID(id) != PCI_VENDOR_LMC)
return NULL;
if (PCI_CHIPID(id) == PCI_PRODUCT_LMC_HSSI) {
return "Lan Media Corporation HSSI";
}
if (PCI_CHIPID(id) == PCI_PRODUCT_LMC_DS3) {
return "Lan Media Corporation DS3";
}
if (PCI_CHIPID(id) == PCI_PRODUCT_LMC_SSI) {
return "Lan Media Corporation SSI";
}
if (PCI_CHIPID(id) == PCI_PRODUCT_LMC_T1) {
return "Lan Media Coporation T1";
}
return NULL;
}
static void lmc_pci_attach(pcici_t config_id, int unit);
static u_long lmc_pci_count;
struct pci_device lmcdevice = {
"lmc",
lmc_pci_probe,
lmc_pci_attach,
&lmc_pci_count,
#if defined(LMC_DEVCONF)
lmc_pci_shutdown,
#endif
};
DATA_SET (pcidevice_set, lmcdevice);
static void
lmc_pci_attach(pcici_t config_id, int unit)
{
lmc_softc_t *sc;
int retval, idx;
u_int32_t revinfo, cfdainfo, id, ssid;
#if !defined(LMC_IOMAPPED)
vm_offset_t pa_csrs;
#endif
unsigned csroffset = LMC_PCI_CSROFFSET;
unsigned csrsize = LMC_PCI_CSRSIZE;
lmc_csrptr_t csr_base;
lmc_spl_t s;
lmc_intrfunc_t (*intr_rtn)(void *) = lmc_intr_normal;
if (unit >= LMC_MAX_DEVICES) {
printf("lmc%d", unit);
printf(": not configured; limit of %d reached or exceeded\n",
LMC_MAX_DEVICES);
return;
}
/*
* allocate memory for the softc
*/
sc = (lmc_softc_t *) malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
if (sc == NULL)
return;
bzero(sc, sizeof(*sc)); /* Zero out the softc*/
revinfo = PCI_CONF_READ(PCI_CFRV) & 0xFF;
id = PCI_CONF_READ(PCI_CFID);
cfdainfo = PCI_CONF_READ(PCI_CFDA);
ssid = pci_conf_read(config_id, PCI_SSID);
switch (PCI_CHIPID(ssid)) {
case PCI_PRODUCT_LMC_HSSI:
sc->lmc_media = &lmc_hssi_media;
break;
case PCI_PRODUCT_LMC_DS3:
sc->lmc_media = &lmc_ds3_media;
break;
case PCI_PRODUCT_LMC_SSI:
sc->lmc_media = &lmc_ssi_media;
break;
case PCI_PRODUCT_LMC_T1:
sc->lmc_media = &lmc_t1_media;
break;
}
/*
* allocate memory for the device descriptors
*/
sc->lmc_rxdescs = (tulip_desc_t *)malloc(sizeof(tulip_desc_t) * LMC_RXDESCS, M_DEVBUF, M_NOWAIT);
sc->lmc_txdescs = (tulip_desc_t *)malloc(sizeof(tulip_desc_t) * LMC_TXDESCS, M_DEVBUF, M_NOWAIT);
if (sc->lmc_rxdescs == NULL || sc->lmc_txdescs == NULL) {
if (sc->lmc_rxdescs)
free((caddr_t) sc->lmc_rxdescs, M_DEVBUF);
if (sc->lmc_txdescs)
free((caddr_t) sc->lmc_txdescs, M_DEVBUF);
free((caddr_t) sc, M_DEVBUF);
return;
}
PCI_GETBUSDEVINFO(sc);
sc->lmc_chipid = LMC_21140A;
sc->lmc_features |= LMC_HAVE_STOREFWD;
if (sc->lmc_chipid == LMC_21140A && revinfo <= 0x22)
sc->lmc_features |= LMC_HAVE_RXBADOVRFLW;
if (cfdainfo & (TULIP_CFDA_SLEEP | TULIP_CFDA_SNOOZE)) {
cfdainfo &= ~(TULIP_CFDA_SLEEP | TULIP_CFDA_SNOOZE);
PCI_CONF_WRITE(PCI_CFDA, cfdainfo);
DELAY(11 * 1000);
}
sc->lmc_unit = unit;
sc->lmc_name = "lmc";
sc->lmc_revinfo = revinfo;
#if BSD >= 199506
sc->lmc_if.if_softc = sc;
#endif
#if defined(LMC_IOMAPPED)
retval = pci_map_port(config_id, PCI_CBIO, &csr_base);
#else
retval = pci_map_mem(config_id, PCI_CBMA, (vm_offset_t *) &csr_base,
&pa_csrs);
#endif
if (!retval) {
free((caddr_t) sc->lmc_rxdescs, M_DEVBUF);
free((caddr_t) sc->lmc_txdescs, M_DEVBUF);
free((caddr_t) sc, M_DEVBUF);
return;
}
tulips[unit] = sc;
lmc_initcsrs(sc, csr_base + csroffset, csrsize);
lmc_initring(sc, &sc->lmc_rxinfo, sc->lmc_rxdescs,
LMC_RXDESCS);
lmc_initring(sc, &sc->lmc_txinfo, sc->lmc_txdescs,
LMC_TXDESCS);
lmc_gpio_mkinput(sc, 0xff);
sc->lmc_gpio = 0; /* drive no signals yet */
sc->lmc_media->defaults(sc);
sc->lmc_media->set_link_status(sc, 0); /* down */
/*
* Make sure there won't be any interrupts or such...
*/
LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
/*
* Wait 10 microseconds (actually 50 PCI cycles but at
* 33MHz that comes to two microseconds but wait a
* bit longer anyways)
*/
DELAY(100);
switch (sc->ictl.cardtype) {
case LMC_CARDTYPE_HSSI:
printf(LMC_PRINTF_FMT ": HSSI, ", LMC_PRINTF_ARGS);
break;
case LMC_CARDTYPE_DS3:
printf(LMC_PRINTF_FMT ": DS3, ", LMC_PRINTF_ARGS);
break;
case LMC_CARDTYPE_SSI:
printf(LMC_PRINTF_FMT ": SSI, ", LMC_PRINTF_ARGS);
break;
}
lmc_read_macaddr(sc);
printf("pass %d.%d, serial " LMC_EADDR_FMT "\n",
(sc->lmc_revinfo & 0xF0) >> 4, sc->lmc_revinfo & 0x0F,
LMC_EADDR_ARGS(sc->lmc_enaddr));
if (!pci_map_int (config_id, intr_rtn, (void*) sc, &net_imask)) {
printf(LMC_PRINTF_FMT ": couldn't map interrupt\n",
LMC_PRINTF_ARGS);
return;
}
#if !defined(LMC_DEVCONF)
at_shutdown(lmc_shutdown, sc, SHUTDOWN_POST_SYNC);
#endif
s = LMC_RAISESPL();
lmc_dec_reset(sc);
lmc_reset(sc);
lmc_attach(sc);
LMC_RESTORESPL(s);
}
static void
lmc_shutdown(int howto, void * arg)
{
lmc_softc_t * const sc = arg;
LMC_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET);
DELAY(10);
sc->lmc_miireg16 = 0; /* deassert ready, and all others too */
printf("lmc: 5\n");
lmc_led_on(sc, LMC_MII16_LED_ALL);
}