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(dev: priv->dev, mask: get_cpu_mask(cpu: ntfy_idx % active_cpus), |
38 | index: 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, length: len); |
73 | if (unlikely(!skb)) |
74 | return NULL; |
75 | |
76 | __skb_put(skb, len); |
77 | skb_copy_to_linear_data_offset(skb, offset: 0, from: 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, data: 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: 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: 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(dev: priv->dev, napi: &block->napi, poll: 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(napi: &block->napi); |
121 | } |
122 | |