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

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
......@@ -222,7 +222,6 @@ struct efx_tx_queue {
* If both this and skb are %NULL, the buffer slot is currently free.
* @data: Pointer to ethernet header
* @len: Buffer length, in bytes.
* @unmap_addr: DMA address to unmap
*/
struct efx_rx_buffer {
dma_addr_t dma_addr;
......@@ -230,7 +229,6 @@ struct efx_rx_buffer {
struct page *page;
char *data;
unsigned int len;
dma_addr_t unmap_addr;
};
/**
......@@ -257,11 +255,6 @@ struct efx_rx_buffer {
* @alloc_page_count: RX allocation strategy counter.
* @alloc_skb_count: RX allocation strategy counter.
* @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
*/
struct efx_rx_queue {
......@@ -284,9 +277,6 @@ struct efx_rx_queue {
struct timer_list slow_fill;
unsigned int slow_fill_count;
struct page *buf_page;
dma_addr_t buf_dma_addr;
char *buf_data;
enum efx_flush_state flushed;
};
......
......@@ -98,27 +98,32 @@ static inline unsigned int efx_rx_buf_size(struct efx_nic *efx)
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_buf: RX buffer structure to populate
*
* This allocates memory for a new receive buffer, maps it for DMA,
* and populates a struct efx_rx_buffer with the relevant
* information. Return a negative error code or 0 on success.
* This allocates EFX_RX_BATCH skbs, maps them for DMA, and populates a
* struct efx_rx_buffer for each one. Return a negative error code or 0
* 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,
struct efx_rx_buffer *rx_buf)
static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
struct net_device *net_dev = efx->net_dev;
struct efx_rx_buffer *rx_buf;
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);
if (unlikely(!rx_buf->skb))
return -ENOMEM;
rx_buf->page = NULL;
/* Adjust the SKB for padding and checksum */
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->data, rx_buf->len,
PCI_DMA_FROMDEVICE);
if (unlikely(pci_dma_mapping_error(efx->pci_dev, rx_buf->dma_addr))) {
if (unlikely(pci_dma_mapping_error(efx->pci_dev,
rx_buf->dma_addr))) {
dev_kfree_skb_any(rx_buf->skb);
rx_buf->skb = NULL;
return -EIO;
}
++rx_queue->added_count;
++rx_queue->alloc_skb_count;
}
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_buf: RX buffer structure to populate
*
* This allocates memory for a new receive buffer, maps it for DMA,
* and populates a struct efx_rx_buffer with the relevant
* information. Return a negative error code or 0 on success.
* This allocates memory for EFX_RX_BATCH receive buffers, maps them for DMA,
* and populates struct efx_rx_buffers for each one. Return a negative error
* 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,
struct efx_rx_buffer *rx_buf)
static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
int bytes, space, offset;
bytes = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
/* 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) {
struct efx_rx_buffer *rx_buf;
struct page *page;
char *page_addr;
dma_addr_t dma_addr;
unsigned index, count;
/* We can split a page between two buffers */
BUILD_BUG_ON(EFX_RX_BATCH & 1);
rx_buf->page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
for (count = 0; count < EFX_RX_BATCH; ++count) {
page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
efx->rx_buffer_order);
if (unlikely(rx_buf->page == NULL))
if (unlikely(page == NULL))
return -ENOMEM;
dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
0, efx_rx_buf_size(efx),
dma_addr = pci_map_page(efx->pci_dev, page, 0,
efx_rx_buf_size(efx),
PCI_DMA_FROMDEVICE);
if (unlikely(pci_dma_mapping_error(efx->pci_dev, dma_addr))) {
__free_pages(rx_buf->page, efx->rx_buffer_order);
rx_buf->page = NULL;
__free_pages(page, efx->rx_buffer_order);
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;
rx_queue->buf_dma_addr = dma_addr;
rx_queue->buf_data = (page_address(rx_buf->page) +
EFX_PAGE_IP_ALIGN);
}
rx_buf->len = bytes;
rx_buf->data = rx_queue->buf_data;
offset = efx_rx_buf_offset(rx_buf);
rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
/* 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 (space >= bytes) {
/* Refs dropped on kernel releasing each skb */
get_page(rx_queue->buf_page);
goto out;
split:
index = rx_queue->added_count & EFX_RXQ_MASK;
rx_buf = efx_rx_buffer(rx_queue, index);
rx_buf->dma_addr = dma_addr;
rx_buf->skb = NULL;
rx_buf->page = page;
rx_buf->data = page_addr;
rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
++rx_queue->added_count;
++rx_queue->alloc_page_count;
if ((~count & 1) && (efx->rx_buffer_len < (PAGE_SIZE >> 1))) {
/* Use the second half of the page */
get_page(page);
dma_addr += (PAGE_SIZE >> 1);
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;
}
/* 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,
struct efx_rx_buffer *rx_buf)
{
if (rx_buf->page) {
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),
PCI_DMA_FROMDEVICE);
rx_buf->unmap_addr = 0;
}
} else if (likely(rx_buf->skb)) {
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)
{
struct efx_rx_buffer *rx_buf;
unsigned fill_level, index;
int i, space, rc = 0;
struct efx_channel *channel = rx_queue->channel;
unsigned fill_level;
int space, rc = 0;
/* Calculate current fill level, and exit if we don't need to fill */
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"
" level %d to level %d using %s allocation\n",
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 {
for (i = 0; i < EFX_RX_BATCH; ++i) {
index = rx_queue->added_count & EFX_RXQ_MASK;
rx_buf = efx_rx_buffer(rx_queue, index);
rc = efx_init_rx_buffer(rx_queue, rx_buf);
if (channel->rx_alloc_push_pages)
rc = efx_init_rx_buffers_page(rx_queue);
else
rc = efx_init_rx_buffers_skb(rx_queue);
if (unlikely(rc)) {
/* Ensure that we don't leave the rx queue
* empty */
/* Ensure that we don't leave the rx queue empty */
if (rx_queue->added_count == rx_queue->removed_count)
efx_schedule_slow_fill(rx_queue);
goto out;
}
++rx_queue->added_count;
}
} while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
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);
}
}
/* 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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment