|
@@ -2286,6 +2286,27 @@ fail_kmem_cache_alloc:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static struct page *ipa3_alloc_page(
|
|
|
+ gfp_t flag, u32 *page_order, bool try_lower)
|
|
|
+{
|
|
|
+ struct page *page = NULL;
|
|
|
+ u32 p_order = *page_order;
|
|
|
+
|
|
|
+ page = __dev_alloc_pages(flag, p_order);
|
|
|
+ /* We will only try 1 page order lower. */
|
|
|
+ if (unlikely(!page)) {
|
|
|
+ if (try_lower && p_order > 0) {
|
|
|
+ p_order = p_order - 1;
|
|
|
+ page = __dev_alloc_pages(flag, p_order);
|
|
|
+ if (likely(page))
|
|
|
+ ipa3_ctx->stats.lower_order++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ *page_order = p_order;
|
|
|
+ return page;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static struct ipa3_rx_pkt_wrapper *ipa3_alloc_rx_pkt_page(
|
|
|
gfp_t flag, bool is_tmp_alloc, struct ipa3_sys_context *sys)
|
|
|
{
|
|
@@ -2296,13 +2317,18 @@ static struct ipa3_rx_pkt_wrapper *ipa3_alloc_rx_pkt_page(
|
|
|
flag);
|
|
|
if (unlikely(!rx_pkt))
|
|
|
return NULL;
|
|
|
- rx_pkt->len = PAGE_SIZE << sys->page_order;
|
|
|
- rx_pkt->page_data.page = __dev_alloc_pages(flag,
|
|
|
- sys->page_order);
|
|
|
+
|
|
|
+ rx_pkt->page_data.page_order = sys->page_order;
|
|
|
+ /* Try a lower order page for order 3 pages in case allocation fails. */
|
|
|
+ rx_pkt->page_data.page = ipa3_alloc_page(flag,
|
|
|
+ &rx_pkt->page_data.page_order,
|
|
|
+ (is_tmp_alloc && rx_pkt->page_data.page_order == 3));
|
|
|
|
|
|
if (unlikely(!rx_pkt->page_data.page))
|
|
|
goto fail_page_alloc;
|
|
|
|
|
|
+ rx_pkt->len = PAGE_SIZE << rx_pkt->page_data.page_order;
|
|
|
+
|
|
|
rx_pkt->page_data.dma_addr = dma_map_page(ipa3_ctx->pdev,
|
|
|
rx_pkt->page_data.page, 0,
|
|
|
rx_pkt->len, DMA_FROM_DEVICE);
|
|
@@ -2320,7 +2346,7 @@ static struct ipa3_rx_pkt_wrapper *ipa3_alloc_rx_pkt_page(
|
|
|
return rx_pkt;
|
|
|
|
|
|
fail_dma_mapping:
|
|
|
- __free_pages(rx_pkt->page_data.page, sys->page_order);
|
|
|
+ __free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order);
|
|
|
fail_page_alloc:
|
|
|
kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt);
|
|
|
return NULL;
|
|
@@ -3052,7 +3078,7 @@ static void free_rx_page(void *chan_user_data, void *xfer_user_data)
|
|
|
}
|
|
|
dma_unmap_page(ipa3_ctx->pdev, rx_pkt->page_data.dma_addr,
|
|
|
rx_pkt->len, DMA_FROM_DEVICE);
|
|
|
- __free_pages(rx_pkt->page_data.page, rx_pkt->sys->page_order);
|
|
|
+ __free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order);
|
|
|
kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt);
|
|
|
}
|
|
|
|
|
@@ -3102,7 +3128,7 @@ static void ipa3_cleanup_rx(struct ipa3_sys_context *sys)
|
|
|
rx_pkt->page_data.dma_addr,
|
|
|
rx_pkt->len,
|
|
|
DMA_FROM_DEVICE);
|
|
|
- __free_pages(rx_pkt->page_data.page, sys->page_order);
|
|
|
+ __free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order);
|
|
|
}
|
|
|
kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache,
|
|
|
rx_pkt);
|
|
@@ -3122,7 +3148,7 @@ static void ipa3_cleanup_rx(struct ipa3_sys_context *sys)
|
|
|
rx_pkt->len,
|
|
|
DMA_FROM_DEVICE);
|
|
|
__free_pages(rx_pkt->page_data.page,
|
|
|
- sys->page_order);
|
|
|
+ rx_pkt->page_data.page_order);
|
|
|
kmem_cache_free(
|
|
|
ipa3_ctx->rx_pkt_wrapper_cache,
|
|
|
rx_pkt);
|
|
@@ -3922,7 +3948,7 @@ static struct sk_buff *handle_page_completion(struct gsi_chan_xfer_notify
|
|
|
} else {
|
|
|
dma_unmap_page(ipa3_ctx->pdev, rx_page.dma_addr,
|
|
|
rx_pkt->len, DMA_FROM_DEVICE);
|
|
|
- __free_pages(rx_pkt->page_data.page, sys->page_order);
|
|
|
+ __free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order);
|
|
|
}
|
|
|
rx_pkt->sys->free_rx_wrapper(rx_pkt);
|
|
|
IPA_STATS_INC_CNT(ipa3_ctx->stats.rx_page_drop_cnt);
|
|
@@ -3954,7 +3980,7 @@ static struct sk_buff *handle_page_completion(struct gsi_chan_xfer_notify
|
|
|
} else {
|
|
|
dma_unmap_page(ipa3_ctx->pdev, rx_page.dma_addr,
|
|
|
rx_pkt->len, DMA_FROM_DEVICE);
|
|
|
- __free_pages(rx_pkt->page_data.page, sys->page_order);
|
|
|
+ __free_pages(rx_pkt->page_data.page, rx_pkt->page_data.page_order);
|
|
|
}
|
|
|
rx_pkt->sys->free_rx_wrapper(rx_pkt);
|
|
|
}
|
|
@@ -3985,7 +4011,7 @@ static struct sk_buff *handle_page_completion(struct gsi_chan_xfer_notify
|
|
|
skb_shinfo(rx_skb)->nr_frags,
|
|
|
rx_page.page, 0,
|
|
|
size,
|
|
|
- PAGE_SIZE << sys->page_order);
|
|
|
+ PAGE_SIZE << rx_page.page_order);
|
|
|
}
|
|
|
} else {
|
|
|
return NULL;
|