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: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
90d683afd1
commit
f7d6f379db
|
@ -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;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
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)
|
||||
|
|
Loading…
Reference in a new issue