Skip to content

Commit c600636

Browse files
HananiaAmirJeff Kirsher
authored andcommitted
ixgbe: work around for DDP last buffer size
A HW limitation was recently discovered where the last buffer in a DDP offload cannot be a full buffer size in length. Fix the issue with a work around by adding another buffer with size = 1. Signed-off-by: Amir Hanania <amir.hanania@intel.com> Tested-by: Ross Brattain <ross.b.brattain@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
1 parent 4c7e604 commit c600636

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

drivers/net/ixgbe/ixgbe_fcoe.c

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
159159
struct scatterlist *sg;
160160
unsigned int i, j, dmacount;
161161
unsigned int len;
162-
static const unsigned int bufflen = 4096;
162+
static const unsigned int bufflen = IXGBE_FCBUFF_MIN;
163163
unsigned int firstoff = 0;
164164
unsigned int lastsize;
165165
unsigned int thisoff = 0;
@@ -254,6 +254,24 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
254254
/* only the last buffer may have non-full bufflen */
255255
lastsize = thisoff + thislen;
256256

257+
/*
258+
* lastsize can not be buffer len.
259+
* If it is then adding another buffer with lastsize = 1.
260+
*/
261+
if (lastsize == bufflen) {
262+
if (j >= IXGBE_BUFFCNT_MAX) {
263+
e_err(drv, "xid=%x:%d,%d,%d:addr=%llx "
264+
"not enough user buffers. We need an extra "
265+
"buffer because lastsize is bufflen.\n",
266+
xid, i, j, dmacount, (u64)addr);
267+
goto out_noddp_free;
268+
}
269+
270+
ddp->udl[j] = (u64)(fcoe->extra_ddp_buffer_dma);
271+
j++;
272+
lastsize = 1;
273+
}
274+
257275
fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT);
258276
fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT);
259277
fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT);
@@ -532,6 +550,24 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
532550
e_err(drv, "failed to allocated FCoE DDP pool\n");
533551

534552
spin_lock_init(&fcoe->lock);
553+
554+
/* Extra buffer to be shared by all DDPs for HW work around */
555+
fcoe->extra_ddp_buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_ATOMIC);
556+
if (fcoe->extra_ddp_buffer == NULL) {
557+
e_err(drv, "failed to allocated extra DDP buffer\n");
558+
goto out_extra_ddp_buffer_alloc;
559+
}
560+
561+
fcoe->extra_ddp_buffer_dma =
562+
dma_map_single(&adapter->pdev->dev,
563+
fcoe->extra_ddp_buffer,
564+
IXGBE_FCBUFF_MIN,
565+
DMA_FROM_DEVICE);
566+
if (dma_mapping_error(&adapter->pdev->dev,
567+
fcoe->extra_ddp_buffer_dma)) {
568+
e_err(drv, "failed to map extra DDP buffer\n");
569+
goto out_extra_ddp_buffer_dma;
570+
}
535571
}
536572

537573
/* Enable L2 eth type filter for FCoE */
@@ -581,6 +617,14 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
581617
}
582618
}
583619
#endif
620+
621+
return;
622+
623+
out_extra_ddp_buffer_dma:
624+
kfree(fcoe->extra_ddp_buffer);
625+
out_extra_ddp_buffer_alloc:
626+
pci_pool_destroy(fcoe->pool);
627+
fcoe->pool = NULL;
584628
}
585629

586630
/**
@@ -600,6 +644,11 @@ void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter)
600644
if (fcoe->pool) {
601645
for (i = 0; i < IXGBE_FCOE_DDP_MAX; i++)
602646
ixgbe_fcoe_ddp_put(adapter->netdev, i);
647+
dma_unmap_single(&adapter->pdev->dev,
648+
fcoe->extra_ddp_buffer_dma,
649+
IXGBE_FCBUFF_MIN,
650+
DMA_FROM_DEVICE);
651+
kfree(fcoe->extra_ddp_buffer);
603652
pci_pool_destroy(fcoe->pool);
604653
fcoe->pool = NULL;
605654
}

drivers/net/ixgbe/ixgbe_fcoe.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ struct ixgbe_fcoe {
7070
spinlock_t lock;
7171
struct pci_pool *pool;
7272
struct ixgbe_fcoe_ddp ddp[IXGBE_FCOE_DDP_MAX];
73+
unsigned char *extra_ddp_buffer;
74+
dma_addr_t extra_ddp_buffer_dma;
7375
};
7476

7577
#endif /* _IXGBE_FCOE_H */

0 commit comments

Comments
 (0)