Ejemplo n.º 1
0
/*---------------------------------------------------------------------------*
 *	IRQ handler
 *---------------------------------------------------------------------------*/
static int
iwic_pci_intr(void *p)
{
	struct iwic_softc *sc = p;

	while (1) {
		int irq_stat = IWIC_READ(sc, ISTA);

		if (irq_stat == 0)
			break;

		if (irq_stat & (ISTA_D_RME | ISTA_D_RMR | ISTA_D_XFR)) {
			iwic_dchan_xfer_irq(sc, irq_stat);
		}
		if (irq_stat & ISTA_D_EXI) {
			iwic_dchan_xirq(sc);
		}
		if (irq_stat & ISTA_B1_EXI) {
			iwic_bchan_xirq(sc, 0);
		}
		if (irq_stat & ISTA_B2_EXI) {
			iwic_bchan_xirq(sc, 1);
		}
	}

	return 0;
}
Ejemplo n.º 2
0
/*---------------------------------------------------------------------------*
 *	initalize / deinitialize B-channel hardware
 *---------------------------------------------------------------------------*/
static void
iwic_bchan_init(struct iwic_softc *sc, int chan_no, int activate)
{
	struct iwic_bchan *bchan = &sc->sc_bchan[chan_no];

	NDBGL1(L1_BCHAN, "chan %d, activate %d", chan_no, activate);

	if(activate)
	{
		if(bchan->bprot == BPROT_NONE)
		{
			/* Extended transparent mode */
			IWIC_WRITE(sc, bchan->offset + B_MODE, B_MODE_MMS);
		}
		else
		{
			/* Transparent mode */
			IWIC_WRITE(sc, bchan->offset + B_MODE, 0);
			/* disable address comparation */
			IWIC_WRITE (sc, bchan->offset+B_ADM1, 0xff);
			IWIC_WRITE (sc, bchan->offset+B_ADM2, 0xff);
		}

		/* reset & start receiver */
		IWIC_WRITE(sc, bchan->offset + B_CMDR, B_CMDR_RRST|B_CMDR_RACT);

		/* clear irq mask */
		IWIC_WRITE(sc, bchan->offset + B_EXIM, 0);
	}
	else
	{
		/* mask all irqs */		
		IWIC_WRITE(sc, bchan->offset + B_EXIM, 0xff);

		/* reset mode */
		IWIC_WRITE(sc, bchan->offset + B_MODE, 0);
		
		/* Bring interface down */
		IWIC_WRITE(sc, bchan->offset + B_CMDR, B_CMDR_RRST | B_CMDR_XRST);

		/* Flush pending interrupts */
		IWIC_READ(sc, bchan->offset + B_EXIR);
	}
}
Ejemplo n.º 3
0
/*---------------------------------------------------------------------------*
 *	B-channel interrupt handler
 *---------------------------------------------------------------------------*/
void
iwic_bchan_xirq(struct iwic_softc *sc, int chan_no)
{
	int irq_stat;
	struct iwic_bchan *chan;
	int cmd = 0;
	int activity = 0;

	chan = &sc->sc_bchan[chan_no];

	irq_stat = IWIC_READ(sc, chan->offset + B_EXIR);

	NDBGL1(L1_H_IRQ, "irq_stat = 0x%x", irq_stat);
	
	if((irq_stat & (B_EXIR_RMR | B_EXIR_RME | B_EXIR_RDOV | B_EXIR_XFR | B_EXIR_XDUN)) == 0)
	{
		NDBGL1(L1_H_XFRERR, "spurious IRQ!");
		return;
	}

	if (irq_stat & B_EXIR_RDOV)
	{
		NDBGL1(L1_H_XFRERR, "iwic%d: EXIR B-channel Receive Data Overflow", sc->sc_unit);
	}

	if (irq_stat & B_EXIR_XDUN)
	{
		NDBGL1(L1_H_XFRERR, "iwic%d: EXIR B-channel Transmit Data Underrun", sc->sc_unit);
		cmd |= (B_CMDR_XRST);	/*XXX must retransmit frame ! */
	}

/* RX message end interrupt */
	
	if(irq_stat & B_EXIR_RME)
	{
		int error;

		NDBGL1(L1_H_IRQ, "B_EXIR_RME");

		error = (IWIC_READ(sc,chan->offset+B_STAR) &
			 (B_STAR_RDOV | B_STAR_CRCE | B_STAR_RMB));

		if(error)
		{
			if(error & B_STAR_RDOV)
				NDBGL1(L1_H_XFRERR, "iwic%d: B-channel Receive Data Overflow", sc->sc_unit);
			if(error & B_STAR_CRCE)
				NDBGL1(L1_H_XFRERR, "iwic%d: B-channel CRC Error", sc->sc_unit);
			if(error & B_STAR_RMB)
				NDBGL1(L1_H_XFRERR, "iwic%d: B-channel Receive Message Aborted", sc->sc_unit);
		}

		/* all error conditions checked, now decide and take action */
		
		if(error == 0)
		{
			int fifo_data_len;
			fifo_data_len = ((IWIC_READ(sc,chan->offset+B_RBCL)) &
					((IWIC_BCHAN_FIFO_LEN)-1));
		
			if(fifo_data_len == 0)
				fifo_data_len = IWIC_BCHAN_FIFO_LEN;


			if(chan->in_mbuf == NULL)
			{
				if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
					panic("L1 iwic_bchan_irq: RME, cannot allocate mbuf!\n");
				chan->in_cbptr = chan->in_mbuf->m_data;
				chan->in_len = 0;
			}

			if((chan->in_len + fifo_data_len) <= BCH_MAX_DATALEN)
			{
				/* read data from fifo */
	
				NDBGL1(L1_H_IRQ, "B_EXIR_RME, rd fifo, len = %d", fifo_data_len);

				IWIC_RDBFIFO(sc, chan, chan->in_cbptr, fifo_data_len);

				cmd |= (B_CMDR_RACK | B_CMDR_RACT);
				IWIC_WRITE(sc, chan->offset + B_CMDR, cmd);
				cmd = 0;
				
		                chan->in_len += fifo_data_len;
				chan->rxcount += fifo_data_len;

				/* setup mbuf data length */
					
				chan->in_mbuf->m_len = chan->in_len;
				chan->in_mbuf->m_pkthdr.len = chan->in_len;

				if(sc->sc_trace & TRACE_B_RX)
				{
					i4b_trace_hdr_t hdr;
					hdr.unit = L0IWICUNIT(sc->sc_unit);
					hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
					hdr.dir = FROM_NT;
					hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
					MICROTIME(hdr.time);
					i4b_l1_trace_ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data);
				}

				(*chan->iwic_drvr_linktab->bch_rx_data_ready)(chan->iwic_drvr_linktab->unit);

				activity = ACT_RX;
				
				/* mark buffer ptr as unused */
					
				chan->in_mbuf = NULL;
				chan->in_cbptr = NULL;
				chan->in_len = 0;
			}
			else
			{
				NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RME, in_len=%d, fifolen=%d", chan->in_len, fifo_data_len);
				chan->in_cbptr = chan->in_mbuf->m_data;
				chan->in_len = 0;
				cmd |= (B_CMDR_RRST | B_CMDR_RACK);
			}
		}
		else
		{
			if (chan->in_mbuf != NULL)
			{
				i4b_Bfreembuf(chan->in_mbuf);
				chan->in_mbuf = NULL;
				chan->in_cbptr = NULL;
				chan->in_len = 0;
			}
			cmd |= (B_CMDR_RRST | B_CMDR_RACK);
		}
	}

/* RX fifo full interrupt */

	if(irq_stat & B_EXIR_RMR)
	{
		NDBGL1(L1_H_IRQ, "B_EXIR_RMR");

		if(chan->in_mbuf == NULL)
		{
			if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
				panic("L1 iwic_bchan_irq: RMR, cannot allocate mbuf!\n");
			chan->in_cbptr = chan->in_mbuf->m_data;
			chan->in_len = 0;
		}

		chan->rxcount += IWIC_BCHAN_FIFO_LEN;
		
		if((chan->in_len + IWIC_BCHAN_FIFO_LEN) <= BCH_MAX_DATALEN)
		{
			/* read data from fifo */

			NDBGL1(L1_H_IRQ, "B_EXIR_RMR, rd fifo, len = max (64)");
			
			IWIC_RDBFIFO(sc, chan, chan->in_cbptr, IWIC_BCHAN_FIFO_LEN);

			chan->in_cbptr += IWIC_BCHAN_FIFO_LEN;
	                chan->in_len += IWIC_BCHAN_FIFO_LEN;
		}
		else
		{
			if(chan->bprot == BPROT_NONE)
			{
				/* setup mbuf data length */
				
				chan->in_mbuf->m_len = chan->in_len;
				chan->in_mbuf->m_pkthdr.len = chan->in_len;

				if(sc->sc_trace & TRACE_B_RX)
				{
					i4b_trace_hdr_t hdr;
					hdr.unit = L0IWICUNIT(sc->sc_unit);
					hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
					hdr.dir = FROM_NT;
					hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
					MICROTIME(hdr.time);
					i4b_l1_trace_ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data);
				}

				/* silence detection */
				
				if(!(i4b_l1_bchan_tel_silence(chan->in_mbuf->m_data, chan->in_mbuf->m_len)))
					activity = ACT_RX;

				if(!(IF_QFULL(&chan->rx_queue)))
				{
					IF_ENQUEUE(&chan->rx_queue, chan->in_mbuf);
				}
				else
				{
					i4b_Bfreembuf(chan->in_mbuf);
				}
				/* signal upper driver that data is available */

				(*chan->iwic_drvr_linktab->bch_rx_data_ready)(chan->iwic_drvr_linktab->unit);
				
				/* alloc new buffer */
				
				if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
					panic("L1 iwic_bchan_irq: RMR, cannot allocate new mbuf!\n");
	
				/* setup new data ptr */
				
				chan->in_cbptr = chan->in_mbuf->m_data;
	
				/* read data from fifo */
	
				NDBGL1(L1_H_IRQ, "B_EXIR_RMR, rd fifo1, len = max (64)");
				
				IWIC_RDBFIFO(sc, chan, chan->in_cbptr, IWIC_BCHAN_FIFO_LEN);

				chan->in_cbptr += IWIC_BCHAN_FIFO_LEN;
				chan->in_len = IWIC_BCHAN_FIFO_LEN;

				chan->rxcount += IWIC_BCHAN_FIFO_LEN;
			}
			else
			{
				NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RPF, in_len=%d", chan->in_len);
				chan->in_cbptr = chan->in_mbuf->m_data;
				chan->in_len = 0;
				cmd |= (B_CMDR_RRST | B_CMDR_RACK);
			}
		}
		
		/* command to release fifo space */
		
		cmd |= B_CMDR_RACK;
	}

/* TX interrupt */
	
	if (irq_stat & B_EXIR_XFR)
	{			
		/* transmit fifo empty, new data can be written to fifo */

		int activity = -1;
		int len;
		int nextlen;

		NDBGL1(L1_H_IRQ, "B_EXIR_XFR");
		
		if(chan->out_mbuf_cur == NULL) 	/* last frame is transmitted */
		{
			IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head);

			if(chan->out_mbuf_head == NULL)
			{
				chan->state &= ~ST_TX_ACTIVE;
				(*chan->iwic_drvr_linktab->bch_tx_queue_empty)(chan->iwic_drvr_linktab->unit);
			}
			else
			{
				chan->state |= ST_TX_ACTIVE;
				chan->out_mbuf_cur = chan->out_mbuf_head;
				chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
				chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;

				if(sc->sc_trace & TRACE_B_TX)
				{
					i4b_trace_hdr_t hdr;
					hdr.unit = L0IWICUNIT(sc->sc_unit);
					hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
					hdr.dir = FROM_TE;
					hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
					MICROTIME(hdr.time);
					i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
				}

				if(chan->bprot == BPROT_NONE)
				{
					if(!(i4b_l1_bchan_tel_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
						activity = ACT_TX;
				}
				else
				{
					activity = ACT_TX;
				}
			}
		}
			
		len = 0;

		while(chan->out_mbuf_cur && len != IWIC_BCHAN_FIFO_LEN)
		{
			nextlen = min(chan->out_mbuf_cur_len, IWIC_BCHAN_FIFO_LEN - len);

			NDBGL1(L1_H_IRQ, "B_EXIR_XFR, wr fifo, len = %d", nextlen);
			
			IWIC_WRBFIFO(sc, chan, chan->out_mbuf_cur_ptr, nextlen);

			cmd |= B_CMDR_XMS;
	
			len += nextlen;
			chan->txcount += nextlen;
	
			chan->out_mbuf_cur_ptr += nextlen;
			chan->out_mbuf_cur_len -= nextlen;
			
			if(chan->out_mbuf_cur_len == 0) 
			{
				if((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL)
				{
					chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
					chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;

					if(sc->sc_trace & TRACE_B_TX)
					{
						i4b_trace_hdr_t hdr;
						hdr.unit = L0IWICUNIT(sc->sc_unit);
						hdr.type = (chan_no == IWIC_BCH_A ? TRC_CH_B1 : TRC_CH_B2);
						hdr.dir = FROM_TE;
						hdr.count = ++sc->sc_bchan[chan_no].sc_trace_bcount;
						MICROTIME(hdr.time);
						i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
					}
				}
				else
				{
					if (chan->bprot != BPROT_NONE)
						cmd |= B_CMDR_XME;
					i4b_Bfreembuf(chan->out_mbuf_head);
					chan->out_mbuf_head = NULL;
				}
			}
		}
	}
	if(cmd)
	{
		cmd |= B_CMDR_RACT;
		IWIC_WRITE(sc, chan->offset + B_CMDR, cmd);
	}
}
Ejemplo n.º 4
0
/*---------------------------------------------------------------------------*
 *	PCI attach
 *---------------------------------------------------------------------------*/
static void
iwic_pci_attach(device_t  parent, device_t  dev, void *aux)
{
	struct iwic_softc *sc = device_private(dev);
	struct iwic_bchan *bchan;
	pci_intr_handle_t ih;
	const char *intrstr;
	struct pci_attach_args *pa = aux;
	pci_chipset_tag_t pc = pa->pa_pc;
	char intrbuf[PCI_INTRSTR_LEN];

	sc->sc_dev = dev;
	sc->sc_cardname = iwic_find_card(pa);

	if (!sc->sc_cardname)
		return;		/* Huh? */

	printf(": %s\n", sc->sc_cardname);

	if (pci_mapreg_map(pa, IWIC_PCI_IOBA, PCI_MAPREG_TYPE_IO, 0,
	    &sc->sc_io_bt, &sc->sc_io_bh, &sc->sc_iobase, &sc->sc_iosize)) {
		aprint_error_dev(sc->sc_dev, "unable to map registers\n");
		return;
	}
	if (pci_intr_map(pa, &ih)) {
		aprint_error_dev(sc->sc_dev, "couldn't map interrupt\n");
		return;
	}
	intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
	sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, iwic_pci_intr, sc);
	if (sc->sc_ih == NULL) {
		aprint_error_dev(sc->sc_dev, "couldn't establish interrupt");
		if (intrstr != NULL)
			aprint_error(" at %s", intrstr);
		aprint_error("\n");
		return;
	}
	sc->sc_pc = pc;
	aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);

	/* disable interrupts */
	IWIC_WRITE(sc, IWIC_IMASK, 0xff);
	IWIC_READ(sc, ISTA);

	iwic_dchan_init(sc);

	bchan = &sc->sc_bchan[IWIC_BCH_A];
	bchan->offset = B1_CHAN_OFFSET;
	bchan->channel = IWIC_BCH_A;
	bchan->state = ST_IDLE;

	iwic_bchannel_setup(sc, IWIC_BCH_A, BPROT_NONE, 0);

	bchan = &sc->sc_bchan[IWIC_BCH_B];
	bchan->offset = B2_CHAN_OFFSET;
	bchan->channel = IWIC_BCH_B;
	bchan->state = ST_IDLE;

	iwic_bchannel_setup(sc, IWIC_BCH_B, BPROT_NONE, 0);

	iwic_init_linktab(sc);

	iwic_attach_bri(sc);
}
Ejemplo n.º 5
0
/*---------------------------------------------------------------------------*
 *	PCI attach
 *---------------------------------------------------------------------------*/
static int
iwic_pci_attach(device_t dev)
{
	unsigned short iobase;
	struct iwic_softc *sc;
	void *ih = 0;
	int unit = device_get_unit(dev);
	struct iwic_bchan *bchan;
	
	/* check max unit range */
	
	if(unit >= IWIC_MAXUNIT)
	{
		printf("iwic%d: Error, unit %d >= IWIC_MAXUNIT!\n", unit, unit);
		return(ENXIO);	
	}	

	sc = iwic_find_sc(unit);	/* get softc */	
	
	sc->sc_unit = unit;

	/* use the i/o mapped base address */
	
	sc->sc_resources.io_rid[0] = BADDR1;
	
	if(!(sc->sc_resources.io_base[0] =
			bus_alloc_resource(dev, SYS_RES_IOPORT,
						&sc->sc_resources.io_rid[0],
						0UL, ~0UL, 1, RF_ACTIVE)))
	{
		printf("iwic%d: Couldn't alloc io port!\n", unit);
		return(ENXIO);                                       
	}

	iobase = rman_get_start(sc->sc_resources.io_base[0]);

	if(!(sc->sc_resources.irq =
			bus_alloc_resource(dev, SYS_RES_IRQ,
					   &sc->sc_resources.irq_rid,
					   0UL, ~0UL, 1, RF_SHAREABLE|RF_ACTIVE)))
	{
		printf("iwic%d: Couldn't alloc irq!\n",unit);
		return(ENXIO);                                       
	}
	
	/* setup card type */
	
	sc->sc_cardtyp = CARD_TYPEP_WINB6692;
	sc->sc_iobase = (u_int32_t) iobase;
	sc->sc_trace = TRACE_OFF;
	sc->sc_I430state = ST_F3N;	/* Deactivated */
	sc->enabled = FALSE;
	
	if(bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET,
				(void(*)(void*))iwic_pci_intr,
				sc, &ih))
	{
		printf("iwic%d: Couldn't set up irq!\n", unit);
		return(ENXIO);
	}

	/* disable interrupts */
	IWIC_WRITE(sc, IMASK, 0xff);

	iwic_dchan_init(sc);

	bchan = &sc->sc_bchan[IWIC_BCH_A];
	bchan->unit = unit;
	bchan->offset = B1_CHAN_OFFSET;
	bchan->channel = IWIC_BCH_A;
	bchan->state = ST_IDLE;
		
	iwic_bchannel_setup(unit, IWIC_BCH_A, BPROT_NONE, 0);

	bchan = &sc->sc_bchan[IWIC_BCH_B];
	bchan->unit = unit;
	bchan->offset = B2_CHAN_OFFSET;
	bchan->channel = IWIC_BCH_B;
	bchan->state = ST_IDLE;
	
	iwic_bchannel_setup(unit, IWIC_BCH_B, BPROT_NONE, 0);

	iwic_init_linktab(sc);
	
	if(bootverbose)
	{
		int ver = IWIC_READ(sc, D_RBCH);
		printf("iwic%d: W6692 chip version = %d\n", unit, D_RBCH_VN(ver));
	}

	i4b_l1_mph_status_ind(L0IWICUNIT(sc->sc_unit), STI_ATTACH, sc->sc_cardtyp, &iwic_l1mux_func);

	IWIC_READ(sc, ISTA);

	/* Enable interrupts */
	IWIC_WRITE(sc, IMASK, IMASK_XINT0 | IMASK_XINT1);

	return(0);
}