root/sys/dev/qat/qat_hw/qat_4xxxvf/adf_4xxxvf_hw_data.c
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright(c) 2007-2026 Intel Corporation */
#include <adf_accel_devices.h>
#include <adf_cfg.h>
#include <adf_common_drv.h>
#include <adf_gen4vf_hw_csr_data.h>
#include <adf_gen4_pfvf.h>
#include <adf_pfvf_vf_msg.h>
#include "adf_4xxxvf_hw_data.h"
#include "icp_qat_hw.h"
#include "adf_transport_internal.h"
#include "adf_pfvf_vf_proto.h"

static struct adf_hw_device_class adf_4xxxiov_class =
    { .name = ADF_4XXXVF_DEVICE_NAME, .type = DEV_4XXXVF, .instances = 0 };

#define ADF_4XXXIOV_DEFAULT_RING_TO_SRV_MAP                                    \
        (ASYM | SYM << ADF_CFG_SERV_RING_PAIR_1_SHIFT |                        \
         ASYM << ADF_CFG_SERV_RING_PAIR_2_SHIFT |                              \
         SYM << ADF_CFG_SERV_RING_PAIR_3_SHIFT)

#define ADF_4XXXIOV_ASYM_SYM ADF_4XXXIOV_DEFAULT_RING_TO_SRV_MAP

#define ADF_4XXXIOV_DC                                                         \
        (COMP | COMP << ADF_CFG_SERV_RING_PAIR_1_SHIFT |                       \
         COMP << ADF_CFG_SERV_RING_PAIR_2_SHIFT |                              \
         COMP << ADF_CFG_SERV_RING_PAIR_3_SHIFT)

#define ADF_4XXXIOV_SYM                                                        \
        (SYM | SYM << ADF_CFG_SERV_RING_PAIR_1_SHIFT |                         \
         SYM << ADF_CFG_SERV_RING_PAIR_2_SHIFT |                               \
         SYM << ADF_CFG_SERV_RING_PAIR_3_SHIFT)

#define ADF_4XXXIOV_ASYM                                                       \
        (ASYM | ASYM << ADF_CFG_SERV_RING_PAIR_1_SHIFT |                       \
         ASYM << ADF_CFG_SERV_RING_PAIR_2_SHIFT |                              \
         ASYM << ADF_CFG_SERV_RING_PAIR_3_SHIFT)

#define ADF_4XXXIOV_ASYM_DC                                                    \
        (ASYM | ASYM << ADF_CFG_SERV_RING_PAIR_1_SHIFT |                       \
         COMP << ADF_CFG_SERV_RING_PAIR_2_SHIFT |                              \
         COMP << ADF_CFG_SERV_RING_PAIR_3_SHIFT)

#define ADF_4XXXIOV_SYM_DC                                                     \
        (SYM | SYM << ADF_CFG_SERV_RING_PAIR_1_SHIFT |                         \
         COMP << ADF_CFG_SERV_RING_PAIR_2_SHIFT |                              \
         COMP << ADF_CFG_SERV_RING_PAIR_3_SHIFT)

#define ADF_4XXXIOV_NA                                                         \
        (NA | NA << ADF_CFG_SERV_RING_PAIR_1_SHIFT |                           \
         NA << ADF_CFG_SERV_RING_PAIR_2_SHIFT |                                \
         NA << ADF_CFG_SERV_RING_PAIR_3_SHIFT)

struct adf_enabled_services {
        const char svcs_enabled[ADF_CFG_MAX_VAL_LEN_IN_BYTES];
        u16 rng_to_svc_msk;
};

static struct adf_enabled_services adf_4xxxiov_svcs[] = {
        { "dc", ADF_4XXXIOV_DC },
        { "sym", ADF_4XXXIOV_SYM },
        { "asym", ADF_4XXXIOV_ASYM },
        { "dc;asym", ADF_4XXXIOV_ASYM_DC },
        { "asym;dc", ADF_4XXXIOV_ASYM_DC },
        { "sym;dc", ADF_4XXXIOV_SYM_DC },
        { "dc;sym", ADF_4XXXIOV_SYM_DC },
        { "asym;sym", ADF_4XXXIOV_ASYM_SYM },
        { "sym;asym", ADF_4XXXIOV_ASYM_SYM }
};

static u32
get_accel_mask(struct adf_accel_dev *accel_dev)
{
        return ADF_4XXXIOV_ACCELERATORS_MASK;
}

static u64
get_ae_mask(struct adf_accel_dev *accel_dev)
{
        return ADF_4XXXIOV_ACCELENGINES_MASK;
}

static u32
get_num_accels(struct adf_hw_device_data *self)
{
        return ADF_4XXXIOV_MAX_ACCELERATORS;
}

static u32
get_num_aes(struct adf_hw_device_data *self)
{
        return ADF_4XXXIOV_MAX_ACCELENGINES;
}

static u32
get_misc_bar_id(struct adf_hw_device_data *self)
{
        return ADF_4XXXIOV_PMISC_BAR;
}

static u32
get_etr_bar_id(struct adf_hw_device_data *self)
{
        return ADF_4XXXIOV_ETR_BAR;
}

static u32
get_clock_speed(struct adf_hw_device_data *self)
{
        /* CPP clock is half high-speed clock */
        return self->clock_frequency / 2;
}

static enum dev_sku_info
get_sku(struct adf_hw_device_data *self)
{
        return DEV_SKU_VF;
}

static int
adf_vf_int_noop(struct adf_accel_dev *accel_dev)
{
        return 0;
}

static void
adf_vf_void_noop(struct adf_accel_dev *accel_dev)
{
}

u32
adf_4xxxvf_get_hw_cap(struct adf_accel_dev *accel_dev)
{
        device_t pdev = accel_dev->accel_pci_dev.pci_dev;
        u32 vffusectl1;
        u32 capabilities_sym, capabilities_sym_cipher, capabilities_sym_auth,
            capabilities_asym, capabilities_dc;

        /* Get fused capabilities */
        vffusectl1 = pci_read_config(pdev, ADF_4XXXIOV_VFFUSECTL1_OFFSET, 4);

        capabilities_sym_cipher = ICP_ACCEL_CAPABILITIES_HKDF |
            ICP_ACCEL_CAPABILITIES_SM4 | ICP_ACCEL_CAPABILITIES_CHACHA_POLY |
            ICP_ACCEL_CAPABILITIES_AESGCM_SPC | ICP_ACCEL_CAPABILITIES_AES_V2;
        capabilities_sym_auth = ICP_ACCEL_CAPABILITIES_SM3 |
            ICP_ACCEL_CAPABILITIES_SHA3 | ICP_ACCEL_CAPABILITIES_SHA3_EXT;

        /* A set bit in vffusectl1 means the feature is OFF in this SKU */
        if (vffusectl1 & ICP_ACCEL_4XXXVF_MASK_CIPHER_SLICE) {
                capabilities_sym_cipher &= ~ICP_ACCEL_CAPABILITIES_HKDF;
                capabilities_sym_cipher &= ~ICP_ACCEL_CAPABILITIES_SM4;
        }

        if (vffusectl1 & ICP_ACCEL_4XXXVF_MASK_UCS_SLICE) {
                capabilities_sym_cipher &= ~ICP_ACCEL_CAPABILITIES_CHACHA_POLY;
                capabilities_sym_cipher &= ~ICP_ACCEL_CAPABILITIES_AESGCM_SPC;
                capabilities_sym_cipher &= ~ICP_ACCEL_CAPABILITIES_AES_V2;
        }

        if (vffusectl1 & ICP_ACCEL_4XXXVF_MASK_AUTH_SLICE) {
                capabilities_sym_auth &= ~ICP_ACCEL_CAPABILITIES_SM3;
                capabilities_sym_auth &= ~ICP_ACCEL_CAPABILITIES_SHA3;
                capabilities_sym_auth &= ~ICP_ACCEL_CAPABILITIES_SHA3_EXT;
        }

        if (vffusectl1 & ICP_ACCEL_4XXXVF_MASK_SMX_SLICE) {
                capabilities_sym_cipher &= ~ICP_ACCEL_CAPABILITIES_SM4;
                capabilities_sym_auth &= ~ICP_ACCEL_CAPABILITIES_SM3;
        }

        if (capabilities_sym_cipher)
                capabilities_sym_cipher |= ICP_ACCEL_CAPABILITIES_CIPHER;

        if (capabilities_sym_auth)
                capabilities_sym_auth |= ICP_ACCEL_CAPABILITIES_AUTHENTICATION;

        capabilities_sym = capabilities_sym_cipher | capabilities_sym_auth;

        if (capabilities_sym)
                capabilities_sym |= ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC;

        capabilities_asym = ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC |
            ICP_ACCEL_CAPABILITIES_SM2 | ICP_ACCEL_CAPABILITIES_ECEDMONT;

        if (vffusectl1 & ICP_ACCEL_4XXXVF_MASK_PKE_SLICE) {
                capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC;
                capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_SM2;
                capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_ECEDMONT;
        }

        capabilities_dc = ICP_ACCEL_CAPABILITIES_COMPRESSION |
            ICP_ACCEL_CAPABILITIES_LZ4_COMPRESSION |
            ICP_ACCEL_CAPABILITIES_LZ4S_COMPRESSION |
            ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY64;

        if (vffusectl1 & ICP_ACCEL_4XXXVF_MASK_COMPRESS_SLICE) {
                capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_COMPRESSION;
                capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_LZ4_COMPRESSION;
                capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_LZ4S_COMPRESSION;
                capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY64;
        }

        return capabilities_sym | capabilities_dc | capabilities_asym;
}

static void
adf_set_asym_rings_mask(struct adf_accel_dev *accel_dev)
{
        accel_dev->hw_device->asym_rings_mask = ADF_4XXX_DEF_ASYM_MASK;
}

static void
enable_pf2vm_interrupt(struct adf_accel_dev *accel_dev)
{
        struct adf_hw_device_data *hw_data;
        struct adf_bar *pmisc;
        struct resource *pmisc_bar_addr;

        hw_data = accel_dev->hw_device;
        pmisc = &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
        pmisc_bar_addr = pmisc->virt_addr;

        ADF_CSR_WR(pmisc_bar_addr, ADF_4XXXIOV_VINTMSKPF2VM_OFFSET, 0x0);
}

static void
disable_pf2vm_interrupt(struct adf_accel_dev *accel_dev)
{
        struct adf_hw_device_data *hw_data;
        struct adf_bar *pmisc;
        struct resource *pmisc_bar_addr;

        hw_data = accel_dev->hw_device;
        pmisc = &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
        pmisc_bar_addr = pmisc->virt_addr;

        ADF_CSR_WR(pmisc_bar_addr, ADF_4XXXIOV_VINTMSKPF2VM_OFFSET, BIT(0));
}

static int
interrupt_active_pf2vm(struct adf_accel_dev *accel_dev)
{
        struct adf_hw_device_data *hw_data;
        struct adf_bar *pmisc;
        struct resource *pmisc_bar_addr;
        u32 v_sou, v_msk;

        hw_data = accel_dev->hw_device;
        pmisc = &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
        pmisc_bar_addr = pmisc->virt_addr;

        v_sou = ADF_CSR_RD(pmisc_bar_addr, ADF_4XXXIOV_VINTSOUPF2VM_OFFSET);
        v_msk = ADF_CSR_RD(pmisc_bar_addr, ADF_4XXXIOV_VINTMSKPF2VM_OFFSET);

        return ((v_sou & ~v_msk) & BIT(0)) ? 1 : 0;
}

static int
get_int_active_bundles(struct adf_accel_dev *accel_dev)
{
        struct adf_hw_device_data *hw_data;
        struct adf_bar *pmisc;
        struct resource *pmisc_bar_addr;
        u32 v_sou, v_msk;

        hw_data = accel_dev->hw_device;
        pmisc = &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];
        pmisc_bar_addr = pmisc->virt_addr;

        v_sou = ADF_CSR_RD(pmisc_bar_addr, ADF_4XXXIOV_VINTSOU_OFFSET);
        v_msk = ADF_CSR_RD(pmisc_bar_addr, ADF_4XXXIOV_VINTMSK_OFFSET);

        return v_sou & ~v_msk & 0xF;
}

static void
get_ring_svc_map_data(int ring_pair_index,
                      u16 ring_to_svc_map,
                      u8 *serv_type,
                      int *ring_index,
                      int *num_rings_per_srv,
                      int bank_num)
{
        *serv_type =
            GET_SRV_TYPE(ring_to_svc_map, bank_num % ADF_CFG_NUM_SERVICES);
        *ring_index = 0;
        *num_rings_per_srv = ADF_4XXXIOV_NUM_RINGS_PER_BANK / 2;
}

static int
get_ring_to_svc_map(struct adf_accel_dev *accel_dev, u16 *ring_to_svc_map)
{
        char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES];
        char val[ADF_CFG_MAX_KEY_LEN_IN_BYTES];
        u32 i = 0;

        if (accel_dev->hw_device->get_ring_to_svc_done)
                return 0;

        /* Get the services enabled by user if provided.
         * The function itself will also be called during the driver probe
         * procedure where no ServicesEnable is provided. Then the device
         * should still start with default configuration without
         * ServicesEnable. Hence it still returns 0 when the
         * adf_cfg_get_param_value() function returns failure.
         */
        snprintf(key, sizeof(key), ADF_SERVICES_ENABLED);
        if (adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, key, val))
                return 0;

        for (i = 0; i < ARRAY_SIZE(adf_4xxxiov_svcs); i++) {
                if (!strncmp(val,
                             adf_4xxxiov_svcs[i].svcs_enabled,
                             ADF_CFG_MAX_KEY_LEN_IN_BYTES)) {
                        *ring_to_svc_map = adf_4xxxiov_svcs[i].rng_to_svc_msk;
                        return 0;
                }
        }

        device_printf(GET_DEV(accel_dev),
                      "Invalid services enabled: %s\n",
                      val);
        return EFAULT;
}

static int
adf_4xxxvf_ring_pair_reset(struct adf_accel_dev *accel_dev, u32 bank_number)
{
        struct pfvf_message req = { 0 };
        unsigned long timeout = msecs_to_jiffies(ADF_PFVF_MSG_RESP_TIMEOUT);
        int ret = 0;

        if (bank_number >= accel_dev->hw_device->num_banks)
                return EINVAL;

        req.type = ADF_VF2PF_MSGTYPE_RP_RESET;
        req.data = bank_number;
        mutex_lock(&accel_dev->u1.vf.rpreset_lock);
        init_completion(&accel_dev->u1.vf.msg_received);
        accel_dev->u1.vf.rpreset_sts = RPRESET_SUCCESS;
        if (adf_send_vf2pf_msg(accel_dev, req)) {
                device_printf(GET_DEV(accel_dev),
                              "vf ring pair reset failure (vf2pf msg error)\n");
                ret = EFAULT;
                goto out;
        }
        if (!wait_for_completion_timeout(&accel_dev->u1.vf.msg_received,
                                         timeout)) {
                device_printf(
                    GET_DEV(accel_dev),
                    "vf ring pair reset failure (pf2vf msg timeout)\n");
                ret = EFAULT;
                goto out;
        }
        if (accel_dev->u1.vf.rpreset_sts != RPRESET_SUCCESS) {
                device_printf(
                    GET_DEV(accel_dev),
                    "vf ring pair reset failure (pf reports error)\n");
                ret = EFAULT;
                goto out;
        }

out:
        mutex_unlock(&accel_dev->u1.vf.rpreset_lock);
        return ret;
}

void
adf_init_hw_data_4xxxiov(struct adf_hw_device_data *hw_data)
{
        hw_data->dev_class = &adf_4xxxiov_class;
        hw_data->num_banks = ADF_4XXXIOV_ETR_MAX_BANKS;
        hw_data->num_rings_per_bank = ADF_4XXXIOV_NUM_RINGS_PER_BANK;
        hw_data->num_accel = ADF_4XXXIOV_MAX_ACCELERATORS;
        hw_data->num_logical_accel = 1;
        hw_data->num_engines = ADF_4XXXIOV_MAX_ACCELENGINES;
        hw_data->tx_rx_gap = ADF_4XXXIOV_RX_RINGS_OFFSET;
        hw_data->tx_rings_mask = ADF_4XXXIOV_TX_RINGS_MASK;
        hw_data->ring_to_svc_map = ADF_4XXXIOV_DEFAULT_RING_TO_SRV_MAP;
        hw_data->alloc_irq = adf_vf_isr_resource_alloc;
        hw_data->free_irq = adf_vf_isr_resource_free;
        hw_data->enable_error_correction = adf_vf_void_noop;
        hw_data->init_admin_comms = adf_vf_int_noop;
        hw_data->exit_admin_comms = adf_vf_void_noop;
        hw_data->send_admin_init = adf_vf2pf_notify_init;
        hw_data->init_arb = adf_vf_int_noop;
        hw_data->exit_arb = adf_vf_void_noop;
        hw_data->disable_iov = adf_vf2pf_notify_shutdown;
        hw_data->get_accel_mask = get_accel_mask;
        hw_data->get_ae_mask = get_ae_mask;
        hw_data->get_num_accels = get_num_accels;
        hw_data->get_num_aes = get_num_aes;
        hw_data->get_etr_bar_id = get_etr_bar_id;
        hw_data->get_misc_bar_id = get_misc_bar_id;
        hw_data->get_clock_speed = get_clock_speed;
        hw_data->get_sku = get_sku;
        hw_data->enable_ints = adf_vf_void_noop;
        hw_data->reset_device = adf_reset_flr;
        hw_data->restore_device = adf_dev_restore;
        hw_data->get_ring_svc_map_data = get_ring_svc_map_data;
        hw_data->get_ring_to_svc_map = get_ring_to_svc_map;
        hw_data->get_accel_cap = adf_4xxxvf_get_hw_cap;
        hw_data->config_device = adf_config_device;
        hw_data->set_asym_rings_mask = adf_set_asym_rings_mask;
        hw_data->ring_pair_reset = adf_4xxxvf_ring_pair_reset;
        hw_data->enable_pf2vf_interrupt = enable_pf2vm_interrupt;
        hw_data->disable_pf2vf_interrupt = disable_pf2vm_interrupt;
        hw_data->interrupt_active_pf2vf = interrupt_active_pf2vm;
        hw_data->get_int_active_bundles = get_int_active_bundles;
        hw_data->dev_class->instances++;
        adf_devmgr_update_class_index(hw_data);
        gen4vf_init_hw_csr_info(&hw_data->csr_info);
        adf_gen4_init_vf_pfvf_ops(&hw_data->csr_info.pfvf_ops);
}

void
adf_clean_hw_data_4xxxiov(struct adf_hw_device_data *hw_data)
{
        hw_data->dev_class->instances--;
        adf_devmgr_update_class_index(hw_data);
}