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