mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-05 20:30:41 +00:00

The RDMA driver needs to map its own MMIO regions for the sake of performance, meaning the IDPF needs to avoid mapping portions of the BAR space. However, to be HW agnostic, the IDPF cannot assume where these are and must avoid mapping hard coded regions as much as possible. The IDPF maps the bare minimum to load and communicate with the control plane, i.e., the mailbox registers and the reset state registers. Because of how and when mailbox register offsets are initialized, it is easier to adjust the existing defines to be relative to the mailbox region starting address. Use a specific mailbox register write function that uses these relative offsets. The reset state register addresses are calculated the same way as for other registers, described below. The IDPF then calls a new virtchnl op to fetch a list of MMIO regions that it should map. The addresses for the registers in these regions are calculated by determining what region the register resides in, adjusting the offset to be relative to that region, and then adding the register's offset to that region's mapped address. If the new virtchnl op is not supported, the IDPF will fallback to mapping the whole bar. However, it will still map them as separate regions outside the mailbox and reset state registers. This way we can use the same logic in both cases to access the MMIO space. Reviewed-by: Madhu Chittim <madhu.chittim@intel.com> Signed-off-by: Joshua Hay <joshua.a.hay@intel.com> Signed-off-by: Tatyana Nikolova <tatyana.e.nikolova@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
207 lines
6.3 KiB
C
207 lines
6.3 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/* Copyright (C) 2023 Intel Corporation */
|
|
|
|
#include "idpf.h"
|
|
#include "idpf_lan_pf_regs.h"
|
|
#include "idpf_virtchnl.h"
|
|
#include "idpf_ptp.h"
|
|
|
|
#define IDPF_PF_ITR_IDX_SPACING 0x4
|
|
|
|
/**
|
|
* idpf_ctlq_reg_init - initialize default mailbox registers
|
|
* @adapter: adapter structure
|
|
* @cq: pointer to the array of create control queues
|
|
*/
|
|
static void idpf_ctlq_reg_init(struct idpf_adapter *adapter,
|
|
struct idpf_ctlq_create_info *cq)
|
|
{
|
|
resource_size_t mbx_start = adapter->dev_ops.static_reg_info[0].start;
|
|
int i;
|
|
|
|
for (i = 0; i < IDPF_NUM_DFLT_MBX_Q; i++) {
|
|
struct idpf_ctlq_create_info *ccq = cq + i;
|
|
|
|
switch (ccq->type) {
|
|
case IDPF_CTLQ_TYPE_MAILBOX_TX:
|
|
/* set head and tail registers in our local struct */
|
|
ccq->reg.head = PF_FW_ATQH - mbx_start;
|
|
ccq->reg.tail = PF_FW_ATQT - mbx_start;
|
|
ccq->reg.len = PF_FW_ATQLEN - mbx_start;
|
|
ccq->reg.bah = PF_FW_ATQBAH - mbx_start;
|
|
ccq->reg.bal = PF_FW_ATQBAL - mbx_start;
|
|
ccq->reg.len_mask = PF_FW_ATQLEN_ATQLEN_M;
|
|
ccq->reg.len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M;
|
|
ccq->reg.head_mask = PF_FW_ATQH_ATQH_M;
|
|
break;
|
|
case IDPF_CTLQ_TYPE_MAILBOX_RX:
|
|
/* set head and tail registers in our local struct */
|
|
ccq->reg.head = PF_FW_ARQH - mbx_start;
|
|
ccq->reg.tail = PF_FW_ARQT - mbx_start;
|
|
ccq->reg.len = PF_FW_ARQLEN - mbx_start;
|
|
ccq->reg.bah = PF_FW_ARQBAH - mbx_start;
|
|
ccq->reg.bal = PF_FW_ARQBAL - mbx_start;
|
|
ccq->reg.len_mask = PF_FW_ARQLEN_ARQLEN_M;
|
|
ccq->reg.len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M;
|
|
ccq->reg.head_mask = PF_FW_ARQH_ARQH_M;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* idpf_mb_intr_reg_init - Initialize mailbox interrupt register
|
|
* @adapter: adapter structure
|
|
*/
|
|
static void idpf_mb_intr_reg_init(struct idpf_adapter *adapter)
|
|
{
|
|
struct idpf_intr_reg *intr = &adapter->mb_vector.intr_reg;
|
|
u32 dyn_ctl = le32_to_cpu(adapter->caps.mailbox_dyn_ctl);
|
|
|
|
intr->dyn_ctl = idpf_get_reg_addr(adapter, dyn_ctl);
|
|
intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
|
|
intr->dyn_ctl_itridx_m = PF_GLINT_DYN_CTL_ITR_INDX_M;
|
|
intr->icr_ena = idpf_get_reg_addr(adapter, PF_INT_DIR_OICR_ENA);
|
|
intr->icr_ena_ctlq_m = PF_INT_DIR_OICR_ENA_M;
|
|
}
|
|
|
|
/**
|
|
* idpf_intr_reg_init - Initialize interrupt registers
|
|
* @vport: virtual port structure
|
|
*/
|
|
static int idpf_intr_reg_init(struct idpf_vport *vport)
|
|
{
|
|
struct idpf_adapter *adapter = vport->adapter;
|
|
int num_vecs = vport->num_q_vectors;
|
|
struct idpf_vec_regs *reg_vals;
|
|
int num_regs, i, err = 0;
|
|
u32 rx_itr, tx_itr;
|
|
u16 total_vecs;
|
|
|
|
total_vecs = idpf_get_reserved_vecs(vport->adapter);
|
|
reg_vals = kcalloc(total_vecs, sizeof(struct idpf_vec_regs),
|
|
GFP_KERNEL);
|
|
if (!reg_vals)
|
|
return -ENOMEM;
|
|
|
|
num_regs = idpf_get_reg_intr_vecs(vport, reg_vals);
|
|
if (num_regs < num_vecs) {
|
|
err = -EINVAL;
|
|
goto free_reg_vals;
|
|
}
|
|
|
|
for (i = 0; i < num_vecs; i++) {
|
|
struct idpf_q_vector *q_vector = &vport->q_vectors[i];
|
|
u16 vec_id = vport->q_vector_idxs[i] - IDPF_MBX_Q_VEC;
|
|
struct idpf_intr_reg *intr = &q_vector->intr_reg;
|
|
u32 spacing;
|
|
|
|
intr->dyn_ctl = idpf_get_reg_addr(adapter,
|
|
reg_vals[vec_id].dyn_ctl_reg);
|
|
intr->dyn_ctl_intena_m = PF_GLINT_DYN_CTL_INTENA_M;
|
|
intr->dyn_ctl_intena_msk_m = PF_GLINT_DYN_CTL_INTENA_MSK_M;
|
|
intr->dyn_ctl_itridx_s = PF_GLINT_DYN_CTL_ITR_INDX_S;
|
|
intr->dyn_ctl_intrvl_s = PF_GLINT_DYN_CTL_INTERVAL_S;
|
|
intr->dyn_ctl_wb_on_itr_m = PF_GLINT_DYN_CTL_WB_ON_ITR_M;
|
|
intr->dyn_ctl_swint_trig_m = PF_GLINT_DYN_CTL_SWINT_TRIG_M;
|
|
intr->dyn_ctl_sw_itridx_ena_m =
|
|
PF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_M;
|
|
|
|
spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing,
|
|
IDPF_PF_ITR_IDX_SPACING);
|
|
rx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_0,
|
|
reg_vals[vec_id].itrn_reg,
|
|
spacing);
|
|
tx_itr = PF_GLINT_ITR_ADDR(VIRTCHNL2_ITR_IDX_1,
|
|
reg_vals[vec_id].itrn_reg,
|
|
spacing);
|
|
intr->rx_itr = idpf_get_reg_addr(adapter, rx_itr);
|
|
intr->tx_itr = idpf_get_reg_addr(adapter, tx_itr);
|
|
}
|
|
|
|
free_reg_vals:
|
|
kfree(reg_vals);
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* idpf_reset_reg_init - Initialize reset registers
|
|
* @adapter: Driver specific private structure
|
|
*/
|
|
static void idpf_reset_reg_init(struct idpf_adapter *adapter)
|
|
{
|
|
adapter->reset_reg.rstat = idpf_get_rstat_reg_addr(adapter, PFGEN_RSTAT);
|
|
adapter->reset_reg.rstat_m = PFGEN_RSTAT_PFR_STATE_M;
|
|
}
|
|
|
|
/**
|
|
* idpf_trigger_reset - trigger reset
|
|
* @adapter: Driver specific private structure
|
|
* @trig_cause: Reason to trigger a reset
|
|
*/
|
|
static void idpf_trigger_reset(struct idpf_adapter *adapter,
|
|
enum idpf_flags __always_unused trig_cause)
|
|
{
|
|
u32 reset_reg;
|
|
|
|
reset_reg = readl(idpf_get_rstat_reg_addr(adapter, PFGEN_CTRL));
|
|
writel(reset_reg | PFGEN_CTRL_PFSWR,
|
|
idpf_get_rstat_reg_addr(adapter, PFGEN_CTRL));
|
|
}
|
|
|
|
/**
|
|
* idpf_ptp_reg_init - Initialize required registers
|
|
* @adapter: Driver specific private structure
|
|
*
|
|
* Set the bits required for enabling shtime and cmd execution
|
|
*/
|
|
static void idpf_ptp_reg_init(const struct idpf_adapter *adapter)
|
|
{
|
|
adapter->ptp->cmd.shtime_enable_mask = PF_GLTSYN_CMD_SYNC_SHTIME_EN_M;
|
|
adapter->ptp->cmd.exec_cmd_mask = PF_GLTSYN_CMD_SYNC_EXEC_CMD_M;
|
|
}
|
|
|
|
/**
|
|
* idpf_idc_register - register for IDC callbacks
|
|
* @adapter: Driver specific private structure
|
|
*
|
|
* Return: 0 on success or error code on failure.
|
|
*/
|
|
static int idpf_idc_register(struct idpf_adapter *adapter)
|
|
{
|
|
return idpf_idc_init_aux_core_dev(adapter, IIDC_FUNCTION_TYPE_PF);
|
|
}
|
|
|
|
/**
|
|
* idpf_reg_ops_init - Initialize register API function pointers
|
|
* @adapter: Driver specific private structure
|
|
*/
|
|
static void idpf_reg_ops_init(struct idpf_adapter *adapter)
|
|
{
|
|
adapter->dev_ops.reg_ops.ctlq_reg_init = idpf_ctlq_reg_init;
|
|
adapter->dev_ops.reg_ops.intr_reg_init = idpf_intr_reg_init;
|
|
adapter->dev_ops.reg_ops.mb_intr_reg_init = idpf_mb_intr_reg_init;
|
|
adapter->dev_ops.reg_ops.reset_reg_init = idpf_reset_reg_init;
|
|
adapter->dev_ops.reg_ops.trigger_reset = idpf_trigger_reset;
|
|
adapter->dev_ops.reg_ops.ptp_reg_init = idpf_ptp_reg_init;
|
|
}
|
|
|
|
/**
|
|
* idpf_dev_ops_init - Initialize device API function pointers
|
|
* @adapter: Driver specific private structure
|
|
*/
|
|
void idpf_dev_ops_init(struct idpf_adapter *adapter)
|
|
{
|
|
idpf_reg_ops_init(adapter);
|
|
|
|
adapter->dev_ops.idc_init = idpf_idc_register;
|
|
|
|
resource_set_range(&adapter->dev_ops.static_reg_info[0],
|
|
PF_FW_BASE, IDPF_PF_MBX_REGION_SZ);
|
|
resource_set_range(&adapter->dev_ops.static_reg_info[1],
|
|
PFGEN_RTRIG, IDPF_PF_RSTAT_REGION_SZ);
|
|
}
|