aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/fatm/if_fatm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/fatm/if_fatm.c')
-rw-r--r--sys/dev/fatm/if_fatm.c3091
1 files changed, 0 insertions, 3091 deletions
diff --git a/sys/dev/fatm/if_fatm.c b/sys/dev/fatm/if_fatm.c
deleted file mode 100644
index 2a1dee685c3d..000000000000
--- a/sys/dev/fatm/if_fatm.c
+++ /dev/null
@@ -1,3091 +0,0 @@
-/*-
- * Copyright (c) 2001-2003
- * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
- * 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.
- *
- * Author: Hartmut Brandt <harti@freebsd.org>
- *
- * Fore PCA200E driver for NATM
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_inet.h"
-#include "opt_natm.h"
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/bus.h>
-#include <sys/errno.h>
-#include <sys/conf.h>
-#include <sys/module.h>
-#include <sys/queue.h>
-#include <sys/syslog.h>
-#include <sys/endian.h>
-#include <sys/sysctl.h>
-#include <sys/condvar.h>
-#include <vm/uma.h>
-
-#include <sys/sockio.h>
-#include <sys/mbuf.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/if_media.h>
-#include <net/if_types.h>
-#include <net/if_atm.h>
-#include <net/route.h>
-#ifdef ENABLE_BPF
-#include <net/bpf.h>
-#endif
-#ifdef INET
-#include <netinet/in.h>
-#include <netinet/if_atm.h>
-#endif
-
-#include <machine/bus.h>
-#include <machine/resource.h>
-#include <sys/bus.h>
-#include <sys/rman.h>
-#include <dev/pci/pcireg.h>
-#include <dev/pci/pcivar.h>
-
-#include <dev/utopia/utopia.h>
-
-#include <dev/fatm/if_fatmreg.h>
-#include <dev/fatm/if_fatmvar.h>
-
-#include <dev/fatm/firmware.h>
-
-devclass_t fatm_devclass;
-
-static const struct {
- uint16_t vid;
- uint16_t did;
- const char *name;
-} fatm_devs[] = {
- { 0x1127, 0x300,
- "FORE PCA200E" },
- { 0, 0, NULL }
-};
-
-static const struct rate {
- uint32_t ratio;
- uint32_t cell_rate;
-} rate_table[] = {
-#include <dev/fatm/if_fatm_rate.h>
-};
-#define RATE_TABLE_SIZE (sizeof(rate_table) / sizeof(rate_table[0]))
-
-SYSCTL_DECL(_hw_atm);
-
-MODULE_DEPEND(fatm, utopia, 1, 1, 1);
-
-static int fatm_utopia_readregs(struct ifatm *, u_int, uint8_t *, u_int *);
-static int fatm_utopia_writereg(struct ifatm *, u_int, u_int, u_int);
-
-static const struct utopia_methods fatm_utopia_methods = {
- fatm_utopia_readregs,
- fatm_utopia_writereg
-};
-
-#define VC_OK(SC, VPI, VCI) \
- (rounddown2(VPI, 1 << IFP2IFATM((SC)->ifp)->mib.vpi_bits) == 0 && \
- (VCI) != 0 && rounddown2(VCI, 1 << IFP2IFATM((SC)->ifp)->mib.vci_bits) == 0)
-
-static int fatm_load_vc(struct fatm_softc *sc, struct card_vcc *vc);
-
-/*
- * Probing is easy: step trough the list of known vendor and device
- * ids and compare. If one is found - it's our.
- */
-static int
-fatm_probe(device_t dev)
-{
- int i;
-
- for (i = 0; fatm_devs[i].name; i++)
- if (pci_get_vendor(dev) == fatm_devs[i].vid &&
- pci_get_device(dev) == fatm_devs[i].did) {
- device_set_desc(dev, fatm_devs[i].name);
- return (BUS_PROBE_DEFAULT);
- }
- return (ENXIO);
-}
-
-/*
- * Function called at completion of a SUNI writeregs/readregs command.
- * This is called from the interrupt handler while holding the softc lock.
- * We use the queue entry as the randevouze point.
- */
-static void
-fatm_utopia_writeregs_complete(struct fatm_softc *sc, struct cmdqueue *q)
-{
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if(H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
- sc->istats.suni_reg_errors++;
- q->error = EIO;
- }
- wakeup(q);
-}
-
-/*
- * Write a SUNI register. The bits that are 1 in mask are written from val
- * into register reg. We wait for the command to complete by sleeping on
- * the register memory.
- *
- * We assume, that we already hold the softc mutex.
- */
-static int
-fatm_utopia_writereg(struct ifatm *ifatm, u_int reg, u_int mask, u_int val)
-{
- int error;
- struct cmdqueue *q;
- struct fatm_softc *sc;
-
- sc = ifatm->ifp->if_softc;
- FATM_CHECKLOCK(sc);
- if (!(ifatm->ifp->if_drv_flags & IFF_DRV_RUNNING))
- return (EIO);
-
- /* get queue element and fill it */
- q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) {
- sc->istats.cmd_queue_full++;
- return (EIO);
- }
- NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN);
-
- q->error = 0;
- q->cb = fatm_utopia_writeregs_complete;
- H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
-
- WRITE4(sc, q->q.card + FATMOC_GETOC3_BUF, 0);
- BARRIER_W(sc);
- WRITE4(sc, q->q.card + FATMOC_OP,
- FATM_MAKE_SETOC3(reg, val, mask) | FATM_OP_INTERRUPT_SEL);
- BARRIER_W(sc);
-
- /*
- * Wait for the command to complete
- */
- error = msleep(q, &sc->mtx, PZERO | PCATCH, "fatm_setreg", hz);
-
- switch(error) {
-
- case EWOULDBLOCK:
- error = EIO;
- break;
-
- case ERESTART:
- error = EINTR;
- break;
-
- case 0:
- error = q->error;
- break;
- }
-
- return (error);
-}
-
-/*
- * Function called at completion of a SUNI readregs command.
- * This is called from the interrupt handler while holding the softc lock.
- * We use reg_mem as the randevouze point.
- */
-static void
-fatm_utopia_readregs_complete(struct fatm_softc *sc, struct cmdqueue *q)
-{
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
- sc->istats.suni_reg_errors++;
- q->error = EIO;
- }
- wakeup(&sc->reg_mem);
-}
-
-/*
- * Read SUNI registers
- *
- * We use a preallocated buffer to read the registers. Therefor we need
- * to protect against multiple threads trying to read registers. We do this
- * with a condition variable and a flag. We wait for the command to complete by sleeping on
- * the register memory.
- *
- * We assume, that we already hold the softc mutex.
- */
-static int
-fatm_utopia_readregs_internal(struct fatm_softc *sc)
-{
- int error, i;
- uint32_t *ptr;
- struct cmdqueue *q;
-
- /* get the buffer */
- for (;;) {
- if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING))
- return (EIO);
- if (!(sc->flags & FATM_REGS_INUSE))
- break;
- cv_wait(&sc->cv_regs, &sc->mtx);
- }
- sc->flags |= FATM_REGS_INUSE;
-
- q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) {
- sc->istats.cmd_queue_full++;
- return (EIO);
- }
- NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN);
-
- q->error = 0;
- q->cb = fatm_utopia_readregs_complete;
- H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
-
- bus_dmamap_sync(sc->reg_mem.dmat, sc->reg_mem.map, BUS_DMASYNC_PREREAD);
-
- WRITE4(sc, q->q.card + FATMOC_GETOC3_BUF, sc->reg_mem.paddr);
- BARRIER_W(sc);
- WRITE4(sc, q->q.card + FATMOC_OP,
- FATM_OP_OC3_GET_REG | FATM_OP_INTERRUPT_SEL);
- BARRIER_W(sc);
-
- /*
- * Wait for the command to complete
- */
- error = msleep(&sc->reg_mem, &sc->mtx, PZERO | PCATCH,
- "fatm_getreg", hz);
-
- switch(error) {
-
- case EWOULDBLOCK:
- error = EIO;
- break;
-
- case ERESTART:
- error = EINTR;
- break;
-
- case 0:
- bus_dmamap_sync(sc->reg_mem.dmat, sc->reg_mem.map,
- BUS_DMASYNC_POSTREAD);
- error = q->error;
- break;
- }
-
- if (error != 0) {
- /* declare buffer to be free */
- sc->flags &= ~FATM_REGS_INUSE;
- cv_signal(&sc->cv_regs);
- return (error);
- }
-
- /* swap if needed */
- ptr = (uint32_t *)sc->reg_mem.mem;
- for (i = 0; i < FATM_NREGS; i++)
- ptr[i] = le32toh(ptr[i]) & 0xff;
-
- return (0);
-}
-
-/*
- * Read SUNI registers for the SUNI module.
- *
- * We assume, that we already hold the mutex.
- */
-static int
-fatm_utopia_readregs(struct ifatm *ifatm, u_int reg, uint8_t *valp, u_int *np)
-{
- int err;
- int i;
- struct fatm_softc *sc;
-
- if (reg >= FATM_NREGS)
- return (EINVAL);
- if (reg + *np > FATM_NREGS)
- *np = FATM_NREGS - reg;
- sc = ifatm->ifp->if_softc;
- FATM_CHECKLOCK(sc);
-
- err = fatm_utopia_readregs_internal(sc);
- if (err != 0)
- return (err);
-
- for (i = 0; i < *np; i++)
- valp[i] = ((uint32_t *)sc->reg_mem.mem)[reg + i];
-
- /* declare buffer to be free */
- sc->flags &= ~FATM_REGS_INUSE;
- cv_signal(&sc->cv_regs);
-
- return (0);
-}
-
-/*
- * Check whether the hard is beating. We remember the last heart beat and
- * compare it to the current one. If it appears stuck for 10 times, we have
- * a problem.
- *
- * Assume we hold the lock.
- */
-static void
-fatm_check_heartbeat(struct fatm_softc *sc)
-{
- uint32_t h;
-
- FATM_CHECKLOCK(sc);
-
- h = READ4(sc, FATMO_HEARTBEAT);
- DBG(sc, BEAT, ("heartbeat %08x", h));
-
- if (sc->stop_cnt == 10)
- return;
-
- if (h == sc->heartbeat) {
- if (++sc->stop_cnt == 10) {
- log(LOG_ERR, "i960 stopped???\n");
- WRITE4(sc, FATMO_HIMR, 1);
- }
- return;
- }
-
- sc->stop_cnt = 0;
- sc->heartbeat = h;
-}
-
-/*
- * Ensure that the heart is still beating.
- */
-static void
-fatm_watchdog(void *arg)
-{
- struct fatm_softc *sc;
-
- sc = arg;
- FATM_CHECKLOCK(sc);
- fatm_check_heartbeat(sc);
- callout_reset(&sc->watchdog_timer, hz * 5, fatm_watchdog, sc);
-}
-
-/*
- * Hard reset the i960 on the board. This is done by initializing registers,
- * clearing interrupts and waiting for the selftest to finish. Not sure,
- * whether all these barriers are actually needed.
- *
- * Assumes that we hold the lock.
- */
-static int
-fatm_reset(struct fatm_softc *sc)
-{
- int w;
- uint32_t val;
-
- FATM_CHECKLOCK(sc);
-
- WRITE4(sc, FATMO_APP_BASE, FATMO_COMMON_ORIGIN);
- BARRIER_W(sc);
-
- WRITE4(sc, FATMO_UART_TO_960, XMIT_READY);
- BARRIER_W(sc);
-
- WRITE4(sc, FATMO_UART_TO_HOST, XMIT_READY);
- BARRIER_W(sc);
-
- WRITE4(sc, FATMO_BOOT_STATUS, COLD_START);
- BARRIER_W(sc);
-
- WRITE1(sc, FATMO_HCR, FATM_HCR_RESET);
- BARRIER_W(sc);
-
- DELAY(1000);
-
- WRITE1(sc, FATMO_HCR, 0);
- BARRIER_RW(sc);
-
- DELAY(1000);
-
- for (w = 100; w; w--) {
- BARRIER_R(sc);
- val = READ4(sc, FATMO_BOOT_STATUS);
- switch (val) {
- case SELF_TEST_OK:
- return (0);
- case SELF_TEST_FAIL:
- return (EIO);
- }
- DELAY(1000);
- }
- return (EIO);
-}
-
-/*
- * Stop the card. Must be called WITH the lock held
- * Reset, free transmit and receive buffers. Wakeup everybody who may sleep.
- */
-static void
-fatm_stop(struct fatm_softc *sc)
-{
- int i;
- struct cmdqueue *q;
- struct rbuf *rb;
- struct txqueue *tx;
- uint32_t stat;
-
- FATM_CHECKLOCK(sc);
-
- /* Stop the board */
- utopia_stop(&sc->utopia);
- (void)fatm_reset(sc);
-
- /* stop watchdog */
- callout_stop(&sc->watchdog_timer);
-
- if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) {
- sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
- ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp),
- sc->utopia.carrier == UTP_CARR_OK);
-
- /*
- * Collect transmit mbufs, partial receive mbufs and
- * supplied mbufs
- */
- for (i = 0; i < FATM_TX_QLEN; i++) {
- tx = GET_QUEUE(sc->txqueue, struct txqueue, i);
- if (tx->m) {
- bus_dmamap_unload(sc->tx_tag, tx->map);
- m_freem(tx->m);
- tx->m = NULL;
- }
- }
-
- /* Collect supplied mbufs */
- while ((rb = LIST_FIRST(&sc->rbuf_used)) != NULL) {
- LIST_REMOVE(rb, link);
- bus_dmamap_unload(sc->rbuf_tag, rb->map);
- m_free(rb->m);
- rb->m = NULL;
- LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
- }
-
- /* Unwait any waiters */
- wakeup(&sc->sadi_mem);
-
- /* wakeup all threads waiting for STAT or REG buffers */
- cv_broadcast(&sc->cv_stat);
- cv_broadcast(&sc->cv_regs);
-
- sc->flags &= ~(FATM_STAT_INUSE | FATM_REGS_INUSE);
-
- /* wakeup all threads waiting on commands */
- for (i = 0; i < FATM_CMD_QLEN; i++) {
- q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, i);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if ((stat = H_GETSTAT(q->q.statp)) != FATM_STAT_FREE) {
- H_SETSTAT(q->q.statp, stat | FATM_STAT_ERROR);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
- wakeup(q);
- }
- }
- utopia_reset_media(&sc->utopia);
- }
- sc->small_cnt = sc->large_cnt = 0;
-
- /* Reset vcc info */
- if (sc->vccs != NULL) {
- sc->open_vccs = 0;
- for (i = 0; i < FORE_MAX_VCC + 1; i++) {
- if (sc->vccs[i] != NULL) {
- if ((sc->vccs[i]->vflags & (FATM_VCC_OPEN |
- FATM_VCC_TRY_OPEN)) == 0) {
- uma_zfree(sc->vcc_zone, sc->vccs[i]);
- sc->vccs[i] = NULL;
- } else {
- sc->vccs[i]->vflags = 0;
- sc->open_vccs++;
- }
- }
- }
- }
-
-}
-
-/*
- * Load the firmware into the board and save the entry point.
- */
-static uint32_t
-firmware_load(struct fatm_softc *sc)
-{
- struct firmware *fw = (struct firmware *)firmware;
-
- DBG(sc, INIT, ("loading - entry=%x", fw->entry));
- bus_space_write_region_4(sc->memt, sc->memh, fw->offset, firmware,
- sizeof(firmware) / sizeof(firmware[0]));
- BARRIER_RW(sc);
-
- return (fw->entry);
-}
-
-/*
- * Read a character from the virtual UART. The availability of a character
- * is signaled by a non-null value of the 32 bit register. The eating of
- * the character by us is signalled to the card by setting that register
- * to zero.
- */
-static int
-rx_getc(struct fatm_softc *sc)
-{
- int w = 50;
- int c;
-
- while (w--) {
- c = READ4(sc, FATMO_UART_TO_HOST);
- BARRIER_RW(sc);
- if (c != 0) {
- WRITE4(sc, FATMO_UART_TO_HOST, 0);
- DBGC(sc, UART, ("%c", c & 0xff));
- return (c & 0xff);
- }
- DELAY(1000);
- }
- return (-1);
-}
-
-/*
- * Eat up characters from the board and stuff them in the bit-bucket.
- */
-static void
-rx_flush(struct fatm_softc *sc)
-{
- int w = 10000;
-
- while (w-- && rx_getc(sc) >= 0)
- ;
-}
-
-/*
- * Write a character to the card. The UART is available if the register
- * is zero.
- */
-static int
-tx_putc(struct fatm_softc *sc, u_char c)
-{
- int w = 10;
- int c1;
-
- while (w--) {
- c1 = READ4(sc, FATMO_UART_TO_960);
- BARRIER_RW(sc);
- if (c1 == 0) {
- WRITE4(sc, FATMO_UART_TO_960, c | CHAR_AVAIL);
- DBGC(sc, UART, ("%c", c & 0xff));
- return (0);
- }
- DELAY(1000);
- }
- return (-1);
-}
-
-/*
- * Start the firmware. This is doing by issuing a 'go' command with
- * the hex entry address of the firmware. Then we wait for the self-test to
- * succeed.
- */
-static int
-fatm_start_firmware(struct fatm_softc *sc, uint32_t start)
-{
- static char hex[] = "0123456789abcdef";
- u_int w, val;
-
- DBG(sc, INIT, ("starting"));
- rx_flush(sc);
- tx_putc(sc, '\r');
- DELAY(1000);
-
- rx_flush(sc);
-
- tx_putc(sc, 'g');
- (void)rx_getc(sc);
- tx_putc(sc, 'o');
- (void)rx_getc(sc);
- tx_putc(sc, ' ');
- (void)rx_getc(sc);
-
- tx_putc(sc, hex[(start >> 12) & 0xf]);
- (void)rx_getc(sc);
- tx_putc(sc, hex[(start >> 8) & 0xf]);
- (void)rx_getc(sc);
- tx_putc(sc, hex[(start >> 4) & 0xf]);
- (void)rx_getc(sc);
- tx_putc(sc, hex[(start >> 0) & 0xf]);
- (void)rx_getc(sc);
-
- tx_putc(sc, '\r');
- rx_flush(sc);
-
- for (w = 100; w; w--) {
- BARRIER_R(sc);
- val = READ4(sc, FATMO_BOOT_STATUS);
- switch (val) {
- case CP_RUNNING:
- return (0);
- case SELF_TEST_FAIL:
- return (EIO);
- }
- DELAY(1000);
- }
- return (EIO);
-}
-
-/*
- * Initialize one card and host queue.
- */
-static void
-init_card_queue(struct fatm_softc *sc, struct fqueue *queue, int qlen,
- size_t qel_size, size_t desc_size, cardoff_t off,
- u_char **statpp, uint32_t *cardstat, u_char *descp, uint32_t carddesc)
-{
- struct fqelem *el = queue->chunk;
-
- while (qlen--) {
- el->card = off;
- off += 8; /* size of card entry */
-
- el->statp = (uint32_t *)(*statpp);
- (*statpp) += sizeof(uint32_t);
- H_SETSTAT(el->statp, FATM_STAT_FREE);
- H_SYNCSTAT_PREWRITE(sc, el->statp);
-
- WRITE4(sc, el->card + FATMOS_STATP, (*cardstat));
- (*cardstat) += sizeof(uint32_t);
-
- el->ioblk = descp;
- descp += desc_size;
- el->card_ioblk = carddesc;
- carddesc += desc_size;
-
- el = (struct fqelem *)((u_char *)el + qel_size);
- }
- queue->tail = queue->head = 0;
-}
-
-/*
- * Issue the initialize operation to the card, wait for completion and
- * initialize the on-board and host queue structures with offsets and
- * addresses.
- */
-static int
-fatm_init_cmd(struct fatm_softc *sc)
-{
- int w, c;
- u_char *statp;
- uint32_t card_stat;
- u_int cnt;
- struct fqelem *el;
- cardoff_t off;
-
- DBG(sc, INIT, ("command"));
- WRITE4(sc, FATMO_ISTAT, 0);
- WRITE4(sc, FATMO_IMASK, 1);
- WRITE4(sc, FATMO_HLOGGER, 0);
-
- WRITE4(sc, FATMO_INIT + FATMOI_RECEIVE_TRESHOLD, 0);
- WRITE4(sc, FATMO_INIT + FATMOI_NUM_CONNECT, FORE_MAX_VCC);
- WRITE4(sc, FATMO_INIT + FATMOI_CQUEUE_LEN, FATM_CMD_QLEN);
- WRITE4(sc, FATMO_INIT + FATMOI_TQUEUE_LEN, FATM_TX_QLEN);
- WRITE4(sc, FATMO_INIT + FATMOI_RQUEUE_LEN, FATM_RX_QLEN);
- WRITE4(sc, FATMO_INIT + FATMOI_RPD_EXTENSION, RPD_EXTENSIONS);
- WRITE4(sc, FATMO_INIT + FATMOI_TPD_EXTENSION, TPD_EXTENSIONS);
-
- /*
- * initialize buffer descriptors
- */
- WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_QUEUE_LENGTH,
- SMALL_SUPPLY_QLEN);
- WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_BUFFER_SIZE,
- SMALL_BUFFER_LEN);
- WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_POOL_SIZE,
- SMALL_POOL_SIZE);
- WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_SUPPLY_BLKSIZE,
- SMALL_SUPPLY_BLKSIZE);
-
- WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_QUEUE_LENGTH,
- LARGE_SUPPLY_QLEN);
- WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_BUFFER_SIZE,
- LARGE_BUFFER_LEN);
- WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_POOL_SIZE,
- LARGE_POOL_SIZE);
- WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_SUPPLY_BLKSIZE,
- LARGE_SUPPLY_BLKSIZE);
-
- WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_QUEUE_LENGTH, 0);
- WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_BUFFER_SIZE, 0);
- WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_POOL_SIZE, 0);
- WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_SUPPLY_BLKSIZE, 0);
-
- WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_QUEUE_LENGTH, 0);
- WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_BUFFER_SIZE, 0);
- WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_POOL_SIZE, 0);
- WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_SUPPLY_BLKSIZE, 0);
-
- /*
- * Start the command
- */
- BARRIER_W(sc);
- WRITE4(sc, FATMO_INIT + FATMOI_STATUS, FATM_STAT_PENDING);
- BARRIER_W(sc);
- WRITE4(sc, FATMO_INIT + FATMOI_OP, FATM_OP_INITIALIZE);
- BARRIER_W(sc);
-
- /*
- * Busy wait for completion
- */
- w = 100;
- while (w--) {
- c = READ4(sc, FATMO_INIT + FATMOI_STATUS);
- BARRIER_R(sc);
- if (c & FATM_STAT_COMPLETE)
- break;
- DELAY(1000);
- }
-
- if (c & FATM_STAT_ERROR)
- return (EIO);
-
- /*
- * Initialize the queues
- */
- statp = sc->stat_mem.mem;
- card_stat = sc->stat_mem.paddr;
-
- /*
- * Command queue. This is special in that it's on the card.
- */
- el = sc->cmdqueue.chunk;
- off = READ4(sc, FATMO_COMMAND_QUEUE);
- DBG(sc, INIT, ("cmd queue=%x", off));
- for (cnt = 0; cnt < FATM_CMD_QLEN; cnt++) {
- el = &((struct cmdqueue *)sc->cmdqueue.chunk + cnt)->q;
-
- el->card = off;
- off += 32; /* size of card structure */
-
- el->statp = (uint32_t *)statp;
- statp += sizeof(uint32_t);
- H_SETSTAT(el->statp, FATM_STAT_FREE);
- H_SYNCSTAT_PREWRITE(sc, el->statp);
-
- WRITE4(sc, el->card + FATMOC_STATP, card_stat);
- card_stat += sizeof(uint32_t);
- }
- sc->cmdqueue.tail = sc->cmdqueue.head = 0;
-
- /*
- * Now the other queues. These are in memory
- */
- init_card_queue(sc, &sc->txqueue, FATM_TX_QLEN,
- sizeof(struct txqueue), TPD_SIZE,
- READ4(sc, FATMO_TRANSMIT_QUEUE),
- &statp, &card_stat, sc->txq_mem.mem, sc->txq_mem.paddr);
-
- init_card_queue(sc, &sc->rxqueue, FATM_RX_QLEN,
- sizeof(struct rxqueue), RPD_SIZE,
- READ4(sc, FATMO_RECEIVE_QUEUE),
- &statp, &card_stat, sc->rxq_mem.mem, sc->rxq_mem.paddr);
-
- init_card_queue(sc, &sc->s1queue, SMALL_SUPPLY_QLEN,
- sizeof(struct supqueue), BSUP_BLK2SIZE(SMALL_SUPPLY_BLKSIZE),
- READ4(sc, FATMO_SMALL_B1_QUEUE),
- &statp, &card_stat, sc->s1q_mem.mem, sc->s1q_mem.paddr);
-
- init_card_queue(sc, &sc->l1queue, LARGE_SUPPLY_QLEN,
- sizeof(struct supqueue), BSUP_BLK2SIZE(LARGE_SUPPLY_BLKSIZE),
- READ4(sc, FATMO_LARGE_B1_QUEUE),
- &statp, &card_stat, sc->l1q_mem.mem, sc->l1q_mem.paddr);
-
- sc->txcnt = 0;
-
- return (0);
-}
-
-/*
- * Read PROM. Called only from attach code. Here we spin because the interrupt
- * handler is not yet set up.
- */
-static int
-fatm_getprom(struct fatm_softc *sc)
-{
- int i;
- struct prom *prom;
- struct cmdqueue *q;
-
- DBG(sc, INIT, ("reading prom"));
- q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head);
- NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN);
-
- q->error = 0;
- q->cb = NULL;
- H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
-
- bus_dmamap_sync(sc->prom_mem.dmat, sc->prom_mem.map,
- BUS_DMASYNC_PREREAD);
-
- WRITE4(sc, q->q.card + FATMOC_GPROM_BUF, sc->prom_mem.paddr);
- BARRIER_W(sc);
- WRITE4(sc, q->q.card + FATMOC_OP, FATM_OP_GET_PROM_DATA);
- BARRIER_W(sc);
-
- for (i = 0; i < 1000; i++) {
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (H_GETSTAT(q->q.statp) &
- (FATM_STAT_COMPLETE | FATM_STAT_ERROR))
- break;
- DELAY(1000);
- }
- if (i == 1000) {
- if_printf(sc->ifp, "getprom timeout\n");
- return (EIO);
- }
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
- if_printf(sc->ifp, "getprom error\n");
- return (EIO);
- }
- H_SETSTAT(q->q.statp, FATM_STAT_FREE);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
- NEXT_QUEUE_ENTRY(sc->cmdqueue.tail, FATM_CMD_QLEN);
-
- bus_dmamap_sync(sc->prom_mem.dmat, sc->prom_mem.map,
- BUS_DMASYNC_POSTREAD);
-
-
-#ifdef notdef
- {
- u_int i;
-
- printf("PROM: ");
- u_char *ptr = (u_char *)sc->prom_mem.mem;
- for (i = 0; i < sizeof(struct prom); i++)
- printf("%02x ", *ptr++);
- printf("\n");
- }
-#endif
-
- prom = (struct prom *)sc->prom_mem.mem;
-
- bcopy(prom->mac + 2, IFP2IFATM(sc->ifp)->mib.esi, 6);
- IFP2IFATM(sc->ifp)->mib.serial = le32toh(prom->serial);
- IFP2IFATM(sc->ifp)->mib.hw_version = le32toh(prom->version);
- IFP2IFATM(sc->ifp)->mib.sw_version = READ4(sc, FATMO_FIRMWARE_RELEASE);
-
- if_printf(sc->ifp, "ESI=%02x:%02x:%02x:%02x:%02x:%02x "
- "serial=%u hw=0x%x sw=0x%x\n", IFP2IFATM(sc->ifp)->mib.esi[0],
- IFP2IFATM(sc->ifp)->mib.esi[1], IFP2IFATM(sc->ifp)->mib.esi[2], IFP2IFATM(sc->ifp)->mib.esi[3],
- IFP2IFATM(sc->ifp)->mib.esi[4], IFP2IFATM(sc->ifp)->mib.esi[5], IFP2IFATM(sc->ifp)->mib.serial,
- IFP2IFATM(sc->ifp)->mib.hw_version, IFP2IFATM(sc->ifp)->mib.sw_version);
-
- return (0);
-}
-
-/*
- * This is the callback function for bus_dmamap_load. We assume, that we
- * have a 32-bit bus and so have always one segment.
- */
-static void
-dmaload_helper(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
-{
- bus_addr_t *ptr = (bus_addr_t *)arg;
-
- if (error != 0) {
- printf("%s: error=%d\n", __func__, error);
- return;
- }
- KASSERT(nsegs == 1, ("too many DMA segments"));
- KASSERT(segs[0].ds_addr <= 0xffffffff, ("DMA address too large %lx",
- (u_long)segs[0].ds_addr));
-
- *ptr = segs[0].ds_addr;
-}
-
-/*
- * Allocate a chunk of DMA-able memory and map it.
- */
-static int
-alloc_dma_memory(struct fatm_softc *sc, const char *nm, struct fatm_mem *mem)
-{
- int error;
-
- mem->mem = NULL;
-
- if (bus_dma_tag_create(sc->parent_dmat, mem->align, 0,
- BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
- NULL, NULL, mem->size, 1, BUS_SPACE_MAXSIZE_32BIT,
- BUS_DMA_ALLOCNOW, NULL, NULL, &mem->dmat)) {
- if_printf(sc->ifp, "could not allocate %s DMA tag\n",
- nm);
- return (ENOMEM);
- }
-
- error = bus_dmamem_alloc(mem->dmat, &mem->mem, 0, &mem->map);
- if (error) {
- if_printf(sc->ifp, "could not allocate %s DMA memory: "
- "%d\n", nm, error);
- bus_dma_tag_destroy(mem->dmat);
- mem->mem = NULL;
- return (error);
- }
-
- error = bus_dmamap_load(mem->dmat, mem->map, mem->mem, mem->size,
- dmaload_helper, &mem->paddr, BUS_DMA_NOWAIT);
- if (error) {
- if_printf(sc->ifp, "could not load %s DMA memory: "
- "%d\n", nm, error);
- bus_dmamem_free(mem->dmat, mem->mem, mem->map);
- bus_dma_tag_destroy(mem->dmat);
- mem->mem = NULL;
- return (error);
- }
-
- DBG(sc, DMA, ("DMA %s V/P/S/Z %p/%lx/%x/%x", nm, mem->mem,
- (u_long)mem->paddr, mem->size, mem->align));
-
- return (0);
-}
-
-#ifdef TEST_DMA_SYNC
-static int
-alloc_dma_memoryX(struct fatm_softc *sc, const char *nm, struct fatm_mem *mem)
-{
- int error;
-
- mem->mem = NULL;
-
- if (bus_dma_tag_create(NULL, mem->align, 0,
- BUS_SPACE_MAXADDR_24BIT, BUS_SPACE_MAXADDR,
- NULL, NULL, mem->size, 1, mem->size,
- BUS_DMA_ALLOCNOW, NULL, NULL, &mem->dmat)) {
- if_printf(sc->ifp, "could not allocate %s DMA tag\n",
- nm);
- return (ENOMEM);
- }
-
- mem->mem = contigmalloc(mem->size, M_DEVBUF, M_WAITOK,
- BUS_SPACE_MAXADDR_24BIT, BUS_SPACE_MAXADDR_32BIT, mem->align, 0);
-
- error = bus_dmamap_create(mem->dmat, 0, &mem->map);
- if (error) {
- if_printf(sc->ifp, "could not allocate %s DMA map: "
- "%d\n", nm, error);
- contigfree(mem->mem, mem->size, M_DEVBUF);
- bus_dma_tag_destroy(mem->dmat);
- mem->mem = NULL;
- return (error);
- }
-
- error = bus_dmamap_load(mem->dmat, mem->map, mem->mem, mem->size,
- dmaload_helper, &mem->paddr, BUS_DMA_NOWAIT);
- if (error) {
- if_printf(sc->ifp, "could not load %s DMA memory: "
- "%d\n", nm, error);
- bus_dmamap_destroy(mem->dmat, mem->map);
- contigfree(mem->mem, mem->size, M_DEVBUF);
- bus_dma_tag_destroy(mem->dmat);
- mem->mem = NULL;
- return (error);
- }
-
- DBG(sc, DMA, ("DMAX %s V/P/S/Z %p/%lx/%x/%x", nm, mem->mem,
- (u_long)mem->paddr, mem->size, mem->align));
-
- printf("DMAX: %s V/P/S/Z %p/%lx/%x/%x", nm, mem->mem,
- (u_long)mem->paddr, mem->size, mem->align);
-
- return (0);
-}
-#endif /* TEST_DMA_SYNC */
-
-/*
- * Destroy all resources of an dma-able memory chunk
- */
-static void
-destroy_dma_memory(struct fatm_mem *mem)
-{
- if (mem->mem != NULL) {
- bus_dmamap_unload(mem->dmat, mem->map);
- bus_dmamem_free(mem->dmat, mem->mem, mem->map);
- bus_dma_tag_destroy(mem->dmat);
- mem->mem = NULL;
- }
-}
-#ifdef TEST_DMA_SYNC
-static void
-destroy_dma_memoryX(struct fatm_mem *mem)
-{
- if (mem->mem != NULL) {
- bus_dmamap_unload(mem->dmat, mem->map);
- bus_dmamap_destroy(mem->dmat, mem->map);
- contigfree(mem->mem, mem->size, M_DEVBUF);
- bus_dma_tag_destroy(mem->dmat);
- mem->mem = NULL;
- }
-}
-#endif /* TEST_DMA_SYNC */
-
-/*
- * Try to supply buffers to the card if there are free entries in the queues
- */
-static void
-fatm_supply_small_buffers(struct fatm_softc *sc)
-{
- int nblocks, nbufs;
- struct supqueue *q;
- struct rbd *bd;
- int i, j, error, cnt;
- struct mbuf *m;
- struct rbuf *rb;
- bus_addr_t phys;
-
- nbufs = max(4 * sc->open_vccs, 32);
- nbufs = min(nbufs, SMALL_POOL_SIZE);
- nbufs -= sc->small_cnt;
-
- nblocks = howmany(nbufs, SMALL_SUPPLY_BLKSIZE);
- for (cnt = 0; cnt < nblocks; cnt++) {
- q = GET_QUEUE(sc->s1queue, struct supqueue, sc->s1queue.head);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE)
- break;
-
- bd = (struct rbd *)q->q.ioblk;
-
- for (i = 0; i < SMALL_SUPPLY_BLKSIZE; i++) {
- if ((rb = LIST_FIRST(&sc->rbuf_free)) == NULL) {
- if_printf(sc->ifp, "out of rbufs\n");
- break;
- }
- MGETHDR(m, M_NOWAIT, MT_DATA);
- if (m == NULL) {
- LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
- break;
- }
- M_ALIGN(m, SMALL_BUFFER_LEN);
- error = bus_dmamap_load(sc->rbuf_tag, rb->map,
- m->m_data, SMALL_BUFFER_LEN, dmaload_helper,
- &phys, BUS_DMA_NOWAIT);
- if (error) {
- if_printf(sc->ifp,
- "dmamap_load mbuf failed %d", error);
- m_freem(m);
- LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
- break;
- }
- bus_dmamap_sync(sc->rbuf_tag, rb->map,
- BUS_DMASYNC_PREREAD);
-
- LIST_REMOVE(rb, link);
- LIST_INSERT_HEAD(&sc->rbuf_used, rb, link);
-
- rb->m = m;
- bd[i].handle = rb - sc->rbufs;
- H_SETDESC(bd[i].buffer, phys);
- }
-
- if (i < SMALL_SUPPLY_BLKSIZE) {
- for (j = 0; j < i; j++) {
- rb = sc->rbufs + bd[j].handle;
- bus_dmamap_unload(sc->rbuf_tag, rb->map);
- m_free(rb->m);
- rb->m = NULL;
-
- LIST_REMOVE(rb, link);
- LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
- }
- break;
- }
- H_SYNCQ_PREWRITE(&sc->s1q_mem, bd,
- sizeof(struct rbd) * SMALL_SUPPLY_BLKSIZE);
-
- H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
-
- WRITE4(sc, q->q.card, q->q.card_ioblk);
- BARRIER_W(sc);
-
- sc->small_cnt += SMALL_SUPPLY_BLKSIZE;
-
- NEXT_QUEUE_ENTRY(sc->s1queue.head, SMALL_SUPPLY_QLEN);
- }
-}
-
-/*
- * Try to supply buffers to the card if there are free entries in the queues
- * We assume that all buffers are within the address space accessible by the
- * card (32-bit), so we don't need bounce buffers.
- */
-static void
-fatm_supply_large_buffers(struct fatm_softc *sc)
-{
- int nbufs, nblocks, cnt;
- struct supqueue *q;
- struct rbd *bd;
- int i, j, error;
- struct mbuf *m;
- struct rbuf *rb;
- bus_addr_t phys;
-
- nbufs = max(4 * sc->open_vccs, 32);
- nbufs = min(nbufs, LARGE_POOL_SIZE);
- nbufs -= sc->large_cnt;
-
- nblocks = howmany(nbufs, LARGE_SUPPLY_BLKSIZE);
-
- for (cnt = 0; cnt < nblocks; cnt++) {
- q = GET_QUEUE(sc->l1queue, struct supqueue, sc->l1queue.head);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE)
- break;
-
- bd = (struct rbd *)q->q.ioblk;
-
- for (i = 0; i < LARGE_SUPPLY_BLKSIZE; i++) {
- if ((rb = LIST_FIRST(&sc->rbuf_free)) == NULL) {
- if_printf(sc->ifp, "out of rbufs\n");
- break;
- }
- if ((m = m_getcl(M_NOWAIT, MT_DATA,
- M_PKTHDR)) == NULL) {
- LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
- break;
- }
- /* No MEXT_ALIGN */
- m->m_data += MCLBYTES - LARGE_BUFFER_LEN;
- error = bus_dmamap_load(sc->rbuf_tag, rb->map,
- m->m_data, LARGE_BUFFER_LEN, dmaload_helper,
- &phys, BUS_DMA_NOWAIT);
- if (error) {
- if_printf(sc->ifp,
- "dmamap_load mbuf failed %d", error);
- m_freem(m);
- LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
- break;
- }
-
- bus_dmamap_sync(sc->rbuf_tag, rb->map,
- BUS_DMASYNC_PREREAD);
-
- LIST_REMOVE(rb, link);
- LIST_INSERT_HEAD(&sc->rbuf_used, rb, link);
-
- rb->m = m;
- bd[i].handle = rb - sc->rbufs;
- H_SETDESC(bd[i].buffer, phys);
- }
-
- if (i < LARGE_SUPPLY_BLKSIZE) {
- for (j = 0; j < i; j++) {
- rb = sc->rbufs + bd[j].handle;
- bus_dmamap_unload(sc->rbuf_tag, rb->map);
- m_free(rb->m);
- rb->m = NULL;
-
- LIST_REMOVE(rb, link);
- LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
- }
- break;
- }
- H_SYNCQ_PREWRITE(&sc->l1q_mem, bd,
- sizeof(struct rbd) * LARGE_SUPPLY_BLKSIZE);
-
- H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
- WRITE4(sc, q->q.card, q->q.card_ioblk);
- BARRIER_W(sc);
-
- sc->large_cnt += LARGE_SUPPLY_BLKSIZE;
-
- NEXT_QUEUE_ENTRY(sc->l1queue.head, LARGE_SUPPLY_QLEN);
- }
-}
-
-
-/*
- * Actually start the card. The lock must be held here.
- * Reset, load the firmware, start it, initializes queues, read the PROM
- * and supply receive buffers to the card.
- */
-static void
-fatm_init_locked(struct fatm_softc *sc)
-{
- struct rxqueue *q;
- int i, c, error;
- uint32_t start;
-
- DBG(sc, INIT, ("initialize"));
- if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING)
- fatm_stop(sc);
-
- /*
- * Hard reset the board
- */
- if (fatm_reset(sc))
- return;
-
- start = firmware_load(sc);
- if (fatm_start_firmware(sc, start) || fatm_init_cmd(sc) ||
- fatm_getprom(sc)) {
- fatm_reset(sc);
- return;
- }
-
- /*
- * Handle media
- */
- c = READ4(sc, FATMO_MEDIA_TYPE);
- switch (c) {
-
- case FORE_MT_TAXI_100:
- IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_TAXI_100;
- IFP2IFATM(sc->ifp)->mib.pcr = 227273;
- break;
-
- case FORE_MT_TAXI_140:
- IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_TAXI_140;
- IFP2IFATM(sc->ifp)->mib.pcr = 318181;
- break;
-
- case FORE_MT_UTP_SONET:
- IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UTP_155;
- IFP2IFATM(sc->ifp)->mib.pcr = 353207;
- break;
-
- case FORE_MT_MM_OC3_ST:
- case FORE_MT_MM_OC3_SC:
- IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_MM_155;
- IFP2IFATM(sc->ifp)->mib.pcr = 353207;
- break;
-
- case FORE_MT_SM_OC3_ST:
- case FORE_MT_SM_OC3_SC:
- IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_SM_155;
- IFP2IFATM(sc->ifp)->mib.pcr = 353207;
- break;
-
- default:
- log(LOG_ERR, "fatm: unknown media type %d\n", c);
- IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UNKNOWN;
- IFP2IFATM(sc->ifp)->mib.pcr = 353207;
- break;
- }
- sc->ifp->if_baudrate = 53 * 8 * IFP2IFATM(sc->ifp)->mib.pcr;
- utopia_init_media(&sc->utopia);
-
- /*
- * Initialize the RBDs
- */
- for (i = 0; i < FATM_RX_QLEN; i++) {
- q = GET_QUEUE(sc->rxqueue, struct rxqueue, i);
- WRITE4(sc, q->q.card + 0, q->q.card_ioblk);
- }
- BARRIER_W(sc);
-
- /*
- * Supply buffers to the card
- */
- fatm_supply_small_buffers(sc);
- fatm_supply_large_buffers(sc);
-
- /*
- * Now set flags, that we are ready
- */
- sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
-
- /*
- * Start the watchdog timer
- */
- callout_reset(&sc->watchdog_timer, hz * 5, fatm_watchdog, sc);
-
- /* start SUNI */
- utopia_start(&sc->utopia);
-
- ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp),
- sc->utopia.carrier == UTP_CARR_OK);
-
- /* start all channels */
- for (i = 0; i < FORE_MAX_VCC + 1; i++)
- if (sc->vccs[i] != NULL) {
- sc->vccs[i]->vflags |= FATM_VCC_REOPEN;
- error = fatm_load_vc(sc, sc->vccs[i]);
- if (error != 0) {
- if_printf(sc->ifp, "reopening %u "
- "failed: %d\n", i, error);
- sc->vccs[i]->vflags &= ~FATM_VCC_REOPEN;
- }
- }
-
- DBG(sc, INIT, ("done"));
-}
-
-/*
- * This is the exported as initialisation function.
- */
-static void
-fatm_init(void *p)
-{
- struct fatm_softc *sc = p;
-
- FATM_LOCK(sc);
- fatm_init_locked(sc);
- FATM_UNLOCK(sc);
-}
-
-/************************************************************/
-/*
- * The INTERRUPT handling
- */
-/*
- * Check the command queue. If a command was completed, call the completion
- * function for that command.
- */
-static void
-fatm_intr_drain_cmd(struct fatm_softc *sc)
-{
- struct cmdqueue *q;
- int stat;
-
- /*
- * Drain command queue
- */
- for (;;) {
- q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.tail);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- stat = H_GETSTAT(q->q.statp);
-
- if (stat != FATM_STAT_COMPLETE &&
- stat != (FATM_STAT_COMPLETE | FATM_STAT_ERROR) &&
- stat != FATM_STAT_ERROR)
- break;
-
- (*q->cb)(sc, q);
-
- H_SETSTAT(q->q.statp, FATM_STAT_FREE);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
-
- NEXT_QUEUE_ENTRY(sc->cmdqueue.tail, FATM_CMD_QLEN);
- }
-}
-
-/*
- * Drain the small buffer supply queue.
- */
-static void
-fatm_intr_drain_small_buffers(struct fatm_softc *sc)
-{
- struct supqueue *q;
- int stat;
-
- for (;;) {
- q = GET_QUEUE(sc->s1queue, struct supqueue, sc->s1queue.tail);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- stat = H_GETSTAT(q->q.statp);
-
- if ((stat & FATM_STAT_COMPLETE) == 0)
- break;
- if (stat & FATM_STAT_ERROR)
- log(LOG_ERR, "%s: status %x\n", __func__, stat);
-
- H_SETSTAT(q->q.statp, FATM_STAT_FREE);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
-
- NEXT_QUEUE_ENTRY(sc->s1queue.tail, SMALL_SUPPLY_QLEN);
- }
-}
-
-/*
- * Drain the large buffer supply queue.
- */
-static void
-fatm_intr_drain_large_buffers(struct fatm_softc *sc)
-{
- struct supqueue *q;
- int stat;
-
- for (;;) {
- q = GET_QUEUE(sc->l1queue, struct supqueue, sc->l1queue.tail);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- stat = H_GETSTAT(q->q.statp);
-
- if ((stat & FATM_STAT_COMPLETE) == 0)
- break;
- if (stat & FATM_STAT_ERROR)
- log(LOG_ERR, "%s status %x\n", __func__, stat);
-
- H_SETSTAT(q->q.statp, FATM_STAT_FREE);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
-
- NEXT_QUEUE_ENTRY(sc->l1queue.tail, LARGE_SUPPLY_QLEN);
- }
-}
-
-/*
- * Check the receive queue. Send any received PDU up the protocol stack
- * (except when there was an error or the VCI appears to be closed. In this
- * case discard the PDU).
- */
-static void
-fatm_intr_drain_rx(struct fatm_softc *sc)
-{
- struct rxqueue *q;
- int stat, mlen;
- u_int i;
- uint32_t h;
- struct mbuf *last, *m0;
- struct rpd *rpd;
- struct rbuf *rb;
- u_int vci, vpi, pt;
- struct atm_pseudohdr aph;
- struct ifnet *ifp;
- struct card_vcc *vc;
-
- for (;;) {
- q = GET_QUEUE(sc->rxqueue, struct rxqueue, sc->rxqueue.tail);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- stat = H_GETSTAT(q->q.statp);
-
- if ((stat & FATM_STAT_COMPLETE) == 0)
- break;
-
- rpd = (struct rpd *)q->q.ioblk;
- H_SYNCQ_POSTREAD(&sc->rxq_mem, rpd, RPD_SIZE);
-
- rpd->nseg = le32toh(rpd->nseg);
- mlen = 0;
- m0 = last = NULL;
- for (i = 0; i < rpd->nseg; i++) {
- rb = sc->rbufs + rpd->segment[i].handle;
- if (m0 == NULL) {
- m0 = last = rb->m;
- } else {
- last->m_next = rb->m;
- last = rb->m;
- }
- last->m_next = NULL;
- if (last->m_flags & M_EXT)
- sc->large_cnt--;
- else
- sc->small_cnt--;
- bus_dmamap_sync(sc->rbuf_tag, rb->map,
- BUS_DMASYNC_POSTREAD);
- bus_dmamap_unload(sc->rbuf_tag, rb->map);
- rb->m = NULL;
-
- LIST_REMOVE(rb, link);
- LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
-
- last->m_len = le32toh(rpd->segment[i].length);
- mlen += last->m_len;
- }
-
- m0->m_pkthdr.len = mlen;
- m0->m_pkthdr.rcvif = sc->ifp;
-
- h = le32toh(rpd->atm_header);
- vpi = (h >> 20) & 0xff;
- vci = (h >> 4 ) & 0xffff;
- pt = (h >> 1 ) & 0x7;
-
- /*
- * Locate the VCC this packet belongs to
- */
- if (!VC_OK(sc, vpi, vci))
- vc = NULL;
- else if ((vc = sc->vccs[vci]) == NULL ||
- !(sc->vccs[vci]->vflags & FATM_VCC_OPEN)) {
- sc->istats.rx_closed++;
- vc = NULL;
- }
-
- DBG(sc, RCV, ("RCV: vc=%u.%u pt=%u mlen=%d %s", vpi, vci,
- pt, mlen, vc == NULL ? "dropped" : ""));
-
- if (vc == NULL) {
- m_freem(m0);
- } else {
-#ifdef ENABLE_BPF
- if (!(vc->param.flags & ATMIO_FLAG_NG) &&
- vc->param.aal == ATMIO_AAL_5 &&
- (vc->param.flags & ATM_PH_LLCSNAP))
- BPF_MTAP(sc->ifp, m0);
-#endif
-
- ATM_PH_FLAGS(&aph) = vc->param.flags;
- ATM_PH_VPI(&aph) = vpi;
- ATM_PH_SETVCI(&aph, vci);
-
- ifp = sc->ifp;
- if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
-
- vc->ipackets++;
- vc->ibytes += m0->m_pkthdr.len;
-
- atm_input(ifp, &aph, m0, vc->rxhand);
- }
-
- H_SETSTAT(q->q.statp, FATM_STAT_FREE);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
-
- WRITE4(sc, q->q.card, q->q.card_ioblk);
- BARRIER_W(sc);
-
- NEXT_QUEUE_ENTRY(sc->rxqueue.tail, FATM_RX_QLEN);
- }
-}
-
-/*
- * Check the transmit queue. Free the mbuf chains that we were transmitting.
- */
-static void
-fatm_intr_drain_tx(struct fatm_softc *sc)
-{
- struct txqueue *q;
- int stat;
-
- /*
- * Drain tx queue
- */
- for (;;) {
- q = GET_QUEUE(sc->txqueue, struct txqueue, sc->txqueue.tail);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- stat = H_GETSTAT(q->q.statp);
-
- if (stat != FATM_STAT_COMPLETE &&
- stat != (FATM_STAT_COMPLETE | FATM_STAT_ERROR) &&
- stat != FATM_STAT_ERROR)
- break;
-
- H_SETSTAT(q->q.statp, FATM_STAT_FREE);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
-
- bus_dmamap_sync(sc->tx_tag, q->map, BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->tx_tag, q->map);
-
- m_freem(q->m);
- q->m = NULL;
- sc->txcnt--;
-
- NEXT_QUEUE_ENTRY(sc->txqueue.tail, FATM_TX_QLEN);
- }
-}
-
-/*
- * Interrupt handler
- */
-static void
-fatm_intr(void *p)
-{
- struct fatm_softc *sc = (struct fatm_softc *)p;
-
- FATM_LOCK(sc);
- if (!READ4(sc, FATMO_PSR)) {
- FATM_UNLOCK(sc);
- return;
- }
- WRITE4(sc, FATMO_HCR, FATM_HCR_CLRIRQ);
-
- if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
- FATM_UNLOCK(sc);
- return;
- }
- fatm_intr_drain_cmd(sc);
- fatm_intr_drain_rx(sc);
- fatm_intr_drain_tx(sc);
- fatm_intr_drain_small_buffers(sc);
- fatm_intr_drain_large_buffers(sc);
- fatm_supply_small_buffers(sc);
- fatm_supply_large_buffers(sc);
-
- FATM_UNLOCK(sc);
-
- if (sc->retry_tx && _IF_QLEN(&sc->ifp->if_snd))
- (*sc->ifp->if_start)(sc->ifp);
-}
-
-/*
- * Get device statistics. This must be called with the softc locked.
- * We use a preallocated buffer, so we need to protect this buffer.
- * We do this by using a condition variable and a flag. If the flag is set
- * the buffer is in use by one thread (one thread is executing a GETSTAT
- * card command). In this case all other threads that are trying to get
- * statistics block on that condition variable. When the thread finishes
- * using the buffer it resets the flag and signals the condition variable. This
- * will wakeup the next thread that is waiting for the buffer. If the interface
- * is stopped the stopping function will broadcast the cv. All threads will
- * find that the interface has been stopped and return.
- *
- * Acquiring of the buffer is done by the fatm_getstat() function. The freeing
- * must be done by the caller when he has finished using the buffer.
- */
-static void
-fatm_getstat_complete(struct fatm_softc *sc, struct cmdqueue *q)
-{
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
- sc->istats.get_stat_errors++;
- q->error = EIO;
- }
- wakeup(&sc->sadi_mem);
-}
-static int
-fatm_getstat(struct fatm_softc *sc)
-{
- int error;
- struct cmdqueue *q;
-
- /*
- * Wait until either the interface is stopped or we can get the
- * statistics buffer
- */
- for (;;) {
- if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING))
- return (EIO);
- if (!(sc->flags & FATM_STAT_INUSE))
- break;
- cv_wait(&sc->cv_stat, &sc->mtx);
- }
- sc->flags |= FATM_STAT_INUSE;
-
- q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) {
- sc->istats.cmd_queue_full++;
- return (EIO);
- }
- NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN);
-
- q->error = 0;
- q->cb = fatm_getstat_complete;
- H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
-
- bus_dmamap_sync(sc->sadi_mem.dmat, sc->sadi_mem.map,
- BUS_DMASYNC_PREREAD);
-
- WRITE4(sc, q->q.card + FATMOC_GSTAT_BUF,
- sc->sadi_mem.paddr);
- BARRIER_W(sc);
- WRITE4(sc, q->q.card + FATMOC_OP,
- FATM_OP_REQUEST_STATS | FATM_OP_INTERRUPT_SEL);
- BARRIER_W(sc);
-
- /*
- * Wait for the command to complete
- */
- error = msleep(&sc->sadi_mem, &sc->mtx, PZERO | PCATCH,
- "fatm_stat", hz);
-
- switch (error) {
-
- case EWOULDBLOCK:
- error = EIO;
- break;
-
- case ERESTART:
- error = EINTR;
- break;
-
- case 0:
- bus_dmamap_sync(sc->sadi_mem.dmat, sc->sadi_mem.map,
- BUS_DMASYNC_POSTREAD);
- error = q->error;
- break;
- }
-
- /*
- * Swap statistics
- */
- if (q->error == 0) {
- u_int i;
- uint32_t *p = (uint32_t *)sc->sadi_mem.mem;
-
- for (i = 0; i < sizeof(struct fatm_stats) / sizeof(uint32_t);
- i++, p++)
- *p = be32toh(*p);
- }
-
- return (error);
-}
-
-/*
- * Create a copy of a single mbuf. It can have either internal or
- * external data, it may have a packet header. External data is really
- * copied, so the new buffer is writeable.
- */
-static struct mbuf *
-copy_mbuf(struct mbuf *m)
-{
- struct mbuf *new;
-
- MGET(new, M_NOWAIT, MT_DATA);
- if (new == NULL)
- return (NULL);
-
- if (m->m_flags & M_PKTHDR) {
- M_MOVE_PKTHDR(new, m);
- if (m->m_len > MHLEN)
- MCLGET(new, M_WAITOK);
- } else {
- if (m->m_len > MLEN)
- MCLGET(new, M_WAITOK);
- }
-
- bcopy(m->m_data, new->m_data, m->m_len);
- new->m_len = m->m_len;
- new->m_flags &= ~M_RDONLY;
-
- return (new);
-}
-
-/*
- * All segments must have a four byte aligned buffer address and a four
- * byte aligned length. Step through an mbuf chain and check these conditions.
- * If the buffer address is not aligned and this is a normal mbuf, move
- * the data down. Else make a copy of the mbuf with aligned data.
- * If the buffer length is not aligned steel data from the next mbuf.
- * We don't need to check whether this has more than one external reference,
- * because steeling data doesn't change the external cluster.
- * If the last mbuf is not aligned, fill with zeroes.
- *
- * Return packet length (well we should have this in the packet header),
- * but be careful not to count the zero fill at the end.
- *
- * If fixing fails free the chain and zero the pointer.
- *
- * We assume, that aligning the virtual address also aligns the mapped bus
- * address.
- */
-static u_int
-fatm_fix_chain(struct fatm_softc *sc, struct mbuf **mp)
-{
- struct mbuf *m = *mp, *prev = NULL, *next, *new;
- u_int mlen = 0, fill = 0;
- int first, off;
- u_char *d, *cp;
-
- do {
- next = m->m_next;
-
- if ((uintptr_t)mtod(m, void *) % 4 != 0 ||
- (m->m_len % 4 != 0 && next)) {
- /*
- * Needs fixing
- */
- first = (m == *mp);
-
- d = mtod(m, u_char *);
- if ((off = (uintptr_t)(void *)d % 4) != 0) {
- if (M_WRITABLE(m)) {
- sc->istats.fix_addr_copy++;
- bcopy(d, d - off, m->m_len);
- m->m_data = (caddr_t)(d - off);
- } else {
- if ((new = copy_mbuf(m)) == NULL) {
- sc->istats.fix_addr_noext++;
- goto fail;
- }
- sc->istats.fix_addr_ext++;
- if (prev)
- prev->m_next = new;
- new->m_next = next;
- m_free(m);
- m = new;
- }
- }
-
- if ((off = m->m_len % 4) != 0) {
- if (!M_WRITABLE(m)) {
- if ((new = copy_mbuf(m)) == NULL) {
- sc->istats.fix_len_noext++;
- goto fail;
- }
- sc->istats.fix_len_copy++;
- if (prev)
- prev->m_next = new;
- new->m_next = next;
- m_free(m);
- m = new;
- } else
- sc->istats.fix_len++;
- d = mtod(m, u_char *) + m->m_len;
- off = 4 - off;
- while (off) {
- if (next == NULL) {
- *d++ = 0;
- fill++;
- } else if (next->m_len == 0) {
- sc->istats.fix_empty++;
- next = m_free(next);
- continue;
- } else {
- cp = mtod(next, u_char *);
- *d++ = *cp++;
- next->m_len--;
- next->m_data = (caddr_t)cp;
- }
- off--;
- m->m_len++;
- }
- }
-
- if (first)
- *mp = m;
- }
-
- mlen += m->m_len;
- prev = m;
- } while ((m = next) != NULL);
-
- return (mlen - fill);
-
- fail:
- m_freem(*mp);
- *mp = NULL;
- return (0);
-}
-
-/*
- * The helper function is used to load the computed physical addresses
- * into the transmit descriptor.
- */
-static void
-fatm_tpd_load(void *varg, bus_dma_segment_t *segs, int nsegs,
- bus_size_t mapsize, int error)
-{
- struct tpd *tpd = varg;
-
- if (error)
- return;
-
- KASSERT(nsegs <= TPD_EXTENSIONS + TXD_FIXED, ("too many segments"));
-
- tpd->spec = 0;
- while (nsegs--) {
- H_SETDESC(tpd->segment[tpd->spec].buffer, segs->ds_addr);
- H_SETDESC(tpd->segment[tpd->spec].length, segs->ds_len);
- tpd->spec++;
- segs++;
- }
-}
-
-/*
- * Start output.
- *
- * Note, that we update the internal statistics without the lock here.
- */
-static int
-fatm_tx(struct fatm_softc *sc, struct mbuf *m, struct card_vcc *vc, u_int mlen)
-{
- struct txqueue *q;
- u_int nblks;
- int error, aal, nsegs;
- struct tpd *tpd;
-
- /*
- * Get a queue element.
- * If there isn't one - try to drain the transmit queue
- * We used to sleep here if that doesn't help, but we
- * should not sleep here, because we are called with locks.
- */
- q = GET_QUEUE(sc->txqueue, struct txqueue, sc->txqueue.head);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE) {
- fatm_intr_drain_tx(sc);
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE) {
- if (sc->retry_tx) {
- sc->istats.tx_retry++;
- IF_PREPEND(&sc->ifp->if_snd, m);
- return (1);
- }
- sc->istats.tx_queue_full++;
- m_freem(m);
- return (0);
- }
- sc->istats.tx_queue_almost_full++;
- }
-
- tpd = q->q.ioblk;
-
- m->m_data += sizeof(struct atm_pseudohdr);
- m->m_len -= sizeof(struct atm_pseudohdr);
-
-#ifdef ENABLE_BPF
- if (!(vc->param.flags & ATMIO_FLAG_NG) &&
- vc->param.aal == ATMIO_AAL_5 &&
- (vc->param.flags & ATM_PH_LLCSNAP))
- BPF_MTAP(sc->ifp, m);
-#endif
-
- /* map the mbuf */
- error = bus_dmamap_load_mbuf(sc->tx_tag, q->map, m,
- fatm_tpd_load, tpd, BUS_DMA_NOWAIT);
- if(error) {
- if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1);
- if_printf(sc->ifp, "mbuf loaded error=%d\n", error);
- m_freem(m);
- return (0);
- }
- nsegs = tpd->spec;
-
- bus_dmamap_sync(sc->tx_tag, q->map, BUS_DMASYNC_PREWRITE);
-
- /*
- * OK. Now go and do it.
- */
- aal = (vc->param.aal == ATMIO_AAL_5) ? 5 : 0;
-
- H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
- q->m = m;
-
- /*
- * If the transmit queue is almost full, schedule a
- * transmit interrupt so that transmit descriptors can
- * be recycled.
- */
- H_SETDESC(tpd->spec, TDX_MKSPEC((sc->txcnt >=
- (4 * FATM_TX_QLEN) / 5), aal, nsegs, mlen));
- H_SETDESC(tpd->atm_header, TDX_MKHDR(vc->param.vpi,
- vc->param.vci, 0, 0));
-
- if (vc->param.traffic == ATMIO_TRAFFIC_UBR)
- H_SETDESC(tpd->stream, 0);
- else {
- u_int i;
-
- for (i = 0; i < RATE_TABLE_SIZE; i++)
- if (rate_table[i].cell_rate < vc->param.tparam.pcr)
- break;
- if (i > 0)
- i--;
- H_SETDESC(tpd->stream, rate_table[i].ratio);
- }
- H_SYNCQ_PREWRITE(&sc->txq_mem, tpd, TPD_SIZE);
-
- nblks = TDX_SEGS2BLKS(nsegs);
-
- DBG(sc, XMIT, ("XMIT: mlen=%d spec=0x%x nsegs=%d blocks=%d",
- mlen, le32toh(tpd->spec), nsegs, nblks));
-
- WRITE4(sc, q->q.card + 0, q->q.card_ioblk | nblks);
- BARRIER_W(sc);
-
- sc->txcnt++;
- if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1);
- vc->obytes += m->m_pkthdr.len;
- vc->opackets++;
-
- NEXT_QUEUE_ENTRY(sc->txqueue.head, FATM_TX_QLEN);
-
- return (0);
-}
-
-static void
-fatm_start(struct ifnet *ifp)
-{
- struct atm_pseudohdr aph;
- struct fatm_softc *sc;
- struct mbuf *m;
- u_int mlen, vpi, vci;
- struct card_vcc *vc;
-
- sc = ifp->if_softc;
-
- while (1) {
- IF_DEQUEUE(&ifp->if_snd, m);
- if (m == NULL)
- break;
-
- /*
- * Loop through the mbuf chain and compute the total length
- * of the packet. Check that all data pointer are
- * 4 byte aligned. If they are not, call fatm_mfix to
- * fix that problem. This comes more or less from the
- * en driver.
- */
- mlen = fatm_fix_chain(sc, &m);
- if (m == NULL)
- continue;
-
- if (m->m_len < sizeof(struct atm_pseudohdr) &&
- (m = m_pullup(m, sizeof(struct atm_pseudohdr))) == NULL)
- continue;
-
- aph = *mtod(m, struct atm_pseudohdr *);
- mlen -= sizeof(struct atm_pseudohdr);
-
- if (mlen == 0) {
- m_freem(m);
- continue;
- }
- if (mlen > FATM_MAXPDU) {
- sc->istats.tx_pdu2big++;
- m_freem(m);
- continue;
- }
-
- vci = ATM_PH_VCI(&aph);
- vpi = ATM_PH_VPI(&aph);
-
- /*
- * From here on we need the softc
- */
- FATM_LOCK(sc);
- if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
- FATM_UNLOCK(sc);
- m_freem(m);
- break;
- }
- if (!VC_OK(sc, vpi, vci) || (vc = sc->vccs[vci]) == NULL ||
- !(vc->vflags & FATM_VCC_OPEN)) {
- FATM_UNLOCK(sc);
- m_freem(m);
- continue;
- }
- if (fatm_tx(sc, m, vc, mlen)) {
- FATM_UNLOCK(sc);
- break;
- }
- FATM_UNLOCK(sc);
- }
-}
-
-/*
- * VCC management
- *
- * This may seem complicated. The reason for this is, that we need an
- * asynchronuous open/close for the NATM VCCs because our ioctl handler
- * is called with the radix node head of the routing table locked. Therefor
- * we cannot sleep there and wait for the open/close to succeed. For this
- * reason we just initiate the operation from the ioctl.
- */
-
-/*
- * Command the card to open/close a VC.
- * Return the queue entry for waiting if we are successful.
- */
-static struct cmdqueue *
-fatm_start_vcc(struct fatm_softc *sc, u_int vpi, u_int vci, uint32_t cmd,
- u_int mtu, void (*func)(struct fatm_softc *, struct cmdqueue *))
-{
- struct cmdqueue *q;
-
- q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head);
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) {
- sc->istats.cmd_queue_full++;
- return (NULL);
- }
- NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN);
-
- q->error = 0;
- q->cb = func;
- H_SETSTAT(q->q.statp, FATM_STAT_PENDING);
- H_SYNCSTAT_PREWRITE(sc, q->q.statp);
-
- WRITE4(sc, q->q.card + FATMOC_ACTIN_VPVC, MKVPVC(vpi, vci));
- BARRIER_W(sc);
- WRITE4(sc, q->q.card + FATMOC_ACTIN_MTU, mtu);
- BARRIER_W(sc);
- WRITE4(sc, q->q.card + FATMOC_OP, cmd);
- BARRIER_W(sc);
-
- return (q);
-}
-
-/*
- * The VC has been opened/closed and somebody has been waiting for this.
- * Wake him up.
- */
-static void
-fatm_cmd_complete(struct fatm_softc *sc, struct cmdqueue *q)
-{
-
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
- sc->istats.get_stat_errors++;
- q->error = EIO;
- }
- wakeup(q);
-}
-
-/*
- * Open complete
- */
-static void
-fatm_open_finish(struct fatm_softc *sc, struct card_vcc *vc)
-{
- vc->vflags &= ~FATM_VCC_TRY_OPEN;
- vc->vflags |= FATM_VCC_OPEN;
-
- if (vc->vflags & FATM_VCC_REOPEN) {
- vc->vflags &= ~FATM_VCC_REOPEN;
- return;
- }
-
- /* inform management if this is not an NG
- * VCC or it's an NG PVC. */
- if (!(vc->param.flags & ATMIO_FLAG_NG) ||
- (vc->param.flags & ATMIO_FLAG_PVC))
- ATMEV_SEND_VCC_CHANGED(IFP2IFATM(sc->ifp), 0, vc->param.vci, 1);
-}
-
-/*
- * The VC that we have tried to open asynchronuosly has been opened.
- */
-static void
-fatm_open_complete(struct fatm_softc *sc, struct cmdqueue *q)
-{
- u_int vci;
- struct card_vcc *vc;
-
- vci = GETVCI(READ4(sc, q->q.card + FATMOC_ACTIN_VPVC));
- vc = sc->vccs[vci];
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
- sc->istats.get_stat_errors++;
- sc->vccs[vci] = NULL;
- uma_zfree(sc->vcc_zone, vc);
- if_printf(sc->ifp, "opening VCI %u failed\n", vci);
- return;
- }
- fatm_open_finish(sc, vc);
-}
-
-/*
- * Wait on the queue entry until the VCC is opened/closed.
- */
-static int
-fatm_waitvcc(struct fatm_softc *sc, struct cmdqueue *q)
-{
- int error;
-
- /*
- * Wait for the command to complete
- */
- error = msleep(q, &sc->mtx, PZERO | PCATCH, "fatm_vci", hz);
-
- if (error != 0)
- return (error);
- return (q->error);
-}
-
-/*
- * Start to open a VCC. This just initiates the operation.
- */
-static int
-fatm_open_vcc(struct fatm_softc *sc, struct atmio_openvcc *op)
-{
- int error;
- struct card_vcc *vc;
-
- /*
- * Check parameters
- */
- if ((op->param.flags & ATMIO_FLAG_NOTX) &&
- (op->param.flags & ATMIO_FLAG_NORX))
- return (EINVAL);
-
- if (!VC_OK(sc, op->param.vpi, op->param.vci))
- return (EINVAL);
- if (op->param.aal != ATMIO_AAL_0 && op->param.aal != ATMIO_AAL_5)
- return (EINVAL);
-
- vc = uma_zalloc(sc->vcc_zone, M_NOWAIT | M_ZERO);
- if (vc == NULL)
- return (ENOMEM);
-
- error = 0;
-
- FATM_LOCK(sc);
- if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
- error = EIO;
- goto done;
- }
- if (sc->vccs[op->param.vci] != NULL) {
- error = EBUSY;
- goto done;
- }
- vc->param = op->param;
- vc->rxhand = op->rxhand;
-
- switch (op->param.traffic) {
-
- case ATMIO_TRAFFIC_UBR:
- break;
-
- case ATMIO_TRAFFIC_CBR:
- if (op->param.tparam.pcr == 0 ||
- op->param.tparam.pcr > IFP2IFATM(sc->ifp)->mib.pcr) {
- error = EINVAL;
- goto done;
- }
- break;
-
- default:
- error = EINVAL;
- goto done;
- }
- vc->ibytes = vc->obytes = 0;
- vc->ipackets = vc->opackets = 0;
-
- vc->vflags = FATM_VCC_TRY_OPEN;
- sc->vccs[op->param.vci] = vc;
- sc->open_vccs++;
-
- error = fatm_load_vc(sc, vc);
- if (error != 0) {
- sc->vccs[op->param.vci] = NULL;
- sc->open_vccs--;
- goto done;
- }
-
- /* don't free below */
- vc = NULL;
-
- done:
- FATM_UNLOCK(sc);
- if (vc != NULL)
- uma_zfree(sc->vcc_zone, vc);
- return (error);
-}
-
-/*
- * Try to initialize the given VC
- */
-static int
-fatm_load_vc(struct fatm_softc *sc, struct card_vcc *vc)
-{
- uint32_t cmd;
- struct cmdqueue *q;
- int error;
-
- /* Command and buffer strategy */
- cmd = FATM_OP_ACTIVATE_VCIN | FATM_OP_INTERRUPT_SEL | (0 << 16);
- if (vc->param.aal == ATMIO_AAL_0)
- cmd |= (0 << 8);
- else
- cmd |= (5 << 8);
-
- q = fatm_start_vcc(sc, vc->param.vpi, vc->param.vci, cmd, 1,
- (vc->param.flags & ATMIO_FLAG_ASYNC) ?
- fatm_open_complete : fatm_cmd_complete);
- if (q == NULL)
- return (EIO);
-
- if (!(vc->param.flags & ATMIO_FLAG_ASYNC)) {
- error = fatm_waitvcc(sc, q);
- if (error != 0)
- return (error);
- fatm_open_finish(sc, vc);
- }
- return (0);
-}
-
-/*
- * Finish close
- */
-static void
-fatm_close_finish(struct fatm_softc *sc, struct card_vcc *vc)
-{
- /* inform management of this is not an NG
- * VCC or it's an NG PVC. */
- if (!(vc->param.flags & ATMIO_FLAG_NG) ||
- (vc->param.flags & ATMIO_FLAG_PVC))
- ATMEV_SEND_VCC_CHANGED(IFP2IFATM(sc->ifp), 0, vc->param.vci, 0);
-
- sc->vccs[vc->param.vci] = NULL;
- sc->open_vccs--;
-
- uma_zfree(sc->vcc_zone, vc);
-}
-
-/*
- * The VC has been closed.
- */
-static void
-fatm_close_complete(struct fatm_softc *sc, struct cmdqueue *q)
-{
- u_int vci;
- struct card_vcc *vc;
-
- vci = GETVCI(READ4(sc, q->q.card + FATMOC_ACTIN_VPVC));
- vc = sc->vccs[vci];
- H_SYNCSTAT_POSTREAD(sc, q->q.statp);
- if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) {
- sc->istats.get_stat_errors++;
- /* keep the VCC in that state */
- if_printf(sc->ifp, "closing VCI %u failed\n", vci);
- return;
- }
-
- fatm_close_finish(sc, vc);
-}
-
-/*
- * Initiate closing a VCC
- */
-static int
-fatm_close_vcc(struct fatm_softc *sc, struct atmio_closevcc *cl)
-{
- int error;
- struct cmdqueue *q;
- struct card_vcc *vc;
-
- if (!VC_OK(sc, cl->vpi, cl->vci))
- return (EINVAL);
-
- error = 0;
-
- FATM_LOCK(sc);
- if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
- error = EIO;
- goto done;
- }
- vc = sc->vccs[cl->vci];
- if (vc == NULL || !(vc->vflags & (FATM_VCC_OPEN | FATM_VCC_TRY_OPEN))) {
- error = ENOENT;
- goto done;
- }
-
- q = fatm_start_vcc(sc, cl->vpi, cl->vci,
- FATM_OP_DEACTIVATE_VCIN | FATM_OP_INTERRUPT_SEL, 1,
- (vc->param.flags & ATMIO_FLAG_ASYNC) ?
- fatm_close_complete : fatm_cmd_complete);
- if (q == NULL) {
- error = EIO;
- goto done;
- }
-
- vc->vflags &= ~(FATM_VCC_OPEN | FATM_VCC_TRY_OPEN);
- vc->vflags |= FATM_VCC_TRY_CLOSE;
-
- if (!(vc->param.flags & ATMIO_FLAG_ASYNC)) {
- error = fatm_waitvcc(sc, q);
- if (error != 0)
- goto done;
-
- fatm_close_finish(sc, vc);
- }
-
- done:
- FATM_UNLOCK(sc);
- return (error);
-}
-
-/*
- * IOCTL handler
- */
-static int
-fatm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t arg)
-{
- int error;
- struct fatm_softc *sc = ifp->if_softc;
- struct ifaddr *ifa = (struct ifaddr *)arg;
- struct ifreq *ifr = (struct ifreq *)arg;
- struct atmio_closevcc *cl = (struct atmio_closevcc *)arg;
- struct atmio_openvcc *op = (struct atmio_openvcc *)arg;
- struct atmio_vcctable *vtab;
-
- error = 0;
- switch (cmd) {
-
- case SIOCATMOPENVCC: /* kernel internal use */
- error = fatm_open_vcc(sc, op);
- break;
-
- case SIOCATMCLOSEVCC: /* kernel internal use */
- error = fatm_close_vcc(sc, cl);
- break;
-
- case SIOCSIFADDR:
- FATM_LOCK(sc);
- ifp->if_flags |= IFF_UP;
- if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
- fatm_init_locked(sc);
- switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
- case AF_INET:
- case AF_INET6:
- ifa->ifa_rtrequest = atm_rtrequest;
- break;
-#endif
- default:
- break;
- }
- FATM_UNLOCK(sc);
- break;
-
- case SIOCSIFFLAGS:
- FATM_LOCK(sc);
- if (ifp->if_flags & IFF_UP) {
- if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
- fatm_init_locked(sc);
- }
- } else {
- if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- fatm_stop(sc);
- }
- }
- FATM_UNLOCK(sc);
- break;
-
- case SIOCGIFMEDIA:
- case SIOCSIFMEDIA:
- if (ifp->if_drv_flags & IFF_DRV_RUNNING)
- error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd);
- else
- error = EINVAL;
- break;
-
- case SIOCATMGVCCS:
- /* return vcc table */
- vtab = atm_getvccs((struct atmio_vcc **)sc->vccs,
- FORE_MAX_VCC + 1, sc->open_vccs, &sc->mtx, 1);
- error = copyout(vtab, ifr->ifr_data, sizeof(*vtab) +
- vtab->count * sizeof(vtab->vccs[0]));
- free(vtab, M_DEVBUF);
- break;
-
- case SIOCATMGETVCCS: /* internal netgraph use */
- vtab = atm_getvccs((struct atmio_vcc **)sc->vccs,
- FORE_MAX_VCC + 1, sc->open_vccs, &sc->mtx, 0);
- if (vtab == NULL) {
- error = ENOMEM;
- break;
- }
- *(void **)arg = vtab;
- break;
-
- default:
- DBG(sc, IOCTL, ("+++ cmd=%08lx arg=%p", cmd, arg));
- error = EINVAL;
- break;
- }
-
- return (error);
-}
-
-/*
- * Detach from the interface and free all resources allocated during
- * initialisation and later.
- */
-static int
-fatm_detach(device_t dev)
-{
- u_int i;
- struct rbuf *rb;
- struct fatm_softc *sc;
- struct txqueue *tx;
-
- sc = device_get_softc(dev);
-
- if (device_is_alive(dev)) {
- FATM_LOCK(sc);
- fatm_stop(sc);
- utopia_detach(&sc->utopia);
- FATM_UNLOCK(sc);
- atm_ifdetach(sc->ifp); /* XXX race */
- }
- callout_drain(&sc->watchdog_timer);
-
- if (sc->ih != NULL)
- bus_teardown_intr(dev, sc->irqres, sc->ih);
-
- while ((rb = LIST_FIRST(&sc->rbuf_used)) != NULL) {
- if_printf(sc->ifp, "rbuf %p still in use!\n", rb);
- bus_dmamap_unload(sc->rbuf_tag, rb->map);
- m_freem(rb->m);
- LIST_REMOVE(rb, link);
- LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
- }
-
- if (sc->txqueue.chunk != NULL) {
- for (i = 0; i < FATM_TX_QLEN; i++) {
- tx = GET_QUEUE(sc->txqueue, struct txqueue, i);
- bus_dmamap_destroy(sc->tx_tag, tx->map);
- }
- }
-
- while ((rb = LIST_FIRST(&sc->rbuf_free)) != NULL) {
- bus_dmamap_destroy(sc->rbuf_tag, rb->map);
- LIST_REMOVE(rb, link);
- }
-
- if (sc->rbufs != NULL)
- free(sc->rbufs, M_DEVBUF);
- if (sc->vccs != NULL) {
- for (i = 0; i < FORE_MAX_VCC + 1; i++)
- if (sc->vccs[i] != NULL) {
- uma_zfree(sc->vcc_zone, sc->vccs[i]);
- sc->vccs[i] = NULL;
- }
- free(sc->vccs, M_DEVBUF);
- }
- if (sc->vcc_zone != NULL)
- uma_zdestroy(sc->vcc_zone);
-
- if (sc->l1queue.chunk != NULL)
- free(sc->l1queue.chunk, M_DEVBUF);
- if (sc->s1queue.chunk != NULL)
- free(sc->s1queue.chunk, M_DEVBUF);
- if (sc->rxqueue.chunk != NULL)
- free(sc->rxqueue.chunk, M_DEVBUF);
- if (sc->txqueue.chunk != NULL)
- free(sc->txqueue.chunk, M_DEVBUF);
- if (sc->cmdqueue.chunk != NULL)
- free(sc->cmdqueue.chunk, M_DEVBUF);
-
- destroy_dma_memory(&sc->reg_mem);
- destroy_dma_memory(&sc->sadi_mem);
- destroy_dma_memory(&sc->prom_mem);
-#ifdef TEST_DMA_SYNC
- destroy_dma_memoryX(&sc->s1q_mem);
- destroy_dma_memoryX(&sc->l1q_mem);
- destroy_dma_memoryX(&sc->rxq_mem);
- destroy_dma_memoryX(&sc->txq_mem);
- destroy_dma_memoryX(&sc->stat_mem);
-#endif
-
- if (sc->tx_tag != NULL)
- if (bus_dma_tag_destroy(sc->tx_tag))
- printf("tx DMA tag busy!\n");
-
- if (sc->rbuf_tag != NULL)
- if (bus_dma_tag_destroy(sc->rbuf_tag))
- printf("rbuf DMA tag busy!\n");
-
- if (sc->parent_dmat != NULL)
- if (bus_dma_tag_destroy(sc->parent_dmat))
- printf("parent DMA tag busy!\n");
-
- if (sc->irqres != NULL)
- bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irqres);
-
- if (sc->memres != NULL)
- bus_release_resource(dev, SYS_RES_MEMORY,
- sc->memid, sc->memres);
-
- (void)sysctl_ctx_free(&sc->sysctl_ctx);
-
- cv_destroy(&sc->cv_stat);
- cv_destroy(&sc->cv_regs);
-
- mtx_destroy(&sc->mtx);
-
- if_free(sc->ifp);
-
- return (0);
-}
-
-/*
- * Sysctl handler
- */
-static int
-fatm_sysctl_istats(SYSCTL_HANDLER_ARGS)
-{
- struct fatm_softc *sc = arg1;
- u_long *ret;
- int error;
-
- ret = malloc(sizeof(sc->istats), M_TEMP, M_WAITOK);
-
- FATM_LOCK(sc);
- bcopy(&sc->istats, ret, sizeof(sc->istats));
- FATM_UNLOCK(sc);
-
- error = SYSCTL_OUT(req, ret, sizeof(sc->istats));
- free(ret, M_TEMP);
-
- return (error);
-}
-
-/*
- * Sysctl handler for card statistics
- * This is disable because it destroys the PHY statistics.
- */
-static int
-fatm_sysctl_stats(SYSCTL_HANDLER_ARGS)
-{
- struct fatm_softc *sc = arg1;
- int error;
- const struct fatm_stats *s;
- u_long *ret;
- u_int i;
-
- ret = malloc(sizeof(u_long) * FATM_NSTATS, M_TEMP, M_WAITOK);
-
- FATM_LOCK(sc);
-
- if ((error = fatm_getstat(sc)) == 0) {
- s = sc->sadi_mem.mem;
- i = 0;
- ret[i++] = s->phy_4b5b.crc_header_errors;
- ret[i++] = s->phy_4b5b.framing_errors;
- ret[i++] = s->phy_oc3.section_bip8_errors;
- ret[i++] = s->phy_oc3.path_bip8_errors;
- ret[i++] = s->phy_oc3.line_bip24_errors;
- ret[i++] = s->phy_oc3.line_febe_errors;
- ret[i++] = s->phy_oc3.path_febe_errors;
- ret[i++] = s->phy_oc3.corr_hcs_errors;
- ret[i++] = s->phy_oc3.ucorr_hcs_errors;
- ret[i++] = s->atm.cells_transmitted;
- ret[i++] = s->atm.cells_received;
- ret[i++] = s->atm.vpi_bad_range;
- ret[i++] = s->atm.vpi_no_conn;
- ret[i++] = s->atm.vci_bad_range;
- ret[i++] = s->atm.vci_no_conn;
- ret[i++] = s->aal0.cells_transmitted;
- ret[i++] = s->aal0.cells_received;
- ret[i++] = s->aal0.cells_dropped;
- ret[i++] = s->aal4.cells_transmitted;
- ret[i++] = s->aal4.cells_received;
- ret[i++] = s->aal4.cells_crc_errors;
- ret[i++] = s->aal4.cels_protocol_errors;
- ret[i++] = s->aal4.cells_dropped;
- ret[i++] = s->aal4.cspdus_transmitted;
- ret[i++] = s->aal4.cspdus_received;
- ret[i++] = s->aal4.cspdus_protocol_errors;
- ret[i++] = s->aal4.cspdus_dropped;
- ret[i++] = s->aal5.cells_transmitted;
- ret[i++] = s->aal5.cells_received;
- ret[i++] = s->aal5.congestion_experienced;
- ret[i++] = s->aal5.cells_dropped;
- ret[i++] = s->aal5.cspdus_transmitted;
- ret[i++] = s->aal5.cspdus_received;
- ret[i++] = s->aal5.cspdus_crc_errors;
- ret[i++] = s->aal5.cspdus_protocol_errors;
- ret[i++] = s->aal5.cspdus_dropped;
- ret[i++] = s->aux.small_b1_failed;
- ret[i++] = s->aux.large_b1_failed;
- ret[i++] = s->aux.small_b2_failed;
- ret[i++] = s->aux.large_b2_failed;
- ret[i++] = s->aux.rpd_alloc_failed;
- ret[i++] = s->aux.receive_carrier;
- }
- /* declare the buffer free */
- sc->flags &= ~FATM_STAT_INUSE;
- cv_signal(&sc->cv_stat);
-
- FATM_UNLOCK(sc);
-
- if (error == 0)
- error = SYSCTL_OUT(req, ret, sizeof(u_long) * FATM_NSTATS);
- free(ret, M_TEMP);
-
- return (error);
-}
-
-#define MAXDMASEGS 32 /* maximum number of receive descriptors */
-
-/*
- * Attach to the device.
- *
- * We assume, that there is a global lock (Giant in this case) that protects
- * multiple threads from entering this function. This makes sense, doesn't it?
- */
-static int
-fatm_attach(device_t dev)
-{
- struct ifnet *ifp;
- struct fatm_softc *sc;
- int unit;
- uint16_t cfg;
- int error = 0;
- struct rbuf *rb;
- u_int i;
- struct txqueue *tx;
-
- sc = device_get_softc(dev);
- unit = device_get_unit(dev);
-
- ifp = sc->ifp = if_alloc(IFT_ATM);
- if (ifp == NULL) {
- error = ENOSPC;
- goto fail;
- }
-
- IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_PCA200E;
- IFP2IFATM(sc->ifp)->mib.serial = 0;
- IFP2IFATM(sc->ifp)->mib.hw_version = 0;
- IFP2IFATM(sc->ifp)->mib.sw_version = 0;
- IFP2IFATM(sc->ifp)->mib.vpi_bits = 0;
- IFP2IFATM(sc->ifp)->mib.vci_bits = FORE_VCIBITS;
- IFP2IFATM(sc->ifp)->mib.max_vpcs = 0;
- IFP2IFATM(sc->ifp)->mib.max_vccs = FORE_MAX_VCC;
- IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UNKNOWN;
- IFP2IFATM(sc->ifp)->phy = &sc->utopia;
-
- LIST_INIT(&sc->rbuf_free);
- LIST_INIT(&sc->rbuf_used);
-
- /*
- * Initialize mutex and condition variables.
- */
- mtx_init(&sc->mtx, device_get_nameunit(dev),
- MTX_NETWORK_LOCK, MTX_DEF);
-
- cv_init(&sc->cv_stat, "fatm_stat");
- cv_init(&sc->cv_regs, "fatm_regs");
-
- sysctl_ctx_init(&sc->sysctl_ctx);
- callout_init_mtx(&sc->watchdog_timer, &sc->mtx, 0);
-
- /*
- * Make the sysctl tree
- */
- if ((sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
- SYSCTL_STATIC_CHILDREN(_hw_atm), OID_AUTO,
- device_get_nameunit(dev), CTLFLAG_RD, 0, "")) == NULL)
- goto fail;
-
- if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
- OID_AUTO, "istats", CTLTYPE_ULONG | CTLFLAG_RD, sc, 0,
- fatm_sysctl_istats, "LU", "internal statistics") == NULL)
- goto fail;
-
- if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
- OID_AUTO, "stats", CTLTYPE_ULONG | CTLFLAG_RD, sc, 0,
- fatm_sysctl_stats, "LU", "card statistics") == NULL)
- goto fail;
-
- if (SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
- OID_AUTO, "retry_tx", CTLFLAG_RW, &sc->retry_tx, 0,
- "retry flag") == NULL)
- goto fail;
-
-#ifdef FATM_DEBUG
- if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
- OID_AUTO, "debug", CTLFLAG_RW, &sc->debug, 0, "debug flags")
- == NULL)
- goto fail;
- sc->debug = FATM_DEBUG;
-#endif
-
- /*
- * Network subsystem stuff
- */
- ifp->if_softc = sc;
- if_initname(ifp, device_get_name(dev), device_get_unit(dev));
- ifp->if_flags = IFF_SIMPLEX;
- ifp->if_ioctl = fatm_ioctl;
- ifp->if_start = fatm_start;
- ifp->if_init = fatm_init;
- ifp->if_linkmib = &IFP2IFATM(sc->ifp)->mib;
- ifp->if_linkmiblen = sizeof(IFP2IFATM(sc->ifp)->mib);
-
- /*
- * Enable busmaster
- */
- pci_enable_busmaster(dev);
-
- /*
- * Map memory
- */
- sc->memid = 0x10;
- sc->memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->memid,
- RF_ACTIVE);
- if (sc->memres == NULL) {
- if_printf(ifp, "could not map memory\n");
- error = ENXIO;
- goto fail;
- }
- sc->memh = rman_get_bushandle(sc->memres);
- sc->memt = rman_get_bustag(sc->memres);
-
- /*
- * Convert endianness of slave access
- */
- cfg = pci_read_config(dev, FATM_PCIR_MCTL, 1);
- cfg |= FATM_PCIM_SWAB;
- pci_write_config(dev, FATM_PCIR_MCTL, cfg, 1);
-
- /*
- * Allocate interrupt (activate at the end)
- */
- sc->irqid = 0;
- sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
- RF_SHAREABLE | RF_ACTIVE);
- if (sc->irqres == NULL) {
- if_printf(ifp, "could not allocate irq\n");
- error = ENXIO;
- goto fail;
- }
-
- /*
- * Allocate the parent DMA tag. This is used simply to hold overall
- * restrictions for the controller (and PCI bus) and is never used
- * to do anything.
- */
- if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
- BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
- NULL, NULL, BUS_SPACE_MAXSIZE_32BIT, MAXDMASEGS,
- BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL,
- &sc->parent_dmat)) {
- if_printf(ifp, "could not allocate parent DMA tag\n");
- error = ENOMEM;
- goto fail;
- }
-
- /*
- * Allocate the receive buffer DMA tag. This tag must map a maximum of
- * a mbuf cluster.
- */
- if (bus_dma_tag_create(sc->parent_dmat, 1, 0,
- BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
- NULL, NULL, MCLBYTES, 1, MCLBYTES, 0,
- NULL, NULL, &sc->rbuf_tag)) {
- if_printf(ifp, "could not allocate rbuf DMA tag\n");
- error = ENOMEM;
- goto fail;
- }
-
- /*
- * Allocate the transmission DMA tag. Must add 1, because
- * rounded up PDU will be 65536 bytes long.
- */
- if (bus_dma_tag_create(sc->parent_dmat, 1, 0,
- BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
- NULL, NULL,
- FATM_MAXPDU + 1, TPD_EXTENSIONS + TXD_FIXED, MCLBYTES, 0,
- NULL, NULL, &sc->tx_tag)) {
- if_printf(ifp, "could not allocate tx DMA tag\n");
- error = ENOMEM;
- goto fail;
- }
-
- /*
- * Allocate DMAable memory.
- */
- sc->stat_mem.size = sizeof(uint32_t) * (FATM_CMD_QLEN + FATM_TX_QLEN
- + FATM_RX_QLEN + SMALL_SUPPLY_QLEN + LARGE_SUPPLY_QLEN);
- sc->stat_mem.align = 4;
-
- sc->txq_mem.size = FATM_TX_QLEN * TPD_SIZE;
- sc->txq_mem.align = 32;
-
- sc->rxq_mem.size = FATM_RX_QLEN * RPD_SIZE;
- sc->rxq_mem.align = 32;
-
- sc->s1q_mem.size = SMALL_SUPPLY_QLEN *
- BSUP_BLK2SIZE(SMALL_SUPPLY_BLKSIZE);
- sc->s1q_mem.align = 32;
-
- sc->l1q_mem.size = LARGE_SUPPLY_QLEN *
- BSUP_BLK2SIZE(LARGE_SUPPLY_BLKSIZE);
- sc->l1q_mem.align = 32;
-
-#ifdef TEST_DMA_SYNC
- if ((error = alloc_dma_memoryX(sc, "STATUS", &sc->stat_mem)) != 0 ||
- (error = alloc_dma_memoryX(sc, "TXQ", &sc->txq_mem)) != 0 ||
- (error = alloc_dma_memoryX(sc, "RXQ", &sc->rxq_mem)) != 0 ||
- (error = alloc_dma_memoryX(sc, "S1Q", &sc->s1q_mem)) != 0 ||
- (error = alloc_dma_memoryX(sc, "L1Q", &sc->l1q_mem)) != 0)
- goto fail;
-#else
- if ((error = alloc_dma_memory(sc, "STATUS", &sc->stat_mem)) != 0 ||
- (error = alloc_dma_memory(sc, "TXQ", &sc->txq_mem)) != 0 ||
- (error = alloc_dma_memory(sc, "RXQ", &sc->rxq_mem)) != 0 ||
- (error = alloc_dma_memory(sc, "S1Q", &sc->s1q_mem)) != 0 ||
- (error = alloc_dma_memory(sc, "L1Q", &sc->l1q_mem)) != 0)
- goto fail;
-#endif
-
- sc->prom_mem.size = sizeof(struct prom);
- sc->prom_mem.align = 32;
- if ((error = alloc_dma_memory(sc, "PROM", &sc->prom_mem)) != 0)
- goto fail;
-
- sc->sadi_mem.size = sizeof(struct fatm_stats);
- sc->sadi_mem.align = 32;
- if ((error = alloc_dma_memory(sc, "STATISTICS", &sc->sadi_mem)) != 0)
- goto fail;
-
- sc->reg_mem.size = sizeof(uint32_t) * FATM_NREGS;
- sc->reg_mem.align = 32;
- if ((error = alloc_dma_memory(sc, "REGISTERS", &sc->reg_mem)) != 0)
- goto fail;
-
- /*
- * Allocate queues
- */
- sc->cmdqueue.chunk = malloc(FATM_CMD_QLEN * sizeof(struct cmdqueue),
- M_DEVBUF, M_ZERO | M_WAITOK);
- sc->txqueue.chunk = malloc(FATM_TX_QLEN * sizeof(struct txqueue),
- M_DEVBUF, M_ZERO | M_WAITOK);
- sc->rxqueue.chunk = malloc(FATM_RX_QLEN * sizeof(struct rxqueue),
- M_DEVBUF, M_ZERO | M_WAITOK);
- sc->s1queue.chunk = malloc(SMALL_SUPPLY_QLEN * sizeof(struct supqueue),
- M_DEVBUF, M_ZERO | M_WAITOK);
- sc->l1queue.chunk = malloc(LARGE_SUPPLY_QLEN * sizeof(struct supqueue),
- M_DEVBUF, M_ZERO | M_WAITOK);
-
- sc->vccs = malloc((FORE_MAX_VCC + 1) * sizeof(sc->vccs[0]),
- M_DEVBUF, M_ZERO | M_WAITOK);
- sc->vcc_zone = uma_zcreate("FATM vccs", sizeof(struct card_vcc),
- NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
- if (sc->vcc_zone == NULL) {
- error = ENOMEM;
- goto fail;
- }
-
- /*
- * Allocate memory for the receive buffer headers. The total number
- * of headers should probably also include the maximum number of
- * buffers on the receive queue.
- */
- sc->rbuf_total = SMALL_POOL_SIZE + LARGE_POOL_SIZE;
- sc->rbufs = malloc(sc->rbuf_total * sizeof(struct rbuf),
- M_DEVBUF, M_ZERO | M_WAITOK);
-
- /*
- * Put all rbuf headers on the free list and create DMA maps.
- */
- for (rb = sc->rbufs, i = 0; i < sc->rbuf_total; i++, rb++) {
- if ((error = bus_dmamap_create(sc->rbuf_tag, 0, &rb->map))) {
- if_printf(sc->ifp, "creating rx map: %d\n",
- error);
- goto fail;
- }
- LIST_INSERT_HEAD(&sc->rbuf_free, rb, link);
- }
-
- /*
- * Create dma maps for transmission. In case of an error, free the
- * allocated DMA maps, because on some architectures maps are NULL
- * and we cannot distinguish between a failure and a NULL map in
- * the detach routine.
- */
- for (i = 0; i < FATM_TX_QLEN; i++) {
- tx = GET_QUEUE(sc->txqueue, struct txqueue, i);
- if ((error = bus_dmamap_create(sc->tx_tag, 0, &tx->map))) {
- if_printf(sc->ifp, "creating tx map: %d\n",
- error);
- while (i > 0) {
- tx = GET_QUEUE(sc->txqueue, struct txqueue,
- i - 1);
- bus_dmamap_destroy(sc->tx_tag, tx->map);
- i--;
- }
- goto fail;
- }
- }
-
- utopia_attach(&sc->utopia, IFP2IFATM(sc->ifp), &sc->media, &sc->mtx,
- &sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
- &fatm_utopia_methods);
- sc->utopia.flags |= UTP_FL_NORESET | UTP_FL_POLL_CARRIER;
-
- /*
- * Attach the interface
- */
- atm_ifattach(ifp);
- ifp->if_snd.ifq_maxlen = 512;
-
-#ifdef ENABLE_BPF
- bpfattach(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
-#endif
-
- error = bus_setup_intr(dev, sc->irqres, INTR_TYPE_NET | INTR_MPSAFE,
- NULL, fatm_intr, sc, &sc->ih);
- if (error) {
- if_printf(ifp, "couldn't setup irq\n");
- goto fail;
- }
-
- fail:
- if (error)
- fatm_detach(dev);
-
- return (error);
-}
-
-#if defined(FATM_DEBUG) && 0
-static void
-dump_s1_queue(struct fatm_softc *sc)
-{
- int i;
- struct supqueue *q;
-
- for(i = 0; i < SMALL_SUPPLY_QLEN; i++) {
- q = GET_QUEUE(sc->s1queue, struct supqueue, i);
- printf("%2d: card=%x(%x,%x) stat=%x\n", i,
- q->q.card,
- READ4(sc, q->q.card),
- READ4(sc, q->q.card + 4),
- *q->q.statp);
- }
-}
-#endif
-
-/*
- * Driver infrastructure.
- */
-static device_method_t fatm_methods[] = {
- DEVMETHOD(device_probe, fatm_probe),
- DEVMETHOD(device_attach, fatm_attach),
- DEVMETHOD(device_detach, fatm_detach),
- { 0, 0 }
-};
-static driver_t fatm_driver = {
- "fatm",
- fatm_methods,
- sizeof(struct fatm_softc),
-};
-
-DRIVER_MODULE(fatm, pci, fatm_driver, fatm_devclass, 0, 0);