Adds support for mailbox interrupt processing of various commands. Signed-off-by: Derek Chickles <derek.chick...@caviumnetworks.com> Signed-off-by: Satanand Burla <satananda.bu...@caviumnetworks.com> Signed-off-by: Felix Manlunas <felix.manlu...@caviumnetworks.com> Signed-off-by: Raghu Vatsavayi <raghu.vatsav...@caviumnetworks.com> --- .../ethernet/cavium/liquidio/cn23xx_pf_device.c | 157 +++++++++++++++++++++ drivers/net/ethernet/cavium/liquidio/lio_main.c | 8 +- .../net/ethernet/cavium/liquidio/octeon_device.c | 1 + .../net/ethernet/cavium/liquidio/octeon_device.h | 6 + drivers/net/ethernet/cavium/liquidio/octeon_droq.c | 28 ++-- 5 files changed, 184 insertions(+), 16 deletions(-)
diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c index b3c61302..4d975d8 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c @@ -30,6 +30,7 @@ #include "octeon_device.h" #include "cn23xx_pf_device.h" #include "octeon_main.h" +#include "octeon_mailbox.h" #define RESET_NOTDONE 0 #define RESET_DONE 1 @@ -682,6 +683,118 @@ static void cn23xx_setup_oq_regs(struct octeon_device *oct, u32 oq_no) } } +static void cn23xx_pf_mbox_thread(struct work_struct *work) +{ + struct cavium_wk *wk = (struct cavium_wk *)work; + struct octeon_mbox *mbox = (struct octeon_mbox *)wk->ctxptr; + struct octeon_device *oct = mbox->oct_dev; + u64 mbox_int_val, val64; + u32 q_no, i; + + if (oct->rev_id < OCTEON_CN23XX_REV_1_1) { + /*read and clear by writing 1*/ + mbox_int_val = readq(mbox->mbox_int_reg); + writeq(mbox_int_val, mbox->mbox_int_reg); + + for (i = 0; i < oct->sriov_info.num_vfs; i++) { + q_no = i * oct->sriov_info.rings_per_vf; + + val64 = readq(oct->mbox[q_no]->mbox_write_reg); + + if (val64 && (val64 != OCTEON_PFVFACK)) { + if (octeon_mbox_read(oct->mbox[q_no])) + octeon_mbox_process_message( + oct->mbox[q_no]); + } + } + + schedule_delayed_work(&wk->work, msecs_to_jiffies(10)); + } else { + octeon_mbox_process_message(mbox); + } +} + +static int cn23xx_setup_pf_mbox(struct octeon_device *oct) +{ + u32 q_no, i; + u16 mac_no = oct->pcie_port; + u16 pf_num = oct->pf_num; + struct octeon_mbox *mbox = NULL; + + if (!oct->sriov_info.num_vfs) + return 0; + + for (i = 0; i < oct->sriov_info.num_vfs; i++) { + q_no = i * oct->sriov_info.rings_per_vf; + + mbox = vmalloc(sizeof(*mbox)); + if (!mbox) + goto free_mbox; + + memset(mbox, 0, sizeof(struct octeon_mbox)); + + spin_lock_init(&mbox->lock); + + mbox->oct_dev = oct; + + mbox->q_no = q_no; + + mbox->state = OCTEON_MBOX_STATE_IDLE; + + /* PF mbox interrupt reg */ + mbox->mbox_int_reg = (u8 *)oct->mmio[0].hw_addr + + CN23XX_SLI_MAC_PF_MBOX_INT(mac_no, pf_num); + + /* PF writes into SIG0 reg */ + mbox->mbox_write_reg = (u8 *)oct->mmio[0].hw_addr + + CN23XX_SLI_PKT_PF_VF_MBOX_SIG(q_no, 0); + + /* PF reads from SIG1 reg */ + mbox->mbox_read_reg = (u8 *)oct->mmio[0].hw_addr + + CN23XX_SLI_PKT_PF_VF_MBOX_SIG(q_no, 1); + + /*Mail Box Thread creation*/ + INIT_DELAYED_WORK(&mbox->mbox_poll_wk.work, + cn23xx_pf_mbox_thread); + mbox->mbox_poll_wk.ctxptr = (void *)mbox; + + oct->mbox[q_no] = mbox; + + writeq(OCTEON_PFVFSIG, mbox->mbox_read_reg); + } + + if (oct->rev_id < OCTEON_CN23XX_REV_1_1) + schedule_delayed_work(&oct->mbox[0]->mbox_poll_wk.work, + msecs_to_jiffies(0)); + + return 0; + +free_mbox: + while (i) { + i--; + vfree(oct->mbox[i]); + } + + return 1; +} + +static int cn23xx_free_pf_mbox(struct octeon_device *oct) +{ + u32 q_no, i; + + if (!oct->sriov_info.num_vfs) + return 0; + + for (i = 0; i < oct->sriov_info.num_vfs; i++) { + q_no = i * oct->sriov_info.rings_per_vf; + cancel_delayed_work_sync( + &oct->mbox[q_no]->mbox_poll_wk.work); + vfree(oct->mbox[q_no]); + } + + return 0; +} + static int cn23xx_enable_io_queues(struct octeon_device *oct) { u64 reg_val; @@ -876,6 +989,29 @@ static u64 cn23xx_pf_msix_interrupt_handler(void *dev) return ret; } +static void cn23xx_handle_pf_mbox_intr(struct octeon_device *oct) +{ + u64 mbox_int_val; + u32 i, q_no; + struct delayed_work *work; + + mbox_int_val = readq(oct->mbox[0]->mbox_int_reg); + + for (i = 0; i < oct->sriov_info.num_vfs; i++) { + q_no = i * oct->sriov_info.rings_per_vf; + + if (mbox_int_val & BIT_ULL(q_no)) { + writeq(BIT_ULL(q_no), + oct->mbox[0]->mbox_int_reg); + if (octeon_mbox_read(oct->mbox[q_no])) { + work = &oct->mbox[q_no]->mbox_poll_wk.work; + schedule_delayed_work(work, + msecs_to_jiffies(0)); + } + } + } +} + static irqreturn_t cn23xx_interrupt_handler(void *dev) { struct octeon_device *oct = (struct octeon_device *)dev; @@ -891,6 +1027,10 @@ static irqreturn_t cn23xx_interrupt_handler(void *dev) dev_err(&oct->pci_dev->dev, "OCTEON[%d]: Error Intr: 0x%016llx\n", oct->octeon_id, CVM_CAST64(intr64)); + /* When VFs write into MBOX_SIG2 reg,these intr is set in PF */ + if (intr64 & CN23XX_INTR_VF_MBOX) + cn23xx_handle_pf_mbox_intr(oct); + if (oct->msix_on != LIO_FLAG_MSIX_ENABLED) { if (intr64 & CN23XX_INTR_PKT_DATA) oct->int_status |= OCT_DEV_INTR_PKT_DATA; @@ -981,6 +1121,13 @@ static void cn23xx_enable_pf_interrupt(struct octeon_device *oct, u8 intr_flag) intr_val = readq(cn23xx->intr_enb_reg64); intr_val |= CN23XX_INTR_PKT_DATA; writeq(intr_val, cn23xx->intr_enb_reg64); + } else if ((intr_flag & OCTEON_MBOX_INTR) && + (oct->sriov_info.num_vfs > 0)) { + if (oct->rev_id >= OCTEON_CN23XX_REV_1_1) { + intr_val = readq(cn23xx->intr_enb_reg64); + intr_val |= CN23XX_INTR_VF_MBOX; + writeq(intr_val, cn23xx->intr_enb_reg64); + } } } @@ -996,6 +1143,13 @@ static void cn23xx_disable_pf_interrupt(struct octeon_device *oct, u8 intr_flag) intr_val = readq(cn23xx->intr_enb_reg64); intr_val &= ~CN23XX_INTR_PKT_DATA; writeq(intr_val, cn23xx->intr_enb_reg64); + } else if ((intr_flag & OCTEON_MBOX_INTR) && + (oct->sriov_info.num_vfs > 0)) { + if (oct->rev_id >= OCTEON_CN23XX_REV_1_1) { + intr_val = readq(cn23xx->intr_enb_reg64); + intr_val &= ~CN23XX_INTR_VF_MBOX; + writeq(intr_val, cn23xx->intr_enb_reg64); + } } } @@ -1268,6 +1422,9 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct) oct->fn_list.setup_iq_regs = cn23xx_setup_iq_regs; oct->fn_list.setup_oq_regs = cn23xx_setup_oq_regs; + oct->fn_list.setup_mbox = cn23xx_setup_pf_mbox; + oct->fn_list.free_mbox = cn23xx_free_pf_mbox; + oct->fn_list.process_interrupt_regs = cn23xx_interrupt_handler; oct->fn_list.msix_interrupt_handler = cn23xx_pf_msix_interrupt_handler; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 438d32f..e480c23 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -1449,8 +1449,10 @@ static void octeon_destroy_resources(struct octeon_device *oct) pci_disable_msi(oct->pci_dev); } - if (OCTEON_CN23XX_PF(oct)) + if (OCTEON_CN23XX_PF(oct)) { octeon_free_ioq_vector(oct); + oct->fn_list.free_mbox(oct); + } /* fallthrough */ case OCT_DEV_IN_RESET: case OCT_DEV_DROQ_INIT_DONE: @@ -4275,6 +4277,10 @@ static int octeon_device_init(struct octeon_device *octeon_dev) atomic_set(&octeon_dev->status, OCT_DEV_DROQ_INIT_DONE); if (OCTEON_CN23XX_PF(octeon_dev)) { + if (octeon_dev->fn_list.setup_mbox(octeon_dev)) { + dev_err(&octeon_dev->pci_dev->dev, "OCTEON: Mailbox setup failed\n"); + return 1; + } if (octeon_allocate_ioq_vector(octeon_dev)) { dev_err(&octeon_dev->pci_dev->dev, "OCTEON: ioq vector allocation failed\n"); return 1; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c index 03a4eac..1136801 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c @@ -768,6 +768,7 @@ octeon_allocate_ioq_vector(struct octeon_device *oct) ioq_vector->oct_dev = oct; ioq_vector->iq_index = i; ioq_vector->droq_index = i; + ioq_vector->mbox = oct->mbox[i]; cpu_num = i % num_online_cpus(); cpumask_set_cpu(cpu_num, &ioq_vector->affinity_mask); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h index 3a71451..fc62d7d 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h @@ -54,6 +54,7 @@ enum octeon_pci_swap_mode { }; #define OCTEON_OUTPUT_INTR (2) +#define OCTEON_MBOX_INTR (4) #define OCTEON_ALL_INTR 0xff /*--------------- PCI BAR1 index registers -------------*/ @@ -209,6 +210,10 @@ struct octeon_fn_list { irqreturn_t (*process_interrupt_regs)(void *); u64 (*msix_interrupt_handler)(void *); + + int (*setup_mbox)(struct octeon_device *); + int (*free_mbox)(struct octeon_device *); + int (*soft_reset)(struct octeon_device *); int (*setup_device_regs)(struct octeon_device *); void (*bar1_idx_setup)(struct octeon_device *, u64, u32, int); @@ -349,6 +354,7 @@ struct octeon_ioq_vector { int iq_index; int droq_index; int vector; + struct octeon_mbox *mbox; struct cpumask affinity_mask; u32 ioq_num; }; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c index f60e532..924f158 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c @@ -19,6 +19,7 @@ * This file may also be available under a different license from Cavium. * Contact Cavium, Inc. for more information **********************************************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/pci.h> #include <linux/netdevice.h> #include <linux/vmalloc.h> @@ -211,7 +212,7 @@ int octeon_delete_droq(struct octeon_device *oct, u32 q_no) { struct octeon_droq *droq = oct->droq[q_no]; - dev_dbg(&oct->pci_dev->dev, "%s[%d]\n", __func__, q_no); + pr_devel("%s[%d]\n", __func__, q_no); octeon_droq_destroy_ring_buffers(oct, droq); vfree(droq->recv_buf_list); @@ -243,7 +244,7 @@ int octeon_init_droq(struct octeon_device *oct, int orig_node = dev_to_node(&oct->pci_dev->dev); int numa_node = cpu_to_node(q_no % num_online_cpus()); - dev_dbg(&oct->pci_dev->dev, "%s[%d]\n", __func__, q_no); + pr_devel("%s[%d]\n", __func__, q_no); droq = oct->droq[q_no]; memset(droq, 0, OCT_DROQ_SIZE); @@ -290,10 +291,10 @@ int octeon_init_droq(struct octeon_device *oct, return 1; } - dev_dbg(&oct->pci_dev->dev, "droq[%d]: desc_ring: virt: 0x%p, dma: %lx\n", - q_no, droq->desc_ring, droq->desc_ring_dma); - dev_dbg(&oct->pci_dev->dev, "droq[%d]: num_desc: %d\n", q_no, - droq->max_count); + pr_devel("droq[%d]: desc_ring: virt: 0x%p, dma: %lx\n", + q_no, droq->desc_ring, droq->desc_ring_dma); + pr_devel("droq[%d]: num_desc: %d\n", q_no, + droq->max_count); droq->info_list = cnnic_numa_alloc_aligned_dma((droq->max_count * @@ -327,8 +328,8 @@ int octeon_init_droq(struct octeon_device *oct, droq->pkts_per_intr = c_pkts_per_intr; droq->refill_threshold = c_refill_threshold; - dev_dbg(&oct->pci_dev->dev, "DROQ INIT: max_empty_descs: %d\n", - droq->max_empty_descs); + pr_devel("DROQ INIT: max_empty_descs: %d\n", + droq->max_empty_descs); spin_lock_init(&droq->lock); @@ -628,9 +629,6 @@ octeon_droq_fast_process_packets(struct octeon_device *oct, dev_err(&oct->pci_dev->dev, "DROQ[%d] idx: %d len:0, pkt_cnt: %d\n", droq->q_no, droq->read_idx, pkt_count); - print_hex_dump_bytes("", DUMP_PREFIX_ADDRESS, - (u8 *)info, - OCT_DROQ_INFO_SIZE); break; } @@ -978,8 +976,8 @@ int octeon_create_droq(struct octeon_device *oct, int numa_node = cpu_to_node(q_no % num_online_cpus()); if (oct->droq[q_no]) { - dev_dbg(&oct->pci_dev->dev, "Droq already in use. Cannot create droq %d again\n", - q_no); + pr_devel("Droq already in use. Cannot create droq %d again\n", + q_no); return 1; } @@ -1000,8 +998,8 @@ int octeon_create_droq(struct octeon_device *oct, oct->num_oqs++; - dev_dbg(&oct->pci_dev->dev, "%s: Total number of OQ: %d\n", __func__, - oct->num_oqs); + pr_devel("%s: Total number of OQ: %d\n", __func__, + oct->num_oqs); /* Global Droq register settings */ -- 1.8.3.1