Commit fd6e5954 authored by Kunkun Jiang's avatar Kunkun Jiang Committed by Dongxu Sun
Browse files

irqchip/gic-v4.1: Extend VSGI command to support the new vPPI

virt inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8K89F


CVE: NA

------------------------------------------------------------------

In HiSilicon implementation, we reuse the *VSGI* command to set the
configuration of a specified vPPI and optionally clear its pending
state. A bit odd, but keeping the smallest change in HW level is safe.

The vINTID field has been therefore extended to [36:32], carefully
encode it to respect the new requirement. Note that _only_ vtimer
interrupt is supported at the moment!

Signed-off-by: default avatarwanghaibin <wanghaibin.wang@huawei.com>
Signed-off-by: default avatarZenghui Yu <yuzenghui@huawei.com>
Signed-off-by: default avatarKunkun Jiang <jiangkunkun@huawei.com>
Signed-off-by: default avatarDongxu Sun <sundongxu3@huawei.com>
parent 5decdcc6
Loading
Loading
Loading
Loading
+36 −2
Original line number Diff line number Diff line
@@ -129,6 +129,21 @@ struct its_node {

#define is_vtimer_irqbypass(its)	(!!((its)->version & GITS_VERSION_VTIMER))

/* Fetch it from gtdt->virtual_timer_interrupt. */
#define is_vtimer_irq(irq)	((irq) == 27)

static inline bool is_its_vsgi_cmd_valid(struct its_node *its, u8 hwirq)
{
	if (__get_intid_range(hwirq) == SGI_RANGE)
		return true;

	/* For PPI range, only vtimer interrupt is supported atm. */
	if (is_vtimer_irq(hwirq) && is_vtimer_irqbypass(its))
		return true;

	return false;
}

#define ITS_ITT_ALIGN		SZ_256

/* The maximum number of VPEID bits supported by VLPI commands */
@@ -574,6 +589,16 @@ static void its_encode_sgi_intid(struct its_cmd_block *cmd, u8 sgi)
	its_mask_encode(&cmd->raw_cmd[0], sgi, 35, 32);
}

static void its_encode_sgi_intid_extension(struct its_cmd_block *cmd, u8 sgi)
{
	/*
	 * We reuse the VSGI command in this implementation to configure
	 * the vPPI or clear its pending state. The vINTID field has been
	 * therefore extended to [36:32].
	 */
	its_mask_encode(&cmd->raw_cmd[0], sgi, 36, 32);
}

static void its_encode_sgi_priority(struct its_cmd_block *cmd, u8 prio)
{
	its_mask_encode(&cmd->raw_cmd[0], prio >> 4, 23, 20);
@@ -973,7 +998,10 @@ static struct its_vpe *its_build_vsgi_cmd(struct its_node *its,

	its_encode_cmd(cmd, GITS_CMD_VSGI);
	its_encode_vpeid(cmd, desc->its_vsgi_cmd.vpe->vpe_id);
	if (!is_vtimer_irqbypass(its))
		its_encode_sgi_intid(cmd, desc->its_vsgi_cmd.sgi);
	else
		its_encode_sgi_intid_extension(cmd, desc->its_vsgi_cmd.sgi);
	its_encode_sgi_priority(cmd, desc->its_vsgi_cmd.priority);
	its_encode_sgi_group(cmd, desc->its_vsgi_cmd.group);
	its_encode_sgi_clear(cmd, desc->its_vsgi_cmd.clear);
@@ -4439,8 +4467,14 @@ static struct irq_chip its_vpe_4_1_irq_chip = {
static void its_configure_sgi(struct irq_data *d, bool clear)
{
	struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
	struct its_node *its = find_4_1_its();
	struct its_cmd_desc desc;

	if (!its || !is_its_vsgi_cmd_valid(its, d->hwirq)) {
		pr_err("ITS: its_configure_sgi failed\n");
		return;
	}

	desc.its_vsgi_cmd.vpe = vpe;
	desc.its_vsgi_cmd.sgi = d->hwirq;
	desc.its_vsgi_cmd.priority = vpe->sgi_config[d->hwirq].priority;
@@ -4453,7 +4487,7 @@ static void its_configure_sgi(struct irq_data *d, bool clear)
	 * destination VPE is mapped there. Since we map them eagerly at
	 * activation time, we're pretty sure the first GICv4.1 ITS will do.
	 */
	its_send_single_vcommand(find_4_1_its(), its_build_vsgi_cmd, &desc);
	its_send_single_vcommand(its, its_build_vsgi_cmd, &desc);
}

static void its_sgi_mask_irq(struct irq_data *d)
+0 −30
Original line number Diff line number Diff line
@@ -136,36 +136,6 @@ static DEFINE_PER_CPU(bool, has_rss);
/* Our default, arbitrary priority value. Linux only uses one anyway. */
#define DEFAULT_PMR_VALUE	0xf0

enum gic_intid_range {
	SGI_RANGE,
	PPI_RANGE,
	SPI_RANGE,
	EPPI_RANGE,
	ESPI_RANGE,
	LPI_RANGE,
	__INVALID_RANGE__
};

static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq)
{
	switch (hwirq) {
	case 0 ... 15:
		return SGI_RANGE;
	case 16 ... 31:
		return PPI_RANGE;
	case 32 ... 1019:
		return SPI_RANGE;
	case EPPI_BASE_INTID ... (EPPI_BASE_INTID + 63):
		return EPPI_RANGE;
	case ESPI_BASE_INTID ... (ESPI_BASE_INTID + 1023):
		return ESPI_RANGE;
	case 8192 ... GENMASK(23, 0):
		return LPI_RANGE;
	default:
		return __INVALID_RANGE__;
	}
}

phys_addr_t get_gicr_paddr(int cpu)
{
	return (per_cpu_ptr(gic_data.rdists.rdist, cpu))->phys_base;
+30 −0
Original line number Diff line number Diff line
@@ -726,6 +726,36 @@ static inline bool gic_enable_sre(void)
	return !!(val & ICC_SRE_EL1_SRE);
}

enum gic_intid_range {
	SGI_RANGE,
	PPI_RANGE,
	SPI_RANGE,
	EPPI_RANGE,
	ESPI_RANGE,
	LPI_RANGE,
	__INVALID_RANGE__
};

static inline enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq)
{
	switch (hwirq) {
	case 0 ... 15:
		return SGI_RANGE;
	case 16 ... 31:
		return PPI_RANGE;
	case 32 ... 1019:
		return SPI_RANGE;
	case EPPI_BASE_INTID ... (EPPI_BASE_INTID + 63):
		return EPPI_RANGE;
	case ESPI_BASE_INTID ... (ESPI_BASE_INTID + 1023):
		return ESPI_RANGE;
	case 8192 ... GENMASK(23, 0):
		return LPI_RANGE;
	default:
		return __INVALID_RANGE__;
	}
}

#endif

#endif