1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Google virtual Ethernet (gve) driver
3 *
4 * Copyright (C) 2015-2021 Google, Inc.
5 */
6
7 #include "gve.h"
8 #include "gve_adminq.h"
9 #include "gve_utils.h"
10
gve_tx_remove_from_block(struct gve_priv * priv,int queue_idx)11 void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx)
12 {
13 struct gve_notify_block *block =
14 &priv->ntfy_blocks[gve_tx_idx_to_ntfy(priv, queue_idx)];
15
16 block->tx = NULL;
17 }
18
gve_tx_add_to_block(struct gve_priv * priv,int queue_idx)19 void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx)
20 {
21 unsigned int active_cpus = min_t(int, priv->num_ntfy_blks / 2,
22 num_online_cpus());
23 int ntfy_idx = gve_tx_idx_to_ntfy(priv, queue_idx);
24 struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
25 struct gve_tx_ring *tx = &priv->tx[queue_idx];
26
27 block->tx = tx;
28 tx->ntfy_id = ntfy_idx;
29 netif_set_xps_queue(priv->dev, get_cpu_mask(ntfy_idx % active_cpus),
30 queue_idx);
31 }
32
gve_rx_remove_from_block(struct gve_priv * priv,int queue_idx)33 void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx)
34 {
35 struct gve_notify_block *block =
36 &priv->ntfy_blocks[gve_rx_idx_to_ntfy(priv, queue_idx)];
37
38 block->rx = NULL;
39 }
40
gve_rx_add_to_block(struct gve_priv * priv,int queue_idx)41 void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx)
42 {
43 u32 ntfy_idx = gve_rx_idx_to_ntfy(priv, queue_idx);
44 struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
45 struct gve_rx_ring *rx = &priv->rx[queue_idx];
46
47 block->rx = rx;
48 rx->ntfy_id = ntfy_idx;
49 }
50
gve_rx_copy(struct net_device * dev,struct napi_struct * napi,struct gve_rx_slot_page_info * page_info,u16 len,u16 padding,struct gve_rx_ctx * ctx)51 struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi,
52 struct gve_rx_slot_page_info *page_info, u16 len,
53 u16 padding, struct gve_rx_ctx *ctx)
54 {
55 void *va = page_info->page_address + padding + page_info->page_offset;
56 int skb_linear_offset = 0;
57 bool set_protocol = false;
58 struct sk_buff *skb;
59
60 if (ctx) {
61 if (!ctx->skb_head)
62 ctx->skb_head = napi_alloc_skb(napi, ctx->total_expected_size);
63
64 if (unlikely(!ctx->skb_head))
65 return NULL;
66 skb = ctx->skb_head;
67 skb_linear_offset = skb->len;
68 set_protocol = ctx->curr_frag_cnt == ctx->expected_frag_cnt - 1;
69 } else {
70 skb = napi_alloc_skb(napi, len);
71
72 if (unlikely(!skb))
73 return NULL;
74 set_protocol = true;
75 }
76 __skb_put(skb, len);
77 skb_copy_to_linear_data_offset(skb, skb_linear_offset, va, len);
78
79 if (set_protocol)
80 skb->protocol = eth_type_trans(skb, dev);
81
82 return skb;
83 }
84
gve_dec_pagecnt_bias(struct gve_rx_slot_page_info * page_info)85 void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info)
86 {
87 page_info->pagecnt_bias--;
88 if (page_info->pagecnt_bias == 0) {
89 int pagecount = page_count(page_info->page);
90
91 /* If we have run out of bias - set it back up to INT_MAX
92 * minus the existing refs.
93 */
94 page_info->pagecnt_bias = INT_MAX - pagecount;
95
96 /* Set pagecount back up to max. */
97 page_ref_add(page_info->page, INT_MAX - pagecount);
98 }
99 }
100