📄 wlc_pio.c
字号:
if (len) { W_REG(®s->fifocontrol, XFC_LO); W_REG(fifo, (uint16)*(uint8*)va16); }}/* 4-byte mode for corerev >= 8. poke a chain of fragment buffers into tx channel fifo */static int_wlc_pio4_tx(pio_info_t *pt, void *p0){ pio4regs_t *pioregs = pt->p4txregs; void *p; osl_t *osh; uint totlen; uchar *va; uint len; WL_TRACE(("wl%d: _wlc_pio4_tx\n", pt->pub->unit)); ASSERT(pioregs); osh = pt->pub->osh; totlen = pkttotlen(osh, p0); /* ASSERT(_wlc_pio_tx_available((pio_t *)pt, totlen, 1)); */ PIO_ADD_TX_CNT(pt, totlen); /* clear frameready */ W_REG(&pioregs->fifocontrol, XFC4_FR); for (p = p0; p; p = PKTNEXT(osh, p)) { va = PKTDATA(osh, p); len = PKTLEN(osh, p); /* skip any zero-byte buffers */ if (len == 0) continue; _wlc_pio4_xmtfifo(pt, pioregs, va, len); totlen -= len; } W_REG(&pioregs->fifocontrol, XFC4_EF); /* save frag in pio sw queue */ pktenq(&pt->txpioq, p0); return 0;}/* 4-byte mode for corerev >= 8. move tx data to fifo */static void_wlc_pio4_xmtfifo(pio_info_t *pt, pio4regs_t *regs, uchar *va, uint len){ uint i; uint32 *va32; volatile uint32 *fifo;#ifndef IL_BIGENDIAN uint byte_valid[] = {0, 1, 3, 7}; /* for first byte, first word, first three bytes */#else uint byte_valid[] = {0, 8, 12, 14}; /* for first byte, first word, first three bytes */#endif /* IL_BIGENDIAN */ if (len == 0) return; fifo = ®s->fifodata; /* write any leading bytes which not aligned to 32-bit boundary */ i = (uint)((uintptr)va & 3); if (i) { i = MIN(i, len); W_REG(®s->fifocontrol, byte_valid[i]); W_REG(fifo, *(uint32*)va); va += i; len -= i; } va32 = (uint32*)va; if (len >= 4) { { /* all 4 bytes are valid */ W_REG(®s->fifocontrol, 0xf); while (len >= 4) { W_REG(fifo, *va32); va32++; len -= 4; } } } if (len) { /* write any trailing bytes */ W_REG(®s->fifocontrol, byte_valid[len]); W_REG(fifo, *va32); }}/* shared rx process between pio2 and pio4 */static bool_wlc_pio_rxcheck(pio_info_t *pt, int len, void **p){ /* flush giant frames */ if (len > RXBUFSZ) { WL_ERROR(("wl%d: %s: giant frame. len %d\n", pt->pub->unit, __FUNCTION__, len)); WLCNTINCR(pt->pub->_cnt.rxgiant); return FALSE; } /* flush runt frames if not tx status frame */ if (len == 0 && pt->_fifo != RX_TXSTATUS_FIFO) { WL_ERROR(("wl%d: %s: runt frame\n", pt->pub->unit, __FUNCTION__)); WLCNTINCR(pt->pub->_cnt.rxrunt); return FALSE; } /* alloc a new buf-wlc_recvdata() fragment reassembly requires RXBUFSZ receive buffers */ if ((*p = PKTGET(pt->pub->osh, RXBUFSZ, FALSE)) == NULL) { WL_ERROR(("wl%d: %s: out of rxbufs\n", pt->pub->unit, __FUNCTION__)); WLCNTINCR(pt->pub->_cnt.rxnobuf); return FALSE; } return TRUE;}/* 2-byte mode for corerev < 8. move rx fifo data to buffer */static void*_wlc_pio2_rx(pio_info_t *pt){ void *p = NULL; osl_t *osh; uint8 *va; uint16 rxstatus; uint32 fifocontrol; d11rxhdr_t *rxh; int i, len, rxhdrlen = 0; pio2regs_t *regs; uint16 *va16; volatile uint16 *dptr, w; WL_TRACE(("wl%d: _wlc_pio2_rx\n", pt->pub->unit)); osh = pt->pub->osh; regs = pt->p2rxregs; ASSERT(regs); /* if frame is not ready, return */ if (!(R_REG(®s->fifocontrol) & RFC_FR)) return NULL; /* clear frame ready */ W_REG(®s->fifocontrol, RFC_FR); /* wait for data valid */ SPINWAIT((((fifocontrol = R_REG(®s->fifocontrol)) & RFC_DR) == 0), 100); if ((fifocontrol & RFC_DR) == 0) { WL_ERROR(("wl%d: %s: data ready never set\n", pt->pub->unit, __FUNCTION__)); return NULL; } dptr = ®s->fifodata; /* rcv data */ /* read the first 16bits of the rxhdr which gives the length */ w = R_REG(dptr); /* hanlde both Big and Little endian */ len = ltoh16(w); if (!_wlc_pio_rxcheck(pt, len, &p)) goto flush; va = (uint8 *)PKTDATA(osh, p); ASSERT(ISALIGNED((uintptr)va, sizeof(uint32))); PKTSETLEN(osh, p, (HWRXOFF + len)); /* get header length */ rxhdrlen = (pt->_fifo == RX_TXSTATUS_FIFO) ? TXSTATUS_LEN : RXHDR_LEN; /* read the rxheader from the fifo first */ va16 = (uint16 *)va; *va16++ = w; i = (rxhdrlen / 2) - 1; { while (i--) { *va16 = R_REG(dptr); va16++; } } /* toss bad packet before read/pass up whole frame */ rxh = (d11rxhdr_t*)va; rxstatus = ltoh16(rxh->RxStatus1); if (rxstatus & RXS_FCSERR) { /* ucode should toss it */ ASSERT(0); goto flush; } /* tx status frame only has header */ if (pt->_fifo == RX_TXSTATUS_FIFO) return (p); /* read the frame */ va16 = (uint16*) &va[HWRXOFF]; if (rxstatus & RXS_PBPRES) { /* advance data pointer by two-byte for address alignment */ va16++; PKTSETLEN(osh, p, (HWRXOFF + len + 2)); } { i = len / 2; while (i--) { *va16 = R_REG(dptr); va16++; } /* read last (odd) byte */ if (len & 1) { *va16 = R_REG(dptr) & 0xff; } } return (p);flush: /* flush rx frame */ W_REG(®s->fifocontrol, RFC_DR); if (p) PKTFREE(osh, p, FALSE); return (NULL);}/* 4-byte mode for corerev >= 8. move rx fifo data to buffer */static void*_wlc_pio4_rx(pio_info_t *pt){ void *p = NULL; osl_t *osh; uint8 *va; uint16 rxstatus; uint32 fifocontrol; d11rxhdr_t *rxh; int i, len, rxhdrlen = 0; pio4regs_t *regs; uint32 *va32; volatile uint32 *dptr, w; WL_TRACE(("wl%d: _wlc_pio4_rx\n", pt->pub->unit)); osh = pt->pub->osh; regs = pt->p4rxregs; ASSERT(regs); /* if frame is not ready, return */ if (!(R_REG(®s->fifocontrol) & RFC_FR)) return NULL; /* clear frame ready */ W_REG(®s->fifocontrol, RFC_FR); /* wait for data valid */ SPINWAIT((((fifocontrol = R_REG(®s->fifocontrol)) & RFC_DR) == 0), 100); if ((fifocontrol & RFC_DR) == 0) { WL_ERROR(("wl%d: %s: data ready never set\n", pt->pub->unit, __FUNCTION__)); return NULL; } dptr = ®s->fifodata; /* rcv data */ /* read the first 16bits of the rxhdr which gives the length */ w = R_REG(dptr); /* hanlde both Big and Little endian */ len = (uint16)ltoh32(w); if (!_wlc_pio_rxcheck(pt, len, &p)) goto flush; va = (uint8 *)PKTDATA(osh, p); ASSERT(ISALIGNED((uintptr)va, sizeof(uint32))); PKTSETLEN(osh, p, (HWRXOFF + len)); /* get header length */ rxhdrlen = (pt->_fifo == RX_TXSTATUS_FIFO) ? TXSTATUS_LEN : RXHDR_LEN; /* read the rxheader from the fifo first */ va32 = (uint32 *)va; *va32++ = w; i = (rxhdrlen / 4) - 1; { while (i--) { *va32 = R_REG(dptr); va32++; } } if (rxhdrlen % 4) { ASSERT((rxhdrlen % 4) == 2); *((uint16 *)va32) = R_REG((volatile uint16 *)dptr); va32 = (uint32 *)((int8*)va32 + 2); } /* toss bad packet before read/pass up whole frame */ rxh = (d11rxhdr_t*)va; rxstatus = ltoh16(rxh->RxStatus1); if (rxstatus & RXS_FCSERR) { /* ucode should toss it */ ASSERT(0); goto flush; } /* tx status frame only has header */ if (pt->_fifo == RX_TXSTATUS_FIFO) return (p); /* read the frame */ va32 = (uint32*) &va[HWRXOFF]; /* align buffer to 32-bit boundary */ if ((uintptr)va32 % 4 && len >= 2) { *((uint16 *)va32) = R_REG((volatile uint16 *)dptr); va32 = (uint32 *)((int8*)va32 + 2); len -= 2; } i = len / 4; { while (i--) { *va32 = R_REG(dptr); va32++; } } /* read the remain bytes if exist */ i = len % 4; if (i) { uint32 mask[] = {0, 0x000000ff, 0x0000ffff, 0x00ffffff}; *va32 = R_REG(dptr) & mask[i]; } return (p);flush: /* flush rx frame */ W_REG(®s->fifocontrol, RFC_DR); if (p) PKTFREE(osh, p, FALSE); return (NULL);}static void*_wlc_pio_getnexttxp(pio_info_t *pt){ return pktdeq(&pt->txpioq);}static int_wlc_pio_txreclaim(pio_info_t *pt){ void *p; while ((p = pktdeq(&pt->txpioq))) PKTFREE(pt->pub->osh, p, TRUE); /* reset per-fifo software counters */ pt->txfrmcnt = 0; pt->txdatacnt = 0; return 0;}static int_wlc_pio_txfifodepthset(pio_info_t *pt, uint len){ pt->txfifolimit = len; return 0;}static uint_wlc_pio_txfifodepthget(pio_info_t *pt){ return pt->txfifolimit;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -