/* * Open the VCC with the given parameters */ static int patm_open_vcc(struct patm_softc *sc, struct atmio_openvcc *arg) { u_int cid; struct patm_vcc *vcc; int error = 0; patm_debug(sc, VCC, "Open VCC: %u.%u flags=%#x", arg->param.vpi, arg->param.vci, arg->param.flags); if (!LEGAL_VPI(sc, arg->param.vpi) || !LEGAL_VCI(sc, arg->param.vci)) return (EINVAL); if (arg->param.vci == 0 && (arg->param.vpi != 0 || !(arg->param.flags & ATMIO_FLAG_NOTX) || arg->param.aal != ATMIO_AAL_RAW)) return (EINVAL); cid = PATM_CID(sc, arg->param.vpi, arg->param.vci); if ((arg->param.flags & ATMIO_FLAG_NOTX) && (arg->param.flags & ATMIO_FLAG_NORX)) return (EINVAL); if ((arg->param.traffic == ATMIO_TRAFFIC_ABR) && (arg->param.flags & (ATMIO_FLAG_NOTX | ATMIO_FLAG_NORX))) return (EINVAL); /* allocate vcc */ vcc = uma_zalloc(sc->vcc_zone, M_NOWAIT | M_ZERO); if (vcc == NULL) return (ENOMEM); mtx_lock(&sc->mtx); if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) { /* stopped while we have analyzed the arguments */ error = EIO; goto done; } if (sc->vccs[cid] != NULL) { /* ups, already open */ error = EBUSY; goto done; } /* check some parameters */ vcc->cid = cid; vcc->vcc = arg->param; vcc->vflags = 0; vcc->rxhand = arg->rxhand; switch (vcc->vcc.aal) { case ATMIO_AAL_0: case ATMIO_AAL_34: case ATMIO_AAL_5: break; case ATMIO_AAL_RAW: if (arg->param.vci == 0 && !(arg->param.flags & ATMIO_FLAG_NOTX)) { error = EINVAL; goto done; } break; default: error = EINVAL; goto done; } switch (vcc->vcc.traffic) { case ATMIO_TRAFFIC_VBR: case ATMIO_TRAFFIC_UBR: case ATMIO_TRAFFIC_CBR: case ATMIO_TRAFFIC_ABR: break; default: error = EINVAL; goto done; } /* initialize */ vcc->chain = NULL; vcc->last = NULL; vcc->ibytes = vcc->ipackets = 0; vcc->obytes = vcc->opackets = 0; /* ask the TX and RX sides */ patm_debug(sc, VCC, "Open VCC: asking Rx/Tx"); if (!(vcc->vcc.flags & ATMIO_FLAG_NOTX) && (error = patm_tx_vcc_can_open(sc, vcc)) != 0) goto done; if (!(vcc->vcc.flags & ATMIO_FLAG_NORX) && (error = patm_rx_vcc_can_open(sc, vcc)) != 0) goto done; /* ok - go ahead */ sc->vccs[cid] = vcc; patm_load_vc(sc, vcc, 0); /* don't free below */ vcc = NULL; sc->vccs_open++; /* done */ done: mtx_unlock(&sc->mtx); if (vcc != NULL) uma_zfree(sc->vcc_zone, vcc); return (error); }
/* * Start the card. This assumes the mutex to be held */ void patm_initialize(struct patm_softc *sc) { uint32_t cfg; u_int i; patm_debug(sc, ATTACH, "configuring..."); /* clear SRAM */ for (i = 0; i < sc->mmap->sram * 1024; i += 4) patm_sram_write4(sc, i, 0, 0, 0, 0); patm_scd_init(sc); /* configuration register. Setting NOIDLE makes the timing wrong! */ cfg = IDT_CFG_TXFIFO9 | IDT_CFG_RXQ512 | PATM_CFG_VPI | /* IDT_CFG_NOIDLE | */ sc->mmap->rxtab; if (!(sc->flags & PATM_UNASS)) cfg |= IDT_CFG_IDLECLP; patm_nor_write(sc, IDT_NOR_CFG, cfg); /* clean all the status queues and the Raw handle */ memset(sc->tsq, 0, sc->sq_size); /* initialize RSQ */ patm_debug(sc, ATTACH, "RSQ %llx", (unsigned long long)sc->rsq_phy); patm_nor_write(sc, IDT_NOR_RSQB, sc->rsq_phy); patm_nor_write(sc, IDT_NOR_RSQT, sc->rsq_phy); patm_nor_write(sc, IDT_NOR_RSQH, 0); sc->rsq_last = PATM_RSQ_SIZE - 1; /* initialize TSTB */ patm_nor_write(sc, IDT_NOR_TSTB, sc->mmap->tst1base << 2); patm_tst_init(sc); /* initialize TSQ */ for (i = 0; i < IDT_TSQ_SIZE; i++) sc->tsq[i].stamp = htole32(IDT_TSQE_EMPTY); patm_nor_write(sc, IDT_NOR_TSQB, sc->tsq_phy); patm_nor_write(sc, IDT_NOR_TSQH, 0); patm_nor_write(sc, IDT_NOR_TSQT, 0); sc->tsq_next = sc->tsq; /* GP */ #if BYTE_ORDER == BIG_ENDIAN && 0 patm_nor_write(sc, IDT_NOR_GP, IDT_GP_BIGE); #else patm_nor_write(sc, IDT_NOR_GP, 0); #endif /* VPM */ patm_nor_write(sc, IDT_NOR_VPM, 0); /* RxFIFO */ patm_nor_write(sc, IDT_NOR_RXFD, IDT_RXFD(sc->mmap->rxfifo_addr, sc->mmap->rxfifo_code)); patm_nor_write(sc, IDT_NOR_RXFT, 0); patm_nor_write(sc, IDT_NOR_RXFH, 0); /* RAWHND */ patm_debug(sc, ATTACH, "RWH %llx", (unsigned long long)sc->rawhnd_phy); patm_nor_write(sc, IDT_NOR_RAWHND, sc->rawhnd_phy); /* ABRSTD */ patm_nor_write(sc, IDT_NOR_ABRSTD, IDT_ABRSTD(sc->mmap->abrstd_addr, sc->mmap->abrstd_code)); for (i = 0; i < sc->mmap->abrstd_size; i++) patm_sram_write(sc, sc->mmap->abrstd_addr + i, 0); patm_nor_write(sc, IDT_NOR_ABRRQ, 0); patm_nor_write(sc, IDT_NOR_VBRRQ, 0); /* rate tables */ if (sc->flags & PATM_25M) { for (i = 0; i < patm_rtables_size; i++) patm_sram_write(sc, sc->mmap->rtables + i, patm_rtables25[i]); } else { for (i = 0; i < patm_rtables_size; i++) patm_sram_write(sc, sc->mmap->rtables + i, patm_rtables155[i]); } patm_nor_write(sc, IDT_NOR_RTBL, sc->mmap->rtables << 2); /* Maximum deficit */ patm_nor_write(sc, IDT_NOR_MXDFCT, 32 | IDT_MDFCT_LCI | IDT_MDFCT_LNI); /* Free buffer queues */ patm_nor_write(sc, IDT_NOR_FBQP0, 0); patm_nor_write(sc, IDT_NOR_FBQP1, 0); patm_nor_write(sc, IDT_NOR_FBQP2, 0); patm_nor_write(sc, IDT_NOR_FBQP3, 0); patm_nor_write(sc, IDT_NOR_FBQWP0, 0); patm_nor_write(sc, IDT_NOR_FBQWP1, 0); patm_nor_write(sc, IDT_NOR_FBQWP2, 0); patm_nor_write(sc, IDT_NOR_FBQWP3, 0); patm_nor_write(sc, IDT_NOR_FBQS0, (SMBUF_THRESHOLD << 28) | (SMBUF_NI_THRESH << 24) | (SMBUF_CI_THRESH << 20) | SMBUF_CELLS); patm_nor_write(sc, IDT_NOR_FBQS1, (LMBUF_THRESHOLD << 28) | (LMBUF_NI_THRESH << 24) | (LMBUF_CI_THRESH << 20) | LMBUF_CELLS); patm_nor_write(sc, IDT_NOR_FBQS2, (VMBUF_THRESHOLD << 28) | VMBUF_CELLS); patm_nor_write(sc, IDT_NOR_FBQS3, 0); /* make SCD0 for UBR0 */ if ((sc->scd0 = patm_scd_alloc(sc)) == NULL) { patm_printf(sc, "cannot create UBR0 SCD\n"); patm_reset(sc); return; } sc->scd0->q.ifq_maxlen = PATM_DLFT_MAXQ; patm_scd_setup(sc, sc->scd0); patm_tct_setup(sc, sc->scd0, NULL); patm_debug(sc, ATTACH, "go..."); sc->utopia.flags &= ~UTP_FL_POLL_CARRIER; sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; /* enable interrupts, Tx and Rx paths */ cfg |= IDT_CFG_RXPTH | IDT_CFG_RXIIMM | IDT_CFG_RAWIE | IDT_CFG_RQFIE | IDT_CFG_TIMOIE | IDT_CFG_FBIE | IDT_CFG_TXENB | IDT_CFG_TXINT | IDT_CFG_TXUIE | IDT_CFG_TXSFI | IDT_CFG_PHYIE; patm_nor_write(sc, IDT_NOR_CFG, cfg); for (i = 0; i < sc->mmap->max_conn; i++) if (sc->vccs[i] != NULL) patm_load_vc(sc, sc->vccs[i], 1); ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp), sc->utopia.carrier == UTP_CARR_OK); }