forked from cores/microwatt
				
			XICS test case
Checks interrupt masking and priorities. Adds to `make test_xics` which is run in `make check` also. Signed-off-by: Michael Neuling <mikey@neuling.org>jtag-port
							parent
							
								
									b4f20c20b9
								
							
						
					
					
						commit
						0076f8bf1d
					
				
											
												Binary file not shown.
											
										
									
								@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					Test 0:PASS
 | 
				
			||||||
 | 
					Test 1:PASS
 | 
				
			||||||
 | 
					Test 2:PASS
 | 
				
			||||||
@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					TEST=xics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include ../Makefile.test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					xics.o : xics.h
 | 
				
			||||||
@ -0,0 +1,186 @@
 | 
				
			|||||||
 | 
					/* Copyright 2013-2014 IBM Corp.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 	http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
				
			||||||
 | 
					 * implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define STACK_TOP 0x4000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Load an immediate 64-bit value into a register */
 | 
				
			||||||
 | 
					#define LOAD_IMM64(r, e)			\
 | 
				
			||||||
 | 
						lis     r,(e)@highest;			\
 | 
				
			||||||
 | 
						ori     r,r,(e)@higher;			\
 | 
				
			||||||
 | 
						rldicr  r,r, 32, 31;			\
 | 
				
			||||||
 | 
						oris    r,r, (e)@h;			\
 | 
				
			||||||
 | 
						ori     r,r, (e)@l;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.section ".head","ax"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Microwatt currently enters in LE mode at 0x0 */
 | 
				
			||||||
 | 
						. = 0
 | 
				
			||||||
 | 
					.global _start
 | 
				
			||||||
 | 
					_start:
 | 
				
			||||||
 | 
						LOAD_IMM64(%r12, 0x000000000ffffff)
 | 
				
			||||||
 | 
						mtdec	%r12
 | 
				
			||||||
 | 
						LOAD_IMM64(%r12, 0x9000000000008003)
 | 
				
			||||||
 | 
						mtmsrd	%r12	// EE on
 | 
				
			||||||
 | 
						/* setup stack */
 | 
				
			||||||
 | 
						LOAD_IMM64(%r1, STACK_TOP - 0x100)
 | 
				
			||||||
 | 
						LOAD_IMM64(%r12, main)
 | 
				
			||||||
 | 
						mtctr	%r12
 | 
				
			||||||
 | 
						bctrl
 | 
				
			||||||
 | 
						attn // terminate on exit
 | 
				
			||||||
 | 
						b .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define EXCEPTION(nr)		\
 | 
				
			||||||
 | 
						.= nr			;\
 | 
				
			||||||
 | 
						b	.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* More exception stubs */
 | 
				
			||||||
 | 
						EXCEPTION(0x300)
 | 
				
			||||||
 | 
						EXCEPTION(0x380)
 | 
				
			||||||
 | 
						EXCEPTION(0x400)
 | 
				
			||||||
 | 
						EXCEPTION(0x480)
 | 
				
			||||||
 | 
						. = 0x500
 | 
				
			||||||
 | 
						b	__isr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EXCEPTION(0x600)
 | 
				
			||||||
 | 
						EXCEPTION(0x700)
 | 
				
			||||||
 | 
						EXCEPTION(0x800)
 | 
				
			||||||
 | 
						EXCEPTION(0x900)
 | 
				
			||||||
 | 
						EXCEPTION(0x980)
 | 
				
			||||||
 | 
						EXCEPTION(0xa00)
 | 
				
			||||||
 | 
						EXCEPTION(0xb00)
 | 
				
			||||||
 | 
						EXCEPTION(0xc00)
 | 
				
			||||||
 | 
						EXCEPTION(0xd00)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//  ISR data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define REDZONE_SIZE    (512)
 | 
				
			||||||
 | 
					#define REG_SAVE_SIZE	((32 + 5)*8)
 | 
				
			||||||
 | 
					#define STACK_FRAME_C_MINIMAL   64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SAVE_NIA	(32*8)
 | 
				
			||||||
 | 
					#define SAVE_LR		(33*8)
 | 
				
			||||||
 | 
					#define SAVE_CTR	(34*8)
 | 
				
			||||||
 | 
					#define SAVE_CR		(35*8)
 | 
				
			||||||
 | 
					#define SAVE_SRR1	(36*8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__isr:
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Assume where we are coming from has a stack and can save there.
 | 
				
			||||||
 | 
					 * We save the full register set. Since we are calling out to C, we
 | 
				
			||||||
 | 
					 * could just save the ABI volatile registers
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
						stdu	%r1,-(REG_SAVE_SIZE+REDZONE_SIZE)(%r1)
 | 
				
			||||||
 | 
						std	%r0,   1*8(%r1)
 | 
				
			||||||
 | 
					//	std	%r1,   1*8(%r1)
 | 
				
			||||||
 | 
						std	%r2,   2*8(%r1)
 | 
				
			||||||
 | 
						std	%r3,   3*8(%r1)
 | 
				
			||||||
 | 
						std	%r4,   4*8(%r1)
 | 
				
			||||||
 | 
						std	%r5,   5*8(%r1)
 | 
				
			||||||
 | 
						std	%r6,   6*8(%r1)
 | 
				
			||||||
 | 
						std	%r7,   7*8(%r1)
 | 
				
			||||||
 | 
						std	%r8,   8*8(%r1)
 | 
				
			||||||
 | 
						std	%r9,   9*8(%r1)
 | 
				
			||||||
 | 
						std	%r10, 10*8(%r1)
 | 
				
			||||||
 | 
						std	%r11, 11*8(%r1)
 | 
				
			||||||
 | 
						std	%r12, 12*8(%r1)
 | 
				
			||||||
 | 
						std	%r13, 13*8(%r1)
 | 
				
			||||||
 | 
						std	%r14, 14*8(%r1)
 | 
				
			||||||
 | 
						std	%r15, 15*8(%r1)
 | 
				
			||||||
 | 
						std	%r16, 16*8(%r1)
 | 
				
			||||||
 | 
						std	%r17, 17*8(%r1)
 | 
				
			||||||
 | 
						std	%r18, 18*8(%r1)
 | 
				
			||||||
 | 
						std	%r19, 19*8(%r1)
 | 
				
			||||||
 | 
						std	%r20, 20*8(%r1)
 | 
				
			||||||
 | 
						std	%r21, 21*8(%r1)
 | 
				
			||||||
 | 
						std	%r22, 22*8(%r1)
 | 
				
			||||||
 | 
						std	%r23, 23*8(%r1)
 | 
				
			||||||
 | 
						std	%r24, 24*8(%r1)
 | 
				
			||||||
 | 
						std	%r25, 25*8(%r1)
 | 
				
			||||||
 | 
						std	%r26, 26*8(%r1)
 | 
				
			||||||
 | 
						std	%r27, 27*8(%r1)
 | 
				
			||||||
 | 
						std	%r28, 28*8(%r1)
 | 
				
			||||||
 | 
						std	%r29, 29*8(%r1)
 | 
				
			||||||
 | 
						std	%r30, 30*8(%r1)
 | 
				
			||||||
 | 
						std	%r31, 31*8(%r1)
 | 
				
			||||||
 | 
						mfsrr0	%r0
 | 
				
			||||||
 | 
						std	%r0,  SAVE_NIA*8(%r1)
 | 
				
			||||||
 | 
						mflr	%r0
 | 
				
			||||||
 | 
						std	%r0,  SAVE_LR*8(%r1)
 | 
				
			||||||
 | 
						mfctr	%r0
 | 
				
			||||||
 | 
						std	%r0,  SAVE_CTR*8(%r1)
 | 
				
			||||||
 | 
						mfcr	%r0
 | 
				
			||||||
 | 
						std	%r0,  SAVE_CR*8(%r1)
 | 
				
			||||||
 | 
						mfsrr1	%r0
 | 
				
			||||||
 | 
						std	%r0,  SAVE_SRR1*8(%r1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stdu	%r1,-STACK_FRAME_C_MINIMAL(%r1)
 | 
				
			||||||
 | 
						LOAD_IMM64(%r3, isr)
 | 
				
			||||||
 | 
						mtctr	%r3,
 | 
				
			||||||
 | 
						bctrl
 | 
				
			||||||
 | 
						nop
 | 
				
			||||||
 | 
						ld	%r1, 0(%r1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ld	%r0,   1*8(%r1)
 | 
				
			||||||
 | 
					//	ld	%r1,   1*8(%r1) // do this at rfid
 | 
				
			||||||
 | 
						ld	%r2,   2*8(%r1)
 | 
				
			||||||
 | 
					//	ld	%r3,   3*8(%r1) // do this at rfid
 | 
				
			||||||
 | 
						ld	%r4,   4*8(%r1)
 | 
				
			||||||
 | 
						ld	%r5,   5*8(%r1)
 | 
				
			||||||
 | 
						ld	%r6,   6*8(%r1)
 | 
				
			||||||
 | 
						ld	%r7,   7*8(%r1)
 | 
				
			||||||
 | 
						ld	%r8,   8*8(%r1)
 | 
				
			||||||
 | 
						ld	%r9,   9*8(%r1)
 | 
				
			||||||
 | 
						ld	%r10, 10*8(%r1)
 | 
				
			||||||
 | 
						ld	%r11, 11*8(%r1)
 | 
				
			||||||
 | 
						ld	%r12, 12*8(%r1)
 | 
				
			||||||
 | 
						ld	%r13, 13*8(%r1)
 | 
				
			||||||
 | 
						ld	%r14, 14*8(%r1)
 | 
				
			||||||
 | 
						ld	%r15, 15*8(%r1)
 | 
				
			||||||
 | 
						ld	%r16, 16*8(%r1)
 | 
				
			||||||
 | 
						ld	%r17, 17*8(%r1)
 | 
				
			||||||
 | 
						ld	%r18, 18*8(%r1)
 | 
				
			||||||
 | 
						ld	%r19, 19*8(%r1)
 | 
				
			||||||
 | 
						ld	%r20, 20*8(%r1)
 | 
				
			||||||
 | 
						ld	%r21, 21*8(%r1)
 | 
				
			||||||
 | 
						ld	%r22, 22*8(%r1)
 | 
				
			||||||
 | 
						ld	%r23, 23*8(%r1)
 | 
				
			||||||
 | 
						ld	%r24, 24*8(%r1)
 | 
				
			||||||
 | 
						ld	%r25, 25*8(%r1)
 | 
				
			||||||
 | 
						ld	%r26, 26*8(%r1)
 | 
				
			||||||
 | 
						ld	%r27, 27*8(%r1)
 | 
				
			||||||
 | 
						ld	%r28, 28*8(%r1)
 | 
				
			||||||
 | 
						ld	%r29, 29*8(%r1)
 | 
				
			||||||
 | 
						ld	%r30, 30*8(%r1)
 | 
				
			||||||
 | 
						ld	%r31, 31*8(%r1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ld	%r3, SAVE_LR*8(%r1)
 | 
				
			||||||
 | 
						mtlr	%r3
 | 
				
			||||||
 | 
						ld	%r3, SAVE_CTR*8(%r1)
 | 
				
			||||||
 | 
						mtctr	%r3
 | 
				
			||||||
 | 
						ld	%r3, SAVE_CR*8(%r1)
 | 
				
			||||||
 | 
						mtcr	%r3
 | 
				
			||||||
 | 
						ld	%r3, SAVE_SRR1*8(%r1)
 | 
				
			||||||
 | 
						mtsrr1	%r3
 | 
				
			||||||
 | 
						ld	%r3, SAVE_NIA*8(%r1)
 | 
				
			||||||
 | 
						mtsrr0	%r3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* restore %r3 */
 | 
				
			||||||
 | 
						ld	%r3, 3*8(%r1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* do final fixup r1 */
 | 
				
			||||||
 | 
						ld	%r1, 0*8(%r1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rfid
 | 
				
			||||||
@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					SECTIONS
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						_start = .;
 | 
				
			||||||
 | 
						. = 0;
 | 
				
			||||||
 | 
						.head : {
 | 
				
			||||||
 | 
							KEEP(*(.head))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						. = 0x1000;
 | 
				
			||||||
 | 
						.text : { *(.text) }
 | 
				
			||||||
 | 
						. = 0x3000;
 | 
				
			||||||
 | 
						.data : { *(.data) }
 | 
				
			||||||
 | 
						.bss : { *(.bss) }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,262 @@
 | 
				
			|||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "console.h"
 | 
				
			||||||
 | 
					#include "xics.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef DEBUG
 | 
				
			||||||
 | 
					//#define DEBUG 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void print_number(unsigned int i) // only for i = 0-999
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int j, k, m;
 | 
				
			||||||
 | 
						bool zeros = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						k = 1000000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (m = 0; m < 10 ; m++) {
 | 
				
			||||||
 | 
							j = i/k;
 | 
				
			||||||
 | 
							if (m == 9) zeros = true;
 | 
				
			||||||
 | 
							if (zeros || (j != 0)) {
 | 
				
			||||||
 | 
							    putchar(48 + j);
 | 
				
			||||||
 | 
							    zeros = true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							i = i % k;
 | 
				
			||||||
 | 
							k = k / 10;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG
 | 
				
			||||||
 | 
					#define DEBUG_STR "\r\nDEBUG: "
 | 
				
			||||||
 | 
					void debug_print(int i)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						putstr(DEBUG_STR, strlen(DEBUG_STR));
 | 
				
			||||||
 | 
						print_number(i);
 | 
				
			||||||
 | 
						putstr("\r\n", 2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define debug_putstr(a, b) putstr(a,b)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define debug_putstr(a, b)
 | 
				
			||||||
 | 
					#define debug_print(i)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ASSERT_FAIL "() ASSERT_FAILURE!\r\n "
 | 
				
			||||||
 | 
					#define assert(cond)	\
 | 
				
			||||||
 | 
						if (!(cond))  { \
 | 
				
			||||||
 | 
							putstr(__FILE__, strlen(__FILE__)); \
 | 
				
			||||||
 | 
							putstr(":", 1);	    \
 | 
				
			||||||
 | 
							print_number(__LINE__);	\
 | 
				
			||||||
 | 
							putstr(":", 1);	    \
 | 
				
			||||||
 | 
							putstr(__FUNCTION__, strlen(__FUNCTION__));\
 | 
				
			||||||
 | 
							putstr(ASSERT_FAIL, strlen(ASSERT_FAIL)); \
 | 
				
			||||||
 | 
							__asm__ ("attn"); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					volatile uint64_t isrs_run;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ISR_IPI      0x0000000000000001
 | 
				
			||||||
 | 
					#define ISR_UART     0x0000000000000002
 | 
				
			||||||
 | 
					#define ISR_SPURIOUS 0x0000000000000004
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IPI "IPI\r\n"
 | 
				
			||||||
 | 
					void ipi_isr(void) {
 | 
				
			||||||
 | 
						debug_putstr(IPI, strlen(IPI));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isrs_run |= ISR_IPI;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define UART "UART\r\n"
 | 
				
			||||||
 | 
					void uart_isr(void) {
 | 
				
			||||||
 | 
						debug_putstr(UART, strlen(UART));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						potato_uart_irq_dis(); // disable interrupt to ack it
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isrs_run |= ISR_UART;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The hardware doesn't support this but it's part of XICS so add it.
 | 
				
			||||||
 | 
					#define SPURIOUS "SPURIOUS\r\n"
 | 
				
			||||||
 | 
					void spurious_isr(void) {
 | 
				
			||||||
 | 
						debug_putstr(SPURIOUS, strlen(SPURIOUS));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isrs_run |= ISR_SPURIOUS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct isr_op {
 | 
				
			||||||
 | 
						void (*func)(void);
 | 
				
			||||||
 | 
						int source_id;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct isr_op isr_table[] = {
 | 
				
			||||||
 | 
						{ .func = ipi_isr,  .source_id = 2 },
 | 
				
			||||||
 | 
						{ .func = uart_isr, .source_id = 16 },
 | 
				
			||||||
 | 
						{ .func = spurious_isr,  .source_id = 0 },
 | 
				
			||||||
 | 
						{ .func = NULL, .source_id = 0 }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ipi_running;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ISR "ISR XISR="
 | 
				
			||||||
 | 
					void isr(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct isr_op *op;
 | 
				
			||||||
 | 
						uint32_t xirr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(!ipi_running); // check we aren't reentrant
 | 
				
			||||||
 | 
						ipi_running = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xirr = xics_read32(XICS_XIRR); // read hardware irq source
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG
 | 
				
			||||||
 | 
						putstr(ISR, strlen(ISR));
 | 
				
			||||||
 | 
						print_number(xirr & 0xff);
 | 
				
			||||||
 | 
						putstr("\r\n", 2);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						op = isr_table;
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							assert(op->func); // didn't find isr
 | 
				
			||||||
 | 
							if (op->source_id == (xirr & 0x00ffffff)) {
 | 
				
			||||||
 | 
							    op->func();
 | 
				
			||||||
 | 
							    break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							op++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xics_write32(XICS_XIRR, xirr); // EOI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ipi_running = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*****************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int xics_test_0(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// setup
 | 
				
			||||||
 | 
						xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
				
			||||||
 | 
						isrs_run = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// trigger two interrupts
 | 
				
			||||||
 | 
						potato_uart_irq_en(); // cause 0x500 interrupt
 | 
				
			||||||
 | 
						xics_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// still masked, so shouldn't happen yet
 | 
				
			||||||
 | 
						assert(isrs_run == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// unmask IPI only
 | 
				
			||||||
 | 
						xics_write8(XICS_XIRR, 0x40);
 | 
				
			||||||
 | 
						assert(isrs_run == ISR_IPI);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// unmask UART
 | 
				
			||||||
 | 
						xics_write8(XICS_XIRR, 0xc0);
 | 
				
			||||||
 | 
						assert(isrs_run == (ISR_IPI | ISR_UART));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// cleanup
 | 
				
			||||||
 | 
						xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
				
			||||||
 | 
						isrs_run = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int xics_test_1(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// setup
 | 
				
			||||||
 | 
						xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
				
			||||||
 | 
						isrs_run = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xics_write8(XICS_XIRR, 0xff); // allow all interrupts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// should be none pending
 | 
				
			||||||
 | 
						assert(isrs_run == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// trigger both
 | 
				
			||||||
 | 
						potato_uart_irq_en(); // cause 0x500 interrupt
 | 
				
			||||||
 | 
						xics_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(isrs_run == (ISR_IPI | ISR_UART));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// cleanup
 | 
				
			||||||
 | 
						xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
				
			||||||
 | 
						isrs_run = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mtmsrd(uint64_t val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						__asm__ volatile("mtmsrd %0" : : "r" (val));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int xics_test_2(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// setup
 | 
				
			||||||
 | 
						xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
				
			||||||
 | 
						isrs_run = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// trigger interrupts with MSR[EE]=0 and show they are not run
 | 
				
			||||||
 | 
						mtmsrd(0x9000000000000003); // EE off
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xics_write8(XICS_XIRR, 0xff); // allow all interrupts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// trigger an IPI
 | 
				
			||||||
 | 
						xics_write8(XICS_MFRR, 0x05); // cause 0x500 interrupt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(isrs_run == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mtmsrd(0x9000000000008003); // EE on
 | 
				
			||||||
 | 
						assert(isrs_run == ISR_IPI);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// cleanup
 | 
				
			||||||
 | 
						xics_write8(XICS_XIRR, 0x00); // mask all interrupts
 | 
				
			||||||
 | 
						isrs_run = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TEST "Test "
 | 
				
			||||||
 | 
					#define PASS "PASS\r\n"
 | 
				
			||||||
 | 
					#define FAIL "FAIL\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int (*tests[])(void) = {
 | 
				
			||||||
 | 
						xics_test_0,
 | 
				
			||||||
 | 
						xics_test_1,
 | 
				
			||||||
 | 
						xics_test_2,
 | 
				
			||||||
 | 
						NULL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int fail = 0;
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
						int (*t)(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						potato_uart_init();
 | 
				
			||||||
 | 
						ipi_running = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* run the tests */
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							t = tests[i];
 | 
				
			||||||
 | 
							if (!t)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							putstr(TEST, strlen(TEST));
 | 
				
			||||||
 | 
							print_number(i);
 | 
				
			||||||
 | 
							putstr(": ", 1);
 | 
				
			||||||
 | 
							if (t() != 0) {
 | 
				
			||||||
 | 
								fail = 1;
 | 
				
			||||||
 | 
								putstr(FAIL, strlen(FAIL));
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								putstr(PASS, strlen(PASS));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							i++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return fail;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define XICS_BASE 0xc0004000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint64_t xics_base = XICS_BASE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define XICS_XIRR_POLL 0x0
 | 
				
			||||||
 | 
					#define XICS_XIRR      0x4
 | 
				
			||||||
 | 
					#define XICS_RESV      0x8
 | 
				
			||||||
 | 
					#define XICS_MFRR      0xC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t xics_read8(int offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint32_t val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__asm__ volatile("lbzcix %0,%1,%2" : "=r" (val) : "b" (xics_base), "r" (offset));
 | 
				
			||||||
 | 
						return val;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void xics_write8(int offset, uint8_t val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						__asm__ volatile("stbcix %0,%1,%2" : : "r" (val), "b" (xics_base), "r" (offset));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t xics_read32(int offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint32_t val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__asm__ volatile("lwzcix %0,%1,%2" : "=r" (val) : "b" (xics_base), "r" (offset));
 | 
				
			||||||
 | 
						return val;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void xics_write32(int offset, uint32_t val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						__asm__ volatile("stwcix %0,%1,%2" : : "r" (val), "b" (xics_base), "r" (offset));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
					Loading…
					
					
				
		Reference in New Issue