root/sys/dev/qat/qat_hw/qat_c4xxx/adf_c4xxx_res_part.c
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright(c) 2007-2022 Intel Corporation */
#include "adf_accel_devices.h"
#include "adf_common_drv.h"
#include "adf_cfg_common.h"
#include "adf_transport_internal.h"
#include "icp_qat_hw.h"
#include "adf_c4xxx_hw_data.h"

#define ADF_C4XXX_PARTTITION_SHIFT 8
#define ADF_C4XXX_PARTITION(svc, ring)                                         \
        ((svc) << ((ring)*ADF_C4XXX_PARTTITION_SHIFT))

static void
adf_get_partitions_mask(struct adf_accel_dev *accel_dev, u32 *partitions_mask)
{
        device_t dev = accel_to_pci_dev(accel_dev);
        u32 enabled_partitions_msk = 0;
        u8 ring_pair = 0;
        enum adf_cfg_service_type serv_type = 0;
        u16 ring_to_svc_map = accel_dev->hw_device->ring_to_svc_map;

        for (ring_pair = 0; ring_pair < ADF_CFG_NUM_SERVICES; ring_pair++) {
                serv_type = GET_SRV_TYPE(ring_to_svc_map, ring_pair);
                switch (serv_type) {
                case CRYPTO: {
                        enabled_partitions_msk |=
                            ADF_C4XXX_PARTITION(ADF_C4XXX_PART_ASYM,
                                                ring_pair++);
                        if (ring_pair < ADF_CFG_NUM_SERVICES)
                                enabled_partitions_msk |=
                                    ADF_C4XXX_PARTITION(ADF_C4XXX_PART_SYM,
                                                        ring_pair);
                        else
                                device_printf(
                                    dev, "Failed to enable SYM partition.\n");
                        break;
                }
                case COMP:
                        enabled_partitions_msk |=
                            ADF_C4XXX_PARTITION(ADF_C4XXX_PART_DC, ring_pair);
                        break;
                case SYM:
                        enabled_partitions_msk |=
                            ADF_C4XXX_PARTITION(ADF_C4XXX_PART_SYM, ring_pair);
                        break;
                case ASYM:
                        enabled_partitions_msk |=
                            ADF_C4XXX_PARTITION(ADF_C4XXX_PART_ASYM, ring_pair);
                        break;
                default:
                        enabled_partitions_msk |=
                            ADF_C4XXX_PARTITION(ADF_C4XXX_PART_UNUSED,
                                                ring_pair);
                        break;
                }
        }
        *partitions_mask = enabled_partitions_msk;
}

static void
adf_enable_sym_threads(struct adf_accel_dev *accel_dev, u32 ae, u32 partition)
{
        struct resource *csr = accel_dev->transport->banks[0].csr_addr;
        const struct adf_ae_info *ae_info = accel_dev->au_info->ae_info;
        u32 num_sym_thds = ae_info[ae].num_sym_thd;
        u32 i;
        u32 part_group = partition / ADF_C4XXX_PARTS_PER_GRP;
        u32 wkrthd2_partmap = part_group << ADF_C4XXX_PARTS_PER_GRP |
            (BIT(partition % ADF_C4XXX_PARTS_PER_GRP));

        for (i = 0; i < num_sym_thds; i++)
                WRITE_CSR_WQM(csr,
                              ADF_C4XXX_WRKTHD2PARTMAP,
                              (ae * ADF_NUM_THREADS_PER_AE + i),
                              wkrthd2_partmap);
}

static void
adf_enable_asym_threads(struct adf_accel_dev *accel_dev, u32 ae, u32 partition)
{
        struct resource *csr = accel_dev->transport->banks[0].csr_addr;
        const struct adf_ae_info *ae_info = accel_dev->au_info->ae_info;
        u32 num_asym_thds = ae_info[ae].num_asym_thd;
        u32 i;
        u32 part_group = partition / ADF_C4XXX_PARTS_PER_GRP;
        u32 wkrthd2_partmap = part_group << ADF_C4XXX_PARTS_PER_GRP |
            (BIT(partition % ADF_C4XXX_PARTS_PER_GRP));
        /* For asymmetric cryptography SKU we have one thread less */
        u32 num_all_thds = ADF_NUM_THREADS_PER_AE - 2;

        for (i = num_all_thds; i > (num_all_thds - num_asym_thds); i--)
                WRITE_CSR_WQM(csr,
                              ADF_C4XXX_WRKTHD2PARTMAP,
                              (ae * ADF_NUM_THREADS_PER_AE + i),
                              wkrthd2_partmap);
}

static void
adf_enable_dc_threads(struct adf_accel_dev *accel_dev, u32 ae, u32 partition)
{
        struct resource *csr = accel_dev->transport->banks[0].csr_addr;
        const struct adf_ae_info *ae_info = accel_dev->au_info->ae_info;
        u32 num_dc_thds = ae_info[ae].num_dc_thd;
        u32 i;
        u32 part_group = partition / ADF_C4XXX_PARTS_PER_GRP;
        u32 wkrthd2_partmap = part_group << ADF_C4XXX_PARTS_PER_GRP |
            (BIT(partition % ADF_C4XXX_PARTS_PER_GRP));

        for (i = 0; i < num_dc_thds; i++)
                WRITE_CSR_WQM(csr,
                              ADF_C4XXX_WRKTHD2PARTMAP,
                              (ae * ADF_NUM_THREADS_PER_AE + i),
                              wkrthd2_partmap);
}

/* Initialise Resource partitioning.
 * Initialise a default set of 4 partitions to arbitrate
 * request rings per bundle.
 */
int
adf_init_arb_c4xxx(struct adf_accel_dev *accel_dev)
{
        struct adf_hw_device_data *hw_data = accel_dev->hw_device;
        struct resource *csr = accel_dev->transport->banks[0].csr_addr;
        struct adf_accel_unit_info *au_info = accel_dev->au_info;
        u32 i;
        unsigned long ae_mask;
        u32 partitions_mask = 0;

        /* invoke common adf_init_arb */
        adf_init_arb(accel_dev);

        adf_get_partitions_mask(accel_dev, &partitions_mask);
        for (i = 0; i < hw_data->num_banks; i++)
                WRITE_CSR_WQM(csr,
                              ADF_C4XXX_PARTITION_LUT_OFFSET,
                              i,
                              partitions_mask);

        ae_mask = hw_data->ae_mask;

        /* Assigning default partitions to accel engine
         * worker threads
         */
        for_each_set_bit(i, &ae_mask, ADF_C4XXX_MAX_ACCELENGINES)
        {
                if (BIT(i) & au_info->sym_ae_msk)
                        adf_enable_sym_threads(accel_dev,
                                               i,
                                               ADF_C4XXX_PART_SYM);
                if (BIT(i) & au_info->asym_ae_msk)
                        adf_enable_asym_threads(accel_dev,
                                                i,
                                                ADF_C4XXX_PART_ASYM);
                if (BIT(i) & au_info->dc_ae_msk)
                        adf_enable_dc_threads(accel_dev, i, ADF_C4XXX_PART_DC);
        }

        return 0;
}

/* Disable the resource partitioning feature
 * and restore the default partitioning scheme
 */
void
adf_exit_arb_c4xxx(struct adf_accel_dev *accel_dev)
{
        struct adf_hw_device_data *hw_data = accel_dev->hw_device;
        struct resource *csr;
        u32 i;
        unsigned long ae_mask;

        if (!accel_dev->transport)
                return;
        csr = accel_dev->transport->banks[0].csr_addr;

        /* Restore the default partitionLUT registers */
        for (i = 0; i < hw_data->num_banks; i++)
                WRITE_CSR_WQM(csr,
                              ADF_C4XXX_PARTITION_LUT_OFFSET,
                              i,
                              ADF_C4XXX_DEFAULT_PARTITIONS);

        ae_mask = hw_data->ae_mask;

        /* Reset worker thread to partition mapping */
        for (i = 0; i < hw_data->num_engines * ADF_NUM_THREADS_PER_AE; i++) {
                if (!test_bit((u32)(i / ADF_NUM_THREADS_PER_AE), &ae_mask))
                        continue;

                WRITE_CSR_WQM(csr, ADF_C4XXX_WRKTHD2PARTMAP, i, 0);
        }
}