static void brcmf_usb_rx_complete(struct urb *urb) { struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context; struct brcmf_usbdev_info *devinfo = req->devinfo; struct sk_buff *skb; brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status); brcmf_usb_del_fromq(devinfo, req); skb = req->skb; req->skb = NULL; /* zero lenght packets indicate usb "failure". Do not refill */ if (urb->status != 0 || !urb->actual_length) { brcmu_pkt_buf_free_skb(skb); brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); return; } if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { skb_put(skb, urb->actual_length); brcmf_rx_frame(devinfo->dev, skb); brcmf_usb_rx_refill(devinfo, req); } else { brcmu_pkt_buf_free_skb(skb); brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); } return; }
static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb) { struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); struct brcmf_usbreq *req; int ret; if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) { /* TODO: handle suspend/resume */ return -EIO; } req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq); if (!req) { brcmu_pkt_buf_free_skb(skb); brcmf_dbg(ERROR, "no req to send\n"); return -ENOMEM; } req->skb = skb; req->devinfo = devinfo; usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe, skb->data, skb->len, brcmf_usb_tx_complete, req); req->urb->transfer_flags |= URB_ZERO_PACKET; brcmf_usb_enq(devinfo, &devinfo->tx_postq, req); ret = usb_submit_urb(req->urb, GFP_ATOMIC); if (ret) { brcmf_dbg(ERROR, "brcmf_usb_tx usb_submit_urb FAILED\n"); brcmf_usb_del_fromq(devinfo, req); brcmu_pkt_buf_free_skb(req->skb); req->skb = NULL; brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req); } return ret; }
void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) { struct sk_buff *skb, *pnext; struct brcmf_if *ifp; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; u8 ifidx; int ret; brcmf_dbg(DATA, "Enter\n"); skb_queue_walk_safe(skb_list, skb, pnext) { skb_unlink(skb, skb_list); /* process and remove protocol-specific header */ ret = brcmf_proto_hdrpull(drvr, drvr->fw_signals, &ifidx, skb); ifp = drvr->iflist[ifidx]; if (ret || !ifp || !ifp->ndev) { if ((ret != -ENODATA) && ifp) ifp->stats.rx_errors++; brcmu_pkt_buf_free_skb(skb); continue; } skb->dev = ifp->ndev; skb->protocol = eth_type_trans(skb, skb->dev); if (skb->pkt_type == PACKET_MULTICAST) ifp->stats.multicast++; /* Process special event packets */ brcmf_fweh_process_skb(drvr, skb); if (!(ifp->ndev->flags & IFF_UP)) { brcmu_pkt_buf_free_skb(skb); continue; } ifp->stats.rx_bytes += skb->len; ifp->stats.rx_packets++; if (in_interrupt()) netif_rx(skb); else /* If the receive is not processed inside an ISR, * the softirqd must be woken explicitly to service the * NET_RX_SOFTIRQ. This is handled by netif_rx_ni(). */ netif_rx_ni(skb); }
static int brcmf_msgbuf_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, uint len) { struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; struct sk_buff *skb = NULL; int timeout; int err; brcmf_dbg(MSGBUF, "ifidx=%d, cmd=%d, len=%d\n", ifidx, cmd, len); msgbuf->ctl_completed = false; err = brcmf_msgbuf_tx_ioctl(drvr, ifidx, cmd, buf, len); if (err) return err; timeout = brcmf_msgbuf_ioctl_resp_wait(msgbuf); if (!timeout) { brcmf_err("Timeout on response for query command\n"); return -EIO; } skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, msgbuf->rx_pktids, msgbuf->ioctl_resp_pktid); if (msgbuf->ioctl_resp_ret_len != 0) { if (!skb) return -EBADF; memcpy(buf, skb->data, (len < msgbuf->ioctl_resp_ret_len) ? len : msgbuf->ioctl_resp_ret_len); } brcmu_pkt_buf_free_skb(skb); return msgbuf->ioctl_resp_status; }
void brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, void *arg) { struct pktq_prec *q; struct sk_buff *p, *prev = NULL; q = &pq->q[prec]; p = q->head; while (p) { if (fn == NULL || (*fn) (p, arg)) { bool head = (p == q->head); if (head) q->head = p->prev; else prev->prev = p->prev; p->prev = NULL; brcmu_pkt_buf_free_skb(p); q->len--; pq->len--; p = (head ? q->head : prev->prev); } else { prev = p; p = p->prev; } } if (q->head == NULL) { q->tail = NULL; } }
static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo, struct brcmf_usbreq *req) { struct sk_buff *skb; int ret; if (!req || !devinfo) return; skb = dev_alloc_skb(devinfo->bus_pub.bus_mtu); if (!skb) { brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); return; } req->skb = skb; usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->rx_pipe, skb->data, skb_tailroom(skb), brcmf_usb_rx_complete, req); req->devinfo = devinfo; brcmf_usb_enq(devinfo, &devinfo->rx_postq, req, NULL); ret = usb_submit_urb(req->urb, GFP_ATOMIC); if (ret) { brcmf_usb_del_fromq(devinfo, req); brcmu_pkt_buf_free_skb(req->skb); req->skb = NULL; brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); } return; }
static void brcmf_usb_rx_complete(struct urb *urb) { struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context; struct brcmf_usbdev_info *devinfo = req->devinfo; struct sk_buff *skb; int ifidx = 0; brcmf_usb_del_fromq(devinfo, req); skb = req->skb; req->skb = NULL; if (urb->status == 0) { devinfo->bus_pub.bus->dstats.rx_packets++; } else { devinfo->bus_pub.bus->dstats.rx_errors++; brcmu_pkt_buf_free_skb(skb); brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); return; } if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) { skb_put(skb, urb->actual_length); if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) { brcmf_dbg(ERROR, "rx protocol error\n"); brcmu_pkt_buf_free_skb(skb); brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); devinfo->bus_pub.bus->dstats.rx_errors++; } else { brcmf_rx_packet(devinfo->dev, ifidx, skb); brcmf_usb_rx_refill(devinfo, req); } } else { brcmu_pkt_buf_free_skb(skb); brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req); } return; }
void brcmf_rx_event(struct device *dev, struct sk_buff *skb) { struct brcmf_if *ifp; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb); if (brcmf_rx_hdrpull(drvr, skb, &ifp)) return; brcmf_fweh_process_skb(ifp->drvr, skb); brcmu_pkt_buf_free_skb(skb); }
bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, int prec) { struct sk_buff *p; int eprec = -1; /* precedence to evict from */ bool discard_oldest; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; /* Fast case, precedence queue is not full and we are also not * exceeding total queue length */ if (!pktq_pfull(q, prec) && !pktq_full(q)) { brcmu_pktq_penq(q, prec, pkt); return true; } /* Determine precedence from which to evict packet, if any */ if (pktq_pfull(q, prec)) eprec = prec; else if (pktq_full(q)) { p = brcmu_pktq_peek_tail(q, &eprec); if (eprec > prec) return false; } /* Evict if needed */ if (eprec >= 0) { /* Detect queueing to unconfigured precedence */ discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec); if (eprec == prec && !discard_oldest) return false; /* refuse newer (incoming) packet */ /* Evict packet according to discard policy */ p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : brcmu_pktq_pdeq_tail(q, eprec); if (p == NULL) brcmf_err("brcmu_pktq_penq() failed, oldest %d\n", discard_oldest); brcmu_pkt_buf_free_skb(p); } /* Enqueue */ p = brcmu_pktq_penq(q, prec, pkt); if (p == NULL) brcmf_err("brcmu_pktq_penq() failed\n"); return p != NULL; }
bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, struct sk_buff *pkt, int prec) { struct sk_buff *p; int eprec = -1; /* precedence to evict from */ bool discard_oldest; /* Fast case, precedence queue is not full and we are also not * exceeding total queue length */ if (!pktq_pfull(q, prec) && !pktq_full(q)) { brcmu_pktq_penq(q, prec, pkt); return true; } /* Determine precedence from which to evict packet, if any */ if (pktq_pfull(q, prec)) eprec = prec; else if (pktq_full(q)) { p = brcmu_pktq_peek_tail(q, &eprec); if (eprec > prec) return false; } /* Evict if needed */ if (eprec >= 0) { /* Detect queueing to unconfigured precedence */ discard_oldest = AC_BITMAP_TST(drvr->wme_dp, eprec); if (eprec == prec && !discard_oldest) return false; /* refuse newer (incoming) packet */ /* Evict packet according to discard policy */ p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : brcmu_pktq_pdeq_tail(q, eprec); if (p == NULL) { BRCMF_ERROR(("%s: brcmu_pktq_penq() failed, oldest %d.", __func__, discard_oldest)); } brcmu_pkt_buf_free_skb(p); } /* Enqueue */ p = brcmu_pktq_penq(q, prec, pkt); if (p == NULL) { BRCMF_ERROR(("%s: brcmu_pktq_penq() failed.", __func__)); } return p != NULL; }
static void brcmf_usb_tx_complete(struct urb *urb) { struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context; struct brcmf_usbdev_info *devinfo = req->devinfo; brcmf_usb_del_fromq(devinfo, req); if (urb->status == 0) devinfo->bus_pub.bus->dstats.tx_packets++; else devinfo->bus_pub.bus->dstats.tx_errors++; brcmu_pkt_buf_free_skb(req->skb); req->skb = NULL; brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req); }
void brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir, bool (*fn)(struct sk_buff *, void *), void *arg) { struct sk_buff_head *q; struct sk_buff *p, *next; q = &pq->q[prec].skblist; skb_queue_walk_safe(q, p, next) { if (fn == NULL || (*fn) (p, arg)) { skb_unlink(p, q); brcmu_pkt_buf_free_skb(p); pq->len--; } } }
bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, int prec) { struct sk_buff *p; int eprec = -1; bool discard_oldest; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; if (!pktq_pfull(q, prec) && !pktq_full(q)) { brcmu_pktq_penq(q, prec, pkt); return true; } if (pktq_pfull(q, prec)) eprec = prec; else if (pktq_full(q)) { p = brcmu_pktq_peek_tail(q, &eprec); if (eprec > prec) return false; } if (eprec >= 0) { discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec); if (eprec == prec && !discard_oldest) return false; p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : brcmu_pktq_pdeq_tail(q, eprec); if (p == NULL) brcmf_dbg(ERROR, "brcmu_pktq_penq() failed, oldest %d\n", discard_oldest); brcmu_pkt_buf_free_skb(p); } p = brcmu_pktq_penq(q, prec, pkt); if (p == NULL) brcmf_dbg(ERROR, "brcmu_pktq_penq() failed\n"); return p != NULL; }
void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_if *ifp; /* await txstatus signal for firmware if active */ if (brcmf_fws_fc_active(drvr->fws)) { if (!success) brcmf_fws_bustxfail(drvr->fws, txp); } else { if (brcmf_proto_hdrpull(drvr, false, txp, &ifp)) brcmu_pkt_buf_free_skb(txp); else brcmf_txfinalize(ifp, txp, success); } }
static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb, struct brcmf_if **ifp) { int ret; /* process and remove protocol-specific header */ ret = brcmf_proto_hdrpull(drvr, true, skb, ifp); if (ret || !(*ifp) || !(*ifp)->ndev) { if (ret != -ENODATA && *ifp) (*ifp)->stats.rx_errors++; brcmu_pkt_buf_free_skb(skb); return -ENODATA; } skb->protocol = eth_type_trans(skb, (*ifp)->ndev); return 0; }
void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success) { struct ethhdr *eh; u16 type; eh = (struct ethhdr *)(txp->data); type = ntohs(eh->h_proto); if (type == ETH_P_PAE) { atomic_dec(&ifp->pend_8021x_cnt); if (waitqueue_active(&ifp->pend_8021x_wait)) wake_up(&ifp->pend_8021x_wait); } if (!success) ifp->stats.tx_errors++; brcmu_pkt_buf_free_skb(txp); }
void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid) { struct brcmf_flowring_ring *ring; u8 hash_idx; struct sk_buff *skb; ring = flow->rings[flowid]; if (!ring) return; brcmf_flowring_block(flow, flowid, false); hash_idx = ring->hash_id; flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX; memset(flow->hash[hash_idx].mac, 0, ETH_ALEN); flow->rings[flowid] = NULL; skb = skb_dequeue(&ring->skblist); while (skb) { brcmu_pkt_buf_free_skb(skb); skb = skb_dequeue(&ring->skblist); } kfree(ring); }
void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) { if (skb->pkt_type == PACKET_MULTICAST) ifp->stats.multicast++; if (!(ifp->ndev->flags & IFF_UP)) { brcmu_pkt_buf_free_skb(skb); return; } ifp->stats.rx_bytes += skb->len; ifp->stats.rx_packets++; brcmf_dbg(DATA, "rx proto=0x%X\n", ntohs(skb->protocol)); if (in_interrupt()) netif_rx(skb); else /* If the receive is not processed inside an ISR, * the softirqd must be woken explicitly to service * the NET_RX_SOFTIRQ. This is handled by netif_rx_ni(). */ netif_rx_ni(skb); }
static void brcmf_msgbuf_release_array(struct device *dev, struct brcmf_msgbuf_pktids *pktids) { struct brcmf_msgbuf_pktid *array; struct brcmf_msgbuf_pktid *pktid; u32 count; array = pktids->array; count = 0; do { if (array[count].allocated.counter) { pktid = &array[count]; dma_unmap_single(dev, pktid->physaddr, pktid->skb->len - pktid->data_offset, pktids->direction); brcmu_pkt_buf_free_skb(pktid->skb); } count++; } while (count < pktids->array_size); kfree(array); kfree(pktids); }
void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) { unsigned char *eth; uint len; struct sk_buff *skb, *pnext; struct brcmf_if *ifp; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; u8 ifidx; int ret; brcmf_dbg(TRACE, "Enter\n"); skb_queue_walk_safe(skb_list, skb, pnext) { skb_unlink(skb, skb_list); /* process and remove protocol-specific header */ ret = brcmf_proto_hdrpull(drvr, drvr->fw_signals, &ifidx, skb); ifp = drvr->iflist[ifidx]; if (ret || !ifp || !ifp->ndev) { if ((ret != -ENODATA) && ifp) ifp->stats.rx_errors++; brcmu_pkt_buf_free_skb(skb); continue; } /* Get the protocol, maintain skb around eth_type_trans() * The main reason for this hack is for the limitation of * Linux 2.4 where 'eth_type_trans' uses the * 'net->hard_header_len' * to perform skb_pull inside vs ETH_HLEN. Since to avoid * coping of the packet coming from the network stack to add * BDC, Hardware header etc, during network interface * registration * we set the 'net->hard_header_len' to ETH_HLEN + extra space * required * for BDC, Hardware header etc. and not just the ETH_HLEN */ eth = skb->data; len = skb->len; skb->dev = ifp->ndev; skb->protocol = eth_type_trans(skb, skb->dev); if (skb->pkt_type == PACKET_MULTICAST) ifp->stats.multicast++; skb->data = eth; skb->len = len; /* Strip header, count, deliver upward */ skb_pull(skb, ETH_HLEN); /* Process special event packets */ brcmf_fweh_process_skb(drvr, skb); if (!(ifp->ndev->flags & IFF_UP)) { brcmu_pkt_buf_free_skb(skb); continue; } ifp->stats.rx_bytes += skb->len; ifp->stats.rx_packets++; if (in_interrupt()) netif_rx(skb); else /* If the receive is not processed inside an ISR, * the softirqd must be woken explicitly to service * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled * by netif_rx_ni(), but in earlier kernels, we need * to do it manually. */ netif_rx_ni(skb); }
/* * 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; }