forked from Mirrors/opensbi
		
	lib: ipi: Adjust Andes PLICSW to single-bit-per-hart scheme
The old scheme doesn't allow sending hart0 self-IPI as the
corresponding bit on pending register is hardwired to 0, this
could lead to unhandle IPIs on SMP systems, esp. on single-core.
Furthermore, the limitation of old scheme is 8-core, instead of
reserving source hart information, we assign bit (x + 1) as the
enable and pending bit of hartx, this also expands the bootable
hart number.
The following diagram shows the enable bits of the new scheme
on 32-core Andes platform.
   Pending regs: 0x1000  x---0---0---0---0------0---0
Pending hart ID:             0   1   2   3 ... 30  31
   Interrupt ID:         0   1   2   3   4 ... 31  32
                         |   |   |   |   |      |   |
    Enable regs: 0x2000  x---1---0---0---0-...--0---0---> hart0
                         |   |   |   |   |      |   |
                 0x2080  x---0---1---0---0-...--0---0---> hart1
                         |   |   |   |   |      |   |
                 0x2100  x---0---0---1---0-...--0---0---> hart2
                         |   |   |   |   |      |   |
                 0x2180  x---0---0---0---1-...--0---0---> hart3
                         .   .   .   .   .      .   .
                         .   .   .   .   .      .   .
                         .   .   .   .   .      .   .
                 0x2f00  x---0---0---0---0-...--1---0---> hart30
                         |   |   |   |   |      |   |
                 0x2f80  x---0---0---0---0-...--0---1---> hart31
                         <-------- word 0 -------><--- word 1 --->
To send IPI to hart0, for example, another hart (including hart0
itself) will set bit 1 of first word on the pending register.
We also fix indentation in andes_plicsw.h along with this patch.
Fixes: ce7c490719 ("lib: utils/ipi: Add Andes fdt ipi driver support")
Signed-off-by: Leo Yu-Chi Liang <ycliang@andestech.com>
Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Randolph <randolph@andestech.com>
Reported-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Link: https://lists.infradead.org/pipermail/opensbi/2023-October/005665.html
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
			
			
This commit is contained in:
		
				
					committed by
					
						
						Anup Patel
					
				
			
			
				
	
			
			
			
						parent
						
							b70d6285f0
						
					
				
				
					commit
					bd74931d79
				
			@@ -13,30 +13,23 @@
 | 
			
		||||
#ifndef _IPI_ANDES_PLICSW_H_
 | 
			
		||||
#define _IPI_ANDES_PLICSW_H_
 | 
			
		||||
 | 
			
		||||
#define PLICSW_PRIORITY_BASE 0x4
 | 
			
		||||
#define PLICSW_PRIORITY_BASE	0x4
 | 
			
		||||
 | 
			
		||||
#define PLICSW_PENDING_BASE 0x1000
 | 
			
		||||
#define PLICSW_PENDING_STRIDE 0x8
 | 
			
		||||
#define PLICSW_PENDING_BASE	0x1000
 | 
			
		||||
 | 
			
		||||
#define PLICSW_ENABLE_BASE 0x2000
 | 
			
		||||
#define PLICSW_ENABLE_STRIDE 0x80
 | 
			
		||||
#define PLICSW_ENABLE_BASE	0x2000
 | 
			
		||||
#define PLICSW_ENABLE_STRIDE	0x80
 | 
			
		||||
 | 
			
		||||
#define PLICSW_CONTEXT_BASE 0x200000
 | 
			
		||||
#define PLICSW_CONTEXT_STRIDE 0x1000
 | 
			
		||||
#define PLICSW_CONTEXT_CLAIM 0x4
 | 
			
		||||
#define PLICSW_CONTEXT_BASE	0x200000
 | 
			
		||||
#define PLICSW_CONTEXT_STRIDE	0x1000
 | 
			
		||||
#define PLICSW_CONTEXT_CLAIM	0x4
 | 
			
		||||
 | 
			
		||||
#define PLICSW_HART_MASK 0x01010101
 | 
			
		||||
 | 
			
		||||
#define PLICSW_HART_MAX_NR 8
 | 
			
		||||
 | 
			
		||||
#define PLICSW_REGION_ALIGN 0x1000
 | 
			
		||||
#define PLICSW_REGION_ALIGN	0x1000
 | 
			
		||||
 | 
			
		||||
struct plicsw_data {
 | 
			
		||||
	unsigned long addr;
 | 
			
		||||
	unsigned long size;
 | 
			
		||||
	uint32_t hart_count;
 | 
			
		||||
	/* hart id to source id table */
 | 
			
		||||
	uint32_t source_id[PLICSW_HART_MAX_NR];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int plicsw_warm_ipi_init(void);
 | 
			
		||||
 
 | 
			
		||||
@@ -18,77 +18,45 @@
 | 
			
		||||
 | 
			
		||||
struct plicsw_data plicsw;
 | 
			
		||||
 | 
			
		||||
static inline void plicsw_claim(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 hartid = current_hartid();
 | 
			
		||||
 | 
			
		||||
	if (plicsw.hart_count <= hartid)
 | 
			
		||||
		ebreak();
 | 
			
		||||
 | 
			
		||||
	plicsw.source_id[hartid] =
 | 
			
		||||
		readl((void *)plicsw.addr + PLICSW_CONTEXT_BASE +
 | 
			
		||||
		      PLICSW_CONTEXT_CLAIM + PLICSW_CONTEXT_STRIDE * hartid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void plicsw_complete(void)
 | 
			
		||||
{
 | 
			
		||||
	u32 hartid = current_hartid();
 | 
			
		||||
	u32 source = plicsw.source_id[hartid];
 | 
			
		||||
 | 
			
		||||
	writel(source, (void *)plicsw.addr + PLICSW_CONTEXT_BASE +
 | 
			
		||||
			       PLICSW_CONTEXT_CLAIM +
 | 
			
		||||
			       PLICSW_CONTEXT_STRIDE * hartid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void plic_sw_pending(u32 target_hart)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * The pending array registers are w1s type.
 | 
			
		||||
	 * IPI pending array mapping as following:
 | 
			
		||||
	 *
 | 
			
		||||
	 * Pending array start address: base + 0x1000
 | 
			
		||||
	 * ---------------------------------
 | 
			
		||||
	 * | hart3 | hart2 | hart1 | hart0 |
 | 
			
		||||
	 * ---------------------------------
 | 
			
		||||
	 * Each hartX can send IPI to another hart by setting the
 | 
			
		||||
	 * bitY to its own region (see the below).
 | 
			
		||||
	 *
 | 
			
		||||
	 * In each hartX region:
 | 
			
		||||
	 * <---------- PICSW_PENDING_STRIDE -------->
 | 
			
		||||
	 * | bit7 | ... | bit3 | bit2 | bit1 | bit0 |
 | 
			
		||||
	 * ------------------------------------------
 | 
			
		||||
	 * The bitY of hartX region indicates that hartX sends an
 | 
			
		||||
	 * IPI to hartY.
 | 
			
		||||
	 */
 | 
			
		||||
	u32 hartid	    = current_hartid();
 | 
			
		||||
	u32 word_index	    = hartid / 4;
 | 
			
		||||
	u32 per_hart_offset = PLICSW_PENDING_STRIDE * hartid;
 | 
			
		||||
	u32 val		    = 1 << target_hart << per_hart_offset;
 | 
			
		||||
 | 
			
		||||
	writel(val, (void *)plicsw.addr + PLICSW_PENDING_BASE + word_index * 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void plicsw_ipi_send(u32 hart_index)
 | 
			
		||||
{
 | 
			
		||||
	ulong pending_reg;
 | 
			
		||||
	u32 interrupt_id, word_index, pending_bit;
 | 
			
		||||
	u32 target_hart = sbi_hartindex_to_hartid(hart_index);
 | 
			
		||||
 | 
			
		||||
	if (plicsw.hart_count <= target_hart)
 | 
			
		||||
		ebreak();
 | 
			
		||||
 | 
			
		||||
	/* Set PLICSW IPI */
 | 
			
		||||
	plic_sw_pending(target_hart);
 | 
			
		||||
	/*
 | 
			
		||||
	 * We assign a single bit for each hart.
 | 
			
		||||
	 * Bit 0 is hardwired to 0, thus unavailable.
 | 
			
		||||
	 * Bit(X+1) indicates that IPI is sent to hartX.
 | 
			
		||||
	 */
 | 
			
		||||
	interrupt_id = target_hart + 1;
 | 
			
		||||
	word_index   = interrupt_id / 32;
 | 
			
		||||
	pending_bit  = interrupt_id % 32;
 | 
			
		||||
	pending_reg  = plicsw.addr + PLICSW_PENDING_BASE + word_index * 4;
 | 
			
		||||
 | 
			
		||||
	/* Set target hart's mip.MSIP */
 | 
			
		||||
	writel_relaxed(BIT(pending_bit), (void *)pending_reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void plicsw_ipi_clear(u32 hart_index)
 | 
			
		||||
{
 | 
			
		||||
	u32 target_hart = sbi_hartindex_to_hartid(hart_index);
 | 
			
		||||
	ulong reg = plicsw.addr + PLICSW_CONTEXT_BASE + PLICSW_CONTEXT_CLAIM +
 | 
			
		||||
		    PLICSW_CONTEXT_STRIDE * target_hart;
 | 
			
		||||
 | 
			
		||||
	if (plicsw.hart_count <= target_hart)
 | 
			
		||||
		ebreak();
 | 
			
		||||
 | 
			
		||||
	/* Clear PLICSW IPI */
 | 
			
		||||
	plicsw_claim();
 | 
			
		||||
	plicsw_complete();
 | 
			
		||||
	/* Claim */
 | 
			
		||||
	u32 source = readl((void *)reg);
 | 
			
		||||
 | 
			
		||||
	/* A successful claim will clear mip.MSIP */
 | 
			
		||||
 | 
			
		||||
	/* Complete */
 | 
			
		||||
	writel(source, (void *)reg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct sbi_ipi_device plicsw_ipi = {
 | 
			
		||||
@@ -110,22 +78,26 @@ int plicsw_warm_ipi_init(void)
 | 
			
		||||
int plicsw_cold_ipi_init(struct plicsw_data *plicsw)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	u32 interrupt_id, word_index, enable_bit;
 | 
			
		||||
	ulong enable_reg, priority_reg;
 | 
			
		||||
 | 
			
		||||
	/* Setup source priority */
 | 
			
		||||
	uint32_t *priority = (void *)plicsw->addr + PLICSW_PRIORITY_BASE;
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < plicsw->hart_count; i++)
 | 
			
		||||
		writel(1, &priority[i]);
 | 
			
		||||
 | 
			
		||||
	/* Setup target enable */
 | 
			
		||||
	uint32_t enable_mask = PLICSW_HART_MASK;
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < plicsw->hart_count; i++) {
 | 
			
		||||
		uint32_t *enable = (void *)plicsw->addr + PLICSW_ENABLE_BASE +
 | 
			
		||||
				   PLICSW_ENABLE_STRIDE * i;
 | 
			
		||||
		writel(enable_mask, enable);
 | 
			
		||||
		writel(enable_mask, enable + 1);
 | 
			
		||||
		enable_mask <<= 1;
 | 
			
		||||
		priority_reg = plicsw->addr + PLICSW_PRIORITY_BASE + i * 4;
 | 
			
		||||
		writel(1, (void *)priority_reg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Setup enable for each hart, skip non-existent interrupt ID 0
 | 
			
		||||
	 * which is hardwired to 0.
 | 
			
		||||
	 */
 | 
			
		||||
	for (int i = 0; i < plicsw->hart_count; i++) {
 | 
			
		||||
		interrupt_id = i + 1;
 | 
			
		||||
		word_index   = interrupt_id / 32;
 | 
			
		||||
		enable_bit   = interrupt_id % 32;
 | 
			
		||||
		enable_reg   = plicsw->addr + PLICSW_ENABLE_BASE +
 | 
			
		||||
			       PLICSW_ENABLE_STRIDE * i + 4 * word_index;
 | 
			
		||||
		writel(BIT(enable_bit), (void *)enable_reg);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Add PLICSW region to the root domain */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user