The current Gelic Etherenet driver was checking the return value of its
dma_map_single call, and not using the dma_mapping_error() routine.
Fixes runtime problems like these:
DMA-API: ps3_gelic_driver sb_05: device driver failed to check map error
WARNING: CPU: 0 PID: 0 at kernel/dma/debug.c:1027 .check_unmap+0x888/0x8dc
Fixes: 02c1889166b4 (ps3: gigabit ethernet driver for PS3, take3)
Signed-off-by: Geoff Levand <geoff@infradead.org>
---
drivers/net/ethernet/toshiba/ps3_gelic_net.c | 52 ++++++++++----------
1 file changed, 27 insertions(+), 25 deletions(-)
@@ -309,22 +309,34 @@ static int gelic_card_init_chain(struct gelic_card *card,structgelic_descr_chain*chain,structgelic_descr*start_descr,intno){-inti;+structdevice*dev=ctodev(card);structgelic_descr*descr;+inti;-descr=start_descr;-memset(descr,0,sizeof(*descr)*no);+memset(start_descr,0,no*sizeof(*start_descr));/* set up the hardware pointers in each descriptor */-for(i=0;i<no;i++,descr++){+for(i=0,descr=start_descr;i<no;i++,descr++){gelic_descr_set_status(descr,GELIC_DESCR_DMA_NOT_IN_USE);descr->bus_addr=dma_map_single(ctodev(card),descr,GELIC_DESCR_SIZE,DMA_BIDIRECTIONAL);-if(!descr->bus_addr)-gotoiommu_error;+if(unlikely(dma_mapping_error(dev,descr->bus_addr))){+dev_err(dev,"%s:%d: dma_mapping_error\n",__func__,+__LINE__);++for(i--,descr--;i>0;i--,descr--){+if(descr->bus_addr){+dma_unmap_single(ctodev(card),+descr->bus_addr,+GELIC_DESCR_SIZE,+DMA_BIDIRECTIONAL);+}+}+return-ENOMEM;+}descr->next=descr+1;descr->prev=descr-1;
@@ -334,8 +346,7 @@ static int gelic_card_init_chain(struct gelic_card *card,start_descr->prev=(descr-1);/* chain bus addr of hw descriptor */-descr=start_descr;-for(i=0;i<no;i++,descr++){+for(i=0,descr=start_descr;i<no;i++,descr++){descr->next_descr_addr=cpu_to_be32(descr->next->bus_addr);}
@@ -346,14 +357,6 @@ static int gelic_card_init_chain(struct gelic_card *card,(descr-1)->next_descr_addr=0;return0;--iommu_error:-for(i--,descr--;0<=i;i--,descr--)-if(descr->bus_addr)-dma_unmap_single(ctodev(card),descr->bus_addr,-GELIC_DESCR_SIZE,-DMA_BIDIRECTIONAL);-return-ENOMEM;}/**
@@ -407,19 +410,18 @@ static int gelic_descr_prepare_rx(struct gelic_card *card,cpu_addr=dma_map_single(dev,descr->skb->data,descr->buf_size,DMA_FROM_DEVICE);-descr->buf_addr=cpu_to_be32(cpu_addr);--if(!descr->buf_addr){+if(unlikely(dma_mapping_error(dev,cpu_addr))){+dev_err(dev,"%s:%d: dma_mapping_error\n",__func__,__LINE__);dev_kfree_skb_any(descr->skb);descr->buf_addr=0;descr->buf_size=0;descr->skb=NULL;-dev_info(dev,-"%s:Could not iommu-map rx buffer\n",__func__);gelic_descr_set_status(descr,GELIC_DESCR_DMA_NOT_IN_USE);return-ENOMEM;}+descr->buf_addr=cpu_to_be32(cpu_addr);+gelic_descr_set_status(descr,GELIC_DESCR_DMA_CARDOWNED);return0;}
@@ -775,6 +777,7 @@ static int gelic_descr_prepare_tx(struct gelic_card *card,structgelic_descr*descr,structsk_buff*skb){+structdevice*dev=ctodev(card);dma_addr_tbuf;if(card->vlan_required){
The Gelic Ethernet device needs to have the RX sk_buffs aligned to
GELIC_NET_RXBUF_ALIGN and the length of the RX sk_buffs must be a multiple of
GELIC_NET_RXBUF_ALIGN.
The current Gelic Ethernet driver was not allocating sk_buffs large enough to
allow for this alignment.
Fixes various randomly occurring runtime network errors.
Fixes: 02c1889166b4 (ps3: gigabit ethernet driver for PS3, take3)
Signed-off-by: Geoff Levand <geoff@infradead.org>
---
drivers/net/ethernet/toshiba/ps3_gelic_net.c | 56 ++++++++++++--------
1 file changed, 34 insertions(+), 22 deletions(-)
@@ -365,51 +365,63 @@ static int gelic_card_init_chain(struct gelic_card *card,**allocatesanewrxskb,iommu-mapsitandattachesittothedescriptor.*Activatethedescriptorstate-wise+*+*GelicRXsk_buffsmustbealignedtoGELIC_NET_RXBUF_ALIGNandthelength+*mustbeamultipleofGELIC_NET_RXBUF_ALIGN.*/staticintgelic_descr_prepare_rx(structgelic_card*card,structgelic_descr*descr){-intoffset;-unsignedintbufsize;+structdevice*dev=ctodev(card);+struct{+unsignedinttotal_bytes;+unsignedintoffset;+}aligned_buf;+dma_addr_tcpu_addr;if(gelic_descr_get_status(descr)!=GELIC_DESCR_DMA_NOT_IN_USE)dev_info(ctodev(card),"%s: ERROR status\n",__func__);-/* we need to round up the buffer size to a multiple of 128 */-bufsize=ALIGN(GELIC_NET_MAX_MTU,GELIC_NET_RXBUF_ALIGN);-/* and we need to have it 128 byte aligned, therefore we allocate a-*bitmore*/-descr->skb=dev_alloc_skb(bufsize+GELIC_NET_RXBUF_ALIGN-1);+aligned_buf.total_bytes=(GELIC_NET_RXBUF_ALIGN-1)++GELIC_NET_MAX_MTU+(GELIC_NET_RXBUF_ALIGN-1);++descr->skb=dev_alloc_skb(aligned_buf.total_bytes);+if(!descr->skb){-descr->buf_addr=0;/* tell DMAC don't touch memory */+descr->buf_addr=0;return-ENOMEM;}-descr->buf_size=cpu_to_be32(bufsize);++aligned_buf.offset=+PTR_ALIGN(descr->skb->data,GELIC_NET_RXBUF_ALIGN)-+descr->skb->data;++descr->buf_size=ALIGN(GELIC_NET_MAX_MTU,GELIC_NET_RXBUF_ALIGN);descr->dmac_cmd_status=0;descr->result_size=0;descr->valid_size=0;descr->data_error=0;-offset=((unsignedlong)descr->skb->data)&-(GELIC_NET_RXBUF_ALIGN-1);-if(offset)-skb_reserve(descr->skb,GELIC_NET_RXBUF_ALIGN-offset);-/* io-mmu-map the skb */-descr->buf_addr=cpu_to_be32(dma_map_single(ctodev(card),-descr->skb->data,-GELIC_NET_MAX_MTU,-DMA_FROM_DEVICE));+skb_reserve(descr->skb,aligned_buf.offset);++cpu_addr=dma_map_single(dev,descr->skb->data,descr->buf_size,+DMA_FROM_DEVICE);++descr->buf_addr=cpu_to_be32(cpu_addr);+if(!descr->buf_addr){dev_kfree_skb_any(descr->skb);+descr->buf_addr=0;+descr->buf_size=0;descr->skb=NULL;-dev_info(ctodev(card),+dev_info(dev,"%s:Could not iommu-map rx buffer\n",__func__);gelic_descr_set_status(descr,GELIC_DESCR_DMA_NOT_IN_USE);return-ENOMEM;-}else{-gelic_descr_set_status(descr,GELIC_DESCR_DMA_CARDOWNED);-return0;}++gelic_descr_set_status(descr,GELIC_DESCR_DMA_CARDOWNED);+return0;}/**
From: Alexander H Duyck <hidden> Date: 2023-02-06 16:25:24
On Sun, 2023-02-05 at 22:10 +0000, Geoff Levand wrote:
quoted hunk
The Gelic Ethernet device needs to have the RX sk_buffs aligned to
GELIC_NET_RXBUF_ALIGN and the length of the RX sk_buffs must be a multiple of
GELIC_NET_RXBUF_ALIGN.
The current Gelic Ethernet driver was not allocating sk_buffs large enough to
allow for this alignment.
Fixes various randomly occurring runtime network errors.
Fixes: 02c1889166b4 (ps3: gigabit ethernet driver for PS3, take3)
Signed-off-by: Geoff Levand <geoff@infradead.org>
---
drivers/net/ethernet/toshiba/ps3_gelic_net.c | 56 ++++++++++++--------
1 file changed, 34 insertions(+), 22 deletions(-)
@@ -365,51 +365,63 @@ static int gelic_card_init_chain(struct gelic_card *card,**allocatesanewrxskb,iommu-mapsitandattachesittothedescriptor.*Activatethedescriptorstate-wise+*+*GelicRXsk_buffsmustbealignedtoGELIC_NET_RXBUF_ALIGNandthelength+*mustbeamultipleofGELIC_NET_RXBUF_ALIGN.*/staticintgelic_descr_prepare_rx(structgelic_card*card,structgelic_descr*descr){-intoffset;-unsignedintbufsize;+structdevice*dev=ctodev(card);+struct{+unsignedinttotal_bytes;+unsignedintoffset;+}aligned_buf;+dma_addr_tcpu_addr;if(gelic_descr_get_status(descr)!=GELIC_DESCR_DMA_NOT_IN_USE)dev_info(ctodev(card),"%s: ERROR status\n",__func__);-/* we need to round up the buffer size to a multiple of 128 */-bufsize=ALIGN(GELIC_NET_MAX_MTU,GELIC_NET_RXBUF_ALIGN);-/* and we need to have it 128 byte aligned, therefore we allocate a-*bitmore*/-descr->skb=dev_alloc_skb(bufsize+GELIC_NET_RXBUF_ALIGN-1);+aligned_buf.total_bytes=(GELIC_NET_RXBUF_ALIGN-1)++GELIC_NET_MAX_MTU+(GELIC_NET_RXBUF_ALIGN-1);+
This value isn't aligned to anything as there have been no steps taken
to align it. In fact it is guaranteed to be off by 2. Did you maybe
mean to use an "&" somewhere?
Rather than messing with all this it might be easier to just drop
offset in favor of NET_SKB_PAD since that should be offset in all cases
where dev_alloc_skb is being used. With that the reserve could just be
a constant.
From: Alexander H Duyck <hidden> Date: 2023-02-06 16:37:48
On Sun, 2023-02-05 at 22:10 +0000, Geoff Levand wrote:
quoted hunk
The current Gelic Etherenet driver was checking the return value of its
dma_map_single call, and not using the dma_mapping_error() routine.
Fixes runtime problems like these:
DMA-API: ps3_gelic_driver sb_05: device driver failed to check map error
WARNING: CPU: 0 PID: 0 at kernel/dma/debug.c:1027 .check_unmap+0x888/0x8dc
Fixes: 02c1889166b4 (ps3: gigabit ethernet driver for PS3, take3)
Signed-off-by: Geoff Levand <geoff@infradead.org>
---
drivers/net/ethernet/toshiba/ps3_gelic_net.c | 52 ++++++++++----------
1 file changed, 27 insertions(+), 25 deletions(-)
@@ -309,22 +309,34 @@ static int gelic_card_init_chain(struct gelic_card *card,structgelic_descr_chain*chain,structgelic_descr*start_descr,intno){-inti;+structdevice*dev=ctodev(card);structgelic_descr*descr;+inti;-descr=start_descr;-memset(descr,0,sizeof(*descr)*no);+memset(start_descr,0,no*sizeof(*start_descr));/* set up the hardware pointers in each descriptor */-for(i=0;i<no;i++,descr++){+for(i=0,descr=start_descr;i<no;i++,descr++){gelic_descr_set_status(descr,GELIC_DESCR_DMA_NOT_IN_USE);descr->bus_addr=dma_map_single(ctodev(card),descr,GELIC_DESCR_SIZE,DMA_BIDIRECTIONAL);
Are bus_addr and the CPU the same byte ordering? Just wondering since
this is being passed raw. I would have expected it to go through a
cpu_to_be32.
- if (!descr->bus_addr)
- goto iommu_error;
+ if (unlikely(dma_mapping_error(dev, descr->bus_addr))) {
The expectation for dma_mapping_error is that the address is in cpu
order. So in this case it is partially correct since bus_addr wasn't
byte swapped, but generally the dma address used should be a CPU byte
ordered variable.
+ dev_err(dev, "%s:%d: dma_mapping_error\n", __func__,
+ __LINE__);
+
+ for (i--, descr--; i > 0; i--, descr--) {
+ if (descr->bus_addr) {
So I am pretty sure this is broken. Usually for something like this I
will resort to just doing a while (i--) as "i == 0" should be a valid
buffer to have to unmap.
Maybe something like:
while (i--) {
descr--;
Also I think you can get rid of the if since descr->bus_addr should be
valid for all values since you populated it just a few lines above for
each value of i.
Hi Alexander,
Thanks for the review.
On 2/6/23 08:25, Alexander H Duyck wrote:
On Sun, 2023-02-05 at 22:10 +0000, Geoff Levand wrote:
quoted
The Gelic Ethernet device needs to have the RX sk_buffs aligned to
GELIC_NET_RXBUF_ALIGN and the length of the RX sk_buffs must be a multiple of
GELIC_NET_RXBUF_ALIGN.
quoted
static int gelic_descr_prepare_rx(struct gelic_card *card,
struct gelic_descr *descr)
{
- int offset;
- unsigned int bufsize;
+ struct device *dev = ctodev(card);
+ struct {
+ unsigned int total_bytes;
+ unsigned int offset;
+ } aligned_buf;
+ dma_addr_t cpu_addr;
if (gelic_descr_get_status(descr) != GELIC_DESCR_DMA_NOT_IN_USE)
dev_info(ctodev(card), "%s: ERROR status\n", __func__);
- /* we need to round up the buffer size to a multiple of 128 */
- bufsize = ALIGN(GELIC_NET_MAX_MTU, GELIC_NET_RXBUF_ALIGN);
- /* and we need to have it 128 byte aligned, therefore we allocate a
- * bit more */
- descr->skb = dev_alloc_skb(bufsize + GELIC_NET_RXBUF_ALIGN - 1);
+ aligned_buf.total_bytes = (GELIC_NET_RXBUF_ALIGN - 1) +
+ GELIC_NET_MAX_MTU + (GELIC_NET_RXBUF_ALIGN - 1);
+
This value isn't aligned to anything as there have been no steps taken
to align it. In fact it is guaranteed to be off by 2. Did you maybe
mean to use an "&" somewhere?
total_bytes here means the total number of bytes to allocate that will
allow for the desired alignment. This value a bit too much though since
we really just need it to end on a GELIC_NET_RXBUF_ALIGN boundary, so
adding ALIGN(GELIC_NET_MAX_MTU, GELIC_NET_RXBUF_ALIGN) should be enough.
I'll fix that in the next patch version.
Rather than messing with all this it might be easier to just drop
offset in favor of NET_SKB_PAD since that should be offset in all cases
where dev_alloc_skb is being used. With that the reserve could just be
a constant.
GELIC_NET_RXBUF_ALIGN is a property of the gelic hardware device. I
would think if NET_SKB_PAD would work it would just be by coincidence.
Hi Alexander,
On 2/6/23 08:37, Alexander H Duyck wrote:
On Sun, 2023-02-05 at 22:10 +0000, Geoff Levand wrote:
quoted
The current Gelic Etherenet driver was checking the return value of its
dma_map_single call, and not using the dma_mapping_error() routine.
Fixes runtime problems like these:
DMA-API: ps3_gelic_driver sb_05: device driver failed to check map error
WARNING: CPU: 0 PID: 0 at kernel/dma/debug.c:1027 .check_unmap+0x888/0x8dc
Fixes: 02c1889166b4 (ps3: gigabit ethernet driver for PS3, take3)
Signed-off-by: Geoff Levand <geoff@infradead.org>
---
drivers/net/ethernet/toshiba/ps3_gelic_net.c | 52 ++++++++++----------
1 file changed, 27 insertions(+), 25 deletions(-)
@@ -309,22 +309,34 @@ static int gelic_card_init_chain(struct gelic_card *card,structgelic_descr_chain*chain,structgelic_descr*start_descr,intno){-inti;+structdevice*dev=ctodev(card);structgelic_descr*descr;+inti;-descr=start_descr;-memset(descr,0,sizeof(*descr)*no);+memset(start_descr,0,no*sizeof(*start_descr));/* set up the hardware pointers in each descriptor */-for(i=0;i<no;i++,descr++){+for(i=0,descr=start_descr;i<no;i++,descr++){gelic_descr_set_status(descr,GELIC_DESCR_DMA_NOT_IN_USE);descr->bus_addr=dma_map_single(ctodev(card),descr,GELIC_DESCR_SIZE,DMA_BIDIRECTIONAL);
Are bus_addr and the CPU the same byte ordering? Just wondering since
this is being passed raw. I would have expected it to go through a
cpu_to_be32.
As I mentioned in my reply to the first patch, the PS3's CPU is
big endian, so we really don't need any of the endian conversions.
quoted
- if (!descr->bus_addr)
- goto iommu_error;
+ if (unlikely(dma_mapping_error(dev, descr->bus_addr))) {
The expectation for dma_mapping_error is that the address is in cpu
order. So in this case it is partially correct since bus_addr wasn't
byte swapped, but generally the dma address used should be a CPU byte
ordered variable.
quoted
+ dev_err(dev, "%s:%d: dma_mapping_error\n", __func__,
+ __LINE__);
+
+ for (i--, descr--; i > 0; i--, descr--) {
+ if (descr->bus_addr) {
So I am pretty sure this is broken. Usually for something like this I
will resort to just doing a while (i--) as "i == 0" should be a valid
buffer to have to unmap.
Maybe something like:
while (i--) {
descr--;
Also I think you can get rid of the if since descr->bus_addr should be
valid for all values since you populated it just a few lines above for
each value of i.
From: Alexander Duyck <hidden> Date: 2023-02-13 15:15:04
On Sun, Feb 12, 2023 at 9:06 AM Geoff Levand [off-list ref] wrote:
Hi Alexander,
Thanks for the review.
On 2/6/23 08:25, Alexander H Duyck wrote:
quoted
On Sun, 2023-02-05 at 22:10 +0000, Geoff Levand wrote:
quoted
The Gelic Ethernet device needs to have the RX sk_buffs aligned to
GELIC_NET_RXBUF_ALIGN and the length of the RX sk_buffs must be a multiple of
GELIC_NET_RXBUF_ALIGN.
quoted
quoted
static int gelic_descr_prepare_rx(struct gelic_card *card,
struct gelic_descr *descr)
{
- int offset;
- unsigned int bufsize;
+ struct device *dev = ctodev(card);
+ struct {
+ unsigned int total_bytes;
+ unsigned int offset;
+ } aligned_buf;
+ dma_addr_t cpu_addr;
if (gelic_descr_get_status(descr) != GELIC_DESCR_DMA_NOT_IN_USE)
dev_info(ctodev(card), "%s: ERROR status\n", __func__);
- /* we need to round up the buffer size to a multiple of 128 */
- bufsize = ALIGN(GELIC_NET_MAX_MTU, GELIC_NET_RXBUF_ALIGN);
- /* and we need to have it 128 byte aligned, therefore we allocate a
- * bit more */
- descr->skb = dev_alloc_skb(bufsize + GELIC_NET_RXBUF_ALIGN - 1);
+ aligned_buf.total_bytes = (GELIC_NET_RXBUF_ALIGN - 1) +
+ GELIC_NET_MAX_MTU + (GELIC_NET_RXBUF_ALIGN - 1);
+
This value isn't aligned to anything as there have been no steps taken
to align it. In fact it is guaranteed to be off by 2. Did you maybe
mean to use an "&" somewhere?
total_bytes here means the total number of bytes to allocate that will
allow for the desired alignment. This value a bit too much though since
we really just need it to end on a GELIC_NET_RXBUF_ALIGN boundary, so
adding ALIGN(GELIC_NET_MAX_MTU, GELIC_NET_RXBUF_ALIGN) should be enough.
I'll fix that in the next patch version.
Originally this was being written using cpu_to_be32. WIth this you are
writing it raw w/ the cpu endianness. Is there a byte ordering issue
here?
No. The PS3 has a big endian CPU, so we really don't need any
of the endian conversions.
This doesn't introduce an ordering error, but it introduces a type
error. The bufsize variable was defined as a CPU ordered variable
whereas buf_size is a __be32. If you enable sparse checking it should
return an error.
I would recommend keeping the cpu_to_be32. If your architecture is big
endian it will do nothing and add no overhead. If at some point in the
future someone were to plug this IP into another architecture it would
take care of sorting out the byte ordering for you.
Rather than messing with all this it might be easier to just drop
offset in favor of NET_SKB_PAD since that should be offset in all cases
where dev_alloc_skb is being used. With that the reserve could just be
a constant.
GELIC_NET_RXBUF_ALIGN is a property of the gelic hardware device. I
would think if NET_SKB_PAD would work it would just be by coincidence.
NET_SKB_PAD is the alignment generated when you use dev_alloc_skb.
What I was getting at is that "offset" could probably be removed in
favor of just using NET_SKB_PAD.
From: Alexander Duyck <hidden> Date: 2023-02-13 15:21:43
On Sun, Feb 12, 2023 at 9:06 AM Geoff Levand [off-list ref] wrote:
Hi Alexander,
On 2/6/23 08:37, Alexander H Duyck wrote:
quoted
On Sun, 2023-02-05 at 22:10 +0000, Geoff Levand wrote:
quoted
The current Gelic Etherenet driver was checking the return value of its
dma_map_single call, and not using the dma_mapping_error() routine.
Fixes runtime problems like these:
DMA-API: ps3_gelic_driver sb_05: device driver failed to check map error
WARNING: CPU: 0 PID: 0 at kernel/dma/debug.c:1027 .check_unmap+0x888/0x8dc
Fixes: 02c1889166b4 (ps3: gigabit ethernet driver for PS3, take3)
Signed-off-by: Geoff Levand <geoff@infradead.org>
---
drivers/net/ethernet/toshiba/ps3_gelic_net.c | 52 ++++++++++----------
1 file changed, 27 insertions(+), 25 deletions(-)
@@ -309,22 +309,34 @@ static int gelic_card_init_chain(struct gelic_card *card,structgelic_descr_chain*chain,structgelic_descr*start_descr,intno){-inti;+structdevice*dev=ctodev(card);structgelic_descr*descr;+inti;-descr=start_descr;-memset(descr,0,sizeof(*descr)*no);+memset(start_descr,0,no*sizeof(*start_descr));/* set up the hardware pointers in each descriptor */-for(i=0;i<no;i++,descr++){+for(i=0,descr=start_descr;i<no;i++,descr++){gelic_descr_set_status(descr,GELIC_DESCR_DMA_NOT_IN_USE);descr->bus_addr=dma_map_single(ctodev(card),descr,GELIC_DESCR_SIZE,DMA_BIDIRECTIONAL);
Are bus_addr and the CPU the same byte ordering? Just wondering since
this is being passed raw. I would have expected it to go through a
cpu_to_be32.
As I mentioned in my reply to the first patch, the PS3's CPU is
big endian, so we really don't need any of the endian conversions.
My advice would be to still make use of the cpu_to_be32 macros. It
will take care of any possible byte ordering issues should you work
with a different CPU architecture in the future. Otherwise if you are
certain that the values will always be CPU ordered you might try
changing the type rather than using __be32 for your descriptor
variable types.
For example most PCIe hardware is using a little endian architecture
and on x86 we don't need to do the byte swapping since the cpu is
little endian. However we still use cpu_to_le32 throughout most
drivers.
You might read through the documentation for sparse at:
https://www.kernel.org/doc/html/latest/dev-tools/sparse.html