Commit a00b87c1 authored by wanghaibin's avatar wanghaibin Committed by Dongxu Sun
Browse files

irqchip/gic-v4.1: Rework get/set_irqchip_state callbacks of GICv4.1-sgi chip

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


CVE: NA

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

Rework get/set_irqchip_state callbacks of GICv4.1-sgi chip
to add support for the new vPPI.

Specifically,

- Reading the pending state is done by re-using a pair of redistributor
  registers (GICR_VSGIR, GICR_VSGIPENDR).
- Setting the pending state is done by generating it as we'd otherwise do
  for a guest (writing to GITS_PPIR).
- Clearing the pending state is done by emitting a VSGI command with the
  "clear" bit set.

Still, we only support vtimer interrupt whose intid is 27. And note that
the pending state of it is stored at bit[16] of GICR_VSGIPENDR.

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 fd6e5954
Loading
Loading
Loading
Loading
+21 −2
Original line number Diff line number Diff line
@@ -4529,11 +4529,15 @@ static int its_sgi_set_irqchip_state(struct irq_data *d,
	if (state) {
		struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
		struct its_node *its = find_4_1_its();
		u64 offset = GITS_SGIR;
		u64 val;

		if (__get_intid_range(d->hwirq) == PPI_RANGE)
			offset = GITS_PPIR;

		val  = FIELD_PREP(GITS_SGIR_VPEID, vpe->vpe_id);
		val |= FIELD_PREP(GITS_SGIR_VINTID, d->hwirq);
		writeq_relaxed(val, its->sgir_base + GITS_SGIR - SZ_128K);
		writeq_relaxed(val, its->sgir_base + offset - SZ_128K);
	} else {
		its_configure_sgi(d, true);
	}
@@ -4545,6 +4549,7 @@ static int its_sgi_get_irqchip_state(struct irq_data *d,
				     enum irqchip_irq_state which, bool *val)
{
	struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
	enum gic_intid_range type;
	void __iomem *base;
	unsigned long flags;
	u32 count = 1000000;	/* 1s! */
@@ -4554,6 +4559,17 @@ static int its_sgi_get_irqchip_state(struct irq_data *d,
	if (which != IRQCHIP_STATE_PENDING)
		return -EINVAL;

	/*
	 * Plug the HiSilicon implementation details in comment!
	 *
	 * For vPPI, we re-use the GICR_VSGIR and GICR_VSGIPENDR in the
	 * implementation which allows reads to GICR_I{S,C}PENDR to be
	 * emulated. And note that the pending state of the vtimer
	 * interrupt is stored at bit[16] of GICR_VSGIPENDR.
	 */
	type = __get_intid_range(d->hwirq);
	WARN_ON_ONCE(type == PPI_RANGE && !is_vtimer_irq(d->hwirq));

	/*
	 * Locking galore! We can race against two different events:
	 *
@@ -4589,6 +4605,9 @@ static int its_sgi_get_irqchip_state(struct irq_data *d,
	if (!count)
		return -ENXIO;

	if (is_vtimer_irq(d->hwirq))
		*val = !!(status & (1 << 16));
	else
		*val = !!(status & (1 << d->hwirq));

	return 0;
+4 −1
Original line number Diff line number Diff line
@@ -378,12 +378,15 @@
#define GITS_TRANSLATER			0x10040

#define GITS_SGIR			0x20020
/* HiSilicon IMP DEF register to set vPPI pending. */
#define GITS_PPIR			0x200A8

/* HiSilicon IMP DEF register */
#define GITS_VERSION			0xC000

#define GITS_SGIR_VPEID			GENMASK_ULL(47, 32)
#define GITS_SGIR_VINTID		GENMASK_ULL(3, 0)
/* Hackish... Extend it to [4:0] to support vPPI. */
#define GITS_SGIR_VINTID		GENMASK_ULL(4, 0)

#define GITS_CTLR_ENABLE		(1U << 0)
#define GITS_CTLR_ImDe			(1U << 1)