static int rmnet_mhi_poll(struct napi_struct *napi, int budget) { int received_packets = 0; struct net_device *dev = napi->dev; struct rmnet_mhi_private *rmnet_mhi_ptr = *(struct rmnet_mhi_private **)netdev_priv(dev); enum MHI_STATUS res = MHI_STATUS_reserved; bool should_reschedule = true; struct sk_buff *skb; dma_addr_t dma_addr; uintptr_t *cb_ptr; rmnet_log(MSG_VERBOSE, "Entered\n"); while (received_packets < budget) { struct mhi_result *result = mhi_poll(rmnet_mhi_ptr->rx_client_handle); if (result->transaction_status == MHI_STATUS_DEVICE_NOT_READY) { continue; } else if (result->transaction_status != MHI_STATUS_SUCCESS) { rmnet_log(MSG_CRITICAL, "mhi_poll failed, error is %d\n", result->transaction_status); break; } /* Nothing more to read, or out of buffers in MHI layer */ if (unlikely(!result->payload_buf || !result->bytes_xferd)) { should_reschedule = false; break; } skb = skb_dequeue(&(rmnet_mhi_ptr->rx_buffers)); if (unlikely(!skb)) { rmnet_log(MSG_CRITICAL, "No RX buffers to match"); break; } cb_ptr = (uintptr_t *)skb->cb; dma_addr = (dma_addr_t)(uintptr_t)(*cb_ptr); /* Sanity check, ensuring that this is actually the buffer */ if (unlikely(dma_addr != result->payload_buf)) { rmnet_log(MSG_CRITICAL, "Buf mismatch, expected 0x%lx, got 0x%lx", (uintptr_t)dma_addr, (uintptr_t)result->payload_buf); break; } dma_unmap_single(&(dev->dev), dma_addr, (rmnet_mhi_ptr->mru - MHI_RX_HEADROOM), DMA_FROM_DEVICE); skb_put(skb, result->bytes_xferd); skb->dev = dev; skb->protocol = rmnet_mhi_ip_type_trans(skb); netif_receive_skb(skb); /* Statistics */ received_packets++; dev->stats.rx_packets++; dev->stats.rx_bytes += result->bytes_xferd; /* Need to allocate a new buffer instead of this one */ skb = alloc_skb(rmnet_mhi_ptr->mru, GFP_ATOMIC); if (unlikely(!skb)) { rmnet_log(MSG_CRITICAL, "Can't allocate a new RX buffer for MHI"); break; } skb_reserve(skb, MHI_RX_HEADROOM); cb_ptr = (uintptr_t *)skb->cb; dma_addr = dma_map_single(&(dev->dev), skb->data, (rmnet_mhi_ptr->mru - MHI_RX_HEADROOM), DMA_FROM_DEVICE); *cb_ptr = (uintptr_t)dma_addr; if (unlikely(dma_mapping_error(&(dev->dev), dma_addr))) { rmnet_log(MSG_CRITICAL, "DMA mapping error in polling function"); dev_kfree_skb_irq(skb); break; } res = mhi_queue_xfer( rmnet_mhi_ptr->rx_client_handle, (uintptr_t)dma_addr, rmnet_mhi_ptr->mru, MHI_EOT); if (unlikely(MHI_STATUS_SUCCESS != res)) { rmnet_log(MSG_CRITICAL, "mhi_queue_xfer failed, error %d", res); dma_unmap_single(&(dev->dev), dma_addr, (rmnet_mhi_ptr->mru - MHI_RX_HEADROOM), DMA_FROM_DEVICE); dev_kfree_skb_irq(skb); break; } skb_queue_tail(&(rmnet_mhi_ptr->rx_buffers), skb); } /* while (received_packets < budget) or any other error */ napi_complete(napi); /* We got a NULL descriptor back */ if (should_reschedule == false) { if (rmnet_mhi_ptr->irq_masked_cntr) { mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); --rmnet_mhi_ptr->irq_masked_cntr; } } else { if (received_packets == budget) rx_napi_budget_overflow[rmnet_mhi_ptr->dev_index]++; napi_reschedule(napi); } rx_napi_skb_burst_min[rmnet_mhi_ptr->dev_index] = min((unsigned long)received_packets, rx_napi_skb_burst_min[rmnet_mhi_ptr->dev_index]); rx_napi_skb_burst_max[rmnet_mhi_ptr->dev_index] = max((unsigned long)received_packets, rx_napi_skb_burst_max[rmnet_mhi_ptr->dev_index]); rmnet_log(MSG_VERBOSE, "Exited, polled %d pkts\n", received_packets); return received_packets; }
static int rmnet_mhi_poll(struct napi_struct *napi, int budget) { int received_packets = 0; struct net_device *dev = napi->dev; struct rmnet_mhi_private *rmnet_mhi_ptr = *(struct rmnet_mhi_private **)netdev_priv(dev); enum MHI_STATUS res = MHI_STATUS_reserved; bool should_reschedule = true; struct sk_buff *skb; struct mhi_skb_priv *skb_priv; int r, cur_mru; rmnet_log(MSG_VERBOSE, "Entered\n"); rmnet_mhi_ptr->mru = mru; while (received_packets < budget) { struct mhi_result *result = mhi_poll(rmnet_mhi_ptr->rx_client_handle); if (result->transaction_status == MHI_STATUS_DEVICE_NOT_READY) { rmnet_log(MSG_INFO, "Transaction status not ready, continuing\n"); break; } else if (result->transaction_status != MHI_STATUS_SUCCESS && result->transaction_status != MHI_STATUS_OVERFLOW) { rmnet_log(MSG_CRITICAL, "mhi_poll failed, error %d\n", result->transaction_status); break; } /* Nothing more to read, or out of buffers in MHI layer */ if (unlikely(!result->buf_addr || !result->bytes_xferd)) { rmnet_log(MSG_CRITICAL, "Not valid buff not rescheduling\n"); should_reschedule = false; break; } skb = skb_dequeue(&(rmnet_mhi_ptr->rx_buffers)); if (unlikely(!skb)) { rmnet_log(MSG_CRITICAL, "No RX buffers to match"); break; } skb_priv = (struct mhi_skb_priv *)(skb->cb); /* Setup the tail to the end of data */ skb_put(skb, result->bytes_xferd); skb->dev = dev; skb->protocol = rmnet_mhi_ip_type_trans(skb); if (result->transaction_status == MHI_STATUS_OVERFLOW) r = rmnet_mhi_process_fragment(rmnet_mhi_ptr, skb, 1); else r = rmnet_mhi_process_fragment(rmnet_mhi_ptr, skb, 0); if (r) { rmnet_log(MSG_CRITICAL, "Failed to process fragmented packet ret %d", r); BUG(); } /* Statistics */ received_packets++; dev->stats.rx_packets++; dev->stats.rx_bytes += result->bytes_xferd; /* Need to allocate a new buffer instead of this one */ cur_mru = rmnet_mhi_ptr->mru; skb = alloc_skb(cur_mru, GFP_ATOMIC); if (unlikely(!skb)) { rmnet_log(MSG_CRITICAL, "Can't allocate a new RX buffer for MHI"); break; } skb_priv = (struct mhi_skb_priv *)(skb->cb); skb_priv->dma_size = cur_mru; rmnet_log(MSG_VERBOSE, "Allocated SKB of MRU 0x%x, SKB_DATA 0%p SKB_LEN 0x%x\n", rmnet_mhi_ptr->mru, skb->data, skb->len); /* Reserve headroom, tail == data */ skb_reserve(skb, MHI_RX_HEADROOM); skb_priv->dma_size -= MHI_RX_HEADROOM; skb_priv->dma_addr = 0; rmnet_log(MSG_VERBOSE, "Mapped SKB %p to DMA Addr 0x%lx, DMA_SIZE: 0x%lx\n", skb->data, (uintptr_t)skb->data, (uintptr_t)skb_priv->dma_size); res = mhi_queue_xfer( rmnet_mhi_ptr->rx_client_handle, skb->data, skb_priv->dma_size, MHI_EOT); if (unlikely(MHI_STATUS_SUCCESS != res)) { rmnet_log(MSG_CRITICAL, "mhi_queue_xfer failed, error %d", res); dev_kfree_skb_irq(skb); break; } skb_queue_tail(&rmnet_mhi_ptr->rx_buffers, skb); } /* while (received_packets < budget) or any other error */ napi_complete(napi); /* We got a NULL descriptor back */ if (should_reschedule == false) { if (atomic_read(&rmnet_mhi_ptr->irq_masked_cntr)) { atomic_dec(&rmnet_mhi_ptr->irq_masked_cntr); mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); } } else { if (received_packets == budget) rx_napi_budget_overflow[rmnet_mhi_ptr->dev_index]++; napi_reschedule(napi); } rx_napi_skb_burst_min[rmnet_mhi_ptr->dev_index] = min((unsigned long)received_packets, rx_napi_skb_burst_min[rmnet_mhi_ptr->dev_index]); rx_napi_skb_burst_max[rmnet_mhi_ptr->dev_index] = max((unsigned long)received_packets, rx_napi_skb_burst_max[rmnet_mhi_ptr->dev_index]); rmnet_log(MSG_VERBOSE, "Exited, polled %d pkts\n", received_packets); return received_packets; }
/* TODO: No error handling yet */ static int rmnet_mhi_poll(struct napi_struct *napi, int budget) { int received_packets = 0; struct net_device *dev = napi->dev; struct rmnet_mhi_private *rmnet_mhi_ptr = netdev_priv(dev); MHI_STATUS res = MHI_STATUS_reserved; bool should_reschedule = true; struct sk_buff *skb; dma_addr_t dma_addr; uintptr_t *cb_ptr; /* Reset the watchdog? */ while (received_packets < budget) { mhi_result *result = mhi_poll(rmnet_mhi_ptr->rx_client_handle); if(result->transaction_status == MHI_STATUS_DEVICE_NOT_READY) { continue; } else if (result->transaction_status != MHI_STATUS_SUCCESS) { /* TODO: Handle error */ pr_err("%s: mhi_poll failed, error is %d", __func__, result->transaction_status); break; } /* Nothing more to read, or out of buffers in MHI layer */ if (unlikely(0 == result->payload_buf || 0 == result->bytes_xferd)) { should_reschedule = false; break; } /* Assumption ---------- The buffer returned back is guaranteed to be the first buffer that was allocated for the RX, so we just dequeue the head. */ /* Take the first one */ skb = skb_dequeue(&(rmnet_mhi_ptr->rx_buffers)); if (unlikely(0 == skb)) { /* TODO: This shouldn't happen, we had a guard above */ pr_err("%s: No RX buffers to match", __func__); break; } cb_ptr = (uintptr_t *)skb->cb; dma_addr = (dma_addr_t)(uintptr_t)(*cb_ptr); /* Sanity check, ensuring that this is actually the buffer */ if (unlikely((uintptr_t)dma_addr != (uintptr_t)result->payload_buf)) { /* TODO: Handle error */ pr_err("%s: Unexpected physical address mismatch, expected 0x%lx, got 0x%lx", __func__, (uintptr_t)dma_addr, (uintptr_t)result->payload_buf); break; } dma_unmap_single(&(dev->dev), dma_addr, (rmnet_mhi_ptr->mru - MHI_RX_HEADROOM), DMA_FROM_DEVICE); skb_put(skb, result->bytes_xferd); skb->dev = dev; skb->protocol = rmnet_mhi_ip_type_trans(skb); netif_receive_skb(skb); /* Statistics */ received_packets++; dev->stats.rx_packets++; dev->stats.rx_bytes += result->bytes_xferd; /* Need to allocate a new buffer instead of this one (TODO: Maybe we can do it @ the end?) */ skb = alloc_skb(rmnet_mhi_ptr->mru, GFP_ATOMIC); if (unlikely(0 == skb)) { /* TODO: Handle error */ pr_err("%s: Can't allocate a new RX buffer for MHI", __func__); break; } skb_reserve(skb, MHI_RX_HEADROOM); cb_ptr = (uintptr_t *)skb->cb; dma_addr = dma_map_single(&(dev->dev), skb->data, rmnet_mhi_ptr->mru - MHI_RX_HEADROOM, DMA_FROM_DEVICE); *cb_ptr = (uintptr_t)dma_addr; if (unlikely(dma_mapping_error(&(dev->dev), dma_addr))) { pr_err("%s: DMA mapping error in polling function", __func__); /* TODO: Handle error */ dev_kfree_skb_irq(skb); break; } /* TODO: What do we do in such a scenario in which we can't allocate a RX buffer? */ if (unlikely(DMA_RANGE_CHECK(dma_addr, rmnet_mhi_ptr->mru, MHI_DMA_MASK))) { pr_err("%s: RX buffer is out of MHI DMA address range", __func__); dma_unmap_single(&(dev->dev), dma_addr, (rmnet_mhi_ptr->mru - MHI_RX_HEADROOM), DMA_FROM_DEVICE); dev_kfree_skb_irq(skb); break; } res = mhi_queue_xfer( rmnet_mhi_ptr->rx_client_handle, (uintptr_t)dma_addr, rmnet_mhi_ptr->mru, 0, 0); if (unlikely(MHI_STATUS_SUCCESS != res)) { /* TODO: Handle error */ pr_err("%s: mhi_queue_xfer failed, error %d", __func__, res); dma_unmap_single(&(dev->dev), dma_addr, (rmnet_mhi_ptr->mru - MHI_RX_HEADROOM), DMA_FROM_DEVICE); dev_kfree_skb_irq(skb); break; } skb_queue_tail(&(rmnet_mhi_ptr->rx_buffers), skb); } /* while (received_packets < budget) or any other error */ napi_complete(napi); /* We got a NULL descriptor back */ if (false == should_reschedule) { if (atomic_read(&rmnet_mhi_ptr->irq_masked)) { atomic_dec(&rmnet_mhi_ptr->irq_masked); mhi_unmask_irq(rmnet_mhi_ptr->rx_client_handle); } } else { if (received_packets == budget) rx_napi_budget_overflow[rmnet_mhi_ptr->dev_index]++; napi_reschedule(napi); } /* Start a watchdog? */ rx_napi_skb_burst_min[rmnet_mhi_ptr->dev_index] = min((unsigned long)received_packets, rx_napi_skb_burst_min[rmnet_mhi_ptr->dev_index]); rx_napi_skb_burst_max[rmnet_mhi_ptr->dev_index] = max((unsigned long)received_packets, rx_napi_skb_burst_max[rmnet_mhi_ptr->dev_index]); return received_packets; }