Esempio n. 1
0
/*
 * open the VCC
 */
void
patm_rx_vcc_open(struct patm_softc *sc, struct patm_vcc *vcc)
{
	uint32_t w1 = IDT_RCT_OPEN;

	patm_debug(sc, VCC, "%u.%u RX opening", vcc->vcc.vpi, vcc->vcc.vci);

	switch (vcc->vcc.aal) {
	  case ATMIO_AAL_0:
		w1 |= IDT_RCT_AAL0 | IDT_RCT_FBP2 | IDT_RCT_RCI;
		break;
	  case ATMIO_AAL_34:
		w1 |= IDT_RCT_AAL34;
		break;
	  case ATMIO_AAL_5:
		w1 |= IDT_RCT_AAL5;
		break;
	  case ATMIO_AAL_RAW:
		w1 |= IDT_RCT_AALRAW | IDT_RCT_RCI;
		break;
	}

	if (vcc->cid != 0)
		patm_sram_write4(sc, sc->mmap->rct + vcc->cid *
		    IDT_RCT_ENTRY_SIZE, w1, 0, 0, 0xffffffff);
	else {
		/* switch the interface into promiscuous mode */
		patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) |
		    IDT_CFG_ICAPT | IDT_CFG_VPECA);
	}

	vcc->vflags |= PATM_VCC_RX_OPEN;
}
Esempio n. 2
0
/* close the given vcc for transmission */
void
patm_rx_vcc_close(struct patm_softc *sc, struct patm_vcc *vcc)
{
	u_int w1;

	patm_debug(sc, VCC, "%u.%u RX closing", vcc->vcc.vpi, vcc->vcc.vci);

	if (vcc->cid == 0) {
		/* switch off promiscuous mode */
		patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) &
		    ~(IDT_CFG_ICAPT | IDT_CFG_VPECA));
		vcc->vflags &= ~PATM_VCC_RX_OPEN;
		return;
	}

	/* close the connection but keep state */
	w1 = rct_read(sc, vcc->cid, 0);
	w1 &= ~IDT_RCT_OPEN;
	rct_write(sc, vcc->cid, 0, w1);

	/* minimum idle count */
	w1 = (w1 & ~IDT_RCT_IACT_CNT_MASK) | (1 << IDT_RCT_IACT_CNT_SHIFT);
	rct_write(sc, vcc->cid, 0, w1);

	/* initialize scan */
	patm_nor_write(sc, IDT_NOR_IRCP, vcc->cid);

	vcc->vflags &= ~PATM_VCC_RX_OPEN;
	vcc->vflags |= PATM_VCC_RX_CLOSING;

	/*
	 * check the RSQ
	 * This is a hack. The problem is, that although an entry is written
	 * to the RSQ, no interrupt is generated. Also we must wait 1 cell
	 * time for the SAR to process the scan of our connection.
	 */
	DELAY(1);
	patm_intr_rsq(sc);
}
Esempio n. 3
0
int
patm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
	struct ifreq *ifr = (struct ifreq *)data;
	struct ifaddr *ifa = (struct ifaddr *)data;
	struct patm_softc *sc = ifp->if_softc;
	int error = 0;
	uint32_t cfg;
	struct atmio_vcctable *vtab;

	switch (cmd) {

	  case SIOCSIFADDR:
		mtx_lock(&sc->mtx);
		ifp->if_flags |= IFF_UP;
		if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
			patm_initialize(sc);
		switch (ifa->ifa_addr->sa_family) {

#ifdef INET
		  case AF_INET:
		  case AF_INET6:
			ifa->ifa_rtrequest = atm_rtrequest;
			break;
#endif
		  default:
			break;
		}
		mtx_unlock(&sc->mtx);
		break;

	  case SIOCSIFFLAGS:
		mtx_lock(&sc->mtx);
		if (ifp->if_flags & IFF_UP) {
			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
				patm_initialize(sc);
			}
		} else {
			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
				patm_stop(sc);
			}
		}
		mtx_unlock(&sc->mtx);
		break;

	  case SIOCGIFMEDIA:
	  case SIOCSIFMEDIA:
		error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd);

		/*
		 * We need to toggle unassigned/idle cells ourself because
		 * the 77252 generates null cells for spacing. When switching
		 * null cells of it gets the timing wrong.
		 */
		mtx_lock(&sc->mtx);
		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
			if (sc->utopia.state & UTP_ST_UNASS) {
				if (!(sc->flags & PATM_UNASS)) {
					cfg = patm_nor_read(sc, IDT_NOR_CFG);
					cfg &= ~IDT_CFG_IDLECLP;
					patm_nor_write(sc, IDT_NOR_CFG, cfg);
					sc->flags |= PATM_UNASS;
				}
			} else {
				if (sc->flags & PATM_UNASS) {
					cfg = patm_nor_read(sc, IDT_NOR_CFG);
					cfg |= IDT_CFG_IDLECLP;
					patm_nor_write(sc, IDT_NOR_CFG, cfg);
					sc->flags &= ~PATM_UNASS;
				}
			}
		} else {
			if (sc->utopia.state & UTP_ST_UNASS)
				sc->flags |= PATM_UNASS;
			else
				sc->flags &= ~PATM_UNASS;
		}
		mtx_unlock(&sc->mtx);
		break;

	  case SIOCSIFMTU:
		/*
		 * Set the interface MTU.
		 */
		if (ifr->ifr_mtu > ATMMTU)
			error = EINVAL;
		else
			ifp->if_mtu = ifr->ifr_mtu;
		break;

	  case SIOCATMOPENVCC:		/* kernel internal use */
		error = patm_open_vcc(sc, (struct atmio_openvcc *)data);
		break;

	  case SIOCATMCLOSEVCC:		/* kernel internal use */
		error = patm_close_vcc(sc, (struct atmio_closevcc *)data);
		break;

	  case SIOCATMGVCCS:	/* external use */
#ifdef CPU_CHERI
#error Unvalidatable ifr_data use.  Unsafe with CheriABI.
#endif
		/* return vcc table */
		vtab = atm_getvccs((struct atmio_vcc **)sc->vccs,
		    sc->mmap->max_conn, sc->vccs_open, &sc->mtx, 1);
		error = copyout(vtab, ifr->ifr_data, sizeof(*vtab) +
		    vtab->count * sizeof(vtab->vccs[0]));
		free(vtab, M_DEVBUF);
		break;

	  case SIOCATMGETVCCS:	/* netgraph internal use */
		vtab = atm_getvccs((struct atmio_vcc **)sc->vccs,
		    sc->mmap->max_conn, sc->vccs_open, &sc->mtx, 0);
		if (vtab == NULL) {
			error = ENOMEM;
			break;
		}
		*(void **)data = vtab;
		break;

	  default:
		patm_debug(sc, IOCTL, "unknown cmd=%08lx arg=%p", cmd, data);
		error = EINVAL;
		break;
	}

	return (error);
}