mirror of https://gitee.com/openkylin/linux.git
gve: Add support for raw addressing to the rx path
Add support to use raw dma addresses in the rx path. Due to this new support we can alloc a new buffer instead of making a copy. RX buffers are handed to the networking stack and are re-allocated as needed, avoiding the need to use skb_copy_to_linear_data() as in "qpl" mode. Reviewed-by: Yangchun Fu <yangchun@google.com> Signed-off-by: Catherine Sullivan <csully@google.com> Signed-off-by: David Awogbemila <awogbemila@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
4944db80ac
commit
ede3fcf5ec
|
@ -38,6 +38,8 @@
|
||||||
#define NIC_TX_STATS_REPORT_NUM 0
|
#define NIC_TX_STATS_REPORT_NUM 0
|
||||||
#define NIC_RX_STATS_REPORT_NUM 4
|
#define NIC_RX_STATS_REPORT_NUM 4
|
||||||
|
|
||||||
|
#define GVE_DATA_SLOT_ADDR_PAGE_MASK (~(PAGE_SIZE - 1))
|
||||||
|
|
||||||
/* Each slot in the desc ring has a 1:1 mapping to a slot in the data ring */
|
/* Each slot in the desc ring has a 1:1 mapping to a slot in the data ring */
|
||||||
struct gve_rx_desc_queue {
|
struct gve_rx_desc_queue {
|
||||||
struct gve_rx_desc *desc_ring; /* the descriptor ring */
|
struct gve_rx_desc *desc_ring; /* the descriptor ring */
|
||||||
|
@ -49,7 +51,7 @@ struct gve_rx_desc_queue {
|
||||||
struct gve_rx_slot_page_info {
|
struct gve_rx_slot_page_info {
|
||||||
struct page *page;
|
struct page *page;
|
||||||
void *page_address;
|
void *page_address;
|
||||||
u32 page_offset; /* offset to write to in page */
|
u8 page_offset; /* flipped to second half? */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A list of pages registered with the device during setup and used by a queue
|
/* A list of pages registered with the device during setup and used by a queue
|
||||||
|
@ -64,10 +66,11 @@ struct gve_queue_page_list {
|
||||||
|
|
||||||
/* Each slot in the data ring has a 1:1 mapping to a slot in the desc ring */
|
/* Each slot in the data ring has a 1:1 mapping to a slot in the desc ring */
|
||||||
struct gve_rx_data_queue {
|
struct gve_rx_data_queue {
|
||||||
struct gve_rx_data_slot *data_ring; /* read by NIC */
|
union gve_rx_data_slot *data_ring; /* read by NIC */
|
||||||
dma_addr_t data_bus; /* dma mapping of the slots */
|
dma_addr_t data_bus; /* dma mapping of the slots */
|
||||||
struct gve_rx_slot_page_info *page_info; /* page info of the buffers */
|
struct gve_rx_slot_page_info *page_info; /* page info of the buffers */
|
||||||
struct gve_queue_page_list *qpl; /* qpl assigned to this queue */
|
struct gve_queue_page_list *qpl; /* qpl assigned to this queue */
|
||||||
|
u8 raw_addressing; /* use raw_addressing? */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gve_priv;
|
struct gve_priv;
|
||||||
|
@ -82,6 +85,7 @@ struct gve_rx_ring {
|
||||||
u32 cnt; /* free-running total number of completed packets */
|
u32 cnt; /* free-running total number of completed packets */
|
||||||
u32 fill_cnt; /* free-running total number of descs and buffs posted */
|
u32 fill_cnt; /* free-running total number of descs and buffs posted */
|
||||||
u32 mask; /* masks the cnt and fill_cnt to the size of the ring */
|
u32 mask; /* masks the cnt and fill_cnt to the size of the ring */
|
||||||
|
u32 db_threshold; /* threshold for posting new buffs and descs */
|
||||||
u64 rx_copybreak_pkt; /* free-running count of copybreak packets */
|
u64 rx_copybreak_pkt; /* free-running count of copybreak packets */
|
||||||
u64 rx_copied_pkt; /* free-running total number of copied packets */
|
u64 rx_copied_pkt; /* free-running total number of copied packets */
|
||||||
u64 rx_skb_alloc_fail; /* free-running count of skb alloc fails */
|
u64 rx_skb_alloc_fail; /* free-running count of skb alloc fails */
|
||||||
|
@ -194,7 +198,7 @@ struct gve_priv {
|
||||||
u16 tx_desc_cnt; /* num desc per ring */
|
u16 tx_desc_cnt; /* num desc per ring */
|
||||||
u16 rx_desc_cnt; /* num desc per ring */
|
u16 rx_desc_cnt; /* num desc per ring */
|
||||||
u16 tx_pages_per_qpl; /* tx buffer length */
|
u16 tx_pages_per_qpl; /* tx buffer length */
|
||||||
u16 rx_pages_per_qpl; /* rx buffer length */
|
u16 rx_data_slot_cnt; /* rx buffer length */
|
||||||
u64 max_registered_pages;
|
u64 max_registered_pages;
|
||||||
u64 num_registered_pages; /* num pages registered with NIC */
|
u64 num_registered_pages; /* num pages registered with NIC */
|
||||||
u32 rx_copybreak; /* copy packets smaller than this */
|
u32 rx_copybreak; /* copy packets smaller than this */
|
||||||
|
@ -444,7 +448,7 @@ static inline u32 gve_num_tx_qpls(struct gve_priv *priv)
|
||||||
*/
|
*/
|
||||||
static inline u32 gve_num_rx_qpls(struct gve_priv *priv)
|
static inline u32 gve_num_rx_qpls(struct gve_priv *priv)
|
||||||
{
|
{
|
||||||
return priv->rx_cfg.num_queues;
|
return priv->raw_addressing ? 0 : priv->rx_cfg.num_queues;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns a pointer to the next available tx qpl in the list of qpls
|
/* Returns a pointer to the next available tx qpl in the list of qpls
|
||||||
|
|
|
@ -408,8 +408,10 @@ static int gve_adminq_create_rx_queue(struct gve_priv *priv, u32 queue_index)
|
||||||
{
|
{
|
||||||
struct gve_rx_ring *rx = &priv->rx[queue_index];
|
struct gve_rx_ring *rx = &priv->rx[queue_index];
|
||||||
union gve_adminq_command cmd;
|
union gve_adminq_command cmd;
|
||||||
|
u32 qpl_id;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
qpl_id = priv->raw_addressing ? GVE_RAW_ADDRESSING_QPL_ID : rx->data.qpl->id;
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
cmd.opcode = cpu_to_be32(GVE_ADMINQ_CREATE_RX_QUEUE);
|
cmd.opcode = cpu_to_be32(GVE_ADMINQ_CREATE_RX_QUEUE);
|
||||||
cmd.create_rx_queue = (struct gve_adminq_create_rx_queue) {
|
cmd.create_rx_queue = (struct gve_adminq_create_rx_queue) {
|
||||||
|
@ -420,7 +422,7 @@ static int gve_adminq_create_rx_queue(struct gve_priv *priv, u32 queue_index)
|
||||||
.queue_resources_addr = cpu_to_be64(rx->q_resources_bus),
|
.queue_resources_addr = cpu_to_be64(rx->q_resources_bus),
|
||||||
.rx_desc_ring_addr = cpu_to_be64(rx->desc.bus),
|
.rx_desc_ring_addr = cpu_to_be64(rx->desc.bus),
|
||||||
.rx_data_ring_addr = cpu_to_be64(rx->data.data_bus),
|
.rx_data_ring_addr = cpu_to_be64(rx->data.data_bus),
|
||||||
.queue_page_list_id = cpu_to_be32(rx->data.qpl->id),
|
.queue_page_list_id = cpu_to_be32(qpl_id),
|
||||||
};
|
};
|
||||||
|
|
||||||
err = gve_adminq_issue_cmd(priv, &cmd);
|
err = gve_adminq_issue_cmd(priv, &cmd);
|
||||||
|
@ -565,11 +567,11 @@ int gve_adminq_describe_device(struct gve_priv *priv)
|
||||||
mac = descriptor->mac;
|
mac = descriptor->mac;
|
||||||
dev_info(&priv->pdev->dev, "MAC addr: %pM\n", mac);
|
dev_info(&priv->pdev->dev, "MAC addr: %pM\n", mac);
|
||||||
priv->tx_pages_per_qpl = be16_to_cpu(descriptor->tx_pages_per_qpl);
|
priv->tx_pages_per_qpl = be16_to_cpu(descriptor->tx_pages_per_qpl);
|
||||||
priv->rx_pages_per_qpl = be16_to_cpu(descriptor->rx_pages_per_qpl);
|
priv->rx_data_slot_cnt = be16_to_cpu(descriptor->rx_pages_per_qpl);
|
||||||
if (priv->rx_pages_per_qpl < priv->rx_desc_cnt) {
|
if (priv->rx_data_slot_cnt < priv->rx_desc_cnt) {
|
||||||
dev_err(&priv->pdev->dev, "rx_pages_per_qpl cannot be smaller than rx_desc_cnt, setting rx_desc_cnt down to %d.\n",
|
dev_err(&priv->pdev->dev, "rx_data_slot_cnt cannot be smaller than rx_desc_cnt, setting rx_desc_cnt down to %d.\n",
|
||||||
priv->rx_pages_per_qpl);
|
priv->rx_data_slot_cnt);
|
||||||
priv->rx_desc_cnt = priv->rx_pages_per_qpl;
|
priv->rx_desc_cnt = priv->rx_data_slot_cnt;
|
||||||
}
|
}
|
||||||
priv->default_num_queues = be16_to_cpu(descriptor->default_num_queues);
|
priv->default_num_queues = be16_to_cpu(descriptor->default_num_queues);
|
||||||
dev_opt = (void *)(descriptor + 1);
|
dev_opt = (void *)(descriptor + 1);
|
||||||
|
|
|
@ -72,12 +72,15 @@ struct gve_rx_desc {
|
||||||
} __packed;
|
} __packed;
|
||||||
static_assert(sizeof(struct gve_rx_desc) == 64);
|
static_assert(sizeof(struct gve_rx_desc) == 64);
|
||||||
|
|
||||||
/* As with the Tx ring format, the qpl_offset entries below are offsets into an
|
/* If the device supports raw dma addressing then the addr in data slot is
|
||||||
* ordered list of registered pages.
|
* the dma address of the buffer.
|
||||||
|
* If the device only supports registered segments then the addr is a byte
|
||||||
|
* offset into the registered segment (an ordered list of pages) where the
|
||||||
|
* buffer is.
|
||||||
*/
|
*/
|
||||||
struct gve_rx_data_slot {
|
union gve_rx_data_slot {
|
||||||
/* byte offset into the rx registered segment of this slot */
|
|
||||||
__be64 qpl_offset;
|
__be64 qpl_offset;
|
||||||
|
__be64 addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* GVE Recive Packet Descriptor Seq No */
|
/* GVE Recive Packet Descriptor Seq No */
|
||||||
|
|
|
@ -693,7 +693,7 @@ static int gve_alloc_qpls(struct gve_priv *priv)
|
||||||
}
|
}
|
||||||
for (; i < num_qpls; i++) {
|
for (; i < num_qpls; i++) {
|
||||||
err = gve_alloc_queue_page_list(priv, i,
|
err = gve_alloc_queue_page_list(priv, i,
|
||||||
priv->rx_pages_per_qpl);
|
priv->rx_data_slot_cnt);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_qpls;
|
goto free_qpls;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,39 @@ static void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx)
|
||||||
block->rx = NULL;
|
block->rx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gve_rx_free_buffer(struct device *dev,
|
||||||
|
struct gve_rx_slot_page_info *page_info,
|
||||||
|
union gve_rx_data_slot *data_slot)
|
||||||
|
{
|
||||||
|
dma_addr_t dma = (dma_addr_t)(be64_to_cpu(data_slot->addr) &
|
||||||
|
GVE_DATA_SLOT_ADDR_PAGE_MASK);
|
||||||
|
|
||||||
|
gve_free_page(dev, page_info->page, dma, DMA_FROM_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gve_rx_unfill_pages(struct gve_priv *priv, struct gve_rx_ring *rx)
|
||||||
|
{
|
||||||
|
if (rx->data.raw_addressing) {
|
||||||
|
u32 slots = rx->mask + 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < slots; i++)
|
||||||
|
gve_rx_free_buffer(&priv->pdev->dev, &rx->data.page_info[i],
|
||||||
|
&rx->data.data_ring[i]);
|
||||||
|
} else {
|
||||||
|
gve_unassign_qpl(priv, rx->data.qpl->id);
|
||||||
|
rx->data.qpl = NULL;
|
||||||
|
}
|
||||||
|
kvfree(rx->data.page_info);
|
||||||
|
rx->data.page_info = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void gve_rx_free_ring(struct gve_priv *priv, int idx)
|
static void gve_rx_free_ring(struct gve_priv *priv, int idx)
|
||||||
{
|
{
|
||||||
struct gve_rx_ring *rx = &priv->rx[idx];
|
struct gve_rx_ring *rx = &priv->rx[idx];
|
||||||
struct device *dev = &priv->pdev->dev;
|
struct device *dev = &priv->pdev->dev;
|
||||||
|
u32 slots = rx->mask + 1;
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
u32 slots;
|
|
||||||
|
|
||||||
gve_rx_remove_from_block(priv, idx);
|
gve_rx_remove_from_block(priv, idx);
|
||||||
|
|
||||||
|
@ -33,11 +60,8 @@ static void gve_rx_free_ring(struct gve_priv *priv, int idx)
|
||||||
rx->q_resources, rx->q_resources_bus);
|
rx->q_resources, rx->q_resources_bus);
|
||||||
rx->q_resources = NULL;
|
rx->q_resources = NULL;
|
||||||
|
|
||||||
gve_unassign_qpl(priv, rx->data.qpl->id);
|
gve_rx_unfill_pages(priv, rx);
|
||||||
rx->data.qpl = NULL;
|
|
||||||
kvfree(rx->data.page_info);
|
|
||||||
|
|
||||||
slots = rx->mask + 1;
|
|
||||||
bytes = sizeof(*rx->data.data_ring) * slots;
|
bytes = sizeof(*rx->data.data_ring) * slots;
|
||||||
dma_free_coherent(dev, bytes, rx->data.data_ring,
|
dma_free_coherent(dev, bytes, rx->data.data_ring,
|
||||||
rx->data.data_bus);
|
rx->data.data_bus);
|
||||||
|
@ -46,19 +70,35 @@ static void gve_rx_free_ring(struct gve_priv *priv, int idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gve_setup_rx_buffer(struct gve_rx_slot_page_info *page_info,
|
static void gve_setup_rx_buffer(struct gve_rx_slot_page_info *page_info,
|
||||||
struct gve_rx_data_slot *slot,
|
dma_addr_t addr, struct page *page, __be64 *slot_addr)
|
||||||
dma_addr_t addr, struct page *page)
|
|
||||||
{
|
{
|
||||||
page_info->page = page;
|
page_info->page = page;
|
||||||
page_info->page_offset = 0;
|
page_info->page_offset = 0;
|
||||||
page_info->page_address = page_address(page);
|
page_info->page_address = page_address(page);
|
||||||
slot->qpl_offset = cpu_to_be64(addr);
|
*slot_addr = cpu_to_be64(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gve_rx_alloc_buffer(struct gve_priv *priv, struct device *dev,
|
||||||
|
struct gve_rx_slot_page_info *page_info,
|
||||||
|
union gve_rx_data_slot *data_slot)
|
||||||
|
{
|
||||||
|
struct page *page;
|
||||||
|
dma_addr_t dma;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = gve_alloc_page(priv, dev, &page, &dma, DMA_FROM_DEVICE);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
gve_setup_rx_buffer(page_info, dma, page, &data_slot->addr);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gve_prefill_rx_pages(struct gve_rx_ring *rx)
|
static int gve_prefill_rx_pages(struct gve_rx_ring *rx)
|
||||||
{
|
{
|
||||||
struct gve_priv *priv = rx->gve;
|
struct gve_priv *priv = rx->gve;
|
||||||
u32 slots;
|
u32 slots;
|
||||||
|
int err;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Allocate one page per Rx queue slot. Each page is split into two
|
/* Allocate one page per Rx queue slot. Each page is split into two
|
||||||
|
@ -71,17 +111,30 @@ static int gve_prefill_rx_pages(struct gve_rx_ring *rx)
|
||||||
if (!rx->data.page_info)
|
if (!rx->data.page_info)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
rx->data.qpl = gve_assign_rx_qpl(priv);
|
if (!rx->data.raw_addressing)
|
||||||
|
rx->data.qpl = gve_assign_rx_qpl(priv);
|
||||||
for (i = 0; i < slots; i++) {
|
for (i = 0; i < slots; i++) {
|
||||||
struct page *page = rx->data.qpl->pages[i];
|
if (!rx->data.raw_addressing) {
|
||||||
dma_addr_t addr = i * PAGE_SIZE;
|
struct page *page = rx->data.qpl->pages[i];
|
||||||
|
dma_addr_t addr = i * PAGE_SIZE;
|
||||||
|
|
||||||
gve_setup_rx_buffer(&rx->data.page_info[i],
|
gve_setup_rx_buffer(&rx->data.page_info[i], addr, page,
|
||||||
&rx->data.data_ring[i], addr, page);
|
&rx->data.data_ring[i].qpl_offset);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
err = gve_rx_alloc_buffer(priv, &priv->pdev->dev, &rx->data.page_info[i],
|
||||||
|
&rx->data.data_ring[i]);
|
||||||
|
if (err)
|
||||||
|
goto alloc_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return slots;
|
return slots;
|
||||||
|
alloc_err:
|
||||||
|
while (i--)
|
||||||
|
gve_rx_free_buffer(&priv->pdev->dev,
|
||||||
|
&rx->data.page_info[i],
|
||||||
|
&rx->data.data_ring[i]);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx)
|
static void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx)
|
||||||
|
@ -110,8 +163,9 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
|
||||||
rx->gve = priv;
|
rx->gve = priv;
|
||||||
rx->q_num = idx;
|
rx->q_num = idx;
|
||||||
|
|
||||||
slots = priv->rx_pages_per_qpl;
|
slots = priv->rx_data_slot_cnt;
|
||||||
rx->mask = slots - 1;
|
rx->mask = slots - 1;
|
||||||
|
rx->data.raw_addressing = priv->raw_addressing;
|
||||||
|
|
||||||
/* alloc rx data ring */
|
/* alloc rx data ring */
|
||||||
bytes = sizeof(*rx->data.data_ring) * slots;
|
bytes = sizeof(*rx->data.data_ring) * slots;
|
||||||
|
@ -156,8 +210,8 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto abort_with_q_resources;
|
goto abort_with_q_resources;
|
||||||
}
|
}
|
||||||
rx->mask = slots - 1;
|
|
||||||
rx->cnt = 0;
|
rx->cnt = 0;
|
||||||
|
rx->db_threshold = priv->rx_desc_cnt / 2;
|
||||||
rx->desc.seqno = 1;
|
rx->desc.seqno = 1;
|
||||||
gve_rx_add_to_block(priv, idx);
|
gve_rx_add_to_block(priv, idx);
|
||||||
|
|
||||||
|
@ -168,7 +222,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
|
||||||
rx->q_resources, rx->q_resources_bus);
|
rx->q_resources, rx->q_resources_bus);
|
||||||
rx->q_resources = NULL;
|
rx->q_resources = NULL;
|
||||||
abort_filled:
|
abort_filled:
|
||||||
kvfree(rx->data.page_info);
|
gve_rx_unfill_pages(priv, rx);
|
||||||
abort_with_slots:
|
abort_with_slots:
|
||||||
bytes = sizeof(*rx->data.data_ring) * slots;
|
bytes = sizeof(*rx->data.data_ring) * slots;
|
||||||
dma_free_coherent(hdev, bytes, rx->data.data_ring, rx->data.data_bus);
|
dma_free_coherent(hdev, bytes, rx->data.data_ring, rx->data.data_bus);
|
||||||
|
@ -233,7 +287,7 @@ static struct sk_buff *gve_rx_copy(struct gve_rx_ring *rx,
|
||||||
{
|
{
|
||||||
struct sk_buff *skb = napi_alloc_skb(napi, len);
|
struct sk_buff *skb = napi_alloc_skb(napi, len);
|
||||||
void *va = page_info->page_address + GVE_RX_PAD +
|
void *va = page_info->page_address + GVE_RX_PAD +
|
||||||
page_info->page_offset;
|
(page_info->page_offset ? PAGE_SIZE / 2 : 0);
|
||||||
|
|
||||||
if (unlikely(!skb))
|
if (unlikely(!skb))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -251,8 +305,7 @@ static struct sk_buff *gve_rx_copy(struct gve_rx_ring *rx,
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sk_buff *gve_rx_add_frags(struct net_device *dev,
|
static struct sk_buff *gve_rx_add_frags(struct napi_struct *napi,
|
||||||
struct napi_struct *napi,
|
|
||||||
struct gve_rx_slot_page_info *page_info,
|
struct gve_rx_slot_page_info *page_info,
|
||||||
u16 len)
|
u16 len)
|
||||||
{
|
{
|
||||||
|
@ -262,20 +315,19 @@ static struct sk_buff *gve_rx_add_frags(struct net_device *dev,
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
skb_add_rx_frag(skb, 0, page_info->page,
|
skb_add_rx_frag(skb, 0, page_info->page,
|
||||||
page_info->page_offset +
|
(page_info->page_offset ? PAGE_SIZE / 2 : 0) +
|
||||||
GVE_RX_PAD, len, PAGE_SIZE / 2);
|
GVE_RX_PAD, len, PAGE_SIZE / 2);
|
||||||
|
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gve_rx_flip_buff(struct gve_rx_slot_page_info *page_info,
|
static void gve_rx_flip_buff(struct gve_rx_slot_page_info *page_info, __be64 *slot_addr)
|
||||||
struct gve_rx_data_slot *data_ring)
|
|
||||||
{
|
{
|
||||||
u64 addr = be64_to_cpu(data_ring->qpl_offset);
|
const __be64 offset = cpu_to_be64(PAGE_SIZE / 2);
|
||||||
|
|
||||||
page_info->page_offset ^= PAGE_SIZE / 2;
|
/* "flip" to other packet buffer on this page */
|
||||||
addr ^= PAGE_SIZE / 2;
|
page_info->page_offset ^= 0x1;
|
||||||
data_ring->qpl_offset = cpu_to_be64(addr);
|
*(slot_addr) ^= offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
|
static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
|
||||||
|
@ -285,7 +337,9 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
|
||||||
struct gve_priv *priv = rx->gve;
|
struct gve_priv *priv = rx->gve;
|
||||||
struct napi_struct *napi = &priv->ntfy_blocks[rx->ntfy_id].napi;
|
struct napi_struct *napi = &priv->ntfy_blocks[rx->ntfy_id].napi;
|
||||||
struct net_device *dev = priv->dev;
|
struct net_device *dev = priv->dev;
|
||||||
struct sk_buff *skb;
|
union gve_rx_data_slot *data_slot;
|
||||||
|
struct sk_buff *skb = NULL;
|
||||||
|
dma_addr_t page_bus;
|
||||||
int pagecount;
|
int pagecount;
|
||||||
u16 len;
|
u16 len;
|
||||||
|
|
||||||
|
@ -294,18 +348,18 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
|
||||||
u64_stats_update_begin(&rx->statss);
|
u64_stats_update_begin(&rx->statss);
|
||||||
rx->rx_desc_err_dropped_pkt++;
|
rx->rx_desc_err_dropped_pkt++;
|
||||||
u64_stats_update_end(&rx->statss);
|
u64_stats_update_end(&rx->statss);
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = be16_to_cpu(rx_desc->len) - GVE_RX_PAD;
|
len = be16_to_cpu(rx_desc->len) - GVE_RX_PAD;
|
||||||
page_info = &rx->data.page_info[idx];
|
page_info = &rx->data.page_info[idx];
|
||||||
dma_sync_single_for_cpu(&priv->pdev->dev, rx->data.qpl->page_buses[idx],
|
|
||||||
PAGE_SIZE, DMA_FROM_DEVICE);
|
|
||||||
|
|
||||||
/* gvnic can only receive into registered segments. If the buffer
|
data_slot = &rx->data.data_ring[idx];
|
||||||
* can't be recycled, our only choice is to copy the data out of
|
page_bus = (rx->data.raw_addressing) ?
|
||||||
* it so that we can return it to the device.
|
be64_to_cpu(data_slot->addr) & GVE_DATA_SLOT_ADDR_PAGE_MASK :
|
||||||
*/
|
rx->data.qpl->page_buses[idx];
|
||||||
|
dma_sync_single_for_cpu(&priv->pdev->dev, page_bus,
|
||||||
|
PAGE_SIZE, DMA_FROM_DEVICE);
|
||||||
|
|
||||||
if (PAGE_SIZE == 4096) {
|
if (PAGE_SIZE == 4096) {
|
||||||
if (len <= priv->rx_copybreak) {
|
if (len <= priv->rx_copybreak) {
|
||||||
|
@ -316,6 +370,10 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
|
||||||
u64_stats_update_end(&rx->statss);
|
u64_stats_update_end(&rx->statss);
|
||||||
goto have_skb;
|
goto have_skb;
|
||||||
}
|
}
|
||||||
|
if (rx->data.raw_addressing) {
|
||||||
|
skb = gve_rx_add_frags(napi, page_info, len);
|
||||||
|
goto have_skb;
|
||||||
|
}
|
||||||
if (unlikely(!gve_can_recycle_pages(dev))) {
|
if (unlikely(!gve_can_recycle_pages(dev))) {
|
||||||
skb = gve_rx_copy(rx, dev, napi, page_info, len);
|
skb = gve_rx_copy(rx, dev, napi, page_info, len);
|
||||||
goto have_skb;
|
goto have_skb;
|
||||||
|
@ -326,17 +384,17 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
|
||||||
* the page fragment to a new SKB and pass it up the
|
* the page fragment to a new SKB and pass it up the
|
||||||
* stack.
|
* stack.
|
||||||
*/
|
*/
|
||||||
skb = gve_rx_add_frags(dev, napi, page_info, len);
|
skb = gve_rx_add_frags(napi, page_info, len);
|
||||||
if (!skb) {
|
if (!skb) {
|
||||||
u64_stats_update_begin(&rx->statss);
|
u64_stats_update_begin(&rx->statss);
|
||||||
rx->rx_skb_alloc_fail++;
|
rx->rx_skb_alloc_fail++;
|
||||||
u64_stats_update_end(&rx->statss);
|
u64_stats_update_end(&rx->statss);
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
/* Make sure the kernel stack can't release the page */
|
/* Make sure the kernel stack can't release the page */
|
||||||
get_page(page_info->page);
|
get_page(page_info->page);
|
||||||
/* "flip" to other packet buffer on this page */
|
/* "flip" to other packet buffer on this page */
|
||||||
gve_rx_flip_buff(page_info, &rx->data.data_ring[idx]);
|
gve_rx_flip_buff(page_info, &rx->data.data_ring[idx].qpl_offset);
|
||||||
} else if (pagecount >= 2) {
|
} else if (pagecount >= 2) {
|
||||||
/* We have previously passed the other half of this
|
/* We have previously passed the other half of this
|
||||||
* page up the stack, but it has not yet been freed.
|
* page up the stack, but it has not yet been freed.
|
||||||
|
@ -347,7 +405,10 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
skb = gve_rx_copy(rx, dev, napi, page_info, len);
|
if (rx->data.raw_addressing)
|
||||||
|
skb = gve_rx_add_frags(napi, page_info, len);
|
||||||
|
else
|
||||||
|
skb = gve_rx_copy(rx, dev, napi, page_info, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
have_skb:
|
have_skb:
|
||||||
|
@ -358,7 +419,7 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
|
||||||
u64_stats_update_begin(&rx->statss);
|
u64_stats_update_begin(&rx->statss);
|
||||||
rx->rx_skb_alloc_fail++;
|
rx->rx_skb_alloc_fail++;
|
||||||
u64_stats_update_end(&rx->statss);
|
u64_stats_update_end(&rx->statss);
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(feat & NETIF_F_RXCSUM)) {
|
if (likely(feat & NETIF_F_RXCSUM)) {
|
||||||
|
@ -399,19 +460,48 @@ static bool gve_rx_work_pending(struct gve_rx_ring *rx)
|
||||||
return (GVE_SEQNO(flags_seq) == rx->desc.seqno);
|
return (GVE_SEQNO(flags_seq) == rx->desc.seqno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool gve_rx_refill_buffers(struct gve_priv *priv, struct gve_rx_ring *rx)
|
||||||
|
{
|
||||||
|
int refill_target = rx->mask + 1;
|
||||||
|
u32 fill_cnt = rx->fill_cnt;
|
||||||
|
|
||||||
|
while (fill_cnt - rx->cnt < refill_target) {
|
||||||
|
struct gve_rx_slot_page_info *page_info;
|
||||||
|
struct device *dev = &priv->pdev->dev;
|
||||||
|
union gve_rx_data_slot *data_slot;
|
||||||
|
u32 idx = fill_cnt & rx->mask;
|
||||||
|
|
||||||
|
page_info = &rx->data.page_info[idx];
|
||||||
|
data_slot = &rx->data.data_ring[idx];
|
||||||
|
gve_rx_free_buffer(dev, page_info, data_slot);
|
||||||
|
page_info->page = NULL;
|
||||||
|
if (gve_rx_alloc_buffer(priv, dev, page_info, data_slot)) {
|
||||||
|
u64_stats_update_begin(&rx->statss);
|
||||||
|
rx->rx_buf_alloc_fail++;
|
||||||
|
u64_stats_update_end(&rx->statss);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fill_cnt++;
|
||||||
|
}
|
||||||
|
rx->fill_cnt = fill_cnt;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget,
|
bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget,
|
||||||
netdev_features_t feat)
|
netdev_features_t feat)
|
||||||
{
|
{
|
||||||
struct gve_priv *priv = rx->gve;
|
struct gve_priv *priv = rx->gve;
|
||||||
|
u32 work_done = 0, packets = 0;
|
||||||
struct gve_rx_desc *desc;
|
struct gve_rx_desc *desc;
|
||||||
u32 cnt = rx->cnt;
|
u32 cnt = rx->cnt;
|
||||||
u32 idx = cnt & rx->mask;
|
u32 idx = cnt & rx->mask;
|
||||||
u32 work_done = 0;
|
|
||||||
u64 bytes = 0;
|
u64 bytes = 0;
|
||||||
|
|
||||||
desc = rx->desc.desc_ring + idx;
|
desc = rx->desc.desc_ring + idx;
|
||||||
while ((GVE_SEQNO(desc->flags_seq) == rx->desc.seqno) &&
|
while ((GVE_SEQNO(desc->flags_seq) == rx->desc.seqno) &&
|
||||||
work_done < budget) {
|
work_done < budget) {
|
||||||
|
bool dropped;
|
||||||
|
|
||||||
netif_info(priv, rx_status, priv->dev,
|
netif_info(priv, rx_status, priv->dev,
|
||||||
"[%d] idx=%d desc=%p desc->flags_seq=0x%x\n",
|
"[%d] idx=%d desc=%p desc->flags_seq=0x%x\n",
|
||||||
rx->q_num, idx, desc, desc->flags_seq);
|
rx->q_num, idx, desc, desc->flags_seq);
|
||||||
|
@ -419,9 +509,11 @@ bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget,
|
||||||
"[%d] seqno=%d rx->desc.seqno=%d\n",
|
"[%d] seqno=%d rx->desc.seqno=%d\n",
|
||||||
rx->q_num, GVE_SEQNO(desc->flags_seq),
|
rx->q_num, GVE_SEQNO(desc->flags_seq),
|
||||||
rx->desc.seqno);
|
rx->desc.seqno);
|
||||||
bytes += be16_to_cpu(desc->len) - GVE_RX_PAD;
|
dropped = !gve_rx(rx, desc, feat, idx);
|
||||||
if (!gve_rx(rx, desc, feat, idx))
|
if (!dropped) {
|
||||||
gve_schedule_reset(priv);
|
bytes += be16_to_cpu(desc->len) - GVE_RX_PAD;
|
||||||
|
packets++;
|
||||||
|
}
|
||||||
cnt++;
|
cnt++;
|
||||||
idx = cnt & rx->mask;
|
idx = cnt & rx->mask;
|
||||||
desc = rx->desc.desc_ring + idx;
|
desc = rx->desc.desc_ring + idx;
|
||||||
|
@ -429,15 +521,34 @@ bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget,
|
||||||
work_done++;
|
work_done++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!work_done)
|
if (!work_done && rx->fill_cnt - cnt > rx->db_threshold)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
u64_stats_update_begin(&rx->statss);
|
u64_stats_update_begin(&rx->statss);
|
||||||
rx->rpackets += work_done;
|
rx->rpackets += packets;
|
||||||
rx->rbytes += bytes;
|
rx->rbytes += bytes;
|
||||||
u64_stats_update_end(&rx->statss);
|
u64_stats_update_end(&rx->statss);
|
||||||
rx->cnt = cnt;
|
rx->cnt = cnt;
|
||||||
rx->fill_cnt += work_done;
|
|
||||||
|
/* restock ring slots */
|
||||||
|
if (!rx->data.raw_addressing) {
|
||||||
|
/* In QPL mode buffs are refilled as the desc are processed */
|
||||||
|
rx->fill_cnt += work_done;
|
||||||
|
} else if (rx->fill_cnt - cnt <= rx->db_threshold) {
|
||||||
|
/* In raw addressing mode buffs are only refilled if the avail
|
||||||
|
* falls below a threshold.
|
||||||
|
*/
|
||||||
|
if (!gve_rx_refill_buffers(priv, rx))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* If we were not able to completely refill buffers, we'll want
|
||||||
|
* to schedule this queue for work again to refill buffers.
|
||||||
|
*/
|
||||||
|
if (rx->fill_cnt - cnt <= rx->db_threshold) {
|
||||||
|
gve_rx_write_doorbell(priv, rx);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gve_rx_write_doorbell(priv, rx);
|
gve_rx_write_doorbell(priv, rx);
|
||||||
return gve_rx_work_pending(rx);
|
return gve_rx_work_pending(rx);
|
||||||
|
|
Loading…
Reference in New Issue