Commit 6aa53e86 authored by Joshua Hay's avatar Joshua Hay Committed by Tony Nguyen
Browse files

idpf: implement get LAN MMIO memory regions



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: default avatarMadhu Chittim <madhu.chittim@intel.com>
Signed-off-by: default avatarJoshua Hay <joshua.a.hay@intel.com>
Signed-off-by: default avatarTatyana Nikolova <tatyana.e.nikolova@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent ed6e1c87
Loading
Loading
Loading
Loading
+66 −3
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ struct idpf_vport_max_q;
#include <net/pkt_sched.h>
#include <linux/aer.h>
#include <linux/etherdevice.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/bitfield.h>
#include <linux/sctp.h>
@@ -197,7 +198,8 @@ struct idpf_vport_max_q {
 * @ptp_reg_init: PTP register initialization
 */
struct idpf_reg_ops {
	void (*ctlq_reg_init)(struct idpf_ctlq_create_info *cq);
	void (*ctlq_reg_init)(struct idpf_adapter *adapter,
			      struct idpf_ctlq_create_info *cq);
	int (*intr_reg_init)(struct idpf_vport *vport);
	void (*mb_intr_reg_init)(struct idpf_adapter *adapter);
	void (*reset_reg_init)(struct idpf_adapter *adapter);
@@ -206,15 +208,25 @@ struct idpf_reg_ops {
	void (*ptp_reg_init)(const struct idpf_adapter *adapter);
};

#define IDPF_MMIO_REG_NUM_STATIC	2
#define IDPF_PF_MBX_REGION_SZ		4096
#define IDPF_PF_RSTAT_REGION_SZ		2048
#define IDPF_VF_MBX_REGION_SZ		10240
#define IDPF_VF_RSTAT_REGION_SZ		2048

/**
 * struct idpf_dev_ops - Device specific operations
 * @reg_ops: Register operations
 * @idc_init: IDC initialization
 * @static_reg_info: array of mailbox and rstat register info
 */
struct idpf_dev_ops {
	struct idpf_reg_ops reg_ops;

	int (*idc_init)(struct idpf_adapter *adapter);

	/* static_reg_info[0] is mailbox region, static_reg_info[1] is rstat */
	struct resource static_reg_info[IDPF_MMIO_REG_NUM_STATIC];
};

/**
@@ -755,6 +767,34 @@ static inline u8 idpf_get_min_tx_pkt_len(struct idpf_adapter *adapter)
	return pkt_len ? pkt_len : IDPF_TX_MIN_PKT_LEN;
}

/**
 * idpf_get_mbx_reg_addr - Get BAR0 mailbox register address
 * @adapter: private data struct
 * @reg_offset: register offset value
 *
 * Return: BAR0 mailbox register address based on register offset.
 */
static inline void __iomem *idpf_get_mbx_reg_addr(struct idpf_adapter *adapter,
						  resource_size_t reg_offset)
{
	return adapter->hw.mbx.vaddr + reg_offset;
}

/**
 * idpf_get_rstat_reg_addr - Get BAR0 rstat register address
 * @adapter: private data struct
 * @reg_offset: register offset value
 *
 * Return: BAR0 rstat register address based on register offset.
 */
static inline void __iomem *idpf_get_rstat_reg_addr(struct idpf_adapter *adapter,
						    resource_size_t reg_offset)
{
	reg_offset -= adapter->dev_ops.static_reg_info[1].start;

	return adapter->hw.rstat.vaddr + reg_offset;
}

/**
 * idpf_get_reg_addr - Get BAR0 register address
 * @adapter: private data struct
@@ -765,7 +805,30 @@ static inline u8 idpf_get_min_tx_pkt_len(struct idpf_adapter *adapter)
static inline void __iomem *idpf_get_reg_addr(struct idpf_adapter *adapter,
					      resource_size_t reg_offset)
{
	return (void __iomem *)(adapter->hw.hw_addr + reg_offset);
	struct idpf_hw *hw = &adapter->hw;

	for (int i = 0; i < hw->num_lan_regs; i++) {
		struct idpf_mmio_reg *region = &hw->lan_regs[i];

		if (reg_offset >= region->addr_start &&
		    reg_offset < (region->addr_start + region->addr_len)) {
			/* Convert the offset so that it is relative to the
			 * start of the region.  Then add the base address of
			 * the region to get the final address.
			 */
			reg_offset -= region->addr_start;

			return region->vaddr + reg_offset;
		}
	}

	/* It's impossible to hit this case with offsets from the CP. But if we
	 * do for any other reason, the kernel will panic on that register
	 * access. Might as well do it here to make it clear what's happening.
	 */
	BUG();

	return NULL;
}

/**
@@ -779,7 +842,7 @@ static inline bool idpf_is_reset_detected(struct idpf_adapter *adapter)
	if (!adapter->hw.arq)
		return true;

	return !(readl(idpf_get_reg_addr(adapter, adapter->hw.arq->reg.len)) &
	return !(readl(idpf_get_mbx_reg_addr(adapter, adapter->hw.arq->reg.len)) &
		 adapter->hw.arq->reg.len_mask);
}

+7 −7
Original line number Diff line number Diff line
@@ -36,19 +36,19 @@ static void idpf_ctlq_init_regs(struct idpf_hw *hw, struct idpf_ctlq_info *cq,
{
	/* Update tail to post pre-allocated buffers for rx queues */
	if (is_rxq)
		wr32(hw, cq->reg.tail, (u32)(cq->ring_size - 1));
		idpf_mbx_wr32(hw, cq->reg.tail, (u32)(cq->ring_size - 1));

	/* For non-Mailbox control queues only TAIL need to be set */
	if (cq->q_id != -1)
		return;

	/* Clear Head for both send or receive */
	wr32(hw, cq->reg.head, 0);
	idpf_mbx_wr32(hw, cq->reg.head, 0);

	/* set starting point */
	wr32(hw, cq->reg.bal, lower_32_bits(cq->desc_ring.pa));
	wr32(hw, cq->reg.bah, upper_32_bits(cq->desc_ring.pa));
	wr32(hw, cq->reg.len, (cq->ring_size | cq->reg.len_ena_mask));
	idpf_mbx_wr32(hw, cq->reg.bal, lower_32_bits(cq->desc_ring.pa));
	idpf_mbx_wr32(hw, cq->reg.bah, upper_32_bits(cq->desc_ring.pa));
	idpf_mbx_wr32(hw, cq->reg.len, (cq->ring_size | cq->reg.len_ena_mask));
}

/**
@@ -329,7 +329,7 @@ int idpf_ctlq_send(struct idpf_hw *hw, struct idpf_ctlq_info *cq,
	 */
	dma_wmb();

	wr32(hw, cq->reg.tail, cq->next_to_use);
	idpf_mbx_wr32(hw, cq->reg.tail, cq->next_to_use);

err_unlock:
	mutex_unlock(&cq->cq_lock);
@@ -521,7 +521,7 @@ int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw, struct idpf_ctlq_info *cq,

		dma_wmb();

		wr32(hw, cq->reg.tail, cq->next_to_post);
		idpf_mbx_wr32(hw, cq->reg.tail, cq->next_to_post);
	}

	mutex_unlock(&cq->cq_lock);
+16 −2
Original line number Diff line number Diff line
@@ -94,12 +94,26 @@ struct idpf_mbxq_desc {
	u32 pf_vf_id;		/* used by CP when sending to PF */
};

/* Max number of MMIO regions not including the mailbox and rstat regions in
 * the fallback case when the whole bar is mapped.
 */
#define IDPF_MMIO_MAP_FALLBACK_MAX_REMAINING		3

struct idpf_mmio_reg {
	void __iomem *vaddr;
	resource_size_t addr_start;
	resource_size_t addr_len;
};

/* Define the driver hardware struct to replace other control structs as needed
 * Align to ctlq_hw_info
 */
struct idpf_hw {
	void __iomem *hw_addr;
	resource_size_t hw_addr_len;
	struct idpf_mmio_reg mbx;
	struct idpf_mmio_reg rstat;
	/* Array of remaining LAN BAR regions */
	int num_lan_regs;
	struct idpf_mmio_reg *lan_regs;

	struct idpf_adapter *back;

+22 −14
Original line number Diff line number Diff line
@@ -10,10 +10,13 @@

/**
 * 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_ctlq_create_info *cq)
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++) {
@@ -22,22 +25,22 @@ static void idpf_ctlq_reg_init(struct idpf_ctlq_create_info *cq)
		switch (ccq->type) {
		case IDPF_CTLQ_TYPE_MAILBOX_TX:
			/* set head and tail registers in our local struct */
			ccq->reg.head = PF_FW_ATQH;
			ccq->reg.tail = PF_FW_ATQT;
			ccq->reg.len = PF_FW_ATQLEN;
			ccq->reg.bah = PF_FW_ATQBAH;
			ccq->reg.bal = PF_FW_ATQBAL;
			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;
			ccq->reg.tail = PF_FW_ARQT;
			ccq->reg.len = PF_FW_ARQLEN;
			ccq->reg.bah = PF_FW_ARQBAH;
			ccq->reg.bal = PF_FW_ARQBAL;
			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;
@@ -130,7 +133,7 @@ static int idpf_intr_reg_init(struct idpf_vport *vport)
 */
static void idpf_reset_reg_init(struct idpf_adapter *adapter)
{
	adapter->reset_reg.rstat = idpf_get_reg_addr(adapter, PFGEN_RSTAT);
	adapter->reset_reg.rstat = idpf_get_rstat_reg_addr(adapter, PFGEN_RSTAT);
	adapter->reset_reg.rstat_m = PFGEN_RSTAT_PFR_STATE_M;
}

@@ -144,9 +147,9 @@ static void idpf_trigger_reset(struct idpf_adapter *adapter,
{
	u32 reset_reg;

	reset_reg = readl(idpf_get_reg_addr(adapter, PFGEN_CTRL));
	reset_reg = readl(idpf_get_rstat_reg_addr(adapter, PFGEN_CTRL));
	writel(reset_reg | PFGEN_CTRL_PFSWR,
	       idpf_get_reg_addr(adapter, PFGEN_CTRL));
	       idpf_get_rstat_reg_addr(adapter, PFGEN_CTRL));
}

/**
@@ -195,4 +198,9 @@ 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);
}
+29 −3
Original line number Diff line number Diff line
@@ -412,7 +412,7 @@ int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
{
	struct iidc_rdma_core_dev_info *cdev_info;
	struct iidc_rdma_priv_dev_info *privd;
	int err;
	int err, i;

	adapter->cdev_info = kzalloc(sizeof(*cdev_info), GFP_KERNEL);
	if (!adapter->cdev_info)
@@ -430,14 +430,36 @@ int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
	cdev_info->rdma_protocol = IIDC_RDMA_PROTOCOL_ROCEV2;
	privd->ftype = ftype;

	privd->mapped_mem_regions =
		kcalloc(adapter->hw.num_lan_regs,
			sizeof(struct iidc_rdma_lan_mapped_mem_region),
			GFP_KERNEL);
	if (!privd->mapped_mem_regions) {
		err = -ENOMEM;
		goto err_plug_aux_dev;
	}

	privd->num_memory_regions = cpu_to_le16(adapter->hw.num_lan_regs);
	for (i = 0; i < adapter->hw.num_lan_regs; i++) {
		privd->mapped_mem_regions[i].region_addr =
			adapter->hw.lan_regs[i].vaddr;
		privd->mapped_mem_regions[i].size =
			cpu_to_le64(adapter->hw.lan_regs[i].addr_len);
		privd->mapped_mem_regions[i].start_offset =
			cpu_to_le64(adapter->hw.lan_regs[i].addr_start);
	}

	idpf_idc_init_msix_data(adapter);

	err = idpf_plug_core_aux_dev(cdev_info);
	if (err)
		goto err_plug_aux_dev;
		goto err_free_mem_regions;

	return 0;

err_free_mem_regions:
	kfree(privd->mapped_mem_regions);
	privd->mapped_mem_regions = NULL;
err_plug_aux_dev:
	kfree(privd);
err_privd_alloc:
@@ -453,12 +475,16 @@ int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
 */
void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info)
{
	struct iidc_rdma_priv_dev_info *privd;

	if (!cdev_info)
		return;

	idpf_unplug_aux_dev(cdev_info->adev);

	kfree(cdev_info->iidc_priv);
	privd = cdev_info->iidc_priv;
	kfree(privd->mapped_mem_regions);
	kfree(privd);
	kfree(cdev_info);
}

Loading