📄 wlc_pio.c
字号:
/* * HND PIO module * Broadcom 802.11abg Networking Device Driver * * Copyright 2005-2006, Broadcom Corporation * All Rights Reserved. * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. * * $Id$ */#ifndef WLPIO#error "WLPIO is not defined"#endif /* WLPIO */#include <wlc_cfg.h>#include <typedefs.h>#include <bcmdefs.h>#include <osl.h>#include <sbutils.h>#include <bcmendian.h>#include <bcmutils.h>#include <wlioctl.h>#include <sbhndpio.h>#include <sbhnddma.h>#include <hnddma.h>#include <d11.h>#include <wlc_rate.h>#include <wlc_key.h>#include <wlc_channel.h>#include <wlc_pub.h>#include <wlc_bsscfg.h>#include <wlc_pio.h>#include <wlc.h>/* private pio structure */typedef struct pio_info_s { pio_t piopub; /* public structure of pio module */ wlc_info_t *wlc; /* common code handler */ wlc_pub_t *pub; /* public common code handler */ uint _fifo; /* fifo number */ bool pio4; /* PIO 4 bytes or 2 bytes */ pio2regs_t *p2txregs; /* pio2 trx regs */ pio2regs_t *p2rxregs; /* pio2 rx regs */ pio4regs_t *p4txregs; /* pio4 tx regs */ pio4regs_t *p4rxregs; /* pio4 rx regs */ /* pio */ struct pktq txpioq; /* tx sw queue, wait txstatus to reclaim */ uint txfrmcnt; /* tx frame count */ uint txdatacnt; /* tx data count */ uint txfifolimit; /* tx fifo depth */} pio_info_t;#define PIO_INFO(pio) (pio_info_t *)pio/* local prototype *//* pio common routines for both pio2 and pio4 */static int _wlc_pio_com_detach(pio_info_t *pt);static int _wlc_pio_com_init(pio_info_t *pt);static int _wlc_pio_com_reset(pio_info_t *pt);static int _wlc_pio_com_txsuspend(pio_info_t *pt);static bool _wlc_pio_com_txsuspended(pio_info_t *pt);static int _wlc_pio_com_txresume(pio_info_t *pt);static bool _wlc_pio_com_txavailable(pio_info_t *pt, uint len, uint nfrags);static bool _wlc_pio_com_rxfrmrdy(pio_info_t *pt);static int _wlc_pio_com_cntupd(pio_info_t *pt, uint len);static char* _wlc_pio_com_dump(pio_info_t *pt, char *buf);static void* _wlc_pio_getnexttxp(pio_info_t *pt);static int _wlc_pio_txreclaim(pio_info_t *pt);static int _wlc_pio_txfifodepthset(pio_info_t *pt, uint len);static uint _wlc_pio_txfifodepthget(pio_info_t *pt);/* pio routines for 2 bytes pio */static int _wlc_pio2_tx(pio_info_t *pt, void *p0);static void _wlc_pio2_xmtfifo(pio_info_t *pioh, pio2regs_t *regs, uchar *va, uint len);static void *_wlc_pio2_rx(pio_info_t *pt);/* pio routines for 4 bytes pio */static int _wlc_pio4_tx(pio_info_t *pt, void *p0);static void _wlc_pio4_xmtfifo(pio_info_t *pt, pio4regs_t *regs, uchar *va, uint len);static void *_wlc_pio4_rx(pio_info_t *pt);static bool _wlc_pio_rxcheck(pio_info_t *pt, int len, void **p);/* len is rounded up since free fifo length in ucode counts in multiples of 4 */#define PIO_ADD_TX_CNT(pt, len) { \ pt->txfrmcnt++; \ ASSERT(pt->txfrmcnt <= D11_MAX_TX_FRMS); \ pt->txdatacnt += ROUNDUP(len, 4); \ ASSERT(pt->txdatacnt <= pt->txfifolimit); \ }#define PIO_SUB_TX_CNT(pt, len) { \ ASSERT(pt->txfrmcnt); \ pt->txfrmcnt--; \ ASSERT(pt->txdatacnt >= ROUNDUP(len, 4)); \ pt->txdatacnt -= ROUNDUP(len, 4); \ }pio_t*wlc_pio_attach(wlc_pub_t *pub, wlc_info_t *cwlc, uint fifo, void *pioregstx, void *pioregsrx){ pio_info_t *pt; piof_t pio_fns; if ((pt = (pio_info_t *)MALLOC(pub->osh, sizeof(pio_info_t))) == NULL) { WL_ERROR(("wlc_pio_attach: out of memory, malloced %d bytes", MALLOCED(pub->osh))); return NULL; } bzero((char *)pt, sizeof(pio_info_t)); pt->wlc = cwlc; pt->pub = pub; pt->_fifo = fifo; /* * register pio functions * To add a new one, add the type and array element in wlc_pio.h, * add handler here and in wlc_pio_register_fn */ pio_fns.detach = (pio_detach_t)_wlc_pio_com_detach; pio_fns.reset = (pio_reset_t)_wlc_pio_com_reset; pio_fns.init = (pio_init_t)_wlc_pio_com_init; pio_fns.txsuspend = (pio_txsuspend_t)_wlc_pio_com_txsuspend; pio_fns.txsuspended = (pio_txsuspended_t)_wlc_pio_com_txsuspended; pio_fns.txresume = (pio_txresume_t)_wlc_pio_com_txresume; pio_fns.txavailable = (pio_txavailable_t)_wlc_pio_com_txavailable; pio_fns.rxfrmrdy = (pio_rxfrmrdy_t)_wlc_pio_com_rxfrmrdy; if (WLC_UPDATE_STATS(wlc)) { pio_fns.dump = (pio_dump_t)_wlc_pio_com_dump; } else { pio_fns.dump = NULL; } pio_fns.cntupd = (pio_cntupd_t)_wlc_pio_com_cntupd; pio_fns.nexttxp = (pio_getnexttxp_t)_wlc_pio_getnexttxp; pio_fns.txreclaim = (pio_txreclaim_t)_wlc_pio_txreclaim; pio_fns.txdepthget = (pio_txfifodepthget_t)_wlc_pio_txfifodepthget; pio_fns.txdepthset = (pio_txfifodepthset_t)_wlc_pio_txfifodepthset; /* init pio reg pointer */ if (D11REV_LT(pt->pub->corerev, 8)) { pt->p2txregs = (pio2regs_t *)pioregstx; pt->p2rxregs = (pio2regs_t *)pioregsrx; pio_fns.rx = (pio_rx_t)_wlc_pio2_rx; pio_fns.tx = (pio_tx_t)_wlc_pio2_tx; pt->pio4 = 0; } else { pt->p4txregs = (pio4regs_t *)pioregstx; pt->p4rxregs = (pio4regs_t *)pioregsrx; pio_fns.rx = (pio_rx_t)_wlc_pio4_rx; pio_fns.tx = (pio_tx_t)_wlc_pio4_tx; pt->pio4 = 1; } wlc_pio_register_fn((pio_t *)pt, &pio_fns); pktq_init(&pt->txpioq, 1, PKTQ_LEN_DEFAULT); ASSERT(pktq_avail(&pt->txpioq) >= D11_MAX_TX_FRMS); return (pio_t*)pt;}/* register pio mode function pointers */voidwlc_pio_register_fn(pio_t *pioh, piof_t *fn){ pioh->pio_fn.detach = fn->detach; pioh->pio_fn.reset = fn->reset; pioh->pio_fn.init = fn->init; pioh->pio_fn.txsuspend = fn->txsuspend; pioh->pio_fn.txsuspended = fn->txsuspended; pioh->pio_fn.txresume = fn->txresume; pioh->pio_fn.rxfrmrdy = fn->rxfrmrdy; pioh->pio_fn.txavailable = fn->txavailable; pioh->pio_fn.dump = fn->dump; pioh->pio_fn.cntupd = fn->cntupd; pioh->pio_fn.nexttxp = fn->nexttxp; pioh->pio_fn.txreclaim = fn->txreclaim; pioh->pio_fn.txdepthget = fn->txdepthget; pioh->pio_fn.txdepthset = fn->txdepthset; pioh->pio_fn.tx = fn->tx; pioh->pio_fn.rx = fn->rx;}static int_wlc_pio_com_detach(pio_info_t *pt){ /* assert pkts are freed */ ASSERT(pktq_empty(&pt->txpioq)); if (pt) MFREE(pt->pub->osh, pt, sizeof(pio_info_t)); return 0;}/* pio initialization */static int_wlc_pio_com_init(pio_info_t *pt){ return 0;}static int_wlc_pio_com_reset(pio_info_t *pt){ return 0;}static int_wlc_pio_com_txsuspend(pio_info_t *pt){ if (pt->pio4) { OR_REG(&pt->p4txregs->fifocontrol, XFC4_SE); } else { OR_REG(&pt->p2txregs->fifocontrol, XFC_SE); } return 0;}static bool_wlc_pio_com_txsuspended(pio_info_t *pt){ if (pt->pio4) { if ((R_REG(&pt->p4txregs->fifocontrol) & (XFC4_SE | XFC4_SP)) == XFC4_SE) return TRUE; } else { if ((R_REG(&pt->p2txregs->fifocontrol) & (XFC_SE | XFC_SP)) == XFC_SE) return TRUE; } return FALSE;}static int_wlc_pio_com_txresume(pio_info_t *pt){ if (pt->pio4) { AND_REG(&pt->p4txregs->fifocontrol, ~XFC4_SE); } else { AND_REG(&pt->p2txregs->fifocontrol, ~XFC_SE); } return 0;}static bool_wlc_pio_com_rxfrmrdy(pio_info_t *pt){ if (pt->pio4) return (R_REG(&pt->p4rxregs->fifocontrol) & RFC_FR); else return (R_REG(&pt->p2rxregs->fifocontrol) & RFC_FR);}static bool_wlc_pio_com_txavailable(pio_info_t *pt, uint len, uint nfrags){ if (((pt->txfrmcnt + nfrags) <= D11_MAX_TX_FRMS) && ((pt->txdatacnt + ((nfrags == 1) ? (ROUNDUP(len, 4)) : (len + 3*nfrags))) <= pt->txfifolimit)) { if (pt->pio4) return (!(R_REG(&pt->p4txregs->fifocontrol) & XFC4_SE)); else return (!(R_REG(&pt->p2txregs->fifocontrol) & XFC_SE)); } return FALSE;}static int_wlc_pio_com_cntupd(pio_info_t *pt, uint len){ PIO_SUB_TX_CNT(pt, len); return 0;}/* need fifo to avoid touch some rx fifo, which doesn't exist */static char*_wlc_pio_com_dump(pio_info_t *pt, char *buf){ /* common software part */ buf += sprintf(buf, "pio%d: qlen %d txfrmcnt %d txdatacnt %d txfifodepth %d\n", pt->_fifo, pktq_len(&pt->txpioq), pt->txfrmcnt, pt->txdatacnt, pt->txfifolimit); if (pt->pio4) { buf += sprintf(buf, "xmtcontrol 0x%x\n", R_REG(&pt->p4txregs->fifocontrol)); if (pt->_fifo == RX_FIFO) { buf += sprintf(buf, "rcvcontrol 0x%x\n", R_REG(&pt->p4rxregs->fifocontrol)); } } else { buf += sprintf(buf, "xmtcontrol 0x%x\n", R_REG(&pt->p2txregs->fifocontrol)); if (pt->_fifo == RX_FIFO) { buf += sprintf(buf, "rcvcontrol 0x%x\n", R_REG(&pt->p2rxregs->fifocontrol)); } } return (buf);}/* 2-byte mode for corerev < 8. poke a chain of fragment buffers into tx channel fifo */static int_wlc_pio2_tx(pio_info_t *pt, void *p0){ pio2regs_t *pioregs = pt->p2txregs; void *p; osl_t *osh; uint totlen; uchar *va; uint len; WL_TRACE(("wl%d: _wlc_pio2_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, XFC_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_pio2_xmtfifo(pt, pioregs, va, len); totlen -= len; } W_REG(&pioregs->fifocontrol, XFC_EF); /* save frag in pio sw queue */ pktenq(&pt->txpioq, p0); return 0;}/* 2-byte mode for corerev < 8. move tx data to fifo */static void_wlc_pio2_xmtfifo(pio_info_t *pt, pio2regs_t *regs, uchar *va, uint len){ uint16 *va16; volatile uint16 *fifo; if (len == 0) return; fifo = ®s->fifodata; /* write any odd leading byte */ if ((uintptr)va & 1) { W_REG(®s->fifocontrol, XFC_LO); W_REG(fifo, (uint16)*va); va++; len--; } va16 = (uint16*)va; if (len >= 2) { W_REG(®s->fifocontrol, XFC_BOTH); { while (len >= 2) { W_REG(fifo, *va16); va16++; len -= 2; } } } /* write any odd trailing byte */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -