return work_done;
 }
 
+static const struct cpumask *gve_get_node_mask(struct gve_priv *priv)
+{
+       if (priv->numa_node == NUMA_NO_NODE)
+               return cpu_all_mask;
+       else
+               return cpumask_of_node(priv->numa_node);
+}
+
 static int gve_alloc_notify_blocks(struct gve_priv *priv)
 {
        int num_vecs_requested = priv->num_ntfy_blks + 1;
-       unsigned int active_cpus;
+       const struct cpumask *node_mask;
+       unsigned int cur_cpu;
        int vecs_enabled;
        int i, j;
        int err;
                if (priv->rx_cfg.num_queues > priv->rx_cfg.max_queues)
                        priv->rx_cfg.num_queues = priv->rx_cfg.max_queues;
        }
-       /* Half the notification blocks go to TX and half to RX */
-       active_cpus = min_t(int, priv->num_ntfy_blks / 2, num_online_cpus());
 
        /* Setup Management Vector  - the last vector */
        snprintf(priv->mgmt_msix_name, sizeof(priv->mgmt_msix_name), "gve-mgmnt@pci:%s",
        }
 
        /* Setup the other blocks - the first n-1 vectors */
+       node_mask = gve_get_node_mask(priv);
+       cur_cpu = cpumask_first(node_mask);
        for (i = 0; i < priv->num_ntfy_blks; i++) {
                struct gve_notify_block *block = &priv->ntfy_blocks[i];
                int msix_idx = i;
                        goto abort_with_some_ntfy_blocks;
                }
                block->irq = priv->msix_vectors[msix_idx].vector;
-               irq_set_affinity_hint(priv->msix_vectors[msix_idx].vector,
-                                     get_cpu_mask(i % active_cpus));
+               irq_set_affinity_and_hint(block->irq,
+                                         cpumask_of(cur_cpu));
                block->irq_db_index = &priv->irq_db_indices[i].index;
+
+               cur_cpu = cpumask_next(cur_cpu, node_mask);
+               /* Wrap once CPUs in the node have been exhausted, or when
+                * starting RX queue affinities. TX and RX queues of the same
+                * index share affinity.
+                */
+               if (cur_cpu >= nr_cpu_ids || (i + 1) == priv->tx_cfg.max_queues)
+                       cur_cpu = cpumask_first(node_mask);
        }
        return 0;
 abort_with_some_ntfy_blocks:
                   struct page **page, dma_addr_t *dma,
                   enum dma_data_direction dir, gfp_t gfp_flags)
 {
-       *page = alloc_page(gfp_flags);
+       *page = alloc_pages_node(priv->numa_node, gfp_flags, 0);
        if (!*page) {
                priv->page_alloc_fail++;
                return -ENOMEM;
         */
        priv->num_ntfy_blks = (num_ntfy - 1) & ~0x1;
        priv->mgmt_msix_idx = priv->num_ntfy_blks;
+       priv->numa_node = dev_to_node(&priv->pdev->dev);
 
        priv->tx_cfg.max_queues =
                min_t(int, priv->tx_cfg.max_queues, priv->num_ntfy_blks / 2);
 
         */
        slots = rx->mask + 1;
 
-       rx->data.page_info = kvzalloc(slots *
-                                     sizeof(*rx->data.page_info), GFP_KERNEL);
+       rx->data.page_info = kvcalloc_node(slots, sizeof(*rx->data.page_info),
+                                          GFP_KERNEL, priv->numa_node);
        if (!rx->data.page_info)
                return -ENOMEM;
 
 
        if (!rx->data.raw_addressing) {
                for (j = 0; j < rx->qpl_copy_pool_mask + 1; j++) {
-                       struct page *page = alloc_page(GFP_KERNEL);
+                       struct page *page = alloc_pages_node(priv->numa_node,
+                                                            GFP_KERNEL, 0);
 
                        if (!page) {
                                err = -ENOMEM;
 
        rx->qpl_copy_pool_mask = min_t(u32, U32_MAX, slots * 2) - 1;
        rx->qpl_copy_pool_head = 0;
-       rx->qpl_copy_pool = kvcalloc(rx->qpl_copy_pool_mask + 1,
-                                    sizeof(rx->qpl_copy_pool[0]),
-                                    GFP_KERNEL);
-
+       rx->qpl_copy_pool = kvcalloc_node(rx->qpl_copy_pool_mask + 1,
+                                         sizeof(rx->qpl_copy_pool[0]),
+                                         GFP_KERNEL, priv->numa_node);
        if (!rx->qpl_copy_pool) {
                err = -ENOMEM;
                goto abort_with_slots;
 
 
        rx->dqo.num_buf_states = cfg->raw_addressing ? buffer_queue_slots :
                gve_get_rx_pages_per_qpl_dqo(cfg->ring_size);
-       rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states,
-                                     sizeof(rx->dqo.buf_states[0]),
-                                     GFP_KERNEL);
+       rx->dqo.buf_states = kvcalloc_node(rx->dqo.num_buf_states,
+                                          sizeof(rx->dqo.buf_states[0]),
+                                          GFP_KERNEL, priv->numa_node);
        if (!rx->dqo.buf_states)
                return -ENOMEM;
 
                                struct gve_rx_buf_state_dqo *buf_state,
                                u16 buf_len)
 {
-       struct page *page = alloc_page(GFP_ATOMIC);
+       struct page *page = alloc_pages_node(rx->gve->numa_node, GFP_ATOMIC, 0);
        int num_frags;
 
        if (!page)