1139749Simp/*- 2116735Sharti * Copyright (c) 2001-2003 3116735Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4116735Sharti * All rights reserved. 5116735Sharti * 6116735Sharti * Redistribution and use in source and binary forms, with or without 7116735Sharti * modification, are permitted provided that the following conditions 8116735Sharti * are met: 9116735Sharti * 1. Redistributions of source code must retain the above copyright 10116735Sharti * notice, this list of conditions and the following disclaimer. 11116735Sharti * 2. Redistributions in binary form must reproduce the above copyright 12116735Sharti * notice, this list of conditions and the following disclaimer in the 13116735Sharti * documentation and/or other materials provided with the distribution. 14116735Sharti * 15116735Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16116735Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17116735Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18116735Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19116735Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20116735Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21116735Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22116735Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23116735Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24116735Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25116735Sharti * SUCH DAMAGE. 26116735Sharti * 27116735Sharti * Author: Hartmut Brandt <harti@freebsd.org> 28116735Sharti * 29116735Sharti * Fore PCA200E driver for NATM 30116735Sharti */ 31119418Sobrien 32116735Sharti#include <sys/cdefs.h> 33116735Sharti__FBSDID("$FreeBSD: stable/11/sys/dev/fatm/if_fatm.c 332288 2018-04-08 16:54:07Z brooks $"); 34116735Sharti 35116735Sharti#include "opt_inet.h" 36116735Sharti#include "opt_natm.h" 37116735Sharti 38116735Sharti#include <sys/types.h> 39116735Sharti#include <sys/param.h> 40116735Sharti#include <sys/systm.h> 41116735Sharti#include <sys/malloc.h> 42116735Sharti#include <sys/kernel.h> 43116735Sharti#include <sys/bus.h> 44116735Sharti#include <sys/errno.h> 45116735Sharti#include <sys/conf.h> 46116735Sharti#include <sys/module.h> 47116735Sharti#include <sys/queue.h> 48116735Sharti#include <sys/syslog.h> 49116735Sharti#include <sys/endian.h> 50116735Sharti#include <sys/sysctl.h> 51116735Sharti#include <sys/condvar.h> 52118208Sharti#include <vm/uma.h> 53116735Sharti 54116735Sharti#include <sys/sockio.h> 55116735Sharti#include <sys/mbuf.h> 56116735Sharti#include <sys/socket.h> 57116735Sharti 58116735Sharti#include <net/if.h> 59257176Sglebius#include <net/if_var.h> 60116735Sharti#include <net/if_media.h> 61147256Sbrooks#include <net/if_types.h> 62116735Sharti#include <net/if_atm.h> 63116735Sharti#include <net/route.h> 64147525Sharti#ifdef ENABLE_BPF 65147525Sharti#include <net/bpf.h> 66147525Sharti#endif 67116735Sharti#ifdef INET 68116735Sharti#include <netinet/in.h> 69116735Sharti#include <netinet/if_atm.h> 70116735Sharti#endif 71116735Sharti 72116735Sharti#include <machine/bus.h> 73116735Sharti#include <machine/resource.h> 74116735Sharti#include <sys/bus.h> 75116735Sharti#include <sys/rman.h> 76119277Simp#include <dev/pci/pcireg.h> 77119277Simp#include <dev/pci/pcivar.h> 78116735Sharti 79116735Sharti#include <dev/utopia/utopia.h> 80116735Sharti 81116735Sharti#include <dev/fatm/if_fatmreg.h> 82116735Sharti#include <dev/fatm/if_fatmvar.h> 83116735Sharti 84116735Sharti#include <dev/fatm/firmware.h> 85116735Sharti 86116735Shartidevclass_t fatm_devclass; 87116735Sharti 88116735Shartistatic const struct { 89116735Sharti uint16_t vid; 90116735Sharti uint16_t did; 91116735Sharti const char *name; 92116735Sharti} fatm_devs[] = { 93116735Sharti { 0x1127, 0x300, 94116735Sharti "FORE PCA200E" }, 95116735Sharti { 0, 0, NULL } 96116735Sharti}; 97116735Sharti 98116735Shartistatic const struct rate { 99116735Sharti uint32_t ratio; 100116735Sharti uint32_t cell_rate; 101116735Sharti} rate_table[] = { 102116735Sharti#include <dev/fatm/if_fatm_rate.h> 103116735Sharti}; 104116735Sharti#define RATE_TABLE_SIZE (sizeof(rate_table) / sizeof(rate_table[0])) 105116735Sharti 106116735ShartiSYSCTL_DECL(_hw_atm); 107116735Sharti 108116735ShartiMODULE_DEPEND(fatm, utopia, 1, 1, 1); 109116735Sharti 110116735Shartistatic int fatm_utopia_readregs(struct ifatm *, u_int, uint8_t *, u_int *); 111116735Shartistatic int fatm_utopia_writereg(struct ifatm *, u_int, u_int, u_int); 112116735Sharti 113116735Shartistatic const struct utopia_methods fatm_utopia_methods = { 114116735Sharti fatm_utopia_readregs, 115116735Sharti fatm_utopia_writereg 116116735Sharti}; 117116735Sharti 118116735Sharti#define VC_OK(SC, VPI, VCI) \ 119298433Spfg (rounddown2(VPI, 1 << IFP2IFATM((SC)->ifp)->mib.vpi_bits) == 0 && \ 120298433Spfg (VCI) != 0 && rounddown2(VCI, 1 << IFP2IFATM((SC)->ifp)->mib.vci_bits) == 0) 121116735Sharti 122118596Shartistatic int fatm_load_vc(struct fatm_softc *sc, struct card_vcc *vc); 123118596Sharti 124116735Sharti/* 125116735Sharti * Probing is easy: step trough the list of known vendor and device 126116735Sharti * ids and compare. If one is found - it's our. 127116735Sharti */ 128116735Shartistatic int 129116735Shartifatm_probe(device_t dev) 130116735Sharti{ 131116735Sharti int i; 132116735Sharti 133116735Sharti for (i = 0; fatm_devs[i].name; i++) 134116735Sharti if (pci_get_vendor(dev) == fatm_devs[i].vid && 135116735Sharti pci_get_device(dev) == fatm_devs[i].did) { 136116735Sharti device_set_desc(dev, fatm_devs[i].name); 137143161Simp return (BUS_PROBE_DEFAULT); 138116735Sharti } 139116735Sharti return (ENXIO); 140116735Sharti} 141116735Sharti 142116735Sharti/* 143116735Sharti * Function called at completion of a SUNI writeregs/readregs command. 144116735Sharti * This is called from the interrupt handler while holding the softc lock. 145116735Sharti * We use the queue entry as the randevouze point. 146116735Sharti */ 147116735Shartistatic void 148116735Shartifatm_utopia_writeregs_complete(struct fatm_softc *sc, struct cmdqueue *q) 149116735Sharti{ 150116735Sharti 151116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 152116735Sharti if(H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) { 153116735Sharti sc->istats.suni_reg_errors++; 154116735Sharti q->error = EIO; 155116735Sharti } 156116735Sharti wakeup(q); 157116735Sharti} 158116735Sharti 159116735Sharti/* 160116735Sharti * Write a SUNI register. The bits that are 1 in mask are written from val 161116735Sharti * into register reg. We wait for the command to complete by sleeping on 162116735Sharti * the register memory. 163116735Sharti * 164116735Sharti * We assume, that we already hold the softc mutex. 165116735Sharti */ 166116735Shartistatic int 167116735Shartifatm_utopia_writereg(struct ifatm *ifatm, u_int reg, u_int mask, u_int val) 168116735Sharti{ 169116735Sharti int error; 170116735Sharti struct cmdqueue *q; 171116735Sharti struct fatm_softc *sc; 172116735Sharti 173147256Sbrooks sc = ifatm->ifp->if_softc; 174116735Sharti FATM_CHECKLOCK(sc); 175148887Srwatson if (!(ifatm->ifp->if_drv_flags & IFF_DRV_RUNNING)) 176116735Sharti return (EIO); 177116735Sharti 178116735Sharti /* get queue element and fill it */ 179116735Sharti q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head); 180116735Sharti 181116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 182116735Sharti if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) { 183116735Sharti sc->istats.cmd_queue_full++; 184116735Sharti return (EIO); 185116735Sharti } 186116735Sharti NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN); 187116735Sharti 188116735Sharti q->error = 0; 189116735Sharti q->cb = fatm_utopia_writeregs_complete; 190116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_PENDING); 191116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 192116735Sharti 193116735Sharti WRITE4(sc, q->q.card + FATMOC_GETOC3_BUF, 0); 194116735Sharti BARRIER_W(sc); 195116735Sharti WRITE4(sc, q->q.card + FATMOC_OP, 196116735Sharti FATM_MAKE_SETOC3(reg, val, mask) | FATM_OP_INTERRUPT_SEL); 197116735Sharti BARRIER_W(sc); 198116735Sharti 199116735Sharti /* 200116735Sharti * Wait for the command to complete 201116735Sharti */ 202116735Sharti error = msleep(q, &sc->mtx, PZERO | PCATCH, "fatm_setreg", hz); 203116735Sharti 204116735Sharti switch(error) { 205116735Sharti 206116735Sharti case EWOULDBLOCK: 207116735Sharti error = EIO; 208116735Sharti break; 209116735Sharti 210116735Sharti case ERESTART: 211116735Sharti error = EINTR; 212116735Sharti break; 213116735Sharti 214116735Sharti case 0: 215116735Sharti error = q->error; 216116735Sharti break; 217116735Sharti } 218116735Sharti 219116735Sharti return (error); 220116735Sharti} 221116735Sharti 222116735Sharti/* 223116735Sharti * Function called at completion of a SUNI readregs command. 224116735Sharti * This is called from the interrupt handler while holding the softc lock. 225116735Sharti * We use reg_mem as the randevouze point. 226116735Sharti */ 227116735Shartistatic void 228116735Shartifatm_utopia_readregs_complete(struct fatm_softc *sc, struct cmdqueue *q) 229116735Sharti{ 230116735Sharti 231116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 232116735Sharti if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) { 233116735Sharti sc->istats.suni_reg_errors++; 234116735Sharti q->error = EIO; 235116735Sharti } 236116735Sharti wakeup(&sc->reg_mem); 237116735Sharti} 238116735Sharti 239116735Sharti/* 240116735Sharti * Read SUNI registers 241116735Sharti * 242116735Sharti * We use a preallocated buffer to read the registers. Therefor we need 243116735Sharti * to protect against multiple threads trying to read registers. We do this 244116735Sharti * with a condition variable and a flag. We wait for the command to complete by sleeping on 245116735Sharti * the register memory. 246116735Sharti * 247116735Sharti * We assume, that we already hold the softc mutex. 248116735Sharti */ 249116735Shartistatic int 250116735Shartifatm_utopia_readregs_internal(struct fatm_softc *sc) 251116735Sharti{ 252116735Sharti int error, i; 253116735Sharti uint32_t *ptr; 254116735Sharti struct cmdqueue *q; 255116735Sharti 256116735Sharti /* get the buffer */ 257116735Sharti for (;;) { 258148887Srwatson if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) 259116735Sharti return (EIO); 260116735Sharti if (!(sc->flags & FATM_REGS_INUSE)) 261116735Sharti break; 262116735Sharti cv_wait(&sc->cv_regs, &sc->mtx); 263116735Sharti } 264116735Sharti sc->flags |= FATM_REGS_INUSE; 265116735Sharti 266116735Sharti q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head); 267116735Sharti 268116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 269116735Sharti if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) { 270116735Sharti sc->istats.cmd_queue_full++; 271116735Sharti return (EIO); 272116735Sharti } 273116735Sharti NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN); 274116735Sharti 275116735Sharti q->error = 0; 276116735Sharti q->cb = fatm_utopia_readregs_complete; 277116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_PENDING); 278116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 279116735Sharti 280116735Sharti bus_dmamap_sync(sc->reg_mem.dmat, sc->reg_mem.map, BUS_DMASYNC_PREREAD); 281116735Sharti 282116735Sharti WRITE4(sc, q->q.card + FATMOC_GETOC3_BUF, sc->reg_mem.paddr); 283116735Sharti BARRIER_W(sc); 284116735Sharti WRITE4(sc, q->q.card + FATMOC_OP, 285116735Sharti FATM_OP_OC3_GET_REG | FATM_OP_INTERRUPT_SEL); 286116735Sharti BARRIER_W(sc); 287116735Sharti 288116735Sharti /* 289116735Sharti * Wait for the command to complete 290116735Sharti */ 291116735Sharti error = msleep(&sc->reg_mem, &sc->mtx, PZERO | PCATCH, 292116735Sharti "fatm_getreg", hz); 293116735Sharti 294116735Sharti switch(error) { 295116735Sharti 296116735Sharti case EWOULDBLOCK: 297116735Sharti error = EIO; 298116735Sharti break; 299116735Sharti 300116735Sharti case ERESTART: 301116735Sharti error = EINTR; 302116735Sharti break; 303116735Sharti 304116735Sharti case 0: 305116735Sharti bus_dmamap_sync(sc->reg_mem.dmat, sc->reg_mem.map, 306116735Sharti BUS_DMASYNC_POSTREAD); 307116735Sharti error = q->error; 308116735Sharti break; 309116735Sharti } 310116735Sharti 311116735Sharti if (error != 0) { 312116735Sharti /* declare buffer to be free */ 313116735Sharti sc->flags &= ~FATM_REGS_INUSE; 314116735Sharti cv_signal(&sc->cv_regs); 315116735Sharti return (error); 316116735Sharti } 317116735Sharti 318116735Sharti /* swap if needed */ 319116735Sharti ptr = (uint32_t *)sc->reg_mem.mem; 320116735Sharti for (i = 0; i < FATM_NREGS; i++) 321116735Sharti ptr[i] = le32toh(ptr[i]) & 0xff; 322116735Sharti 323116735Sharti return (0); 324116735Sharti} 325116735Sharti 326116735Sharti/* 327116735Sharti * Read SUNI registers for the SUNI module. 328116735Sharti * 329116735Sharti * We assume, that we already hold the mutex. 330116735Sharti */ 331116735Shartistatic int 332116735Shartifatm_utopia_readregs(struct ifatm *ifatm, u_int reg, uint8_t *valp, u_int *np) 333116735Sharti{ 334116735Sharti int err; 335116735Sharti int i; 336116735Sharti struct fatm_softc *sc; 337116735Sharti 338116735Sharti if (reg >= FATM_NREGS) 339116735Sharti return (EINVAL); 340116735Sharti if (reg + *np > FATM_NREGS) 341116735Sharti *np = FATM_NREGS - reg; 342147256Sbrooks sc = ifatm->ifp->if_softc; 343116735Sharti FATM_CHECKLOCK(sc); 344116735Sharti 345116735Sharti err = fatm_utopia_readregs_internal(sc); 346116735Sharti if (err != 0) 347116735Sharti return (err); 348116735Sharti 349116735Sharti for (i = 0; i < *np; i++) 350116735Sharti valp[i] = ((uint32_t *)sc->reg_mem.mem)[reg + i]; 351116735Sharti 352116735Sharti /* declare buffer to be free */ 353116735Sharti sc->flags &= ~FATM_REGS_INUSE; 354116735Sharti cv_signal(&sc->cv_regs); 355116735Sharti 356116735Sharti return (0); 357116735Sharti} 358116735Sharti 359116735Sharti/* 360116735Sharti * Check whether the hard is beating. We remember the last heart beat and 361116735Sharti * compare it to the current one. If it appears stuck for 10 times, we have 362116735Sharti * a problem. 363116735Sharti * 364116735Sharti * Assume we hold the lock. 365116735Sharti */ 366116735Shartistatic void 367116735Shartifatm_check_heartbeat(struct fatm_softc *sc) 368116735Sharti{ 369116735Sharti uint32_t h; 370116735Sharti 371116735Sharti FATM_CHECKLOCK(sc); 372116735Sharti 373116735Sharti h = READ4(sc, FATMO_HEARTBEAT); 374116735Sharti DBG(sc, BEAT, ("heartbeat %08x", h)); 375116735Sharti 376116735Sharti if (sc->stop_cnt == 10) 377116735Sharti return; 378116735Sharti 379116735Sharti if (h == sc->heartbeat) { 380116735Sharti if (++sc->stop_cnt == 10) { 381116735Sharti log(LOG_ERR, "i960 stopped???\n"); 382116735Sharti WRITE4(sc, FATMO_HIMR, 1); 383116735Sharti } 384116735Sharti return; 385116735Sharti } 386116735Sharti 387116735Sharti sc->stop_cnt = 0; 388116735Sharti sc->heartbeat = h; 389116735Sharti} 390116735Sharti 391116735Sharti/* 392116735Sharti * Ensure that the heart is still beating. 393116735Sharti */ 394116735Shartistatic void 395199559Sjhbfatm_watchdog(void *arg) 396116735Sharti{ 397199559Sjhb struct fatm_softc *sc; 398116735Sharti 399199559Sjhb sc = arg; 400199559Sjhb FATM_CHECKLOCK(sc); 401199559Sjhb fatm_check_heartbeat(sc); 402199559Sjhb callout_reset(&sc->watchdog_timer, hz * 5, fatm_watchdog, sc); 403116735Sharti} 404116735Sharti 405116735Sharti/* 406116735Sharti * Hard reset the i960 on the board. This is done by initializing registers, 407116735Sharti * clearing interrupts and waiting for the selftest to finish. Not sure, 408116735Sharti * whether all these barriers are actually needed. 409116735Sharti * 410116735Sharti * Assumes that we hold the lock. 411116735Sharti */ 412116735Shartistatic int 413116735Shartifatm_reset(struct fatm_softc *sc) 414116735Sharti{ 415116735Sharti int w; 416116735Sharti uint32_t val; 417116735Sharti 418116735Sharti FATM_CHECKLOCK(sc); 419116735Sharti 420116735Sharti WRITE4(sc, FATMO_APP_BASE, FATMO_COMMON_ORIGIN); 421116735Sharti BARRIER_W(sc); 422116735Sharti 423116735Sharti WRITE4(sc, FATMO_UART_TO_960, XMIT_READY); 424116735Sharti BARRIER_W(sc); 425116735Sharti 426116735Sharti WRITE4(sc, FATMO_UART_TO_HOST, XMIT_READY); 427116735Sharti BARRIER_W(sc); 428116735Sharti 429116735Sharti WRITE4(sc, FATMO_BOOT_STATUS, COLD_START); 430116735Sharti BARRIER_W(sc); 431116735Sharti 432116735Sharti WRITE1(sc, FATMO_HCR, FATM_HCR_RESET); 433116735Sharti BARRIER_W(sc); 434116735Sharti 435116735Sharti DELAY(1000); 436116735Sharti 437116735Sharti WRITE1(sc, FATMO_HCR, 0); 438116735Sharti BARRIER_RW(sc); 439116735Sharti 440116735Sharti DELAY(1000); 441116735Sharti 442116735Sharti for (w = 100; w; w--) { 443116735Sharti BARRIER_R(sc); 444116735Sharti val = READ4(sc, FATMO_BOOT_STATUS); 445116735Sharti switch (val) { 446116735Sharti case SELF_TEST_OK: 447116735Sharti return (0); 448116735Sharti case SELF_TEST_FAIL: 449116735Sharti return (EIO); 450116735Sharti } 451116735Sharti DELAY(1000); 452116735Sharti } 453116735Sharti return (EIO); 454116735Sharti} 455116735Sharti 456116735Sharti/* 457116735Sharti * Stop the card. Must be called WITH the lock held 458118596Sharti * Reset, free transmit and receive buffers. Wakeup everybody who may sleep. 459116735Sharti */ 460116735Shartistatic void 461116735Shartifatm_stop(struct fatm_softc *sc) 462116735Sharti{ 463116735Sharti int i; 464116735Sharti struct cmdqueue *q; 465116735Sharti struct rbuf *rb; 466116735Sharti struct txqueue *tx; 467116735Sharti uint32_t stat; 468116735Sharti 469116735Sharti FATM_CHECKLOCK(sc); 470116735Sharti 471116735Sharti /* Stop the board */ 472116735Sharti utopia_stop(&sc->utopia); 473116735Sharti (void)fatm_reset(sc); 474116735Sharti 475116735Sharti /* stop watchdog */ 476199559Sjhb callout_stop(&sc->watchdog_timer); 477116735Sharti 478148887Srwatson if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) { 479148887Srwatson sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 480147256Sbrooks ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp), 481118168Sharti sc->utopia.carrier == UTP_CARR_OK); 482116735Sharti 483116735Sharti /* 484116735Sharti * Collect transmit mbufs, partial receive mbufs and 485116735Sharti * supplied mbufs 486116735Sharti */ 487116735Sharti for (i = 0; i < FATM_TX_QLEN; i++) { 488116735Sharti tx = GET_QUEUE(sc->txqueue, struct txqueue, i); 489116735Sharti if (tx->m) { 490116735Sharti bus_dmamap_unload(sc->tx_tag, tx->map); 491116735Sharti m_freem(tx->m); 492116735Sharti tx->m = NULL; 493116735Sharti } 494116735Sharti } 495116735Sharti 496116735Sharti /* Collect supplied mbufs */ 497116735Sharti while ((rb = LIST_FIRST(&sc->rbuf_used)) != NULL) { 498116735Sharti LIST_REMOVE(rb, link); 499116735Sharti bus_dmamap_unload(sc->rbuf_tag, rb->map); 500116735Sharti m_free(rb->m); 501116735Sharti rb->m = NULL; 502116735Sharti LIST_INSERT_HEAD(&sc->rbuf_free, rb, link); 503116735Sharti } 504116735Sharti 505116735Sharti /* Unwait any waiters */ 506116735Sharti wakeup(&sc->sadi_mem); 507116735Sharti 508116735Sharti /* wakeup all threads waiting for STAT or REG buffers */ 509116735Sharti cv_broadcast(&sc->cv_stat); 510116735Sharti cv_broadcast(&sc->cv_regs); 511116735Sharti 512116735Sharti sc->flags &= ~(FATM_STAT_INUSE | FATM_REGS_INUSE); 513116735Sharti 514116735Sharti /* wakeup all threads waiting on commands */ 515116735Sharti for (i = 0; i < FATM_CMD_QLEN; i++) { 516116735Sharti q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, i); 517116735Sharti 518116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 519116735Sharti if ((stat = H_GETSTAT(q->q.statp)) != FATM_STAT_FREE) { 520116735Sharti H_SETSTAT(q->q.statp, stat | FATM_STAT_ERROR); 521116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 522116735Sharti wakeup(q); 523116735Sharti } 524116735Sharti } 525116735Sharti utopia_reset_media(&sc->utopia); 526116735Sharti } 527116735Sharti sc->small_cnt = sc->large_cnt = 0; 528116735Sharti 529116735Sharti /* Reset vcc info */ 530118208Sharti if (sc->vccs != NULL) { 531118596Sharti sc->open_vccs = 0; 532118596Sharti for (i = 0; i < FORE_MAX_VCC + 1; i++) { 533118208Sharti if (sc->vccs[i] != NULL) { 534118596Sharti if ((sc->vccs[i]->vflags & (FATM_VCC_OPEN | 535118596Sharti FATM_VCC_TRY_OPEN)) == 0) { 536118596Sharti uma_zfree(sc->vcc_zone, sc->vccs[i]); 537118596Sharti sc->vccs[i] = NULL; 538118596Sharti } else { 539118596Sharti sc->vccs[i]->vflags = 0; 540118596Sharti sc->open_vccs++; 541118596Sharti } 542118208Sharti } 543118596Sharti } 544118208Sharti } 545116735Sharti 546116735Sharti} 547116735Sharti 548116735Sharti/* 549116735Sharti * Load the firmware into the board and save the entry point. 550116735Sharti */ 551116735Shartistatic uint32_t 552116735Shartifirmware_load(struct fatm_softc *sc) 553116735Sharti{ 554116735Sharti struct firmware *fw = (struct firmware *)firmware; 555116735Sharti 556116735Sharti DBG(sc, INIT, ("loading - entry=%x", fw->entry)); 557116735Sharti bus_space_write_region_4(sc->memt, sc->memh, fw->offset, firmware, 558116735Sharti sizeof(firmware) / sizeof(firmware[0])); 559116735Sharti BARRIER_RW(sc); 560116735Sharti 561116735Sharti return (fw->entry); 562116735Sharti} 563116735Sharti 564116735Sharti/* 565116735Sharti * Read a character from the virtual UART. The availability of a character 566116735Sharti * is signaled by a non-null value of the 32 bit register. The eating of 567116735Sharti * the character by us is signalled to the card by setting that register 568116735Sharti * to zero. 569116735Sharti */ 570116735Shartistatic int 571116735Shartirx_getc(struct fatm_softc *sc) 572116735Sharti{ 573116735Sharti int w = 50; 574116735Sharti int c; 575116735Sharti 576116735Sharti while (w--) { 577116735Sharti c = READ4(sc, FATMO_UART_TO_HOST); 578116735Sharti BARRIER_RW(sc); 579116735Sharti if (c != 0) { 580116735Sharti WRITE4(sc, FATMO_UART_TO_HOST, 0); 581116735Sharti DBGC(sc, UART, ("%c", c & 0xff)); 582116735Sharti return (c & 0xff); 583116735Sharti } 584116735Sharti DELAY(1000); 585116735Sharti } 586116735Sharti return (-1); 587116735Sharti} 588116735Sharti 589116735Sharti/* 590116735Sharti * Eat up characters from the board and stuff them in the bit-bucket. 591116735Sharti */ 592116735Shartistatic void 593116735Shartirx_flush(struct fatm_softc *sc) 594116735Sharti{ 595116735Sharti int w = 10000; 596116735Sharti 597116735Sharti while (w-- && rx_getc(sc) >= 0) 598116735Sharti ; 599116735Sharti} 600116735Sharti 601116735Sharti/* 602116735Sharti * Write a character to the card. The UART is available if the register 603116735Sharti * is zero. 604116735Sharti */ 605116735Shartistatic int 606116735Shartitx_putc(struct fatm_softc *sc, u_char c) 607116735Sharti{ 608116735Sharti int w = 10; 609116735Sharti int c1; 610116735Sharti 611116735Sharti while (w--) { 612116735Sharti c1 = READ4(sc, FATMO_UART_TO_960); 613116735Sharti BARRIER_RW(sc); 614116735Sharti if (c1 == 0) { 615116735Sharti WRITE4(sc, FATMO_UART_TO_960, c | CHAR_AVAIL); 616116735Sharti DBGC(sc, UART, ("%c", c & 0xff)); 617116735Sharti return (0); 618116735Sharti } 619116735Sharti DELAY(1000); 620116735Sharti } 621116735Sharti return (-1); 622116735Sharti} 623116735Sharti 624116735Sharti/* 625116735Sharti * Start the firmware. This is doing by issuing a 'go' command with 626116735Sharti * the hex entry address of the firmware. Then we wait for the self-test to 627116735Sharti * succeed. 628116735Sharti */ 629116735Shartistatic int 630116735Shartifatm_start_firmware(struct fatm_softc *sc, uint32_t start) 631116735Sharti{ 632116735Sharti static char hex[] = "0123456789abcdef"; 633116735Sharti u_int w, val; 634116735Sharti 635116735Sharti DBG(sc, INIT, ("starting")); 636116735Sharti rx_flush(sc); 637116735Sharti tx_putc(sc, '\r'); 638116735Sharti DELAY(1000); 639116735Sharti 640116735Sharti rx_flush(sc); 641116735Sharti 642116735Sharti tx_putc(sc, 'g'); 643116735Sharti (void)rx_getc(sc); 644116735Sharti tx_putc(sc, 'o'); 645116735Sharti (void)rx_getc(sc); 646116735Sharti tx_putc(sc, ' '); 647116735Sharti (void)rx_getc(sc); 648116735Sharti 649116735Sharti tx_putc(sc, hex[(start >> 12) & 0xf]); 650116735Sharti (void)rx_getc(sc); 651116735Sharti tx_putc(sc, hex[(start >> 8) & 0xf]); 652116735Sharti (void)rx_getc(sc); 653116735Sharti tx_putc(sc, hex[(start >> 4) & 0xf]); 654116735Sharti (void)rx_getc(sc); 655116735Sharti tx_putc(sc, hex[(start >> 0) & 0xf]); 656116735Sharti (void)rx_getc(sc); 657116735Sharti 658116735Sharti tx_putc(sc, '\r'); 659116735Sharti rx_flush(sc); 660116735Sharti 661116735Sharti for (w = 100; w; w--) { 662116735Sharti BARRIER_R(sc); 663116735Sharti val = READ4(sc, FATMO_BOOT_STATUS); 664116735Sharti switch (val) { 665116735Sharti case CP_RUNNING: 666116735Sharti return (0); 667116735Sharti case SELF_TEST_FAIL: 668116735Sharti return (EIO); 669116735Sharti } 670116735Sharti DELAY(1000); 671116735Sharti } 672116735Sharti return (EIO); 673116735Sharti} 674116735Sharti 675116735Sharti/* 676116735Sharti * Initialize one card and host queue. 677116735Sharti */ 678116735Shartistatic void 679116735Shartiinit_card_queue(struct fatm_softc *sc, struct fqueue *queue, int qlen, 680116735Sharti size_t qel_size, size_t desc_size, cardoff_t off, 681116735Sharti u_char **statpp, uint32_t *cardstat, u_char *descp, uint32_t carddesc) 682116735Sharti{ 683116735Sharti struct fqelem *el = queue->chunk; 684116735Sharti 685116735Sharti while (qlen--) { 686116735Sharti el->card = off; 687116735Sharti off += 8; /* size of card entry */ 688116735Sharti 689116735Sharti el->statp = (uint32_t *)(*statpp); 690116735Sharti (*statpp) += sizeof(uint32_t); 691116735Sharti H_SETSTAT(el->statp, FATM_STAT_FREE); 692116735Sharti H_SYNCSTAT_PREWRITE(sc, el->statp); 693116735Sharti 694116735Sharti WRITE4(sc, el->card + FATMOS_STATP, (*cardstat)); 695116735Sharti (*cardstat) += sizeof(uint32_t); 696116735Sharti 697116735Sharti el->ioblk = descp; 698116735Sharti descp += desc_size; 699116735Sharti el->card_ioblk = carddesc; 700116735Sharti carddesc += desc_size; 701116735Sharti 702116735Sharti el = (struct fqelem *)((u_char *)el + qel_size); 703116735Sharti } 704116735Sharti queue->tail = queue->head = 0; 705116735Sharti} 706116735Sharti 707116735Sharti/* 708116735Sharti * Issue the initialize operation to the card, wait for completion and 709116735Sharti * initialize the on-board and host queue structures with offsets and 710116735Sharti * addresses. 711116735Sharti */ 712116735Shartistatic int 713116735Shartifatm_init_cmd(struct fatm_softc *sc) 714116735Sharti{ 715116735Sharti int w, c; 716116735Sharti u_char *statp; 717116735Sharti uint32_t card_stat; 718116735Sharti u_int cnt; 719116735Sharti struct fqelem *el; 720116735Sharti cardoff_t off; 721116735Sharti 722116735Sharti DBG(sc, INIT, ("command")); 723116735Sharti WRITE4(sc, FATMO_ISTAT, 0); 724116735Sharti WRITE4(sc, FATMO_IMASK, 1); 725116735Sharti WRITE4(sc, FATMO_HLOGGER, 0); 726116735Sharti 727116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_RECEIVE_TRESHOLD, 0); 728116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_NUM_CONNECT, FORE_MAX_VCC); 729116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_CQUEUE_LEN, FATM_CMD_QLEN); 730116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_TQUEUE_LEN, FATM_TX_QLEN); 731116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_RQUEUE_LEN, FATM_RX_QLEN); 732116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_RPD_EXTENSION, RPD_EXTENSIONS); 733116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_TPD_EXTENSION, TPD_EXTENSIONS); 734116735Sharti 735116735Sharti /* 736116735Sharti * initialize buffer descriptors 737116735Sharti */ 738116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_QUEUE_LENGTH, 739116735Sharti SMALL_SUPPLY_QLEN); 740116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_BUFFER_SIZE, 741116735Sharti SMALL_BUFFER_LEN); 742116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_POOL_SIZE, 743116735Sharti SMALL_POOL_SIZE); 744116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B1 + FATMOB_SUPPLY_BLKSIZE, 745116735Sharti SMALL_SUPPLY_BLKSIZE); 746116735Sharti 747116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_QUEUE_LENGTH, 748116735Sharti LARGE_SUPPLY_QLEN); 749116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_BUFFER_SIZE, 750116735Sharti LARGE_BUFFER_LEN); 751116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_POOL_SIZE, 752116735Sharti LARGE_POOL_SIZE); 753116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B1 + FATMOB_SUPPLY_BLKSIZE, 754116735Sharti LARGE_SUPPLY_BLKSIZE); 755116735Sharti 756116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_QUEUE_LENGTH, 0); 757116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_BUFFER_SIZE, 0); 758116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_POOL_SIZE, 0); 759116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_SMALL_B2 + FATMOB_SUPPLY_BLKSIZE, 0); 760116735Sharti 761116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_QUEUE_LENGTH, 0); 762116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_BUFFER_SIZE, 0); 763116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_POOL_SIZE, 0); 764116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_LARGE_B2 + FATMOB_SUPPLY_BLKSIZE, 0); 765116735Sharti 766116735Sharti /* 767116735Sharti * Start the command 768116735Sharti */ 769116735Sharti BARRIER_W(sc); 770116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_STATUS, FATM_STAT_PENDING); 771116735Sharti BARRIER_W(sc); 772116735Sharti WRITE4(sc, FATMO_INIT + FATMOI_OP, FATM_OP_INITIALIZE); 773116735Sharti BARRIER_W(sc); 774116735Sharti 775116735Sharti /* 776116735Sharti * Busy wait for completion 777116735Sharti */ 778116735Sharti w = 100; 779116735Sharti while (w--) { 780116735Sharti c = READ4(sc, FATMO_INIT + FATMOI_STATUS); 781116735Sharti BARRIER_R(sc); 782116735Sharti if (c & FATM_STAT_COMPLETE) 783116735Sharti break; 784116735Sharti DELAY(1000); 785116735Sharti } 786116735Sharti 787116735Sharti if (c & FATM_STAT_ERROR) 788116735Sharti return (EIO); 789116735Sharti 790116735Sharti /* 791116735Sharti * Initialize the queues 792116735Sharti */ 793116735Sharti statp = sc->stat_mem.mem; 794116735Sharti card_stat = sc->stat_mem.paddr; 795116735Sharti 796116735Sharti /* 797116735Sharti * Command queue. This is special in that it's on the card. 798116735Sharti */ 799116735Sharti el = sc->cmdqueue.chunk; 800116735Sharti off = READ4(sc, FATMO_COMMAND_QUEUE); 801116735Sharti DBG(sc, INIT, ("cmd queue=%x", off)); 802116735Sharti for (cnt = 0; cnt < FATM_CMD_QLEN; cnt++) { 803116735Sharti el = &((struct cmdqueue *)sc->cmdqueue.chunk + cnt)->q; 804116735Sharti 805116735Sharti el->card = off; 806116735Sharti off += 32; /* size of card structure */ 807116735Sharti 808116735Sharti el->statp = (uint32_t *)statp; 809116735Sharti statp += sizeof(uint32_t); 810116735Sharti H_SETSTAT(el->statp, FATM_STAT_FREE); 811116735Sharti H_SYNCSTAT_PREWRITE(sc, el->statp); 812116735Sharti 813116735Sharti WRITE4(sc, el->card + FATMOC_STATP, card_stat); 814116735Sharti card_stat += sizeof(uint32_t); 815116735Sharti } 816116735Sharti sc->cmdqueue.tail = sc->cmdqueue.head = 0; 817116735Sharti 818116735Sharti /* 819116735Sharti * Now the other queues. These are in memory 820116735Sharti */ 821116735Sharti init_card_queue(sc, &sc->txqueue, FATM_TX_QLEN, 822116735Sharti sizeof(struct txqueue), TPD_SIZE, 823116735Sharti READ4(sc, FATMO_TRANSMIT_QUEUE), 824116735Sharti &statp, &card_stat, sc->txq_mem.mem, sc->txq_mem.paddr); 825116735Sharti 826116735Sharti init_card_queue(sc, &sc->rxqueue, FATM_RX_QLEN, 827116735Sharti sizeof(struct rxqueue), RPD_SIZE, 828116735Sharti READ4(sc, FATMO_RECEIVE_QUEUE), 829116735Sharti &statp, &card_stat, sc->rxq_mem.mem, sc->rxq_mem.paddr); 830116735Sharti 831116735Sharti init_card_queue(sc, &sc->s1queue, SMALL_SUPPLY_QLEN, 832116735Sharti sizeof(struct supqueue), BSUP_BLK2SIZE(SMALL_SUPPLY_BLKSIZE), 833116735Sharti READ4(sc, FATMO_SMALL_B1_QUEUE), 834116735Sharti &statp, &card_stat, sc->s1q_mem.mem, sc->s1q_mem.paddr); 835116735Sharti 836116735Sharti init_card_queue(sc, &sc->l1queue, LARGE_SUPPLY_QLEN, 837116735Sharti sizeof(struct supqueue), BSUP_BLK2SIZE(LARGE_SUPPLY_BLKSIZE), 838116735Sharti READ4(sc, FATMO_LARGE_B1_QUEUE), 839116735Sharti &statp, &card_stat, sc->l1q_mem.mem, sc->l1q_mem.paddr); 840116735Sharti 841116735Sharti sc->txcnt = 0; 842116735Sharti 843116735Sharti return (0); 844116735Sharti} 845116735Sharti 846116735Sharti/* 847116735Sharti * Read PROM. Called only from attach code. Here we spin because the interrupt 848116735Sharti * handler is not yet set up. 849116735Sharti */ 850116735Shartistatic int 851116735Shartifatm_getprom(struct fatm_softc *sc) 852116735Sharti{ 853116735Sharti int i; 854116735Sharti struct prom *prom; 855116735Sharti struct cmdqueue *q; 856116735Sharti 857116735Sharti DBG(sc, INIT, ("reading prom")); 858116735Sharti q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head); 859116735Sharti NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN); 860116735Sharti 861116735Sharti q->error = 0; 862201758Smbr q->cb = NULL; 863116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_PENDING); 864116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 865116735Sharti 866116735Sharti bus_dmamap_sync(sc->prom_mem.dmat, sc->prom_mem.map, 867116735Sharti BUS_DMASYNC_PREREAD); 868116735Sharti 869116735Sharti WRITE4(sc, q->q.card + FATMOC_GPROM_BUF, sc->prom_mem.paddr); 870116735Sharti BARRIER_W(sc); 871116735Sharti WRITE4(sc, q->q.card + FATMOC_OP, FATM_OP_GET_PROM_DATA); 872116735Sharti BARRIER_W(sc); 873116735Sharti 874116735Sharti for (i = 0; i < 1000; i++) { 875116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 876116735Sharti if (H_GETSTAT(q->q.statp) & 877116735Sharti (FATM_STAT_COMPLETE | FATM_STAT_ERROR)) 878116735Sharti break; 879116735Sharti DELAY(1000); 880116735Sharti } 881116735Sharti if (i == 1000) { 882147256Sbrooks if_printf(sc->ifp, "getprom timeout\n"); 883116735Sharti return (EIO); 884116735Sharti } 885116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 886116735Sharti if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) { 887147256Sbrooks if_printf(sc->ifp, "getprom error\n"); 888116735Sharti return (EIO); 889116735Sharti } 890116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_FREE); 891116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 892116735Sharti NEXT_QUEUE_ENTRY(sc->cmdqueue.tail, FATM_CMD_QLEN); 893116735Sharti 894116735Sharti bus_dmamap_sync(sc->prom_mem.dmat, sc->prom_mem.map, 895116735Sharti BUS_DMASYNC_POSTREAD); 896116735Sharti 897116735Sharti 898116735Sharti#ifdef notdef 899116735Sharti { 900116735Sharti u_int i; 901116735Sharti 902116735Sharti printf("PROM: "); 903116735Sharti u_char *ptr = (u_char *)sc->prom_mem.mem; 904116735Sharti for (i = 0; i < sizeof(struct prom); i++) 905116735Sharti printf("%02x ", *ptr++); 906116735Sharti printf("\n"); 907116735Sharti } 908116735Sharti#endif 909116735Sharti 910116735Sharti prom = (struct prom *)sc->prom_mem.mem; 911116735Sharti 912147256Sbrooks bcopy(prom->mac + 2, IFP2IFATM(sc->ifp)->mib.esi, 6); 913147256Sbrooks IFP2IFATM(sc->ifp)->mib.serial = le32toh(prom->serial); 914147256Sbrooks IFP2IFATM(sc->ifp)->mib.hw_version = le32toh(prom->version); 915147256Sbrooks IFP2IFATM(sc->ifp)->mib.sw_version = READ4(sc, FATMO_FIRMWARE_RELEASE); 916116735Sharti 917147256Sbrooks if_printf(sc->ifp, "ESI=%02x:%02x:%02x:%02x:%02x:%02x " 918147256Sbrooks "serial=%u hw=0x%x sw=0x%x\n", IFP2IFATM(sc->ifp)->mib.esi[0], 919147256Sbrooks IFP2IFATM(sc->ifp)->mib.esi[1], IFP2IFATM(sc->ifp)->mib.esi[2], IFP2IFATM(sc->ifp)->mib.esi[3], 920147256Sbrooks IFP2IFATM(sc->ifp)->mib.esi[4], IFP2IFATM(sc->ifp)->mib.esi[5], IFP2IFATM(sc->ifp)->mib.serial, 921147256Sbrooks IFP2IFATM(sc->ifp)->mib.hw_version, IFP2IFATM(sc->ifp)->mib.sw_version); 922116735Sharti 923116735Sharti return (0); 924116735Sharti} 925116735Sharti 926116735Sharti/* 927116735Sharti * This is the callback function for bus_dmamap_load. We assume, that we 928116735Sharti * have a 32-bit bus and so have always one segment. 929116735Sharti */ 930116735Shartistatic void 931116735Shartidmaload_helper(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 932116735Sharti{ 933116735Sharti bus_addr_t *ptr = (bus_addr_t *)arg; 934116735Sharti 935116735Sharti if (error != 0) { 936116735Sharti printf("%s: error=%d\n", __func__, error); 937116735Sharti return; 938116735Sharti } 939116735Sharti KASSERT(nsegs == 1, ("too many DMA segments")); 940116735Sharti KASSERT(segs[0].ds_addr <= 0xffffffff, ("DMA address too large %lx", 941116735Sharti (u_long)segs[0].ds_addr)); 942116735Sharti 943116735Sharti *ptr = segs[0].ds_addr; 944116735Sharti} 945116735Sharti 946116735Sharti/* 947116735Sharti * Allocate a chunk of DMA-able memory and map it. 948116735Sharti */ 949116735Shartistatic int 950116735Shartialloc_dma_memory(struct fatm_softc *sc, const char *nm, struct fatm_mem *mem) 951116735Sharti{ 952116735Sharti int error; 953116735Sharti 954116735Sharti mem->mem = NULL; 955116735Sharti 956116735Sharti if (bus_dma_tag_create(sc->parent_dmat, mem->align, 0, 957116735Sharti BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 958117126Sscottl NULL, NULL, mem->size, 1, BUS_SPACE_MAXSIZE_32BIT, 959117126Sscottl BUS_DMA_ALLOCNOW, NULL, NULL, &mem->dmat)) { 960147256Sbrooks if_printf(sc->ifp, "could not allocate %s DMA tag\n", 961116735Sharti nm); 962116735Sharti return (ENOMEM); 963116735Sharti } 964116735Sharti 965116735Sharti error = bus_dmamem_alloc(mem->dmat, &mem->mem, 0, &mem->map); 966116735Sharti if (error) { 967147256Sbrooks if_printf(sc->ifp, "could not allocate %s DMA memory: " 968116735Sharti "%d\n", nm, error); 969116735Sharti bus_dma_tag_destroy(mem->dmat); 970116735Sharti mem->mem = NULL; 971116735Sharti return (error); 972116735Sharti } 973116735Sharti 974116735Sharti error = bus_dmamap_load(mem->dmat, mem->map, mem->mem, mem->size, 975116735Sharti dmaload_helper, &mem->paddr, BUS_DMA_NOWAIT); 976116735Sharti if (error) { 977147256Sbrooks if_printf(sc->ifp, "could not load %s DMA memory: " 978116735Sharti "%d\n", nm, error); 979116735Sharti bus_dmamem_free(mem->dmat, mem->mem, mem->map); 980116735Sharti bus_dma_tag_destroy(mem->dmat); 981116735Sharti mem->mem = NULL; 982116735Sharti return (error); 983116735Sharti } 984116735Sharti 985116735Sharti DBG(sc, DMA, ("DMA %s V/P/S/Z %p/%lx/%x/%x", nm, mem->mem, 986116735Sharti (u_long)mem->paddr, mem->size, mem->align)); 987116735Sharti 988116735Sharti return (0); 989116735Sharti} 990116735Sharti 991116735Sharti#ifdef TEST_DMA_SYNC 992116735Shartistatic int 993116735Shartialloc_dma_memoryX(struct fatm_softc *sc, const char *nm, struct fatm_mem *mem) 994116735Sharti{ 995116735Sharti int error; 996116735Sharti 997116735Sharti mem->mem = NULL; 998116735Sharti 999116735Sharti if (bus_dma_tag_create(NULL, mem->align, 0, 1000116735Sharti BUS_SPACE_MAXADDR_24BIT, BUS_SPACE_MAXADDR, 1001116735Sharti NULL, NULL, mem->size, 1, mem->size, 1002117126Sscottl BUS_DMA_ALLOCNOW, NULL, NULL, &mem->dmat)) { 1003147256Sbrooks if_printf(sc->ifp, "could not allocate %s DMA tag\n", 1004116735Sharti nm); 1005116735Sharti return (ENOMEM); 1006116735Sharti } 1007116735Sharti 1008116735Sharti mem->mem = contigmalloc(mem->size, M_DEVBUF, M_WAITOK, 1009116735Sharti BUS_SPACE_MAXADDR_24BIT, BUS_SPACE_MAXADDR_32BIT, mem->align, 0); 1010116735Sharti 1011116735Sharti error = bus_dmamap_create(mem->dmat, 0, &mem->map); 1012116735Sharti if (error) { 1013147256Sbrooks if_printf(sc->ifp, "could not allocate %s DMA map: " 1014116735Sharti "%d\n", nm, error); 1015116735Sharti contigfree(mem->mem, mem->size, M_DEVBUF); 1016116735Sharti bus_dma_tag_destroy(mem->dmat); 1017116735Sharti mem->mem = NULL; 1018116735Sharti return (error); 1019116735Sharti } 1020116735Sharti 1021116735Sharti error = bus_dmamap_load(mem->dmat, mem->map, mem->mem, mem->size, 1022116735Sharti dmaload_helper, &mem->paddr, BUS_DMA_NOWAIT); 1023116735Sharti if (error) { 1024147256Sbrooks if_printf(sc->ifp, "could not load %s DMA memory: " 1025116735Sharti "%d\n", nm, error); 1026116735Sharti bus_dmamap_destroy(mem->dmat, mem->map); 1027116735Sharti contigfree(mem->mem, mem->size, M_DEVBUF); 1028116735Sharti bus_dma_tag_destroy(mem->dmat); 1029116735Sharti mem->mem = NULL; 1030116735Sharti return (error); 1031116735Sharti } 1032116735Sharti 1033116735Sharti DBG(sc, DMA, ("DMAX %s V/P/S/Z %p/%lx/%x/%x", nm, mem->mem, 1034116735Sharti (u_long)mem->paddr, mem->size, mem->align)); 1035116735Sharti 1036116735Sharti printf("DMAX: %s V/P/S/Z %p/%lx/%x/%x", nm, mem->mem, 1037116735Sharti (u_long)mem->paddr, mem->size, mem->align); 1038116735Sharti 1039116735Sharti return (0); 1040116735Sharti} 1041116735Sharti#endif /* TEST_DMA_SYNC */ 1042116735Sharti 1043116735Sharti/* 1044116735Sharti * Destroy all resources of an dma-able memory chunk 1045116735Sharti */ 1046116735Shartistatic void 1047116735Shartidestroy_dma_memory(struct fatm_mem *mem) 1048116735Sharti{ 1049116735Sharti if (mem->mem != NULL) { 1050116735Sharti bus_dmamap_unload(mem->dmat, mem->map); 1051116735Sharti bus_dmamem_free(mem->dmat, mem->mem, mem->map); 1052116735Sharti bus_dma_tag_destroy(mem->dmat); 1053116735Sharti mem->mem = NULL; 1054116735Sharti } 1055116735Sharti} 1056116735Sharti#ifdef TEST_DMA_SYNC 1057116735Shartistatic void 1058116735Shartidestroy_dma_memoryX(struct fatm_mem *mem) 1059116735Sharti{ 1060116735Sharti if (mem->mem != NULL) { 1061116735Sharti bus_dmamap_unload(mem->dmat, mem->map); 1062116735Sharti bus_dmamap_destroy(mem->dmat, mem->map); 1063116735Sharti contigfree(mem->mem, mem->size, M_DEVBUF); 1064116735Sharti bus_dma_tag_destroy(mem->dmat); 1065116735Sharti mem->mem = NULL; 1066116735Sharti } 1067116735Sharti} 1068116735Sharti#endif /* TEST_DMA_SYNC */ 1069116735Sharti 1070116735Sharti/* 1071116735Sharti * Try to supply buffers to the card if there are free entries in the queues 1072116735Sharti */ 1073116735Shartistatic void 1074116735Shartifatm_supply_small_buffers(struct fatm_softc *sc) 1075116735Sharti{ 1076116735Sharti int nblocks, nbufs; 1077116735Sharti struct supqueue *q; 1078116735Sharti struct rbd *bd; 1079116735Sharti int i, j, error, cnt; 1080116735Sharti struct mbuf *m; 1081116735Sharti struct rbuf *rb; 1082116735Sharti bus_addr_t phys; 1083116735Sharti 1084116735Sharti nbufs = max(4 * sc->open_vccs, 32); 1085116735Sharti nbufs = min(nbufs, SMALL_POOL_SIZE); 1086116735Sharti nbufs -= sc->small_cnt; 1087116735Sharti 1088298646Spfg nblocks = howmany(nbufs, SMALL_SUPPLY_BLKSIZE); 1089116735Sharti for (cnt = 0; cnt < nblocks; cnt++) { 1090116735Sharti q = GET_QUEUE(sc->s1queue, struct supqueue, sc->s1queue.head); 1091116735Sharti 1092116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 1093116735Sharti if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE) 1094116735Sharti break; 1095116735Sharti 1096116735Sharti bd = (struct rbd *)q->q.ioblk; 1097116735Sharti 1098116735Sharti for (i = 0; i < SMALL_SUPPLY_BLKSIZE; i++) { 1099116735Sharti if ((rb = LIST_FIRST(&sc->rbuf_free)) == NULL) { 1100147256Sbrooks if_printf(sc->ifp, "out of rbufs\n"); 1101116735Sharti break; 1102116735Sharti } 1103243857Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 1104116735Sharti if (m == NULL) { 1105116735Sharti LIST_INSERT_HEAD(&sc->rbuf_free, rb, link); 1106116735Sharti break; 1107116735Sharti } 1108276692Srwatson M_ALIGN(m, SMALL_BUFFER_LEN); 1109116735Sharti error = bus_dmamap_load(sc->rbuf_tag, rb->map, 1110116735Sharti m->m_data, SMALL_BUFFER_LEN, dmaload_helper, 1111116735Sharti &phys, BUS_DMA_NOWAIT); 1112116735Sharti if (error) { 1113147256Sbrooks if_printf(sc->ifp, 1114116735Sharti "dmamap_load mbuf failed %d", error); 1115116735Sharti m_freem(m); 1116116735Sharti LIST_INSERT_HEAD(&sc->rbuf_free, rb, link); 1117116735Sharti break; 1118116735Sharti } 1119116735Sharti bus_dmamap_sync(sc->rbuf_tag, rb->map, 1120116735Sharti BUS_DMASYNC_PREREAD); 1121116735Sharti 1122116735Sharti LIST_REMOVE(rb, link); 1123116735Sharti LIST_INSERT_HEAD(&sc->rbuf_used, rb, link); 1124116735Sharti 1125116735Sharti rb->m = m; 1126116735Sharti bd[i].handle = rb - sc->rbufs; 1127116735Sharti H_SETDESC(bd[i].buffer, phys); 1128116735Sharti } 1129116735Sharti 1130116735Sharti if (i < SMALL_SUPPLY_BLKSIZE) { 1131116735Sharti for (j = 0; j < i; j++) { 1132116735Sharti rb = sc->rbufs + bd[j].handle; 1133116735Sharti bus_dmamap_unload(sc->rbuf_tag, rb->map); 1134116735Sharti m_free(rb->m); 1135116735Sharti rb->m = NULL; 1136116735Sharti 1137116735Sharti LIST_REMOVE(rb, link); 1138116735Sharti LIST_INSERT_HEAD(&sc->rbuf_free, rb, link); 1139116735Sharti } 1140116735Sharti break; 1141116735Sharti } 1142116735Sharti H_SYNCQ_PREWRITE(&sc->s1q_mem, bd, 1143116735Sharti sizeof(struct rbd) * SMALL_SUPPLY_BLKSIZE); 1144116735Sharti 1145116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_PENDING); 1146116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 1147116735Sharti 1148116735Sharti WRITE4(sc, q->q.card, q->q.card_ioblk); 1149116735Sharti BARRIER_W(sc); 1150116735Sharti 1151116735Sharti sc->small_cnt += SMALL_SUPPLY_BLKSIZE; 1152116735Sharti 1153116735Sharti NEXT_QUEUE_ENTRY(sc->s1queue.head, SMALL_SUPPLY_QLEN); 1154116735Sharti } 1155116735Sharti} 1156116735Sharti 1157116735Sharti/* 1158116735Sharti * Try to supply buffers to the card if there are free entries in the queues 1159116735Sharti * We assume that all buffers are within the address space accessible by the 1160116735Sharti * card (32-bit), so we don't need bounce buffers. 1161116735Sharti */ 1162116735Shartistatic void 1163116735Shartifatm_supply_large_buffers(struct fatm_softc *sc) 1164116735Sharti{ 1165116735Sharti int nbufs, nblocks, cnt; 1166116735Sharti struct supqueue *q; 1167116735Sharti struct rbd *bd; 1168116735Sharti int i, j, error; 1169116735Sharti struct mbuf *m; 1170116735Sharti struct rbuf *rb; 1171116735Sharti bus_addr_t phys; 1172116735Sharti 1173116735Sharti nbufs = max(4 * sc->open_vccs, 32); 1174116735Sharti nbufs = min(nbufs, LARGE_POOL_SIZE); 1175116735Sharti nbufs -= sc->large_cnt; 1176116735Sharti 1177298646Spfg nblocks = howmany(nbufs, LARGE_SUPPLY_BLKSIZE); 1178116735Sharti 1179116735Sharti for (cnt = 0; cnt < nblocks; cnt++) { 1180116735Sharti q = GET_QUEUE(sc->l1queue, struct supqueue, sc->l1queue.head); 1181116735Sharti 1182116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 1183116735Sharti if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE) 1184116735Sharti break; 1185116735Sharti 1186116735Sharti bd = (struct rbd *)q->q.ioblk; 1187116735Sharti 1188116735Sharti for (i = 0; i < LARGE_SUPPLY_BLKSIZE; i++) { 1189116735Sharti if ((rb = LIST_FIRST(&sc->rbuf_free)) == NULL) { 1190147256Sbrooks if_printf(sc->ifp, "out of rbufs\n"); 1191116735Sharti break; 1192116735Sharti } 1193243857Sglebius if ((m = m_getcl(M_NOWAIT, MT_DATA, 1194116735Sharti M_PKTHDR)) == NULL) { 1195116735Sharti LIST_INSERT_HEAD(&sc->rbuf_free, rb, link); 1196116735Sharti break; 1197116735Sharti } 1198116735Sharti /* No MEXT_ALIGN */ 1199116735Sharti m->m_data += MCLBYTES - LARGE_BUFFER_LEN; 1200116735Sharti error = bus_dmamap_load(sc->rbuf_tag, rb->map, 1201116735Sharti m->m_data, LARGE_BUFFER_LEN, dmaload_helper, 1202116735Sharti &phys, BUS_DMA_NOWAIT); 1203116735Sharti if (error) { 1204147256Sbrooks if_printf(sc->ifp, 1205116735Sharti "dmamap_load mbuf failed %d", error); 1206116735Sharti m_freem(m); 1207116735Sharti LIST_INSERT_HEAD(&sc->rbuf_free, rb, link); 1208116735Sharti break; 1209116735Sharti } 1210116735Sharti 1211116735Sharti bus_dmamap_sync(sc->rbuf_tag, rb->map, 1212116735Sharti BUS_DMASYNC_PREREAD); 1213116735Sharti 1214116735Sharti LIST_REMOVE(rb, link); 1215116735Sharti LIST_INSERT_HEAD(&sc->rbuf_used, rb, link); 1216116735Sharti 1217116735Sharti rb->m = m; 1218116735Sharti bd[i].handle = rb - sc->rbufs; 1219116735Sharti H_SETDESC(bd[i].buffer, phys); 1220116735Sharti } 1221116735Sharti 1222116735Sharti if (i < LARGE_SUPPLY_BLKSIZE) { 1223116735Sharti for (j = 0; j < i; j++) { 1224116735Sharti rb = sc->rbufs + bd[j].handle; 1225116735Sharti bus_dmamap_unload(sc->rbuf_tag, rb->map); 1226116735Sharti m_free(rb->m); 1227116735Sharti rb->m = NULL; 1228116735Sharti 1229116735Sharti LIST_REMOVE(rb, link); 1230116735Sharti LIST_INSERT_HEAD(&sc->rbuf_free, rb, link); 1231116735Sharti } 1232116735Sharti break; 1233116735Sharti } 1234116735Sharti H_SYNCQ_PREWRITE(&sc->l1q_mem, bd, 1235116735Sharti sizeof(struct rbd) * LARGE_SUPPLY_BLKSIZE); 1236116735Sharti 1237116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_PENDING); 1238116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 1239116735Sharti WRITE4(sc, q->q.card, q->q.card_ioblk); 1240116735Sharti BARRIER_W(sc); 1241116735Sharti 1242116735Sharti sc->large_cnt += LARGE_SUPPLY_BLKSIZE; 1243116735Sharti 1244116735Sharti NEXT_QUEUE_ENTRY(sc->l1queue.head, LARGE_SUPPLY_QLEN); 1245116735Sharti } 1246116735Sharti} 1247116735Sharti 1248116735Sharti 1249116735Sharti/* 1250116735Sharti * Actually start the card. The lock must be held here. 1251116735Sharti * Reset, load the firmware, start it, initializes queues, read the PROM 1252116735Sharti * and supply receive buffers to the card. 1253116735Sharti */ 1254116735Shartistatic void 1255116735Shartifatm_init_locked(struct fatm_softc *sc) 1256116735Sharti{ 1257116735Sharti struct rxqueue *q; 1258118596Sharti int i, c, error; 1259116735Sharti uint32_t start; 1260116735Sharti 1261116735Sharti DBG(sc, INIT, ("initialize")); 1262148887Srwatson if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) 1263116735Sharti fatm_stop(sc); 1264116735Sharti 1265116735Sharti /* 1266116735Sharti * Hard reset the board 1267116735Sharti */ 1268116735Sharti if (fatm_reset(sc)) 1269116735Sharti return; 1270116735Sharti 1271116735Sharti start = firmware_load(sc); 1272116735Sharti if (fatm_start_firmware(sc, start) || fatm_init_cmd(sc) || 1273116735Sharti fatm_getprom(sc)) { 1274116735Sharti fatm_reset(sc); 1275116735Sharti return; 1276116735Sharti } 1277116735Sharti 1278116735Sharti /* 1279116735Sharti * Handle media 1280116735Sharti */ 1281116735Sharti c = READ4(sc, FATMO_MEDIA_TYPE); 1282116735Sharti switch (c) { 1283116735Sharti 1284116735Sharti case FORE_MT_TAXI_100: 1285147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_TAXI_100; 1286147256Sbrooks IFP2IFATM(sc->ifp)->mib.pcr = 227273; 1287116735Sharti break; 1288116735Sharti 1289116735Sharti case FORE_MT_TAXI_140: 1290147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_TAXI_140; 1291147256Sbrooks IFP2IFATM(sc->ifp)->mib.pcr = 318181; 1292116735Sharti break; 1293116735Sharti 1294116735Sharti case FORE_MT_UTP_SONET: 1295147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UTP_155; 1296147256Sbrooks IFP2IFATM(sc->ifp)->mib.pcr = 353207; 1297116735Sharti break; 1298116735Sharti 1299116735Sharti case FORE_MT_MM_OC3_ST: 1300116735Sharti case FORE_MT_MM_OC3_SC: 1301147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_MM_155; 1302147256Sbrooks IFP2IFATM(sc->ifp)->mib.pcr = 353207; 1303116735Sharti break; 1304116735Sharti 1305116735Sharti case FORE_MT_SM_OC3_ST: 1306116735Sharti case FORE_MT_SM_OC3_SC: 1307147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_SM_155; 1308147256Sbrooks IFP2IFATM(sc->ifp)->mib.pcr = 353207; 1309116735Sharti break; 1310116735Sharti 1311116735Sharti default: 1312116735Sharti log(LOG_ERR, "fatm: unknown media type %d\n", c); 1313147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UNKNOWN; 1314147256Sbrooks IFP2IFATM(sc->ifp)->mib.pcr = 353207; 1315116735Sharti break; 1316116735Sharti } 1317147256Sbrooks sc->ifp->if_baudrate = 53 * 8 * IFP2IFATM(sc->ifp)->mib.pcr; 1318116735Sharti utopia_init_media(&sc->utopia); 1319116735Sharti 1320116735Sharti /* 1321116735Sharti * Initialize the RBDs 1322116735Sharti */ 1323116735Sharti for (i = 0; i < FATM_RX_QLEN; i++) { 1324116735Sharti q = GET_QUEUE(sc->rxqueue, struct rxqueue, i); 1325116735Sharti WRITE4(sc, q->q.card + 0, q->q.card_ioblk); 1326116735Sharti } 1327116735Sharti BARRIER_W(sc); 1328116735Sharti 1329116735Sharti /* 1330116735Sharti * Supply buffers to the card 1331116735Sharti */ 1332116735Sharti fatm_supply_small_buffers(sc); 1333116735Sharti fatm_supply_large_buffers(sc); 1334116735Sharti 1335116735Sharti /* 1336116735Sharti * Now set flags, that we are ready 1337116735Sharti */ 1338148887Srwatson sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 1339116735Sharti 1340116735Sharti /* 1341116735Sharti * Start the watchdog timer 1342116735Sharti */ 1343199559Sjhb callout_reset(&sc->watchdog_timer, hz * 5, fatm_watchdog, sc); 1344116735Sharti 1345116735Sharti /* start SUNI */ 1346116735Sharti utopia_start(&sc->utopia); 1347116735Sharti 1348147256Sbrooks ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp), 1349118168Sharti sc->utopia.carrier == UTP_CARR_OK); 1350118168Sharti 1351118596Sharti /* start all channels */ 1352118596Sharti for (i = 0; i < FORE_MAX_VCC + 1; i++) 1353118596Sharti if (sc->vccs[i] != NULL) { 1354118596Sharti sc->vccs[i]->vflags |= FATM_VCC_REOPEN; 1355118596Sharti error = fatm_load_vc(sc, sc->vccs[i]); 1356118596Sharti if (error != 0) { 1357147256Sbrooks if_printf(sc->ifp, "reopening %u " 1358118596Sharti "failed: %d\n", i, error); 1359118596Sharti sc->vccs[i]->vflags &= ~FATM_VCC_REOPEN; 1360118596Sharti } 1361118596Sharti } 1362118596Sharti 1363116735Sharti DBG(sc, INIT, ("done")); 1364116735Sharti} 1365116735Sharti 1366116735Sharti/* 1367116735Sharti * This is the exported as initialisation function. 1368116735Sharti */ 1369116735Shartistatic void 1370116735Shartifatm_init(void *p) 1371116735Sharti{ 1372116735Sharti struct fatm_softc *sc = p; 1373116735Sharti 1374116735Sharti FATM_LOCK(sc); 1375116735Sharti fatm_init_locked(sc); 1376116735Sharti FATM_UNLOCK(sc); 1377116735Sharti} 1378116735Sharti 1379116735Sharti/************************************************************/ 1380116735Sharti/* 1381116735Sharti * The INTERRUPT handling 1382116735Sharti */ 1383116735Sharti/* 1384116735Sharti * Check the command queue. If a command was completed, call the completion 1385116735Sharti * function for that command. 1386116735Sharti */ 1387116735Shartistatic void 1388116735Shartifatm_intr_drain_cmd(struct fatm_softc *sc) 1389116735Sharti{ 1390116735Sharti struct cmdqueue *q; 1391116735Sharti int stat; 1392116735Sharti 1393116735Sharti /* 1394116735Sharti * Drain command queue 1395116735Sharti */ 1396116735Sharti for (;;) { 1397116735Sharti q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.tail); 1398116735Sharti 1399116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 1400116735Sharti stat = H_GETSTAT(q->q.statp); 1401116735Sharti 1402116735Sharti if (stat != FATM_STAT_COMPLETE && 1403116735Sharti stat != (FATM_STAT_COMPLETE | FATM_STAT_ERROR) && 1404116735Sharti stat != FATM_STAT_ERROR) 1405116735Sharti break; 1406116735Sharti 1407116735Sharti (*q->cb)(sc, q); 1408116735Sharti 1409116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_FREE); 1410116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 1411116735Sharti 1412116735Sharti NEXT_QUEUE_ENTRY(sc->cmdqueue.tail, FATM_CMD_QLEN); 1413116735Sharti } 1414116735Sharti} 1415116735Sharti 1416116735Sharti/* 1417116735Sharti * Drain the small buffer supply queue. 1418116735Sharti */ 1419116735Shartistatic void 1420116735Shartifatm_intr_drain_small_buffers(struct fatm_softc *sc) 1421116735Sharti{ 1422116735Sharti struct supqueue *q; 1423116735Sharti int stat; 1424116735Sharti 1425116735Sharti for (;;) { 1426116735Sharti q = GET_QUEUE(sc->s1queue, struct supqueue, sc->s1queue.tail); 1427116735Sharti 1428116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 1429116735Sharti stat = H_GETSTAT(q->q.statp); 1430116735Sharti 1431116735Sharti if ((stat & FATM_STAT_COMPLETE) == 0) 1432116735Sharti break; 1433116735Sharti if (stat & FATM_STAT_ERROR) 1434116735Sharti log(LOG_ERR, "%s: status %x\n", __func__, stat); 1435116735Sharti 1436116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_FREE); 1437116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 1438116735Sharti 1439116735Sharti NEXT_QUEUE_ENTRY(sc->s1queue.tail, SMALL_SUPPLY_QLEN); 1440116735Sharti } 1441116735Sharti} 1442116735Sharti 1443116735Sharti/* 1444116735Sharti * Drain the large buffer supply queue. 1445116735Sharti */ 1446116735Shartistatic void 1447116735Shartifatm_intr_drain_large_buffers(struct fatm_softc *sc) 1448116735Sharti{ 1449116735Sharti struct supqueue *q; 1450116735Sharti int stat; 1451116735Sharti 1452116735Sharti for (;;) { 1453116735Sharti q = GET_QUEUE(sc->l1queue, struct supqueue, sc->l1queue.tail); 1454116735Sharti 1455116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 1456116735Sharti stat = H_GETSTAT(q->q.statp); 1457116735Sharti 1458116735Sharti if ((stat & FATM_STAT_COMPLETE) == 0) 1459116735Sharti break; 1460116735Sharti if (stat & FATM_STAT_ERROR) 1461116735Sharti log(LOG_ERR, "%s status %x\n", __func__, stat); 1462116735Sharti 1463116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_FREE); 1464116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 1465116735Sharti 1466116735Sharti NEXT_QUEUE_ENTRY(sc->l1queue.tail, LARGE_SUPPLY_QLEN); 1467116735Sharti } 1468116735Sharti} 1469116735Sharti 1470116735Sharti/* 1471116735Sharti * Check the receive queue. Send any received PDU up the protocol stack 1472116735Sharti * (except when there was an error or the VCI appears to be closed. In this 1473116735Sharti * case discard the PDU). 1474116735Sharti */ 1475116735Shartistatic void 1476116735Shartifatm_intr_drain_rx(struct fatm_softc *sc) 1477116735Sharti{ 1478116735Sharti struct rxqueue *q; 1479118208Sharti int stat, mlen; 1480116735Sharti u_int i; 1481116735Sharti uint32_t h; 1482116735Sharti struct mbuf *last, *m0; 1483116735Sharti struct rpd *rpd; 1484116735Sharti struct rbuf *rb; 1485116735Sharti u_int vci, vpi, pt; 1486116735Sharti struct atm_pseudohdr aph; 1487116735Sharti struct ifnet *ifp; 1488118208Sharti struct card_vcc *vc; 1489116735Sharti 1490116735Sharti for (;;) { 1491116735Sharti q = GET_QUEUE(sc->rxqueue, struct rxqueue, sc->rxqueue.tail); 1492116735Sharti 1493116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 1494116735Sharti stat = H_GETSTAT(q->q.statp); 1495116735Sharti 1496116735Sharti if ((stat & FATM_STAT_COMPLETE) == 0) 1497116735Sharti break; 1498116735Sharti 1499116735Sharti rpd = (struct rpd *)q->q.ioblk; 1500116735Sharti H_SYNCQ_POSTREAD(&sc->rxq_mem, rpd, RPD_SIZE); 1501116735Sharti 1502116735Sharti rpd->nseg = le32toh(rpd->nseg); 1503116735Sharti mlen = 0; 1504315221Spfg m0 = last = NULL; 1505116735Sharti for (i = 0; i < rpd->nseg; i++) { 1506116735Sharti rb = sc->rbufs + rpd->segment[i].handle; 1507116735Sharti if (m0 == NULL) { 1508116735Sharti m0 = last = rb->m; 1509116735Sharti } else { 1510116735Sharti last->m_next = rb->m; 1511116735Sharti last = rb->m; 1512116735Sharti } 1513116735Sharti last->m_next = NULL; 1514116735Sharti if (last->m_flags & M_EXT) 1515116735Sharti sc->large_cnt--; 1516116735Sharti else 1517116735Sharti sc->small_cnt--; 1518116735Sharti bus_dmamap_sync(sc->rbuf_tag, rb->map, 1519116735Sharti BUS_DMASYNC_POSTREAD); 1520116735Sharti bus_dmamap_unload(sc->rbuf_tag, rb->map); 1521116735Sharti rb->m = NULL; 1522116735Sharti 1523116735Sharti LIST_REMOVE(rb, link); 1524116735Sharti LIST_INSERT_HEAD(&sc->rbuf_free, rb, link); 1525116735Sharti 1526116735Sharti last->m_len = le32toh(rpd->segment[i].length); 1527116735Sharti mlen += last->m_len; 1528116735Sharti } 1529116735Sharti 1530116735Sharti m0->m_pkthdr.len = mlen; 1531147256Sbrooks m0->m_pkthdr.rcvif = sc->ifp; 1532116735Sharti 1533116735Sharti h = le32toh(rpd->atm_header); 1534116735Sharti vpi = (h >> 20) & 0xff; 1535116735Sharti vci = (h >> 4 ) & 0xffff; 1536116735Sharti pt = (h >> 1 ) & 0x7; 1537116735Sharti 1538116735Sharti /* 1539116735Sharti * Locate the VCC this packet belongs to 1540116735Sharti */ 1541116735Sharti if (!VC_OK(sc, vpi, vci)) 1542118208Sharti vc = NULL; 1543118208Sharti else if ((vc = sc->vccs[vci]) == NULL || 1544118208Sharti !(sc->vccs[vci]->vflags & FATM_VCC_OPEN)) { 1545116735Sharti sc->istats.rx_closed++; 1546118208Sharti vc = NULL; 1547116735Sharti } 1548116735Sharti 1549116735Sharti DBG(sc, RCV, ("RCV: vc=%u.%u pt=%u mlen=%d %s", vpi, vci, 1550118208Sharti pt, mlen, vc == NULL ? "dropped" : "")); 1551116735Sharti 1552118208Sharti if (vc == NULL) { 1553116735Sharti m_freem(m0); 1554116735Sharti } else { 1555147525Sharti#ifdef ENABLE_BPF 1556147525Sharti if (!(vc->param.flags & ATMIO_FLAG_NG) && 1557147525Sharti vc->param.aal == ATMIO_AAL_5 && 1558147525Sharti (vc->param.flags & ATM_PH_LLCSNAP)) 1559147525Sharti BPF_MTAP(sc->ifp, m0); 1560147525Sharti#endif 1561147525Sharti 1562118208Sharti ATM_PH_FLAGS(&aph) = vc->param.flags; 1563116735Sharti ATM_PH_VPI(&aph) = vpi; 1564116735Sharti ATM_PH_SETVCI(&aph, vci); 1565116735Sharti 1566147256Sbrooks ifp = sc->ifp; 1567271849Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 1568116735Sharti 1569118208Sharti vc->ipackets++; 1570118208Sharti vc->ibytes += m0->m_pkthdr.len; 1571118208Sharti 1572118208Sharti atm_input(ifp, &aph, m0, vc->rxhand); 1573116735Sharti } 1574116735Sharti 1575116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_FREE); 1576116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 1577116735Sharti 1578116735Sharti WRITE4(sc, q->q.card, q->q.card_ioblk); 1579116735Sharti BARRIER_W(sc); 1580116735Sharti 1581116735Sharti NEXT_QUEUE_ENTRY(sc->rxqueue.tail, FATM_RX_QLEN); 1582116735Sharti } 1583116735Sharti} 1584116735Sharti 1585116735Sharti/* 1586116735Sharti * Check the transmit queue. Free the mbuf chains that we were transmitting. 1587116735Sharti */ 1588116735Shartistatic void 1589116735Shartifatm_intr_drain_tx(struct fatm_softc *sc) 1590116735Sharti{ 1591116735Sharti struct txqueue *q; 1592116735Sharti int stat; 1593116735Sharti 1594116735Sharti /* 1595116735Sharti * Drain tx queue 1596116735Sharti */ 1597116735Sharti for (;;) { 1598116735Sharti q = GET_QUEUE(sc->txqueue, struct txqueue, sc->txqueue.tail); 1599116735Sharti 1600116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 1601116735Sharti stat = H_GETSTAT(q->q.statp); 1602116735Sharti 1603116735Sharti if (stat != FATM_STAT_COMPLETE && 1604116735Sharti stat != (FATM_STAT_COMPLETE | FATM_STAT_ERROR) && 1605116735Sharti stat != FATM_STAT_ERROR) 1606116735Sharti break; 1607116735Sharti 1608116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_FREE); 1609116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 1610116735Sharti 1611116735Sharti bus_dmamap_sync(sc->tx_tag, q->map, BUS_DMASYNC_POSTWRITE); 1612116735Sharti bus_dmamap_unload(sc->tx_tag, q->map); 1613116735Sharti 1614116735Sharti m_freem(q->m); 1615116735Sharti q->m = NULL; 1616116735Sharti sc->txcnt--; 1617116735Sharti 1618116735Sharti NEXT_QUEUE_ENTRY(sc->txqueue.tail, FATM_TX_QLEN); 1619116735Sharti } 1620116735Sharti} 1621116735Sharti 1622116735Sharti/* 1623116735Sharti * Interrupt handler 1624116735Sharti */ 1625116735Shartistatic void 1626116735Shartifatm_intr(void *p) 1627116735Sharti{ 1628116735Sharti struct fatm_softc *sc = (struct fatm_softc *)p; 1629116735Sharti 1630116735Sharti FATM_LOCK(sc); 1631116735Sharti if (!READ4(sc, FATMO_PSR)) { 1632116735Sharti FATM_UNLOCK(sc); 1633116735Sharti return; 1634116735Sharti } 1635116735Sharti WRITE4(sc, FATMO_HCR, FATM_HCR_CLRIRQ); 1636116735Sharti 1637148887Srwatson if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1638116735Sharti FATM_UNLOCK(sc); 1639116735Sharti return; 1640116735Sharti } 1641116735Sharti fatm_intr_drain_cmd(sc); 1642116735Sharti fatm_intr_drain_rx(sc); 1643116735Sharti fatm_intr_drain_tx(sc); 1644116735Sharti fatm_intr_drain_small_buffers(sc); 1645116735Sharti fatm_intr_drain_large_buffers(sc); 1646116735Sharti fatm_supply_small_buffers(sc); 1647116735Sharti fatm_supply_large_buffers(sc); 1648116735Sharti 1649116735Sharti FATM_UNLOCK(sc); 1650116735Sharti 1651147256Sbrooks if (sc->retry_tx && _IF_QLEN(&sc->ifp->if_snd)) 1652147256Sbrooks (*sc->ifp->if_start)(sc->ifp); 1653116735Sharti} 1654116735Sharti 1655116735Sharti/* 1656116735Sharti * Get device statistics. This must be called with the softc locked. 1657116735Sharti * We use a preallocated buffer, so we need to protect this buffer. 1658116735Sharti * We do this by using a condition variable and a flag. If the flag is set 1659116735Sharti * the buffer is in use by one thread (one thread is executing a GETSTAT 1660116735Sharti * card command). In this case all other threads that are trying to get 1661116735Sharti * statistics block on that condition variable. When the thread finishes 1662116735Sharti * using the buffer it resets the flag and signals the condition variable. This 1663116735Sharti * will wakeup the next thread that is waiting for the buffer. If the interface 1664116735Sharti * is stopped the stopping function will broadcast the cv. All threads will 1665116735Sharti * find that the interface has been stopped and return. 1666116735Sharti * 1667298955Spfg * Acquiring of the buffer is done by the fatm_getstat() function. The freeing 1668116735Sharti * must be done by the caller when he has finished using the buffer. 1669116735Sharti */ 1670116735Shartistatic void 1671116735Shartifatm_getstat_complete(struct fatm_softc *sc, struct cmdqueue *q) 1672116735Sharti{ 1673116735Sharti 1674116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 1675116735Sharti if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) { 1676116735Sharti sc->istats.get_stat_errors++; 1677116735Sharti q->error = EIO; 1678116735Sharti } 1679116735Sharti wakeup(&sc->sadi_mem); 1680116735Sharti} 1681116735Shartistatic int 1682116735Shartifatm_getstat(struct fatm_softc *sc) 1683116735Sharti{ 1684116735Sharti int error; 1685116735Sharti struct cmdqueue *q; 1686116735Sharti 1687116735Sharti /* 1688116735Sharti * Wait until either the interface is stopped or we can get the 1689116735Sharti * statistics buffer 1690116735Sharti */ 1691116735Sharti for (;;) { 1692148887Srwatson if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) 1693116735Sharti return (EIO); 1694116735Sharti if (!(sc->flags & FATM_STAT_INUSE)) 1695116735Sharti break; 1696116735Sharti cv_wait(&sc->cv_stat, &sc->mtx); 1697116735Sharti } 1698116735Sharti sc->flags |= FATM_STAT_INUSE; 1699116735Sharti 1700116735Sharti q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head); 1701116735Sharti 1702116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 1703116735Sharti if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) { 1704116735Sharti sc->istats.cmd_queue_full++; 1705116735Sharti return (EIO); 1706116735Sharti } 1707116735Sharti NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN); 1708116735Sharti 1709116735Sharti q->error = 0; 1710116735Sharti q->cb = fatm_getstat_complete; 1711116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_PENDING); 1712116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 1713116735Sharti 1714116735Sharti bus_dmamap_sync(sc->sadi_mem.dmat, sc->sadi_mem.map, 1715116735Sharti BUS_DMASYNC_PREREAD); 1716116735Sharti 1717116735Sharti WRITE4(sc, q->q.card + FATMOC_GSTAT_BUF, 1718116735Sharti sc->sadi_mem.paddr); 1719116735Sharti BARRIER_W(sc); 1720116735Sharti WRITE4(sc, q->q.card + FATMOC_OP, 1721116735Sharti FATM_OP_REQUEST_STATS | FATM_OP_INTERRUPT_SEL); 1722116735Sharti BARRIER_W(sc); 1723116735Sharti 1724116735Sharti /* 1725116735Sharti * Wait for the command to complete 1726116735Sharti */ 1727116735Sharti error = msleep(&sc->sadi_mem, &sc->mtx, PZERO | PCATCH, 1728116735Sharti "fatm_stat", hz); 1729116735Sharti 1730116735Sharti switch (error) { 1731116735Sharti 1732116735Sharti case EWOULDBLOCK: 1733116735Sharti error = EIO; 1734116735Sharti break; 1735116735Sharti 1736116735Sharti case ERESTART: 1737116735Sharti error = EINTR; 1738116735Sharti break; 1739116735Sharti 1740116735Sharti case 0: 1741116735Sharti bus_dmamap_sync(sc->sadi_mem.dmat, sc->sadi_mem.map, 1742116735Sharti BUS_DMASYNC_POSTREAD); 1743116735Sharti error = q->error; 1744116735Sharti break; 1745116735Sharti } 1746116735Sharti 1747116735Sharti /* 1748116735Sharti * Swap statistics 1749116735Sharti */ 1750116735Sharti if (q->error == 0) { 1751116735Sharti u_int i; 1752116735Sharti uint32_t *p = (uint32_t *)sc->sadi_mem.mem; 1753116735Sharti 1754116735Sharti for (i = 0; i < sizeof(struct fatm_stats) / sizeof(uint32_t); 1755116735Sharti i++, p++) 1756116735Sharti *p = be32toh(*p); 1757116735Sharti } 1758116735Sharti 1759116735Sharti return (error); 1760116735Sharti} 1761116735Sharti 1762116735Sharti/* 1763116735Sharti * Create a copy of a single mbuf. It can have either internal or 1764116735Sharti * external data, it may have a packet header. External data is really 1765116735Sharti * copied, so the new buffer is writeable. 1766116735Sharti */ 1767116735Shartistatic struct mbuf * 1768116735Sharticopy_mbuf(struct mbuf *m) 1769116735Sharti{ 1770116735Sharti struct mbuf *new; 1771116735Sharti 1772243857Sglebius MGET(new, M_NOWAIT, MT_DATA); 1773116735Sharti if (new == NULL) 1774116735Sharti return (NULL); 1775116735Sharti 1776116735Sharti if (m->m_flags & M_PKTHDR) { 1777116735Sharti M_MOVE_PKTHDR(new, m); 1778177599Sru if (m->m_len > MHLEN) 1779243857Sglebius MCLGET(new, M_WAITOK); 1780116735Sharti } else { 1781177599Sru if (m->m_len > MLEN) 1782243857Sglebius MCLGET(new, M_WAITOK); 1783116735Sharti } 1784116735Sharti 1785116735Sharti bcopy(m->m_data, new->m_data, m->m_len); 1786116735Sharti new->m_len = m->m_len; 1787116735Sharti new->m_flags &= ~M_RDONLY; 1788116735Sharti 1789116735Sharti return (new); 1790116735Sharti} 1791116735Sharti 1792116735Sharti/* 1793116735Sharti * All segments must have a four byte aligned buffer address and a four 1794116735Sharti * byte aligned length. Step through an mbuf chain and check these conditions. 1795116735Sharti * If the buffer address is not aligned and this is a normal mbuf, move 1796116735Sharti * the data down. Else make a copy of the mbuf with aligned data. 1797116735Sharti * If the buffer length is not aligned steel data from the next mbuf. 1798116735Sharti * We don't need to check whether this has more than one external reference, 1799116735Sharti * because steeling data doesn't change the external cluster. 1800116735Sharti * If the last mbuf is not aligned, fill with zeroes. 1801116735Sharti * 1802116735Sharti * Return packet length (well we should have this in the packet header), 1803116735Sharti * but be careful not to count the zero fill at the end. 1804116735Sharti * 1805116735Sharti * If fixing fails free the chain and zero the pointer. 1806116735Sharti * 1807116735Sharti * We assume, that aligning the virtual address also aligns the mapped bus 1808116735Sharti * address. 1809116735Sharti */ 1810116735Shartistatic u_int 1811116735Shartifatm_fix_chain(struct fatm_softc *sc, struct mbuf **mp) 1812116735Sharti{ 1813116735Sharti struct mbuf *m = *mp, *prev = NULL, *next, *new; 1814116735Sharti u_int mlen = 0, fill = 0; 1815116735Sharti int first, off; 1816116735Sharti u_char *d, *cp; 1817116735Sharti 1818116735Sharti do { 1819116735Sharti next = m->m_next; 1820116735Sharti 1821116735Sharti if ((uintptr_t)mtod(m, void *) % 4 != 0 || 1822116735Sharti (m->m_len % 4 != 0 && next)) { 1823116735Sharti /* 1824116735Sharti * Needs fixing 1825116735Sharti */ 1826116735Sharti first = (m == *mp); 1827116735Sharti 1828116735Sharti d = mtod(m, u_char *); 1829116735Sharti if ((off = (uintptr_t)(void *)d % 4) != 0) { 1830150346Sandre if (M_WRITABLE(m)) { 1831116735Sharti sc->istats.fix_addr_copy++; 1832116735Sharti bcopy(d, d - off, m->m_len); 1833116735Sharti m->m_data = (caddr_t)(d - off); 1834116735Sharti } else { 1835116735Sharti if ((new = copy_mbuf(m)) == NULL) { 1836116735Sharti sc->istats.fix_addr_noext++; 1837116735Sharti goto fail; 1838116735Sharti } 1839116735Sharti sc->istats.fix_addr_ext++; 1840116735Sharti if (prev) 1841116735Sharti prev->m_next = new; 1842116735Sharti new->m_next = next; 1843116735Sharti m_free(m); 1844116735Sharti m = new; 1845116735Sharti } 1846116735Sharti } 1847116735Sharti 1848116735Sharti if ((off = m->m_len % 4) != 0) { 1849150346Sandre if (!M_WRITABLE(m)) { 1850116735Sharti if ((new = copy_mbuf(m)) == NULL) { 1851116735Sharti sc->istats.fix_len_noext++; 1852116735Sharti goto fail; 1853116735Sharti } 1854116735Sharti sc->istats.fix_len_copy++; 1855116735Sharti if (prev) 1856116735Sharti prev->m_next = new; 1857116735Sharti new->m_next = next; 1858116735Sharti m_free(m); 1859116735Sharti m = new; 1860116735Sharti } else 1861116735Sharti sc->istats.fix_len++; 1862116735Sharti d = mtod(m, u_char *) + m->m_len; 1863116735Sharti off = 4 - off; 1864116735Sharti while (off) { 1865116735Sharti if (next == NULL) { 1866116735Sharti *d++ = 0; 1867116735Sharti fill++; 1868116735Sharti } else if (next->m_len == 0) { 1869116735Sharti sc->istats.fix_empty++; 1870116735Sharti next = m_free(next); 1871116735Sharti continue; 1872116735Sharti } else { 1873116735Sharti cp = mtod(next, u_char *); 1874116735Sharti *d++ = *cp++; 1875116735Sharti next->m_len--; 1876116735Sharti next->m_data = (caddr_t)cp; 1877116735Sharti } 1878116735Sharti off--; 1879116735Sharti m->m_len++; 1880116735Sharti } 1881116735Sharti } 1882116735Sharti 1883116735Sharti if (first) 1884116735Sharti *mp = m; 1885116735Sharti } 1886116735Sharti 1887116735Sharti mlen += m->m_len; 1888116735Sharti prev = m; 1889116735Sharti } while ((m = next) != NULL); 1890116735Sharti 1891116735Sharti return (mlen - fill); 1892116735Sharti 1893116735Sharti fail: 1894116735Sharti m_freem(*mp); 1895116735Sharti *mp = NULL; 1896116735Sharti return (0); 1897116735Sharti} 1898116735Sharti 1899116735Sharti/* 1900116735Sharti * The helper function is used to load the computed physical addresses 1901116735Sharti * into the transmit descriptor. 1902116735Sharti */ 1903116735Shartistatic void 1904116735Shartifatm_tpd_load(void *varg, bus_dma_segment_t *segs, int nsegs, 1905116735Sharti bus_size_t mapsize, int error) 1906116735Sharti{ 1907116735Sharti struct tpd *tpd = varg; 1908116735Sharti 1909116735Sharti if (error) 1910116735Sharti return; 1911116735Sharti 1912116735Sharti KASSERT(nsegs <= TPD_EXTENSIONS + TXD_FIXED, ("too many segments")); 1913116735Sharti 1914116735Sharti tpd->spec = 0; 1915116735Sharti while (nsegs--) { 1916116735Sharti H_SETDESC(tpd->segment[tpd->spec].buffer, segs->ds_addr); 1917116735Sharti H_SETDESC(tpd->segment[tpd->spec].length, segs->ds_len); 1918116735Sharti tpd->spec++; 1919116735Sharti segs++; 1920116735Sharti } 1921116735Sharti} 1922116735Sharti 1923116735Sharti/* 1924116735Sharti * Start output. 1925116735Sharti * 1926116735Sharti * Note, that we update the internal statistics without the lock here. 1927116735Sharti */ 1928116735Shartistatic int 1929118208Shartifatm_tx(struct fatm_softc *sc, struct mbuf *m, struct card_vcc *vc, u_int mlen) 1930116735Sharti{ 1931116735Sharti struct txqueue *q; 1932116735Sharti u_int nblks; 1933116735Sharti int error, aal, nsegs; 1934116735Sharti struct tpd *tpd; 1935116735Sharti 1936116735Sharti /* 1937116735Sharti * Get a queue element. 1938116735Sharti * If there isn't one - try to drain the transmit queue 1939116735Sharti * We used to sleep here if that doesn't help, but we 1940116735Sharti * should not sleep here, because we are called with locks. 1941116735Sharti */ 1942116735Sharti q = GET_QUEUE(sc->txqueue, struct txqueue, sc->txqueue.head); 1943116735Sharti 1944116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 1945116735Sharti if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE) { 1946116735Sharti fatm_intr_drain_tx(sc); 1947116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 1948116735Sharti if (H_GETSTAT(q->q.statp) != FATM_STAT_FREE) { 1949116735Sharti if (sc->retry_tx) { 1950116735Sharti sc->istats.tx_retry++; 1951147256Sbrooks IF_PREPEND(&sc->ifp->if_snd, m); 1952116735Sharti return (1); 1953116735Sharti } 1954116735Sharti sc->istats.tx_queue_full++; 1955116735Sharti m_freem(m); 1956116735Sharti return (0); 1957116735Sharti } 1958116735Sharti sc->istats.tx_queue_almost_full++; 1959116735Sharti } 1960116735Sharti 1961116735Sharti tpd = q->q.ioblk; 1962116735Sharti 1963116735Sharti m->m_data += sizeof(struct atm_pseudohdr); 1964116735Sharti m->m_len -= sizeof(struct atm_pseudohdr); 1965116735Sharti 1966147525Sharti#ifdef ENABLE_BPF 1967147525Sharti if (!(vc->param.flags & ATMIO_FLAG_NG) && 1968147525Sharti vc->param.aal == ATMIO_AAL_5 && 1969147525Sharti (vc->param.flags & ATM_PH_LLCSNAP)) 1970147525Sharti BPF_MTAP(sc->ifp, m); 1971147525Sharti#endif 1972147525Sharti 1973116735Sharti /* map the mbuf */ 1974116735Sharti error = bus_dmamap_load_mbuf(sc->tx_tag, q->map, m, 1975116735Sharti fatm_tpd_load, tpd, BUS_DMA_NOWAIT); 1976116735Sharti if(error) { 1977271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); 1978147256Sbrooks if_printf(sc->ifp, "mbuf loaded error=%d\n", error); 1979116735Sharti m_freem(m); 1980116735Sharti return (0); 1981116735Sharti } 1982116735Sharti nsegs = tpd->spec; 1983116735Sharti 1984116735Sharti bus_dmamap_sync(sc->tx_tag, q->map, BUS_DMASYNC_PREWRITE); 1985116735Sharti 1986116735Sharti /* 1987116735Sharti * OK. Now go and do it. 1988116735Sharti */ 1989118208Sharti aal = (vc->param.aal == ATMIO_AAL_5) ? 5 : 0; 1990116735Sharti 1991116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_PENDING); 1992116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 1993116735Sharti q->m = m; 1994116735Sharti 1995116735Sharti /* 1996116735Sharti * If the transmit queue is almost full, schedule a 1997116735Sharti * transmit interrupt so that transmit descriptors can 1998116735Sharti * be recycled. 1999116735Sharti */ 2000116735Sharti H_SETDESC(tpd->spec, TDX_MKSPEC((sc->txcnt >= 2001116735Sharti (4 * FATM_TX_QLEN) / 5), aal, nsegs, mlen)); 2002118208Sharti H_SETDESC(tpd->atm_header, TDX_MKHDR(vc->param.vpi, 2003118208Sharti vc->param.vci, 0, 0)); 2004116735Sharti 2005118208Sharti if (vc->param.traffic == ATMIO_TRAFFIC_UBR) 2006116735Sharti H_SETDESC(tpd->stream, 0); 2007116735Sharti else { 2008116735Sharti u_int i; 2009116735Sharti 2010116735Sharti for (i = 0; i < RATE_TABLE_SIZE; i++) 2011118208Sharti if (rate_table[i].cell_rate < vc->param.tparam.pcr) 2012116735Sharti break; 2013116735Sharti if (i > 0) 2014116735Sharti i--; 2015116735Sharti H_SETDESC(tpd->stream, rate_table[i].ratio); 2016116735Sharti } 2017116735Sharti H_SYNCQ_PREWRITE(&sc->txq_mem, tpd, TPD_SIZE); 2018116735Sharti 2019116735Sharti nblks = TDX_SEGS2BLKS(nsegs); 2020116735Sharti 2021116735Sharti DBG(sc, XMIT, ("XMIT: mlen=%d spec=0x%x nsegs=%d blocks=%d", 2022116735Sharti mlen, le32toh(tpd->spec), nsegs, nblks)); 2023116735Sharti 2024116735Sharti WRITE4(sc, q->q.card + 0, q->q.card_ioblk | nblks); 2025116735Sharti BARRIER_W(sc); 2026116735Sharti 2027116735Sharti sc->txcnt++; 2028271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1); 2029118208Sharti vc->obytes += m->m_pkthdr.len; 2030118208Sharti vc->opackets++; 2031116735Sharti 2032116735Sharti NEXT_QUEUE_ENTRY(sc->txqueue.head, FATM_TX_QLEN); 2033116735Sharti 2034116735Sharti return (0); 2035116735Sharti} 2036116735Sharti 2037116735Shartistatic void 2038116735Shartifatm_start(struct ifnet *ifp) 2039116735Sharti{ 2040116735Sharti struct atm_pseudohdr aph; 2041116735Sharti struct fatm_softc *sc; 2042116735Sharti struct mbuf *m; 2043116735Sharti u_int mlen, vpi, vci; 2044118208Sharti struct card_vcc *vc; 2045116735Sharti 2046147721Sharti sc = ifp->if_softc; 2047116735Sharti 2048116735Sharti while (1) { 2049116735Sharti IF_DEQUEUE(&ifp->if_snd, m); 2050116735Sharti if (m == NULL) 2051116735Sharti break; 2052116735Sharti 2053116735Sharti /* 2054116735Sharti * Loop through the mbuf chain and compute the total length 2055116735Sharti * of the packet. Check that all data pointer are 2056116735Sharti * 4 byte aligned. If they are not, call fatm_mfix to 2057116735Sharti * fix that problem. This comes more or less from the 2058116735Sharti * en driver. 2059116735Sharti */ 2060116735Sharti mlen = fatm_fix_chain(sc, &m); 2061116735Sharti if (m == NULL) 2062116735Sharti continue; 2063116735Sharti 2064116735Sharti if (m->m_len < sizeof(struct atm_pseudohdr) && 2065116735Sharti (m = m_pullup(m, sizeof(struct atm_pseudohdr))) == NULL) 2066116735Sharti continue; 2067116735Sharti 2068116735Sharti aph = *mtod(m, struct atm_pseudohdr *); 2069116735Sharti mlen -= sizeof(struct atm_pseudohdr); 2070116735Sharti 2071116735Sharti if (mlen == 0) { 2072116735Sharti m_freem(m); 2073116735Sharti continue; 2074116735Sharti } 2075116735Sharti if (mlen > FATM_MAXPDU) { 2076116735Sharti sc->istats.tx_pdu2big++; 2077116735Sharti m_freem(m); 2078116735Sharti continue; 2079116735Sharti } 2080116735Sharti 2081116735Sharti vci = ATM_PH_VCI(&aph); 2082116735Sharti vpi = ATM_PH_VPI(&aph); 2083116735Sharti 2084116735Sharti /* 2085116735Sharti * From here on we need the softc 2086116735Sharti */ 2087116735Sharti FATM_LOCK(sc); 2088148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2089116735Sharti FATM_UNLOCK(sc); 2090116735Sharti m_freem(m); 2091116735Sharti break; 2092116735Sharti } 2093118208Sharti if (!VC_OK(sc, vpi, vci) || (vc = sc->vccs[vci]) == NULL || 2094118208Sharti !(vc->vflags & FATM_VCC_OPEN)) { 2095116735Sharti FATM_UNLOCK(sc); 2096116735Sharti m_freem(m); 2097116735Sharti continue; 2098116735Sharti } 2099118208Sharti if (fatm_tx(sc, m, vc, mlen)) { 2100116735Sharti FATM_UNLOCK(sc); 2101116735Sharti break; 2102116735Sharti } 2103116735Sharti FATM_UNLOCK(sc); 2104116735Sharti } 2105116735Sharti} 2106116735Sharti 2107116735Sharti/* 2108298955Spfg * VCC management 2109116735Sharti * 2110116735Sharti * This may seem complicated. The reason for this is, that we need an 2111116735Sharti * asynchronuous open/close for the NATM VCCs because our ioctl handler 2112116735Sharti * is called with the radix node head of the routing table locked. Therefor 2113116735Sharti * we cannot sleep there and wait for the open/close to succeed. For this 2114116735Sharti * reason we just initiate the operation from the ioctl. 2115116735Sharti */ 2116116735Sharti 2117116735Sharti/* 2118116735Sharti * Command the card to open/close a VC. 2119298955Spfg * Return the queue entry for waiting if we are successful. 2120116735Sharti */ 2121116735Shartistatic struct cmdqueue * 2122116735Shartifatm_start_vcc(struct fatm_softc *sc, u_int vpi, u_int vci, uint32_t cmd, 2123116735Sharti u_int mtu, void (*func)(struct fatm_softc *, struct cmdqueue *)) 2124116735Sharti{ 2125116735Sharti struct cmdqueue *q; 2126116735Sharti 2127116735Sharti q = GET_QUEUE(sc->cmdqueue, struct cmdqueue, sc->cmdqueue.head); 2128116735Sharti 2129116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 2130116735Sharti if (!(H_GETSTAT(q->q.statp) & FATM_STAT_FREE)) { 2131116735Sharti sc->istats.cmd_queue_full++; 2132116735Sharti return (NULL); 2133116735Sharti } 2134116735Sharti NEXT_QUEUE_ENTRY(sc->cmdqueue.head, FATM_CMD_QLEN); 2135116735Sharti 2136116735Sharti q->error = 0; 2137116735Sharti q->cb = func; 2138116735Sharti H_SETSTAT(q->q.statp, FATM_STAT_PENDING); 2139116735Sharti H_SYNCSTAT_PREWRITE(sc, q->q.statp); 2140116735Sharti 2141116735Sharti WRITE4(sc, q->q.card + FATMOC_ACTIN_VPVC, MKVPVC(vpi, vci)); 2142116735Sharti BARRIER_W(sc); 2143116735Sharti WRITE4(sc, q->q.card + FATMOC_ACTIN_MTU, mtu); 2144116735Sharti BARRIER_W(sc); 2145116735Sharti WRITE4(sc, q->q.card + FATMOC_OP, cmd); 2146116735Sharti BARRIER_W(sc); 2147116735Sharti 2148116735Sharti return (q); 2149116735Sharti} 2150116735Sharti 2151116735Sharti/* 2152118208Sharti * The VC has been opened/closed and somebody has been waiting for this. 2153118208Sharti * Wake him up. 2154116735Sharti */ 2155118208Shartistatic void 2156118208Shartifatm_cmd_complete(struct fatm_softc *sc, struct cmdqueue *q) 2157116735Sharti{ 2158116735Sharti 2159118208Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 2160118208Sharti if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) { 2161118208Sharti sc->istats.get_stat_errors++; 2162118208Sharti q->error = EIO; 2163118208Sharti } 2164118208Sharti wakeup(q); 2165118208Sharti} 2166116735Sharti 2167118208Sharti/* 2168118208Sharti * Open complete 2169118208Sharti */ 2170118208Shartistatic void 2171118208Shartifatm_open_finish(struct fatm_softc *sc, struct card_vcc *vc) 2172118208Sharti{ 2173118208Sharti vc->vflags &= ~FATM_VCC_TRY_OPEN; 2174118208Sharti vc->vflags |= FATM_VCC_OPEN; 2175116735Sharti 2176118596Sharti if (vc->vflags & FATM_VCC_REOPEN) { 2177118596Sharti vc->vflags &= ~FATM_VCC_REOPEN; 2178118596Sharti return; 2179118596Sharti } 2180118596Sharti 2181118208Sharti /* inform management if this is not an NG 2182118208Sharti * VCC or it's an NG PVC. */ 2183118208Sharti if (!(vc->param.flags & ATMIO_FLAG_NG) || 2184118208Sharti (vc->param.flags & ATMIO_FLAG_PVC)) 2185147256Sbrooks ATMEV_SEND_VCC_CHANGED(IFP2IFATM(sc->ifp), 0, vc->param.vci, 1); 2186116735Sharti} 2187116735Sharti 2188116735Sharti/* 2189118208Sharti * The VC that we have tried to open asynchronuosly has been opened. 2190116735Sharti */ 2191118208Shartistatic void 2192118208Shartifatm_open_complete(struct fatm_softc *sc, struct cmdqueue *q) 2193116735Sharti{ 2194118208Sharti u_int vci; 2195118208Sharti struct card_vcc *vc; 2196116735Sharti 2197118208Sharti vci = GETVCI(READ4(sc, q->q.card + FATMOC_ACTIN_VPVC)); 2198118208Sharti vc = sc->vccs[vci]; 2199118208Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 2200118208Sharti if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) { 2201118208Sharti sc->istats.get_stat_errors++; 2202118208Sharti sc->vccs[vci] = NULL; 2203118208Sharti uma_zfree(sc->vcc_zone, vc); 2204147256Sbrooks if_printf(sc->ifp, "opening VCI %u failed\n", vci); 2205118208Sharti return; 2206118208Sharti } 2207118208Sharti fatm_open_finish(sc, vc); 2208116735Sharti} 2209116735Sharti 2210116735Sharti/* 2211116735Sharti * Wait on the queue entry until the VCC is opened/closed. 2212116735Sharti */ 2213116735Shartistatic int 2214116735Shartifatm_waitvcc(struct fatm_softc *sc, struct cmdqueue *q) 2215116735Sharti{ 2216116735Sharti int error; 2217116735Sharti 2218116735Sharti /* 2219116735Sharti * Wait for the command to complete 2220116735Sharti */ 2221116735Sharti error = msleep(q, &sc->mtx, PZERO | PCATCH, "fatm_vci", hz); 2222116735Sharti 2223116735Sharti if (error != 0) 2224116735Sharti return (error); 2225116735Sharti return (q->error); 2226116735Sharti} 2227116735Sharti 2228116735Sharti/* 2229118208Sharti * Start to open a VCC. This just initiates the operation. 2230116735Sharti */ 2231116735Shartistatic int 2232118548Shartifatm_open_vcc(struct fatm_softc *sc, struct atmio_openvcc *op) 2233116735Sharti{ 2234116735Sharti int error; 2235118208Sharti struct card_vcc *vc; 2236116735Sharti 2237118208Sharti /* 2238118208Sharti * Check parameters 2239118208Sharti */ 2240118208Sharti if ((op->param.flags & ATMIO_FLAG_NOTX) && 2241118208Sharti (op->param.flags & ATMIO_FLAG_NORX)) 2242118208Sharti return (EINVAL); 2243118208Sharti 2244118208Sharti if (!VC_OK(sc, op->param.vpi, op->param.vci)) 2245118208Sharti return (EINVAL); 2246118208Sharti if (op->param.aal != ATMIO_AAL_0 && op->param.aal != ATMIO_AAL_5) 2247118208Sharti return (EINVAL); 2248118208Sharti 2249118208Sharti vc = uma_zalloc(sc->vcc_zone, M_NOWAIT | M_ZERO); 2250118208Sharti if (vc == NULL) 2251118208Sharti return (ENOMEM); 2252118208Sharti 2253116735Sharti error = 0; 2254116735Sharti 2255116735Sharti FATM_LOCK(sc); 2256148887Srwatson if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2257118208Sharti error = EIO; 2258118208Sharti goto done; 2259116735Sharti } 2260118208Sharti if (sc->vccs[op->param.vci] != NULL) { 2261118208Sharti error = EBUSY; 2262118208Sharti goto done; 2263118208Sharti } 2264118208Sharti vc->param = op->param; 2265118208Sharti vc->rxhand = op->rxhand; 2266116735Sharti 2267118208Sharti switch (op->param.traffic) { 2268116735Sharti 2269118208Sharti case ATMIO_TRAFFIC_UBR: 2270118208Sharti break; 2271116735Sharti 2272118208Sharti case ATMIO_TRAFFIC_CBR: 2273118208Sharti if (op->param.tparam.pcr == 0 || 2274147256Sbrooks op->param.tparam.pcr > IFP2IFATM(sc->ifp)->mib.pcr) { 2275118208Sharti error = EINVAL; 2276118208Sharti goto done; 2277118208Sharti } 2278118208Sharti break; 2279116735Sharti 2280118208Sharti default: 2281118208Sharti error = EINVAL; 2282118208Sharti goto done; 2283118208Sharti } 2284118208Sharti vc->ibytes = vc->obytes = 0; 2285118208Sharti vc->ipackets = vc->opackets = 0; 2286116735Sharti 2287118208Sharti vc->vflags = FATM_VCC_TRY_OPEN; 2288118208Sharti sc->vccs[op->param.vci] = vc; 2289118208Sharti sc->open_vccs++; 2290116735Sharti 2291118596Sharti error = fatm_load_vc(sc, vc); 2292123798Speter if (error != 0) { 2293118596Sharti sc->vccs[op->param.vci] = NULL; 2294118596Sharti sc->open_vccs--; 2295118596Sharti goto done; 2296116735Sharti } 2297116735Sharti 2298118208Sharti /* don't free below */ 2299118208Sharti vc = NULL; 2300118208Sharti 2301118208Sharti done: 2302116735Sharti FATM_UNLOCK(sc); 2303118208Sharti if (vc != NULL) 2304118208Sharti uma_zfree(sc->vcc_zone, vc); 2305116735Sharti return (error); 2306116735Sharti} 2307116735Sharti 2308116735Sharti/* 2309118596Sharti * Try to initialize the given VC 2310118596Sharti */ 2311118596Shartistatic int 2312118596Shartifatm_load_vc(struct fatm_softc *sc, struct card_vcc *vc) 2313118596Sharti{ 2314118596Sharti uint32_t cmd; 2315118596Sharti struct cmdqueue *q; 2316118596Sharti int error; 2317118596Sharti 2318118596Sharti /* Command and buffer strategy */ 2319118596Sharti cmd = FATM_OP_ACTIVATE_VCIN | FATM_OP_INTERRUPT_SEL | (0 << 16); 2320118596Sharti if (vc->param.aal == ATMIO_AAL_0) 2321118596Sharti cmd |= (0 << 8); 2322118596Sharti else 2323118596Sharti cmd |= (5 << 8); 2324118596Sharti 2325118596Sharti q = fatm_start_vcc(sc, vc->param.vpi, vc->param.vci, cmd, 1, 2326118596Sharti (vc->param.flags & ATMIO_FLAG_ASYNC) ? 2327118596Sharti fatm_open_complete : fatm_cmd_complete); 2328118596Sharti if (q == NULL) 2329118596Sharti return (EIO); 2330118596Sharti 2331118596Sharti if (!(vc->param.flags & ATMIO_FLAG_ASYNC)) { 2332118596Sharti error = fatm_waitvcc(sc, q); 2333118596Sharti if (error != 0) 2334118596Sharti return (error); 2335118596Sharti fatm_open_finish(sc, vc); 2336118596Sharti } 2337118596Sharti return (0); 2338118596Sharti} 2339118596Sharti 2340118596Sharti/* 2341118208Sharti * Finish close 2342116735Sharti */ 2343116735Shartistatic void 2344118208Shartifatm_close_finish(struct fatm_softc *sc, struct card_vcc *vc) 2345116735Sharti{ 2346118208Sharti /* inform management of this is not an NG 2347118208Sharti * VCC or it's an NG PVC. */ 2348118208Sharti if (!(vc->param.flags & ATMIO_FLAG_NG) || 2349118208Sharti (vc->param.flags & ATMIO_FLAG_PVC)) 2350147256Sbrooks ATMEV_SEND_VCC_CHANGED(IFP2IFATM(sc->ifp), 0, vc->param.vci, 0); 2351116735Sharti 2352118208Sharti sc->vccs[vc->param.vci] = NULL; 2353118208Sharti sc->open_vccs--; 2354116735Sharti 2355118208Sharti uma_zfree(sc->vcc_zone, vc); 2356116735Sharti} 2357116735Sharti 2358116735Sharti/* 2359116735Sharti * The VC has been closed. 2360116735Sharti */ 2361116735Shartistatic void 2362116735Shartifatm_close_complete(struct fatm_softc *sc, struct cmdqueue *q) 2363116735Sharti{ 2364116735Sharti u_int vci; 2365118208Sharti struct card_vcc *vc; 2366116735Sharti 2367116735Sharti vci = GETVCI(READ4(sc, q->q.card + FATMOC_ACTIN_VPVC)); 2368118208Sharti vc = sc->vccs[vci]; 2369116735Sharti H_SYNCSTAT_POSTREAD(sc, q->q.statp); 2370116735Sharti if (H_GETSTAT(q->q.statp) & FATM_STAT_ERROR) { 2371116735Sharti sc->istats.get_stat_errors++; 2372116735Sharti /* keep the VCC in that state */ 2373147256Sbrooks if_printf(sc->ifp, "closing VCI %u failed\n", vci); 2374116735Sharti return; 2375116735Sharti } 2376116735Sharti 2377118208Sharti fatm_close_finish(sc, vc); 2378116735Sharti} 2379116735Sharti 2380116735Sharti/* 2381118208Sharti * Initiate closing a VCC 2382116735Sharti */ 2383116735Shartistatic int 2384118548Shartifatm_close_vcc(struct fatm_softc *sc, struct atmio_closevcc *cl) 2385116735Sharti{ 2386116735Sharti int error; 2387118208Sharti struct cmdqueue *q; 2388118208Sharti struct card_vcc *vc; 2389116735Sharti 2390118208Sharti if (!VC_OK(sc, cl->vpi, cl->vci)) 2391118208Sharti return (EINVAL); 2392118208Sharti 2393118208Sharti error = 0; 2394118208Sharti 2395116735Sharti FATM_LOCK(sc); 2396148887Srwatson if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2397118208Sharti error = EIO; 2398118208Sharti goto done; 2399118208Sharti } 2400118208Sharti vc = sc->vccs[cl->vci]; 2401118208Sharti if (vc == NULL || !(vc->vflags & (FATM_VCC_OPEN | FATM_VCC_TRY_OPEN))) { 2402118208Sharti error = ENOENT; 2403118208Sharti goto done; 2404118208Sharti } 2405116735Sharti 2406118208Sharti q = fatm_start_vcc(sc, cl->vpi, cl->vci, 2407118208Sharti FATM_OP_DEACTIVATE_VCIN | FATM_OP_INTERRUPT_SEL, 1, 2408118548Sharti (vc->param.flags & ATMIO_FLAG_ASYNC) ? 2409118548Sharti fatm_close_complete : fatm_cmd_complete); 2410118208Sharti if (q == NULL) { 2411118208Sharti error = EIO; 2412118208Sharti goto done; 2413118208Sharti } 2414116735Sharti 2415118208Sharti vc->vflags &= ~(FATM_VCC_OPEN | FATM_VCC_TRY_OPEN); 2416118208Sharti vc->vflags |= FATM_VCC_TRY_CLOSE; 2417118208Sharti 2418118548Sharti if (!(vc->param.flags & ATMIO_FLAG_ASYNC)) { 2419118208Sharti error = fatm_waitvcc(sc, q); 2420118208Sharti if (error != 0) 2421118208Sharti goto done; 2422118208Sharti 2423118208Sharti fatm_close_finish(sc, vc); 2424118208Sharti } 2425118208Sharti 2426118208Sharti done: 2427116735Sharti FATM_UNLOCK(sc); 2428116735Sharti return (error); 2429116735Sharti} 2430116735Sharti 2431116735Sharti/* 2432116735Sharti * IOCTL handler 2433116735Sharti */ 2434116735Shartistatic int 2435116735Shartifatm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t arg) 2436116735Sharti{ 2437116735Sharti int error; 2438116735Sharti struct fatm_softc *sc = ifp->if_softc; 2439116735Sharti struct ifaddr *ifa = (struct ifaddr *)arg; 2440116735Sharti struct ifreq *ifr = (struct ifreq *)arg; 2441116735Sharti struct atmio_closevcc *cl = (struct atmio_closevcc *)arg; 2442116735Sharti struct atmio_openvcc *op = (struct atmio_openvcc *)arg; 2443116735Sharti struct atmio_vcctable *vtab; 2444116735Sharti 2445116735Sharti error = 0; 2446116735Sharti switch (cmd) { 2447116735Sharti 2448118548Sharti case SIOCATMOPENVCC: /* kernel internal use */ 2449118548Sharti error = fatm_open_vcc(sc, op); 2450116735Sharti break; 2451116735Sharti 2452118548Sharti case SIOCATMCLOSEVCC: /* kernel internal use */ 2453118548Sharti error = fatm_close_vcc(sc, cl); 2454116735Sharti break; 2455116735Sharti 2456116735Sharti case SIOCSIFADDR: 2457116735Sharti FATM_LOCK(sc); 2458116735Sharti ifp->if_flags |= IFF_UP; 2459148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 2460116735Sharti fatm_init_locked(sc); 2461116735Sharti switch (ifa->ifa_addr->sa_family) { 2462116735Sharti#ifdef INET 2463116735Sharti case AF_INET: 2464116735Sharti case AF_INET6: 2465116735Sharti ifa->ifa_rtrequest = atm_rtrequest; 2466116735Sharti break; 2467116735Sharti#endif 2468116735Sharti default: 2469116735Sharti break; 2470116735Sharti } 2471116735Sharti FATM_UNLOCK(sc); 2472116735Sharti break; 2473116735Sharti 2474116735Sharti case SIOCSIFFLAGS: 2475116735Sharti FATM_LOCK(sc); 2476116735Sharti if (ifp->if_flags & IFF_UP) { 2477148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2478116735Sharti fatm_init_locked(sc); 2479116735Sharti } 2480116735Sharti } else { 2481148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2482116735Sharti fatm_stop(sc); 2483116735Sharti } 2484116735Sharti } 2485116735Sharti FATM_UNLOCK(sc); 2486116735Sharti break; 2487116735Sharti 2488116735Sharti case SIOCGIFMEDIA: 2489116735Sharti case SIOCSIFMEDIA: 2490148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2491116735Sharti error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd); 2492116735Sharti else 2493116735Sharti error = EINVAL; 2494116735Sharti break; 2495116735Sharti 2496116735Sharti case SIOCATMGVCCS: 2497116735Sharti /* return vcc table */ 2498118208Sharti vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, 2499118208Sharti FORE_MAX_VCC + 1, sc->open_vccs, &sc->mtx, 1); 2500332288Sbrooks error = copyout(vtab, ifr_data_get_ptr(ifr), sizeof(*vtab) + 2501116735Sharti vtab->count * sizeof(vtab->vccs[0])); 2502116735Sharti free(vtab, M_DEVBUF); 2503116735Sharti break; 2504116735Sharti 2505116735Sharti case SIOCATMGETVCCS: /* internal netgraph use */ 2506118208Sharti vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, 2507118208Sharti FORE_MAX_VCC + 1, sc->open_vccs, &sc->mtx, 0); 2508116735Sharti if (vtab == NULL) { 2509116735Sharti error = ENOMEM; 2510116735Sharti break; 2511116735Sharti } 2512116735Sharti *(void **)arg = vtab; 2513116735Sharti break; 2514116735Sharti 2515116735Sharti default: 2516116735Sharti DBG(sc, IOCTL, ("+++ cmd=%08lx arg=%p", cmd, arg)); 2517116735Sharti error = EINVAL; 2518116735Sharti break; 2519116735Sharti } 2520116735Sharti 2521116735Sharti return (error); 2522116735Sharti} 2523116735Sharti 2524116735Sharti/* 2525116735Sharti * Detach from the interface and free all resources allocated during 2526116735Sharti * initialisation and later. 2527116735Sharti */ 2528116735Shartistatic int 2529116735Shartifatm_detach(device_t dev) 2530116735Sharti{ 2531116735Sharti u_int i; 2532116735Sharti struct rbuf *rb; 2533116735Sharti struct fatm_softc *sc; 2534116735Sharti struct txqueue *tx; 2535116735Sharti 2536147721Sharti sc = device_get_softc(dev); 2537116735Sharti 2538116735Sharti if (device_is_alive(dev)) { 2539116735Sharti FATM_LOCK(sc); 2540116735Sharti fatm_stop(sc); 2541116735Sharti utopia_detach(&sc->utopia); 2542116735Sharti FATM_UNLOCK(sc); 2543147256Sbrooks atm_ifdetach(sc->ifp); /* XXX race */ 2544116735Sharti } 2545199559Sjhb callout_drain(&sc->watchdog_timer); 2546116735Sharti 2547116735Sharti if (sc->ih != NULL) 2548116735Sharti bus_teardown_intr(dev, sc->irqres, sc->ih); 2549116735Sharti 2550116735Sharti while ((rb = LIST_FIRST(&sc->rbuf_used)) != NULL) { 2551147256Sbrooks if_printf(sc->ifp, "rbuf %p still in use!\n", rb); 2552116735Sharti bus_dmamap_unload(sc->rbuf_tag, rb->map); 2553116735Sharti m_freem(rb->m); 2554116735Sharti LIST_REMOVE(rb, link); 2555116735Sharti LIST_INSERT_HEAD(&sc->rbuf_free, rb, link); 2556116735Sharti } 2557116735Sharti 2558116735Sharti if (sc->txqueue.chunk != NULL) { 2559116735Sharti for (i = 0; i < FATM_TX_QLEN; i++) { 2560116735Sharti tx = GET_QUEUE(sc->txqueue, struct txqueue, i); 2561116735Sharti bus_dmamap_destroy(sc->tx_tag, tx->map); 2562116735Sharti } 2563116735Sharti } 2564116735Sharti 2565116735Sharti while ((rb = LIST_FIRST(&sc->rbuf_free)) != NULL) { 2566116735Sharti bus_dmamap_destroy(sc->rbuf_tag, rb->map); 2567116735Sharti LIST_REMOVE(rb, link); 2568116735Sharti } 2569116735Sharti 2570118208Sharti if (sc->rbufs != NULL) 2571118208Sharti free(sc->rbufs, M_DEVBUF); 2572118596Sharti if (sc->vccs != NULL) { 2573118596Sharti for (i = 0; i < FORE_MAX_VCC + 1; i++) 2574118596Sharti if (sc->vccs[i] != NULL) { 2575118596Sharti uma_zfree(sc->vcc_zone, sc->vccs[i]); 2576118596Sharti sc->vccs[i] = NULL; 2577118596Sharti } 2578118208Sharti free(sc->vccs, M_DEVBUF); 2579118596Sharti } 2580118208Sharti if (sc->vcc_zone != NULL) 2581118208Sharti uma_zdestroy(sc->vcc_zone); 2582116735Sharti 2583118208Sharti if (sc->l1queue.chunk != NULL) 2584118208Sharti free(sc->l1queue.chunk, M_DEVBUF); 2585118208Sharti if (sc->s1queue.chunk != NULL) 2586118208Sharti free(sc->s1queue.chunk, M_DEVBUF); 2587118208Sharti if (sc->rxqueue.chunk != NULL) 2588118208Sharti free(sc->rxqueue.chunk, M_DEVBUF); 2589118208Sharti if (sc->txqueue.chunk != NULL) 2590118208Sharti free(sc->txqueue.chunk, M_DEVBUF); 2591118208Sharti if (sc->cmdqueue.chunk != NULL) 2592118208Sharti free(sc->cmdqueue.chunk, M_DEVBUF); 2593116735Sharti 2594116735Sharti destroy_dma_memory(&sc->reg_mem); 2595116735Sharti destroy_dma_memory(&sc->sadi_mem); 2596116735Sharti destroy_dma_memory(&sc->prom_mem); 2597116735Sharti#ifdef TEST_DMA_SYNC 2598116735Sharti destroy_dma_memoryX(&sc->s1q_mem); 2599116735Sharti destroy_dma_memoryX(&sc->l1q_mem); 2600116735Sharti destroy_dma_memoryX(&sc->rxq_mem); 2601116735Sharti destroy_dma_memoryX(&sc->txq_mem); 2602116735Sharti destroy_dma_memoryX(&sc->stat_mem); 2603116735Sharti#endif 2604116735Sharti 2605116735Sharti if (sc->tx_tag != NULL) 2606116735Sharti if (bus_dma_tag_destroy(sc->tx_tag)) 2607116735Sharti printf("tx DMA tag busy!\n"); 2608116735Sharti 2609116735Sharti if (sc->rbuf_tag != NULL) 2610116735Sharti if (bus_dma_tag_destroy(sc->rbuf_tag)) 2611116735Sharti printf("rbuf DMA tag busy!\n"); 2612116735Sharti 2613116735Sharti if (sc->parent_dmat != NULL) 2614116735Sharti if (bus_dma_tag_destroy(sc->parent_dmat)) 2615116735Sharti printf("parent DMA tag busy!\n"); 2616116735Sharti 2617116735Sharti if (sc->irqres != NULL) 2618116735Sharti bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irqres); 2619116735Sharti 2620116735Sharti if (sc->memres != NULL) 2621116735Sharti bus_release_resource(dev, SYS_RES_MEMORY, 2622116735Sharti sc->memid, sc->memres); 2623116735Sharti 2624116735Sharti (void)sysctl_ctx_free(&sc->sysctl_ctx); 2625116735Sharti 2626116735Sharti cv_destroy(&sc->cv_stat); 2627116735Sharti cv_destroy(&sc->cv_regs); 2628116735Sharti 2629116735Sharti mtx_destroy(&sc->mtx); 2630116735Sharti 2631147525Sharti if_free(sc->ifp); 2632147525Sharti 2633116735Sharti return (0); 2634116735Sharti} 2635116735Sharti 2636116735Sharti/* 2637116735Sharti * Sysctl handler 2638116735Sharti */ 2639116735Shartistatic int 2640116735Shartifatm_sysctl_istats(SYSCTL_HANDLER_ARGS) 2641116735Sharti{ 2642116735Sharti struct fatm_softc *sc = arg1; 2643116735Sharti u_long *ret; 2644116735Sharti int error; 2645116735Sharti 2646116735Sharti ret = malloc(sizeof(sc->istats), M_TEMP, M_WAITOK); 2647116735Sharti 2648116735Sharti FATM_LOCK(sc); 2649116735Sharti bcopy(&sc->istats, ret, sizeof(sc->istats)); 2650116735Sharti FATM_UNLOCK(sc); 2651116735Sharti 2652116735Sharti error = SYSCTL_OUT(req, ret, sizeof(sc->istats)); 2653116735Sharti free(ret, M_TEMP); 2654116735Sharti 2655116735Sharti return (error); 2656116735Sharti} 2657116735Sharti 2658116735Sharti/* 2659116735Sharti * Sysctl handler for card statistics 2660118168Sharti * This is disable because it destroys the PHY statistics. 2661116735Sharti */ 2662116735Shartistatic int 2663116735Shartifatm_sysctl_stats(SYSCTL_HANDLER_ARGS) 2664116735Sharti{ 2665116735Sharti struct fatm_softc *sc = arg1; 2666116735Sharti int error; 2667116735Sharti const struct fatm_stats *s; 2668116735Sharti u_long *ret; 2669116735Sharti u_int i; 2670116735Sharti 2671116735Sharti ret = malloc(sizeof(u_long) * FATM_NSTATS, M_TEMP, M_WAITOK); 2672116735Sharti 2673116735Sharti FATM_LOCK(sc); 2674116735Sharti 2675116735Sharti if ((error = fatm_getstat(sc)) == 0) { 2676116735Sharti s = sc->sadi_mem.mem; 2677116735Sharti i = 0; 2678116735Sharti ret[i++] = s->phy_4b5b.crc_header_errors; 2679116735Sharti ret[i++] = s->phy_4b5b.framing_errors; 2680116735Sharti ret[i++] = s->phy_oc3.section_bip8_errors; 2681116735Sharti ret[i++] = s->phy_oc3.path_bip8_errors; 2682116735Sharti ret[i++] = s->phy_oc3.line_bip24_errors; 2683116735Sharti ret[i++] = s->phy_oc3.line_febe_errors; 2684116735Sharti ret[i++] = s->phy_oc3.path_febe_errors; 2685116735Sharti ret[i++] = s->phy_oc3.corr_hcs_errors; 2686116735Sharti ret[i++] = s->phy_oc3.ucorr_hcs_errors; 2687116735Sharti ret[i++] = s->atm.cells_transmitted; 2688116735Sharti ret[i++] = s->atm.cells_received; 2689116735Sharti ret[i++] = s->atm.vpi_bad_range; 2690116735Sharti ret[i++] = s->atm.vpi_no_conn; 2691116735Sharti ret[i++] = s->atm.vci_bad_range; 2692116735Sharti ret[i++] = s->atm.vci_no_conn; 2693116735Sharti ret[i++] = s->aal0.cells_transmitted; 2694116735Sharti ret[i++] = s->aal0.cells_received; 2695116735Sharti ret[i++] = s->aal0.cells_dropped; 2696116735Sharti ret[i++] = s->aal4.cells_transmitted; 2697116735Sharti ret[i++] = s->aal4.cells_received; 2698116735Sharti ret[i++] = s->aal4.cells_crc_errors; 2699116735Sharti ret[i++] = s->aal4.cels_protocol_errors; 2700116735Sharti ret[i++] = s->aal4.cells_dropped; 2701116735Sharti ret[i++] = s->aal4.cspdus_transmitted; 2702116735Sharti ret[i++] = s->aal4.cspdus_received; 2703116735Sharti ret[i++] = s->aal4.cspdus_protocol_errors; 2704116735Sharti ret[i++] = s->aal4.cspdus_dropped; 2705116735Sharti ret[i++] = s->aal5.cells_transmitted; 2706116735Sharti ret[i++] = s->aal5.cells_received; 2707116735Sharti ret[i++] = s->aal5.congestion_experienced; 2708116735Sharti ret[i++] = s->aal5.cells_dropped; 2709116735Sharti ret[i++] = s->aal5.cspdus_transmitted; 2710116735Sharti ret[i++] = s->aal5.cspdus_received; 2711116735Sharti ret[i++] = s->aal5.cspdus_crc_errors; 2712116735Sharti ret[i++] = s->aal5.cspdus_protocol_errors; 2713116735Sharti ret[i++] = s->aal5.cspdus_dropped; 2714116735Sharti ret[i++] = s->aux.small_b1_failed; 2715116735Sharti ret[i++] = s->aux.large_b1_failed; 2716116735Sharti ret[i++] = s->aux.small_b2_failed; 2717116735Sharti ret[i++] = s->aux.large_b2_failed; 2718116735Sharti ret[i++] = s->aux.rpd_alloc_failed; 2719116735Sharti ret[i++] = s->aux.receive_carrier; 2720116735Sharti } 2721116735Sharti /* declare the buffer free */ 2722116735Sharti sc->flags &= ~FATM_STAT_INUSE; 2723116735Sharti cv_signal(&sc->cv_stat); 2724116735Sharti 2725116735Sharti FATM_UNLOCK(sc); 2726116735Sharti 2727116735Sharti if (error == 0) 2728116735Sharti error = SYSCTL_OUT(req, ret, sizeof(u_long) * FATM_NSTATS); 2729116735Sharti free(ret, M_TEMP); 2730116735Sharti 2731116735Sharti return (error); 2732116735Sharti} 2733116735Sharti 2734116735Sharti#define MAXDMASEGS 32 /* maximum number of receive descriptors */ 2735116735Sharti 2736116735Sharti/* 2737116735Sharti * Attach to the device. 2738116735Sharti * 2739116735Sharti * We assume, that there is a global lock (Giant in this case) that protects 2740116735Sharti * multiple threads from entering this function. This makes sense, doesn't it? 2741116735Sharti */ 2742116735Shartistatic int 2743116735Shartifatm_attach(device_t dev) 2744116735Sharti{ 2745116735Sharti struct ifnet *ifp; 2746116735Sharti struct fatm_softc *sc; 2747116735Sharti int unit; 2748116735Sharti uint16_t cfg; 2749116735Sharti int error = 0; 2750116735Sharti struct rbuf *rb; 2751116735Sharti u_int i; 2752116735Sharti struct txqueue *tx; 2753116735Sharti 2754116735Sharti sc = device_get_softc(dev); 2755116735Sharti unit = device_get_unit(dev); 2756116735Sharti 2757147256Sbrooks ifp = sc->ifp = if_alloc(IFT_ATM); 2758147256Sbrooks if (ifp == NULL) { 2759147256Sbrooks error = ENOSPC; 2760147256Sbrooks goto fail; 2761147256Sbrooks } 2762116735Sharti 2763147256Sbrooks IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_PCA200E; 2764147256Sbrooks IFP2IFATM(sc->ifp)->mib.serial = 0; 2765147256Sbrooks IFP2IFATM(sc->ifp)->mib.hw_version = 0; 2766147256Sbrooks IFP2IFATM(sc->ifp)->mib.sw_version = 0; 2767147256Sbrooks IFP2IFATM(sc->ifp)->mib.vpi_bits = 0; 2768147256Sbrooks IFP2IFATM(sc->ifp)->mib.vci_bits = FORE_VCIBITS; 2769147256Sbrooks IFP2IFATM(sc->ifp)->mib.max_vpcs = 0; 2770147256Sbrooks IFP2IFATM(sc->ifp)->mib.max_vccs = FORE_MAX_VCC; 2771147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UNKNOWN; 2772147256Sbrooks IFP2IFATM(sc->ifp)->phy = &sc->utopia; 2773147256Sbrooks 2774116735Sharti LIST_INIT(&sc->rbuf_free); 2775116735Sharti LIST_INIT(&sc->rbuf_used); 2776116735Sharti 2777116735Sharti /* 2778116735Sharti * Initialize mutex and condition variables. 2779116735Sharti */ 2780116735Sharti mtx_init(&sc->mtx, device_get_nameunit(dev), 2781116735Sharti MTX_NETWORK_LOCK, MTX_DEF); 2782116735Sharti 2783116735Sharti cv_init(&sc->cv_stat, "fatm_stat"); 2784116735Sharti cv_init(&sc->cv_regs, "fatm_regs"); 2785116735Sharti 2786116735Sharti sysctl_ctx_init(&sc->sysctl_ctx); 2787199559Sjhb callout_init_mtx(&sc->watchdog_timer, &sc->mtx, 0); 2788116735Sharti 2789116735Sharti /* 2790116735Sharti * Make the sysctl tree 2791116735Sharti */ 2792116735Sharti if ((sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 2793116735Sharti SYSCTL_STATIC_CHILDREN(_hw_atm), OID_AUTO, 2794116735Sharti device_get_nameunit(dev), CTLFLAG_RD, 0, "")) == NULL) 2795116735Sharti goto fail; 2796116735Sharti 2797116735Sharti if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 2798217556Smdf OID_AUTO, "istats", CTLTYPE_ULONG | CTLFLAG_RD, sc, 0, 2799217556Smdf fatm_sysctl_istats, "LU", "internal statistics") == NULL) 2800116735Sharti goto fail; 2801116735Sharti 2802116735Sharti if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 2803217556Smdf OID_AUTO, "stats", CTLTYPE_ULONG | CTLFLAG_RD, sc, 0, 2804217556Smdf fatm_sysctl_stats, "LU", "card statistics") == NULL) 2805116735Sharti goto fail; 2806116735Sharti 2807116735Sharti if (SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 2808116735Sharti OID_AUTO, "retry_tx", CTLFLAG_RW, &sc->retry_tx, 0, 2809116735Sharti "retry flag") == NULL) 2810116735Sharti goto fail; 2811116735Sharti 2812116735Sharti#ifdef FATM_DEBUG 2813116735Sharti if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 2814116735Sharti OID_AUTO, "debug", CTLFLAG_RW, &sc->debug, 0, "debug flags") 2815116735Sharti == NULL) 2816116735Sharti goto fail; 2817116735Sharti sc->debug = FATM_DEBUG; 2818116735Sharti#endif 2819116735Sharti 2820116735Sharti /* 2821116735Sharti * Network subsystem stuff 2822116735Sharti */ 2823116735Sharti ifp->if_softc = sc; 2824121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 2825116735Sharti ifp->if_flags = IFF_SIMPLEX; 2826116735Sharti ifp->if_ioctl = fatm_ioctl; 2827116735Sharti ifp->if_start = fatm_start; 2828116735Sharti ifp->if_init = fatm_init; 2829147256Sbrooks ifp->if_linkmib = &IFP2IFATM(sc->ifp)->mib; 2830147256Sbrooks ifp->if_linkmiblen = sizeof(IFP2IFATM(sc->ifp)->mib); 2831116735Sharti 2832116735Sharti /* 2833254263Sscottl * Enable busmaster 2834116735Sharti */ 2835254263Sscottl pci_enable_busmaster(dev); 2836116735Sharti 2837116735Sharti /* 2838116735Sharti * Map memory 2839116735Sharti */ 2840116735Sharti sc->memid = 0x10; 2841127135Snjl sc->memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->memid, 2842127135Snjl RF_ACTIVE); 2843116735Sharti if (sc->memres == NULL) { 2844116735Sharti if_printf(ifp, "could not map memory\n"); 2845116735Sharti error = ENXIO; 2846116735Sharti goto fail; 2847116735Sharti } 2848116735Sharti sc->memh = rman_get_bushandle(sc->memres); 2849116735Sharti sc->memt = rman_get_bustag(sc->memres); 2850116735Sharti 2851116735Sharti /* 2852298955Spfg * Convert endianness of slave access 2853116735Sharti */ 2854116735Sharti cfg = pci_read_config(dev, FATM_PCIR_MCTL, 1); 2855116735Sharti cfg |= FATM_PCIM_SWAB; 2856116735Sharti pci_write_config(dev, FATM_PCIR_MCTL, cfg, 1); 2857116735Sharti 2858116735Sharti /* 2859116735Sharti * Allocate interrupt (activate at the end) 2860116735Sharti */ 2861116735Sharti sc->irqid = 0; 2862127135Snjl sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 2863127135Snjl RF_SHAREABLE | RF_ACTIVE); 2864116735Sharti if (sc->irqres == NULL) { 2865116735Sharti if_printf(ifp, "could not allocate irq\n"); 2866116735Sharti error = ENXIO; 2867116735Sharti goto fail; 2868116735Sharti } 2869116735Sharti 2870116735Sharti /* 2871116735Sharti * Allocate the parent DMA tag. This is used simply to hold overall 2872116735Sharti * restrictions for the controller (and PCI bus) and is never used 2873116735Sharti * to do anything. 2874116735Sharti */ 2875183504Smarius if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, 2876116735Sharti BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 2877117126Sscottl NULL, NULL, BUS_SPACE_MAXSIZE_32BIT, MAXDMASEGS, 2878117164Sharti BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, 2879117126Sscottl &sc->parent_dmat)) { 2880116735Sharti if_printf(ifp, "could not allocate parent DMA tag\n"); 2881116735Sharti error = ENOMEM; 2882116735Sharti goto fail; 2883116735Sharti } 2884116735Sharti 2885116735Sharti /* 2886116735Sharti * Allocate the receive buffer DMA tag. This tag must map a maximum of 2887116735Sharti * a mbuf cluster. 2888116735Sharti */ 2889116735Sharti if (bus_dma_tag_create(sc->parent_dmat, 1, 0, 2890116735Sharti BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 2891117126Sscottl NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, 2892117164Sharti NULL, NULL, &sc->rbuf_tag)) { 2893116735Sharti if_printf(ifp, "could not allocate rbuf DMA tag\n"); 2894116735Sharti error = ENOMEM; 2895116735Sharti goto fail; 2896116735Sharti } 2897116735Sharti 2898116735Sharti /* 2899117164Sharti * Allocate the transmission DMA tag. Must add 1, because 2900117164Sharti * rounded up PDU will be 65536 bytes long. 2901116735Sharti */ 2902116735Sharti if (bus_dma_tag_create(sc->parent_dmat, 1, 0, 2903116735Sharti BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 2904116735Sharti NULL, NULL, 2905117164Sharti FATM_MAXPDU + 1, TPD_EXTENSIONS + TXD_FIXED, MCLBYTES, 0, 2906117164Sharti NULL, NULL, &sc->tx_tag)) { 2907116735Sharti if_printf(ifp, "could not allocate tx DMA tag\n"); 2908116735Sharti error = ENOMEM; 2909116735Sharti goto fail; 2910116735Sharti } 2911116735Sharti 2912116735Sharti /* 2913116735Sharti * Allocate DMAable memory. 2914116735Sharti */ 2915116735Sharti sc->stat_mem.size = sizeof(uint32_t) * (FATM_CMD_QLEN + FATM_TX_QLEN 2916116735Sharti + FATM_RX_QLEN + SMALL_SUPPLY_QLEN + LARGE_SUPPLY_QLEN); 2917116735Sharti sc->stat_mem.align = 4; 2918116735Sharti 2919116735Sharti sc->txq_mem.size = FATM_TX_QLEN * TPD_SIZE; 2920116735Sharti sc->txq_mem.align = 32; 2921116735Sharti 2922116735Sharti sc->rxq_mem.size = FATM_RX_QLEN * RPD_SIZE; 2923116735Sharti sc->rxq_mem.align = 32; 2924116735Sharti 2925116735Sharti sc->s1q_mem.size = SMALL_SUPPLY_QLEN * 2926116735Sharti BSUP_BLK2SIZE(SMALL_SUPPLY_BLKSIZE); 2927116735Sharti sc->s1q_mem.align = 32; 2928116735Sharti 2929116735Sharti sc->l1q_mem.size = LARGE_SUPPLY_QLEN * 2930116735Sharti BSUP_BLK2SIZE(LARGE_SUPPLY_BLKSIZE); 2931116735Sharti sc->l1q_mem.align = 32; 2932116735Sharti 2933116735Sharti#ifdef TEST_DMA_SYNC 2934116735Sharti if ((error = alloc_dma_memoryX(sc, "STATUS", &sc->stat_mem)) != 0 || 2935116735Sharti (error = alloc_dma_memoryX(sc, "TXQ", &sc->txq_mem)) != 0 || 2936116735Sharti (error = alloc_dma_memoryX(sc, "RXQ", &sc->rxq_mem)) != 0 || 2937116735Sharti (error = alloc_dma_memoryX(sc, "S1Q", &sc->s1q_mem)) != 0 || 2938116735Sharti (error = alloc_dma_memoryX(sc, "L1Q", &sc->l1q_mem)) != 0) 2939116735Sharti goto fail; 2940116735Sharti#else 2941116735Sharti if ((error = alloc_dma_memory(sc, "STATUS", &sc->stat_mem)) != 0 || 2942116735Sharti (error = alloc_dma_memory(sc, "TXQ", &sc->txq_mem)) != 0 || 2943116735Sharti (error = alloc_dma_memory(sc, "RXQ", &sc->rxq_mem)) != 0 || 2944116735Sharti (error = alloc_dma_memory(sc, "S1Q", &sc->s1q_mem)) != 0 || 2945116735Sharti (error = alloc_dma_memory(sc, "L1Q", &sc->l1q_mem)) != 0) 2946116735Sharti goto fail; 2947116735Sharti#endif 2948116735Sharti 2949116735Sharti sc->prom_mem.size = sizeof(struct prom); 2950116735Sharti sc->prom_mem.align = 32; 2951116735Sharti if ((error = alloc_dma_memory(sc, "PROM", &sc->prom_mem)) != 0) 2952116735Sharti goto fail; 2953116735Sharti 2954116735Sharti sc->sadi_mem.size = sizeof(struct fatm_stats); 2955116735Sharti sc->sadi_mem.align = 32; 2956116735Sharti if ((error = alloc_dma_memory(sc, "STATISTICS", &sc->sadi_mem)) != 0) 2957116735Sharti goto fail; 2958116735Sharti 2959116735Sharti sc->reg_mem.size = sizeof(uint32_t) * FATM_NREGS; 2960116735Sharti sc->reg_mem.align = 32; 2961116735Sharti if ((error = alloc_dma_memory(sc, "REGISTERS", &sc->reg_mem)) != 0) 2962116735Sharti goto fail; 2963116735Sharti 2964116735Sharti /* 2965116735Sharti * Allocate queues 2966116735Sharti */ 2967116735Sharti sc->cmdqueue.chunk = malloc(FATM_CMD_QLEN * sizeof(struct cmdqueue), 2968116735Sharti M_DEVBUF, M_ZERO | M_WAITOK); 2969116735Sharti sc->txqueue.chunk = malloc(FATM_TX_QLEN * sizeof(struct txqueue), 2970116735Sharti M_DEVBUF, M_ZERO | M_WAITOK); 2971116735Sharti sc->rxqueue.chunk = malloc(FATM_RX_QLEN * sizeof(struct rxqueue), 2972116735Sharti M_DEVBUF, M_ZERO | M_WAITOK); 2973116735Sharti sc->s1queue.chunk = malloc(SMALL_SUPPLY_QLEN * sizeof(struct supqueue), 2974116735Sharti M_DEVBUF, M_ZERO | M_WAITOK); 2975116735Sharti sc->l1queue.chunk = malloc(LARGE_SUPPLY_QLEN * sizeof(struct supqueue), 2976116735Sharti M_DEVBUF, M_ZERO | M_WAITOK); 2977116735Sharti 2978118208Sharti sc->vccs = malloc((FORE_MAX_VCC + 1) * sizeof(sc->vccs[0]), 2979116735Sharti M_DEVBUF, M_ZERO | M_WAITOK); 2980118208Sharti sc->vcc_zone = uma_zcreate("FATM vccs", sizeof(struct card_vcc), 2981118208Sharti NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 2982118208Sharti if (sc->vcc_zone == NULL) { 2983118208Sharti error = ENOMEM; 2984118208Sharti goto fail; 2985118208Sharti } 2986116735Sharti 2987116735Sharti /* 2988116735Sharti * Allocate memory for the receive buffer headers. The total number 2989116735Sharti * of headers should probably also include the maximum number of 2990116735Sharti * buffers on the receive queue. 2991116735Sharti */ 2992116735Sharti sc->rbuf_total = SMALL_POOL_SIZE + LARGE_POOL_SIZE; 2993116735Sharti sc->rbufs = malloc(sc->rbuf_total * sizeof(struct rbuf), 2994116735Sharti M_DEVBUF, M_ZERO | M_WAITOK); 2995116735Sharti 2996116735Sharti /* 2997116735Sharti * Put all rbuf headers on the free list and create DMA maps. 2998116735Sharti */ 2999116735Sharti for (rb = sc->rbufs, i = 0; i < sc->rbuf_total; i++, rb++) { 3000116735Sharti if ((error = bus_dmamap_create(sc->rbuf_tag, 0, &rb->map))) { 3001147256Sbrooks if_printf(sc->ifp, "creating rx map: %d\n", 3002116735Sharti error); 3003116735Sharti goto fail; 3004116735Sharti } 3005116735Sharti LIST_INSERT_HEAD(&sc->rbuf_free, rb, link); 3006116735Sharti } 3007116735Sharti 3008116735Sharti /* 3009116735Sharti * Create dma maps for transmission. In case of an error, free the 3010116735Sharti * allocated DMA maps, because on some architectures maps are NULL 3011116735Sharti * and we cannot distinguish between a failure and a NULL map in 3012116735Sharti * the detach routine. 3013116735Sharti */ 3014116735Sharti for (i = 0; i < FATM_TX_QLEN; i++) { 3015116735Sharti tx = GET_QUEUE(sc->txqueue, struct txqueue, i); 3016116735Sharti if ((error = bus_dmamap_create(sc->tx_tag, 0, &tx->map))) { 3017147256Sbrooks if_printf(sc->ifp, "creating tx map: %d\n", 3018116735Sharti error); 3019116735Sharti while (i > 0) { 3020116735Sharti tx = GET_QUEUE(sc->txqueue, struct txqueue, 3021116735Sharti i - 1); 3022116735Sharti bus_dmamap_destroy(sc->tx_tag, tx->map); 3023116735Sharti i--; 3024116735Sharti } 3025116735Sharti goto fail; 3026116735Sharti } 3027116735Sharti } 3028116735Sharti 3029147256Sbrooks utopia_attach(&sc->utopia, IFP2IFATM(sc->ifp), &sc->media, &sc->mtx, 3030116735Sharti &sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 3031116735Sharti &fatm_utopia_methods); 3032116735Sharti sc->utopia.flags |= UTP_FL_NORESET | UTP_FL_POLL_CARRIER; 3033116735Sharti 3034116735Sharti /* 3035116735Sharti * Attach the interface 3036116735Sharti */ 3037116735Sharti atm_ifattach(ifp); 3038116735Sharti ifp->if_snd.ifq_maxlen = 512; 3039116735Sharti 3040147525Sharti#ifdef ENABLE_BPF 3041147525Sharti bpfattach(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc)); 3042147525Sharti#endif 3043147525Sharti 3044156950Sharti error = bus_setup_intr(dev, sc->irqres, INTR_TYPE_NET | INTR_MPSAFE, 3045166901Spiso NULL, fatm_intr, sc, &sc->ih); 3046116735Sharti if (error) { 3047116735Sharti if_printf(ifp, "couldn't setup irq\n"); 3048116735Sharti goto fail; 3049116735Sharti } 3050116735Sharti 3051116735Sharti fail: 3052116735Sharti if (error) 3053116735Sharti fatm_detach(dev); 3054116735Sharti 3055116735Sharti return (error); 3056116735Sharti} 3057116735Sharti 3058116735Sharti#if defined(FATM_DEBUG) && 0 3059116735Shartistatic void 3060116735Shartidump_s1_queue(struct fatm_softc *sc) 3061116735Sharti{ 3062116735Sharti int i; 3063116735Sharti struct supqueue *q; 3064116735Sharti 3065116735Sharti for(i = 0; i < SMALL_SUPPLY_QLEN; i++) { 3066116735Sharti q = GET_QUEUE(sc->s1queue, struct supqueue, i); 3067116735Sharti printf("%2d: card=%x(%x,%x) stat=%x\n", i, 3068116735Sharti q->q.card, 3069116735Sharti READ4(sc, q->q.card), 3070116735Sharti READ4(sc, q->q.card + 4), 3071116735Sharti *q->q.statp); 3072116735Sharti } 3073116735Sharti} 3074116735Sharti#endif 3075116735Sharti 3076116735Sharti/* 3077116735Sharti * Driver infrastructure. 3078116735Sharti */ 3079116735Shartistatic device_method_t fatm_methods[] = { 3080116735Sharti DEVMETHOD(device_probe, fatm_probe), 3081116735Sharti DEVMETHOD(device_attach, fatm_attach), 3082116735Sharti DEVMETHOD(device_detach, fatm_detach), 3083116735Sharti { 0, 0 } 3084116735Sharti}; 3085116735Shartistatic driver_t fatm_driver = { 3086116735Sharti "fatm", 3087116735Sharti fatm_methods, 3088116735Sharti sizeof(struct fatm_softc), 3089116735Sharti}; 3090116735Sharti 3091116735ShartiDRIVER_MODULE(fatm, pci, fatm_driver, fatm_devclass, 0, 0); 3092