Commit cde29af9 authored by Shinas Rasheed's avatar Shinas Rasheed Committed by Paolo Abeni
Browse files

octeon_ep: add PF-VF mailbox communication



Implement mailbox communication between PF and VFs.
PF-VF mailbox is used for all control commands from VF to PF and
asynchronous notification messages from PF to VF.

Signed-off-by: default avatarShinas Rasheed <srasheed@marvell.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent c49b292d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -7,4 +7,4 @@ obj-$(CONFIG_OCTEON_EP) += octeon_ep.o

octeon_ep-y := octep_main.o octep_cn9k_pf.o octep_tx.o octep_rx.o \
	       octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o \
	       octep_cnxk_pf.o
	       octep_pfvf_mbox.o octep_cnxk_pf.o
+52 −7
Original line number Diff line number Diff line
@@ -362,16 +362,55 @@ static void octep_setup_mbox_regs_cn93_pf(struct octep_device *oct, int q_no)
{
	struct octep_mbox *mbox = oct->mbox[q_no];

	mbox->q_no = q_no;

	/* PF mbox interrupt reg */
	mbox->mbox_int_reg = oct->mmio[0].hw_addr + CN93_SDP_EPF_MBOX_RINT(0);

	/* PF to VF DATA reg. PF writes into this reg */
	mbox->mbox_write_reg = oct->mmio[0].hw_addr + CN93_SDP_R_MBOX_PF_VF_DATA(q_no);
	mbox->pf_vf_data_reg = oct->mmio[0].hw_addr + CN93_SDP_MBOX_PF_VF_DATA(q_no);

	/* VF to PF DATA reg. PF reads from this reg */
	mbox->mbox_read_reg = oct->mmio[0].hw_addr + CN93_SDP_R_MBOX_VF_PF_DATA(q_no);
	mbox->vf_pf_data_reg = oct->mmio[0].hw_addr + CN93_SDP_MBOX_VF_PF_DATA(q_no);
}

/* Poll for mailbox messages from VF */
static void octep_poll_pfvf_mailbox(struct octep_device *oct)
{
	u32 vf, active_vfs, active_rings_per_vf, vf_mbox_queue;
	u64 reg0, reg1;

	reg0 = octep_read_csr64(oct, CN93_SDP_EPF_MBOX_RINT(0));
	reg1 = octep_read_csr64(oct, CN93_SDP_EPF_MBOX_RINT(1));
	if (reg0 || reg1) {
		active_vfs = CFG_GET_ACTIVE_VFS(oct->conf);
		active_rings_per_vf = CFG_GET_ACTIVE_RPVF(oct->conf);
		for (vf = 0; vf < active_vfs; vf++) {
			vf_mbox_queue = vf * active_rings_per_vf;

			if (vf_mbox_queue < 64) {
				if (!(reg0 & (0x1UL << vf_mbox_queue)))
					continue;
			} else {
				if (!(reg1 & (0x1UL << (vf_mbox_queue - 64))))
					continue;
			}

			if (!oct->mbox[vf_mbox_queue]) {
				dev_err(&oct->pdev->dev, "bad mbox vf %d\n", vf);
				continue;
			}
			schedule_work(&oct->mbox[vf_mbox_queue]->wk.work);
		}
		if (reg0)
			octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT(0), reg0);
		if (reg1)
			octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT(1), reg1);
	}
}

/* PF-VF mailbox interrupt handler */
static irqreturn_t octep_pfvf_mbox_intr_handler_cn93_pf(void *dev)
{
	struct octep_device *oct = (struct octep_device *)dev;

	octep_poll_pfvf_mailbox(oct);
	return IRQ_HANDLED;
}

/* Poll OEI events like heartbeat */
@@ -403,6 +442,7 @@ static irqreturn_t octep_oei_intr_handler_cn93_pf(void *dev)
 */
static void octep_poll_non_ioq_interrupts_cn93_pf(struct octep_device *oct)
{
	octep_poll_pfvf_mailbox(oct);
	octep_poll_oei_cn93_pf(oct);
}

@@ -646,6 +686,8 @@ static void octep_enable_interrupts_cn93_pf(struct octep_device *oct)

	octep_write_csr64(oct, CN93_SDP_EPF_MISC_RINT_ENA_W1S, intr_mask);
	octep_write_csr64(oct, CN93_SDP_EPF_DMA_RINT_ENA_W1S, intr_mask);
	octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT_ENA_W1S(0), -1ULL);
	octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT_ENA_W1S(1), -1ULL);

	octep_write_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT_ENA_W1S(0), -1ULL);
	octep_write_csr64(oct, CN93_SDP_EPF_PP_VF_RINT_ENA_W1S(0), -1ULL);
@@ -672,6 +714,8 @@ static void octep_disable_interrupts_cn93_pf(struct octep_device *oct)

	octep_write_csr64(oct, CN93_SDP_EPF_MISC_RINT_ENA_W1C, intr_mask);
	octep_write_csr64(oct, CN93_SDP_EPF_DMA_RINT_ENA_W1C, intr_mask);
	octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT_ENA_W1C(0), -1ULL);
	octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT_ENA_W1C(1), -1ULL);

	octep_write_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT_ENA_W1C(0), -1ULL);
	octep_write_csr64(oct, CN93_SDP_EPF_PP_VF_RINT_ENA_W1C(0), -1ULL);
@@ -807,6 +851,7 @@ void octep_device_setup_cn93_pf(struct octep_device *oct)
	oct->hw_ops.setup_oq_regs = octep_setup_oq_regs_cn93_pf;
	oct->hw_ops.setup_mbox_regs = octep_setup_mbox_regs_cn93_pf;

	oct->hw_ops.mbox_intr_handler = octep_pfvf_mbox_intr_handler_cn93_pf;
	oct->hw_ops.oei_intr_handler = octep_oei_intr_handler_cn93_pf;
	oct->hw_ops.ire_intr_handler = octep_ire_intr_handler_cn93_pf;
	oct->hw_ops.ore_intr_handler = octep_ore_intr_handler_cn93_pf;
+39 −7
Original line number Diff line number Diff line
@@ -392,16 +392,44 @@ static void octep_setup_mbox_regs_cnxk_pf(struct octep_device *oct, int q_no)
{
	struct octep_mbox *mbox = oct->mbox[q_no];

	mbox->q_no = q_no;

	/* PF mbox interrupt reg */
	mbox->mbox_int_reg = oct->mmio[0].hw_addr + CNXK_SDP_EPF_MBOX_RINT(0);

	/* PF to VF DATA reg. PF writes into this reg */
	mbox->mbox_write_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_MBOX_PF_VF_DATA(q_no);
	mbox->pf_vf_data_reg = oct->mmio[0].hw_addr + CNXK_SDP_MBOX_PF_VF_DATA(q_no);

	/* VF to PF DATA reg. PF reads from this reg */
	mbox->mbox_read_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_MBOX_VF_PF_DATA(q_no);
	mbox->vf_pf_data_reg = oct->mmio[0].hw_addr + CNXK_SDP_MBOX_VF_PF_DATA(q_no);
}

static void octep_poll_pfvf_mailbox_cnxk_pf(struct octep_device *oct)
{
	u32 vf, active_vfs, active_rings_per_vf, vf_mbox_queue;
	u64 reg0;

	reg0 = octep_read_csr64(oct, CNXK_SDP_EPF_MBOX_RINT(0));
	if (reg0) {
		active_vfs = CFG_GET_ACTIVE_VFS(oct->conf);
		active_rings_per_vf = CFG_GET_ACTIVE_RPVF(oct->conf);
		for (vf = 0; vf < active_vfs; vf++) {
			vf_mbox_queue = vf * active_rings_per_vf;
			if (!(reg0 & (0x1UL << vf_mbox_queue)))
				continue;

			if (!oct->mbox[vf_mbox_queue]) {
				dev_err(&oct->pdev->dev, "bad mbox vf %d\n", vf);
				continue;
			}
			schedule_work(&oct->mbox[vf_mbox_queue]->wk.work);
		}
		if (reg0)
			octep_write_csr64(oct, CNXK_SDP_EPF_MBOX_RINT(0), reg0);
	}
}

static irqreturn_t octep_pfvf_mbox_intr_handler_cnxk_pf(void *dev)
{
	struct octep_device *oct = (struct octep_device *)dev;

	octep_poll_pfvf_mailbox_cnxk_pf(oct);
	return IRQ_HANDLED;
}

/* Poll OEI events like heartbeat */
@@ -435,6 +463,7 @@ static irqreturn_t octep_oei_intr_handler_cnxk_pf(void *dev)
 */
static void octep_poll_non_ioq_interrupts_cnxk_pf(struct octep_device *oct)
{
	octep_poll_pfvf_mailbox_cnxk_pf(oct);
	octep_poll_oei_cnxk_pf(oct);
}

@@ -682,6 +711,7 @@ static void octep_enable_interrupts_cnxk_pf(struct octep_device *oct)

	octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT_ENA_W1S, intr_mask);
	octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT_ENA_W1S, intr_mask);
	octep_write_csr64(oct, CNXK_SDP_EPF_MBOX_RINT_ENA_W1S(0), -1ULL);

	octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S(0), -1ULL);
	octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S(0), -1ULL);
@@ -708,6 +738,7 @@ static void octep_disable_interrupts_cnxk_pf(struct octep_device *oct)

	octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT_ENA_W1C, intr_mask);
	octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT_ENA_W1C, intr_mask);
	octep_write_csr64(oct, CNXK_SDP_EPF_MBOX_RINT_ENA_W1C(0), -1ULL);

	octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C(0), -1ULL);
	octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C(0), -1ULL);
@@ -843,6 +874,7 @@ void octep_device_setup_cnxk_pf(struct octep_device *oct)
	oct->hw_ops.setup_oq_regs = octep_setup_oq_regs_cnxk_pf;
	oct->hw_ops.setup_mbox_regs = octep_setup_mbox_regs_cnxk_pf;

	oct->hw_ops.mbox_intr_handler = octep_pfvf_mbox_intr_handler_cnxk_pf;
	oct->hw_ops.oei_intr_handler = octep_oei_intr_handler_cnxk_pf;
	oct->hw_ops.ire_intr_handler = octep_ire_intr_handler_cnxk_pf;
	oct->hw_ops.ore_intr_handler = octep_ore_intr_handler_cnxk_pf;
+3 −1
Original line number Diff line number Diff line
@@ -16,10 +16,12 @@
 * |reserved (4 bytes)                         |
 * |-------------------------------------------|
 * |host version (8 bytes)                     |
 * |    low 32 bits                            |
 * |host status (8 bytes)                      |
 * |host reserved (104 bytes)                  |
 * |-------------------------------------------|
 * |fw version (8 bytes)                       |
 * |fw version's (8 bytes)                     |
 * |    min=high 32 bits, max=low 32 bits      |
 * |fw status (8 bytes)                        |
 * |fw reserved (104 bytes)                    |
 * |===========================================|
+81 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include "octep_config.h"
#include "octep_main.h"
#include "octep_ctrl_net.h"
#include "octep_pfvf_mbox.h"

#define OCTEP_INTR_POLL_TIME_MSECS    100
struct workqueue_struct *octep_wq;
@@ -159,6 +160,21 @@ static void octep_disable_msix(struct octep_device *oct)
	dev_info(&oct->pdev->dev, "Disabled MSI-X\n");
}

/**
 * octep_mbox_intr_handler() - common handler for pfvf mbox interrupts.
 *
 * @irq: Interrupt number.
 * @data: interrupt data.
 *
 * this is common handler for pfvf mbox interrupts.
 */
static irqreturn_t octep_mbox_intr_handler(int irq, void *data)
{
	struct octep_device *oct = data;

	return oct->hw_ops.mbox_intr_handler(oct);
}

/**
 * octep_oei_intr_handler() - common handler for output endpoint interrupts.
 *
@@ -362,7 +378,11 @@ static int octep_request_irqs(struct octep_device *oct)

		snprintf(irq_name, OCTEP_MSIX_NAME_SIZE,
			 "%s-%s", netdev->name, non_ioq_msix_names[i]);
		if (!strncmp(non_ioq_msix_names[i], "epf_oei_rint",
		if (!strncmp(non_ioq_msix_names[i], "epf_mbox_rint", strlen("epf_mbox_rint"))) {
			ret = request_irq(msix_entry->vector,
					  octep_mbox_intr_handler, 0,
					  irq_name, oct);
		} else if (!strncmp(non_ioq_msix_names[i], "epf_oei_rint",
			   strlen("epf_oei_rint"))) {
			ret = request_irq(msix_entry->vector,
					  octep_oei_intr_handler, 0,
@@ -1322,6 +1342,7 @@ static void octep_device_cleanup(struct octep_device *oct)
		oct->mbox[i] = NULL;
	}

	octep_delete_pfvf_mbox(oct);
	octep_ctrl_net_uninit(oct);
	cancel_delayed_work_sync(&oct->hb_task);

@@ -1419,6 +1440,12 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
		goto err_octep_config;
	}

	err = octep_setup_pfvf_mbox(octep_dev);
	if (err) {
		dev_err(&pdev->dev, "PF-VF mailbox setup failed\n");
		goto register_dev_err;
	}

	err = octep_ctrl_net_get_info(octep_dev, OCTEP_CTRL_NET_INVALID_VFID,
				      &octep_dev->conf->fw_info);
	if (err) {
@@ -1487,6 +1514,21 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
	return err;
}

static int octep_sriov_disable(struct octep_device *oct)
{
	struct pci_dev *pdev = oct->pdev;

	if (pci_vfs_assigned(oct->pdev)) {
		dev_warn(&pdev->dev, "Can't disable SRIOV while VFs are assigned\n");
		return -EPERM;
	}

	pci_disable_sriov(pdev);
	CFG_GET_ACTIVE_VFS(oct->conf) = 0;

	return 0;
}

/**
 * octep_remove() - Remove Octeon PCI device from driver control.
 *
@@ -1504,6 +1546,7 @@ static void octep_remove(struct pci_dev *pdev)
		return;

	netdev = oct->netdev;
	octep_sriov_disable(oct);
	if (netdev->reg_state == NETREG_REGISTERED)
		unregister_netdev(netdev);

@@ -1514,11 +1557,47 @@ static void octep_remove(struct pci_dev *pdev)
	pci_disable_device(pdev);
}

static int octep_sriov_enable(struct octep_device *oct, int num_vfs)
{
	struct pci_dev *pdev = oct->pdev;
	int err;

	CFG_GET_ACTIVE_VFS(oct->conf) = num_vfs;
	err = pci_enable_sriov(pdev, num_vfs);
	if (err) {
		dev_warn(&pdev->dev, "Failed to enable SRIOV err=%d\n", err);
		CFG_GET_ACTIVE_VFS(oct->conf) = 0;
		return err;
	}

	return num_vfs;
}

static int octep_sriov_configure(struct pci_dev *pdev, int num_vfs)
{
	struct octep_device *oct = pci_get_drvdata(pdev);
	int max_nvfs;

	if (num_vfs == 0)
		return octep_sriov_disable(oct);

	max_nvfs = CFG_GET_MAX_VFS(oct->conf);

	if (num_vfs > max_nvfs) {
		dev_err(&pdev->dev, "Invalid VF count Max supported VFs = %d\n",
			max_nvfs);
		return -EINVAL;
	}

	return octep_sriov_enable(oct, num_vfs);
}

static struct pci_driver octep_driver = {
	.name = OCTEP_DRV_NAME,
	.id_table = octep_pci_id_tbl,
	.probe = octep_probe,
	.remove = octep_remove,
	.sriov_configure = octep_sriov_configure,
};

/**
Loading