All of lore.kernel.org
 help / color / mirror / Atom feed
From: wuyun.wu@huawei.com (Yun Wu (Abel))
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 04/13] irqchip: GICv3: ITS command queue
Date: Wed, 10 Dec 2014 11:03:01 +0800	[thread overview]
Message-ID: <5487B7E5.2080104@huawei.com> (raw)
In-Reply-To: <1416839720-18400-5-git-send-email-marc.zyngier@arm.com>

On 2014/11/24 22:35, Marc Zyngier wrote:

[...]

> +static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,
> +						 struct its_cmd_desc *desc)
> +{
> +	unsigned long itt_addr;
> +	u8 size = order_base_2(desc->its_mapd_cmd.dev->nr_ites);

If @nr_ites is 1, then @size becomes 0, and... (see below)

> +
> +	itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt);
> +	itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN);
> +
> +	its_encode_cmd(cmd, GITS_CMD_MAPD);
> +	its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id);
> +	its_encode_size(cmd, size - 1);

here (size - 1) becomes the value of ~0, which will exceed the maximum
supported bits of identifier.

Regards,
	Abel

> +	its_encode_itt(cmd, itt_addr);
> +	its_encode_valid(cmd, desc->its_mapd_cmd.valid);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_mapd_cmd.dev->collection;
> +}
> +
> +static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
> +						 struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_MAPC);
> +	its_encode_collection(cmd, desc->its_mapc_cmd.col->col_id);
> +	its_encode_target(cmd, desc->its_mapc_cmd.col->target_address);
> +	its_encode_valid(cmd, desc->its_mapc_cmd.valid);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_mapc_cmd.col;
> +}
> +
> +static struct its_collection *its_build_mapvi_cmd(struct its_cmd_block *cmd,
> +						  struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_MAPVI);
> +	its_encode_devid(cmd, desc->its_mapvi_cmd.dev->device_id);
> +	its_encode_event_id(cmd, desc->its_mapvi_cmd.event_id);
> +	its_encode_phys_id(cmd, desc->its_mapvi_cmd.phys_id);
> +	its_encode_collection(cmd, desc->its_mapvi_cmd.dev->collection->col_id);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_mapvi_cmd.dev->collection;
> +}
> +
> +static struct its_collection *its_build_movi_cmd(struct its_cmd_block *cmd,
> +						 struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_MOVI);
> +	its_encode_devid(cmd, desc->its_movi_cmd.dev->device_id);
> +	its_encode_event_id(cmd, desc->its_movi_cmd.id);
> +	its_encode_collection(cmd, desc->its_movi_cmd.col->col_id);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_movi_cmd.dev->collection;
> +}
> +
> +static struct its_collection *its_build_discard_cmd(struct its_cmd_block *cmd,
> +						    struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_DISCARD);
> +	its_encode_devid(cmd, desc->its_discard_cmd.dev->device_id);
> +	its_encode_event_id(cmd, desc->its_discard_cmd.event_id);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_discard_cmd.dev->collection;
> +}
> +
> +static struct its_collection *its_build_inv_cmd(struct its_cmd_block *cmd,
> +						struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_INV);
> +	its_encode_devid(cmd, desc->its_inv_cmd.dev->device_id);
> +	its_encode_event_id(cmd, desc->its_inv_cmd.event_id);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_inv_cmd.dev->collection;
> +}
> +
> +static struct its_collection *its_build_invall_cmd(struct its_cmd_block *cmd,
> +						   struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_INVALL);
> +	its_encode_collection(cmd, desc->its_mapc_cmd.col->col_id);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return NULL;
> +}
> +
> +static u64 its_cmd_ptr_to_offset(struct its_node *its,
> +				 struct its_cmd_block *ptr)
> +{
> +	return (ptr - its->cmd_base) * sizeof(*ptr);
> +}
> +
> +static int its_queue_full(struct its_node *its)
> +{
> +	int widx;
> +	int ridx;
> +
> +	widx = its->cmd_write - its->cmd_base;
> +	ridx = readl_relaxed(its->base + GITS_CREADR) / sizeof(struct its_cmd_block);
> +
> +	/* This is incredibly unlikely to happen, unless the ITS locks up. */
> +	if (((widx + 1) % ITS_CMD_QUEUE_NR_ENTRIES) == ridx)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static struct its_cmd_block *its_allocate_entry(struct its_node *its)
> +{
> +	struct its_cmd_block *cmd;
> +	u32 count = 1000000;	/* 1s! */
> +
> +	while (its_queue_full(its)) {
> +		count--;
> +		if (!count) {
> +			pr_err_ratelimited("ITS queue not draining\n");
> +			return NULL;
> +		}
> +		cpu_relax();
> +		udelay(1);
> +	}
> +
> +	cmd = its->cmd_write++;
> +
> +	/* Handle queue wrapping */
> +	if (its->cmd_write == (its->cmd_base + ITS_CMD_QUEUE_NR_ENTRIES))
> +		its->cmd_write = its->cmd_base;
> +
> +	return cmd;
> +}
> +
> +static struct its_cmd_block *its_post_commands(struct its_node *its)
> +{
> +	u64 wr = its_cmd_ptr_to_offset(its, its->cmd_write);
> +
> +	writel_relaxed(wr, its->base + GITS_CWRITER);
> +
> +	return its->cmd_write;
> +}
> +
> +static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
> +{
> +	/*
> +	 * Make sure the commands written to memory are observable by
> +	 * the ITS.
> +	 */
> +	if (its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING)
> +		__flush_dcache_area(cmd, sizeof(*cmd));
> +	else
> +		dsb(ishst);
> +}
> +
> +static void its_wait_for_range_completion(struct its_node *its,
> +					  struct its_cmd_block *from,
> +					  struct its_cmd_block *to)
> +{
> +	u64 rd_idx, from_idx, to_idx;
> +	u32 count = 1000000;	/* 1s! */
> +
> +	from_idx = its_cmd_ptr_to_offset(its, from);
> +	to_idx = its_cmd_ptr_to_offset(its, to);
> +
> +	while (1) {
> +		rd_idx = readl_relaxed(its->base + GITS_CREADR);
> +		if (rd_idx >= to_idx || rd_idx < from_idx)
> +			break;
> +
> +		count--;
> +		if (!count) {
> +			pr_err_ratelimited("ITS queue timeout\n");
> +			return;
> +		}
> +		cpu_relax();
> +		udelay(1);
> +	}
> +}
> +
> +static void its_send_single_command(struct its_node *its,
> +				    its_cmd_builder_t builder,
> +				    struct its_cmd_desc *desc)
> +{
> +	struct its_cmd_block *cmd, *sync_cmd, *next_cmd;
> +	struct its_collection *sync_col;
> +
> +	raw_spin_lock(&its->lock);
> +
> +	cmd = its_allocate_entry(its);
> +	if (!cmd) {		/* We're soooooo screewed... */
> +		pr_err_ratelimited("ITS can't allocate, dropping command\n");
> +		raw_spin_unlock(&its->lock);
> +		return;
> +	}
> +	sync_col = builder(cmd, desc);
> +	its_flush_cmd(its, cmd);
> +
> +	if (sync_col) {
> +		sync_cmd = its_allocate_entry(its);
> +		if (!sync_cmd) {
> +			pr_err_ratelimited("ITS can't SYNC, skipping\n");
> +			goto post;
> +		}
> +		its_encode_cmd(sync_cmd, GITS_CMD_SYNC);
> +		its_encode_target(sync_cmd, sync_col->target_address);
> +		its_fixup_cmd(sync_cmd);
> +		its_flush_cmd(its, sync_cmd);
> +	}
> +
> +post:
> +	next_cmd = its_post_commands(its);
> +	raw_spin_unlock(&its->lock);
> +
> +	its_wait_for_range_completion(its, cmd, next_cmd);
> +}
> +
> +static void its_send_inv(struct its_device *dev, u32 event_id)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_inv_cmd.dev = dev;
> +	desc.its_inv_cmd.event_id = event_id;
> +
> +	its_send_single_command(dev->its, its_build_inv_cmd, &desc);
> +}
> +
> +static void its_send_mapd(struct its_device *dev, int valid)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_mapd_cmd.dev = dev;
> +	desc.its_mapd_cmd.valid = !!valid;
> +
> +	its_send_single_command(dev->its, its_build_mapd_cmd, &desc);
> +}
> +
> +static void its_send_mapc(struct its_node *its, struct its_collection *col,
> +			  int valid)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_mapc_cmd.col = col;
> +	desc.its_mapc_cmd.valid = !!valid;
> +
> +	its_send_single_command(its, its_build_mapc_cmd, &desc);
> +}
> +
> +static void its_send_mapvi(struct its_device *dev, u32 irq_id, u32 id)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_mapvi_cmd.dev = dev;
> +	desc.its_mapvi_cmd.phys_id = irq_id;
> +	desc.its_mapvi_cmd.event_id = id;
> +
> +	its_send_single_command(dev->its, its_build_mapvi_cmd, &desc);
> +}
> +
> +static void its_send_movi(struct its_device *dev,
> +			  struct its_collection *col, u32 id)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_movi_cmd.dev = dev;
> +	desc.its_movi_cmd.col = col;
> +	desc.its_movi_cmd.id = id;
> +
> +	its_send_single_command(dev->its, its_build_movi_cmd, &desc);
> +}
> +
> +static void its_send_discard(struct its_device *dev, u32 id)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_discard_cmd.dev = dev;
> +	desc.its_discard_cmd.event_id = id;
> +
> +	its_send_single_command(dev->its, its_build_discard_cmd, &desc);
> +}
> +
> +static void its_send_invall(struct its_node *its, struct its_collection *col)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_invall_cmd.col = col;
> +
> +	its_send_single_command(its, its_build_invall_cmd, &desc);
> +}
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 040615a..21c9d70 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -80,9 +80,27 @@
>  #define GICR_MOVALLR			0x0110
>  #define GICR_PIDR2			GICD_PIDR2
>  
> +#define GICR_CTLR_ENABLE_LPIS		(1UL << 0)
> +
> +#define GICR_TYPER_CPU_NUMBER(r)	(((r) >> 8) & 0xffff)
> +
>  #define GICR_WAKER_ProcessorSleep	(1U << 1)
>  #define GICR_WAKER_ChildrenAsleep	(1U << 2)
>  
> +#define GICR_PROPBASER_NonShareable	(0U << 10)
> +#define GICR_PROPBASER_InnerShareable	(1U << 10)
> +#define GICR_PROPBASER_OuterShareable	(2U << 10)
> +#define GICR_PROPBASER_SHAREABILITY_MASK (3UL << 10)
> +#define GICR_PROPBASER_nCnB		(0U << 7)
> +#define GICR_PROPBASER_nC		(1U << 7)
> +#define GICR_PROPBASER_RaWt		(2U << 7)
> +#define GICR_PROPBASER_RaWb		(3U << 7)
> +#define GICR_PROPBASER_WaWt		(4U << 7)
> +#define GICR_PROPBASER_WaWb		(5U << 7)
> +#define GICR_PROPBASER_RaWaWt		(6U << 7)
> +#define GICR_PROPBASER_RaWaWb		(7U << 7)
> +#define GICR_PROPBASER_IDBITS_MASK	(0x1f)
> +
>  /*
>   * Re-Distributor registers, offsets from SGI_base
>   */
> @@ -95,9 +113,93 @@
>  #define GICR_IPRIORITYR0		GICD_IPRIORITYR
>  #define GICR_ICFGR0			GICD_ICFGR
>  
> +#define GICR_TYPER_PLPIS		(1U << 0)
>  #define GICR_TYPER_VLPIS		(1U << 1)
>  #define GICR_TYPER_LAST			(1U << 4)
>  
> +#define LPI_PROP_GROUP1			(1 << 1)
> +#define LPI_PROP_ENABLED		(1 << 0)
> +
> +/*
> + * ITS registers, offsets from ITS_base
> + */
> +#define GITS_CTLR			0x0000
> +#define GITS_IIDR			0x0004
> +#define GITS_TYPER			0x0008
> +#define GITS_CBASER			0x0080
> +#define GITS_CWRITER			0x0088
> +#define GITS_CREADR			0x0090
> +#define GITS_BASER			0x0100
> +#define GITS_PIDR2			GICR_PIDR2
> +
> +#define GITS_TRANSLATER			0x10040
> +
> +#define GITS_TYPER_PTA			(1UL << 19)
> +
> +#define GITS_CBASER_VALID		(1UL << 63)
> +#define GITS_CBASER_nCnB		(0UL << 59)
> +#define GITS_CBASER_nC			(1UL << 59)
> +#define GITS_CBASER_RaWt		(2UL << 59)
> +#define GITS_CBASER_RaWb		(3UL << 59)
> +#define GITS_CBASER_WaWt		(4UL << 59)
> +#define GITS_CBASER_WaWb		(5UL << 59)
> +#define GITS_CBASER_RaWaWt		(6UL << 59)
> +#define GITS_CBASER_RaWaWb		(7UL << 59)
> +#define GITS_CBASER_NonShareable	(0UL << 10)
> +#define GITS_CBASER_InnerShareable	(1UL << 10)
> +#define GITS_CBASER_OuterShareable	(2UL << 10)
> +#define GITS_CBASER_SHAREABILITY_MASK	(3UL << 10)
> +
> +#define GITS_BASER_NR_REGS		8
> +
> +#define GITS_BASER_VALID		(1UL << 63)
> +#define GITS_BASER_nCnB			(0UL << 59)
> +#define GITS_BASER_nC			(1UL << 59)
> +#define GITS_BASER_RaWt			(2UL << 59)
> +#define GITS_BASER_RaWb			(3UL << 59)
> +#define GITS_BASER_WaWt			(4UL << 59)
> +#define GITS_BASER_WaWb			(5UL << 59)
> +#define GITS_BASER_RaWaWt		(6UL << 59)
> +#define GITS_BASER_RaWaWb		(7UL << 59)
> +#define GITS_BASER_TYPE_SHIFT		(56)
> +#define GITS_BASER_TYPE(r)		(((r) >> GITS_BASER_TYPE_SHIFT) & 7)
> +#define GITS_BASER_ENTRY_SIZE_SHIFT	(48)
> +#define GITS_BASER_ENTRY_SIZE(r)	((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1)
> +#define GITS_BASER_NonShareable		(0UL << 10)
> +#define GITS_BASER_InnerShareable	(1UL << 10)
> +#define GITS_BASER_OuterShareable	(2UL << 10)
> +#define GITS_BASER_SHAREABILITY_SHIFT	(10)
> +#define GITS_BASER_SHAREABILITY_MASK	(3UL << GITS_BASER_SHAREABILITY_SHIFT)
> +#define GITS_BASER_PAGE_SIZE_SHIFT	(8)
> +#define GITS_BASER_PAGE_SIZE_4K		(0UL << GITS_BASER_PAGE_SIZE_SHIFT)
> +#define GITS_BASER_PAGE_SIZE_16K	(1UL << GITS_BASER_PAGE_SIZE_SHIFT)
> +#define GITS_BASER_PAGE_SIZE_64K	(2UL << GITS_BASER_PAGE_SIZE_SHIFT)
> +#define GITS_BASER_PAGE_SIZE_MASK	(3UL << GITS_BASER_PAGE_SIZE_SHIFT)
> +
> +#define GITS_BASER_TYPE_NONE		0
> +#define GITS_BASER_TYPE_DEVICE		1
> +#define GITS_BASER_TYPE_VCPU		2
> +#define GITS_BASER_TYPE_CPU		3
> +#define GITS_BASER_TYPE_COLLECTION	4
> +#define GITS_BASER_TYPE_RESERVED5	5
> +#define GITS_BASER_TYPE_RESERVED6	6
> +#define GITS_BASER_TYPE_RESERVED7	7
> +
> +/*
> + * ITS commands
> + */
> +#define GITS_CMD_MAPD			0x08
> +#define GITS_CMD_MAPC			0x09
> +#define GITS_CMD_MAPVI			0x0a
> +#define GITS_CMD_MOVI			0x01
> +#define GITS_CMD_DISCARD		0x0f
> +#define GITS_CMD_INV			0x0c
> +#define GITS_CMD_MOVALL			0x0e
> +#define GITS_CMD_INVALL			0x0d
> +#define GITS_CMD_INT			0x03
> +#define GITS_CMD_CLEAR			0x04
> +#define GITS_CMD_SYNC			0x05
> +
>  /*
>   * CPU interface registers
>   */

WARNING: multiple messages have this Message-ID (diff)
From: "Yun Wu (Abel)" <wuyun.wu@huawei.com>
To: Marc Zyngier <marc.zyngier@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>,
	Jason Cooper <jason@lakedaemon.net>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>,
	"Jiang Liu" <jiang.liu@linux.intel.com>,
	Bjorn Helgaas <bhelgaas@google.com>,
	"Yingjoe Chen" <yingjoe.chen@mediatek.com>,
	Will Deacon <will.deacon@arm.com>,
	"Catalin marinas" <catalin.marinas@arm.com>,
	Mark Rutland <mark.rutland@arm.com>,
	Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>,
	Robert Richter <robert.richter@caviumnetworks.com>
Subject: Re: [PATCH v3 04/13] irqchip: GICv3: ITS command queue
Date: Wed, 10 Dec 2014 11:03:01 +0800	[thread overview]
Message-ID: <5487B7E5.2080104@huawei.com> (raw)
In-Reply-To: <1416839720-18400-5-git-send-email-marc.zyngier@arm.com>

On 2014/11/24 22:35, Marc Zyngier wrote:

[...]

> +static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,
> +						 struct its_cmd_desc *desc)
> +{
> +	unsigned long itt_addr;
> +	u8 size = order_base_2(desc->its_mapd_cmd.dev->nr_ites);

If @nr_ites is 1, then @size becomes 0, and... (see below)

> +
> +	itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt);
> +	itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN);
> +
> +	its_encode_cmd(cmd, GITS_CMD_MAPD);
> +	its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id);
> +	its_encode_size(cmd, size - 1);

here (size - 1) becomes the value of ~0, which will exceed the maximum
supported bits of identifier.

Regards,
	Abel

> +	its_encode_itt(cmd, itt_addr);
> +	its_encode_valid(cmd, desc->its_mapd_cmd.valid);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_mapd_cmd.dev->collection;
> +}
> +
> +static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
> +						 struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_MAPC);
> +	its_encode_collection(cmd, desc->its_mapc_cmd.col->col_id);
> +	its_encode_target(cmd, desc->its_mapc_cmd.col->target_address);
> +	its_encode_valid(cmd, desc->its_mapc_cmd.valid);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_mapc_cmd.col;
> +}
> +
> +static struct its_collection *its_build_mapvi_cmd(struct its_cmd_block *cmd,
> +						  struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_MAPVI);
> +	its_encode_devid(cmd, desc->its_mapvi_cmd.dev->device_id);
> +	its_encode_event_id(cmd, desc->its_mapvi_cmd.event_id);
> +	its_encode_phys_id(cmd, desc->its_mapvi_cmd.phys_id);
> +	its_encode_collection(cmd, desc->its_mapvi_cmd.dev->collection->col_id);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_mapvi_cmd.dev->collection;
> +}
> +
> +static struct its_collection *its_build_movi_cmd(struct its_cmd_block *cmd,
> +						 struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_MOVI);
> +	its_encode_devid(cmd, desc->its_movi_cmd.dev->device_id);
> +	its_encode_event_id(cmd, desc->its_movi_cmd.id);
> +	its_encode_collection(cmd, desc->its_movi_cmd.col->col_id);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_movi_cmd.dev->collection;
> +}
> +
> +static struct its_collection *its_build_discard_cmd(struct its_cmd_block *cmd,
> +						    struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_DISCARD);
> +	its_encode_devid(cmd, desc->its_discard_cmd.dev->device_id);
> +	its_encode_event_id(cmd, desc->its_discard_cmd.event_id);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_discard_cmd.dev->collection;
> +}
> +
> +static struct its_collection *its_build_inv_cmd(struct its_cmd_block *cmd,
> +						struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_INV);
> +	its_encode_devid(cmd, desc->its_inv_cmd.dev->device_id);
> +	its_encode_event_id(cmd, desc->its_inv_cmd.event_id);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return desc->its_inv_cmd.dev->collection;
> +}
> +
> +static struct its_collection *its_build_invall_cmd(struct its_cmd_block *cmd,
> +						   struct its_cmd_desc *desc)
> +{
> +	its_encode_cmd(cmd, GITS_CMD_INVALL);
> +	its_encode_collection(cmd, desc->its_mapc_cmd.col->col_id);
> +
> +	its_fixup_cmd(cmd);
> +
> +	return NULL;
> +}
> +
> +static u64 its_cmd_ptr_to_offset(struct its_node *its,
> +				 struct its_cmd_block *ptr)
> +{
> +	return (ptr - its->cmd_base) * sizeof(*ptr);
> +}
> +
> +static int its_queue_full(struct its_node *its)
> +{
> +	int widx;
> +	int ridx;
> +
> +	widx = its->cmd_write - its->cmd_base;
> +	ridx = readl_relaxed(its->base + GITS_CREADR) / sizeof(struct its_cmd_block);
> +
> +	/* This is incredibly unlikely to happen, unless the ITS locks up. */
> +	if (((widx + 1) % ITS_CMD_QUEUE_NR_ENTRIES) == ridx)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static struct its_cmd_block *its_allocate_entry(struct its_node *its)
> +{
> +	struct its_cmd_block *cmd;
> +	u32 count = 1000000;	/* 1s! */
> +
> +	while (its_queue_full(its)) {
> +		count--;
> +		if (!count) {
> +			pr_err_ratelimited("ITS queue not draining\n");
> +			return NULL;
> +		}
> +		cpu_relax();
> +		udelay(1);
> +	}
> +
> +	cmd = its->cmd_write++;
> +
> +	/* Handle queue wrapping */
> +	if (its->cmd_write == (its->cmd_base + ITS_CMD_QUEUE_NR_ENTRIES))
> +		its->cmd_write = its->cmd_base;
> +
> +	return cmd;
> +}
> +
> +static struct its_cmd_block *its_post_commands(struct its_node *its)
> +{
> +	u64 wr = its_cmd_ptr_to_offset(its, its->cmd_write);
> +
> +	writel_relaxed(wr, its->base + GITS_CWRITER);
> +
> +	return its->cmd_write;
> +}
> +
> +static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
> +{
> +	/*
> +	 * Make sure the commands written to memory are observable by
> +	 * the ITS.
> +	 */
> +	if (its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING)
> +		__flush_dcache_area(cmd, sizeof(*cmd));
> +	else
> +		dsb(ishst);
> +}
> +
> +static void its_wait_for_range_completion(struct its_node *its,
> +					  struct its_cmd_block *from,
> +					  struct its_cmd_block *to)
> +{
> +	u64 rd_idx, from_idx, to_idx;
> +	u32 count = 1000000;	/* 1s! */
> +
> +	from_idx = its_cmd_ptr_to_offset(its, from);
> +	to_idx = its_cmd_ptr_to_offset(its, to);
> +
> +	while (1) {
> +		rd_idx = readl_relaxed(its->base + GITS_CREADR);
> +		if (rd_idx >= to_idx || rd_idx < from_idx)
> +			break;
> +
> +		count--;
> +		if (!count) {
> +			pr_err_ratelimited("ITS queue timeout\n");
> +			return;
> +		}
> +		cpu_relax();
> +		udelay(1);
> +	}
> +}
> +
> +static void its_send_single_command(struct its_node *its,
> +				    its_cmd_builder_t builder,
> +				    struct its_cmd_desc *desc)
> +{
> +	struct its_cmd_block *cmd, *sync_cmd, *next_cmd;
> +	struct its_collection *sync_col;
> +
> +	raw_spin_lock(&its->lock);
> +
> +	cmd = its_allocate_entry(its);
> +	if (!cmd) {		/* We're soooooo screewed... */
> +		pr_err_ratelimited("ITS can't allocate, dropping command\n");
> +		raw_spin_unlock(&its->lock);
> +		return;
> +	}
> +	sync_col = builder(cmd, desc);
> +	its_flush_cmd(its, cmd);
> +
> +	if (sync_col) {
> +		sync_cmd = its_allocate_entry(its);
> +		if (!sync_cmd) {
> +			pr_err_ratelimited("ITS can't SYNC, skipping\n");
> +			goto post;
> +		}
> +		its_encode_cmd(sync_cmd, GITS_CMD_SYNC);
> +		its_encode_target(sync_cmd, sync_col->target_address);
> +		its_fixup_cmd(sync_cmd);
> +		its_flush_cmd(its, sync_cmd);
> +	}
> +
> +post:
> +	next_cmd = its_post_commands(its);
> +	raw_spin_unlock(&its->lock);
> +
> +	its_wait_for_range_completion(its, cmd, next_cmd);
> +}
> +
> +static void its_send_inv(struct its_device *dev, u32 event_id)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_inv_cmd.dev = dev;
> +	desc.its_inv_cmd.event_id = event_id;
> +
> +	its_send_single_command(dev->its, its_build_inv_cmd, &desc);
> +}
> +
> +static void its_send_mapd(struct its_device *dev, int valid)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_mapd_cmd.dev = dev;
> +	desc.its_mapd_cmd.valid = !!valid;
> +
> +	its_send_single_command(dev->its, its_build_mapd_cmd, &desc);
> +}
> +
> +static void its_send_mapc(struct its_node *its, struct its_collection *col,
> +			  int valid)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_mapc_cmd.col = col;
> +	desc.its_mapc_cmd.valid = !!valid;
> +
> +	its_send_single_command(its, its_build_mapc_cmd, &desc);
> +}
> +
> +static void its_send_mapvi(struct its_device *dev, u32 irq_id, u32 id)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_mapvi_cmd.dev = dev;
> +	desc.its_mapvi_cmd.phys_id = irq_id;
> +	desc.its_mapvi_cmd.event_id = id;
> +
> +	its_send_single_command(dev->its, its_build_mapvi_cmd, &desc);
> +}
> +
> +static void its_send_movi(struct its_device *dev,
> +			  struct its_collection *col, u32 id)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_movi_cmd.dev = dev;
> +	desc.its_movi_cmd.col = col;
> +	desc.its_movi_cmd.id = id;
> +
> +	its_send_single_command(dev->its, its_build_movi_cmd, &desc);
> +}
> +
> +static void its_send_discard(struct its_device *dev, u32 id)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_discard_cmd.dev = dev;
> +	desc.its_discard_cmd.event_id = id;
> +
> +	its_send_single_command(dev->its, its_build_discard_cmd, &desc);
> +}
> +
> +static void its_send_invall(struct its_node *its, struct its_collection *col)
> +{
> +	struct its_cmd_desc desc;
> +
> +	desc.its_invall_cmd.col = col;
> +
> +	its_send_single_command(its, its_build_invall_cmd, &desc);
> +}
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 040615a..21c9d70 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -80,9 +80,27 @@
>  #define GICR_MOVALLR			0x0110
>  #define GICR_PIDR2			GICD_PIDR2
>  
> +#define GICR_CTLR_ENABLE_LPIS		(1UL << 0)
> +
> +#define GICR_TYPER_CPU_NUMBER(r)	(((r) >> 8) & 0xffff)
> +
>  #define GICR_WAKER_ProcessorSleep	(1U << 1)
>  #define GICR_WAKER_ChildrenAsleep	(1U << 2)
>  
> +#define GICR_PROPBASER_NonShareable	(0U << 10)
> +#define GICR_PROPBASER_InnerShareable	(1U << 10)
> +#define GICR_PROPBASER_OuterShareable	(2U << 10)
> +#define GICR_PROPBASER_SHAREABILITY_MASK (3UL << 10)
> +#define GICR_PROPBASER_nCnB		(0U << 7)
> +#define GICR_PROPBASER_nC		(1U << 7)
> +#define GICR_PROPBASER_RaWt		(2U << 7)
> +#define GICR_PROPBASER_RaWb		(3U << 7)
> +#define GICR_PROPBASER_WaWt		(4U << 7)
> +#define GICR_PROPBASER_WaWb		(5U << 7)
> +#define GICR_PROPBASER_RaWaWt		(6U << 7)
> +#define GICR_PROPBASER_RaWaWb		(7U << 7)
> +#define GICR_PROPBASER_IDBITS_MASK	(0x1f)
> +
>  /*
>   * Re-Distributor registers, offsets from SGI_base
>   */
> @@ -95,9 +113,93 @@
>  #define GICR_IPRIORITYR0		GICD_IPRIORITYR
>  #define GICR_ICFGR0			GICD_ICFGR
>  
> +#define GICR_TYPER_PLPIS		(1U << 0)
>  #define GICR_TYPER_VLPIS		(1U << 1)
>  #define GICR_TYPER_LAST			(1U << 4)
>  
> +#define LPI_PROP_GROUP1			(1 << 1)
> +#define LPI_PROP_ENABLED		(1 << 0)
> +
> +/*
> + * ITS registers, offsets from ITS_base
> + */
> +#define GITS_CTLR			0x0000
> +#define GITS_IIDR			0x0004
> +#define GITS_TYPER			0x0008
> +#define GITS_CBASER			0x0080
> +#define GITS_CWRITER			0x0088
> +#define GITS_CREADR			0x0090
> +#define GITS_BASER			0x0100
> +#define GITS_PIDR2			GICR_PIDR2
> +
> +#define GITS_TRANSLATER			0x10040
> +
> +#define GITS_TYPER_PTA			(1UL << 19)
> +
> +#define GITS_CBASER_VALID		(1UL << 63)
> +#define GITS_CBASER_nCnB		(0UL << 59)
> +#define GITS_CBASER_nC			(1UL << 59)
> +#define GITS_CBASER_RaWt		(2UL << 59)
> +#define GITS_CBASER_RaWb		(3UL << 59)
> +#define GITS_CBASER_WaWt		(4UL << 59)
> +#define GITS_CBASER_WaWb		(5UL << 59)
> +#define GITS_CBASER_RaWaWt		(6UL << 59)
> +#define GITS_CBASER_RaWaWb		(7UL << 59)
> +#define GITS_CBASER_NonShareable	(0UL << 10)
> +#define GITS_CBASER_InnerShareable	(1UL << 10)
> +#define GITS_CBASER_OuterShareable	(2UL << 10)
> +#define GITS_CBASER_SHAREABILITY_MASK	(3UL << 10)
> +
> +#define GITS_BASER_NR_REGS		8
> +
> +#define GITS_BASER_VALID		(1UL << 63)
> +#define GITS_BASER_nCnB			(0UL << 59)
> +#define GITS_BASER_nC			(1UL << 59)
> +#define GITS_BASER_RaWt			(2UL << 59)
> +#define GITS_BASER_RaWb			(3UL << 59)
> +#define GITS_BASER_WaWt			(4UL << 59)
> +#define GITS_BASER_WaWb			(5UL << 59)
> +#define GITS_BASER_RaWaWt		(6UL << 59)
> +#define GITS_BASER_RaWaWb		(7UL << 59)
> +#define GITS_BASER_TYPE_SHIFT		(56)
> +#define GITS_BASER_TYPE(r)		(((r) >> GITS_BASER_TYPE_SHIFT) & 7)
> +#define GITS_BASER_ENTRY_SIZE_SHIFT	(48)
> +#define GITS_BASER_ENTRY_SIZE(r)	((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1)
> +#define GITS_BASER_NonShareable		(0UL << 10)
> +#define GITS_BASER_InnerShareable	(1UL << 10)
> +#define GITS_BASER_OuterShareable	(2UL << 10)
> +#define GITS_BASER_SHAREABILITY_SHIFT	(10)
> +#define GITS_BASER_SHAREABILITY_MASK	(3UL << GITS_BASER_SHAREABILITY_SHIFT)
> +#define GITS_BASER_PAGE_SIZE_SHIFT	(8)
> +#define GITS_BASER_PAGE_SIZE_4K		(0UL << GITS_BASER_PAGE_SIZE_SHIFT)
> +#define GITS_BASER_PAGE_SIZE_16K	(1UL << GITS_BASER_PAGE_SIZE_SHIFT)
> +#define GITS_BASER_PAGE_SIZE_64K	(2UL << GITS_BASER_PAGE_SIZE_SHIFT)
> +#define GITS_BASER_PAGE_SIZE_MASK	(3UL << GITS_BASER_PAGE_SIZE_SHIFT)
> +
> +#define GITS_BASER_TYPE_NONE		0
> +#define GITS_BASER_TYPE_DEVICE		1
> +#define GITS_BASER_TYPE_VCPU		2
> +#define GITS_BASER_TYPE_CPU		3
> +#define GITS_BASER_TYPE_COLLECTION	4
> +#define GITS_BASER_TYPE_RESERVED5	5
> +#define GITS_BASER_TYPE_RESERVED6	6
> +#define GITS_BASER_TYPE_RESERVED7	7
> +
> +/*
> + * ITS commands
> + */
> +#define GITS_CMD_MAPD			0x08
> +#define GITS_CMD_MAPC			0x09
> +#define GITS_CMD_MAPVI			0x0a
> +#define GITS_CMD_MOVI			0x01
> +#define GITS_CMD_DISCARD		0x0f
> +#define GITS_CMD_INV			0x0c
> +#define GITS_CMD_MOVALL			0x0e
> +#define GITS_CMD_INVALL			0x0d
> +#define GITS_CMD_INT			0x03
> +#define GITS_CMD_CLEAR			0x04
> +#define GITS_CMD_SYNC			0x05
> +
>  /*
>   * CPU interface registers
>   */




  reply	other threads:[~2014-12-10  3:03 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-24 14:35 [PATCH v3 00/13] arm64: PCI/MSI: GICv3 ITS support (stacked domain edition) Marc Zyngier
2014-11-24 14:35 ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 01/13] arm64: PCI/MSI: Use asm-generic/msi.h Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 02/13] irqchip: GICv3: Convert to domain hierarchy Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 03/13] irqchip: GICv3: rework redistributor structure Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 04/13] irqchip: GICv3: ITS command queue Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-12-10  3:03   ` Yun Wu (Abel) [this message]
2014-12-10  3:03     ` Yun Wu (Abel)
2014-12-10 11:20     ` Marc Zyngier
2014-12-10 11:20       ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 05/13] irqchip: GICv3: ITS: irqchip implementation Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 06/13] irqchip: GICv3: ITS: LPI allocator Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-11-24 14:57   ` Jiang Liu
2014-11-24 14:57     ` Jiang Liu
2014-11-24 15:32     ` Marc Zyngier
2014-11-24 15:32       ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 07/13] irqchip: GICv3: ITS: tables allocators Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 08/13] irqchip: GICv3: ITS: device allocation and configuration Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 09/13] irqchip: GICv3: ITS: MSI support Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-12-04 21:52   ` Stuart Yoder
2014-12-04 21:52     ` Stuart Yoder
2014-12-04 21:58     ` Thomas Gleixner
2014-12-04 21:58       ` Thomas Gleixner
2014-12-05 10:10     ` Marc Zyngier
2014-12-05 10:10       ` Marc Zyngier
2014-12-08  3:28   ` Yun Wu (Abel)
2014-12-08  3:28     ` Yun Wu (Abel)
2014-12-08  9:32     ` Marc Zyngier
2014-12-08  9:32       ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 10/13] irqchip: GICv3: ITS: DT probing and initialization Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-11-25 21:08   ` Stuart Yoder
2014-11-25 21:08     ` Stuart Yoder
2014-11-26 10:14     ` Marc Zyngier
2014-11-26 10:14       ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 11/13] irqchip: GICv3: ITS: plug ITS init into main GICv3 code Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 12/13] irqchip: GICv3: ITS: enable compilation of the ITS driver Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-11-24 14:35 ` [PATCH v3 13/13] irqchip: GICv3: Binding updates for ITS Marc Zyngier
2014-11-24 14:35   ` Marc Zyngier
2014-11-26  8:06 ` [PATCH v3 00/13] arm64: PCI/MSI: GICv3 ITS support (stacked domain edition) Jason Cooper
2014-11-26  8:06   ` Jason Cooper

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5487B7E5.2080104@huawei.com \
    --to=wuyun.wu@huawei.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.