Skip to content

Commit 757d86b

Browse files
aurel32jukkar
authored andcommitted
drivers: eth: gmac: keep a reference to the packet fragments
The SAM GMAC Ethernet driver uses scatter gather DMA to transmit data. Each fragment of a network packet is mapped from a set of descriptors that is used by the controller to do the DMA transfer. This means that the packet is not necessary sent when the send() function returns. For that reason the driver calls net_pkt_ref() on the packet to prevent it from being freed. It is then unreferenced with net_pkt_unref() in the TX ISR when the packet has effectively been sent. However this doesn't work if the packet is modified in the meantime, like it will be done in PR #12563 to remove the Ethernet header contained in the first fragment. To avoid that, call net_pkt_frag_ref() on each fragment of the packet, and unreferenced them with net_pkt_frag_unref() in the TX ISR when the packet has effectively been sent. Signed-off-by: Aurelien Jarno <[email protected]>
1 parent 2c3ecd8 commit 757d86b

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

drivers/ethernet/eth_sam_gmac.c

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@ static struct net_buf *rx_frag_list_que1[PRIORITY_QUEUE1_RX_DESC_COUNT];
103103
#if GMAC_PRIORITY_QUEUE_NO == 2
104104
static struct net_buf *rx_frag_list_que2[PRIORITY_QUEUE2_RX_DESC_COUNT];
105105
#endif
106+
/* TX buffer accounting list */
107+
static struct net_buf *tx_frag_list_que0[MAIN_QUEUE_TX_DESC_COUNT];
108+
#if GMAC_PRIORITY_QUEUE_NO >= 1
109+
static struct net_buf *tx_frag_list_que1[PRIORITY_QUEUE1_TX_DESC_COUNT];
110+
#endif
111+
#if GMAC_PRIORITY_QUEUE_NO == 2
112+
static struct net_buf *tx_frag_list_que2[PRIORITY_QUEUE2_TX_DESC_COUNT];
113+
#endif
106114
/* TX frames accounting list */
107115
static struct net_pkt *tx_frame_list_que0[CONFIG_NET_PKT_TX_COUNT + 1];
108116
#if GMAC_PRIORITY_QUEUE_NO >= 1
@@ -274,6 +282,7 @@ static void tx_descriptors_init(Gmac *gmac, struct gmac_queue *queue)
274282
tx_desc_list->buf[tx_desc_list->len - 1].w1 |= GMAC_TXW1_WRAP;
275283

276284
/* Reset TX frame list */
285+
ring_buf_reset(&queue->tx_frag_list);
277286
ring_buf_reset(&queue->tx_frames);
278287
}
279288

@@ -474,6 +483,7 @@ static void tx_completed(Gmac *gmac, struct gmac_queue *queue)
474483
{
475484
struct gmac_desc_list *tx_desc_list = &queue->tx_desc_list;
476485
struct gmac_desc *tx_desc;
486+
struct net_buf *frag;
477487
struct net_pkt *pkt;
478488
#if defined(CONFIG_PTP_CLOCK_SAM_GMAC)
479489
u16_t vlan_tag = NET_VLAN_TAG_UNSPEC;
@@ -492,8 +502,13 @@ static void tx_completed(Gmac *gmac, struct gmac_queue *queue)
492502
MODULO_INC(tx_desc_list->tail, tx_desc_list->len);
493503
k_sem_give(&queue->tx_desc_sem);
494504

505+
/* Release net buffer to the buffer pool */
506+
frag = UINT_TO_POINTER(ring_buf_get(&queue->tx_frag_list));
507+
net_pkt_frag_unref(frag);
508+
LOG_DBG("Dropping frag %p", frag);
509+
495510
if (tx_desc->w1 & GMAC_TXW1_LASTBUFFER) {
496-
/* Release net buffer to the buffer pool */
511+
/* Release net packet to the packet pool */
497512
pkt = UINT_TO_POINTER(ring_buf_get(&queue->tx_frames));
498513
#if defined(CONFIG_PTP_CLOCK_SAM_GMAC)
499514
#if defined(CONFIG_NET_VLAN)
@@ -526,16 +541,27 @@ static void tx_completed(Gmac *gmac, struct gmac_queue *queue)
526541
static void tx_error_handler(Gmac *gmac, struct gmac_queue *queue)
527542
{
528543
struct net_pkt *pkt;
544+
struct net_buf *frag;
545+
struct ring_buf *tx_frag_list = &queue->tx_frag_list;
529546
struct ring_buf *tx_frames = &queue->tx_frames;
530547

531548
queue->err_tx_flushed_count++;
532549

533550
/* Stop transmission, clean transmit pipeline and control registers */
534551
gmac->GMAC_NCR &= ~GMAC_NCR_TXEN;
535552

553+
/* Free all frag resources in the TX path */
554+
while (tx_frag_list->tail != tx_frag_list->head) {
555+
/* Release net buffer to the buffer pool */
556+
frag = UINT_TO_POINTER(tx_frag_list->buf[tx_frag_list->tail]);
557+
net_pkt_frag_unref(frag);
558+
LOG_DBG("Dropping frag %p", frag);
559+
MODULO_INC(tx_frag_list->tail, tx_frag_list->len);
560+
}
561+
536562
/* Free all pkt resources in the TX path */
537563
while (tx_frames->tail != tx_frames->head) {
538-
/* Release net buffer to the buffer pool */
564+
/* Release net packet to the packet pool */
539565
pkt = UINT_TO_POINTER(tx_frames->buf[tx_frames->tail]);
540566
net_pkt_unref(pkt);
541567
LOG_DBG("Dropping pkt %p", pkt);
@@ -1306,6 +1332,12 @@ static int eth_tx(struct device *dev, struct net_pkt *pkt)
13061332
__ASSERT(tx_desc_list->head != tx_desc_list->tail,
13071333
"tx_desc_list overflow");
13081334

1335+
/* Account for a sent frag */
1336+
ring_buf_put(&queue->tx_frag_list, POINTER_TO_UINT(frag));
1337+
1338+
/* frag is internally queued, so it requires to hold a reference */
1339+
net_pkt_frag_ref(frag);
1340+
13091341
irq_unlock(key);
13101342

13111343
/* Continue with the rest of fragments (only data) */
@@ -1860,6 +1892,10 @@ static struct eth_sam_dev_data eth0_data = {
18601892
.buf = (u32_t *)rx_frag_list_que0,
18611893
.len = ARRAY_SIZE(rx_frag_list_que0),
18621894
},
1895+
.tx_frag_list = {
1896+
.buf = (u32_t *)tx_frag_list_que0,
1897+
.len = ARRAY_SIZE(tx_frag_list_que0),
1898+
},
18631899
.tx_frames = {
18641900
.buf = (u32_t *)tx_frame_list_que0,
18651901
.len = ARRAY_SIZE(tx_frame_list_que0),
@@ -1879,6 +1915,10 @@ static struct eth_sam_dev_data eth0_data = {
18791915
.buf = (u32_t *)rx_frag_list_que1,
18801916
.len = ARRAY_SIZE(rx_frag_list_que1),
18811917
},
1918+
.tx_frag_list = {
1919+
.buf = (u32_t *)tx_frag_list_que1,
1920+
.len = ARRAY_SIZE(tx_frag_list_que1),
1921+
},
18821922
.tx_frames = {
18831923
.buf = (u32_t *)tx_frame_list_que1,
18841924
.len = ARRAY_SIZE(tx_frame_list_que1),
@@ -1899,6 +1939,10 @@ static struct eth_sam_dev_data eth0_data = {
18991939
.buf = (u32_t *)rx_frag_list_que2,
19001940
.len = ARRAY_SIZE(rx_frag_list_que2),
19011941
},
1942+
.tx_frag_list = {
1943+
.buf = (u32_t *)tx_frag_list_que2,
1944+
.len = ARRAY_SIZE(tx_frag_list_que2),
1945+
},
19021946
.tx_frames = {
19031947
.buf = (u32_t *)tx_frame_list_que2,
19041948
.len = ARRAY_SIZE(tx_frame_list_que2),

drivers/ethernet/eth_sam_gmac_priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ struct gmac_queue {
170170
struct k_sem tx_desc_sem;
171171

172172
struct ring_buf rx_frag_list;
173+
struct ring_buf tx_frag_list;
173174
struct ring_buf tx_frames;
174175

175176
/** Number of RX frames dropped by the driver */

0 commit comments

Comments
 (0)