aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ena/ena.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ena/ena.c')
-rw-r--r--sys/dev/ena/ena.c306
1 files changed, 249 insertions, 57 deletions
diff --git a/sys/dev/ena/ena.c b/sys/dev/ena/ena.c
index 3ff32cc9966c..af158b5aea1d 100644
--- a/sys/dev/ena/ena.c
+++ b/sys/dev/ena/ena.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2015-2023 Amazon.com, Inc. or its affiliates.
+ * Copyright (c) 2015-2024 Amazon.com, Inc. or its affiliates.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -148,7 +148,7 @@ static int ena_ioctl(if_t, u_long, caddr_t);
static int ena_get_dev_offloads(struct ena_com_dev_get_features_ctx *);
static void ena_update_host_info(struct ena_admin_host_info *, if_t);
static void ena_update_hwassist(struct ena_adapter *);
-static int ena_setup_ifnet(device_t, struct ena_adapter *,
+static void ena_setup_ifnet(device_t, struct ena_adapter *,
struct ena_com_dev_get_features_ctx *);
static int ena_enable_wc(device_t, struct resource *);
static int ena_set_queues_placement_policy(device_t, struct ena_com_dev *,
@@ -156,7 +156,7 @@ static int ena_set_queues_placement_policy(device_t, struct ena_com_dev *,
static int ena_map_llq_mem_bar(device_t, struct ena_com_dev *);
static uint32_t ena_calc_max_io_queue_num(device_t, struct ena_com_dev *,
struct ena_com_dev_get_features_ctx *);
-static int ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *);
+static int ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *, struct ena_adapter *);
static void ena_config_host_info(struct ena_com_dev *, device_t);
static int ena_attach(device_t);
static int ena_detach(device_t);
@@ -169,6 +169,11 @@ static int ena_copy_eni_metrics(struct ena_adapter *);
static int ena_copy_srd_metrics(struct ena_adapter *);
static int ena_copy_customer_metrics(struct ena_adapter *);
static void ena_timer_service(void *);
+static enum ena_regs_reset_reason_types check_cdesc_in_tx_cq(struct ena_adapter *,
+ struct ena_ring *);
+#ifdef DEV_NETMAP
+static int ena_reinit_netmap(struct ena_adapter *adapter);
+#endif
static char ena_version[] = ENA_DEVICE_NAME ENA_DRV_MODULE_NAME
" v" ENA_DRV_MODULE_VERSION;
@@ -560,6 +565,32 @@ ena_free_rx_dma_tag(struct ena_adapter *adapter)
return (ret);
}
+int
+validate_tx_req_id(struct ena_ring *tx_ring, uint16_t req_id, int tx_req_id_rc)
+{
+ struct ena_adapter *adapter = tx_ring->adapter;
+ enum ena_regs_reset_reason_types reset_reason = ENA_REGS_RESET_INV_TX_REQ_ID;
+
+ if (unlikely(tx_req_id_rc != 0)) {
+ if (tx_req_id_rc == ENA_COM_FAULT) {
+ reset_reason = ENA_REGS_RESET_TX_DESCRIPTOR_MALFORMED;
+ ena_log(adapter->pdev, ERR,
+ "TX descriptor malformed. req_id %hu qid %hu\n",
+ req_id, tx_ring->qid);
+ } else if (tx_req_id_rc == ENA_COM_INVAL) {
+ ena_log_nm(adapter->pdev, WARN,
+ "Invalid req_id %hu in qid %hu\n",
+ req_id, tx_ring->qid);
+ counter_u64_add(tx_ring->tx_stats.bad_req_id, 1);
+ }
+
+ ena_trigger_reset(adapter, reset_reason);
+ return (EFAULT);
+ }
+
+ return (0);
+}
+
static void
ena_release_all_tx_dmamap(struct ena_ring *tx_ring)
{
@@ -1133,6 +1164,21 @@ ena_refill_rx_bufs(struct ena_ring *rx_ring, uint32_t num)
return (i);
}
+#ifdef DEV_NETMAP
+static int
+ena_reinit_netmap(struct ena_adapter *adapter)
+{
+ int rc;
+
+ netmap_detach(adapter->ifp);
+ rc = ena_netmap_attach(adapter);
+ if (rc != 0)
+ ena_log(adapter->pdev, ERR, "netmap attach failed: %d\n", rc);
+
+ return rc;
+}
+
+#endif /* DEV_NETMAP */
int
ena_update_buf_ring_size(struct ena_adapter *adapter,
uint32_t new_buf_ring_size)
@@ -1150,6 +1196,12 @@ ena_update_buf_ring_size(struct ena_adapter *adapter,
/* Reconfigure buf ring for all Tx rings. */
ena_free_all_io_rings_resources(adapter);
ena_init_io_rings_advanced(adapter);
+#ifdef DEV_NETMAP
+ rc = ena_reinit_netmap(adapter);
+ if (rc != 0)
+ return rc;
+
+#endif /* DEV_NETMAP */
if (dev_was_up) {
/*
* If ena_up() fails, it's not because of recent buf_ring size
@@ -1167,7 +1219,12 @@ ena_update_buf_ring_size(struct ena_adapter *adapter,
adapter->buf_ring_size = old_buf_ring_size;
ena_free_all_io_rings_resources(adapter);
ena_init_io_rings_advanced(adapter);
+#ifdef DEV_NETMAP
+ rc = ena_reinit_netmap(adapter);
+ if (rc != 0)
+ return rc;
+#endif /* DEV_NETMAP */
ENA_FLAG_SET_ATOMIC(ENA_FLAG_DEV_UP_BEFORE_RESET,
adapter);
ena_trigger_reset(adapter, ENA_REGS_RESET_OS_TRIGGER);
@@ -1195,6 +1252,12 @@ ena_update_queue_size(struct ena_adapter *adapter, uint32_t new_tx_size,
/* Configure queues with new size. */
ena_init_io_rings_basic(adapter);
+#ifdef DEV_NETMAP
+ rc = ena_reinit_netmap(adapter);
+ if (rc != 0)
+ return rc;
+
+#endif /* DEV_NETMAP */
if (dev_was_up) {
rc = ena_up(adapter);
if (unlikely(rc != 0)) {
@@ -1206,7 +1269,12 @@ ena_update_queue_size(struct ena_adapter *adapter, uint32_t new_tx_size,
adapter->requested_tx_ring_size = old_tx_size;
adapter->requested_rx_ring_size = old_rx_size;
ena_init_io_rings_basic(adapter);
+#ifdef DEV_NETMAP
+ rc = ena_reinit_netmap(adapter);
+ if (rc != 0)
+ return rc;
+#endif /* DEV_NETMAP */
/* And try again. */
rc = ena_up(adapter);
if (unlikely(rc != 0)) {
@@ -1330,7 +1398,12 @@ ena_update_io_queue_nb(struct ena_adapter *adapter, uint32_t new_num)
ena_down(adapter);
ena_update_io_rings(adapter, new_num);
+#ifdef DEV_NETMAP
+ rc = ena_reinit_netmap(adapter);
+ if (rc != 0)
+ return rc;
+#endif /* DEV_NETMAP */
if (dev_was_up) {
rc = ena_up(adapter);
if (unlikely(rc != 0)) {
@@ -1340,7 +1413,12 @@ ena_update_io_queue_nb(struct ena_adapter *adapter, uint32_t new_num)
new_num, old_num);
ena_update_io_rings(adapter, old_num);
+#ifdef DEV_NETMAP
+ rc = ena_reinit_netmap(adapter);
+ if (rc != 0)
+ return rc;
+#endif /* DEV_NETMAP */
rc = ena_up(adapter);
if (unlikely(rc != 0)) {
ena_log(adapter->pdev, ERR,
@@ -2462,7 +2540,7 @@ ena_update_hwassist(struct ena_adapter *adapter)
if_sethwassistbits(ifp, flags, 0);
}
-static int
+static void
ena_setup_ifnet(device_t pdev, struct ena_adapter *adapter,
struct ena_com_dev_get_features_ctx *feat)
{
@@ -2470,10 +2548,6 @@ ena_setup_ifnet(device_t pdev, struct ena_adapter *adapter,
int caps = 0;
ifp = adapter->ifp = if_gethandle(IFT_ETHER);
- if (unlikely(ifp == NULL)) {
- ena_log(pdev, ERR, "can not allocate ifnet structure\n");
- return (ENXIO);
- }
if_initname(ifp, device_get_name(pdev), device_get_unit(pdev));
if_setdev(ifp, pdev);
if_setsoftc(ifp, adapter);
@@ -2516,8 +2590,6 @@ ena_setup_ifnet(device_t pdev, struct ena_adapter *adapter,
ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
ether_ifattach(ifp, adapter->mac_addr);
-
- return (0);
}
void
@@ -2684,27 +2756,51 @@ ena_map_llq_mem_bar(device_t pdev, struct ena_com_dev *ena_dev)
}
static inline void
-set_default_llq_configurations(struct ena_llq_configurations *llq_config,
- struct ena_admin_feature_llq_desc *llq)
+ena_set_llq_configurations(struct ena_llq_configurations *llq_config,
+ struct ena_admin_feature_llq_desc *llq, struct ena_adapter *adapter)
{
+ bool use_large_llq;
+
llq_config->llq_header_location = ENA_ADMIN_INLINE_HEADER;
llq_config->llq_stride_ctrl = ENA_ADMIN_MULTIPLE_DESCS_PER_ENTRY;
llq_config->llq_num_decs_before_header =
ENA_ADMIN_LLQ_NUM_DESCS_BEFORE_HEADER_2;
- if ((llq->entry_size_ctrl_supported & ENA_ADMIN_LIST_ENTRY_SIZE_256B) !=
- 0 && ena_force_large_llq_header) {
- llq_config->llq_ring_entry_size =
- ENA_ADMIN_LIST_ENTRY_SIZE_256B;
+
+ switch (ena_force_large_llq_header)
+ {
+ case ENA_LLQ_HEADER_SIZE_POLICY_REGULAR:
+ use_large_llq = false;
+ break;
+ case ENA_LLQ_HEADER_SIZE_POLICY_LARGE:
+ use_large_llq = true;
+ break;
+ case ENA_LLQ_HEADER_SIZE_POLICY_DEFAULT:
+ use_large_llq =
+ (llq->entry_size_recommended == ENA_ADMIN_LIST_ENTRY_SIZE_256B);
+ break;
+ default:
+ use_large_llq = false;
+ ena_log(adapter->pdev, WARN,
+ "force_large_llq_header should have values [0-2]\n");
+ break;
+ }
+
+ if (!(llq->entry_size_ctrl_supported & ENA_ADMIN_LIST_ENTRY_SIZE_256B))
+ use_large_llq = false;
+
+ if (use_large_llq) {
+ llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
llq_config->llq_ring_entry_size_value = 256;
+ adapter->llq_policy = ENA_ADMIN_LIST_ENTRY_SIZE_256B;
} else {
- llq_config->llq_ring_entry_size =
- ENA_ADMIN_LIST_ENTRY_SIZE_128B;
+ llq_config->llq_ring_entry_size = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
llq_config->llq_ring_entry_size_value = 128;
+ adapter->llq_policy = ENA_ADMIN_LIST_ENTRY_SIZE_128B;
}
}
static int
-ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *ctx)
+ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *ctx, struct ena_adapter *adapter)
{
struct ena_admin_feature_llq_desc *llq = &ctx->get_feat_ctx->llq;
struct ena_com_dev *ena_dev = ctx->ena_dev;
@@ -2754,30 +2850,34 @@ ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *ctx)
max_queues->max_packet_rx_descs);
}
- /* round down to the nearest power of 2 */
- max_tx_queue_size = 1 << (flsl(max_tx_queue_size) - 1);
- max_rx_queue_size = 1 << (flsl(max_rx_queue_size) - 1);
-
- /*
- * When forcing large headers, we multiply the entry size by 2,
- * and therefore divide the queue size by 2, leaving the amount
- * of memory used by the queues unchanged.
- */
- if (ena_force_large_llq_header) {
- if ((llq->entry_size_ctrl_supported &
- ENA_ADMIN_LIST_ENTRY_SIZE_256B) != 0 &&
- ena_dev->tx_mem_queue_type ==
- ENA_ADMIN_PLACEMENT_POLICY_DEV) {
- max_tx_queue_size /= 2;
- ena_log(ctx->pdev, INFO,
- "Forcing large headers and decreasing maximum Tx queue size to %d\n",
- max_tx_queue_size);
+ if (adapter->llq_policy == ENA_ADMIN_LIST_ENTRY_SIZE_256B) {
+ if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
+ if (llq->max_wide_llq_depth != max_tx_queue_size) {
+ if (llq->max_wide_llq_depth == 0) {
+ /* if there is no large llq max depth from device, we divide
+ * the queue size by 2, leaving the amount of memory
+ * used by the queues unchanged.
+ */
+ max_tx_queue_size /= 2;
+ } else {
+ max_tx_queue_size = llq->max_wide_llq_depth;
+ }
+ ena_log(ctx->pdev, INFO,
+ "Using large LLQ headers and decreasing maximum Tx queue size to %d\n",
+ max_tx_queue_size);
+ } else {
+ ena_log(ctx->pdev, INFO, "Using large LLQ headers\n");
+ }
} else {
ena_log(ctx->pdev, WARN,
- "Forcing large headers failed: LLQ is disabled or device does not support large headers\n");
+ "Using large headers failed: LLQ is disabled or device does not support large headers\n");
}
}
+ /* round down to the nearest power of 2 */
+ max_tx_queue_size = 1 << (flsl(max_tx_queue_size) - 1);
+ max_rx_queue_size = 1 << (flsl(max_rx_queue_size) - 1);
+
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,
@@ -2917,7 +3017,9 @@ ena_device_init(struct ena_adapter *adapter, device_t pdev,
BIT(ENA_ADMIN_FATAL_ERROR) |
BIT(ENA_ADMIN_WARNING) |
BIT(ENA_ADMIN_NOTIFICATION) |
- BIT(ENA_ADMIN_KEEP_ALIVE);
+ BIT(ENA_ADMIN_KEEP_ALIVE) |
+ BIT(ENA_ADMIN_CONF_NOTIFICATIONS) |
+ BIT(ENA_ADMIN_DEVICE_REQUEST_RESET);
aenq_groups &= get_feat_ctx->aenq.supported_groups;
rc = ena_com_set_aenq_config(ena_dev, aenq_groups);
@@ -2928,7 +3030,7 @@ ena_device_init(struct ena_adapter *adapter, device_t pdev,
*wd_active = !!(aenq_groups & BIT(ENA_ADMIN_KEEP_ALIVE));
- set_default_llq_configurations(&llq_config, &get_feat_ctx->llq);
+ ena_set_llq_configurations(&llq_config, &get_feat_ctx->llq, adapter);
rc = ena_set_queues_placement_policy(pdev, ena_dev, &get_feat_ctx->llq,
&llq_config);
@@ -3008,6 +3110,7 @@ static void
check_for_missing_keep_alive(struct ena_adapter *adapter)
{
sbintime_t timestamp, time;
+ enum ena_regs_reset_reason_types reset_reason = ENA_REGS_RESET_KEEP_ALIVE_TO;
if (adapter->wd_active == 0)
return;
@@ -3019,8 +3122,10 @@ check_for_missing_keep_alive(struct ena_adapter *adapter)
time = getsbinuptime() - timestamp;
if (unlikely(time > adapter->keep_alive_timeout)) {
ena_log(adapter->pdev, ERR, "Keep alive watchdog timeout.\n");
- counter_u64_add(adapter->dev_stats.wd_expired, 1);
- ena_trigger_reset(adapter, ENA_REGS_RESET_KEEP_ALIVE_TO);
+ if (ena_com_aenq_has_keep_alive(adapter->ena_dev))
+ reset_reason = ENA_REGS_RESET_MISSING_ADMIN_INTERRUPT;
+
+ ena_trigger_reset(adapter, reset_reason);
}
}
@@ -3028,11 +3133,15 @@ check_for_missing_keep_alive(struct ena_adapter *adapter)
static void
check_for_admin_com_state(struct ena_adapter *adapter)
{
+ enum ena_regs_reset_reason_types reset_reason = ENA_REGS_RESET_ADMIN_TO;
if (unlikely(ena_com_get_admin_running_state(adapter->ena_dev) == false)) {
ena_log(adapter->pdev, ERR,
"ENA admin queue is not in running state!\n");
counter_u64_add(adapter->dev_stats.admin_q_pause, 1);
- ena_trigger_reset(adapter, ENA_REGS_RESET_ADMIN_TO);
+ if (ena_com_get_missing_admin_interrupt(adapter->ena_dev))
+ reset_reason = ENA_REGS_RESET_MISSING_ADMIN_INTERRUPT;
+
+ ena_trigger_reset(adapter, reset_reason);
}
}
@@ -3060,18 +3169,45 @@ check_for_rx_interrupt_queue(struct ena_adapter *adapter,
return (0);
}
+static enum ena_regs_reset_reason_types
+check_cdesc_in_tx_cq(struct ena_adapter *adapter,
+ struct ena_ring *tx_ring)
+{
+ device_t pdev = adapter->pdev;
+ int rc;
+ u16 req_id;
+
+ rc = ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq, &req_id);
+ /* TX CQ is empty */
+ if (rc == ENA_COM_TRY_AGAIN) {
+ ena_log(pdev, ERR,
+ "No completion descriptors found in CQ %d\n",
+ tx_ring->qid);
+ return ENA_REGS_RESET_MISS_TX_CMPL;
+ }
+
+ /* TX CQ has cdescs */
+ ena_log(pdev, ERR,
+ "Completion descriptors found in CQ %d",
+ tx_ring->qid);
+
+ return ENA_REGS_RESET_MISS_INTERRUPT;
+}
+
static int
check_missing_comp_in_tx_queue(struct ena_adapter *adapter,
struct ena_ring *tx_ring)
{
+ uint32_t missed_tx = 0, new_missed_tx = 0;
device_t pdev = adapter->pdev;
struct bintime curtime, time;
struct ena_tx_buffer *tx_buf;
int time_since_last_cleanup;
int missing_tx_comp_to;
sbintime_t time_offset;
- uint32_t missed_tx = 0;
int i, rc = 0;
+ enum ena_regs_reset_reason_types reset_reason = ENA_REGS_RESET_MISS_TX_CMPL;
+ bool cleanup_scheduled, cleanup_running;
getbinuptime(&curtime);
@@ -3113,23 +3249,37 @@ check_missing_comp_in_tx_queue(struct ena_adapter *adapter,
"%d msecs have passed since last cleanup. Missing Tx timeout value %d msecs.\n",
tx_ring->qid, i, time_since_last_cleanup,
missing_tx_comp_to);
+ /* Add new TX completions which are missed */
+ new_missed_tx++;
}
tx_buf->print_once = false;
missed_tx++;
}
}
-
+ /* Checking if this TX ring missing TX completions have passed the threshold */
if (unlikely(missed_tx > adapter->missing_tx_threshold)) {
ena_log(pdev, ERR,
"The number of lost tx completion is above the threshold "
"(%d > %d). Reset the device\n",
missed_tx, adapter->missing_tx_threshold);
- ena_trigger_reset(adapter, ENA_REGS_RESET_MISS_TX_CMPL);
+ /* Set the reset flag to prevent ena_cleanup() from running */
+ ENA_FLAG_SET_ATOMIC(ENA_FLAG_TRIGGER_RESET, adapter);
+ /* Need to make sure that ENA_FLAG_TRIGGER_RESET is visible to ena_cleanup() and
+ * that cleanup_running is visible to check_missing_comp_in_tx_queue() to
+ * prevent the case of accessing CQ concurrently with check_cdesc_in_tx_cq()
+ */
+ mb();
+ cleanup_scheduled = !!(atomic_load_16(&tx_ring->que->cleanup_task.ta_pending));
+ cleanup_running = !!(atomic_load_8((&tx_ring->cleanup_running)));
+ if (!(cleanup_scheduled || cleanup_running))
+ reset_reason = check_cdesc_in_tx_cq(adapter, tx_ring);
+
+ adapter->reset_reason = reset_reason;
rc = EIO;
}
-
- counter_u64_add(tx_ring->tx_stats.missing_tx_comp, missed_tx);
+ /* Add the newly discovered missing TX completions */
+ counter_u64_add(tx_ring->tx_stats.missing_tx_comp, new_missed_tx);
return (rc);
}
@@ -3588,6 +3738,7 @@ ena_reset_task(void *arg, int pending)
ENA_LOCK_LOCK();
if (likely(ENA_FLAG_ISSET(ENA_FLAG_TRIGGER_RESET, adapter))) {
+ ena_increment_reset_counter(adapter);
ena_destroy_device(adapter, false);
ena_restore_device(adapter);
@@ -3706,6 +3857,8 @@ ena_attach(device_t pdev)
goto err_bus_free;
}
+ ena_dev->ena_min_poll_delay_us = ENA_ADMIN_POLL_DELAY_US;
+
/* Initially clear all the flags */
ENA_FLAG_ZERO(adapter);
@@ -3736,7 +3889,7 @@ ena_attach(device_t pdev)
/* Calculate initial and maximum IO queue number and size */
max_num_io_queues = ena_calc_max_io_queue_num(pdev, ena_dev,
&get_feat_ctx);
- rc = ena_calc_io_queue_size(&calc_queue_ctx);
+ rc = ena_calc_io_queue_size(&calc_queue_ctx, adapter);
if (unlikely((rc != 0) || (max_num_io_queues <= 0))) {
rc = EFAULT;
goto err_com_free;
@@ -3811,11 +3964,7 @@ ena_attach(device_t pdev)
ena_sysctl_add_nodes(adapter);
/* setup network interface */
- rc = ena_setup_ifnet(pdev, adapter, &get_feat_ctx);
- if (unlikely(rc != 0)) {
- ena_log(pdev, ERR, "Error with network interface setup\n");
- goto err_customer_metrics_alloc;
- }
+ ena_setup_ifnet(pdev, adapter, &get_feat_ctx);
/* Initialize reset task queue */
TASK_INIT(&adapter->reset_task, 0, ena_reset_task, adapter);
@@ -3851,9 +4000,9 @@ ena_attach(device_t pdev)
#ifdef DEV_NETMAP
err_detach:
ether_ifdetach(adapter->ifp);
-#endif /* DEV_NETMAP */
-err_customer_metrics_alloc:
+ ifmedia_removeall(&adapter->media);
free(adapter->customer_metrics_array, M_DEVBUF);
+#endif /* DEV_NETMAP */
err_metrics_buffer_destroy:
ena_com_delete_customer_metrics_buffer(ena_dev);
err_msix_free:
@@ -3900,8 +4049,14 @@ ena_detach(device_t pdev)
return (EBUSY);
}
+ rc = bus_generic_detach(pdev);
+ if (rc != 0)
+ return (rc);
+
ether_ifdetach(adapter->ifp);
+ ifmedia_removeall(&adapter->media);
+
/* Stop timer service */
ENA_LOCK_LOCK();
ENA_TIMER_DRAIN(adapter);
@@ -3964,7 +4119,7 @@ ena_detach(device_t pdev)
free(ena_dev, M_DEVBUF);
- return (bus_generic_detach(pdev));
+ return (0);
}
/******************************************************************************
@@ -4050,11 +4205,48 @@ unimplemented_aenq_handler(void *adapter_data,
"Unknown event was received or event with unimplemented handler\n");
}
+static void ena_conf_notification(void *adapter_data,
+ struct ena_admin_aenq_entry *aenq_e)
+{
+ struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
+ struct ena_admin_aenq_conf_notifications_desc *desc;
+ u64 bitmap, bit;
+
+ desc = (struct ena_admin_aenq_conf_notifications_desc *)aenq_e;
+ bitmap = desc->notifications_bitmap;
+
+ if (bitmap == 0) {
+ ena_log(adapter->pdev, INFO,
+ "Empty configuration notification bitmap\n");
+ return;
+ }
+
+ for (bit = ffsll(bitmap); bit != 0; bit = ffsll(bitmap)) {
+ bit--;
+ ena_log(adapter->pdev, INFO,
+ "Sub-optimal configuration notification code: %" PRIu64 " Refer to AWS ENA documentation for additional details and mitigation options.\n",
+ bit + 1);
+ // Clear the processed bit
+ bitmap &= ~(1UL << bit);
+ }
+}
+
+static void ena_admin_device_request_reset(void *adapter_data,
+ struct ena_admin_aenq_entry *aenq_e)
+{
+ struct ena_adapter *adapter = (struct ena_adapter *)adapter_data;
+ ena_log(adapter->pdev, WARN,
+ "The device has detected an unhealthy state, reset is requested\n");
+ ena_trigger_reset(adapter, ENA_REGS_RESET_DEVICE_REQUEST);
+}
+
static struct ena_aenq_handlers aenq_handlers = {
.handlers = {
[ENA_ADMIN_LINK_CHANGE] = ena_update_on_link_change,
[ENA_ADMIN_NOTIFICATION] = ena_notification,
[ENA_ADMIN_KEEP_ALIVE] = ena_keep_alive_wd,
+ [ENA_ADMIN_CONF_NOTIFICATIONS] = ena_conf_notification,
+ [ENA_ADMIN_DEVICE_REQUEST_RESET] = ena_admin_device_request_reset,
},
.unimplemented_handler = unimplemented_aenq_handler
};