Commit d9fb8408 authored by Damian Muszynski's avatar Damian Muszynski Committed by Herbert Xu
Browse files

crypto: qat - add rate limiting feature to qat_4xxx



The Rate Limiting (RL) feature allows to control the rate of requests
that can be submitted on a ring pair (RP). This allows sharing a QAT
device among multiple users while ensuring a guaranteed throughput.

The driver provides a mechanism that allows users to set policies, that
are programmed to the device. The device is then enforcing those policies.

Configuration of RL is accomplished through entities called SLAs
(Service Level Agreement). Each SLA object gets a unique identifier
and defines the limitations for a single service across up to four
ring pairs (RPs count allocated to a single VF).

The rate is determined using two fields:
  * CIR (Committed Information Rate), i.e., the guaranteed rate.
  * PIR (Peak Information Rate), i.e., the maximum rate achievable
    when the device has available resources.
The rate values are expressed in permille scale i.e. 0-1000.
Ring pair selection is achieved by providing a 64-bit mask, where
each bit corresponds to one of the ring pairs.

This adds an interface and logic that allow to add, update, retrieve
and remove an SLA.

Signed-off-by: default avatarDamian Muszynski <damian.muszynski@intel.com>
Reviewed-by: default avatarGiovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: default avatarTero Kristo <tero.kristo@linux.intel.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent c7fd5379
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -343,6 +343,24 @@ static u32 get_heartbeat_clock(struct adf_hw_device_data *self)
	return ADF_4XXX_KPT_COUNTER_FREQ;
}

static void adf_init_rl_data(struct adf_rl_hw_data *rl_data)
{
	rl_data->pciout_tb_offset = ADF_GEN4_RL_TOKEN_PCIEOUT_BUCKET_OFFSET;
	rl_data->pciin_tb_offset = ADF_GEN4_RL_TOKEN_PCIEIN_BUCKET_OFFSET;
	rl_data->r2l_offset = ADF_GEN4_RL_R2L_OFFSET;
	rl_data->l2c_offset = ADF_GEN4_RL_L2C_OFFSET;
	rl_data->c2s_offset = ADF_GEN4_RL_C2S_OFFSET;

	rl_data->pcie_scale_div = ADF_4XXX_RL_PCIE_SCALE_FACTOR_DIV;
	rl_data->pcie_scale_mul = ADF_4XXX_RL_PCIE_SCALE_FACTOR_MUL;
	rl_data->dcpr_correction = ADF_4XXX_RL_DCPR_CORRECTION;
	rl_data->max_tp[ADF_SVC_ASYM] = ADF_4XXX_RL_MAX_TP_ASYM;
	rl_data->max_tp[ADF_SVC_SYM] = ADF_4XXX_RL_MAX_TP_SYM;
	rl_data->max_tp[ADF_SVC_DC] = ADF_4XXX_RL_MAX_TP_DC;
	rl_data->scan_interval = ADF_4XXX_RL_SCANS_PER_SEC;
	rl_data->scale_ref = ADF_4XXX_RL_SLICE_REF;
}

static void adf_enable_error_correction(struct adf_accel_dev *accel_dev)
{
	struct adf_bar *misc_bar = &GET_BARS(accel_dev)[ADF_4XXX_PMISC_BAR];
@@ -594,12 +612,14 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id)
	hw_data->stop_timer = adf_gen4_timer_stop;
	hw_data->get_hb_clock = get_heartbeat_clock;
	hw_data->num_hb_ctrs = ADF_NUM_HB_CNT_PER_AE;
	hw_data->clock_frequency = ADF_4XXX_AE_FREQ;

	adf_gen4_set_err_mask(&hw_data->dev_err_mask);
	adf_gen4_init_hw_csr_ops(&hw_data->csr_ops);
	adf_gen4_init_pf_pfvf_ops(&hw_data->pfvf_ops);
	adf_gen4_init_dc_ops(&hw_data->dc_ops);
	adf_gen4_init_ras_ops(&hw_data->ras_ops);
	adf_init_rl_data(&hw_data->rl_data);
}

void adf_clean_hw_data_4xxx(struct adf_hw_device_data *hw_data)
+12 −1
Original line number Diff line number Diff line
@@ -82,8 +82,19 @@
#define ADF_402XX_ASYM_OBJ	"qat_402xx_asym.bin"
#define ADF_402XX_ADMIN_OBJ	"qat_402xx_admin.bin"

/* RL constants */
#define ADF_4XXX_RL_PCIE_SCALE_FACTOR_DIV	100
#define ADF_4XXX_RL_PCIE_SCALE_FACTOR_MUL	102
#define ADF_4XXX_RL_DCPR_CORRECTION		1
#define ADF_4XXX_RL_SCANS_PER_SEC		954
#define ADF_4XXX_RL_MAX_TP_ASYM			173750UL
#define ADF_4XXX_RL_MAX_TP_SYM			95000UL
#define ADF_4XXX_RL_MAX_TP_DC			45000UL
#define ADF_4XXX_RL_SLICE_REF			1000UL

/* Clocks frequency */
#define ADF_4XXX_KPT_COUNTER_FREQ	(100 * HZ_PER_MHZ)
#define ADF_4XXX_AE_FREQ		(1000 * HZ_PER_MHZ)

/* qat_4xxx fuse bits are different from old GENs, redefine them */
enum icp_qat_4xxx_slice_mask {
+2 −0
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ intel_qat-objs := adf_cfg.o \
	qat_algs.o \
	qat_asym_algs.o \
	qat_algs_send.o \
	adf_rl.o \
	adf_rl_admin.o \
	qat_uclo.o \
	qat_hal.o \
	qat_bl.o
+3 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <linux/ratelimit.h>
#include <linux/types.h>
#include "adf_cfg_common.h"
#include "adf_rl.h"
#include "adf_pfvf_msg.h"

#define ADF_DH895XCC_DEVICE_NAME "dh895xcc"
@@ -247,6 +248,7 @@ struct adf_hw_device_data {
	struct adf_dc_ops dc_ops;
	struct adf_ras_ops ras_ops;
	struct adf_dev_err_mask dev_err_mask;
	struct adf_rl_hw_data rl_data;
	const char *fw_name;
	const char *fw_mmp_name;
	u32 fuses;
@@ -358,6 +360,7 @@ struct adf_accel_dev {
	struct adf_accel_pci accel_pci_dev;
	struct adf_timer *timer;
	struct adf_heartbeat *heartbeat;
	struct adf_rl *rate_limiting;
	union {
		struct {
			/* protects VF2PF interrupts access */
+47 −0
Original line number Diff line number Diff line
@@ -330,6 +330,53 @@ static int adf_get_fw_capabilities(struct adf_accel_dev *accel_dev, u16 *caps)
	return 0;
}

int adf_send_admin_rl_init(struct adf_accel_dev *accel_dev,
			   struct icp_qat_fw_init_admin_slice_cnt *slices)
{
	u32 ae_mask = accel_dev->hw_device->admin_ae_mask;
	struct icp_qat_fw_init_admin_resp resp = { };
	struct icp_qat_fw_init_admin_req req = { };
	int ret;

	req.cmd_id = ICP_QAT_FW_RL_INIT;

	ret = adf_send_admin(accel_dev, &req, &resp, ae_mask);
	if (ret)
		return ret;

	memcpy(slices, &resp.slices, sizeof(*slices));

	return 0;
}

int adf_send_admin_rl_add_update(struct adf_accel_dev *accel_dev,
				 struct icp_qat_fw_init_admin_req *req)
{
	u32 ae_mask = accel_dev->hw_device->admin_ae_mask;
	struct icp_qat_fw_init_admin_resp resp = { };

	/*
	 * req struct filled in rl implementation. Used commands
	 * ICP_QAT_FW_RL_ADD for a new SLA
	 * ICP_QAT_FW_RL_UPDATE for update SLA
	 */
	return adf_send_admin(accel_dev, req, &resp, ae_mask);
}

int adf_send_admin_rl_delete(struct adf_accel_dev *accel_dev, u16 node_id,
			     u8 node_type)
{
	u32 ae_mask = accel_dev->hw_device->admin_ae_mask;
	struct icp_qat_fw_init_admin_resp resp = { };
	struct icp_qat_fw_init_admin_req req = { };

	req.cmd_id = ICP_QAT_FW_RL_REMOVE;
	req.node_id = node_id;
	req.node_type = node_type;

	return adf_send_admin(accel_dev, &req, &resp, ae_mask);
}

/**
 * adf_send_admin_init() - Function sends init message to FW
 * @accel_dev: Pointer to acceleration device.
Loading