int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func, uint regaddr, u8 *byte) { int err_ret; brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr); brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait); if (brcmf_pm_resume_error(sdiodev)) return -EIO; if (rw && func == 0) { /* handle F0 separately */ err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte); } else { sdio_claim_host(sdiodev->func[func]); if (rw) /* CMD52 Write */ sdio_writeb(sdiodev->func[func], *byte, regaddr, &err_ret); else if (func == 0) { *byte = sdio_f0_readb(sdiodev->func[func], regaddr, &err_ret); } else { *byte = sdio_readb(sdiodev->func[func], regaddr, &err_ret); } sdio_release_host(sdiodev->func[func]); } if (err_ret) brcmf_dbg(ERROR, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", rw ? "write" : "read", func, regaddr, *byte, err_ret); return err_ret; }
int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, uint rw, uint func, uint addr, u32 *word, uint nbytes) { int err_ret = -EIO; if (func == 0) { brcmf_dbg(ERROR, "Only CMD52 allowed to F0\n"); return -EINVAL; } brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", rw, func, addr, nbytes); brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); if (brcmf_pm_resume_error(sdiodev)) return -EIO; /* Claim host controller */ sdio_claim_host(sdiodev->func[func]); if (rw) { /* CMD52 Write */ if (nbytes == 4) sdio_writel(sdiodev->func[func], *word, addr, &err_ret); else if (nbytes == 2) sdio_writew(sdiodev->func[func], (*word & 0xFFFF), addr, &err_ret); else brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes); } else { /* CMD52 Read */ if (nbytes == 4) *word = sdio_readl(sdiodev->func[func], addr, &err_ret); else if (nbytes == 2) *word = sdio_readw(sdiodev->func[func], addr, &err_ret) & 0xFFFF; else brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes); } /* Release host controller */ sdio_release_host(sdiodev->func[func]); if (err_ret) brcmf_dbg(ERROR, "Failed to %s word, Err: 0x%08x\n", rw ? "write" : "read", err_ret); return err_ret; }
/* * This function takes a queue of packets. The packets on the queue * are assumed to be properly aligned by the caller. */ int brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc, uint write, uint func, uint addr, struct sk_buff_head *pktq) { bool fifo = (fix_inc == SDIOH_DATA_FIX); u32 SGCount = 0; int err_ret = 0; struct sk_buff *pkt; brcmf_dbg(TRACE, "Enter\n"); brcmf_pm_resume_wait(sdiodev, &sdiodev->request_chain_wait); if (brcmf_pm_resume_error(sdiodev)) return -EIO; /* Claim host controller */ sdio_claim_host(sdiodev->func[func]); skb_queue_walk(pktq, pkt) { uint pkt_len = pkt->len; pkt_len += 3; pkt_len &= 0xFFFFFFFC; err_ret = brcmf_sdioh_request_data(sdiodev, write, fifo, func, addr, pkt, pkt_len); if (err_ret) { brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n", write ? "TX" : "RX", pkt, SGCount, addr, pkt_len, err_ret); } else { brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n", write ? "TX" : "RX", pkt, SGCount, addr, pkt_len); } if (!fifo) addr += pkt_len; SGCount++; }
/* * This function takes a buffer or packet, and fixes everything up * so that in the end, a DMA-able packet is created. * * A buffer does not have an associated packet pointer, * and may or may not be aligned. * A packet may consist of a single packet, or a packet chain. * If it is a packet chain, then all the packets in the chain * must be properly aligned. * * If the packet data is not aligned, then there may only be * one packet, and in this case, it is copied to a new * aligned packet. * */ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, uint fix_inc, uint write, uint func, uint addr, uint reg_width, uint buflen_u, u8 *buffer, struct sk_buff *pkt) { int Status; struct sk_buff *mypkt = NULL; brcmf_dbg(TRACE, "Enter\n"); brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); if (brcmf_pm_resume_error(sdiodev)) return -EIO; /* Case 1: we don't have a packet. */ if (pkt == NULL) { brcmf_dbg(DATA, "Creating new %s Packet, len=%d\n", write ? "TX" : "RX", buflen_u); mypkt = brcmu_pkt_buf_get_skb(buflen_u); if (!mypkt) { brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", buflen_u); return -EIO; } /* For a write, copy the buffer data into the packet. */ if (write) memcpy(mypkt->data, buffer, buflen_u); Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, func, addr, mypkt); /* For a read, copy the packet data back to the buffer. */ if (!write) memcpy(buffer, mypkt->data, buflen_u); brcmu_pkt_buf_free_skb(mypkt); } else if (((ulong) (pkt->data) & DMA_ALIGN_MASK) != 0) { /* * Case 2: We have a packet, but it is unaligned. * In this case, we cannot have a chain (pkt->next == NULL) */ brcmf_dbg(DATA, "Creating aligned %s Packet, len=%d\n", write ? "TX" : "RX", pkt->len); mypkt = brcmu_pkt_buf_get_skb(pkt->len); if (!mypkt) { brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", pkt->len); return -EIO; } /* For a write, copy the buffer data into the packet. */ if (write) memcpy(mypkt->data, pkt->data, pkt->len); Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, func, addr, mypkt); /* For a read, copy the packet data back to the buffer. */ if (!write) memcpy(pkt->data, mypkt->data, mypkt->len); brcmu_pkt_buf_free_skb(mypkt); } else { /* case 3: We have a packet and it is aligned. */ brcmf_dbg(DATA, "Aligned %s Packet, direct DMA\n", write ? "Tx" : "Rx"); Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, func, addr, pkt); } return Status; }
static int brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc, uint write, uint func, uint addr, struct sk_buff *pkt) { bool fifo = (fix_inc == SDIOH_DATA_FIX); u32 SGCount = 0; int err_ret = 0; struct sk_buff *pnext; brcmf_dbg(TRACE, "Enter\n"); brcmf_pm_resume_wait(sdiodev, &sdiodev->request_packet_wait); if (brcmf_pm_resume_error(sdiodev)) return -EIO; /* Claim host controller */ sdio_claim_host(sdiodev->func[func]); for (pnext = pkt; pnext; pnext = pnext->next) { uint pkt_len = pnext->len; pkt_len += 3; pkt_len &= 0xFFFFFFFC; if ((write) && (!fifo)) { err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, ((u8 *) (pnext->data)), pkt_len); } else if (write) { err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, ((u8 *) (pnext->data)), pkt_len); } else if (fifo) { err_ret = sdio_readsb(sdiodev->func[func], ((u8 *) (pnext->data)), addr, pkt_len); } else { err_ret = sdio_memcpy_fromio(sdiodev->func[func], ((u8 *) (pnext->data)), addr, pkt_len); } if (err_ret) { brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n", write ? "TX" : "RX", pnext, SGCount, addr, pkt_len, err_ret); } else { brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n", write ? "TX" : "RX", pnext, SGCount, addr, pkt_len); } if (!fifo) addr += pkt_len; SGCount++; } /* Release host controller */ sdio_release_host(sdiodev->func[func]); brcmf_dbg(TRACE, "Exit\n"); return err_ret; }