| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676 |
- // SPDX-License-Identifier: GPL-2.0
- /* Marvell Octeon CN10K DPI driver
- *
- * Copyright (C) 2024 Marvell.
- *
- */
- #include <linux/bitfield.h>
- #include <linux/compat.h>
- #include <linux/delay.h>
- #include <linux/miscdevice.h>
- #include <linux/module.h>
- #include <linux/pci.h>
- #include <linux/irq.h>
- #include <linux/interrupt.h>
- #include <uapi/misc/mrvl_cn10k_dpi.h>
- /* PCI device IDs */
- #define PCI_DEVID_MRVL_CN10K_DPI_PF 0xA080
- #define PCI_SUBDEVID_MRVL_CN10K_DPI_PF 0xB900
- /* PCI BAR Number */
- #define PCI_DPI_CFG_BAR 0
- /* MSI-X interrupts */
- #define DPI_MAX_REQQ_INT 0x20
- #define DPI_MAX_CC_INT 0x40
- /* MBOX MSI-X interrupt vector index */
- #define DPI_MBOX_PF_VF_INT_IDX 0x75
- #define DPI_MAX_IRQS (DPI_MBOX_PF_VF_INT_IDX + 1)
- #define DPI_MAX_VFS 0x20
- #define DPI_MAX_ENG_FIFO_SZ 0x20
- #define DPI_MAX_ENG_MOLR 0x400
- #define DPI_DMA_IDS_DMA_NPA_PF_FUNC(x) FIELD_PREP(GENMASK_ULL(31, 16), x)
- #define DPI_DMA_IDS_INST_STRM(x) FIELD_PREP(GENMASK_ULL(47, 40), x)
- #define DPI_DMA_IDS_DMA_STRM(x) FIELD_PREP(GENMASK_ULL(39, 32), x)
- #define DPI_DMA_ENG_EN_MOLR(x) FIELD_PREP(GENMASK_ULL(41, 32), x)
- #define DPI_EBUS_PORTX_CFG_MPS(x) FIELD_PREP(GENMASK(6, 4), x)
- #define DPI_DMA_IDS_DMA_SSO_PF_FUNC(x) FIELD_PREP(GENMASK(15, 0), x)
- #define DPI_DMA_IDS2_INST_AURA(x) FIELD_PREP(GENMASK(19, 0), x)
- #define DPI_DMA_IBUFF_CSIZE_CSIZE(x) FIELD_PREP(GENMASK(13, 0), x)
- #define DPI_EBUS_PORTX_CFG_MRRS(x) FIELD_PREP(GENMASK(2, 0), x)
- #define DPI_ENG_BUF_BLKS(x) FIELD_PREP(GENMASK(5, 0), x)
- #define DPI_DMA_CONTROL_DMA_ENB GENMASK_ULL(53, 48)
- #define DPI_DMA_CONTROL_O_MODE BIT_ULL(14)
- #define DPI_DMA_CONTROL_LDWB BIT_ULL(32)
- #define DPI_DMA_CONTROL_WQECSMODE1 BIT_ULL(37)
- #define DPI_DMA_CONTROL_ZBWCSEN BIT_ULL(39)
- #define DPI_DMA_CONTROL_WQECSOFF(ofst) (((u64)ofst) << 40)
- #define DPI_DMA_CONTROL_WQECSDIS BIT_ULL(47)
- #define DPI_DMA_CONTROL_PKT_EN BIT_ULL(56)
- #define DPI_DMA_IBUFF_CSIZE_NPA_FREE BIT(16)
- #define DPI_CTL_EN BIT_ULL(0)
- #define DPI_DMA_CC_INT BIT_ULL(0)
- #define DPI_DMA_QRST BIT_ULL(0)
- #define DPI_REQQ_INT_INSTRFLT BIT_ULL(0)
- #define DPI_REQQ_INT_RDFLT BIT_ULL(1)
- #define DPI_REQQ_INT_WRFLT BIT_ULL(2)
- #define DPI_REQQ_INT_CSFLT BIT_ULL(3)
- #define DPI_REQQ_INT_INST_DBO BIT_ULL(4)
- #define DPI_REQQ_INT_INST_ADDR_NULL BIT_ULL(5)
- #define DPI_REQQ_INT_INST_FILL_INVAL BIT_ULL(6)
- #define DPI_REQQ_INT_INSTR_PSN BIT_ULL(7)
- #define DPI_REQQ_INT \
- (DPI_REQQ_INT_INSTRFLT | \
- DPI_REQQ_INT_RDFLT | \
- DPI_REQQ_INT_WRFLT | \
- DPI_REQQ_INT_CSFLT | \
- DPI_REQQ_INT_INST_DBO | \
- DPI_REQQ_INT_INST_ADDR_NULL | \
- DPI_REQQ_INT_INST_FILL_INVAL | \
- DPI_REQQ_INT_INSTR_PSN)
- #define DPI_PF_RAS_EBI_DAT_PSN BIT_ULL(0)
- #define DPI_PF_RAS_NCB_DAT_PSN BIT_ULL(1)
- #define DPI_PF_RAS_NCB_CMD_PSN BIT_ULL(2)
- #define DPI_PF_RAS_INT \
- (DPI_PF_RAS_EBI_DAT_PSN | \
- DPI_PF_RAS_NCB_DAT_PSN | \
- DPI_PF_RAS_NCB_CMD_PSN)
- /* Message fields in word_l of DPI mailbox structure */
- #define DPI_MBOX_VFID(msg) FIELD_GET(GENMASK_ULL(7, 0), msg)
- #define DPI_MBOX_CMD(msg) FIELD_GET(GENMASK_ULL(11, 8), msg)
- #define DPI_MBOX_CBUF_SIZE(msg) FIELD_GET(GENMASK_ULL(27, 12), msg)
- #define DPI_MBOX_CBUF_AURA(msg) FIELD_GET(GENMASK_ULL(47, 28), msg)
- #define DPI_MBOX_SSO_PFFUNC(msg) FIELD_GET(GENMASK_ULL(63, 48), msg)
- /* Message fields in word_h of DPI mailbox structure */
- #define DPI_MBOX_NPA_PFFUNC(msg) FIELD_GET(GENMASK_ULL(15, 0), msg)
- #define DPI_MBOX_WQES_COMPL(msg) FIELD_GET(GENMASK_ULL(16, 16), msg)
- #define DPI_MBOX_WQES_OFFSET(msg) FIELD_GET(GENMASK_ULL(23, 17), msg)
- #define DPI_DMAX_IBUFF_CSIZE(x) (0x0ULL | ((x) << 11))
- #define DPI_DMAX_IDS(x) (0x18ULL | ((x) << 11))
- #define DPI_DMAX_IDS2(x) (0x20ULL | ((x) << 11))
- #define DPI_DMAX_QRST(x) (0x30ULL | ((x) << 11))
- #define DPI_CTL 0x10010ULL
- #define DPI_DMA_CONTROL 0x10018ULL
- #define DPI_PF_RAS 0x10308ULL
- #define DPI_PF_RAS_ENA_W1C 0x10318ULL
- #define DPI_MBOX_VF_PF_INT 0x16300ULL
- #define DPI_MBOX_VF_PF_INT_W1S 0x16308ULL
- #define DPI_MBOX_VF_PF_INT_ENA_W1C 0x16310ULL
- #define DPI_MBOX_VF_PF_INT_ENA_W1S 0x16318ULL
- #define DPI_DMA_ENGX_EN(x) (0x10040ULL | ((x) << 3))
- #define DPI_ENGX_BUF(x) (0x100C0ULL | ((x) << 3))
- #define DPI_EBUS_PORTX_CFG(x) (0x10100ULL | ((x) << 3))
- #define DPI_DMA_CCX_INT(x) (0x11000ULL | ((x) << 3))
- #define DPI_DMA_CCX_INT_ENA_W1C(x) (0x11800ULL | ((x) << 3))
- #define DPI_REQQX_INT(x) (0x12C00ULL | ((x) << 5))
- #define DPI_REQQX_INT_ENA_W1C(x) (0x13800ULL | ((x) << 5))
- #define DPI_MBOX_PF_VF_DATA0(x) (0x16000ULL | ((x) << 4))
- #define DPI_MBOX_PF_VF_DATA1(x) (0x16008ULL | ((x) << 4))
- #define DPI_WCTL_FIF_THR 0x17008ULL
- #define DPI_EBUS_MAX_PORTS 2
- #define DPI_EBUS_MRRS_MIN 128
- #define DPI_EBUS_MRRS_MAX 1024
- #define DPI_EBUS_MPS_MIN 128
- #define DPI_EBUS_MPS_MAX 1024
- #define DPI_WCTL_FIFO_THRESHOLD 0x30
- #define DPI_QUEUE_OPEN 0x1
- #define DPI_QUEUE_CLOSE 0x2
- #define DPI_REG_DUMP 0x3
- #define DPI_GET_REG_CFG 0x4
- #define DPI_QUEUE_OPEN_V2 0x5
- enum dpi_mbox_rsp_type {
- DPI_MBOX_TYPE_CMD,
- DPI_MBOX_TYPE_RSP_ACK,
- DPI_MBOX_TYPE_RSP_NACK,
- };
- struct dpivf_config {
- u32 aura;
- u16 csize;
- u16 sso_pf_func;
- u16 npa_pf_func;
- };
- struct dpipf_vf {
- struct dpivf_config vf_config;
- bool setup_done;
- u8 this_vfid;
- };
- /* DPI device mailbox */
- struct dpi_mbox {
- struct work_struct work;
- /* lock to serialize mbox requests */
- struct mutex lock;
- struct dpipf *pf;
- u8 __iomem *pf_vf_data_reg;
- u8 __iomem *vf_pf_data_reg;
- };
- struct dpipf {
- struct miscdevice miscdev;
- void __iomem *reg_base;
- struct pci_dev *pdev;
- struct dpipf_vf vf[DPI_MAX_VFS];
- /* Mailbox to talk to VFs */
- struct dpi_mbox *mbox[DPI_MAX_VFS];
- };
- struct dpi_mbox_message {
- uint64_t word_l;
- uint64_t word_h;
- };
- static inline void dpi_reg_write(struct dpipf *dpi, u64 offset, u64 val)
- {
- writeq(val, dpi->reg_base + offset);
- }
- static inline u64 dpi_reg_read(struct dpipf *dpi, u64 offset)
- {
- return readq(dpi->reg_base + offset);
- }
- static void dpi_wqe_cs_offset(struct dpipf *dpi, u8 offset)
- {
- u64 reg;
- reg = dpi_reg_read(dpi, DPI_DMA_CONTROL);
- reg &= ~DPI_DMA_CONTROL_WQECSDIS;
- reg |= DPI_DMA_CONTROL_ZBWCSEN | DPI_DMA_CONTROL_WQECSMODE1;
- reg |= DPI_DMA_CONTROL_WQECSOFF(offset);
- dpi_reg_write(dpi, DPI_DMA_CONTROL, reg);
- }
- static int dpi_queue_init(struct dpipf *dpi, struct dpipf_vf *dpivf, u8 vf)
- {
- u16 sso_pf_func = dpivf->vf_config.sso_pf_func;
- u16 npa_pf_func = dpivf->vf_config.npa_pf_func;
- u16 csize = dpivf->vf_config.csize;
- u32 aura = dpivf->vf_config.aura;
- unsigned long timeout;
- u64 reg;
- dpi_reg_write(dpi, DPI_DMAX_QRST(vf), DPI_DMA_QRST);
- /* Wait for a maximum of 3 sec */
- timeout = jiffies + msecs_to_jiffies(3000);
- while (!time_after(jiffies, timeout)) {
- reg = dpi_reg_read(dpi, DPI_DMAX_QRST(vf));
- if (!(reg & DPI_DMA_QRST))
- break;
- /* Reset would take time for the request cache to drain */
- usleep_range(500, 1000);
- }
- if (reg & DPI_DMA_QRST) {
- dev_err(&dpi->pdev->dev, "Queue reset failed\n");
- return -EBUSY;
- }
- dpi_reg_write(dpi, DPI_DMAX_IDS2(vf), 0);
- dpi_reg_write(dpi, DPI_DMAX_IDS(vf), 0);
- reg = DPI_DMA_IBUFF_CSIZE_CSIZE(csize) | DPI_DMA_IBUFF_CSIZE_NPA_FREE;
- dpi_reg_write(dpi, DPI_DMAX_IBUFF_CSIZE(vf), reg);
- reg = dpi_reg_read(dpi, DPI_DMAX_IDS2(vf));
- reg |= DPI_DMA_IDS2_INST_AURA(aura);
- dpi_reg_write(dpi, DPI_DMAX_IDS2(vf), reg);
- reg = dpi_reg_read(dpi, DPI_DMAX_IDS(vf));
- reg |= DPI_DMA_IDS_DMA_NPA_PF_FUNC(npa_pf_func);
- reg |= DPI_DMA_IDS_DMA_SSO_PF_FUNC(sso_pf_func);
- reg |= DPI_DMA_IDS_DMA_STRM(vf + 1);
- reg |= DPI_DMA_IDS_INST_STRM(vf + 1);
- dpi_reg_write(dpi, DPI_DMAX_IDS(vf), reg);
- return 0;
- }
- static void dpi_queue_fini(struct dpipf *dpi, u8 vf)
- {
- dpi_reg_write(dpi, DPI_DMAX_QRST(vf), DPI_DMA_QRST);
- /* Reset IDS and IDS2 registers */
- dpi_reg_write(dpi, DPI_DMAX_IDS2(vf), 0);
- dpi_reg_write(dpi, DPI_DMAX_IDS(vf), 0);
- }
- static irqreturn_t dpi_mbox_intr_handler(int irq, void *data)
- {
- struct dpipf *dpi = data;
- u64 reg;
- u32 vf;
- reg = dpi_reg_read(dpi, DPI_MBOX_VF_PF_INT);
- if (reg) {
- for (vf = 0; vf < pci_num_vf(dpi->pdev); vf++) {
- if (reg & BIT_ULL(vf))
- schedule_work(&dpi->mbox[vf]->work);
- }
- dpi_reg_write(dpi, DPI_MBOX_VF_PF_INT, reg);
- }
- return IRQ_HANDLED;
- }
- static int queue_config(struct dpipf *dpi, struct dpipf_vf *dpivf, struct dpi_mbox_message *msg)
- {
- int ret = 0;
- switch (DPI_MBOX_CMD(msg->word_l)) {
- case DPI_QUEUE_OPEN:
- case DPI_QUEUE_OPEN_V2:
- dpivf->vf_config.aura = DPI_MBOX_CBUF_AURA(msg->word_l);
- dpivf->vf_config.csize = DPI_MBOX_CMD(msg->word_l) == DPI_QUEUE_OPEN ?
- DPI_MBOX_CBUF_SIZE(msg->word_l) >> 3 :
- DPI_MBOX_CBUF_SIZE(msg->word_l);
- dpivf->vf_config.sso_pf_func = DPI_MBOX_SSO_PFFUNC(msg->word_l);
- dpivf->vf_config.npa_pf_func = DPI_MBOX_NPA_PFFUNC(msg->word_h);
- ret = dpi_queue_init(dpi, dpivf, DPI_MBOX_VFID(msg->word_l));
- if (!ret) {
- if (DPI_MBOX_WQES_COMPL(msg->word_h))
- dpi_wqe_cs_offset(dpi, DPI_MBOX_WQES_OFFSET(msg->word_h));
- dpivf->setup_done = true;
- }
- break;
- case DPI_QUEUE_CLOSE:
- memset(&dpivf->vf_config, 0, sizeof(struct dpivf_config));
- dpi_queue_fini(dpi, DPI_MBOX_VFID(msg->word_l));
- dpivf->setup_done = false;
- break;
- default:
- return -EINVAL;
- }
- return ret;
- }
- static void dpi_pfvf_mbox_work(struct work_struct *work)
- {
- struct dpi_mbox *mbox = container_of(work, struct dpi_mbox, work);
- struct dpi_mbox_message msg;
- struct dpipf_vf *dpivf;
- struct dpipf *dpi;
- int vfid, ret;
- dpi = mbox->pf;
- memset(&msg, 0, sizeof(msg));
- mutex_lock(&mbox->lock);
- msg.word_l = readq(mbox->vf_pf_data_reg);
- if (msg.word_l == (u64)-1)
- goto exit;
- vfid = DPI_MBOX_VFID(msg.word_l);
- if (vfid >= pci_num_vf(dpi->pdev))
- goto exit;
- dpivf = &dpi->vf[vfid];
- msg.word_h = readq(mbox->pf_vf_data_reg);
- ret = queue_config(dpi, dpivf, &msg);
- if (ret < 0)
- writeq(DPI_MBOX_TYPE_RSP_NACK, mbox->pf_vf_data_reg);
- else
- writeq(DPI_MBOX_TYPE_RSP_ACK, mbox->pf_vf_data_reg);
- exit:
- mutex_unlock(&mbox->lock);
- }
- /* Setup registers for a PF mailbox */
- static void dpi_setup_mbox_regs(struct dpipf *dpi, int vf)
- {
- struct dpi_mbox *mbox = dpi->mbox[vf];
- mbox->pf_vf_data_reg = dpi->reg_base + DPI_MBOX_PF_VF_DATA0(vf);
- mbox->vf_pf_data_reg = dpi->reg_base + DPI_MBOX_PF_VF_DATA1(vf);
- }
- static int dpi_pfvf_mbox_setup(struct dpipf *dpi)
- {
- int vf;
- for (vf = 0; vf < DPI_MAX_VFS; vf++) {
- dpi->mbox[vf] = devm_kzalloc(&dpi->pdev->dev, sizeof(*dpi->mbox[vf]), GFP_KERNEL);
- if (!dpi->mbox[vf])
- return -ENOMEM;
- mutex_init(&dpi->mbox[vf]->lock);
- INIT_WORK(&dpi->mbox[vf]->work, dpi_pfvf_mbox_work);
- dpi->mbox[vf]->pf = dpi;
- dpi_setup_mbox_regs(dpi, vf);
- }
- return 0;
- }
- static void dpi_pfvf_mbox_destroy(struct dpipf *dpi)
- {
- unsigned int vf;
- for (vf = 0; vf < DPI_MAX_VFS; vf++) {
- if (work_pending(&dpi->mbox[vf]->work))
- cancel_work_sync(&dpi->mbox[vf]->work);
- dpi->mbox[vf] = NULL;
- }
- }
- static void dpi_init(struct dpipf *dpi)
- {
- unsigned int engine, port;
- u8 mrrs_val, mps_val;
- u64 reg;
- for (engine = 0; engine < DPI_MAX_ENGINES; engine++) {
- if (engine == 4 || engine == 5)
- reg = DPI_ENG_BUF_BLKS(16);
- else
- reg = DPI_ENG_BUF_BLKS(8);
- dpi_reg_write(dpi, DPI_ENGX_BUF(engine), reg);
- }
- reg = DPI_DMA_CONTROL_ZBWCSEN | DPI_DMA_CONTROL_PKT_EN | DPI_DMA_CONTROL_LDWB |
- DPI_DMA_CONTROL_O_MODE | DPI_DMA_CONTROL_DMA_ENB;
- dpi_reg_write(dpi, DPI_DMA_CONTROL, reg);
- dpi_reg_write(dpi, DPI_CTL, DPI_CTL_EN);
- mrrs_val = 2; /* 512B */
- mps_val = 1; /* 256B */
- for (port = 0; port < DPI_EBUS_MAX_PORTS; port++) {
- reg = dpi_reg_read(dpi, DPI_EBUS_PORTX_CFG(port));
- reg &= ~(DPI_EBUS_PORTX_CFG_MRRS(7) | DPI_EBUS_PORTX_CFG_MPS(7));
- reg |= DPI_EBUS_PORTX_CFG_MPS(mps_val) | DPI_EBUS_PORTX_CFG_MRRS(mrrs_val);
- dpi_reg_write(dpi, DPI_EBUS_PORTX_CFG(port), reg);
- }
- dpi_reg_write(dpi, DPI_WCTL_FIF_THR, DPI_WCTL_FIFO_THRESHOLD);
- }
- static void dpi_fini(struct dpipf *dpi)
- {
- unsigned int engine;
- for (engine = 0; engine < DPI_MAX_ENGINES; engine++)
- dpi_reg_write(dpi, DPI_ENGX_BUF(engine), 0);
- dpi_reg_write(dpi, DPI_DMA_CONTROL, 0);
- dpi_reg_write(dpi, DPI_CTL, 0);
- }
- static void dpi_free_irq_vectors(void *pdev)
- {
- pci_free_irq_vectors((struct pci_dev *)pdev);
- }
- static int dpi_irq_init(struct dpipf *dpi)
- {
- struct pci_dev *pdev = dpi->pdev;
- struct device *dev = &pdev->dev;
- int i, ret;
- /* Clear all RAS interrupts */
- dpi_reg_write(dpi, DPI_PF_RAS, DPI_PF_RAS_INT);
- /* Clear all RAS interrupt enable bits */
- dpi_reg_write(dpi, DPI_PF_RAS_ENA_W1C, DPI_PF_RAS_INT);
- for (i = 0; i < DPI_MAX_REQQ_INT; i++) {
- dpi_reg_write(dpi, DPI_REQQX_INT(i), DPI_REQQ_INT);
- dpi_reg_write(dpi, DPI_REQQX_INT_ENA_W1C(i), DPI_REQQ_INT);
- }
- for (i = 0; i < DPI_MAX_CC_INT; i++) {
- dpi_reg_write(dpi, DPI_DMA_CCX_INT(i), DPI_DMA_CC_INT);
- dpi_reg_write(dpi, DPI_DMA_CCX_INT_ENA_W1C(i), DPI_DMA_CC_INT);
- }
- ret = pci_alloc_irq_vectors(pdev, DPI_MAX_IRQS, DPI_MAX_IRQS, PCI_IRQ_MSIX);
- if (ret != DPI_MAX_IRQS) {
- dev_err(dev, "DPI: Failed to alloc %d msix irqs\n", DPI_MAX_IRQS);
- return ret;
- }
- ret = devm_add_action_or_reset(dev, dpi_free_irq_vectors, pdev);
- if (ret) {
- dev_err(dev, "DPI: Failed to add irq free action\n");
- return ret;
- }
- ret = devm_request_irq(dev, pci_irq_vector(pdev, DPI_MBOX_PF_VF_INT_IDX),
- dpi_mbox_intr_handler, 0, "dpi-mbox", dpi);
- if (ret) {
- dev_err(dev, "DPI: request_irq failed for mbox; err=%d\n", ret);
- return ret;
- }
- dpi_reg_write(dpi, DPI_MBOX_VF_PF_INT_ENA_W1S, GENMASK_ULL(31, 0));
- return 0;
- }
- static int dpi_mps_mrrs_config(struct dpipf *dpi, void __user *arg)
- {
- struct dpi_mps_mrrs_cfg cfg;
- u8 mrrs_val, mps_val;
- u64 reg;
- if (copy_from_user(&cfg, arg, sizeof(struct dpi_mps_mrrs_cfg)))
- return -EFAULT;
- if (cfg.max_read_req_sz < DPI_EBUS_MRRS_MIN || cfg.max_read_req_sz > DPI_EBUS_MRRS_MAX ||
- !is_power_of_2(cfg.max_read_req_sz))
- return -EINVAL;
- if (cfg.max_payload_sz < DPI_EBUS_MPS_MIN || cfg.max_payload_sz > DPI_EBUS_MPS_MAX ||
- !is_power_of_2(cfg.max_payload_sz))
- return -EINVAL;
- if (cfg.port >= DPI_EBUS_MAX_PORTS)
- return -EINVAL;
- /* Make sure reserved fields are set to 0 */
- if (cfg.reserved)
- return -EINVAL;
- mrrs_val = fls(cfg.max_read_req_sz >> 8);
- mps_val = fls(cfg.max_payload_sz >> 8);
- reg = dpi_reg_read(dpi, DPI_EBUS_PORTX_CFG(cfg.port));
- reg &= ~(DPI_EBUS_PORTX_CFG_MRRS(0x7) | DPI_EBUS_PORTX_CFG_MPS(0x7));
- reg |= DPI_EBUS_PORTX_CFG_MPS(mps_val) | DPI_EBUS_PORTX_CFG_MRRS(mrrs_val);
- dpi_reg_write(dpi, DPI_EBUS_PORTX_CFG(cfg.port), reg);
- return 0;
- }
- static int dpi_engine_config(struct dpipf *dpi, void __user *arg)
- {
- struct dpi_engine_cfg cfg;
- unsigned int engine;
- u8 *eng_buf;
- u64 reg;
- if (copy_from_user(&cfg, arg, sizeof(struct dpi_engine_cfg)))
- return -EFAULT;
- /* Make sure reserved fields are set to 0 */
- if (cfg.reserved)
- return -EINVAL;
- eng_buf = (u8 *)&cfg.fifo_mask;
- for (engine = 0; engine < DPI_MAX_ENGINES; engine++) {
- if (eng_buf[engine] > DPI_MAX_ENG_FIFO_SZ)
- return -EINVAL;
- dpi_reg_write(dpi, DPI_ENGX_BUF(engine), eng_buf[engine]);
- if (cfg.update_molr) {
- if (cfg.molr[engine] > DPI_MAX_ENG_MOLR)
- return -EINVAL;
- reg = DPI_DMA_ENG_EN_MOLR(cfg.molr[engine]);
- dpi_reg_write(dpi, DPI_DMA_ENGX_EN(engine), reg);
- } else {
- /* Make sure unused fields are set to 0 */
- if (cfg.molr[engine])
- return -EINVAL;
- }
- }
- return 0;
- }
- static long dpi_dev_ioctl(struct file *fptr, unsigned int cmd, unsigned long data)
- {
- void __user *arg = (void __user *)data;
- struct dpipf *dpi;
- int ret;
- dpi = container_of(fptr->private_data, struct dpipf, miscdev);
- switch (cmd) {
- case DPI_MPS_MRRS_CFG:
- ret = dpi_mps_mrrs_config(dpi, arg);
- break;
- case DPI_ENGINE_CFG:
- ret = dpi_engine_config(dpi, arg);
- break;
- default:
- ret = -ENOTTY;
- break;
- }
- return ret;
- }
- static const struct file_operations dpi_device_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = dpi_dev_ioctl,
- .compat_ioctl = compat_ptr_ioctl,
- };
- static int dpi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
- {
- struct device *dev = &pdev->dev;
- struct dpipf *dpi;
- int ret;
- dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
- if (!dpi)
- return -ENOMEM;
- dpi->pdev = pdev;
- ret = pcim_enable_device(pdev);
- if (ret) {
- dev_err(dev, "DPI: Failed to enable PCI device\n");
- return ret;
- }
- ret = pcim_iomap_regions(pdev, BIT(0) | BIT(4), KBUILD_MODNAME);
- if (ret) {
- dev_err(dev, "DPI: Failed to request MMIO region\n");
- return ret;
- }
- dpi->reg_base = pcim_iomap_table(pdev)[PCI_DPI_CFG_BAR];
- /* Initialize global PF registers */
- dpi_init(dpi);
- /* Setup PF-VF mailbox */
- ret = dpi_pfvf_mbox_setup(dpi);
- if (ret) {
- dev_err(dev, "DPI: Failed to setup pf-vf mbox\n");
- goto err_dpi_fini;
- }
- /* Register interrupts */
- ret = dpi_irq_init(dpi);
- if (ret) {
- dev_err(dev, "DPI: Failed to initialize irq vectors\n");
- goto err_dpi_mbox_free;
- }
- pci_set_drvdata(pdev, dpi);
- dpi->miscdev.minor = MISC_DYNAMIC_MINOR;
- dpi->miscdev.name = KBUILD_MODNAME;
- dpi->miscdev.fops = &dpi_device_fops;
- dpi->miscdev.parent = dev;
- ret = misc_register(&dpi->miscdev);
- if (ret) {
- dev_err(dev, "DPI: Failed to register misc device\n");
- goto err_dpi_mbox_free;
- }
- return 0;
- err_dpi_mbox_free:
- dpi_pfvf_mbox_destroy(dpi);
- err_dpi_fini:
- dpi_fini(dpi);
- return ret;
- }
- static void dpi_remove(struct pci_dev *pdev)
- {
- struct dpipf *dpi = pci_get_drvdata(pdev);
- misc_deregister(&dpi->miscdev);
- pci_sriov_configure_simple(pdev, 0);
- dpi_pfvf_mbox_destroy(dpi);
- dpi_fini(dpi);
- pci_set_drvdata(pdev, NULL);
- }
- static const struct pci_device_id dpi_id_table[] = {
- { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_MRVL_CN10K_DPI_PF,
- PCI_VENDOR_ID_CAVIUM, PCI_SUBDEVID_MRVL_CN10K_DPI_PF) },
- { 0, } /* end of table */
- };
- static struct pci_driver dpi_driver = {
- .name = KBUILD_MODNAME,
- .id_table = dpi_id_table,
- .probe = dpi_probe,
- .remove = dpi_remove,
- .sriov_configure = pci_sriov_configure_simple,
- };
- module_pci_driver(dpi_driver);
- MODULE_DEVICE_TABLE(pci, dpi_id_table);
- MODULE_AUTHOR("Marvell.");
- MODULE_DESCRIPTION("Marvell Octeon CN10K DPI Driver");
- MODULE_LICENSE("GPL");
|