Skip to content

Commit

Permalink
gve: DQO: Add ring allocation and initialization
Browse files Browse the repository at this point in the history
Allocate the buffer and completion ring structures. Do not populate the
rings yet. That will happen in the respective rx and tx datapath
follow-on patches

Signed-off-by: Bailey Forrest <bcf@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: Catherine Sullivan <csully@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Bailey Forrest authored and David S. Miller committed Jun 24, 2021
1 parent 5e8c5ad commit 9c1a59a
Show file tree
Hide file tree
Showing 7 changed files with 420 additions and 13 deletions.
8 changes: 6 additions & 2 deletions drivers/net/ethernet/google/gve/gve.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ struct gve_rx_ring {
struct gve_queue_resources *q_resources; /* head and tail pointer idx */
dma_addr_t q_resources_bus; /* dma address for the queue resources */
struct u64_stats_sync statss; /* sync stats for 32bit archs */

/* head and tail of skb chain for the current packet or NULL if none */
struct sk_buff *skb_head;
struct sk_buff *skb_tail;
};

/* A TX desc ring entry */
Expand Down Expand Up @@ -816,14 +820,14 @@ void gve_free_page(struct device *dev, struct page *page, dma_addr_t dma,
netdev_tx_t gve_tx(struct sk_buff *skb, struct net_device *dev);
bool gve_tx_poll(struct gve_notify_block *block, int budget);
int gve_tx_alloc_rings(struct gve_priv *priv);
void gve_tx_free_rings(struct gve_priv *priv);
void gve_tx_free_rings_gqi(struct gve_priv *priv);
__be32 gve_tx_load_event_counter(struct gve_priv *priv,
struct gve_tx_ring *tx);
/* rx handling */
void gve_rx_write_doorbell(struct gve_priv *priv, struct gve_rx_ring *rx);
bool gve_rx_poll(struct gve_notify_block *block, int budget);
int gve_rx_alloc_rings(struct gve_priv *priv);
void gve_rx_free_rings(struct gve_priv *priv);
void gve_rx_free_rings_gqi(struct gve_priv *priv);
bool gve_clean_rx_done(struct gve_rx_ring *rx, int budget,
netdev_features_t feat);
/* Reset */
Expand Down
18 changes: 18 additions & 0 deletions drivers/net/ethernet/google/gve/gve_dqo.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,24 @@
netdev_tx_t gve_tx_dqo(struct sk_buff *skb, struct net_device *dev);
bool gve_tx_poll_dqo(struct gve_notify_block *block, bool do_clean);
int gve_rx_poll_dqo(struct gve_notify_block *block, int budget);
int gve_tx_alloc_rings_dqo(struct gve_priv *priv);
void gve_tx_free_rings_dqo(struct gve_priv *priv);
int gve_rx_alloc_rings_dqo(struct gve_priv *priv);
void gve_rx_free_rings_dqo(struct gve_priv *priv);
int gve_clean_tx_done_dqo(struct gve_priv *priv, struct gve_tx_ring *tx,
struct napi_struct *napi);
void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx);
void gve_rx_write_doorbell_dqo(const struct gve_priv *priv, int queue_idx);

static inline void
gve_tx_put_doorbell_dqo(const struct gve_priv *priv,
const struct gve_queue_resources *q_resources, u32 val)
{
u64 index;

index = be32_to_cpu(q_resources->db_index);
iowrite32(val, &priv->db_bar2[index]);
}

static inline void
gve_write_irq_doorbell_dqo(const struct gve_priv *priv,
Expand Down
53 changes: 44 additions & 9 deletions drivers/net/ethernet/google/gve/gve_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,13 +571,21 @@ static int gve_create_rings(struct gve_priv *priv)
netif_dbg(priv, drv, priv->dev, "created %d rx queues\n",
priv->rx_cfg.num_queues);

/* Rx data ring has been prefilled with packet buffers at queue
* allocation time.
* Write the doorbell to provide descriptor slots and packet buffers
* to the NIC.
*/
for (i = 0; i < priv->rx_cfg.num_queues; i++)
gve_rx_write_doorbell(priv, &priv->rx[i]);
if (gve_is_gqi(priv)) {
/* Rx data ring has been prefilled with packet buffers at queue
* allocation time.
*
* Write the doorbell to provide descriptor slots and packet
* buffers to the NIC.
*/
for (i = 0; i < priv->rx_cfg.num_queues; i++)
gve_rx_write_doorbell(priv, &priv->rx[i]);
} else {
for (i = 0; i < priv->rx_cfg.num_queues; i++) {
/* Post buffers and ring doorbell. */
gve_rx_post_buffers_dqo(&priv->rx[i]);
}
}

return 0;
}
Expand Down Expand Up @@ -606,6 +614,15 @@ static void add_napi_init_sync_stats(struct gve_priv *priv,
}
}

static void gve_tx_free_rings(struct gve_priv *priv)
{
if (gve_is_gqi(priv)) {
gve_tx_free_rings_gqi(priv);
} else {
gve_tx_free_rings_dqo(priv);
}
}

static int gve_alloc_rings(struct gve_priv *priv)
{
int err;
Expand All @@ -615,17 +632,26 @@ static int gve_alloc_rings(struct gve_priv *priv)
GFP_KERNEL);
if (!priv->tx)
return -ENOMEM;
err = gve_tx_alloc_rings(priv);

if (gve_is_gqi(priv))
err = gve_tx_alloc_rings(priv);
else
err = gve_tx_alloc_rings_dqo(priv);
if (err)
goto free_tx;

/* Setup rx rings */
priv->rx = kvzalloc(priv->rx_cfg.num_queues * sizeof(*priv->rx),
GFP_KERNEL);
if (!priv->rx) {
err = -ENOMEM;
goto free_tx_queue;
}
err = gve_rx_alloc_rings(priv);

if (gve_is_gqi(priv))
err = gve_rx_alloc_rings(priv);
else
err = gve_rx_alloc_rings_dqo(priv);
if (err)
goto free_rx;

Expand Down Expand Up @@ -670,6 +696,14 @@ static int gve_destroy_rings(struct gve_priv *priv)
return 0;
}

static inline void gve_rx_free_rings(struct gve_priv *priv)
{
if (gve_is_gqi(priv))
gve_rx_free_rings_gqi(priv);
else
gve_rx_free_rings_dqo(priv);
}

static void gve_free_rings(struct gve_priv *priv)
{
int ntfy_idx;
Expand Down Expand Up @@ -869,6 +903,7 @@ static int gve_open(struct net_device *dev)
err = gve_alloc_qpls(priv);
if (err)
return err;

err = gve_alloc_rings(priv);
if (err)
goto free_qpls;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/google/gve/gve_rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ int gve_rx_alloc_rings(struct gve_priv *priv)
return err;
}

void gve_rx_free_rings(struct gve_priv *priv)
void gve_rx_free_rings_gqi(struct gve_priv *priv)
{
int i;

Expand Down
157 changes: 157 additions & 0 deletions drivers/net/ethernet/google/gve/gve_rx_dqo.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,163 @@
#include <net/ipv6.h>
#include <net/tcp.h>

static void gve_free_page_dqo(struct gve_priv *priv,
struct gve_rx_buf_state_dqo *bs)
{
}

static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx)
{
struct gve_rx_ring *rx = &priv->rx[idx];
struct device *hdev = &priv->pdev->dev;
size_t completion_queue_slots;
size_t buffer_queue_slots;
size_t size;
int i;

completion_queue_slots = rx->dqo.complq.mask + 1;
buffer_queue_slots = rx->dqo.bufq.mask + 1;

gve_rx_remove_from_block(priv, idx);

if (rx->q_resources) {
dma_free_coherent(hdev, sizeof(*rx->q_resources),
rx->q_resources, rx->q_resources_bus);
rx->q_resources = NULL;
}

for (i = 0; i < rx->dqo.num_buf_states; i++) {
struct gve_rx_buf_state_dqo *bs = &rx->dqo.buf_states[i];

if (bs->page_info.page)
gve_free_page_dqo(priv, bs);
}

if (rx->dqo.bufq.desc_ring) {
size = sizeof(rx->dqo.bufq.desc_ring[0]) * buffer_queue_slots;
dma_free_coherent(hdev, size, rx->dqo.bufq.desc_ring,
rx->dqo.bufq.bus);
rx->dqo.bufq.desc_ring = NULL;
}

if (rx->dqo.complq.desc_ring) {
size = sizeof(rx->dqo.complq.desc_ring[0]) *
completion_queue_slots;
dma_free_coherent(hdev, size, rx->dqo.complq.desc_ring,
rx->dqo.complq.bus);
rx->dqo.complq.desc_ring = NULL;
}

kvfree(rx->dqo.buf_states);
rx->dqo.buf_states = NULL;

netif_dbg(priv, drv, priv->dev, "freed rx ring %d\n", idx);
}

static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx)
{
struct gve_rx_ring *rx = &priv->rx[idx];
struct device *hdev = &priv->pdev->dev;
size_t size;
int i;

const u32 buffer_queue_slots =
priv->options_dqo_rda.rx_buff_ring_entries;
const u32 completion_queue_slots = priv->rx_desc_cnt;

netif_dbg(priv, drv, priv->dev, "allocating rx ring DQO\n");

memset(rx, 0, sizeof(*rx));
rx->gve = priv;
rx->q_num = idx;
rx->dqo.bufq.mask = buffer_queue_slots - 1;
rx->dqo.complq.num_free_slots = completion_queue_slots;
rx->dqo.complq.mask = completion_queue_slots - 1;
rx->skb_head = NULL;
rx->skb_tail = NULL;

rx->dqo.num_buf_states = min_t(s16, S16_MAX, buffer_queue_slots * 4);
rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states,
sizeof(rx->dqo.buf_states[0]),
GFP_KERNEL);
if (!rx->dqo.buf_states)
return -ENOMEM;

/* Set up linked list of buffer IDs */
for (i = 0; i < rx->dqo.num_buf_states - 1; i++)
rx->dqo.buf_states[i].next = i + 1;

rx->dqo.buf_states[rx->dqo.num_buf_states - 1].next = -1;
rx->dqo.recycled_buf_states.head = -1;
rx->dqo.recycled_buf_states.tail = -1;
rx->dqo.used_buf_states.head = -1;
rx->dqo.used_buf_states.tail = -1;

/* Allocate RX completion queue */
size = sizeof(rx->dqo.complq.desc_ring[0]) *
completion_queue_slots;
rx->dqo.complq.desc_ring =
dma_alloc_coherent(hdev, size, &rx->dqo.complq.bus, GFP_KERNEL);
if (!rx->dqo.complq.desc_ring)
goto err;

/* Allocate RX buffer queue */
size = sizeof(rx->dqo.bufq.desc_ring[0]) * buffer_queue_slots;
rx->dqo.bufq.desc_ring =
dma_alloc_coherent(hdev, size, &rx->dqo.bufq.bus, GFP_KERNEL);
if (!rx->dqo.bufq.desc_ring)
goto err;

rx->q_resources = dma_alloc_coherent(hdev, sizeof(*rx->q_resources),
&rx->q_resources_bus, GFP_KERNEL);
if (!rx->q_resources)
goto err;

gve_rx_add_to_block(priv, idx);

return 0;

err:
gve_rx_free_ring_dqo(priv, idx);
return -ENOMEM;
}

int gve_rx_alloc_rings_dqo(struct gve_priv *priv)
{
int err = 0;
int i;

for (i = 0; i < priv->rx_cfg.num_queues; i++) {
err = gve_rx_alloc_ring_dqo(priv, i);
if (err) {
netif_err(priv, drv, priv->dev,
"Failed to alloc rx ring=%d: err=%d\n",
i, err);
goto err;
}
}

return 0;

err:
for (i--; i >= 0; i--)
gve_rx_free_ring_dqo(priv, i);

return err;
}

void gve_rx_free_rings_dqo(struct gve_priv *priv)
{
int i;

for (i = 0; i < priv->rx_cfg.num_queues; i++)
gve_rx_free_ring_dqo(priv, i);
}

void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx)
{
}

int gve_rx_poll_dqo(struct gve_notify_block *block, int budget)
{
u32 work_done = 0;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/google/gve/gve_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ int gve_tx_alloc_rings(struct gve_priv *priv)
return err;
}

void gve_tx_free_rings(struct gve_priv *priv)
void gve_tx_free_rings_gqi(struct gve_priv *priv)
{
int i;

Expand Down
Loading

0 comments on commit 9c1a59a

Please sign in to comment.