diff options
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_fcoe.c')
| -rw-r--r-- | drivers/net/ixgbe/ixgbe_fcoe.c | 51 | 
1 files changed, 50 insertions, 1 deletions
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 8753980668c..c54a88274d5 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -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;  	}  |