Commit 6461b446 authored by Shannon Nelson's avatar Shannon Nelson Committed by David S. Miller

ionic: Add interrupts and doorbells

The ionic interrupt model is based on interrupt control blocks
accessed through the PCI BAR.  Doorbell registers are used by
the driver to signal to the NIC that requests are waiting on
the message queues.  Interrupts are used by the NIC to signal
to the driver that answers are waiting on the completion queues.
Signed-off-by: default avatarShannon Nelson <snelson@pensando.io>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1a58e196
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#ifndef _IONIC_H_ #ifndef _IONIC_H_
#define _IONIC_H_ #define _IONIC_H_
struct ionic_lif;
#include "ionic_if.h" #include "ionic_if.h"
#include "ionic_dev.h" #include "ionic_dev.h"
#include "ionic_devlink.h" #include "ionic_devlink.h"
...@@ -39,6 +41,7 @@ struct ionic { ...@@ -39,6 +41,7 @@ struct ionic {
unsigned int nrxqs_per_lif; unsigned int nrxqs_per_lif;
DECLARE_BITMAP(lifbits, IONIC_LIFS_MAX); DECLARE_BITMAP(lifbits, IONIC_LIFS_MAX);
unsigned int nintrs; unsigned int nintrs;
DECLARE_BITMAP(intrs, IONIC_INTR_CTRL_REGS_MAX);
}; };
int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait); int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait);
......
...@@ -9,5 +9,7 @@ int ionic_bus_alloc_irq_vectors(struct ionic *ionic, unsigned int nintrs); ...@@ -9,5 +9,7 @@ int ionic_bus_alloc_irq_vectors(struct ionic *ionic, unsigned int nintrs);
void ionic_bus_free_irq_vectors(struct ionic *ionic); void ionic_bus_free_irq_vectors(struct ionic *ionic);
int ionic_bus_register_driver(void); int ionic_bus_register_driver(void);
void ionic_bus_unregister_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_ */ #endif /* _IONIC_BUS_H_ */
...@@ -87,6 +87,18 @@ static void ionic_unmap_bars(struct ionic *ionic) ...@@ -87,6 +87,18 @@ static void ionic_unmap_bars(struct ionic *ionic)
} }
} }
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) static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include "ionic.h" #include "ionic.h"
#include "ionic_dev.h" #include "ionic_dev.h"
#include "ionic_lif.h"
void ionic_init_devinfo(struct ionic *ionic) void ionic_init_devinfo(struct ionic *ionic)
{ {
...@@ -260,3 +261,8 @@ void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, u16 lif_index) ...@@ -260,3 +261,8 @@ void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, u16 lif_index)
ionic_dev_cmd_go(idev, &cmd); 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;
}
...@@ -126,8 +126,28 @@ struct ionic_dev { ...@@ -126,8 +126,28 @@ struct ionic_dev {
struct ionic_devinfo dev_info; 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; 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); void ionic_init_devinfo(struct ionic *ionic);
int ionic_dev_setup(struct ionic *ionic); int ionic_dev_setup(struct ionic *ionic);
void ionic_dev_teardown(struct ionic *ionic); void ionic_dev_teardown(struct ionic *ionic);
...@@ -155,4 +175,6 @@ void ionic_dev_cmd_lif_init(struct ionic_dev *idev, u16 lif_index, ...@@ -155,4 +175,6 @@ void ionic_dev_cmd_lif_init(struct ionic_dev *idev, u16 lif_index,
dma_addr_t addr); dma_addr_t addr);
void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, u16 lif_index); 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_ */ #endif /* _IONIC_DEV_H_ */
...@@ -94,6 +94,12 @@ static void ionic_lif_free(struct ionic_lif *lif) ...@@ -94,6 +94,12 @@ static void ionic_lif_free(struct ionic_lif *lif)
lif->info = NULL; lif->info = NULL;
lif->info_pa = 0; 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 */ /* free netdev & lif */
ionic_debugfs_del_lif(lif); ionic_debugfs_del_lif(lif);
list_del(&lif->list); list_del(&lif->list);
...@@ -136,7 +142,9 @@ void ionic_lifs_deinit(struct ionic *ionic) ...@@ -136,7 +142,9 @@ void ionic_lifs_deinit(struct ionic *ionic)
static int ionic_lif_init(struct ionic_lif *lif) static int ionic_lif_init(struct ionic_lif *lif)
{ {
struct ionic_dev *idev = &lif->ionic->idev; struct ionic_dev *idev = &lif->ionic->idev;
struct device *dev = lif->ionic->dev;
struct ionic_lif_init_comp comp; struct ionic_lif_init_comp comp;
int dbpage_num;
int err; int err;
ionic_debugfs_add_lif(lif); ionic_debugfs_add_lif(lif);
...@@ -151,9 +159,40 @@ static int ionic_lif_init(struct ionic_lif *lif) ...@@ -151,9 +159,40 @@ static int ionic_lif_init(struct ionic_lif *lif)
lif->hw_index = le16_to_cpu(comp.hw_index); 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); set_bit(IONIC_LIF_INITED, lif->state);
return 0; return 0;
err_out_free_dbid:
kfree(lif->dbid_inuse);
lif->dbid_inuse = NULL;
return err;
} }
int ionic_lifs_init(struct ionic *ionic) int ionic_lifs_init(struct ionic *ionic)
......
...@@ -23,6 +23,8 @@ struct ionic_lif { ...@@ -23,6 +23,8 @@ struct ionic_lif {
bool registered; bool registered;
unsigned int index; unsigned int index;
unsigned int hw_index; unsigned int hw_index;
unsigned int kern_pid;
u64 __iomem *kern_dbpage;
unsigned int neqs; unsigned int neqs;
unsigned int nxqs; unsigned int nxqs;
...@@ -30,6 +32,8 @@ struct ionic_lif { ...@@ -30,6 +32,8 @@ struct ionic_lif {
dma_addr_t info_pa; dma_addr_t info_pa;
u32 info_sz; u32 info_sz;
unsigned long *dbid_inuse;
unsigned int dbid_count;
struct dentry *dentry; struct dentry *dentry;
u32 flags; u32 flags;
}; };
......
...@@ -22,6 +22,9 @@ struct ionic_intr { ...@@ -22,6 +22,9 @@ struct ionic_intr {
u32 rsvd[3]; 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. /** enum ionic_intr_mask_vals - valid values for mask and mask_assert.
* @IONIC_INTR_MASK_CLEAR: unmask interrupt. * @IONIC_INTR_MASK_CLEAR: unmask interrupt.
* @IONIC_INTR_MASK_SET: mask interrupt. * @IONIC_INTR_MASK_SET: mask interrupt.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment