ena_init_io_rings_common(adapter, rxr, i);
 
                /* TX specific ring state */
-               txr->ring_size = adapter->tx_ring_size;
+               txr->ring_size = adapter->requested_tx_ring_size;
                txr->tx_max_header_size = ena_dev->tx_max_header_size;
                txr->tx_mem_queue_type = ena_dev->tx_mem_queue_type;
                txr->sgl_size = adapter->max_tx_sgl_size;
                        ena_com_get_nonadaptive_moderation_interval_tx(ena_dev);
 
                /* RX specific ring state */
-               rxr->ring_size = adapter->rx_ring_size;
+               rxr->ring_size = adapter->requested_rx_ring_size;
                rxr->rx_copybreak = adapter->rx_copybreak;
                rxr->sgl_size = adapter->max_rx_sgl_size;
                rxr->smoothed_interval =
 
 /* ena_refill_all_rx_bufs - allocate all queues Rx buffers
  * @adapter: board private structure
- *
  */
 static void ena_refill_all_rx_bufs(struct ena_adapter *adapter)
 {
        ctx.qid = ena_qid;
        ctx.mem_queue_type = ena_dev->tx_mem_queue_type;
        ctx.msix_vector = msix_vector;
-       ctx.queue_size = adapter->tx_ring_size;
+       ctx.queue_size = tx_ring->ring_size;
        ctx.numa_node = cpu_to_node(tx_ring->cpu);
 
        rc = ena_com_create_io_queue(ena_dev, &ctx);
        ctx.direction = ENA_COM_IO_QUEUE_DIRECTION_RX;
        ctx.mem_queue_type = ENA_ADMIN_PLACEMENT_POLICY_HOST;
        ctx.msix_vector = msix_vector;
-       ctx.queue_size = adapter->rx_ring_size;
+       ctx.queue_size = rx_ring->ring_size;
        ctx.numa_node = cpu_to_node(rx_ring->cpu);
 
        rc = ena_com_create_io_queue(ena_dev, &ctx);
        return rc;
 }
 
+static void set_io_rings_size(struct ena_adapter *adapter,
+                                    int new_tx_size, int new_rx_size)
+{
+       int i;
+
+       for (i = 0; i < adapter->num_queues; i++) {
+               adapter->tx_ring[i].ring_size = new_tx_size;
+               adapter->rx_ring[i].ring_size = new_rx_size;
+       }
+}
+
+/* This function allows queue allocation to backoff when the system is
+ * low on memory. If there is not enough memory to allocate io queues
+ * the driver will try to allocate smaller queues.
+ *
+ * The backoff algorithm is as follows:
+ *  1. Try to allocate TX and RX and if successful.
+ *  1.1. return success
+ *
+ *  2. Divide by 2 the size of the larger of RX and TX queues (or both if their size is the same).
+ *
+ *  3. If TX or RX is smaller than 256
+ *  3.1. return failure.
+ *  4. else
+ *  4.1. go back to 1.
+ */
+static int create_queues_with_size_backoff(struct ena_adapter *adapter)
+{
+       int rc, cur_rx_ring_size, cur_tx_ring_size;
+       int new_rx_ring_size, new_tx_ring_size;
+
+       /* current queue sizes might be set to smaller than the requested
+        * ones due to past queue allocation failures.
+        */
+       set_io_rings_size(adapter, adapter->requested_tx_ring_size,
+                         adapter->requested_rx_ring_size);
+
+       while (1) {
+               rc = ena_setup_all_tx_resources(adapter);
+               if (rc)
+                       goto err_setup_tx;
+
+               rc = ena_create_all_io_tx_queues(adapter);
+               if (rc)
+                       goto err_create_tx_queues;
+
+               rc = ena_setup_all_rx_resources(adapter);
+               if (rc)
+                       goto err_setup_rx;
+
+               rc = ena_create_all_io_rx_queues(adapter);
+               if (rc)
+                       goto err_create_rx_queues;
+
+               return 0;
+
+err_create_rx_queues:
+               ena_free_all_io_rx_resources(adapter);
+err_setup_rx:
+               ena_destroy_all_tx_queues(adapter);
+err_create_tx_queues:
+               ena_free_all_io_tx_resources(adapter);
+err_setup_tx:
+               if (rc != -ENOMEM) {
+                       netif_err(adapter, ifup, adapter->netdev,
+                                 "Queue creation failed with error code %d\n",
+                                 rc);
+                       return rc;
+               }
+
+               cur_tx_ring_size = adapter->tx_ring[0].ring_size;
+               cur_rx_ring_size = adapter->rx_ring[0].ring_size;
+
+               netif_err(adapter, ifup, adapter->netdev,
+                         "Not enough memory to create queues with sizes TX=%d, RX=%d\n",
+                         cur_tx_ring_size, cur_rx_ring_size);
+
+               new_tx_ring_size = cur_tx_ring_size;
+               new_rx_ring_size = cur_rx_ring_size;
+
+               /* Decrease the size of the larger queue, or
+                * decrease both if they are the same size.
+                */
+               if (cur_rx_ring_size <= cur_tx_ring_size)
+                       new_tx_ring_size = cur_tx_ring_size / 2;
+               if (cur_rx_ring_size >= cur_tx_ring_size)
+                       new_rx_ring_size = cur_rx_ring_size / 2;
+
+               if (cur_tx_ring_size < ENA_MIN_RING_SIZE ||
+                   cur_rx_ring_size < ENA_MIN_RING_SIZE) {
+                       netif_err(adapter, ifup, adapter->netdev,
+                                 "Queue creation failed with the smallest possible queue size of %d for both queues. Not retrying with smaller queues\n",
+                                 ENA_MIN_RING_SIZE);
+                       return rc;
+               }
+
+               netif_err(adapter, ifup, adapter->netdev,
+                         "Retrying queue creation with sizes TX=%d, RX=%d\n",
+                         new_tx_ring_size,
+                         new_rx_ring_size);
+
+               set_io_rings_size(adapter, new_tx_ring_size,
+                                 new_rx_ring_size);
+       }
+}
+
 static int ena_up(struct ena_adapter *adapter)
 {
        int rc, i;
        if (rc)
                goto err_req_irq;
 
-       /* allocate transmit descriptors */
-       rc = ena_setup_all_tx_resources(adapter);
+       rc = create_queues_with_size_backoff(adapter);
        if (rc)
-               goto err_setup_tx;
-
-       /* allocate receive descriptors */
-       rc = ena_setup_all_rx_resources(adapter);
-       if (rc)
-               goto err_setup_rx;
-
-       /* Create TX queues */
-       rc = ena_create_all_io_tx_queues(adapter);
-       if (rc)
-               goto err_create_tx_queues;
-
-       /* Create RX queues */
-       rc = ena_create_all_io_rx_queues(adapter);
-       if (rc)
-               goto err_create_rx_queues;
+               goto err_create_queues_with_backoff;
 
        rc = ena_up_complete(adapter);
        if (rc)
        return rc;
 
 err_up:
-       ena_destroy_all_rx_queues(adapter);
-err_create_rx_queues:
        ena_destroy_all_tx_queues(adapter);
-err_create_tx_queues:
-       ena_free_all_io_rx_resources(adapter);
-err_setup_rx:
        ena_free_all_io_tx_resources(adapter);
-err_setup_tx:
+       ena_destroy_all_rx_queues(adapter);
+       ena_free_all_io_rx_resources(adapter);
+err_create_queues_with_backoff:
        ena_free_io_irq(adapter);
 err_req_irq:
        ena_del_napi(adapter);
        max_tx_queue_size = rounddown_pow_of_two(max_tx_queue_size);
        max_rx_queue_size = rounddown_pow_of_two(max_rx_queue_size);
 
-       tx_queue_size = min_t(u32, tx_queue_size, max_tx_queue_size);
-       rx_queue_size = min_t(u32, rx_queue_size, max_rx_queue_size);
+       tx_queue_size = clamp_val(tx_queue_size, ENA_MIN_RING_SIZE,
+                                 max_tx_queue_size);
+       rx_queue_size = clamp_val(rx_queue_size, ENA_MIN_RING_SIZE,
+                                 max_rx_queue_size);
 
        tx_queue_size = rounddown_pow_of_two(tx_queue_size);
        rx_queue_size = rounddown_pow_of_two(rx_queue_size);
 
-       if (unlikely(!rx_queue_size || !tx_queue_size)) {
-               dev_err(&ctx->pdev->dev, "Invalid queue size\n");
-               return -EFAULT;
-       }
-
        ctx->max_tx_queue_size = max_tx_queue_size;
        ctx->max_rx_queue_size = max_rx_queue_size;
        ctx->tx_queue_size = tx_queue_size;
        adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
        adapter->reset_reason = ENA_REGS_RESET_NORMAL;
 
-       adapter->tx_ring_size = calc_queue_ctx.tx_queue_size;
-       adapter->rx_ring_size = calc_queue_ctx.rx_queue_size;
+       adapter->requested_tx_ring_size = calc_queue_ctx.tx_queue_size;
+       adapter->requested_rx_ring_size = calc_queue_ctx.rx_queue_size;
        adapter->max_tx_ring_size = calc_queue_ctx.max_tx_queue_size;
        adapter->max_rx_ring_size = calc_queue_ctx.max_rx_queue_size;
        adapter->max_tx_sgl_size = calc_queue_ctx.max_tx_sgl_size;