// SPDX-License-Identifier: GPL-2.0
/* Marvell RVU Ethernet driver
*
* Copyright (C) 2024 Marvell.
*
*/
#include "otx2_common.h"
#include "otx2_reg.h"
#include "otx2_struct.h"
#include "cn10k.h"
static struct dev_hw_ops cn20k_hw_ops = {
.pfaf_mbox_intr_handler = cn20k_pfaf_mbox_intr_handler,
.vfaf_mbox_intr_handler = cn20k_vfaf_mbox_intr_handler,
.pfvf_mbox_intr_handler = cn20k_pfvf_mbox_intr_handler,
};
void cn20k_init(struct otx2_nic *pfvf)
{
pfvf->hw_ops = &cn20k_hw_ops;
}
EXPORT_SYMBOL(cn20k_init);
/* CN20K mbox AF => PFx irq handler */
irqreturn_t cn20k_pfaf_mbox_intr_handler(int irq, void *pf_irq)
{
struct otx2_nic *pf = pf_irq;
struct mbox *mw = &pf->mbox;
struct otx2_mbox_dev *mdev;
struct otx2_mbox *mbox;
struct mbox_hdr *hdr;
u64 pf_trig_val;
pf_trig_val = otx2_read64(pf, RVU_PF_INT) & 0 x3ULL;
/* Clear the IRQ */
otx2_write64(pf, RVU_PF_INT, pf_trig_val);
if (pf_trig_val & BIT_ULL(0 )) {
mbox = &mw->mbox_up;
mdev = &mbox->dev[0 ];
otx2_sync_mbox_bbuf(mbox, 0 );
hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
if (hdr->num_msgs)
queue_work(pf->mbox_wq, &mw->mbox_up_wrk);
trace_otx2_msg_interrupt(pf->pdev, "UP message from AF to PF" ,
BIT_ULL(0 ));
}
if (pf_trig_val & BIT_ULL(1 )) {
mbox = &mw->mbox;
mdev = &mbox->dev[0 ];
otx2_sync_mbox_bbuf(mbox, 0 );
hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
if (hdr->num_msgs)
queue_work(pf->mbox_wq, &mw->mbox_wrk);
trace_otx2_msg_interrupt(pf->pdev, "DOWN reply from AF to PF" ,
BIT_ULL(1 ));
}
return IRQ_HANDLED;
}
irqreturn_t cn20k_vfaf_mbox_intr_handler(int irq, void *vf_irq)
{
struct otx2_nic *vf = vf_irq;
struct otx2_mbox_dev *mdev;
struct otx2_mbox *mbox;
struct mbox_hdr *hdr;
u64 vf_trig_val;
vf_trig_val = otx2_read64(vf, RVU_VF_INT) & 0 x3ULL;
/* Clear the IRQ */
otx2_write64(vf, RVU_VF_INT, vf_trig_val);
/* Read latest mbox data */
smp_rmb();
if (vf_trig_val & BIT_ULL(1 )) {
/* Check for PF => VF response messages */
mbox = &vf->mbox.mbox;
mdev = &mbox->dev[0 ];
otx2_sync_mbox_bbuf(mbox, 0 );
hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
if (hdr->num_msgs)
queue_work(vf->mbox_wq, &vf->mbox.mbox_wrk);
trace_otx2_msg_interrupt(mbox->pdev, "DOWN reply from PF0 to VF" ,
BIT_ULL(1 ));
}
if (vf_trig_val & BIT_ULL(0 )) {
/* Check for PF => VF notification messages */
mbox = &vf->mbox.mbox_up;
mdev = &mbox->dev[0 ];
otx2_sync_mbox_bbuf(mbox, 0 );
hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
if (hdr->num_msgs)
queue_work(vf->mbox_wq, &vf->mbox.mbox_up_wrk);
trace_otx2_msg_interrupt(mbox->pdev, "UP message from PF0 to VF" ,
BIT_ULL(0 ));
}
return IRQ_HANDLED;
}
void cn20k_enable_pfvf_mbox_intr(struct otx2_nic *pf, int numvfs)
{
/* Clear PF <=> VF mailbox IRQ */
otx2_write64(pf, RVU_MBOX_PF_VFPF_INTX(0 ), ~0 ull);
otx2_write64(pf, RVU_MBOX_PF_VFPF_INTX(1 ), ~0 ull);
otx2_write64(pf, RVU_MBOX_PF_VFPF1_INTX(0 ), ~0 ull);
otx2_write64(pf, RVU_MBOX_PF_VFPF1_INTX(1 ), ~0 ull);
/* Enable PF <=> VF mailbox IRQ */
otx2_write64(pf, RVU_MBOX_PF_VFPF_INT_ENA_W1SX(0 ), INTR_MASK(numvfs));
otx2_write64(pf, RVU_MBOX_PF_VFPF1_INT_ENA_W1SX(0 ), INTR_MASK(numvfs));
if (numvfs > 64 ) {
numvfs -= 64 ;
otx2_write64(pf, RVU_MBOX_PF_VFPF_INT_ENA_W1SX(1 ),
INTR_MASK(numvfs));
otx2_write64(pf, RVU_MBOX_PF_VFPF1_INT_ENA_W1SX(1 ),
INTR_MASK(numvfs));
}
}
void cn20k_disable_pfvf_mbox_intr(struct otx2_nic *pf, int numvfs)
{
int vector, intr_vec, vec = 0 ;
/* Disable PF <=> VF mailbox IRQ */
otx2_write64(pf, RVU_MBOX_PF_VFPF_INT_ENA_W1CX(0 ), ~0 ull);
otx2_write64(pf, RVU_MBOX_PF_VFPF_INT_ENA_W1CX(1 ), ~0 ull);
otx2_write64(pf, RVU_MBOX_PF_VFPF1_INT_ENA_W1CX(0 ), ~0 ull);
otx2_write64(pf, RVU_MBOX_PF_VFPF1_INT_ENA_W1CX(1 ), ~0 ull);
otx2_write64(pf, RVU_MBOX_PF_VFPF_INTX(0 ), ~0 ull);
otx2_write64(pf, RVU_MBOX_PF_VFPF1_INTX(0 ), ~0 ull);
if (numvfs > 64 ) {
otx2_write64(pf, RVU_MBOX_PF_VFPF_INTX(1 ), ~0 ull);
otx2_write64(pf, RVU_MBOX_PF_VFPF1_INTX(1 ), ~0 ull);
}
for (intr_vec = RVU_MBOX_PF_INT_VEC_VFPF_MBOX0; intr_vec <=
RVU_MBOX_PF_INT_VEC_VFPF1_MBOX1; intr_vec++, vec++) {
vector = pci_irq_vector(pf->pdev, intr_vec);
free_irq(vector, pf->hw.pfvf_irq_devid[vec]);
}
}
irqreturn_t cn20k_pfvf_mbox_intr_handler(int irq, void *pf_irq)
{
struct pf_irq_data *irq_data = pf_irq;
struct otx2_nic *pf = irq_data->pf;
struct mbox *mbox;
u64 intr;
/* Sync with mbox memory region */
rmb();
/* Clear interrupts */
intr = otx2_read64(pf, irq_data->intr_status);
otx2_write64(pf, irq_data->intr_status, intr);
mbox = pf->mbox_pfvf;
if (intr)
trace_otx2_msg_interrupt(pf->pdev, "VF(s) to PF" , intr);
irq_data->pf_queue_work_hdlr(mbox, pf->mbox_pfvf_wq, irq_data->start,
irq_data->mdevs, intr);
return IRQ_HANDLED;
}
int cn20k_register_pfvf_mbox_intr(struct otx2_nic *pf, int numvfs)
{
struct otx2_hw *hw = &pf->hw;
struct pf_irq_data *irq_data;
int intr_vec, ret, vec = 0 ;
char *irq_name;
/* irq data for 4 PF intr vectors */
irq_data = devm_kcalloc(pf->dev, 4 ,
sizeof (struct pf_irq_data), GFP_KERNEL);
if (!irq_data)
return -ENOMEM;
for (intr_vec = RVU_MBOX_PF_INT_VEC_VFPF_MBOX0; intr_vec <=
RVU_MBOX_PF_INT_VEC_VFPF1_MBOX1; intr_vec++, vec++) {
switch (intr_vec) {
case RVU_MBOX_PF_INT_VEC_VFPF_MBOX0:
irq_data[vec].intr_status =
RVU_MBOX_PF_VFPF_INTX(0 );
irq_data[vec].start = 0 ;
irq_data[vec].mdevs = 64 ;
break ;
case RVU_MBOX_PF_INT_VEC_VFPF_MBOX1:
irq_data[vec].intr_status =
RVU_MBOX_PF_VFPF_INTX(1 );
irq_data[vec].start = 64 ;
irq_data[vec].mdevs = 96 ;
break ;
case RVU_MBOX_PF_INT_VEC_VFPF1_MBOX0:
irq_data[vec].intr_status =
RVU_MBOX_PF_VFPF1_INTX(0 );
irq_data[vec].start = 0 ;
irq_data[vec].mdevs = 64 ;
break ;
case RVU_MBOX_PF_INT_VEC_VFPF1_MBOX1:
irq_data[vec].intr_status =
RVU_MBOX_PF_VFPF1_INTX(1 );
irq_data[vec].start = 64 ;
irq_data[vec].mdevs = 96 ;
break ;
}
irq_data[vec].pf_queue_work_hdlr = otx2_queue_vf_work;
irq_data[vec].vec_num = intr_vec;
irq_data[vec].pf = pf;
/* Register mailbox interrupt handler */
irq_name = &hw->irq_name[intr_vec * NAME_SIZE];
if (pf->pcifunc)
snprintf(irq_name, NAME_SIZE,
"RVUPF%d_VF%d Mbox%d" , rvu_get_pf(pf->pdev,
pf->pcifunc), vec / 2 , vec % 2 );
else
snprintf(irq_name, NAME_SIZE, "RVUPF_VF%d Mbox%d" ,
vec / 2 , vec % 2 );
hw->pfvf_irq_devid[vec] = &irq_data[vec];
ret = request_irq(pci_irq_vector(pf->pdev, intr_vec),
pf->hw_ops->pfvf_mbox_intr_handler, 0 ,
irq_name,
&irq_data[vec]);
if (ret) {
dev_err(pf->dev,
"RVUPF: IRQ registration failed for PFVF mbox0 irq\n" );
return ret;
}
}
cn20k_enable_pfvf_mbox_intr(pf, numvfs);
return 0 ;
}
Messung V0.5 in Prozent C=95 H=91 G=92
¤ Dauer der Verarbeitung: 0.7 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland