/* Device console log buffer state */ #define CONSOLE_BUFFER_MAX 2024
struct rte_log_le {
__le32 buf; /* Can't be pointer on (64-bit) hosts */
__le32 buf_size;
__le32 idx; char *_buf_compat; /* Redundant pointer for backward compat. */
};
struct rte_console { /* Virtual UART * When there is no UART (e.g. Quickturn), * the host should write a complete * input line directly into cbuf and then write * the length into vcons_in. * This may also be used when there is a real UART * (at risk of conflicting with * the real UART). vcons_out is currently unused.
*/
uint vcons_in;
uint vcons_out;
/* Output (logging) buffer * Console output is written to a ring buffer log_buf at index log_idx. * The host may read the output when it sees log_idx advance. * Output will be lost if the output wraps around faster than the host * polls.
*/ struct rte_log_le log_le;
/* Console input line buffer * Characters are read one at a time into cbuf * until <CR> is received, then * the buffer is processed as a command line. * Also used for virtual UART.
*/
uint cbuf_idx; char cbuf[CBUF_LEN];
};
#define TXQLEN 2048 /* bulk tx queue length */ #define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */ #define TXLOW (TXHI - 256) /* turn off flow control below TXLOW */ #define PRIOMASK 7
#define TXRETRIES 2 /* # of retries for tx frames */
#define BRCMF_RXBOUND 50 /* Default for max rx frames in
one scheduling */
#define BRCMF_TXBOUND 20 /* Default for max tx frames in
one scheduling */
#define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */
#define MEMBLOCK 2048 /* Block size used for downloading
of dongle image */ #define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold
biggest possible glom */
#define BRCMF_FIRSTREAD (1 << 6)
/* SBSDIO_DEVICE_CTL */
/* 1: device will assert busy signal when receiving CMD53 */ #define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: assertion of sdio interrupt is synchronous to the sdio clock */ #define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: mask all interrupts to host except the chipActive (rev 8) */ #define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: isolate internal sdio signals, put external pads in tri-state; requires
* sdio bus power cycle to clear (rev 9) */ #define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: enable F2 Watermark */ #define SBSDIO_DEVCTL_F2WM_ENAB 0x10 /* Force SD->SB reset mapping (rev 11) */ #define SBSDIO_DEVCTL_SB_RST_CTL 0x30 /* Determined by CoreControl bit */ #define SBSDIO_DEVCTL_RST_CORECTL 0x00 /* Force backplane reset */ #define SBSDIO_DEVCTL_RST_BPRESET 0x10 /* Force no backplane reset */ #define SBSDIO_DEVCTL_RST_NOBPRESET 0x20
/* direct(mapped) cis space */
/* MAPPED common CIS address */ #define SBSDIO_CIS_BASE_COMMON 0x1000 /* maximum bytes in one CIS */ #define SBSDIO_CIS_SIZE_LIMIT 0x200 /* cis offset addr is < 17 bits */ #define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF
/* manfid tuple length, include tuple, link bytes */ #define SBSDIO_CIS_MANFID_TUPLE_LEN 6
/* Current protocol version */ #define SDPCM_PROT_VERSION 4
/* * Shared structure between dongle and the host. * The structure contains pointers to trap or assert information.
*/ #define SDPCM_SHARED_VERSION 0x0003 #define SDPCM_SHARED_VERSION_MASK 0x00FF #define SDPCM_SHARED_ASSERT_BUILT 0x0100 #define SDPCM_SHARED_ASSERT 0x0200 #define SDPCM_SHARED_TRAP 0x0400
/* Space for header read, limit for data packets */ #define MAX_HDR_READ (1 << 6) #define MAX_RX_DATASZ 2048
/* Bump up limit on waiting for HT to account for first startup; * if the image is doing a CRC calculation before programming the PMU * for HT availability, it could take a couple hundred ms more, so * max out at a 1 second (1000000us).
*/ #undef PMU_MAX_TRANSITION_DLY #define PMU_MAX_TRANSITION_DLY 1000000
/* Value for ChipClockCSR during initial setup */ #define BRCMF_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \
SBSDIO_ALP_AVAIL_REQ)
/* dongle SDIO bus specific header info */ struct brcmf_sdio_hdrinfo {
u8 seq_num;
u8 channel;
u16 len;
u16 len_left;
u16 len_nxtfrm;
u8 dat_offset; bool lastfrm;
u16 tail_pad;
};
/* * hold counter variables
*/ struct brcmf_sdio_count {
uint intrcount; /* Count of device interrupt callbacks */
uint lastintrs; /* Count as of last watchdog timer */
uint pollcnt; /* Count of active polls */
uint regfails; /* Count of R_REG failures */
uint tx_sderrs; /* Count of tx attempts with sd errors */
uint fcqueued; /* Tx packets that got queued */
uint rxrtx; /* Count of rtx requests (NAK to dongle) */
uint rx_toolong; /* Receive frames too long to receive */
uint rxc_errors; /* SDIO errors when reading control frames */
uint rx_hdrfail; /* SDIO errors on header reads */
uint rx_badhdr; /* Bad received headers (roosync?) */
uint rx_badseq; /* Mismatched rx sequence number */
uint fc_rcvd; /* Number of flow-control events received */
uint fc_xoff; /* Number which turned on flow-control */
uint fc_xon; /* Number which turned off flow-control */
uint rxglomfail; /* Failed deglom attempts */
uint rxglomframes; /* Number of glom frames (superframes) */
uint rxglompkts; /* Number of packets from glom frames */
uint f2rxhdrs; /* Number of header reads */
uint f2rxdata; /* Number of frame data reads */
uint f2txdata; /* Number of f2 frame writes */
uint f1regdata; /* Number of f1 register accesses */
uint tickcnt; /* Number of watchdog been schedule */
ulong tx_ctlerrs; /* Err of sending ctrl frames */
ulong tx_ctlpkts; /* Ctrl frames sent to dongle */
ulong rx_ctlerrs; /* Err of processing rx ctrl frames */
ulong rx_ctlpkts; /* Ctrl frames processed from dongle */
ulong rx_readahead_cnt; /* packets where header read-ahead was used */
};
/* misc chip info needed by some of the routines */ /* Private data for SDIO bus interaction */ struct brcmf_sdio { struct brcmf_sdio_dev *sdiodev; /* sdio device handler */ struct brcmf_chip *ci; /* Chip info struct */ struct brcmf_core *sdio_core; /* sdio core info struct */
u32 hostintmask; /* Copy of Host Interrupt Mask */
atomic_t intstatus; /* Intstatus bits (events) pending */
atomic_t fcstate; /* State of dongle flow-control */
uint blocksize; /* Block size of SDIO transfers */
uint roundup; /* Max roundup limit */
struct pktq txq; /* Queue length used for flow-control */
u8 flowcontrol; /* per prio flow control bitmask */
u8 tx_seq; /* Transmit sequence number (next) */
u8 tx_max; /* Maximum transmit sequence allowed */
u8 *hdrbuf; /* buffer for handling rx frame */
u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
u8 rx_seq; /* Receive sequence number (expected) */ struct brcmf_sdio_hdrinfo cur_read; /* info of current read frame */ bool rxskip; /* Skip receive (awaiting NAK ACK) */ bool rxpending; /* Data frame pending in dongle */
uint rxbound; /* Rx frames to read before resched */
uint txbound; /* Tx frames to send before resched */
uint txminmax;
struct sk_buff *glomd; /* Packet containing glomming descriptor */ struct sk_buff_head glom; /* Packet list for glommed superframe */
u8 *rxbuf; /* Buffer for receiving control packets */
uint rxblen; /* Allocated length of rxbuf */
u8 *rxctl; /* Aligned pointer into rxbuf */
u8 *rxctl_orig; /* pointer for freeing rxctl */
uint rxlen; /* Length of valid data in buffer */
spinlock_t rxctl_lock; /* protection lock for ctrl frame resources */
u8 sdpcm_ver; /* Bus protocol reported by dongle */
bool intr; /* Use interrupts */ bool poll; /* Use polling */
atomic_t ipend; /* Device interrupt is pending */
uint spurious; /* Count of spurious interrupts */
uint pollrate; /* Ticks between device polls */
uint polltick; /* Tick counter */
uint clkstate; /* State of sd and backplane clock(s) */
s32 idletime; /* Control for activity timeout */
s32 idlecount; /* Activity timeout counter */
s32 idleclock; /* How to set bus driver when idle */ bool rxflow_mode; /* Rx flow control mode */ bool rxflow; /* Is rx flow control on */ bool alp_only; /* Don't use HT clock (ALP only) */
u8 *ctrl_frame_buf;
u16 ctrl_frame_len; bool ctrl_frame_stat; int ctrl_frame_err;
/* SDIO Pad drive strength to select value mappings */ struct sdiod_drive_str {
u8 strength; /* Pad Drive Strength in mA */
u8 sel; /* Chip-specific select value */
};
/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */ staticconststruct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
{32, 0x6},
{26, 0x7},
{22, 0x4},
{16, 0x5},
{12, 0x2},
{8, 0x3},
{4, 0x0},
{0, 0x1}
};
/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ staticconststruct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = {
{6, 0x7},
{5, 0x6},
{4, 0x5},
{3, 0x4},
{2, 0x2},
{1, 0x1},
{0, 0x0}
};
/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ staticconststruct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
{3, 0x3},
{2, 0x2},
{1, 0x1},
{0, 0x0} };
/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */ staticconststruct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
{16, 0x7},
{12, 0x5},
{8, 0x3},
{4, 0x1}
};
staticint
brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
{
u8 wr_val = 0, rd_val, cmp_val, bmask; int err = 0; int err_cnt = 0; int try_cnt = 0;
brcmf_dbg(TRACE, "Enter: on=%d\n", on);
sdio_retune_crc_disable(bus->sdiodev->func1);
/* Cannot re-tune if device is asleep; defer till we're awake */ if (on)
sdio_retune_hold_now(bus->sdiodev->func1);
wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); /* 1st KSO write goes to AOS wake up core if device is asleep */
brcmf_sdiod_writeb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
/* In case of 43012 chip, the chip could go down immediately after * KSO bit is cleared. So the further reads of KSO register could * fail. Thereby just bailing out immediately after clearing KSO * bit, to avoid polling of KSO bit.
*/ if (!on && bus->ci->chip == CY_CC_43012_CHIP_ID) return err;
if (on) { /* device WAKEUP through KSO: * write bit 0 & read back until * both bits 0 (kso bit) & 1 (dev on status) are set
*/
cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK |
SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
bmask = cmp_val;
usleep_range(2000, 3000);
} else { /* Put device to sleep, turn off KSO */
cmp_val = 0; /* only check for bit0, bit1(dev on status) may not * get cleared right away
*/
bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
}
do { /* reliable KSO bit set/clr: * the sdiod sleep write access is synced to PMU 32khz clk * just one write attempt may fail, * read it back until it matches written value
*/
rd_val = brcmf_sdiod_readb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
&err); if (!err) { if ((rd_val & bmask) == cmp_val) break;
err_cnt = 0;
} /* bail out upon subsequent access errors */ if (err && (err_cnt++ > BRCMF_SDIO_MAX_ACCESS_ERRORS)) break;
/* Turn backplane clock on or off */ staticint brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
{ int err;
u8 clkctl, clkreq, devctl; unsignedlong timeout;
brcmf_dbg(SDIO, "Enter\n");
clkctl = 0;
if (bus->sr_enabled) {
bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY); return 0;
}
/* Early exit if we're already there */ if (bus->clkstate == target) return 0;
switch (target) { case CLK_AVAIL: /* Make sure SD clock is available */ if (bus->clkstate == CLK_NONE)
brcmf_sdio_sdclk(bus, true); /* Now request HT Avail on the backplane */
brcmf_sdio_htclk(bus, true, pendok); break;
case CLK_SDONLY: /* Remove HT request, or bring up SD clock */ if (bus->clkstate == CLK_NONE)
brcmf_sdio_sdclk(bus, true); elseif (bus->clkstate == CLK_AVAIL)
brcmf_sdio_htclk(bus, false, false); else
brcmf_err("request for %d -> %d\n",
bus->clkstate, target); break;
case CLK_NONE: /* Make sure to remove HT request */ if (bus->clkstate == CLK_AVAIL)
brcmf_sdio_htclk(bus, false, false); /* Now remove the SD clock */
brcmf_sdio_sdclk(bus, false); break;
} #ifdef DEBUG
brcmf_dbg(SDIO, "%d -> %d\n", oldstate, bus->clkstate); #endif/* DEBUG */
/* If SR is enabled control bus state with KSO */ if (bus->sr_enabled) { /* Done if we're already in the requested state */ if (sleep == bus->sleeping) goto end;
/* Going to sleep */ if (sleep) {
clkcsr = brcmf_sdiod_readb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR,
&err); if ((clkcsr & SBSDIO_CSR_MASK) == 0) {
brcmf_dbg(SDIO, "no clock, set ALP\n");
brcmf_sdiod_writeb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR,
SBSDIO_ALP_AVAIL_REQ, &err);
}
err = brcmf_sdio_kso_control(bus, false);
} else {
err = brcmf_sdio_kso_control(bus, true);
} if (err) {
brcmf_err("error while changing bus sleep state %d\n",
err); goto done;
}
}
end: /* control clocks */ if (sleep) { if (!bus->sr_enabled)
brcmf_sdio_clkctl(bus, CLK_NONE, pendok);
} else {
brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);
brcmf_sdio_wd_timer(bus, true);
}
bus->sleeping = sleep;
brcmf_dbg(SDIO, "new state %s\n",
(sleep ? "SLEEP" : "WAKE"));
done:
brcmf_dbg(SDIO, "Exit: err=%d\n", err); return err;
/* * Read last word in socram to determine * address of sdpcm_shared structure
*/
shaddr = bus->ci->rambase + bus->ci->ramsize - 4; if (!bus->ci->rambase && brcmf_chip_sr_capable(bus->ci))
shaddr -= bus->ci->srsize;
rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr,
(u8 *)&addr_le, 4); if (rv < 0) goto fail;
/* * Check if addr is valid. * NVRAM length at the end of memory should have been overwritten.
*/
addr = le32_to_cpu(addr_le); if (!brcmf_sdio_valid_shared_address(addr)) {
brcmf_err("invalid sdpcm_shared address 0x%08X\n", addr);
rv = -EINVAL; goto fail;
}
/* * DEVREADY does not occur with gSPI.
*/ if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
bus->sdpcm_ver =
(hmb_data & HMB_DATA_VERSION_MASK) >>
HMB_DATA_VERSION_SHIFT; if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
brcmf_err("Version mismatch, dongle reports %d, " "expecting %d\n",
bus->sdpcm_ver, SDPCM_PROT_VERSION); else
brcmf_dbg(SDIO, "Dongle ready, protocol version %d\n",
bus->sdpcm_ver);
/* * Retrieve console state address now that firmware should have * updated it.
*/
brcmf_sdio_get_console_addr(bus);
}
/* * Flow Control has been moved into the RX headers and this out of band * method isn't used any more. * remaining backward compatible with older dongles.
*/ if (hmb_data & HMB_DATA_FC) {
fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >>
HMB_DATA_FCDATA_SHIFT;
if (fcbits & ~bus->flowcontrol)
bus->sdcnt.fc_xoff++;
if (bus->flowcontrol & ~fcbits)
bus->sdcnt.fc_xon++;
/* Wait until the packet has been flushed (device/FIFO stable) */ for (lastrbc = retries = 0xffff; retries > 0; retries--) {
hi = brcmf_sdiod_readb(bus->sdiodev, SBSDIO_FUNC1_RFRAMEBCHI,
&err);
lo = brcmf_sdiod_readb(bus->sdiodev, SBSDIO_FUNC1_RFRAMEBCLO,
&err);
bus->sdcnt.f1regdata += 2;
if ((hi == 0) && (lo == 0)) break;
if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
brcmf_err("count growing: last 0x%04x now 0x%04x\n",
lastrbc, (hi << 8) + lo);
}
lastrbc = (hi << 8) + lo;
}
if (!retries)
brcmf_err("count never zeroed: last 0x%04x\n", lastrbc); else
brcmf_dbg(SDIO, "flush took %d iterations\n", 0xffff - retries);
if (rtx) {
bus->sdcnt.rxrtx++;
brcmf_sdiod_writel(sdiod, core->base + SD_REG(tosbmailbox),
SMB_NAK, &err);
bus->sdcnt.f1regdata++; if (err == 0)
bus->rxskip = true;
}
/* Clear partial in any case */
bus->cur_read.len = 0;
}
for (i = 0; i < 3; i++) {
hi = brcmf_sdiod_readb(sdiodev, SBSDIO_FUNC1_WFRAMEBCHI, NULL);
lo = brcmf_sdiod_readb(sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL);
bus->sdcnt.f1regdata += 2; if ((hi == 0) && (lo == 0)) break;
}
}
/* return total length of buffer chain */ static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus)
{ struct sk_buff *p;
uint total;
total = 0;
skb_queue_walk(&bus->glom, p)
total += p->len; return total;
}
/* If there's a descriptor, generate the packet chain */ if (bus->glomd) {
pfirst = pnext = NULL;
dlen = (u16) (bus->glomd->len);
dptr = bus->glomd->data; if (!dlen || (dlen & 1)) {
brcmf_err("bad glomd len(%d), ignore descriptor\n",
dlen);
dlen = 0;
}
for (totlen = num = 0; dlen; num++) { /* Get (and move past) next length */
sublen = get_unaligned_le16(dptr);
dlen -= sizeof(u16);
dptr += sizeof(u16); if ((sublen < SDPCM_HDRLEN) ||
((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
brcmf_err("descriptor len %d bad: %d\n",
num, sublen);
pnext = NULL; break;
} if (sublen % bus->sgentry_align) {
brcmf_err("sublen %d not multiple of %d\n",
sublen, bus->sgentry_align);
}
totlen += sublen;
/* For last frame, adjust read len so total
is a block multiple */ if (!dlen) {
sublen +=
(roundup(totlen, bus->blocksize) - totlen);
totlen = roundup(totlen, bus->blocksize);
}
/* Allocate/chain packet for next subframe */
pnext = brcmu_pkt_buf_get_skb(sublen + bus->sgentry_align); if (pnext == NULL) {
brcmf_err("bcm_pkt_buf_get_skb failed, num %d len %d\n",
num, sublen); break;
}
skb_queue_tail(&bus->glom, pnext);
/* Ok -- either we just generated a packet chain,
or had one from before */ if (!skb_queue_empty(&bus->glom)) { if (BRCMF_GLOM_ON()) {
brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
skb_queue_walk(&bus->glom, pnext) {
brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n",
pnext, (u8 *) (pnext->data),
pnext->len, pnext->len);
}
}
/* Do an SDIO read for the superframe. Configurable iovar to * read directly into the chained packet, or allocate a large * packet and copy into the chain.
*/
sdio_claim_host(bus->sdiodev->func1);
errcode = brcmf_sdiod_recv_chain(bus->sdiodev,
&bus->glom, dlen);
sdio_release_host(bus->sdiodev->func1);
bus->sdcnt.f2rxdata++;
/* On failure, kill the superframe */ if (errcode < 0) {
brcmf_err("glom read of %d bytes failed: %d\n",
dlen, errcode);
brcmf_dbg(SDIO, "Enter\n"); if (bus->rxblen)
buf = vzalloc(bus->rxblen); if (!buf) goto done;
rbuf = bus->rxbuf;
pad = ((unsignedlong)rbuf % bus->head_align); if (pad)
rbuf += (bus->head_align - pad);
/* Copy the already-read portion over */
memcpy(buf, hdr, BRCMF_FIRSTREAD); if (len <= BRCMF_FIRSTREAD) goto gotpkt;
/* Raise rdlen to next SDIO block to avoid tail command */
rdlen = len - BRCMF_FIRSTREAD; if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
pad = bus->blocksize - (rdlen % bus->blocksize); if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
((len + pad) < bus->sdiodev->bus_if->maxctl))
rdlen += pad;
} elseif (rdlen % bus->head_align) {
rdlen += bus->head_align - (rdlen % bus->head_align);
}
/* Drop if the read is too big or it exceeds our maximum */ if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
rdlen, bus->sdiodev->bus_if->maxctl);
brcmf_sdio_rxfail(bus, false, false); goto done;
}
/* Point to valid data and indicate its length */
spin_lock_bh(&bus->rxctl_lock); if (bus->rxctl) {
brcmf_err("last control frame is being processed.\n");
spin_unlock_bh(&bus->rxctl_lock);
vfree(buf); goto done;
}
bus->rxctl = buf + doff;
bus->rxctl_orig = buf;
bus->rxlen = len - doff;
spin_unlock_bh(&bus->rxctl_lock);
done: /* Awake any waiters */
brcmf_sdio_dcmd_resp_wake(bus);
}
/* prepare the descriptor for the next read */
rd->len = rd->len_nxtfrm << 4;
rd->len_nxtfrm = 0; /* treat all packet as event if we don't know */
rd->channel = SDPCM_EVENT_CHANNEL;
}
rxcount = maxframes - rxleft; /* Message if we hit the limit */ if (!rxleft)
brcmf_dbg(DATA, "hit rx limit of %d frames\n", maxframes); else
brcmf_dbg(DATA, "processed %d frames\n", rxcount); /* Back off rxseq if awaiting rtx, update rx_seq */ if (bus->rxskip)
rd->seq_num--;
bus->rx_seq = rd->seq_num;
/* * struct brcmf_skbuff_cb reserves first two bytes in sk_buff::cb for * bus layer usage.
*/ /* flag marking a dummy skb added for DMA alignment requirement */ #define ALIGN_SKB_FLAG 0x8000 /* bit mask of data length chopped from the previous packet */ #define ALIGN_SKB_CHOP_LEN_MASK 0x7fff
/** * brcmf_sdio_txpkt_prep - packet preparation for transmit * @bus: brcmf_sdio structure pointer * @pktq: packet list pointer * @chan: virtual channel to transmit the packet * * Processes to be applied to the packet * - Align data buffer pointer * - Align data buffer length * - Prepare header * Return: negative value if there is error
*/ staticint
brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
uint chan)
{
u16 head_pad, total_len; struct sk_buff *pkt_next;
u8 txseq; int ret; struct brcmf_sdio_hdrinfo hd_info = {0};
txseq = bus->tx_seq;
total_len = 0;
skb_queue_walk(pktq, pkt_next) { /* alignment packet inserted in previous * loop cycle can be skipped as it is * already properly aligned and does not * need an sdpcm header.
*/ if (*(u16 *)(pkt_next->cb) & ALIGN_SKB_FLAG) continue;
/* align packet data pointer */
ret = brcmf_sdio_txpkt_hdalign(bus, pkt_next); if (ret < 0) return ret;
head_pad = (u16)ret; if (head_pad)
memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad);
/* Now fill the header */
brcmf_sdio_hdpack(bus, pkt_next->data, &hd_info);
if (BRCMF_BYTES_ON() &&
((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
(BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)))
brcmf_dbg_hex_dump(true, pkt_next->data, hd_info.len, "Tx Frame:\n"); elseif (BRCMF_HDRS_ON())
brcmf_dbg_hex_dump(true, pkt_next->data,
head_pad + bus->tx_hdrlen, "Tx Header:\n");
} /* Hardware length tag of the first packet should be total * length of the chain (including padding)
*/ if (bus->txglom)
brcmf_sdio_update_hwhdr(__skb_peek(pktq)->data, total_len); return 0;
}
/** * brcmf_sdio_txpkt_postp - packet post processing for transmit
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.26 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.