Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7d6f379 authored by Steve Hodgson's avatar Steve Hodgson Committed by David S. Miller
Browse files

sfc: Support only two rx buffers per page



- Pull the loop handling into efx_init_rx_buffers_(skb|page)
- Remove rx_queue->buf_page, and associated clean up code
- Remove unmap_addr, since unmap_addr is trivially calculable

This will allow us to recycle discarded buffers directly
from efx_rx_packet(), since will never be in the middle of
splitting a page.

Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 90d683af
Loading
Loading
Loading
Loading
+0 −10
Original line number Original line Diff line number Diff line
@@ -222,7 +222,6 @@ struct efx_tx_queue {
 *	If both this and skb are %NULL, the buffer slot is currently free.
 *	If both this and skb are %NULL, the buffer slot is currently free.
 * @data: Pointer to ethernet header
 * @data: Pointer to ethernet header
 * @len: Buffer length, in bytes.
 * @len: Buffer length, in bytes.
 * @unmap_addr: DMA address to unmap
 */
 */
struct efx_rx_buffer {
struct efx_rx_buffer {
	dma_addr_t dma_addr;
	dma_addr_t dma_addr;
@@ -230,7 +229,6 @@ struct efx_rx_buffer {
	struct page *page;
	struct page *page;
	char *data;
	char *data;
	unsigned int len;
	unsigned int len;
	dma_addr_t unmap_addr;
};
};


/**
/**
@@ -257,11 +255,6 @@ struct efx_rx_buffer {
 * @alloc_page_count: RX allocation strategy counter.
 * @alloc_page_count: RX allocation strategy counter.
 * @alloc_skb_count: RX allocation strategy counter.
 * @alloc_skb_count: RX allocation strategy counter.
 * @slow_fill: Timer used to defer efx_nic_generate_fill_event().
 * @slow_fill: Timer used to defer efx_nic_generate_fill_event().
 * @buf_page: Page for next RX buffer.
 *	We can use a single page for multiple RX buffers. This tracks
 *	the remaining space in the allocation.
 * @buf_dma_addr: Page's DMA address.
 * @buf_data: Page's host address.
 * @flushed: Use when handling queue flushing
 * @flushed: Use when handling queue flushing
 */
 */
struct efx_rx_queue {
struct efx_rx_queue {
@@ -284,9 +277,6 @@ struct efx_rx_queue {
	struct timer_list slow_fill;
	struct timer_list slow_fill;
	unsigned int slow_fill_count;
	unsigned int slow_fill_count;


	struct page *buf_page;
	dma_addr_t buf_dma_addr;
	char *buf_data;
	enum efx_flush_state flushed;
	enum efx_flush_state flushed;
};
};


+96 −132
Original line number Original line Diff line number Diff line
@@ -98,27 +98,32 @@ static inline unsigned int efx_rx_buf_size(struct efx_nic *efx)
	return PAGE_SIZE << efx->rx_buffer_order;
	return PAGE_SIZE << efx->rx_buffer_order;
}
}



/**
/**
 * efx_init_rx_buffer_skb - create new RX buffer using skb-based allocation
 * efx_init_rx_buffers_skb - create EFX_RX_BATCH skb-based RX buffers
 *
 *
 * @rx_queue:		Efx RX queue
 * @rx_queue:		Efx RX queue
 * @rx_buf:		RX buffer structure to populate
 *
 *
 * This allocates memory for a new receive buffer, maps it for DMA,
 * This allocates EFX_RX_BATCH skbs, maps them for DMA, and populates a
 * and populates a struct efx_rx_buffer with the relevant
 * struct efx_rx_buffer for each one. Return a negative error code or 0
 * information.  Return a negative error code or 0 on success.
 * on success. May fail having only inserted fewer than EFX_RX_BATCH
 * buffers.
 */
 */
static int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue)
				  struct efx_rx_buffer *rx_buf)
{
{
	struct efx_nic *efx = rx_queue->efx;
	struct efx_nic *efx = rx_queue->efx;
	struct net_device *net_dev = efx->net_dev;
	struct net_device *net_dev = efx->net_dev;
	struct efx_rx_buffer *rx_buf;
	int skb_len = efx->rx_buffer_len;
	int skb_len = efx->rx_buffer_len;
	unsigned index, count;

	for (count = 0; count < EFX_RX_BATCH; ++count) {
		index = rx_queue->added_count & EFX_RXQ_MASK;
		rx_buf = efx_rx_buffer(rx_queue, index);


		rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
		rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
		if (unlikely(!rx_buf->skb))
		if (unlikely(!rx_buf->skb))
			return -ENOMEM;
			return -ENOMEM;
		rx_buf->page = NULL;


		/* Adjust the SKB for padding and checksum */
		/* Adjust the SKB for padding and checksum */
		skb_reserve(rx_buf->skb, NET_IP_ALIGN);
		skb_reserve(rx_buf->skb, NET_IP_ALIGN);
@@ -129,124 +134,96 @@ static int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
		rx_buf->dma_addr = pci_map_single(efx->pci_dev,
		rx_buf->dma_addr = pci_map_single(efx->pci_dev,
						  rx_buf->data, rx_buf->len,
						  rx_buf->data, rx_buf->len,
						  PCI_DMA_FROMDEVICE);
						  PCI_DMA_FROMDEVICE);

		if (unlikely(pci_dma_mapping_error(efx->pci_dev,
	if (unlikely(pci_dma_mapping_error(efx->pci_dev, rx_buf->dma_addr))) {
						   rx_buf->dma_addr))) {
			dev_kfree_skb_any(rx_buf->skb);
			dev_kfree_skb_any(rx_buf->skb);
			rx_buf->skb = NULL;
			rx_buf->skb = NULL;
			return -EIO;
			return -EIO;
		}
		}


		++rx_queue->added_count;
		++rx_queue->alloc_skb_count;
	}

	return 0;
	return 0;
}
}


/**
/**
 * efx_init_rx_buffer_page - create new RX buffer using page-based allocation
 * efx_init_rx_buffers_page - create EFX_RX_BATCH page-based RX buffers
 *
 *
 * @rx_queue:		Efx RX queue
 * @rx_queue:		Efx RX queue
 * @rx_buf:		RX buffer structure to populate
 *
 *
 * This allocates memory for a new receive buffer, maps it for DMA,
 * This allocates memory for EFX_RX_BATCH receive buffers, maps them for DMA,
 * and populates a struct efx_rx_buffer with the relevant
 * and populates struct efx_rx_buffers for each one. Return a negative error
 * information.  Return a negative error code or 0 on success.
 * code or 0 on success. If a single page can be split between two buffers,
 * then the page will either be inserted fully, or not at at all.
 */
 */
static int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
				   struct efx_rx_buffer *rx_buf)
{
{
	struct efx_nic *efx = rx_queue->efx;
	struct efx_nic *efx = rx_queue->efx;
	int bytes, space, offset;
	struct efx_rx_buffer *rx_buf;

	struct page *page;
	bytes = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
	char *page_addr;

	/* If there is space left in the previously allocated page,
	 * then use it. Otherwise allocate a new one */
	rx_buf->page = rx_queue->buf_page;
	if (rx_buf->page == NULL) {
	dma_addr_t dma_addr;
	dma_addr_t dma_addr;
	unsigned index, count;


		rx_buf->page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
	/* We can split a page between two buffers */
	BUILD_BUG_ON(EFX_RX_BATCH & 1);

	for (count = 0; count < EFX_RX_BATCH; ++count) {
		page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
				   efx->rx_buffer_order);
				   efx->rx_buffer_order);
		if (unlikely(rx_buf->page == NULL))
		if (unlikely(page == NULL))
			return -ENOMEM;
			return -ENOMEM;

		dma_addr = pci_map_page(efx->pci_dev, page, 0,
		dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
					efx_rx_buf_size(efx),
					0, efx_rx_buf_size(efx),
					PCI_DMA_FROMDEVICE);
					PCI_DMA_FROMDEVICE);

		if (unlikely(pci_dma_mapping_error(efx->pci_dev, dma_addr))) {
		if (unlikely(pci_dma_mapping_error(efx->pci_dev, dma_addr))) {
			__free_pages(rx_buf->page, efx->rx_buffer_order);
			__free_pages(page, efx->rx_buffer_order);
			rx_buf->page = NULL;
			return -EIO;
			return -EIO;
		}
		}
		EFX_BUG_ON_PARANOID(dma_addr & (PAGE_SIZE - 1));
		page_addr = page_address(page) + EFX_PAGE_IP_ALIGN;
		dma_addr += EFX_PAGE_IP_ALIGN;


		rx_queue->buf_page = rx_buf->page;
	split:
		rx_queue->buf_dma_addr = dma_addr;
		index = rx_queue->added_count & EFX_RXQ_MASK;
		rx_queue->buf_data = (page_address(rx_buf->page) +
		rx_buf = efx_rx_buffer(rx_queue, index);
				      EFX_PAGE_IP_ALIGN);
		rx_buf->dma_addr = dma_addr;
	}
		rx_buf->skb = NULL;

		rx_buf->page = page;
	rx_buf->len = bytes;
		rx_buf->data = page_addr;
	rx_buf->data = rx_queue->buf_data;
		rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
	offset = efx_rx_buf_offset(rx_buf);
		++rx_queue->added_count;
	rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
		++rx_queue->alloc_page_count;

	/* Try to pack multiple buffers per page */
	if (efx->rx_buffer_order == 0) {
		/* The next buffer starts on the next 512 byte boundary */
		rx_queue->buf_data += ((bytes + 0x1ff) & ~0x1ff);
		offset += ((bytes + 0x1ff) & ~0x1ff);


		space = efx_rx_buf_size(efx) - offset;
		if ((~count & 1) && (efx->rx_buffer_len < (PAGE_SIZE >> 1))) {
		if (space >= bytes) {
			/* Use the second half of the page */
			/* Refs dropped on kernel releasing each skb */
			get_page(page);
			get_page(rx_queue->buf_page);
			dma_addr += (PAGE_SIZE >> 1);
			goto out;
			page_addr += (PAGE_SIZE >> 1);
			++count;
			goto split;
		}
		}
	}
	}


	/* This is the final RX buffer for this page, so mark it for
	 * unmapping */
	rx_queue->buf_page = NULL;
	rx_buf->unmap_addr = rx_queue->buf_dma_addr;

 out:
	return 0;
	return 0;
}
}


/* This allocates memory for a new receive buffer, maps it for DMA,
 * and populates a struct efx_rx_buffer with the relevant
 * information.
 */
static int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
			      struct efx_rx_buffer *new_rx_buf)
{
	int rc = 0;

	if (rx_queue->channel->rx_alloc_push_pages) {
		new_rx_buf->skb = NULL;
		rc = efx_init_rx_buffer_page(rx_queue, new_rx_buf);
		rx_queue->alloc_page_count++;
	} else {
		new_rx_buf->page = NULL;
		rc = efx_init_rx_buffer_skb(rx_queue, new_rx_buf);
		rx_queue->alloc_skb_count++;
	}

	if (unlikely(rc < 0))
		EFX_LOG_RL(rx_queue->efx, "%s RXQ[%d] =%d\n", __func__,
			   rx_queue->queue, rc);
	return rc;
}

static void efx_unmap_rx_buffer(struct efx_nic *efx,
static void efx_unmap_rx_buffer(struct efx_nic *efx,
				struct efx_rx_buffer *rx_buf)
				struct efx_rx_buffer *rx_buf)
{
{
	if (rx_buf->page) {
	if (rx_buf->page) {
		EFX_BUG_ON_PARANOID(rx_buf->skb);
		EFX_BUG_ON_PARANOID(rx_buf->skb);
		if (rx_buf->unmap_addr) {

			pci_unmap_page(efx->pci_dev, rx_buf->unmap_addr,
		/* Unmap the buffer if there's only one buffer per page(s),
		 * or this is the second half of a two buffer page. */
		if (efx->rx_buffer_order != 0 ||
		    (efx_rx_buf_offset(rx_buf) & (PAGE_SIZE >> 1)) != 0) {
			pci_unmap_page(efx->pci_dev,
				       rx_buf->dma_addr & ~(PAGE_SIZE - 1),
				       efx_rx_buf_size(efx),
				       efx_rx_buf_size(efx),
				       PCI_DMA_FROMDEVICE);
				       PCI_DMA_FROMDEVICE);
			rx_buf->unmap_addr = 0;
		}
		}
	} else if (likely(rx_buf->skb)) {
	} else if (likely(rx_buf->skb)) {
		pci_unmap_single(efx->pci_dev, rx_buf->dma_addr,
		pci_unmap_single(efx->pci_dev, rx_buf->dma_addr,
@@ -286,9 +263,9 @@ static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
 */
 */
void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
{
{
	struct efx_rx_buffer *rx_buf;
	struct efx_channel *channel = rx_queue->channel;
	unsigned fill_level, index;
	unsigned fill_level;
	int i, space, rc = 0;
	int space, rc = 0;


	/* Calculate current fill level, and exit if we don't need to fill */
	/* Calculate current fill level, and exit if we don't need to fill */
	fill_level = (rx_queue->added_count - rx_queue->removed_count);
	fill_level = (rx_queue->added_count - rx_queue->removed_count);
@@ -309,22 +286,19 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
	EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
	EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
		  " level %d to level %d using %s allocation\n",
		  " level %d to level %d using %s allocation\n",
		  rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
		  rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
		  rx_queue->channel->rx_alloc_push_pages ? "page" : "skb");
		  channel->rx_alloc_push_pages ? "page" : "skb");


	do {
	do {
		for (i = 0; i < EFX_RX_BATCH; ++i) {
		if (channel->rx_alloc_push_pages)
			index = rx_queue->added_count & EFX_RXQ_MASK;
			rc = efx_init_rx_buffers_page(rx_queue);
			rx_buf = efx_rx_buffer(rx_queue, index);
		else
			rc = efx_init_rx_buffer(rx_queue, rx_buf);
			rc = efx_init_rx_buffers_skb(rx_queue);
		if (unlikely(rc)) {
		if (unlikely(rc)) {
				/* Ensure that we don't leave the rx queue
			/* Ensure that we don't leave the rx queue empty */
				 * empty */
			if (rx_queue->added_count == rx_queue->removed_count)
			if (rx_queue->added_count == rx_queue->removed_count)
				efx_schedule_slow_fill(rx_queue);
				efx_schedule_slow_fill(rx_queue);
			goto out;
			goto out;
		}
		}
			++rx_queue->added_count;
		}
	} while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
	} while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);


	EFX_TRACE(rx_queue->efx, "RX queue %d fast-filled descriptor ring "
	EFX_TRACE(rx_queue->efx, "RX queue %d fast-filled descriptor ring "
@@ -638,16 +612,6 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
			efx_fini_rx_buffer(rx_queue, rx_buf);
			efx_fini_rx_buffer(rx_queue, rx_buf);
		}
		}
	}
	}

	/* For a page that is part-way through splitting into RX buffers */
	if (rx_queue->buf_page != NULL) {
		pci_unmap_page(rx_queue->efx->pci_dev, rx_queue->buf_dma_addr,
			       efx_rx_buf_size(rx_queue->efx),
			       PCI_DMA_FROMDEVICE);
		__free_pages(rx_queue->buf_page,
			     rx_queue->efx->rx_buffer_order);
		rx_queue->buf_page = NULL;
	}
}
}


void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)