[PATCH 04/14] net: ionic: Export the APIs from net driver to support device commands

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



RDMA driver needs to establish admin queues to support admin operations.
Export the APIs to send device commands, allocate interrupts for
event queues and get doorbell page information.

Reviewed-by: Shannon Nelson <shannon.nelson@xxxxxxx>
Co-developed-by: Allen Hubbe <allen.hubbe@xxxxxxx>
Signed-off-by: Allen Hubbe <allen.hubbe@xxxxxxx>
Signed-off-by: Abhijit Gangurde <abhijit.gangurde@xxxxxxx>
---
 drivers/net/ethernet/pensando/ionic/ionic.h   |  8 +-
 .../net/ethernet/pensando/ionic/ionic_api.c   | 93 ++++++++++++++++++
 .../net/ethernet/pensando/ionic/ionic_api.h   | 94 +++++++++++++++++++
 .../net/ethernet/pensando/ionic/ionic_bus.h   |  1 +
 .../ethernet/pensando/ionic/ionic_bus_pci.c   |  6 ++
 .../net/ethernet/pensando/ionic/ionic_lif.c   | 41 ++++++--
 .../net/ethernet/pensando/ionic/ionic_lif.h   |  5 +
 .../net/ethernet/pensando/ionic/ionic_main.c  |  2 +-
 8 files changed, 237 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/pensando/ionic/ionic.h b/drivers/net/ethernet/pensando/ionic/ionic.h
index 013e1ce72d0d..5abdaf2fa3a6 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic.h
@@ -65,12 +65,6 @@ struct ionic {
 	int watchdog_period;
 };
 
-struct ionic_admin_ctx {
-	struct completion work;
-	union ionic_adminq_cmd cmd;
-	union ionic_adminq_comp comp;
-};
-
 int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx);
 int ionic_adminq_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx,
 		      const int err, const bool do_msg);
@@ -97,4 +91,6 @@ int ionic_port_reset(struct ionic *ionic);
 
 bool ionic_doorbell_wa(struct ionic *ionic);
 
+int ionic_error_to_errno(enum ionic_status_code code);
+
 #endif /* _IONIC_H_ */
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_api.c b/drivers/net/ethernet/pensando/ionic/ionic_api.c
index 8c39e6183ad4..201053cf4ea8 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_api.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_api.c
@@ -4,6 +4,7 @@
 #include <linux/kernel.h>
 
 #include "ionic.h"
+#include "ionic_bus.h"
 #include "ionic_lif.h"
 
 struct net_device *ionic_api_get_netdev_from_handle(void *handle)
@@ -31,6 +32,31 @@ const union ionic_lif_identity *ionic_api_get_identity(void *handle,
 }
 EXPORT_SYMBOL_NS(ionic_api_get_identity, "NET_IONIC");
 
+void ionic_api_request_reset(void *handle)
+{
+	struct ionic_lif *lif = handle;
+	struct ionic *ionic;
+	int err;
+
+	union ionic_dev_cmd cmd = {
+		.cmd.opcode = IONIC_CMD_RDMA_RESET_LIF,
+		.cmd.lif_index = cpu_to_le16(lif->index),
+	};
+
+	ionic = lif->ionic;
+
+	mutex_lock(&ionic->dev_cmd_lock);
+
+	ionic_dev_cmd_go(&ionic->idev, &cmd);
+	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
+
+	mutex_unlock(&ionic->dev_cmd_lock);
+
+	if (err)
+		netdev_warn(lif->netdev, "request_reset: error %d\n", err);
+}
+EXPORT_SYMBOL_NS(ionic_api_request_reset, "NET_IONIC");
+
 const struct ionic_devinfo *ionic_api_get_devinfo(void *handle)
 {
 	struct ionic_lif *lif = handle;
@@ -38,3 +64,70 @@ const struct ionic_devinfo *ionic_api_get_devinfo(void *handle)
 	return &lif->ionic->idev.dev_info;
 }
 EXPORT_SYMBOL_NS(ionic_api_get_devinfo, "NET_IONIC");
+
+int ionic_api_get_intr(void *handle, int *irq)
+{
+	struct ionic_intr_info intr_obj;
+	struct ionic_lif *lif = handle;
+	int err;
+
+	if (!lif->nrdma_eqs_avail)
+		return -ENOSPC;
+
+	err = ionic_intr_alloc(lif->ionic, &intr_obj);
+	if (err)
+		return err;
+
+	err = ionic_bus_get_irq(lif->ionic, intr_obj.index);
+	if (err < 0) {
+		ionic_intr_free(lif->ionic, intr_obj.index);
+		return err;
+	}
+
+	lif->nrdma_eqs_avail--;
+
+	*irq = err;
+	return intr_obj.index;
+}
+EXPORT_SYMBOL_NS(ionic_api_get_intr, "NET_IONIC");
+
+void ionic_api_put_intr(void *handle, int intr_index)
+{
+	struct ionic_lif *lif = handle;
+
+	ionic_intr_free(lif->ionic, intr_index);
+
+	lif->nrdma_eqs_avail++;
+}
+EXPORT_SYMBOL_NS(ionic_api_put_intr, "NET_IONIC");
+
+void ionic_api_kernel_dbpage(void *handle,
+			     struct ionic_intr __iomem **intr_ctrl,
+			     u32 *dbid, u64 __iomem **dbpage)
+{
+	struct ionic_lif *lif = handle;
+
+	*intr_ctrl = lif->ionic->idev.intr_ctrl;
+
+	*dbid = lif->kern_pid;
+	*dbpage = lif->kern_dbpage;
+}
+EXPORT_SYMBOL_NS(ionic_api_kernel_dbpage, "NET_IONIC");
+
+int ionic_api_adminq_post(void *handle, struct ionic_admin_ctx *ctx)
+{
+	return ionic_adminq_post(handle, ctx);
+}
+EXPORT_SYMBOL_NS(ionic_api_adminq_post, "NET_IONIC");
+
+int ionic_api_adminq_post_wait(void *handle, struct ionic_admin_ctx *ctx)
+{
+	return ionic_adminq_post_wait(handle, ctx);
+}
+EXPORT_SYMBOL_NS(ionic_api_adminq_post_wait, "NET_IONIC");
+
+int ionic_api_error_to_errno(enum ionic_status_code code)
+{
+	return ionic_error_to_errno(code);
+}
+EXPORT_SYMBOL_NS(ionic_api_error_to_errno, "NET_IONIC");
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_api.h b/drivers/net/ethernet/pensando/ionic/ionic_api.h
index f59391102c62..80606a37ae45 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_api.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_api.h
@@ -65,4 +65,98 @@ struct net_device *ionic_api_get_netdev_from_handle(void *handle);
  */
 const struct ionic_devinfo *ionic_api_get_devinfo(void *handle);
 
+/**
+ * ionic_api_request_reset - request reset or disable the device or lif
+ * @handle:     Handle to lif
+ *
+ * The reset is triggered asynchronously. It will wait until reset request
+ * completes or times out.
+ */
+void ionic_api_request_reset(void *handle);
+
+/**
+ * ionic_api_get_intr - Reserve a device interrupt index
+ * @handle:     Handle to lif
+ * @irq:        OS interrupt number returned
+ *
+ * Reserve an interrupt index, and indicate the irq number for that index.
+ *
+ * Return: interrupt index or negative error status
+ */
+int ionic_api_get_intr(void *handle, int *irq);
+
+/**
+ * ionic_api_put_intr - Release a device interrupt index
+ * @handle:     Handle to lif
+ * @intr:       Interrupt index
+ *
+ * Mark the interrupt index unused so that it can be reserved again.
+ */
+void ionic_api_put_intr(void *handle, int intr);
+
+/**
+ * ionic_api_kernel_dbpage - Get mapped doorbell page for use in kernel space
+ * @handle:     Handle to lif
+ * @intr_ctrl:  Interrupt control registers
+ * @dbid:       Doorbell id for use in kernel space
+ * @dbpage:     One ioremapped doorbell page for use in kernel space
+ *
+ * This also provides mapped interrupt control registers.
+ *
+ * The id and page returned here refer to the doorbell page reserved for use in
+ * kernel space for this lif.  For user space, use ionic_api_get_dbid to
+ * allocate a doorbell id for exclusive use by a process.
+ */
+void ionic_api_kernel_dbpage(void *handle,
+			     struct ionic_intr __iomem **intr_ctrl,
+			     u32 *dbid, u64 __iomem **dbpage);
+
+/**
+ * struct ionic_admin_ctx - Admin command context
+ * @work:       Work completion wait queue element
+ * @cmd:        Admin command (64B) to be copied to the queue
+ * @comp:       Admin completion (16B) copied from the queue
+ */
+struct ionic_admin_ctx {
+	struct completion work;
+	union ionic_adminq_cmd cmd;
+	union ionic_adminq_comp comp;
+};
+
+/**
+ * ionic_api_adminq_post - Post an admin command
+ * @handle:     Handle to lif
+ * @ctx:        API admin command context
+ *
+ * Post the command to an admin queue in the ethernet driver.  If this command
+ * succeeds, then the command has been posted, but that does not indicate a
+ * completion.  If this command returns success, then the completion callback
+ * will eventually be called.
+ *
+ * Return: zero or negative error status
+ */
+int ionic_api_adminq_post(void *handle, struct ionic_admin_ctx *ctx);
+
+/**
+ * ionic_api_adminq_post_wait - Post an admin command and wait for response
+ * @handle:     Handle to lif
+ * @ctx:        API admin command context
+ *
+ * Post the command to an admin queue in the ethernet driver.  If this command
+ * succeeds, then the command has been posted, but that does not indicate a
+ * completion.  If this command returns success, then the completion callback
+ * will eventually be called.
+ *
+ * Return: zero or negative error status
+ */
+int ionic_api_adminq_post_wait(void *handle, struct ionic_admin_ctx *ctx);
+
+/**
+ * ionic_api_error_to_errno - Transform ionic_if errors to os errno
+ * @code:       Ionic error number
+ *
+ * Return:      Negative OS error number or zero
+ */
+int ionic_api_error_to_errno(enum ionic_status_code code);
+
 #endif /* _IONIC_API_H_ */
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus.h b/drivers/net/ethernet/pensando/ionic/ionic_bus.h
index 2f4d08c64910..0963b6aabd42 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_bus.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_bus.h
@@ -12,5 +12,6 @@ int ionic_bus_register_driver(void);
 void ionic_bus_unregister_driver(void);
 void __iomem *ionic_bus_map_dbpage(struct ionic *ionic, int page_num);
 void ionic_bus_unmap_dbpage(struct ionic *ionic, void __iomem *page);
+phys_addr_t ionic_bus_phys_dbpage(struct ionic *ionic, int page_num);
 
 #endif /* _IONIC_BUS_H_ */
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
index bb75044dfb82..5fa8840b063f 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
@@ -109,6 +109,12 @@ void ionic_bus_unmap_dbpage(struct ionic *ionic, void __iomem *page)
 	iounmap(page);
 }
 
+phys_addr_t ionic_bus_phys_dbpage(struct ionic *ionic, int page_num)
+{
+	return ionic->bars[IONIC_PCI_BAR_DBELL].bus_addr +
+		((phys_addr_t)page_num << PAGE_SHIFT);
+}
+
 static void ionic_vf_dealloc_locked(struct ionic *ionic)
 {
 	struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_STATSADDR };
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index e63ed91879a1..c1ad2b95d2b9 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -244,14 +244,13 @@ static int ionic_request_irq(struct ionic_lif *lif, struct ionic_qcq *qcq)
 				0, intr->name, &qcq->napi);
 }
 
-static int ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr)
+int ionic_intr_alloc(struct ionic *ionic, struct ionic_intr_info *intr)
 {
-	struct ionic *ionic = lif->ionic;
 	int index;
 
 	index = find_first_zero_bit(ionic->intrs, ionic->nintrs);
 	if (index == ionic->nintrs) {
-		netdev_warn(lif->netdev, "%s: no intr, index=%d nintrs=%d\n",
+		netdev_warn(ionic->lif->netdev, "%s: no intr, index=%d nintrs=%d\n",
 			    __func__, index, ionic->nintrs);
 		return -ENOSPC;
 	}
@@ -262,7 +261,7 @@ static int ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr)
 	return 0;
 }
 
-static void ionic_intr_free(struct ionic *ionic, int index)
+void ionic_intr_free(struct ionic *ionic, int index)
 {
 	if (index != IONIC_INTR_INDEX_NOT_ASSIGNED && index < ionic->nintrs)
 		clear_bit(index, ionic->intrs);
@@ -504,7 +503,7 @@ static int ionic_alloc_qcq_interrupt(struct ionic_lif *lif, struct ionic_qcq *qc
 		return 0;
 	}
 
-	err = ionic_intr_alloc(lif, &qcq->intr);
+	err = ionic_intr_alloc(lif->ionic, &qcq->intr);
 	if (err) {
 		netdev_warn(lif->netdev, "no intr for %s: %d\n",
 			    qcq->q.name, err);
@@ -3268,6 +3267,7 @@ int ionic_lif_alloc(struct ionic *ionic)
 	lif->netdev->max_mtu =
 		le32_to_cpu(lif->identity->eth.max_frame_size) - VLAN_ETH_HLEN;
 
+	lif->nrdma_eqs_avail = ionic->nrdma_eqs_per_lif;
 	lif->nrdma_eqs = ionic->nrdma_eqs_per_lif;
 	lif->nxqs = ionic->ntxqs_per_lif;
 
@@ -3295,6 +3295,7 @@ int ionic_lif_alloc(struct ionic *ionic)
 	mutex_init(&lif->queue_lock);
 	mutex_init(&lif->config_lock);
 	mutex_init(&lif->adev_lock);
+	mutex_init(&lif->dbid_inuse_lock);
 
 	spin_lock_init(&lif->adminq_lock);
 
@@ -3351,6 +3352,7 @@ int ionic_lif_alloc(struct ionic *ionic)
 	lif->info = NULL;
 	lif->info_pa = 0;
 err_out_free_mutex:
+	mutex_destroy(&lif->dbid_inuse_lock);
 	mutex_destroy(&lif->adev_lock);
 	mutex_destroy(&lif->config_lock);
 	mutex_destroy(&lif->queue_lock);
@@ -3507,6 +3509,14 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif)
 	dev_err(ionic->dev, "FW Up: LIFs restart failed - err %d\n", err);
 }
 
+static void ionic_lif_dbid_inuse_free(struct ionic_lif *lif)
+{
+	mutex_lock(&lif->dbid_inuse_lock);
+	bitmap_free(lif->dbid_inuse);
+	lif->dbid_inuse = NULL;
+	mutex_unlock(&lif->dbid_inuse_lock);
+}
+
 void ionic_lif_free(struct ionic_lif *lif)
 {
 	struct device *dev = lif->ionic->dev;
@@ -3535,10 +3545,12 @@ void ionic_lif_free(struct ionic_lif *lif)
 	/* unmap doorbell page */
 	ionic_bus_unmap_dbpage(lif->ionic, lif->kern_dbpage);
 	lif->kern_dbpage = NULL;
+	ionic_lif_dbid_inuse_free(lif);
 
 	mutex_destroy(&lif->config_lock);
 	mutex_destroy(&lif->queue_lock);
 	mutex_destroy(&lif->adev_lock);
+	mutex_destroy(&lif->dbid_inuse_lock);
 
 	/* free netdev & lif */
 	ionic_debugfs_del_lif(lif);
@@ -3562,6 +3574,8 @@ void ionic_lif_deinit(struct ionic_lif *lif)
 	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
 	ionic_lif_qcq_deinit(lif, lif->adminqcq);
 
+	ionic_lif_dbid_inuse_free(lif);
+
 	ionic_lif_reset(lif);
 }
 
@@ -3755,12 +3769,25 @@ int ionic_lif_init(struct ionic_lif *lif)
 		return -EINVAL;
 	}
 
+	mutex_lock(&lif->dbid_inuse_lock);
+	lif->dbid_inuse = bitmap_zalloc(lif->dbid_count, GFP_KERNEL);
+	if (!lif->dbid_inuse) {
+		dev_err(dev, "Failed alloc doorbell id bitmap, aborting\n");
+		mutex_unlock(&lif->dbid_inuse_lock);
+		return -ENOMEM;
+	}
+
+	/* first doorbell id reserved for kernel (dbid aka pid == zero) */
+	set_bit(0, lif->dbid_inuse);
+	mutex_unlock(&lif->dbid_inuse_lock);
 	lif->kern_pid = 0;
+
 	dbpage_num = ionic_db_page_num(lif, lif->kern_pid);
 	lif->kern_dbpage = ionic_bus_map_dbpage(lif->ionic, dbpage_num);
 	if (!lif->kern_dbpage) {
 		dev_err(dev, "Cannot map dbpage, aborting\n");
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto err_out_free_dbid;
 	}
 
 	err = ionic_lif_adminq_init(lif);
@@ -3807,6 +3834,8 @@ int ionic_lif_init(struct ionic_lif *lif)
 	ionic_lif_reset(lif);
 	ionic_bus_unmap_dbpage(lif->ionic, lif->kern_dbpage);
 	lif->kern_dbpage = NULL;
+err_out_free_dbid:
+	ionic_lif_dbid_inuse_free(lif);
 
 	return err;
 }
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
index 333394e477e0..54c8bbe8960a 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
@@ -204,6 +204,7 @@ struct ionic_lif {
 	unsigned int kern_pid;
 	u64 __iomem *kern_dbpage;
 	unsigned int nrdma_eqs;
+	unsigned int nrdma_eqs_avail;
 	unsigned int nxqs;
 	unsigned int ntxq_descs;
 	unsigned int nrxq_descs;
@@ -241,6 +242,8 @@ struct ionic_lif {
 	u32 tx_coalesce_usecs;		/* what the user asked for */
 	u32 tx_coalesce_hw;		/* what the hw is using */
 	unsigned int dbid_count;
+	struct mutex dbid_inuse_lock;   /* lock the dbid bit list */
+	unsigned long *dbid_inuse;
 
 	struct ionic_phc *phc;
 
@@ -402,6 +405,8 @@ int ionic_lif_set_hwstamp_rxfilt(struct ionic_lif *lif, u64 pkt_class);
 
 int ionic_lif_rss_config(struct ionic_lif *lif, u16 types,
 			 const u8 *key, const u32 *indir);
+int ionic_intr_alloc(struct ionic *ionic, struct ionic_intr_info *intr);
+void ionic_intr_free(struct ionic *ionic, int index);
 void ionic_lif_rx_mode(struct ionic_lif *lif);
 int ionic_reconfigure_queues(struct ionic_lif *lif,
 			     struct ionic_queue_params *qparam);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c
index daf1e82cb76b..83e3117a199f 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_main.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c
@@ -72,7 +72,7 @@ static const char *ionic_error_to_str(enum ionic_status_code code)
 	}
 }
 
-static int ionic_error_to_errno(enum ionic_status_code code)
+int ionic_error_to_errno(enum ionic_status_code code)
 {
 	switch (code) {
 	case IONIC_RC_SUCCESS:
-- 
2.34.1





[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux