Skip to content

Commit c754568

Browse files
Pavel Belousdavem330
authored andcommitted
atlantic: fix iommu errors
Call skb_frag_dma_map multiple times if tx length is greater than device max and avoid processing tx ring until entire packet has been sent. Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com> Signed-off-by: Pavel Belous <pavel.belous@aquantia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent a7bb1be commit c754568

File tree

3 files changed

+49
-27
lines changed

3 files changed

+49
-27
lines changed

drivers/net/ethernet/aquantia/atlantic/aq_nic.c

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ static unsigned int aq_nic_map_skb(struct aq_nic_s *self,
473473
unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
474474
unsigned int frag_count = 0U;
475475
unsigned int dx = ring->sw_tail;
476+
struct aq_ring_buff_s *first = NULL;
476477
struct aq_ring_buff_s *dx_buff = &ring->buff_ring[dx];
477478

478479
if (unlikely(skb_is_gso(skb))) {
@@ -483,6 +484,7 @@ static unsigned int aq_nic_map_skb(struct aq_nic_s *self,
483484
dx_buff->len_l4 = tcp_hdrlen(skb);
484485
dx_buff->mss = skb_shinfo(skb)->gso_size;
485486
dx_buff->is_txc = 1U;
487+
dx_buff->eop_index = 0xffffU;
486488

487489
dx_buff->is_ipv6 =
488490
(ip_hdr(skb)->version == 6) ? 1U : 0U;
@@ -502,6 +504,7 @@ static unsigned int aq_nic_map_skb(struct aq_nic_s *self,
502504
if (unlikely(dma_mapping_error(aq_nic_get_dev(self), dx_buff->pa)))
503505
goto exit;
504506

507+
first = dx_buff;
505508
dx_buff->len_pkt = skb->len;
506509
dx_buff->is_sop = 1U;
507510
dx_buff->is_mapped = 1U;
@@ -530,40 +533,46 @@ static unsigned int aq_nic_map_skb(struct aq_nic_s *self,
530533

531534
for (; nr_frags--; ++frag_count) {
532535
unsigned int frag_len = 0U;
536+
unsigned int buff_offset = 0U;
537+
unsigned int buff_size = 0U;
533538
dma_addr_t frag_pa;
534539
skb_frag_t *frag = &skb_shinfo(skb)->frags[frag_count];
535540

536541
frag_len = skb_frag_size(frag);
537-
frag_pa = skb_frag_dma_map(aq_nic_get_dev(self), frag, 0,
538-
frag_len, DMA_TO_DEVICE);
539542

540-
if (unlikely(dma_mapping_error(aq_nic_get_dev(self), frag_pa)))
541-
goto mapping_error;
543+
while (frag_len) {
544+
if (frag_len > AQ_CFG_TX_FRAME_MAX)
545+
buff_size = AQ_CFG_TX_FRAME_MAX;
546+
else
547+
buff_size = frag_len;
548+
549+
frag_pa = skb_frag_dma_map(aq_nic_get_dev(self),
550+
frag,
551+
buff_offset,
552+
buff_size,
553+
DMA_TO_DEVICE);
554+
555+
if (unlikely(dma_mapping_error(aq_nic_get_dev(self),
556+
frag_pa)))
557+
goto mapping_error;
542558

543-
while (frag_len > AQ_CFG_TX_FRAME_MAX) {
544559
dx = aq_ring_next_dx(ring, dx);
545560
dx_buff = &ring->buff_ring[dx];
546561

547562
dx_buff->flags = 0U;
548-
dx_buff->len = AQ_CFG_TX_FRAME_MAX;
563+
dx_buff->len = buff_size;
549564
dx_buff->pa = frag_pa;
550565
dx_buff->is_mapped = 1U;
566+
dx_buff->eop_index = 0xffffU;
567+
568+
frag_len -= buff_size;
569+
buff_offset += buff_size;
551570

552-
frag_len -= AQ_CFG_TX_FRAME_MAX;
553-
frag_pa += AQ_CFG_TX_FRAME_MAX;
554571
++ret;
555572
}
556-
557-
dx = aq_ring_next_dx(ring, dx);
558-
dx_buff = &ring->buff_ring[dx];
559-
560-
dx_buff->flags = 0U;
561-
dx_buff->len = frag_len;
562-
dx_buff->pa = frag_pa;
563-
dx_buff->is_mapped = 1U;
564-
++ret;
565573
}
566574

575+
first->eop_index = dx;
567576
dx_buff->is_eop = 1U;
568577
dx_buff->skb = skb;
569578
goto exit;

drivers/net/ethernet/aquantia/atlantic/aq_ring.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ int aq_ring_init(struct aq_ring_s *self)
104104
return 0;
105105
}
106106

107+
static inline bool aq_ring_dx_in_range(unsigned int h, unsigned int i,
108+
unsigned int t)
109+
{
110+
return (h < t) ? ((h < i) && (i < t)) : ((h < i) || (i < t));
111+
}
112+
107113
void aq_ring_update_queue_state(struct aq_ring_s *ring)
108114
{
109115
if (aq_ring_avail_dx(ring) <= AQ_CFG_SKB_FRAGS_MAX)
@@ -139,23 +145,28 @@ void aq_ring_tx_clean(struct aq_ring_s *self)
139145
struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
140146

141147
if (likely(buff->is_mapped)) {
142-
if (unlikely(buff->is_sop))
148+
if (unlikely(buff->is_sop)) {
149+
if (!buff->is_eop &&
150+
buff->eop_index != 0xffffU &&
151+
(!aq_ring_dx_in_range(self->sw_head,
152+
buff->eop_index,
153+
self->hw_head)))
154+
break;
155+
143156
dma_unmap_single(dev, buff->pa, buff->len,
144157
DMA_TO_DEVICE);
145-
else
158+
} else {
146159
dma_unmap_page(dev, buff->pa, buff->len,
147160
DMA_TO_DEVICE);
161+
}
148162
}
149163

150164
if (unlikely(buff->is_eop))
151165
dev_kfree_skb_any(buff->skb);
152-
}
153-
}
154166

155-
static inline unsigned int aq_ring_dx_in_range(unsigned int h, unsigned int i,
156-
unsigned int t)
157-
{
158-
return (h < t) ? ((h < i) && (i < t)) : ((h < i) || (i < t));
167+
buff->pa = 0U;
168+
buff->eop_index = 0xffffU;
169+
}
159170
}
160171

161172
#define AQ_SKB_ALIGN SKB_DATA_ALIGN(sizeof(struct skb_shared_info))

drivers/net/ethernet/aquantia/atlantic/aq_ring.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ struct __packed aq_ring_buff_s {
6565
};
6666
union {
6767
struct {
68-
u32 len:16;
68+
u16 len;
6969
u32 is_ip_cso:1;
7070
u32 is_udp_cso:1;
7171
u32 is_tcp_cso:1;
@@ -77,8 +77,10 @@ struct __packed aq_ring_buff_s {
7777
u32 is_cleaned:1;
7878
u32 is_error:1;
7979
u32 rsvd3:6;
80+
u16 eop_index;
81+
u16 rsvd4;
8082
};
81-
u32 flags;
83+
u64 flags;
8284
};
8385
};
8486

0 commit comments

Comments
 (0)