From e200365d695393b9e18a28605fd2e10c555129cd Mon Sep 17 00:00:00 2001
From: Michal Krawczyk <mk@semihalf.com>
Date: Thu, 7 Jun 2018 11:43:01 +0200
Subject: [PATCH 016/166] net/ena: add LSC intr support and AENQ handling

To make the LSC interrupt working, the AENQ must be configured properly
in the ENA device. The AENQ interrupt is common for all maintenance
interrupts - the proper handler is then executed depending on the
received descriptor.

Signed-off-by: Michal Krawczyk <mk@semihalf.com>
---
 drivers/net/ena/ena_ethdev.c | 53 +++++++++++++++++++++++++++++++-----
 drivers/net/ena/ena_ethdev.h |  2 ++
 2 files changed, 48 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c
index d8c3b3ee81..e70e7d3dbc 100644
--- a/drivers/net/ena/ena_ethdev.c
+++ b/drivers/net/ena/ena_ethdev.c
@@ -203,7 +203,7 @@ static const struct rte_pci_id pci_id_ena_map[] = {
 	{ .device_id = 0 },
 };
 
-static struct ena_aenq_handlers empty_aenq_handlers;
+static struct ena_aenq_handlers aenq_handlers;
 
 static int ena_device_init(struct ena_com_dev *ena_dev,
 			   struct ena_com_dev_get_features_ctx *get_feat_ctx);
@@ -734,8 +734,11 @@ static int ena_link_update(struct rte_eth_dev *dev,
 			   __rte_unused int wait_to_complete)
 {
 	struct rte_eth_link *link = &dev->data->dev_link;
+	struct ena_adapter *adapter;
+
+	adapter = (struct ena_adapter *)(dev->data->dev_private);
 
-	link->link_status = 1;
+	link->link_status = adapter->link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
 	link->link_speed = ETH_SPEED_NUM_NONE;
 	link->link_duplex = ETH_LINK_FULL_DUPLEX;
 
@@ -1241,6 +1244,7 @@ static int ena_populate_rx_queue(struct ena_ring *rxq, unsigned int count)
 static int ena_device_init(struct ena_com_dev *ena_dev,
 			   struct ena_com_dev_get_features_ctx *get_feat_ctx)
 {
+	uint32_t aenq_groups;
 	int rc;
 	bool readless_supported;
 
@@ -1276,7 +1280,7 @@ static int ena_device_init(struct ena_com_dev *ena_dev,
 	ena_dev->dma_addr_bits = ena_com_get_dma_width(ena_dev);
 
 	/* ENA device administration layer init */
-	rc = ena_com_admin_init(ena_dev, &empty_aenq_handlers, true);
+	rc = ena_com_admin_init(ena_dev, &aenq_handlers, true);
 	if (rc) {
 		RTE_LOG(ERR, PMD,
 			"cannot initialize ena admin queue with device\n");
@@ -1299,6 +1303,15 @@ static int ena_device_init(struct ena_com_dev *ena_dev,
 		goto err_admin_init;
 	}
 
+	aenq_groups = BIT(ENA_ADMIN_LINK_CHANGE);
+
+	aenq_groups &= get_feat_ctx->aenq.supported_groups;
+	rc = ena_com_set_aenq_config(ena_dev, aenq_groups);
+	if (rc) {
+		RTE_LOG(ERR, PMD, "Cannot configure aenq groups rc: %d\n", rc);
+		goto err_admin_init;
+	}
+
 	return 0;
 
 err_admin_init:
@@ -1310,12 +1323,14 @@ static int ena_device_init(struct ena_com_dev *ena_dev,
 	return rc;
 }
 
-static void ena_interrupt_handler_rte(__rte_unused void *cb_arg)
+static void ena_interrupt_handler_rte(void *cb_arg)
 {
 	struct ena_adapter *adapter = (struct ena_adapter *)cb_arg;
 	struct ena_com_dev *ena_dev = &adapter->ena_dev;
 
 	ena_com_admin_q_comp_intr_handler(ena_dev);
+	if (adapter->state != ENA_ADAPTER_STATE_CLOSED)
+		ena_com_aenq_intr_handler(ena_dev, adapter);
 }
 
 static int eth_ena_dev_init(struct rte_eth_dev *eth_dev)
@@ -1419,6 +1434,7 @@ static int eth_ena_dev_init(struct rte_eth_dev *eth_dev)
 				   adapter);
 	rte_intr_enable(intr_handle);
 	ena_com_set_admin_polling_mode(ena_dev, false);
+	ena_com_admin_aenq_enable(ena_dev);
 
 	adapters_found++;
 	adapter->state = ENA_ADAPTER_STATE_INIT;
@@ -1906,6 +1922,9 @@ static uint16_t eth_ena_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 	return sent_idx;
 }
 
+/*********************************************************************
+ *  PMD configuration
+ *********************************************************************/
 static int eth_ena_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 	struct rte_pci_device *pci_dev)
 {
@@ -1920,7 +1939,7 @@ static int eth_ena_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver rte_ena_pmd = {
 	.id_table = pci_id_ena_map,
-	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
 	.probe = eth_ena_pci_probe,
 	.remove = eth_ena_pci_remove,
 };
@@ -1944,6 +1963,26 @@ ena_init_log(void)
 /******************************************************************************
  ******************************** AENQ Handlers *******************************
  *****************************************************************************/
+static void ena_update_on_link_change(void *adapter_data,
+				      struct ena_admin_aenq_entry *aenq_e)
+{
+	struct rte_eth_dev *eth_dev;
+	struct ena_adapter *adapter;
+	struct ena_admin_aenq_link_change_desc *aenq_link_desc;
+	uint32_t status;
+
+	adapter = (struct ena_adapter *)adapter_data;
+	aenq_link_desc = (struct ena_admin_aenq_link_change_desc *)aenq_e;
+	eth_dev = adapter->rte_dev;
+
+	status = get_ena_admin_aenq_link_change_desc_link_status(aenq_link_desc);
+	adapter->link_status = status;
+
+	ena_link_update(eth_dev, 0);
+	_rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_INTR_LSC, NULL,
+				      NULL);
+}
+
 /**
  * This handler will called for unknown event group or unimplemented handlers
  **/
@@ -1953,9 +1992,9 @@ static void unimplemented_aenq_handler(__rte_unused void *data,
 	// Unimplemented handler
 }
 
-static struct ena_aenq_handlers empty_aenq_handlers = {
+static struct ena_aenq_handlers aenq_handlers = {
 	.handlers = {
-		[ENA_ADMIN_LINK_CHANGE] = unimplemented_aenq_handler,
+		[ENA_ADMIN_LINK_CHANGE] = ena_update_on_link_change,
 		[ENA_ADMIN_NOTIFICATION] = unimplemented_aenq_handler,
 		[ENA_ADMIN_KEEP_ALIVE] = unimplemented_aenq_handler
 	},
diff --git a/drivers/net/ena/ena_ethdev.h b/drivers/net/ena/ena_ethdev.h
index 79fb14aebf..16172a54ac 100644
--- a/drivers/net/ena/ena_ethdev.h
+++ b/drivers/net/ena/ena_ethdev.h
@@ -181,6 +181,8 @@ struct ena_adapter {
 	uint64_t tx_selected_offloads;
 	uint64_t rx_supported_offloads;
 	uint64_t rx_selected_offloads;
+
+	bool link_status;
 };
 
 #endif /* _ENA_ETHDEV_H_ */
-- 
2.25.1

