mirror of
git://git.openwrt.org/openwrt/openwrt.git
synced 2025-01-04 21:51:56 +00:00
ipq40xx: essedma: Add fix for memory allocation issues
This patch adds a ChromiumOS 3.18 patch [0] that fixes memory
allocation issues under memory pressure by keeping track
of missed allocs and rectify the omission at a later date.
It also adds ethtool counters for memory allocation
failures accounting so this can be verified.
[0] <d4e1e4ce68
>
Reported-by: Chen Minqiang <ptpt52@gmail.com>
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
This commit is contained in:
parent
bfdf00977d
commit
84f13e19b4
@ -0,0 +1,197 @@
|
||||
From 72c050acbc425ef99313d5c2e4c866e25567e569 Mon Sep 17 00:00:00 2001
|
||||
From: Rakesh Nair <ranair@codeaurora.org>
|
||||
Date: Thu, 8 Jun 2017 14:29:20 +0530
|
||||
Subject: [PATCH] CHROMIUM: net: qualcomm: Add fix for memory allocation issues
|
||||
|
||||
Added ethtool counters for memory allocation failures accounting.
|
||||
Added support to track number of allocation failures that could
|
||||
not be fulfilled in the current iteration in the rx descriptor
|
||||
field and use the info to allocate in the subsequent iteration.
|
||||
|
||||
Change-Id: Ie4fd3b6cf25304e5db2c9247a498791e7e9bb4aa
|
||||
Signed-off-by: Rakesh Nair <ranair@codeaurora.org>
|
||||
Signed-off-by: Kan Yan <kyan@google.com>
|
||||
Reviewed-on: https://chromium-review.googlesource.com/535419
|
||||
Reviewed-by: Grant Grundler <grundler@chromium.org>
|
||||
---
|
||||
drivers/net/ethernet/qualcomm/essedma/edma.c | 54 ++++++++++++++-----
|
||||
drivers/net/ethernet/qualcomm/essedma/edma.h | 2 +
|
||||
.../ethernet/qualcomm/essedma/edma_ethtool.c | 1 +
|
||||
3 files changed, 43 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
@@ -103,6 +103,9 @@ static int edma_alloc_rx_ring(struct edm
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
+ /* Initialize pending_fill */
|
||||
+ erxd->pending_fill = 0;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -185,11 +188,8 @@ static int edma_alloc_rx_buf(struct edma
|
||||
u16 prod_idx, length;
|
||||
u32 reg_data;
|
||||
|
||||
- if (cleaned_count > erdr->count) {
|
||||
- dev_err(&pdev->dev, "Incorrect cleaned_count %d",
|
||||
- cleaned_count);
|
||||
- return -1;
|
||||
- }
|
||||
+ if (cleaned_count > erdr->count)
|
||||
+ cleaned_count = erdr->count - 1;
|
||||
|
||||
i = erdr->sw_next_to_fill;
|
||||
|
||||
@@ -199,6 +199,9 @@ static int edma_alloc_rx_buf(struct edma
|
||||
|
||||
if (sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_REUSE) {
|
||||
skb = sw_desc->skb;
|
||||
+
|
||||
+ /* Clear REUSE Flag */
|
||||
+ sw_desc->flags &= ~EDMA_SW_DESC_FLAG_SKB_REUSE;
|
||||
} else {
|
||||
/* alloc skb */
|
||||
skb = netdev_alloc_skb_ip_align(edma_netdev[0], length);
|
||||
@@ -264,6 +267,13 @@ static int edma_alloc_rx_buf(struct edma
|
||||
reg_data &= ~EDMA_RFD_PROD_IDX_BITS;
|
||||
reg_data |= prod_idx;
|
||||
edma_write_reg(EDMA_REG_RFD_IDX_Q(queue_id), reg_data);
|
||||
+
|
||||
+ /* If we couldn't allocate all the buffers
|
||||
+ * we increment the alloc failure counters
|
||||
+ */
|
||||
+ if (cleaned_count)
|
||||
+ edma_cinfo->edma_ethstats.rx_alloc_fail_ctr++;
|
||||
+
|
||||
return cleaned_count;
|
||||
}
|
||||
|
||||
@@ -534,7 +544,7 @@ static int edma_rx_complete_paged(struct
|
||||
* edma_rx_complete()
|
||||
* Main api called from the poll function to process rx packets.
|
||||
*/
|
||||
-static void edma_rx_complete(struct edma_common_info *edma_cinfo,
|
||||
+static u16 edma_rx_complete(struct edma_common_info *edma_cinfo,
|
||||
int *work_done, int work_to_do, int queue_id,
|
||||
struct napi_struct *napi)
|
||||
{
|
||||
@@ -554,6 +564,7 @@ static void edma_rx_complete(struct edma
|
||||
u16 count = erdr->count, rfd_avail;
|
||||
u8 queue_to_rxid[8] = {0, 0, 1, 1, 2, 2, 3, 3};
|
||||
|
||||
+ cleaned_count = erdr->pending_fill;
|
||||
sw_next_to_clean = erdr->sw_next_to_clean;
|
||||
|
||||
edma_read_reg(EDMA_REG_RFD_IDX_Q(queue_id), &data);
|
||||
@@ -652,12 +663,13 @@ static void edma_rx_complete(struct edma
|
||||
(*work_done)++;
|
||||
drop_count = 0;
|
||||
}
|
||||
- if (cleaned_count == EDMA_RX_BUFFER_WRITE) {
|
||||
+ if (cleaned_count >= EDMA_RX_BUFFER_WRITE) {
|
||||
/* If buffer clean count reaches 16, we replenish HW buffers. */
|
||||
ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id);
|
||||
edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id),
|
||||
sw_next_to_clean);
|
||||
cleaned_count = ret_count;
|
||||
+ erdr->pending_fill = ret_count;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -730,11 +742,12 @@ static void edma_rx_complete(struct edma
|
||||
adapter->stats.rx_bytes += length;
|
||||
|
||||
/* Check if we reached refill threshold */
|
||||
- if (cleaned_count == EDMA_RX_BUFFER_WRITE) {
|
||||
+ if (cleaned_count >= EDMA_RX_BUFFER_WRITE) {
|
||||
ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id);
|
||||
edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id),
|
||||
sw_next_to_clean);
|
||||
cleaned_count = ret_count;
|
||||
+ erdr->pending_fill = ret_count;
|
||||
}
|
||||
|
||||
/* At this point skb should go to stack */
|
||||
@@ -756,11 +769,17 @@ static void edma_rx_complete(struct edma
|
||||
/* Refill here in case refill threshold wasn't reached */
|
||||
if (likely(cleaned_count)) {
|
||||
ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id);
|
||||
- if (ret_count)
|
||||
- dev_dbg(&pdev->dev, "Not all buffers was reallocated");
|
||||
+ erdr->pending_fill = ret_count;
|
||||
+ if (ret_count) {
|
||||
+ if (net_ratelimit())
|
||||
+ dev_dbg(&pdev->dev, "Not all buffers was reallocated");
|
||||
+ }
|
||||
+
|
||||
edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id),
|
||||
erdr->sw_next_to_clean);
|
||||
}
|
||||
+
|
||||
+ return erdr->pending_fill;
|
||||
}
|
||||
|
||||
/* edma_delete_rfs_filter()
|
||||
@@ -2064,6 +2083,7 @@ int edma_poll(struct napi_struct *napi,
|
||||
u32 shadow_rx_status, shadow_tx_status;
|
||||
int queue_id;
|
||||
int i, work_done = 0;
|
||||
+ u16 rx_pending_fill;
|
||||
|
||||
/* Store the Rx/Tx status by ANDing it with
|
||||
* appropriate CPU RX?TX mask
|
||||
@@ -2097,13 +2117,19 @@ int edma_poll(struct napi_struct *napi,
|
||||
*/
|
||||
while (edma_percpu_info->rx_status) {
|
||||
queue_id = ffs(edma_percpu_info->rx_status) - 1;
|
||||
- edma_rx_complete(edma_cinfo, &work_done,
|
||||
- budget, queue_id, napi);
|
||||
+ rx_pending_fill = edma_rx_complete(edma_cinfo, &work_done,
|
||||
+ budget, queue_id, napi);
|
||||
|
||||
- if (likely(work_done < budget))
|
||||
+ if (likely(work_done < budget)) {
|
||||
+ if (rx_pending_fill) {
|
||||
+ /* reschedule poll() to refill rx buffer deficit */
|
||||
+ work_done = budget;
|
||||
+ break;
|
||||
+ }
|
||||
edma_percpu_info->rx_status &= ~(1 << queue_id);
|
||||
- else
|
||||
+ } else {
|
||||
break;
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Clear the status register, to avoid the interrupts to
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.h
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.h
|
||||
@@ -225,6 +225,7 @@ struct edma_ethtool_statistics {
|
||||
u32 rx_q6_byte;
|
||||
u32 rx_q7_byte;
|
||||
u32 tx_desc_error;
|
||||
+ u32 rx_alloc_fail_ctr;
|
||||
};
|
||||
|
||||
struct edma_mdio_data {
|
||||
@@ -362,6 +363,7 @@ struct edma_rfd_desc_ring {
|
||||
dma_addr_t dma; /* descriptor ring physical address */
|
||||
u16 sw_next_to_fill; /* next descriptor to fill */
|
||||
u16 sw_next_to_clean; /* next descriptor to clean */
|
||||
+ u16 pending_fill; /* fill pending from previous iteration */
|
||||
};
|
||||
|
||||
/* edma_rfs_flter_node - rfs filter node in hash table */
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma_ethtool.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma_ethtool.c
|
||||
@@ -78,6 +78,7 @@ static const struct edma_ethtool_stats e
|
||||
{"rx_q6_byte", EDMA_STAT(rx_q6_byte)},
|
||||
{"rx_q7_byte", EDMA_STAT(rx_q7_byte)},
|
||||
{"tx_desc_error", EDMA_STAT(tx_desc_error)},
|
||||
+ {"rx_alloc_fail_ctr", EDMA_STAT(rx_alloc_fail_ctr)},
|
||||
};
|
||||
|
||||
#define EDMA_STATS_LEN ARRAY_SIZE(edma_gstrings_stats)
|
@ -0,0 +1,197 @@
|
||||
From 72c050acbc425ef99313d5c2e4c866e25567e569 Mon Sep 17 00:00:00 2001
|
||||
From: Rakesh Nair <ranair@codeaurora.org>
|
||||
Date: Thu, 8 Jun 2017 14:29:20 +0530
|
||||
Subject: [PATCH] CHROMIUM: net: qualcomm: Add fix for memory allocation issues
|
||||
|
||||
Added ethtool counters for memory allocation failures accounting.
|
||||
Added support to track number of allocation failures that could
|
||||
not be fulfilled in the current iteration in the rx descriptor
|
||||
field and use the info to allocate in the subsequent iteration.
|
||||
|
||||
Change-Id: Ie4fd3b6cf25304e5db2c9247a498791e7e9bb4aa
|
||||
Signed-off-by: Rakesh Nair <ranair@codeaurora.org>
|
||||
Signed-off-by: Kan Yan <kyan@google.com>
|
||||
Reviewed-on: https://chromium-review.googlesource.com/535419
|
||||
Reviewed-by: Grant Grundler <grundler@chromium.org>
|
||||
---
|
||||
drivers/net/ethernet/qualcomm/essedma/edma.c | 54 ++++++++++++++-----
|
||||
drivers/net/ethernet/qualcomm/essedma/edma.h | 2 +
|
||||
.../ethernet/qualcomm/essedma/edma_ethtool.c | 1 +
|
||||
3 files changed, 43 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.c
|
||||
@@ -103,6 +103,9 @@ static int edma_alloc_rx_ring(struct edm
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
+ /* Initialize pending_fill */
|
||||
+ erxd->pending_fill = 0;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -185,11 +188,8 @@ static int edma_alloc_rx_buf(struct edma
|
||||
u16 prod_idx, length;
|
||||
u32 reg_data;
|
||||
|
||||
- if (cleaned_count > erdr->count) {
|
||||
- dev_err(&pdev->dev, "Incorrect cleaned_count %d",
|
||||
- cleaned_count);
|
||||
- return -1;
|
||||
- }
|
||||
+ if (cleaned_count > erdr->count)
|
||||
+ cleaned_count = erdr->count - 1;
|
||||
|
||||
i = erdr->sw_next_to_fill;
|
||||
|
||||
@@ -199,6 +199,9 @@ static int edma_alloc_rx_buf(struct edma
|
||||
|
||||
if (sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_REUSE) {
|
||||
skb = sw_desc->skb;
|
||||
+
|
||||
+ /* Clear REUSE Flag */
|
||||
+ sw_desc->flags &= ~EDMA_SW_DESC_FLAG_SKB_REUSE;
|
||||
} else {
|
||||
/* alloc skb */
|
||||
skb = netdev_alloc_skb_ip_align(edma_netdev[0], length);
|
||||
@@ -264,6 +267,13 @@ static int edma_alloc_rx_buf(struct edma
|
||||
reg_data &= ~EDMA_RFD_PROD_IDX_BITS;
|
||||
reg_data |= prod_idx;
|
||||
edma_write_reg(EDMA_REG_RFD_IDX_Q(queue_id), reg_data);
|
||||
+
|
||||
+ /* If we couldn't allocate all the buffers
|
||||
+ * we increment the alloc failure counters
|
||||
+ */
|
||||
+ if (cleaned_count)
|
||||
+ edma_cinfo->edma_ethstats.rx_alloc_fail_ctr++;
|
||||
+
|
||||
return cleaned_count;
|
||||
}
|
||||
|
||||
@@ -534,7 +544,7 @@ static int edma_rx_complete_paged(struct
|
||||
* edma_rx_complete()
|
||||
* Main api called from the poll function to process rx packets.
|
||||
*/
|
||||
-static void edma_rx_complete(struct edma_common_info *edma_cinfo,
|
||||
+static u16 edma_rx_complete(struct edma_common_info *edma_cinfo,
|
||||
int *work_done, int work_to_do, int queue_id,
|
||||
struct napi_struct *napi)
|
||||
{
|
||||
@@ -554,6 +564,7 @@ static void edma_rx_complete(struct edma
|
||||
u16 count = erdr->count, rfd_avail;
|
||||
u8 queue_to_rxid[8] = {0, 0, 1, 1, 2, 2, 3, 3};
|
||||
|
||||
+ cleaned_count = erdr->pending_fill;
|
||||
sw_next_to_clean = erdr->sw_next_to_clean;
|
||||
|
||||
edma_read_reg(EDMA_REG_RFD_IDX_Q(queue_id), &data);
|
||||
@@ -652,12 +663,13 @@ static void edma_rx_complete(struct edma
|
||||
(*work_done)++;
|
||||
drop_count = 0;
|
||||
}
|
||||
- if (cleaned_count == EDMA_RX_BUFFER_WRITE) {
|
||||
+ if (cleaned_count >= EDMA_RX_BUFFER_WRITE) {
|
||||
/* If buffer clean count reaches 16, we replenish HW buffers. */
|
||||
ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id);
|
||||
edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id),
|
||||
sw_next_to_clean);
|
||||
cleaned_count = ret_count;
|
||||
+ erdr->pending_fill = ret_count;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -730,11 +742,12 @@ static void edma_rx_complete(struct edma
|
||||
adapter->stats.rx_bytes += length;
|
||||
|
||||
/* Check if we reached refill threshold */
|
||||
- if (cleaned_count == EDMA_RX_BUFFER_WRITE) {
|
||||
+ if (cleaned_count >= EDMA_RX_BUFFER_WRITE) {
|
||||
ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id);
|
||||
edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id),
|
||||
sw_next_to_clean);
|
||||
cleaned_count = ret_count;
|
||||
+ erdr->pending_fill = ret_count;
|
||||
}
|
||||
|
||||
/* At this point skb should go to stack */
|
||||
@@ -756,11 +769,17 @@ static void edma_rx_complete(struct edma
|
||||
/* Refill here in case refill threshold wasn't reached */
|
||||
if (likely(cleaned_count)) {
|
||||
ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id);
|
||||
- if (ret_count)
|
||||
- dev_dbg(&pdev->dev, "Not all buffers was reallocated");
|
||||
+ erdr->pending_fill = ret_count;
|
||||
+ if (ret_count) {
|
||||
+ if (net_ratelimit())
|
||||
+ dev_dbg(&pdev->dev, "Not all buffers was reallocated");
|
||||
+ }
|
||||
+
|
||||
edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id),
|
||||
erdr->sw_next_to_clean);
|
||||
}
|
||||
+
|
||||
+ return erdr->pending_fill;
|
||||
}
|
||||
|
||||
/* edma_delete_rfs_filter()
|
||||
@@ -2064,6 +2083,7 @@ int edma_poll(struct napi_struct *napi,
|
||||
u32 shadow_rx_status, shadow_tx_status;
|
||||
int queue_id;
|
||||
int i, work_done = 0;
|
||||
+ u16 rx_pending_fill;
|
||||
|
||||
/* Store the Rx/Tx status by ANDing it with
|
||||
* appropriate CPU RX?TX mask
|
||||
@@ -2097,13 +2117,19 @@ int edma_poll(struct napi_struct *napi,
|
||||
*/
|
||||
while (edma_percpu_info->rx_status) {
|
||||
queue_id = ffs(edma_percpu_info->rx_status) - 1;
|
||||
- edma_rx_complete(edma_cinfo, &work_done,
|
||||
- budget, queue_id, napi);
|
||||
+ rx_pending_fill = edma_rx_complete(edma_cinfo, &work_done,
|
||||
+ budget, queue_id, napi);
|
||||
|
||||
- if (likely(work_done < budget))
|
||||
+ if (likely(work_done < budget)) {
|
||||
+ if (rx_pending_fill) {
|
||||
+ /* reschedule poll() to refill rx buffer deficit */
|
||||
+ work_done = budget;
|
||||
+ break;
|
||||
+ }
|
||||
edma_percpu_info->rx_status &= ~(1 << queue_id);
|
||||
- else
|
||||
+ } else {
|
||||
break;
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Clear the status register, to avoid the interrupts to
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma.h
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma.h
|
||||
@@ -225,6 +225,7 @@ struct edma_ethtool_statistics {
|
||||
u32 rx_q6_byte;
|
||||
u32 rx_q7_byte;
|
||||
u32 tx_desc_error;
|
||||
+ u32 rx_alloc_fail_ctr;
|
||||
};
|
||||
|
||||
struct edma_mdio_data {
|
||||
@@ -362,6 +363,7 @@ struct edma_rfd_desc_ring {
|
||||
dma_addr_t dma; /* descriptor ring physical address */
|
||||
u16 sw_next_to_fill; /* next descriptor to fill */
|
||||
u16 sw_next_to_clean; /* next descriptor to clean */
|
||||
+ u16 pending_fill; /* fill pending from previous iteration */
|
||||
};
|
||||
|
||||
/* edma_rfs_flter_node - rfs filter node in hash table */
|
||||
--- a/drivers/net/ethernet/qualcomm/essedma/edma_ethtool.c
|
||||
+++ b/drivers/net/ethernet/qualcomm/essedma/edma_ethtool.c
|
||||
@@ -78,6 +78,7 @@ static const struct edma_ethtool_stats e
|
||||
{"rx_q6_byte", EDMA_STAT(rx_q6_byte)},
|
||||
{"rx_q7_byte", EDMA_STAT(rx_q7_byte)},
|
||||
{"tx_desc_error", EDMA_STAT(tx_desc_error)},
|
||||
+ {"rx_alloc_fail_ctr", EDMA_STAT(rx_alloc_fail_ctr)},
|
||||
};
|
||||
|
||||
#define EDMA_STATS_LEN ARRAY_SIZE(edma_gstrings_stats)
|
Loading…
Reference in New Issue
Block a user