* [PATCH net-next v2 0/5] r8152: RX improve
[not found] <1394712342-15778-289-Taiwan-albertk@realtek.com>
@ 2019-08-13 3:42 ` Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 1/5] r8152: separate the rx buffer size Hayes Wang
` (5 more replies)
0 siblings, 6 replies; 12+ messages in thread
From: Hayes Wang @ 2019-08-13 3:42 UTC (permalink / raw)
To: netdev; +Cc: nic_swsd, linux-kernel, linux-usb, Hayes Wang
v2:
For patch #2, replace list_for_each_safe with list_for_each_entry_safe.
Remove unlikely in WARN_ON. Adjust the coding style.
For patch #4, replace list_for_each_safe with list_for_each_entry_safe.
Remove "else" after "continue".
For patch #5. replace sysfs with ethtool to modify rx_copybreak and
rx_pending.
v1:
The different chips use different rx buffer size.
Use skb_add_rx_frag() to reduce memory copy for RX.
Hayes Wang (5):
r8152: separate the rx buffer size
r8152: replace array with linking list for rx information
r8152: use alloc_pages for rx buffer
r8152: support skb_add_rx_frag
r8152: change rx_copybreak and rx_pending through ethtool
drivers/net/usb/r8152.c | 374 ++++++++++++++++++++++++++++++++--------
1 file changed, 304 insertions(+), 70 deletions(-)
--
2.21.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH net-next v2 1/5] r8152: separate the rx buffer size
2019-08-13 3:42 ` [PATCH net-next v2 0/5] r8152: RX improve Hayes Wang
@ 2019-08-13 3:42 ` Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 2/5] r8152: replace array with linking list for rx information Hayes Wang
` (4 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Hayes Wang @ 2019-08-13 3:42 UTC (permalink / raw)
To: netdev; +Cc: nic_swsd, linux-kernel, linux-usb, Hayes Wang
The different chips may accept different rx buffer sizes. The RTL8152
supports 16K bytes, and RTL8153 support 32K bytes.
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
drivers/net/usb/r8152.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 0cc03a9ff545..94da79028a65 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -749,6 +749,7 @@ struct r8152 {
u32 msg_enable;
u32 tx_qlen;
u32 coalesce;
+ u32 rx_buf_sz;
u16 ocp_base;
u16 speed;
u8 *intr_buff;
@@ -1516,13 +1517,13 @@ static int alloc_all_mem(struct r8152 *tp)
skb_queue_head_init(&tp->rx_queue);
for (i = 0; i < RTL8152_MAX_RX; i++) {
- buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node);
+ buf = kmalloc_node(tp->rx_buf_sz, GFP_KERNEL, node);
if (!buf)
goto err1;
if (buf != rx_agg_align(buf)) {
kfree(buf);
- buf = kmalloc_node(agg_buf_sz + RX_ALIGN, GFP_KERNEL,
+ buf = kmalloc_node(tp->rx_buf_sz + RX_ALIGN, GFP_KERNEL,
node);
if (!buf)
goto err1;
@@ -2113,7 +2114,7 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
return 0;
usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
- agg->head, agg_buf_sz,
+ agg->head, tp->rx_buf_sz,
(usb_complete_t)read_bulk_callback, agg);
ret = usb_submit_urb(agg->urb, mem_flags);
@@ -2447,7 +2448,7 @@ static void r8153_set_rx_early_timeout(struct r8152 *tp)
static void r8153_set_rx_early_size(struct r8152 *tp)
{
- u32 ocp_data = agg_buf_sz - rx_reserved_size(tp->netdev->mtu);
+ u32 ocp_data = tp->rx_buf_sz - rx_reserved_size(tp->netdev->mtu);
switch (tp->version) {
case RTL_VER_03:
@@ -5115,6 +5116,7 @@ static int rtl_ops_init(struct r8152 *tp)
ops->in_nway = rtl8152_in_nway;
ops->hw_phy_cfg = r8152b_hw_phy_cfg;
ops->autosuspend_en = rtl_runtime_suspend_enable;
+ tp->rx_buf_sz = 16 * 1024;
break;
case RTL_VER_03:
@@ -5132,6 +5134,7 @@ static int rtl_ops_init(struct r8152 *tp)
ops->in_nway = rtl8153_in_nway;
ops->hw_phy_cfg = r8153_hw_phy_cfg;
ops->autosuspend_en = rtl8153_runtime_enable;
+ tp->rx_buf_sz = 32 * 1024;
break;
case RTL_VER_08:
@@ -5147,6 +5150,7 @@ static int rtl_ops_init(struct r8152 *tp)
ops->in_nway = rtl8153_in_nway;
ops->hw_phy_cfg = r8153b_hw_phy_cfg;
ops->autosuspend_en = rtl8153b_runtime_enable;
+ tp->rx_buf_sz = 32 * 1024;
break;
default:
--
2.21.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 2/5] r8152: replace array with linking list for rx information
2019-08-13 3:42 ` [PATCH net-next v2 0/5] r8152: RX improve Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 1/5] r8152: separate the rx buffer size Hayes Wang
@ 2019-08-13 3:42 ` Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 3/5] r8152: use alloc_pages for rx buffer Hayes Wang
` (3 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Hayes Wang @ 2019-08-13 3:42 UTC (permalink / raw)
To: netdev; +Cc: nic_swsd, linux-kernel, linux-usb, Hayes Wang
The original method uses an array to store the rx information. The
new one uses a list to link each rx structure. Then, it is possible
to increase/decrease the number of rx structure dynamically.
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
drivers/net/usb/r8152.c | 182 +++++++++++++++++++++++++++-------------
1 file changed, 125 insertions(+), 57 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 94da79028a65..d063c9b358e5 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -22,6 +22,7 @@
#include <linux/mdio.h>
#include <linux/usb/cdc.h>
#include <linux/suspend.h>
+#include <linux/atomic.h>
#include <linux/acpi.h>
/* Information for net-next */
@@ -694,7 +695,7 @@ struct tx_desc {
struct r8152;
struct rx_agg {
- struct list_head list;
+ struct list_head list, info_list;
struct urb *urb;
struct r8152 *context;
void *buffer;
@@ -719,7 +720,7 @@ struct r8152 {
struct net_device *netdev;
struct urb *intr_urb;
struct tx_agg tx_info[RTL8152_MAX_TX];
- struct rx_agg rx_info[RTL8152_MAX_RX];
+ struct list_head rx_info;
struct list_head rx_done, tx_free;
struct sk_buff_head tx_queue, rx_queue;
spinlock_t rx_lock, tx_lock;
@@ -744,6 +745,8 @@ struct r8152 {
void (*autosuspend_en)(struct r8152 *tp, bool enable);
} rtl_ops;
+ atomic_t rx_count;
+
int intr_interval;
u32 saved_wolopts;
u32 msg_enable;
@@ -1468,18 +1471,81 @@ static inline void *tx_agg_align(void *data)
return (void *)ALIGN((uintptr_t)data, TX_ALIGN);
}
+static void free_rx_agg(struct r8152 *tp, struct rx_agg *agg)
+{
+ list_del(&agg->info_list);
+
+ usb_free_urb(agg->urb);
+ kfree(agg->buffer);
+ kfree(agg);
+
+ atomic_dec(&tp->rx_count);
+}
+
+static struct rx_agg *alloc_rx_agg(struct r8152 *tp, gfp_t mflags)
+{
+ struct net_device *netdev = tp->netdev;
+ int node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1;
+ struct rx_agg *rx_agg;
+ unsigned long flags;
+ u8 *buf;
+
+ rx_agg = kmalloc_node(sizeof(*rx_agg), mflags, node);
+ if (!rx_agg)
+ return NULL;
+
+ buf = kmalloc_node(tp->rx_buf_sz, mflags, node);
+ if (!buf)
+ goto free_rx;
+
+ if (buf != rx_agg_align(buf)) {
+ kfree(buf);
+ buf = kmalloc_node(tp->rx_buf_sz + RX_ALIGN, mflags,
+ node);
+ if (!buf)
+ goto free_rx;
+ }
+
+ rx_agg->buffer = buf;
+ rx_agg->head = rx_agg_align(buf);
+
+ rx_agg->urb = usb_alloc_urb(0, mflags);
+ if (!rx_agg->urb)
+ goto free_buf;
+
+ rx_agg->context = tp;
+
+ INIT_LIST_HEAD(&rx_agg->list);
+ INIT_LIST_HEAD(&rx_agg->info_list);
+ spin_lock_irqsave(&tp->rx_lock, flags);
+ list_add_tail(&rx_agg->info_list, &tp->rx_info);
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
+
+ atomic_inc(&tp->rx_count);
+
+ return rx_agg;
+
+free_buf:
+ kfree(rx_agg->buffer);
+free_rx:
+ kfree(rx_agg);
+ return NULL;
+}
+
static void free_all_mem(struct r8152 *tp)
{
+ struct rx_agg *agg, *agg_next;
+ unsigned long flags;
int i;
- for (i = 0; i < RTL8152_MAX_RX; i++) {
- usb_free_urb(tp->rx_info[i].urb);
- tp->rx_info[i].urb = NULL;
+ spin_lock_irqsave(&tp->rx_lock, flags);
- kfree(tp->rx_info[i].buffer);
- tp->rx_info[i].buffer = NULL;
- tp->rx_info[i].head = NULL;
- }
+ list_for_each_entry_safe(agg, agg_next, &tp->rx_info, info_list)
+ free_rx_agg(tp, agg);
+
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
+
+ WARN_ON(atomic_read(&tp->rx_count));
for (i = 0; i < RTL8152_MAX_TX; i++) {
usb_free_urb(tp->tx_info[i].urb);
@@ -1503,46 +1569,28 @@ static int alloc_all_mem(struct r8152 *tp)
struct usb_interface *intf = tp->intf;
struct usb_host_interface *alt = intf->cur_altsetting;
struct usb_host_endpoint *ep_intr = alt->endpoint + 2;
- struct urb *urb;
int node, i;
- u8 *buf;
node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1;
spin_lock_init(&tp->rx_lock);
spin_lock_init(&tp->tx_lock);
+ INIT_LIST_HEAD(&tp->rx_info);
INIT_LIST_HEAD(&tp->tx_free);
INIT_LIST_HEAD(&tp->rx_done);
skb_queue_head_init(&tp->tx_queue);
skb_queue_head_init(&tp->rx_queue);
+ atomic_set(&tp->rx_count, 0);
for (i = 0; i < RTL8152_MAX_RX; i++) {
- buf = kmalloc_node(tp->rx_buf_sz, GFP_KERNEL, node);
- if (!buf)
+ if (!alloc_rx_agg(tp, GFP_KERNEL))
goto err1;
-
- if (buf != rx_agg_align(buf)) {
- kfree(buf);
- buf = kmalloc_node(tp->rx_buf_sz + RX_ALIGN, GFP_KERNEL,
- node);
- if (!buf)
- goto err1;
- }
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- kfree(buf);
- goto err1;
- }
-
- INIT_LIST_HEAD(&tp->rx_info[i].list);
- tp->rx_info[i].context = tp;
- tp->rx_info[i].urb = urb;
- tp->rx_info[i].buffer = buf;
- tp->rx_info[i].head = rx_agg_align(buf);
}
for (i = 0; i < RTL8152_MAX_TX; i++) {
+ struct urb *urb;
+ u8 *buf;
+
buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node);
if (!buf)
goto err1;
@@ -2331,44 +2379,64 @@ static void rxdy_gated_en(struct r8152 *tp, bool enable)
static int rtl_start_rx(struct r8152 *tp)
{
- int i, ret = 0;
+ struct rx_agg *agg, *agg_next;
+ struct list_head tmp_list;
+ unsigned long flags;
+ int ret = 0;
- INIT_LIST_HEAD(&tp->rx_done);
- for (i = 0; i < RTL8152_MAX_RX; i++) {
- INIT_LIST_HEAD(&tp->rx_info[i].list);
- ret = r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL);
- if (ret)
- break;
- }
+ INIT_LIST_HEAD(&tmp_list);
- if (ret && ++i < RTL8152_MAX_RX) {
- struct list_head rx_queue;
- unsigned long flags;
+ spin_lock_irqsave(&tp->rx_lock, flags);
- INIT_LIST_HEAD(&rx_queue);
+ INIT_LIST_HEAD(&tp->rx_done);
- do {
- struct rx_agg *agg = &tp->rx_info[i++];
- struct urb *urb = agg->urb;
+ list_splice_init(&tp->rx_info, &tmp_list);
- urb->actual_length = 0;
- list_add_tail(&agg->list, &rx_queue);
- } while (i < RTL8152_MAX_RX);
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
- spin_lock_irqsave(&tp->rx_lock, flags);
- list_splice_tail(&rx_queue, &tp->rx_done);
- spin_unlock_irqrestore(&tp->rx_lock, flags);
+ list_for_each_entry_safe(agg, agg_next, &tmp_list, info_list) {
+ INIT_LIST_HEAD(&agg->list);
+
+ if (ret < 0)
+ list_add_tail(&agg->list, &tp->rx_done);
+ else
+ ret = r8152_submit_rx(tp, agg, GFP_KERNEL);
}
+ spin_lock_irqsave(&tp->rx_lock, flags);
+ WARN_ON(!list_empty(&tp->rx_info));
+ list_splice(&tmp_list, &tp->rx_info);
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
+
return ret;
}
static int rtl_stop_rx(struct r8152 *tp)
{
- int i;
+ struct rx_agg *agg, *agg_next;
+ struct list_head tmp_list;
+ unsigned long flags;
+
+ INIT_LIST_HEAD(&tmp_list);
+
+ /* The usb_kill_urb() couldn't be used in atomic.
+ * Therefore, move the list of rx_info to a tmp one.
+ * Then, list_for_each_entry_safe could be used without
+ * spin lock.
+ */
+
+ spin_lock_irqsave(&tp->rx_lock, flags);
+ list_splice_init(&tp->rx_info, &tmp_list);
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
+
+ list_for_each_entry_safe(agg, agg_next, &tmp_list, info_list)
+ usb_kill_urb(agg->urb);
- for (i = 0; i < RTL8152_MAX_RX; i++)
- usb_kill_urb(tp->rx_info[i].urb);
+ /* Move back the list of temp to the rx_info */
+ spin_lock_irqsave(&tp->rx_lock, flags);
+ WARN_ON(!list_empty(&tp->rx_info));
+ list_splice(&tmp_list, &tp->rx_info);
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
while (!skb_queue_empty(&tp->rx_queue))
dev_kfree_skb(__skb_dequeue(&tp->rx_queue));
--
2.21.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 3/5] r8152: use alloc_pages for rx buffer
2019-08-13 3:42 ` [PATCH net-next v2 0/5] r8152: RX improve Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 1/5] r8152: separate the rx buffer size Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 2/5] r8152: replace array with linking list for rx information Hayes Wang
@ 2019-08-13 3:42 ` Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 4/5] r8152: support skb_add_rx_frag Hayes Wang
` (2 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Hayes Wang @ 2019-08-13 3:42 UTC (permalink / raw)
To: netdev; +Cc: nic_swsd, linux-kernel, linux-usb, Hayes Wang
Replace kmalloc_node() with alloc_pages() for rx buffer.
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
drivers/net/usb/r8152.c | 31 +++++++++++--------------------
1 file changed, 11 insertions(+), 20 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index d063c9b358e5..f41cb728e999 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -698,8 +698,8 @@ struct rx_agg {
struct list_head list, info_list;
struct urb *urb;
struct r8152 *context;
+ struct page *page;
void *buffer;
- void *head;
};
struct tx_agg {
@@ -1476,7 +1476,7 @@ static void free_rx_agg(struct r8152 *tp, struct rx_agg *agg)
list_del(&agg->info_list);
usb_free_urb(agg->urb);
- kfree(agg->buffer);
+ __free_pages(agg->page, get_order(tp->rx_buf_sz));
kfree(agg);
atomic_dec(&tp->rx_count);
@@ -1486,28 +1486,19 @@ static struct rx_agg *alloc_rx_agg(struct r8152 *tp, gfp_t mflags)
{
struct net_device *netdev = tp->netdev;
int node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1;
+ unsigned int order = get_order(tp->rx_buf_sz);
struct rx_agg *rx_agg;
unsigned long flags;
- u8 *buf;
rx_agg = kmalloc_node(sizeof(*rx_agg), mflags, node);
if (!rx_agg)
return NULL;
- buf = kmalloc_node(tp->rx_buf_sz, mflags, node);
- if (!buf)
+ rx_agg->page = alloc_pages(mflags, order);
+ if (!rx_agg->page)
goto free_rx;
- if (buf != rx_agg_align(buf)) {
- kfree(buf);
- buf = kmalloc_node(tp->rx_buf_sz + RX_ALIGN, mflags,
- node);
- if (!buf)
- goto free_rx;
- }
-
- rx_agg->buffer = buf;
- rx_agg->head = rx_agg_align(buf);
+ rx_agg->buffer = page_address(rx_agg->page);
rx_agg->urb = usb_alloc_urb(0, mflags);
if (!rx_agg->urb)
@@ -1526,7 +1517,7 @@ static struct rx_agg *alloc_rx_agg(struct r8152 *tp, gfp_t mflags)
return rx_agg;
free_buf:
- kfree(rx_agg->buffer);
+ __free_pages(rx_agg->page, order);
free_rx:
kfree(rx_agg);
return NULL;
@@ -2003,8 +1994,8 @@ static int rx_bottom(struct r8152 *tp, int budget)
if (urb->actual_length < ETH_ZLEN)
goto submit;
- rx_desc = agg->head;
- rx_data = agg->head;
+ rx_desc = agg->buffer;
+ rx_data = agg->buffer;
len_used += sizeof(struct rx_desc);
while (urb->actual_length > len_used) {
@@ -2051,7 +2042,7 @@ static int rx_bottom(struct r8152 *tp, int budget)
find_next_rx:
rx_data = rx_agg_align(rx_data + pkt_len + ETH_FCS_LEN);
rx_desc = (struct rx_desc *)rx_data;
- len_used = (int)(rx_data - (u8 *)agg->head);
+ len_used = (int)(rx_data - (u8 *)agg->buffer);
len_used += sizeof(struct rx_desc);
}
@@ -2162,7 +2153,7 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
return 0;
usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
- agg->head, tp->rx_buf_sz,
+ agg->buffer, tp->rx_buf_sz,
(usb_complete_t)read_bulk_callback, agg);
ret = usb_submit_urb(agg->urb, mem_flags);
--
2.21.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 4/5] r8152: support skb_add_rx_frag
2019-08-13 3:42 ` [PATCH net-next v2 0/5] r8152: RX improve Hayes Wang
` (2 preceding siblings ...)
2019-08-13 3:42 ` [PATCH net-next v2 3/5] r8152: use alloc_pages for rx buffer Hayes Wang
@ 2019-08-13 3:42 ` Hayes Wang
2019-08-16 6:42 ` Eric Dumazet
2019-08-19 3:15 ` [PATCH net-next] r8152: fix accessing skb after napi_gro_receive Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 5/5] r8152: change rx_copybreak and rx_pending through ethtool Hayes Wang
2019-08-14 1:15 ` [PATCH net-next v2 0/5] r8152: RX improve Jakub Kicinski
5 siblings, 2 replies; 12+ messages in thread
From: Hayes Wang @ 2019-08-13 3:42 UTC (permalink / raw)
To: netdev; +Cc: nic_swsd, linux-kernel, linux-usb, Hayes Wang
Use skb_add_rx_frag() to reduce the memory copy for rx data.
Use a new list of rx_used to store the rx buffer which couldn't be
reused yet.
Besides, the total number of rx buffer may be increased or decreased
dynamically. And it is limited by RTL8152_MAX_RX_AGG.
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
drivers/net/usb/r8152.c | 120 +++++++++++++++++++++++++++++++++++-----
1 file changed, 105 insertions(+), 15 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index f41cb728e999..2ae04522cd5a 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -584,6 +584,9 @@ enum rtl_register_content {
#define TX_ALIGN 4
#define RX_ALIGN 8
+#define RTL8152_MAX_RX_AGG (10 * RTL8152_MAX_RX)
+#define RTL8152_RXFG_HEADSZ 256
+
#define INTR_LINK 0x0004
#define RTL8152_REQT_READ 0xc0
@@ -720,7 +723,7 @@ struct r8152 {
struct net_device *netdev;
struct urb *intr_urb;
struct tx_agg tx_info[RTL8152_MAX_TX];
- struct list_head rx_info;
+ struct list_head rx_info, rx_used;
struct list_head rx_done, tx_free;
struct sk_buff_head tx_queue, rx_queue;
spinlock_t rx_lock, tx_lock;
@@ -1476,7 +1479,7 @@ static void free_rx_agg(struct r8152 *tp, struct rx_agg *agg)
list_del(&agg->info_list);
usb_free_urb(agg->urb);
- __free_pages(agg->page, get_order(tp->rx_buf_sz));
+ put_page(agg->page);
kfree(agg);
atomic_dec(&tp->rx_count);
@@ -1494,7 +1497,7 @@ static struct rx_agg *alloc_rx_agg(struct r8152 *tp, gfp_t mflags)
if (!rx_agg)
return NULL;
- rx_agg->page = alloc_pages(mflags, order);
+ rx_agg->page = alloc_pages(mflags | __GFP_COMP, order);
if (!rx_agg->page)
goto free_rx;
@@ -1947,6 +1950,46 @@ static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc)
return checksum;
}
+static inline bool rx_count_exceed(struct r8152 *tp)
+{
+ return atomic_read(&tp->rx_count) > RTL8152_MAX_RX;
+}
+
+static inline int agg_offset(struct rx_agg *agg, void *addr)
+{
+ return (int)(addr - agg->buffer);
+}
+
+static struct rx_agg *rtl_get_free_rx(struct r8152 *tp, gfp_t mflags)
+{
+ struct rx_agg *agg, *agg_next, *agg_free = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tp->rx_lock, flags);
+
+ list_for_each_entry_safe(agg, agg_next, &tp->rx_used, list) {
+ if (page_count(agg->page) == 1) {
+ if (!agg_free) {
+ list_del_init(&agg->list);
+ agg_free = agg;
+ continue;
+ }
+ if (rx_count_exceed(tp)) {
+ list_del_init(&agg->list);
+ free_rx_agg(tp, agg);
+ }
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
+
+ if (!agg_free && atomic_read(&tp->rx_count) < RTL8152_MAX_RX_AGG)
+ agg_free = alloc_rx_agg(tp, mflags);
+
+ return agg_free;
+}
+
static int rx_bottom(struct r8152 *tp, int budget)
{
unsigned long flags;
@@ -1982,7 +2025,7 @@ static int rx_bottom(struct r8152 *tp, int budget)
list_for_each_safe(cursor, next, &rx_queue) {
struct rx_desc *rx_desc;
- struct rx_agg *agg;
+ struct rx_agg *agg, *agg_free;
int len_used = 0;
struct urb *urb;
u8 *rx_data;
@@ -1994,6 +2037,8 @@ static int rx_bottom(struct r8152 *tp, int budget)
if (urb->actual_length < ETH_ZLEN)
goto submit;
+ agg_free = rtl_get_free_rx(tp, GFP_ATOMIC);
+
rx_desc = agg->buffer;
rx_data = agg->buffer;
len_used += sizeof(struct rx_desc);
@@ -2001,7 +2046,7 @@ static int rx_bottom(struct r8152 *tp, int budget)
while (urb->actual_length > len_used) {
struct net_device *netdev = tp->netdev;
struct net_device_stats *stats = &netdev->stats;
- unsigned int pkt_len;
+ unsigned int pkt_len, rx_frag_head_sz;
struct sk_buff *skb;
/* limite the skb numbers for rx_queue */
@@ -2019,22 +2064,37 @@ static int rx_bottom(struct r8152 *tp, int budget)
pkt_len -= ETH_FCS_LEN;
rx_data += sizeof(struct rx_desc);
- skb = napi_alloc_skb(napi, pkt_len);
+ if (!agg_free || RTL8152_RXFG_HEADSZ > pkt_len)
+ rx_frag_head_sz = pkt_len;
+ else
+ rx_frag_head_sz = RTL8152_RXFG_HEADSZ;
+
+ skb = napi_alloc_skb(napi, rx_frag_head_sz);
if (!skb) {
stats->rx_dropped++;
goto find_next_rx;
}
skb->ip_summed = r8152_rx_csum(tp, rx_desc);
- memcpy(skb->data, rx_data, pkt_len);
- skb_put(skb, pkt_len);
+ memcpy(skb->data, rx_data, rx_frag_head_sz);
+ skb_put(skb, rx_frag_head_sz);
+ pkt_len -= rx_frag_head_sz;
+ rx_data += rx_frag_head_sz;
+ if (pkt_len) {
+ skb_add_rx_frag(skb, 0, agg->page,
+ agg_offset(agg, rx_data),
+ pkt_len,
+ SKB_DATA_ALIGN(pkt_len));
+ get_page(agg->page);
+ }
+
skb->protocol = eth_type_trans(skb, netdev);
rtl_rx_vlan_tag(rx_desc, skb);
if (work_done < budget) {
napi_gro_receive(napi, skb);
work_done++;
stats->rx_packets++;
- stats->rx_bytes += pkt_len;
+ stats->rx_bytes += skb->len;
} else {
__skb_queue_tail(&tp->rx_queue, skb);
}
@@ -2042,10 +2102,24 @@ static int rx_bottom(struct r8152 *tp, int budget)
find_next_rx:
rx_data = rx_agg_align(rx_data + pkt_len + ETH_FCS_LEN);
rx_desc = (struct rx_desc *)rx_data;
- len_used = (int)(rx_data - (u8 *)agg->buffer);
+ len_used = agg_offset(agg, rx_data);
len_used += sizeof(struct rx_desc);
}
+ WARN_ON(!agg_free && page_count(agg->page) > 1);
+
+ if (agg_free) {
+ spin_lock_irqsave(&tp->rx_lock, flags);
+ if (page_count(agg->page) == 1) {
+ list_add(&agg_free->list, &tp->rx_used);
+ } else {
+ list_add_tail(&agg->list, &tp->rx_used);
+ agg = agg_free;
+ urb = agg->urb;
+ }
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
+ }
+
submit:
if (!ret) {
ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
@@ -2373,13 +2447,14 @@ static int rtl_start_rx(struct r8152 *tp)
struct rx_agg *agg, *agg_next;
struct list_head tmp_list;
unsigned long flags;
- int ret = 0;
+ int ret = 0, i = 0;
INIT_LIST_HEAD(&tmp_list);
spin_lock_irqsave(&tp->rx_lock, flags);
INIT_LIST_HEAD(&tp->rx_done);
+ INIT_LIST_HEAD(&tp->rx_used);
list_splice_init(&tp->rx_info, &tmp_list);
@@ -2388,10 +2463,18 @@ static int rtl_start_rx(struct r8152 *tp)
list_for_each_entry_safe(agg, agg_next, &tmp_list, info_list) {
INIT_LIST_HEAD(&agg->list);
- if (ret < 0)
+ /* Only RTL8152_MAX_RX rx_agg need to be submitted. */
+ if (++i > RTL8152_MAX_RX) {
+ spin_lock_irqsave(&tp->rx_lock, flags);
+ list_add_tail(&agg->list, &tp->rx_used);
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
+ } else if (unlikely(ret < 0)) {
+ spin_lock_irqsave(&tp->rx_lock, flags);
list_add_tail(&agg->list, &tp->rx_done);
- else
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
+ } else {
ret = r8152_submit_rx(tp, agg, GFP_KERNEL);
+ }
}
spin_lock_irqsave(&tp->rx_lock, flags);
@@ -2420,8 +2503,15 @@ static int rtl_stop_rx(struct r8152 *tp)
list_splice_init(&tp->rx_info, &tmp_list);
spin_unlock_irqrestore(&tp->rx_lock, flags);
- list_for_each_entry_safe(agg, agg_next, &tmp_list, info_list)
- usb_kill_urb(agg->urb);
+ list_for_each_entry_safe(agg, agg_next, &tmp_list, info_list) {
+ /* At least RTL8152_MAX_RX rx_agg have the page_count being
+ * equal to 1, so the other ones could be freed safely.
+ */
+ if (page_count(agg->page) > 1)
+ free_rx_agg(tp, agg);
+ else
+ usb_kill_urb(agg->urb);
+ }
/* Move back the list of temp to the rx_info */
spin_lock_irqsave(&tp->rx_lock, flags);
--
2.21.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH net-next v2 5/5] r8152: change rx_copybreak and rx_pending through ethtool
2019-08-13 3:42 ` [PATCH net-next v2 0/5] r8152: RX improve Hayes Wang
` (3 preceding siblings ...)
2019-08-13 3:42 ` [PATCH net-next v2 4/5] r8152: support skb_add_rx_frag Hayes Wang
@ 2019-08-13 3:42 ` Hayes Wang
2019-08-14 1:15 ` [PATCH net-next v2 0/5] r8152: RX improve Jakub Kicinski
5 siblings, 0 replies; 12+ messages in thread
From: Hayes Wang @ 2019-08-13 3:42 UTC (permalink / raw)
To: netdev; +Cc: nic_swsd, linux-kernel, linux-usb, Hayes Wang
Let the rx_copybreak and rx_pending could be modified by
ethtool.
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
drivers/net/usb/r8152.c | 91 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 86 insertions(+), 5 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 2ae04522cd5a..40d18e866269 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -26,7 +26,7 @@
#include <linux/acpi.h>
/* Information for net-next */
-#define NETNEXT_VERSION "09"
+#define NETNEXT_VERSION "10"
/* Information for net */
#define NET_VERSION "10"
@@ -584,7 +584,7 @@ enum rtl_register_content {
#define TX_ALIGN 4
#define RX_ALIGN 8
-#define RTL8152_MAX_RX_AGG (10 * RTL8152_MAX_RX)
+#define RTL8152_RX_MAX_PENDING 4096
#define RTL8152_RXFG_HEADSZ 256
#define INTR_LINK 0x0004
@@ -756,6 +756,9 @@ struct r8152 {
u32 tx_qlen;
u32 coalesce;
u32 rx_buf_sz;
+ u32 rx_copybreak;
+ u32 rx_pending;
+
u16 ocp_base;
u16 speed;
u8 *intr_buff;
@@ -1984,7 +1987,7 @@ static struct rx_agg *rtl_get_free_rx(struct r8152 *tp, gfp_t mflags)
spin_unlock_irqrestore(&tp->rx_lock, flags);
- if (!agg_free && atomic_read(&tp->rx_count) < RTL8152_MAX_RX_AGG)
+ if (!agg_free && atomic_read(&tp->rx_count) < tp->rx_pending)
agg_free = alloc_rx_agg(tp, mflags);
return agg_free;
@@ -2064,10 +2067,10 @@ static int rx_bottom(struct r8152 *tp, int budget)
pkt_len -= ETH_FCS_LEN;
rx_data += sizeof(struct rx_desc);
- if (!agg_free || RTL8152_RXFG_HEADSZ > pkt_len)
+ if (!agg_free || tp->rx_copybreak > pkt_len)
rx_frag_head_sz = pkt_len;
else
- rx_frag_head_sz = RTL8152_RXFG_HEADSZ;
+ rx_frag_head_sz = tp->rx_copybreak;
skb = napi_alloc_skb(napi, rx_frag_head_sz);
if (!skb) {
@@ -5104,6 +5107,77 @@ static int rtl8152_set_coalesce(struct net_device *netdev,
return ret;
}
+static int rtl8152_get_tunable(struct net_device *netdev,
+ const struct ethtool_tunable *tunable, void *d)
+{
+ struct r8152 *tp = netdev_priv(netdev);
+
+ switch (tunable->id) {
+ case ETHTOOL_RX_COPYBREAK:
+ *(u32 *)d = tp->rx_copybreak;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int rtl8152_set_tunable(struct net_device *netdev,
+ const struct ethtool_tunable *tunable,
+ const void *d)
+{
+ struct r8152 *tp = netdev_priv(netdev);
+ u32 val;
+
+ switch (tunable->id) {
+ case ETHTOOL_RX_COPYBREAK:
+ val = *(u32 *)d;
+ if (val < ETH_ZLEN) {
+ netif_err(tp, rx_err, netdev,
+ "Invalid rx copy break value\n");
+ return -EINVAL;
+ }
+
+ if (tp->rx_copybreak != val) {
+ napi_disable(&tp->napi);
+ tp->rx_copybreak = val;
+ napi_enable(&tp->napi);
+ }
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static void rtl8152_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct r8152 *tp = netdev_priv(netdev);
+
+ ring->rx_max_pending = RTL8152_RX_MAX_PENDING;
+ ring->rx_pending = tp->rx_pending;
+}
+
+static int rtl8152_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct r8152 *tp = netdev_priv(netdev);
+
+ if (ring->rx_pending < (RTL8152_MAX_RX * 2))
+ return -EINVAL;
+
+ if (tp->rx_pending != ring->rx_pending) {
+ napi_disable(&tp->napi);
+ tp->rx_pending = ring->rx_pending;
+ napi_enable(&tp->napi);
+ }
+
+ return 0;
+}
+
static const struct ethtool_ops ops = {
.get_drvinfo = rtl8152_get_drvinfo,
.get_link = ethtool_op_get_link,
@@ -5121,6 +5195,10 @@ static const struct ethtool_ops ops = {
.set_eee = rtl_ethtool_set_eee,
.get_link_ksettings = rtl8152_get_link_ksettings,
.set_link_ksettings = rtl8152_set_link_ksettings,
+ .get_tunable = rtl8152_get_tunable,
+ .set_tunable = rtl8152_set_tunable,
+ .get_ringparam = rtl8152_get_ringparam,
+ .set_ringparam = rtl8152_set_ringparam,
};
static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -5474,6 +5552,9 @@ static int rtl8152_probe(struct usb_interface *intf,
tp->speed = tp->mii.supports_gmii ? SPEED_1000 : SPEED_100;
tp->duplex = DUPLEX_FULL;
+ tp->rx_copybreak = RTL8152_RXFG_HEADSZ;
+ tp->rx_pending = 10 * RTL8152_MAX_RX;
+
intf->needs_remote_wakeup = 1;
tp->rtl_ops.init(tp);
--
2.21.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH net-next v2 0/5] r8152: RX improve
2019-08-13 3:42 ` [PATCH net-next v2 0/5] r8152: RX improve Hayes Wang
` (4 preceding siblings ...)
2019-08-13 3:42 ` [PATCH net-next v2 5/5] r8152: change rx_copybreak and rx_pending through ethtool Hayes Wang
@ 2019-08-14 1:15 ` Jakub Kicinski
5 siblings, 0 replies; 12+ messages in thread
From: Jakub Kicinski @ 2019-08-14 1:15 UTC (permalink / raw)
To: Hayes Wang; +Cc: netdev, nic_swsd, linux-kernel, linux-usb
On Tue, 13 Aug 2019 11:42:04 +0800, Hayes Wang wrote:
> v2:
> For patch #2, replace list_for_each_safe with list_for_each_entry_safe.
> Remove unlikely in WARN_ON. Adjust the coding style.
>
> For patch #4, replace list_for_each_safe with list_for_each_entry_safe.
> Remove "else" after "continue".
>
> For patch #5. replace sysfs with ethtool to modify rx_copybreak and
> rx_pending.
>
> v1:
> The different chips use different rx buffer size.
>
> Use skb_add_rx_frag() to reduce memory copy for RX.
Applied, thank you.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH net-next v2 4/5] r8152: support skb_add_rx_frag
2019-08-13 3:42 ` [PATCH net-next v2 4/5] r8152: support skb_add_rx_frag Hayes Wang
@ 2019-08-16 6:42 ` Eric Dumazet
2019-08-19 3:15 ` [PATCH net-next] r8152: fix accessing skb after napi_gro_receive Hayes Wang
1 sibling, 0 replies; 12+ messages in thread
From: Eric Dumazet @ 2019-08-16 6:42 UTC (permalink / raw)
To: Hayes Wang, netdev; +Cc: nic_swsd, linux-kernel, linux-usb
On 8/13/19 5:42 AM, Hayes Wang wrote:
> Use skb_add_rx_frag() to reduce the memory copy for rx data.
>
> Use a new list of rx_used to store the rx buffer which couldn't be
> reused yet.
>
> Besides, the total number of rx buffer may be increased or decreased
> dynamically. And it is limited by RTL8152_MAX_RX_AGG.
>
> Signed-off-by: Hayes Wang <hayeswang@realtek.com>
>
...
> skb->protocol = eth_type_trans(skb, netdev);
> rtl_rx_vlan_tag(rx_desc, skb);
> if (work_done < budget) {
> napi_gro_receive(napi, skb);
> work_done++;
> stats->rx_packets++;
> - stats->rx_bytes += pkt_len;
> + stats->rx_bytes += skb->len;
use-after-free. skb is no longer in your hands after napi_gro_receive()
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH net-next] r8152: fix accessing skb after napi_gro_receive
2019-08-13 3:42 ` [PATCH net-next v2 4/5] r8152: support skb_add_rx_frag Hayes Wang
2019-08-16 6:42 ` Eric Dumazet
@ 2019-08-19 3:15 ` Hayes Wang
2019-08-20 1:13 ` David Miller
2019-08-29 16:31 ` Eric Dumazet
1 sibling, 2 replies; 12+ messages in thread
From: Hayes Wang @ 2019-08-19 3:15 UTC (permalink / raw)
To: netdev; +Cc: nic_swsd, linux-kernel, Hayes Wang
Fix accessing skb after napi_gro_receive which is caused by
commit 47922fcde536 ("r8152: support skb_add_rx_frag").
Fixes: 47922fcde536 ("r8152: support skb_add_rx_frag")
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
drivers/net/usb/r8152.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 40d18e866269..b1db6df6f4ab 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -2094,10 +2094,10 @@ static int rx_bottom(struct r8152 *tp, int budget)
skb->protocol = eth_type_trans(skb, netdev);
rtl_rx_vlan_tag(rx_desc, skb);
if (work_done < budget) {
- napi_gro_receive(napi, skb);
work_done++;
stats->rx_packets++;
stats->rx_bytes += skb->len;
+ napi_gro_receive(napi, skb);
} else {
__skb_queue_tail(&tp->rx_queue, skb);
}
--
2.21.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH net-next] r8152: fix accessing skb after napi_gro_receive
2019-08-19 3:15 ` [PATCH net-next] r8152: fix accessing skb after napi_gro_receive Hayes Wang
@ 2019-08-20 1:13 ` David Miller
2019-08-29 16:31 ` Eric Dumazet
1 sibling, 0 replies; 12+ messages in thread
From: David Miller @ 2019-08-20 1:13 UTC (permalink / raw)
To: hayeswang; +Cc: netdev, nic_swsd, linux-kernel
From: Hayes Wang <hayeswang@realtek.com>
Date: Mon, 19 Aug 2019 11:15:19 +0800
> Fix accessing skb after napi_gro_receive which is caused by
> commit 47922fcde536 ("r8152: support skb_add_rx_frag").
>
> Fixes: 47922fcde536 ("r8152: support skb_add_rx_frag")
> Signed-off-by: Hayes Wang <hayeswang@realtek.com>
Applied, thanks.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH net-next] r8152: fix accessing skb after napi_gro_receive
2019-08-19 3:15 ` [PATCH net-next] r8152: fix accessing skb after napi_gro_receive Hayes Wang
2019-08-20 1:13 ` David Miller
@ 2019-08-29 16:31 ` Eric Dumazet
2019-09-02 3:11 ` Hayes Wang
1 sibling, 1 reply; 12+ messages in thread
From: Eric Dumazet @ 2019-08-29 16:31 UTC (permalink / raw)
To: Hayes Wang, netdev; +Cc: nic_swsd, linux-kernel
On 8/19/19 5:15 AM, Hayes Wang wrote:
> Fix accessing skb after napi_gro_receive which is caused by
> commit 47922fcde536 ("r8152: support skb_add_rx_frag").
>
> Fixes: 47922fcde536 ("r8152: support skb_add_rx_frag")
> Signed-off-by: Hayes Wang <hayeswang@realtek.com>
> ---
It is customary to add a tag to credit the reporter...
Something like :
Reported-by: ....
Thanks.
^ permalink raw reply [flat|nested] 12+ messages in thread
* RE: [PATCH net-next] r8152: fix accessing skb after napi_gro_receive
2019-08-29 16:31 ` Eric Dumazet
@ 2019-09-02 3:11 ` Hayes Wang
0 siblings, 0 replies; 12+ messages in thread
From: Hayes Wang @ 2019-09-02 3:11 UTC (permalink / raw)
To: Eric Dumazet, netdev; +Cc: nic_swsd, linux-kernel
Eric Dumazet [mailto:eric.dumazet@gmail.com]
> Sent: Friday, August 30, 2019 12:32 AM
> To: Hayes Wang; netdev@vger.kernel.org
> Cc: nic_swsd; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH net-next] r8152: fix accessing skb after napi_gro_receive
>
> On 8/19/19 5:15 AM, Hayes Wang wrote:
> > Fix accessing skb after napi_gro_receive which is caused by
> > commit 47922fcde536 ("r8152: support skb_add_rx_frag").
> >
> > Fixes: 47922fcde536 ("r8152: support skb_add_rx_frag")
> > Signed-off-by: Hayes Wang <hayeswang@realtek.com>
> > ---
>
> It is customary to add a tag to credit the reporter...
>
> Something like :
>
> Reported-by: ....
>
> Thanks.
Sorry. It's my mistake.
I would note that next time.
Best Regards,
Hayes
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2019-09-02 3:11 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <1394712342-15778-289-Taiwan-albertk@realtek.com>
2019-08-13 3:42 ` [PATCH net-next v2 0/5] r8152: RX improve Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 1/5] r8152: separate the rx buffer size Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 2/5] r8152: replace array with linking list for rx information Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 3/5] r8152: use alloc_pages for rx buffer Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 4/5] r8152: support skb_add_rx_frag Hayes Wang
2019-08-16 6:42 ` Eric Dumazet
2019-08-19 3:15 ` [PATCH net-next] r8152: fix accessing skb after napi_gro_receive Hayes Wang
2019-08-20 1:13 ` David Miller
2019-08-29 16:31 ` Eric Dumazet
2019-09-02 3:11 ` Hayes Wang
2019-08-13 3:42 ` [PATCH net-next v2 5/5] r8152: change rx_copybreak and rx_pending through ethtool Hayes Wang
2019-08-14 1:15 ` [PATCH net-next v2 0/5] r8152: RX improve Jakub Kicinski
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.