#ifndef _IONIC_H_
 #define _IONIC_H_
 
+struct ionic_lif;
+
 #include "ionic_if.h"
 #include "ionic_dev.h"
 #include "ionic_devlink.h"
        unsigned int nrxqs_per_lif;
        DECLARE_BITMAP(lifbits, IONIC_LIFS_MAX);
        unsigned int nintrs;
+       DECLARE_BITMAP(intrs, IONIC_INTR_CTRL_REGS_MAX);
 };
 
 int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait);
 
 void ionic_bus_free_irq_vectors(struct ionic *ionic);
 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);
 
 #endif /* _IONIC_BUS_H_ */
 
        }
 }
 
+void __iomem *ionic_bus_map_dbpage(struct ionic *ionic, int page_num)
+{
+       return pci_iomap_range(ionic->pdev,
+                              ionic->bars[IONIC_PCI_BAR_DBELL].res_index,
+                              (u64)page_num << PAGE_SHIFT, PAGE_SIZE);
+}
+
+void ionic_bus_unmap_dbpage(struct ionic *ionic, void __iomem *page)
+{
+       iounmap(page);
+}
+
 static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct device *dev = &pdev->dev;
 
 #include <linux/etherdevice.h>
 #include "ionic.h"
 #include "ionic_dev.h"
+#include "ionic_lif.h"
 
 void ionic_init_devinfo(struct ionic *ionic)
 {
 
        ionic_dev_cmd_go(idev, &cmd);
 }
+
+int ionic_db_page_num(struct ionic_lif *lif, int pid)
+{
+       return (lif->hw_index * lif->dbid_count) + pid;
+}
 
        struct ionic_devinfo dev_info;
 };
 
+#define INTR_INDEX_NOT_ASSIGNED                -1
+#define INTR_NAME_MAX_SZ               32
+
+struct ionic_intr_info {
+       char name[INTR_NAME_MAX_SZ];
+       unsigned int index;
+       unsigned int vector;
+       u64 rearm_count;
+       unsigned int cpu;
+       cpumask_t affinity_mask;
+};
+
 struct ionic;
 
+static inline void ionic_intr_init(struct ionic_dev *idev,
+                                  struct ionic_intr_info *intr,
+                                  unsigned long index)
+{
+       ionic_intr_clean(idev->intr_ctrl, index);
+       intr->index = index;
+}
+
 void ionic_init_devinfo(struct ionic *ionic);
 int ionic_dev_setup(struct ionic *ionic);
 void ionic_dev_teardown(struct ionic *ionic);
                            dma_addr_t addr);
 void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, u16 lif_index);
 
+int ionic_db_page_num(struct ionic_lif *lif, int pid);
+
 #endif /* _IONIC_DEV_H_ */
 
        lif->info = NULL;
        lif->info_pa = 0;
 
+       /* unmap doorbell page */
+       ionic_bus_unmap_dbpage(lif->ionic, lif->kern_dbpage);
+       lif->kern_dbpage = NULL;
+       kfree(lif->dbid_inuse);
+       lif->dbid_inuse = NULL;
+
        /* free netdev & lif */
        ionic_debugfs_del_lif(lif);
        list_del(&lif->list);
 static int ionic_lif_init(struct ionic_lif *lif)
 {
        struct ionic_dev *idev = &lif->ionic->idev;
+       struct device *dev = lif->ionic->dev;
        struct ionic_lif_init_comp comp;
+       int dbpage_num;
        int err;
 
        ionic_debugfs_add_lif(lif);
 
        lif->hw_index = le16_to_cpu(comp.hw_index);
 
+       /* now that we have the hw_index we can figure out our doorbell page */
+       lif->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif);
+       if (!lif->dbid_count) {
+               dev_err(dev, "No doorbell pages, aborting\n");
+               return -EINVAL;
+       }
+
+       lif->dbid_inuse = bitmap_alloc(lif->dbid_count, GFP_KERNEL);
+       if (!lif->dbid_inuse) {
+               dev_err(dev, "Failed alloc doorbell id bitmap, aborting\n");
+               return -ENOMEM;
+       }
+
+       /* first doorbell id reserved for kernel (dbid aka pid == zero) */
+       set_bit(0, lif->dbid_inuse);
+       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");
+               err = -ENOMEM;
+               goto err_out_free_dbid;
+       }
+
        set_bit(IONIC_LIF_INITED, lif->state);
 
        return 0;
+
+err_out_free_dbid:
+       kfree(lif->dbid_inuse);
+       lif->dbid_inuse = NULL;
+
+       return err;
 }
 
 int ionic_lifs_init(struct ionic *ionic)
 
        bool registered;
        unsigned int index;
        unsigned int hw_index;
+       unsigned int kern_pid;
+       u64 __iomem *kern_dbpage;
        unsigned int neqs;
        unsigned int nxqs;
 
        dma_addr_t info_pa;
        u32 info_sz;
 
+       unsigned long *dbid_inuse;
+       unsigned int dbid_count;
        struct dentry *dentry;
        u32 flags;
 };
 
        u32 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.