|
@@ -159,7 +159,7 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
|
|
|
struct scatterlist *sg;
|
|
|
unsigned int i, j, dmacount;
|
|
|
unsigned int len;
|
|
|
- static const unsigned int bufflen = 4096;
|
|
|
+ static const unsigned int bufflen = IXGBE_FCBUFF_MIN;
|
|
|
unsigned int firstoff = 0;
|
|
|
unsigned int lastsize;
|
|
|
unsigned int thisoff = 0;
|
|
@@ -254,6 +254,24 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
|
|
|
/* only the last buffer may have non-full bufflen */
|
|
|
lastsize = thisoff + thislen;
|
|
|
|
|
|
+ /*
|
|
|
+ * lastsize can not be buffer len.
|
|
|
+ * If it is then adding another buffer with lastsize = 1.
|
|
|
+ */
|
|
|
+ if (lastsize == bufflen) {
|
|
|
+ if (j >= IXGBE_BUFFCNT_MAX) {
|
|
|
+ e_err(drv, "xid=%x:%d,%d,%d:addr=%llx "
|
|
|
+ "not enough user buffers. We need an extra "
|
|
|
+ "buffer because lastsize is bufflen.\n",
|
|
|
+ xid, i, j, dmacount, (u64)addr);
|
|
|
+ goto out_noddp_free;
|
|
|
+ }
|
|
|
+
|
|
|
+ ddp->udl[j] = (u64)(fcoe->extra_ddp_buffer_dma);
|
|
|
+ j++;
|
|
|
+ lastsize = 1;
|
|
|
+ }
|
|
|
+
|
|
|
fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT);
|
|
|
fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT);
|
|
|
fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT);
|
|
@@ -532,6 +550,24 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
|
|
|
e_err(drv, "failed to allocated FCoE DDP pool\n");
|
|
|
|
|
|
spin_lock_init(&fcoe->lock);
|
|
|
+
|
|
|
+ /* Extra buffer to be shared by all DDPs for HW work around */
|
|
|
+ fcoe->extra_ddp_buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_ATOMIC);
|
|
|
+ if (fcoe->extra_ddp_buffer == NULL) {
|
|
|
+ e_err(drv, "failed to allocated extra DDP buffer\n");
|
|
|
+ goto out_extra_ddp_buffer_alloc;
|
|
|
+ }
|
|
|
+
|
|
|
+ fcoe->extra_ddp_buffer_dma =
|
|
|
+ dma_map_single(&adapter->pdev->dev,
|
|
|
+ fcoe->extra_ddp_buffer,
|
|
|
+ IXGBE_FCBUFF_MIN,
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
+ if (dma_mapping_error(&adapter->pdev->dev,
|
|
|
+ fcoe->extra_ddp_buffer_dma)) {
|
|
|
+ e_err(drv, "failed to map extra DDP buffer\n");
|
|
|
+ goto out_extra_ddp_buffer_dma;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Enable L2 eth type filter for FCoE */
|
|
@@ -581,6 +617,14 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
|
|
|
}
|
|
|
}
|
|
|
#endif
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
+out_extra_ddp_buffer_dma:
|
|
|
+ kfree(fcoe->extra_ddp_buffer);
|
|
|
+out_extra_ddp_buffer_alloc:
|
|
|
+ pci_pool_destroy(fcoe->pool);
|
|
|
+ fcoe->pool = NULL;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -600,6 +644,11 @@ void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter)
|
|
|
if (fcoe->pool) {
|
|
|
for (i = 0; i < IXGBE_FCOE_DDP_MAX; i++)
|
|
|
ixgbe_fcoe_ddp_put(adapter->netdev, i);
|
|
|
+ dma_unmap_single(&adapter->pdev->dev,
|
|
|
+ fcoe->extra_ddp_buffer_dma,
|
|
|
+ IXGBE_FCBUFF_MIN,
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
+ kfree(fcoe->extra_ddp_buffer);
|
|
|
pci_pool_destroy(fcoe->pool);
|
|
|
fcoe->pool = NULL;
|
|
|
}
|