[v2,04/17] net/ionic: register and initialize the adapter

Message ID 20191015082235.28639-5-cardigliano@ntop.org (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers
Series Introduces net/ionic PMD |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK

Commit Message

Alfredo Cardigliano Oct. 15, 2019, 8:22 a.m. UTC
  Register the Pensando ionic PMD (net_ionic) and define initial probe
and remove callbacks with adapter initialization.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 doc/guides/nics/features/ionic.ini |   2 +
 drivers/net/ionic/Makefile         |   3 +
 drivers/net/ionic/ionic.h          |  63 +++++++++++++
 drivers/net/ionic/ionic_dev.c      | 128 ++++++++++++++++++++++++++
 drivers/net/ionic/ionic_dev.h      | 138 ++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_ethdev.c   | 138 ++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_mac_api.c  |  61 +++++++++++++
 drivers/net/ionic/ionic_mac_api.h  |  13 +++
 drivers/net/ionic/ionic_main.c     | 133 +++++++++++++++++++++++++++
 drivers/net/ionic/ionic_osdep.h    |  79 ++++++++++++++++
 drivers/net/ionic/ionic_regs.h     | 142 +++++++++++++++++++++++++++++
 drivers/net/ionic/meson.build      |   4 +
 12 files changed, 904 insertions(+)
 create mode 100644 drivers/net/ionic/ionic.h
 create mode 100644 drivers/net/ionic/ionic_dev.c
 create mode 100644 drivers/net/ionic/ionic_dev.h
 create mode 100644 drivers/net/ionic/ionic_mac_api.c
 create mode 100644 drivers/net/ionic/ionic_mac_api.h
 create mode 100644 drivers/net/ionic/ionic_main.c
 create mode 100644 drivers/net/ionic/ionic_osdep.h
 create mode 100644 drivers/net/ionic/ionic_regs.h
  

Comments

Ferruh Yigit Dec. 2, 2019, 4:09 p.m. UTC | #1
On 10/15/2019 9:22 AM, Alfredo Cardigliano wrote:
> Register the Pensando ionic PMD (net_ionic) and define initial probe
> and remove callbacks with adapter initialization.
> 
> Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
> Reviewed-by: Shannon Nelson <snelson@pensando.io>
> ---
>  doc/guides/nics/features/ionic.ini |   2 +
>  drivers/net/ionic/Makefile         |   3 +
>  drivers/net/ionic/ionic.h          |  63 +++++++++++++
>  drivers/net/ionic/ionic_dev.c      | 128 ++++++++++++++++++++++++++
>  drivers/net/ionic/ionic_dev.h      | 138 ++++++++++++++++++++++++++++
>  drivers/net/ionic/ionic_ethdev.c   | 138 ++++++++++++++++++++++++++++
>  drivers/net/ionic/ionic_mac_api.c  |  61 +++++++++++++
>  drivers/net/ionic/ionic_mac_api.h  |  13 +++
>  drivers/net/ionic/ionic_main.c     | 133 +++++++++++++++++++++++++++
>  drivers/net/ionic/ionic_osdep.h    |  79 ++++++++++++++++
>  drivers/net/ionic/ionic_regs.h     | 142 +++++++++++++++++++++++++++++
>  drivers/net/ionic/meson.build      |   4 +
>  12 files changed, 904 insertions(+)
>  create mode 100644 drivers/net/ionic/ionic.h
>  create mode 100644 drivers/net/ionic/ionic_dev.c
>  create mode 100644 drivers/net/ionic/ionic_dev.h
>  create mode 100644 drivers/net/ionic/ionic_mac_api.c
>  create mode 100644 drivers/net/ionic/ionic_mac_api.h
>  create mode 100644 drivers/net/ionic/ionic_main.c
>  create mode 100644 drivers/net/ionic/ionic_osdep.h
>  create mode 100644 drivers/net/ionic/ionic_regs.h
> 

<...>

> +int
> +ionic_dev_setup(struct ionic_adapter *adapter)
> +{
> +	struct ionic_dev_bar *bar = adapter->bars;
> +	unsigned int num_bars = adapter->num_bars;
> +	struct ionic_dev *idev = &adapter->idev;
> +	uint32_t sig;
> +
> +	/* BAR0: dev_cmd and interrupts */
> +	if (num_bars < 1) {
> +		ionic_init_print(ERR, "No bars found, aborting\n");
> +		return -EFAULT;
> +	}
> +
> +	if (bar->len < IONIC_BAR0_SIZE) {
> +		ionic_init_print(ERR,
> +			"Resource bar size %lu too small, aborting\n",
> +			bar->len);
> +		return -EFAULT;
> +	}
> +
> +	idev->dev_info = bar->vaddr + IONIC_BAR0_DEV_INFO_REGS_OFFSET;
> +	idev->dev_cmd = bar->vaddr + IONIC_BAR0_DEV_CMD_REGS_OFFSET;
> +	idev->intr_status = bar->vaddr + IONIC_BAR0_INTR_STATUS_OFFSET;
> +	idev->intr_ctrl = bar->vaddr + IONIC_BAR0_INTR_CTRL_OFFSET;

These are causing build error with clang [1], can you please check?

[1]
.../drivers/net/ionic/ionic_dev.c:33:30: error: arithmetic on a pointer to void
is a GNU extension [-Werror,-Wpointer-arith]
        idev->dev_info = bar->vaddr + IONIC_BAR0_DEV_INFO_REGS_OFFSET;
                         ~~~~~~~~~~ ^
.../drivers/net/ionic/ionic_dev.c:34:29: error: arithmetic on a pointer to void
is a GNU extension [-Werror,-Wpointer-arith]
        idev->dev_cmd = bar->vaddr + IONIC_BAR0_DEV_CMD_REGS_OFFSET;
                        ~~~~~~~~~~ ^
.../drivers/net/ionic/ionic_dev.c:35:33: error: arithmetic on a pointer to void
is a GNU extension [-Werror,-Wpointer-arith]
        idev->intr_status = bar->vaddr + IONIC_BAR0_INTR_STATUS_OFFSET;
                            ~~~~~~~~~~ ^
.../drivers/net/ionic/ionic_dev.c:36:31: error: arithmetic on a pointer to void
is a GNU extension [-Werror,-Wpointer-arith]
        idev->intr_ctrl = bar->vaddr + IONIC_BAR0_INTR_CTRL_OFFSET;
                          ~~~~~~~~~~ ^

<...>

> @@ -0,0 +1,138 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
> + */
> +
> +#ifndef _IONIC_DEV_H_
> +#define _IONIC_DEV_H_
> +
> +#include "ionic_osdep.h"
> +#include "ionic_if.h"
> +#include "ionic_regs.h"
> +
> +/** IONIC_API_VERSION - Version number of this interface.
> + *
> + * Any interface changes to this interface must also change the version.
> + *
> + * If drivers are compiled from different sources,
> + * they are compatible only if IONIC_API_VERSION is statically the same in both
> + * sources.  Drivers must have matching values of IONIC_API_VERSION at compile
> + * time, to be considered compatible at run time.
> + */
> +#define IONIC_API_VERSION		"3"

Does it make sense to put a table in to the documenation, to document which dpdk
version supports which API version?

<...>

> + * There is no room in struct rte_pci_driver to keep a reference
> + * to the adapter, using a static list for the time being.
> + */
> +static LIST_HEAD(ionic_pci_adapters_list, ionic_adapter) ionic_pci_adapters =
> +		LIST_HEAD_INITIALIZER(ionic_pci_adapters);

Why this list is used? Will holding the reference in the private data help?

> +static rte_spinlock_t ionic_pci_adapters_lock = RTE_SPINLOCK_INITIALIZER;
> +
> +static int
> +eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
> +		struct rte_pci_device *pci_dev)
> +{
> +	struct rte_mem_resource *resource;
> +	struct ionic_adapter *adapter;
> +	struct ionic_hw *hw;
> +	unsigned long i;
> +	int err;
> +
> +	/* Multi-process not supported */
> +	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
> +		return -EPERM;
> +
> +	ionic_init_print(DEBUG, "Initializing device %s %s",
> +			pci_dev->device.name,
> +			rte_eal_process_type() == RTE_PROC_SECONDARY ?
> +			"[SECONDARY]" : "");

According above check, it can't be secondary.

> +
> +	adapter = rte_zmalloc("ionic", sizeof(*adapter), 0);
> +
> +	if (!adapter) {
> +		ionic_init_print(ERR, "OOM");
> +		return -ENOMEM;
> +	}
> +
> +	adapter->pci_dev = pci_dev;
> +	hw = &adapter->hw;
> +
> +	hw->device_id = pci_dev->id.device_id;
> +	hw->vendor_id = pci_dev->id.vendor_id;
> +
> +	err = ionic_init_mac(hw);
> +	if (err != 0) {
> +		ionic_init_print(ERR, "Mac init failed: %d", err);

Should some clenaup done here? Same thing for all returns, should they free
allocated memory.

> +		return -EIO;
> +	}
> +
> +	adapter->is_mgmt_nic = (pci_dev->id.device_id == IONIC_DEV_ID_ETH_MGMT);
> +
> +	adapter->num_bars = 0;
> +	for (i = 0; i < PCI_MAX_RESOURCE && i < IONIC_BARS_MAX; i++) {
> +		resource = &pci_dev->mem_resource[i];
> +		if (resource->phys_addr == 0 || resource->len == 0)
> +			continue;
> +		adapter->bars[adapter->num_bars].vaddr = resource->addr;
> +		adapter->bars[adapter->num_bars].bus_addr = resource->phys_addr;
> +		adapter->bars[adapter->num_bars].len = resource->len;
> +		adapter->num_bars++;
> +	}
> +
> +	/* Discover ionic dev resources */
> +
> +	err = ionic_setup(adapter);
> +	if (err) {
> +		ionic_init_print(ERR, "Cannot setup device: %d, aborting", err);
> +		return err;
> +	}
> +
> +	err = ionic_identify(adapter);
> +	if (err) {
> +		ionic_init_print(ERR, "Cannot identify device: %d, aborting",
> +				err);

According dpdk coding convention, new line should have a tap. I can see you are
using a mixed format but since this is new code, it is good to have a clean code
that applies the coding convention:
https://doc.dpdk.org/guides/contributing/coding_style.html

For the shared code, shared with other platforms, looks like your 'ionic_if.h'
code is like that, we are more flexible to prevent additional overhead of
maintaining different versions just for the syntax changes, but for the code
that is for the DPDK only please follow the DPDK coding convention.

> +		return err;
> +	}
> +
> +	err = ionic_init(adapter);
> +	if (err) {
> +		ionic_init_print(ERR, "Cannot init device: %d, aborting", err);
> +		return err;
> +	}
> +
> +	rte_spinlock_lock(&ionic_pci_adapters_lock);
> +	LIST_INSERT_HEAD(&ionic_pci_adapters, adapter, pci_adapters);
> +	rte_spinlock_unlock(&ionic_pci_adapters_lock);
> +
> +	return 0;
> +}
> +
> +static int
> +eth_ionic_pci_remove(struct rte_pci_device *pci_dev)
> +{
> +	struct ionic_adapter *adapter = NULL;
> +
> +	rte_spinlock_lock(&ionic_pci_adapters_lock);
> +	LIST_FOREACH(adapter, &ionic_pci_adapters, pci_adapters) {
> +		if (adapter->pci_dev == pci_dev)
> +			break;
> +
> +		adapter = NULL;
> +	}
> +	if (adapter)
> +		LIST_REMOVE(adapter, pci_adapters);
> +	rte_spinlock_unlock(&ionic_pci_adapters_lock);

It is possible to get ethdev from pci_dev, and if you strore the adapter in
ethdev private data, you can access it without needing list for adapter, please
check other pysical device drivers, they have the sample.

> +
> +	if (adapter)
> +		rte_free(adapter);
> +
> +	return 0;
> +}
> +
> +static struct rte_pci_driver rte_ionic_pmd = {
> +	.id_table = pci_id_ionic_map,
> +	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
> +	.probe = eth_ionic_pci_probe,
> +	.remove = eth_ionic_pci_remove,
> +};
> +
> +RTE_PMD_REGISTER_PCI(net_ionic, rte_ionic_pmd);
> +RTE_PMD_REGISTER_PCI_TABLE(net_ionic, pci_id_ionic_map);
> +RTE_PMD_REGISTER_KMOD_DEP(net_ionic, "* igb_uio | uio_pci_generic | vfio-pci");
> +
>  RTE_INIT(ionic_init_log)
>  {
>  	ionic_logtype_init = rte_log_register("pmd.net.ionic.init");
> @@ -14,6 +150,8 @@ RTE_INIT(ionic_init_log)
>  	if (ionic_logtype_init >= 0)
>  		rte_log_set_level(ionic_logtype_init, RTE_LOG_NOTICE);
>  
> +	ionic_struct_size_checks();
> +

For this check log init function doesn't look like correct place.

This fucntion is c constructor, it is called in the beggining of the
application, even though there is no ionic device attached at all, why you are
making all dpdk users check for it?
Also what will happend when check fails? Does it make sense to do this check in
probe() and return a fail if checks fail?

<...>
  
Stephen Hemminger Dec. 2, 2019, 4:35 p.m. UTC | #2
On Tue, 15 Oct 2019 10:22:22 +0200
Alfredo Cardigliano <cardigliano@ntop.org> wrote:

> +	/* BAR0: dev_cmd and interrupts */
> +	if (num_bars < 1) {
> +		ionic_init_print(ERR, "No bars found, aborting\n");

Since ionic_init_print already adds a newline. All your log
messages will be double spaced.
  
Alfredo Cardigliano Dec. 8, 2019, 7:25 p.m. UTC | #3
> On 2 Dec 2019, at 17:09, Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> 
>> + * There is no room in struct rte_pci_driver to keep a reference
>> + * to the adapter, using a static list for the time being.
>> + */
>> +static LIST_HEAD(ionic_pci_adapters_list, ionic_adapter) ionic_pci_adapters =
>> +		LIST_HEAD_INITIALIZER(ionic_pci_adapters);
> 
> Why this list is used? Will holding the reference in the private data help?


A pci_dev is tied to an adapter, that can be tied to multiple LIFs (logical interfaces), 
an eth_dev is created with rte_eth_dev_create for each LIF. The reason we have the
adapters list is for example to handle eth_ionic_pci_remove which is called on a 
pci_dev, thus we need to keep the adapter with the list of LIFs (eth_devs) to destroy
them.

Btw, all other comments have been fixed, a new patch-set is coming.

Thank you
Alfredo
  
Ferruh Yigit Dec. 9, 2019, 9:12 a.m. UTC | #4
On 12/8/2019 7:25 PM, Alfredo Cardigliano wrote:
> 
>> On 2 Dec 2019, at 17:09, Ferruh Yigit <ferruh.yigit@intel.com
>> <mailto:ferruh.yigit@intel.com>> wrote:
>>
>>> + * There is no room in struct rte_pci_driver to keep a reference
>>> + * to the adapter, using a static list for the time being.
>>> + */
>>> +static LIST_HEAD(ionic_pci_adapters_list, ionic_adapter) ionic_pci_adapters =
>>> +LIST_HEAD_INITIALIZER(ionic_pci_adapters);
>>
>> Why this list is used? Will holding the reference in the private data help?
> 
> A pci_dev is tied to an adapter, that can be tied to multiple LIFs (logical
> interfaces), 
> an eth_dev is created with rte_eth_dev_create for each LIF.The reason we have the
> adapters list is for example to handle eth_ionic_pci_remove which is called on a 
> pci_dev, thus we need to keep the adapter with the list of LIFs (eth_devs) to
> destroy
> them.

Got it, we are keeping device private data in eth_dev level, not pci_dev level,
that is why, what about to store the 'adapter' in eth_dev device private data
and in 'eth_ionic_pci_remove()' reconstruct eth_dev name ("net_%s_lif_%lu",
pci_dev->device.name, i) and get eth_dev from it. This way you can access
'adapter' without keeping specific list for it.

> 
> Btw, all other comments have been fixed, a new patch-set is coming.

Good to know, thanks.
  

Patch

diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini
index 3a92eedc7..6915d9c42 100644
--- a/doc/guides/nics/features/ionic.ini
+++ b/doc/guides/nics/features/ionic.ini
@@ -4,5 +4,7 @@ 
 ; Refer to default.ini for the full list of available PMD features.
 ;
 [Features]
+Linux UIO            = Y
+Linux VFIO           = Y
 x86-64               = Y
 Usage doc            = Y
diff --git a/drivers/net/ionic/Makefile b/drivers/net/ionic/Makefile
index f9b9a6af9..69fb7dcf1 100644
--- a/drivers/net/ionic/Makefile
+++ b/drivers/net/ionic/Makefile
@@ -53,6 +53,9 @@  LDLIBS += -lrte_bus_pci
 #
 # all source are stored in SRCS-y
 #
+SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_mac_api.c
+SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_dev.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_main.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h
new file mode 100644
index 000000000..1f91e0a10
--- /dev/null
+++ b/drivers/net/ionic/ionic.h
@@ -0,0 +1,63 @@ 
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_H_
+#define _IONIC_H_
+
+#include <stdint.h>
+
+#include "ionic_dev.h"
+#include "ionic_if.h"
+#include "ionic_osdep.h"
+
+#define IONIC_DRV_NAME			"ionic"
+#define IONIC_DRV_DESCRIPTION		"Pensando Ethernet NIC Driver"
+#define IONIC_DRV_VERSION		"0.11.0-49"
+
+/* Vendor ID */
+#define IONIC_PENSANDO_VENDOR_ID	0x1dd8
+
+/* Device IDs */
+#define IONIC_DEV_ID_ETH_PF		0x1002
+#define IONIC_DEV_ID_ETH_VF		0x1003
+#define IONIC_DEV_ID_ETH_MGMT		0x1004
+
+enum ionic_mac_type {
+	IONIC_MAC_UNKNOWN = 0,
+	IONIC_MAC_CAPRI,
+	IONIC_NUM_MACS
+};
+
+struct ionic_mac_info {
+	enum ionic_mac_type type;
+};
+
+struct ionic_hw {
+	struct ionic_mac_info mac;
+	uint16_t device_id;
+	uint16_t vendor_id;
+};
+
+/*
+ * Structure to store private data for each driver instance (for each adapter).
+ */
+struct ionic_adapter {
+	struct ionic_hw hw;
+	struct ionic_dev idev;
+	struct ionic_dev_bar bars[IONIC_BARS_MAX];
+	struct ionic_identity	ident;
+	uint32_t num_bars;
+	bool is_mgmt_nic;
+	struct rte_pci_device *pci_dev;
+	LIST_ENTRY(ionic_adapter) pci_adapters;
+};
+
+int ionic_dev_cmd_wait_check(struct ionic_dev *idev, unsigned long max_wait);
+int ionic_setup(struct ionic_adapter *adapter);
+
+int ionic_identify(struct ionic_adapter *adapter);
+int ionic_init(struct ionic_adapter *adapter);
+int ionic_reset(struct ionic_adapter *adapter);
+
+#endif /* _IONIC_H_ */
diff --git a/drivers/net/ionic/ionic_dev.c b/drivers/net/ionic/ionic_dev.c
new file mode 100644
index 000000000..5cdcaa104
--- /dev/null
+++ b/drivers/net/ionic/ionic_dev.c
@@ -0,0 +1,128 @@ 
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#include <rte_malloc.h>
+
+#include "ionic_dev.h"
+#include "ionic.h"
+
+int
+ionic_dev_setup(struct ionic_adapter *adapter)
+{
+	struct ionic_dev_bar *bar = adapter->bars;
+	unsigned int num_bars = adapter->num_bars;
+	struct ionic_dev *idev = &adapter->idev;
+	uint32_t sig;
+
+	/* BAR0: dev_cmd and interrupts */
+	if (num_bars < 1) {
+		ionic_init_print(ERR, "No bars found, aborting\n");
+		return -EFAULT;
+	}
+
+	if (bar->len < IONIC_BAR0_SIZE) {
+		ionic_init_print(ERR,
+			"Resource bar size %lu too small, aborting\n",
+			bar->len);
+		return -EFAULT;
+	}
+
+	idev->dev_info = bar->vaddr + IONIC_BAR0_DEV_INFO_REGS_OFFSET;
+	idev->dev_cmd = bar->vaddr + IONIC_BAR0_DEV_CMD_REGS_OFFSET;
+	idev->intr_status = bar->vaddr + IONIC_BAR0_INTR_STATUS_OFFSET;
+	idev->intr_ctrl = bar->vaddr + IONIC_BAR0_INTR_CTRL_OFFSET;
+
+	sig = ioread32(&idev->dev_info->signature);
+	if (sig != IONIC_DEV_INFO_SIGNATURE) {
+		ionic_init_print(ERR, "Incompatible firmware signature %x",
+			sig);
+		return -EFAULT;
+	}
+
+	/* BAR1: doorbells */
+	bar++;
+	if (num_bars < 2) {
+		ionic_init_print(ERR, "Doorbell bar missing, aborting\n");
+		return -EFAULT;
+	}
+
+	idev->db_pages = bar->vaddr;
+	idev->phy_db_pages = bar->bus_addr;
+
+	return 0;
+}
+
+/* Devcmd Interface */
+
+uint8_t
+ionic_dev_cmd_status(struct ionic_dev *idev)
+{
+	return ioread8(&idev->dev_cmd->comp.comp.status);
+}
+
+bool
+ionic_dev_cmd_done(struct ionic_dev *idev)
+{
+	return ioread32(&idev->dev_cmd->done) & IONIC_DEV_CMD_DONE;
+}
+
+void
+ionic_dev_cmd_comp(struct ionic_dev *idev, void *mem)
+{
+	union ionic_dev_cmd_comp *comp = mem;
+	unsigned int i;
+	uint32_t comp_size = sizeof(comp->words) /
+		sizeof(comp->words[0]);
+
+	for (i = 0; i < comp_size; i++)
+		comp->words[i] = ioread32(&idev->dev_cmd->comp.words[i]);
+}
+
+void
+ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd)
+{
+	unsigned int i;
+	uint32_t cmd_size = sizeof(cmd->words) /
+		sizeof(cmd->words[0]);
+
+	for (i = 0; i < cmd_size; i++)
+		iowrite32(cmd->words[i], &idev->dev_cmd->cmd.words[i]);
+
+	iowrite32(0, &idev->dev_cmd->done);
+	iowrite32(1, &idev->dev_cmd->doorbell);
+}
+
+/* Device commands */
+
+void
+ionic_dev_cmd_identify(struct ionic_dev *idev, uint8_t ver)
+{
+	union ionic_dev_cmd cmd = {
+		.identify.opcode = IONIC_CMD_IDENTIFY,
+		.identify.ver = ver,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_init(struct ionic_dev *idev)
+{
+	union ionic_dev_cmd cmd = {
+		.init.opcode = IONIC_CMD_INIT,
+		.init.type = 0,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_reset(struct ionic_dev *idev)
+{
+	union ionic_dev_cmd cmd = {
+		.reset.opcode = IONIC_CMD_RESET,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
diff --git a/drivers/net/ionic/ionic_dev.h b/drivers/net/ionic/ionic_dev.h
new file mode 100644
index 000000000..a157e4175
--- /dev/null
+++ b/drivers/net/ionic/ionic_dev.h
@@ -0,0 +1,138 @@ 
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_DEV_H_
+#define _IONIC_DEV_H_
+
+#include "ionic_osdep.h"
+#include "ionic_if.h"
+#include "ionic_regs.h"
+
+/** IONIC_API_VERSION - Version number of this interface.
+ *
+ * Any interface changes to this interface must also change the version.
+ *
+ * If drivers are compiled from different sources,
+ * they are compatible only if IONIC_API_VERSION is statically the same in both
+ * sources.  Drivers must have matching values of IONIC_API_VERSION at compile
+ * time, to be considered compatible at run time.
+ */
+#define IONIC_API_VERSION		"3"
+
+#define IONIC_DEVCMD_TIMEOUT	30 /* devcmd_timeout */
+
+struct ionic_adapter;
+
+struct ionic_dev_bar {
+	void __iomem *vaddr;
+	rte_iova_t bus_addr;
+	unsigned long len;
+};
+
+static inline void ionic_struct_size_checks(void)
+{
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_doorbell) != 8);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_intr) != 32);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_intr_status) != 8);
+
+	RTE_BUILD_BUG_ON(sizeof(union ionic_dev_regs) != 4096);
+	RTE_BUILD_BUG_ON(sizeof(union ionic_dev_info_regs) != 2048);
+	RTE_BUILD_BUG_ON(sizeof(union ionic_dev_cmd_regs) != 2048);
+
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_stats) != 1024);
+
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_admin_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_admin_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_nop_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_nop_comp) != 16);
+
+	/* Device commands */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_identify_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_identify_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_init_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_init_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_reset_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_reset_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_getattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_getattr_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_setattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_setattr_comp) != 16);
+
+	/* Port commands */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_identify_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_identify_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_init_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_init_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_reset_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_reset_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_getattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_getattr_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_setattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_setattr_comp) != 16);
+
+	/* LIF commands */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_init_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_init_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_reset_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_getattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_getattr_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_setattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_setattr_comp) != 16);
+
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_q_init_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_q_init_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_q_control_cmd) != 64);
+
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rx_mode_set_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rx_filter_add_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rx_filter_add_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rx_filter_del_cmd) != 64);
+
+	/* RDMA commands */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rdma_reset_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rdma_queue_cmd) != 64);
+
+	/* Events */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_notifyq_cmd) != 4);
+	RTE_BUILD_BUG_ON(sizeof(union ionic_notifyq_comp) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_notifyq_event) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_link_change_event) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_reset_event) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_heartbeat_event) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_log_event) != 64);
+
+	/* I/O */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_txq_desc) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_txq_sg_desc) != 128);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_txq_comp) != 16);
+
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rxq_desc) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rxq_sg_desc) != 128);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rxq_comp) != 16);
+}
+
+struct ionic_dev {
+	union ionic_dev_info_regs __iomem *dev_info;
+	union ionic_dev_cmd_regs __iomem *dev_cmd;
+
+	struct ionic_doorbell __iomem *db_pages;
+	rte_iova_t phy_db_pages;
+
+	struct ionic_intr __iomem *intr_ctrl;
+
+	struct ionic_intr_status __iomem *intr_status;
+};
+
+int ionic_dev_setup(struct ionic_adapter *adapter);
+
+void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd);
+uint8_t ionic_dev_cmd_status(struct ionic_dev *idev);
+bool ionic_dev_cmd_done(struct ionic_dev *idev);
+void ionic_dev_cmd_comp(struct ionic_dev *idev, void *mem);
+
+void ionic_dev_cmd_identify(struct ionic_dev *idev, uint8_t ver);
+void ionic_dev_cmd_init(struct ionic_dev *idev);
+void ionic_dev_cmd_reset(struct ionic_dev *idev);
+
+#endif /* _IONIC_DEV_H_ */
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 863d20d19..148d6f236 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -2,11 +2,147 @@ 
  * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
  */
 
+#include <rte_pci.h>
+#include <rte_bus_pci.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_driver.h>
+#include <rte_malloc.h>
+
 #include "ionic_logs.h"
+#include "ionic.h"
+#include "ionic_dev.h"
+#include "ionic_mac_api.h"
 
 int ionic_logtype_init;
 int ionic_logtype_driver;
 
+static const struct rte_pci_id pci_id_ionic_map[] = {
+	{ RTE_PCI_DEVICE(IONIC_PENSANDO_VENDOR_ID, IONIC_DEV_ID_ETH_PF) },
+	{ RTE_PCI_DEVICE(IONIC_PENSANDO_VENDOR_ID, IONIC_DEV_ID_ETH_VF) },
+	{ RTE_PCI_DEVICE(IONIC_PENSANDO_VENDOR_ID, IONIC_DEV_ID_ETH_MGMT) },
+	{ .vendor_id = 0, /* sentinel */ },
+};
+
+/*
+ * There is no room in struct rte_pci_driver to keep a reference
+ * to the adapter, using a static list for the time being.
+ */
+static LIST_HEAD(ionic_pci_adapters_list, ionic_adapter) ionic_pci_adapters =
+		LIST_HEAD_INITIALIZER(ionic_pci_adapters);
+static rte_spinlock_t ionic_pci_adapters_lock = RTE_SPINLOCK_INITIALIZER;
+
+static int
+eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+		struct rte_pci_device *pci_dev)
+{
+	struct rte_mem_resource *resource;
+	struct ionic_adapter *adapter;
+	struct ionic_hw *hw;
+	unsigned long i;
+	int err;
+
+	/* Multi-process not supported */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return -EPERM;
+
+	ionic_init_print(DEBUG, "Initializing device %s %s",
+			pci_dev->device.name,
+			rte_eal_process_type() == RTE_PROC_SECONDARY ?
+			"[SECONDARY]" : "");
+
+	adapter = rte_zmalloc("ionic", sizeof(*adapter), 0);
+
+	if (!adapter) {
+		ionic_init_print(ERR, "OOM");
+		return -ENOMEM;
+	}
+
+	adapter->pci_dev = pci_dev;
+	hw = &adapter->hw;
+
+	hw->device_id = pci_dev->id.device_id;
+	hw->vendor_id = pci_dev->id.vendor_id;
+
+	err = ionic_init_mac(hw);
+	if (err != 0) {
+		ionic_init_print(ERR, "Mac init failed: %d", err);
+		return -EIO;
+	}
+
+	adapter->is_mgmt_nic = (pci_dev->id.device_id == IONIC_DEV_ID_ETH_MGMT);
+
+	adapter->num_bars = 0;
+	for (i = 0; i < PCI_MAX_RESOURCE && i < IONIC_BARS_MAX; i++) {
+		resource = &pci_dev->mem_resource[i];
+		if (resource->phys_addr == 0 || resource->len == 0)
+			continue;
+		adapter->bars[adapter->num_bars].vaddr = resource->addr;
+		adapter->bars[adapter->num_bars].bus_addr = resource->phys_addr;
+		adapter->bars[adapter->num_bars].len = resource->len;
+		adapter->num_bars++;
+	}
+
+	/* Discover ionic dev resources */
+
+	err = ionic_setup(adapter);
+	if (err) {
+		ionic_init_print(ERR, "Cannot setup device: %d, aborting", err);
+		return err;
+	}
+
+	err = ionic_identify(adapter);
+	if (err) {
+		ionic_init_print(ERR, "Cannot identify device: %d, aborting",
+				err);
+		return err;
+	}
+
+	err = ionic_init(adapter);
+	if (err) {
+		ionic_init_print(ERR, "Cannot init device: %d, aborting", err);
+		return err;
+	}
+
+	rte_spinlock_lock(&ionic_pci_adapters_lock);
+	LIST_INSERT_HEAD(&ionic_pci_adapters, adapter, pci_adapters);
+	rte_spinlock_unlock(&ionic_pci_adapters_lock);
+
+	return 0;
+}
+
+static int
+eth_ionic_pci_remove(struct rte_pci_device *pci_dev)
+{
+	struct ionic_adapter *adapter = NULL;
+
+	rte_spinlock_lock(&ionic_pci_adapters_lock);
+	LIST_FOREACH(adapter, &ionic_pci_adapters, pci_adapters) {
+		if (adapter->pci_dev == pci_dev)
+			break;
+
+		adapter = NULL;
+	}
+	if (adapter)
+		LIST_REMOVE(adapter, pci_adapters);
+	rte_spinlock_unlock(&ionic_pci_adapters_lock);
+
+	if (adapter)
+		rte_free(adapter);
+
+	return 0;
+}
+
+static struct rte_pci_driver rte_ionic_pmd = {
+	.id_table = pci_id_ionic_map,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
+	.probe = eth_ionic_pci_probe,
+	.remove = eth_ionic_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ionic, rte_ionic_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ionic, pci_id_ionic_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ionic, "* igb_uio | uio_pci_generic | vfio-pci");
+
 RTE_INIT(ionic_init_log)
 {
 	ionic_logtype_init = rte_log_register("pmd.net.ionic.init");
@@ -14,6 +150,8 @@  RTE_INIT(ionic_init_log)
 	if (ionic_logtype_init >= 0)
 		rte_log_set_level(ionic_logtype_init, RTE_LOG_NOTICE);
 
+	ionic_struct_size_checks();
+
 	ionic_logtype_driver = rte_log_register("pmd.net.ionic.driver");
 
 	if (ionic_logtype_driver >= 0)
diff --git a/drivers/net/ionic/ionic_mac_api.c b/drivers/net/ionic/ionic_mac_api.c
new file mode 100644
index 000000000..5413afa93
--- /dev/null
+++ b/drivers/net/ionic/ionic_mac_api.c
@@ -0,0 +1,61 @@ 
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#include "ionic_mac_api.h"
+
+int32_t
+ionic_init_mac(struct ionic_hw *hw)
+{
+	int err = 0;
+
+	ionic_drv_print_call();
+
+	/*
+	 * Set the mac type
+	 */
+	ionic_set_mac_type(hw);
+
+	switch (hw->mac.type) {
+	case IONIC_MAC_CAPRI:
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+int32_t
+ionic_set_mac_type(struct ionic_hw *hw)
+{
+	int err = 0;
+
+	ionic_drv_print_call();
+
+	if (hw->vendor_id != IONIC_PENSANDO_VENDOR_ID) {
+		ionic_drv_print(ERR, "Unsupported vendor id: %x",
+				hw->vendor_id);
+		return -EINVAL;
+	}
+
+	switch (hw->device_id) {
+	case IONIC_DEV_ID_ETH_PF:
+	case IONIC_DEV_ID_ETH_VF:
+	case IONIC_DEV_ID_ETH_MGMT:
+		hw->mac.type = IONIC_MAC_CAPRI;
+		break;
+	default:
+		err = -EINVAL;
+		ionic_drv_print(ERR, "Unsupported device id: %x",
+				hw->device_id);
+		break;
+	}
+
+	ionic_drv_print(INFO, "Mac: %d (%d)\n",
+			hw->mac.type, err);
+
+	return err;
+}
+
diff --git a/drivers/net/ionic/ionic_mac_api.h b/drivers/net/ionic/ionic_mac_api.h
new file mode 100644
index 000000000..41f9328f3
--- /dev/null
+++ b/drivers/net/ionic/ionic_mac_api.h
@@ -0,0 +1,13 @@ 
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_API_H_
+#define _IONIC_API_H_
+
+#include "ionic.h"
+
+int32_t ionic_init_mac(struct ionic_hw *hw);
+int32_t ionic_set_mac_type(struct ionic_hw *hw);
+
+#endif /* _IONIC_API_H_ */
diff --git a/drivers/net/ionic/ionic_main.c b/drivers/net/ionic/ionic_main.c
new file mode 100644
index 000000000..79a141140
--- /dev/null
+++ b/drivers/net/ionic/ionic_main.c
@@ -0,0 +1,133 @@ 
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#include "ionic.h"
+
+static int
+ionic_dev_cmd_wait(struct ionic_dev *idev, unsigned long max_wait)
+{
+	unsigned long step_msec = 100;
+	unsigned int max_wait_msec = max_wait * 1000;
+	unsigned long elapsed_msec = 0;
+	int done;
+
+	/* Wait for dev cmd to complete.. but no more than max_wait sec */
+
+	do {
+		done = ionic_dev_cmd_done(idev);
+
+		if (done) {
+			ionic_drv_print(DEBUG, "DEVCMD %d done took %ld msecs\n",
+					idev->dev_cmd->cmd.cmd.opcode,
+					elapsed_msec);
+			return 0;
+		}
+
+		msec_delay(step_msec);
+
+		elapsed_msec += step_msec;
+	} while (elapsed_msec < max_wait_msec);
+
+	ionic_drv_print(DEBUG, "DEVCMD %d timeout after %ld msecs\n",
+			idev->dev_cmd->cmd.cmd.opcode,
+			elapsed_msec);
+
+	return -ETIMEDOUT;
+}
+
+static int
+ionic_dev_cmd_check_error(struct ionic_dev *idev)
+{
+	uint8_t status;
+
+	status = ionic_dev_cmd_status(idev);
+
+	if (status == 0)
+		return 0;
+
+	return -EIO;
+}
+
+int
+ionic_dev_cmd_wait_check(struct ionic_dev *idev, unsigned long max_wait)
+{
+	int err;
+
+	err = ionic_dev_cmd_wait(idev, max_wait);
+
+	if (err)
+		return err;
+
+	return ionic_dev_cmd_check_error(idev);
+}
+
+int
+ionic_setup(struct ionic_adapter *adapter)
+{
+	return ionic_dev_setup(adapter);
+}
+
+int
+ionic_identify(struct ionic_adapter *adapter)
+{
+	struct ionic_dev *idev = &adapter->idev;
+	struct ionic_identity *ident = &adapter->ident;
+	int err = 0;
+	uint32_t i;
+	unsigned int nwords;
+	uint32_t drv_size = sizeof(ident->drv.words) /
+		sizeof(ident->drv.words[0]);
+	uint32_t cmd_size = sizeof(idev->dev_cmd->data) /
+		sizeof(idev->dev_cmd->data[0]);
+	uint32_t dev_size = sizeof(ident->dev.words) /
+		sizeof(ident->dev.words[0]);
+
+	memset(ident, 0, sizeof(*ident));
+
+	ident->drv.os_type = IONIC_OS_TYPE_LINUX;
+	ident->drv.os_dist = 0;
+	snprintf(ident->drv.os_dist_str,
+		sizeof(ident->drv.os_dist_str), "Unknown");
+	ident->drv.kernel_ver = 0;
+	snprintf(ident->drv.kernel_ver_str,
+		sizeof(ident->drv.kernel_ver_str), "DPDK");
+	strncpy(ident->drv.driver_ver_str, IONIC_DRV_VERSION,
+		sizeof(ident->drv.driver_ver_str) - 1);
+
+	nwords = RTE_MIN(drv_size, cmd_size);
+	for (i = 0; i < nwords; i++)
+		iowrite32(ident->drv.words[i], &idev->dev_cmd->data[i]);
+
+	ionic_dev_cmd_identify(idev, IONIC_IDENTITY_VERSION_1);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+	if (!err) {
+		nwords = RTE_MIN(dev_size, cmd_size);
+		for (i = 0; i < nwords; i++)
+			ident->dev.words[i] = ioread32(&idev->dev_cmd->data[i]);
+	}
+
+	return err;
+}
+
+int
+ionic_init(struct ionic_adapter *adapter)
+{
+	struct ionic_dev *idev = &adapter->idev;
+	int err;
+
+	ionic_dev_cmd_init(idev);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+	return err;
+}
+
+int
+ionic_reset(struct ionic_adapter *adapter)
+{
+	struct ionic_dev *idev = &adapter->idev;
+	int err;
+
+	ionic_dev_cmd_reset(idev);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+	return err;
+}
diff --git a/drivers/net/ionic/ionic_osdep.h b/drivers/net/ionic/ionic_osdep.h
new file mode 100644
index 000000000..5b8baa67b
--- /dev/null
+++ b/drivers/net/ionic/ionic_osdep.h
@@ -0,0 +1,79 @@ 
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_OSDEP_
+#define _IONIC_OSDEP_
+
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_log.h>
+#include <rte_byteorder.h>
+#include <rte_io.h>
+#include <rte_memory.h>
+
+#include "ionic_logs.h"
+
+#define DELAY(x) rte_delay_us(x)
+#define usec_delay(x) DELAY(x)
+#define msec_delay(x) DELAY(1000 * (x))
+
+#define BIT(nr)            (1UL << (nr))
+#define BIT_ULL(nr)        (1ULL << (nr))
+#define BITS_TO_LONGS(nr)  div_round_up(nr, 8 * sizeof(long))
+
+#ifndef PAGE_SHIFT
+#define PAGE_SHIFT      12
+#define PAGE_SIZE       (1 << PAGE_SHIFT)
+#endif
+
+#define __iomem
+
+typedef uint8_t	 u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+typedef uint16_t __le16;
+typedef uint32_t __le32;
+typedef uint64_t __le64;
+
+#ifndef __cplusplus
+typedef uint8_t bool;
+#define false   0
+#define true    1
+#endif
+
+static inline uint32_t div_round_up(uint32_t n, uint32_t d)
+{
+	return (n + d - 1) / d;
+}
+
+static inline uint16_t ilog2(uint32_t n)
+{
+	uint16_t logv = -1;
+
+	if (n == 0)
+		return 0;
+
+	while (n) {
+		logv++;
+		n >>= 1;
+	}
+
+	return logv;
+}
+
+#define ioread8(reg)		rte_read8(reg)
+#define ioread32(reg)		rte_read32(reg)
+#define iowrite8(value, reg)	rte_write8(value, reg)
+#define iowrite32(value, reg)	rte_write32(value, reg)
+#define writeq(value, reg)	rte_write64(value, reg)
+
+#endif
diff --git a/drivers/net/ionic/ionic_regs.h b/drivers/net/ionic/ionic_regs.h
new file mode 100644
index 000000000..e213062c9
--- /dev/null
+++ b/drivers/net/ionic/ionic_regs.h
@@ -0,0 +1,142 @@ 
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_REGS_H_
+#define _IONIC_REGS_H_
+
+/** struct ionic_intr - interrupt control register set.
+ * @coal_init:			coalesce timer initial value.
+ * @mask:			interrupt mask value.
+ * @credits:			interrupt credit count and return.
+ * @mask_assert:		interrupt mask value on assert.
+ * @coal:			coalesce timer time remaining.
+ */
+struct ionic_intr {
+	uint32_t coal_init;
+	uint32_t mask;
+	uint32_t credits;
+	uint32_t mask_assert;
+	uint32_t coal;
+	uint32_t rsvd[3];
+};
+
+#define IONIC_INTR_CTRL_REGS_MAX	2048
+#define IONIC_INTR_CTRL_COAL_MAX	0x3F
+
+/** enum ionic_intr_mask_vals - valid values for mask and mask_assert.
+ * @IONIC_INTR_MASK_CLEAR:	unmask interrupt.
+ * @IONIC_INTR_MASK_SET:	mask interrupt.
+ */
+enum ionic_intr_mask_vals {
+	IONIC_INTR_MASK_CLEAR		= 0,
+	IONIC_INTR_MASK_SET		= 1,
+};
+
+/** enum ionic_intr_credits_bits - bitwise composition of credits values.
+ * @IONIC_INTR_CRED_COUNT:	bit mask of credit count, no shift needed.
+ * @IONIC_INTR_CRED_COUNT_SIGNED: bit mask of credit count, including sign bit.
+ * @IONIC_INTR_CRED_UNMASK:	unmask the interrupt.
+ * @IONIC_INTR_CRED_RESET_COALESCE: reset the coalesce timer.
+ * @IONIC_INTR_CRED_REARM:	unmask the and reset the timer.
+ */
+enum ionic_intr_credits_bits {
+	IONIC_INTR_CRED_COUNT		= 0x7fffu,
+	IONIC_INTR_CRED_COUNT_SIGNED	= 0xffffu,
+	IONIC_INTR_CRED_UNMASK		= 0x10000u,
+	IONIC_INTR_CRED_RESET_COALESCE	= 0x20000u,
+	IONIC_INTR_CRED_REARM		= (IONIC_INTR_CRED_UNMASK |
+					   IONIC_INTR_CRED_RESET_COALESCE),
+};
+
+static inline void
+ionic_intr_coal_init(struct ionic_intr __iomem *intr_ctrl,
+		int intr_idx, uint32_t coal)
+{
+	iowrite32(coal, &intr_ctrl[intr_idx].coal_init);
+}
+
+static inline void
+ionic_intr_mask(struct ionic_intr __iomem *intr_ctrl,
+		int intr_idx, uint32_t mask)
+{
+	iowrite32(mask, &intr_ctrl[intr_idx].mask);
+}
+
+static inline void
+ionic_intr_credits(struct ionic_intr __iomem *intr_ctrl,
+		int intr_idx, uint32_t cred, uint32_t flags)
+{
+	if (cred > IONIC_INTR_CRED_COUNT) {
+		IONIC_WARN_ON(cred > IONIC_INTR_CRED_COUNT);
+		cred = ioread32(&intr_ctrl[intr_idx].credits);
+		cred &= IONIC_INTR_CRED_COUNT_SIGNED;
+	}
+
+	iowrite32(cred | flags, &intr_ctrl[intr_idx].credits);
+}
+
+static inline void
+ionic_intr_clean(struct ionic_intr __iomem *intr_ctrl,
+		int intr_idx)
+{
+	uint32_t cred;
+
+	cred = ioread32(&intr_ctrl[intr_idx].credits);
+	cred &= IONIC_INTR_CRED_COUNT_SIGNED;
+	cred |= IONIC_INTR_CRED_RESET_COALESCE;
+	iowrite32(cred, &intr_ctrl[intr_idx].credits);
+}
+
+static inline void
+ionic_intr_mask_assert(struct ionic_intr __iomem *intr_ctrl,
+		int intr_idx, uint32_t mask)
+{
+	iowrite32(mask, &intr_ctrl[intr_idx].mask_assert);
+}
+
+/** enum ionic_dbell_bits - bitwise composition of dbell values.
+ *
+ * @IONIC_DBELL_QID_MASK:	unshifted mask of valid queue id bits.
+ * @IONIC_DBELL_QID_SHIFT:	queue id shift amount in dbell value.
+ * @IONIC_DBELL_QID:		macro to build QID component of dbell value.
+ *
+ * @IONIC_DBELL_RING_MASK:	unshifted mask of valid ring bits.
+ * @IONIC_DBELL_RING_SHIFT:	ring shift amount in dbell value.
+ * @IONIC_DBELL_RING:		macro to build ring component of dbell value.
+ *
+ * @IONIC_DBELL_RING_0:		ring zero dbell component value.
+ * @IONIC_DBELL_RING_1:		ring one dbell component value.
+ * @IONIC_DBELL_RING_2:		ring two dbell component value.
+ * @IONIC_DBELL_RING_3:		ring three dbell component value.
+ *
+ * @IONIC_DBELL_INDEX_MASK:	bit mask of valid index bits, no shift needed.
+ */
+enum ionic_dbell_bits {
+	IONIC_DBELL_QID_MASK		= 0xffffff,
+	IONIC_DBELL_QID_SHIFT		= 24,
+
+#define IONIC_DBELL_QID(n) \
+	(((u64)(n) & IONIC_DBELL_QID_MASK) << IONIC_DBELL_QID_SHIFT)
+
+	IONIC_DBELL_RING_MASK		= 0x7,
+	IONIC_DBELL_RING_SHIFT		= 16,
+
+#define IONIC_DBELL_RING(n) \
+	(((u64)(n) & IONIC_DBELL_RING_MASK) << IONIC_DBELL_RING_SHIFT)
+
+	IONIC_DBELL_RING_0		= 0,
+	IONIC_DBELL_RING_1		= IONIC_DBELL_RING(1),
+	IONIC_DBELL_RING_2		= IONIC_DBELL_RING(2),
+	IONIC_DBELL_RING_3		= IONIC_DBELL_RING(3),
+
+	IONIC_DBELL_INDEX_MASK		= 0xffff,
+};
+
+static inline void
+ionic_dbell_ring(u64 __iomem *db_page, int qtype, u64 val)
+{
+	writeq(val, &db_page[qtype]);
+}
+
+#endif /* _IONIC_REGS_H_ */
diff --git a/drivers/net/ionic/meson.build b/drivers/net/ionic/meson.build
index 5534ad6c3..bd63e6136 100644
--- a/drivers/net/ionic/meson.build
+++ b/drivers/net/ionic/meson.build
@@ -4,6 +4,10 @@ 
 version = 1
 
 sources = files(
+	'ionic_mac_api.c',
+	'ionic_dev.c',
+	'ionic_ethdev.c',
+	'ionic_main.c',
 	'ionic_ethdev.c'
 )