Linux 6.9-rc6
[sfrench/cifs-2.6.git] / drivers / net / ethernet / google / gve / gve_utils.c
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
11 bool gve_tx_was_added_to_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         return block->tx != NULL;
17 }
18
19 void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx)
20 {
21         struct gve_notify_block *block =
22                         &priv->ntfy_blocks[gve_tx_idx_to_ntfy(priv, queue_idx)];
23
24         block->tx = NULL;
25 }
26
27 void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx)
28 {
29         unsigned int active_cpus = min_t(int, priv->num_ntfy_blks / 2,
30                                          num_online_cpus());
31         int ntfy_idx = gve_tx_idx_to_ntfy(priv, queue_idx);
32         struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
33         struct gve_tx_ring *tx = &priv->tx[queue_idx];
34
35         block->tx = tx;
36         tx->ntfy_id = ntfy_idx;
37         netif_set_xps_queue(priv->dev, get_cpu_mask(ntfy_idx % active_cpus),
38                             queue_idx);
39 }
40
41 bool gve_rx_was_added_to_block(struct gve_priv *priv, int queue_idx)
42 {
43         struct gve_notify_block *block =
44                         &priv->ntfy_blocks[gve_rx_idx_to_ntfy(priv, queue_idx)];
45
46         return block->rx != NULL;
47 }
48
49 void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx)
50 {
51         struct gve_notify_block *block =
52                         &priv->ntfy_blocks[gve_rx_idx_to_ntfy(priv, queue_idx)];
53
54         block->rx = NULL;
55 }
56
57 void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx)
58 {
59         u32 ntfy_idx = gve_rx_idx_to_ntfy(priv, queue_idx);
60         struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
61         struct gve_rx_ring *rx = &priv->rx[queue_idx];
62
63         block->rx = rx;
64         rx->ntfy_id = ntfy_idx;
65 }
66
67 struct sk_buff *gve_rx_copy_data(struct net_device *dev, struct napi_struct *napi,
68                                  u8 *data, u16 len)
69 {
70         struct sk_buff *skb;
71
72         skb = napi_alloc_skb(napi, len);
73         if (unlikely(!skb))
74                 return NULL;
75
76         __skb_put(skb, len);
77         skb_copy_to_linear_data_offset(skb, 0, data, len);
78         skb->protocol = eth_type_trans(skb, dev);
79
80         return skb;
81 }
82
83 struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi,
84                             struct gve_rx_slot_page_info *page_info, u16 len)
85 {
86         void *va = page_info->page_address + page_info->page_offset +
87                 page_info->pad;
88
89         return gve_rx_copy_data(dev, napi, va, len);
90 }
91
92 void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info)
93 {
94         page_info->pagecnt_bias--;
95         if (page_info->pagecnt_bias == 0) {
96                 int pagecount = page_count(page_info->page);
97
98                 /* If we have run out of bias - set it back up to INT_MAX
99                  * minus the existing refs.
100                  */
101                 page_info->pagecnt_bias = INT_MAX - pagecount;
102
103                 /* Set pagecount back up to max. */
104                 page_ref_add(page_info->page, INT_MAX - pagecount);
105         }
106 }
107
108 void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
109                   int (*gve_poll)(struct napi_struct *, int))
110 {
111         struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
112
113         netif_napi_add(priv->dev, &block->napi, gve_poll);
114 }
115
116 void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
117 {
118         struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
119
120         netif_napi_del(&block->napi);
121 }