root/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c
// SPDX-License-Identifier: GPL-2.0
/* Marvell RVU Admin Function driver
 *
 * Copyright (C) 2021 Marvell.
 *
 */

#include <linux/pci.h>
#include "rvu.h"

/* SDP PF device id */
#define PCI_DEVID_OTX2_SDP_PF   0xA0F6

/* Maximum SDP blocks in a chip */
#define MAX_SDP         2

/* SDP PF number */
static int sdp_pf_num[MAX_SDP] = {-1, -1};

bool is_sdp_pfvf(struct rvu *rvu, u16 pcifunc)
{
        u16 pf = rvu_get_pf(rvu->pdev, pcifunc);
        u32 found = 0, i = 0;

        while (i < MAX_SDP) {
                if (pf == sdp_pf_num[i])
                        found = 1;
                i++;
        }

        if (!found)
                return false;

        return true;
}

bool is_sdp_pf(struct rvu *rvu, u16 pcifunc)
{
        return (is_sdp_pfvf(rvu, pcifunc) &&
                !(pcifunc & RVU_PFVF_FUNC_MASK));
}

#define RVU_SDP_VF_DEVID        0xA0F7
bool is_sdp_vf(struct rvu *rvu, u16 pcifunc)
{
        if (!(pcifunc & ~RVU_PFVF_FUNC_MASK))
                return (rvu->vf_devid == RVU_SDP_VF_DEVID);

        return (is_sdp_pfvf(rvu, pcifunc) &&
                !!(pcifunc & RVU_PFVF_FUNC_MASK));
}

int rvu_sdp_init(struct rvu *rvu)
{
        struct pci_dev *pdev = NULL;
        struct rvu_pfvf *pfvf;
        u32 i = 0;

        if (rvu->fwdata && rvu->fwdata->channel_data.valid) {
                sdp_pf_num[0] = 0;
                pfvf = &rvu->pf[sdp_pf_num[0]];
                pfvf->sdp_info = &rvu->fwdata->channel_data.info;

                return 0;
        }

        while ((i < MAX_SDP) && (pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
                                                       PCI_DEVID_OTX2_SDP_PF,
                                                       pdev)) != NULL) {
                /* The RVU PF number is one less than bus number */
                sdp_pf_num[i] = pdev->bus->number - 1;
                pfvf = &rvu->pf[sdp_pf_num[i]];

                pfvf->sdp_info = devm_kzalloc(rvu->dev,
                                              sizeof(struct sdp_node_info),
                                              GFP_KERNEL);
                if (!pfvf->sdp_info) {
                        pci_dev_put(pdev);
                        return -ENOMEM;
                }

                dev_info(rvu->dev, "SDP PF number:%d\n", sdp_pf_num[i]);

                i++;
        }

        pci_dev_put(pdev);

        return 0;
}

int
rvu_mbox_handler_set_sdp_chan_info(struct rvu *rvu,
                                   struct sdp_chan_info_msg *req,
                                   struct msg_rsp *rsp)
{
        struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);

        memcpy(pfvf->sdp_info, &req->info, sizeof(struct sdp_node_info));
        dev_info(rvu->dev, "AF: SDP%d max_vfs %d num_pf_rings %d pf_srn %d\n",
                 req->info.node_id, req->info.max_vfs, req->info.num_pf_rings,
                 req->info.pf_srn);
        return 0;
}

int
rvu_mbox_handler_get_sdp_chan_info(struct rvu *rvu, struct msg_req *req,
                                   struct sdp_get_chan_info_msg *rsp)
{
        struct rvu_hwinfo *hw = rvu->hw;
        int blkaddr;

        if (!hw->cap.programmable_chans) {
                rsp->chan_base = NIX_CHAN_SDP_CH_START;
                rsp->num_chan = NIX_CHAN_SDP_NUM_CHANS;
        } else {
                blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0);
                rsp->chan_base = hw->sdp_chan_base;
                rsp->num_chan = rvu_read64(rvu, blkaddr, NIX_AF_CONST1) & 0xFFFUL;
        }

        return 0;
}