1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * This software may be distributed and modified according to the terms of 5 * the GNU General Public License version 2. Note that NO WARRANTY is provided. 6 * See "LICENSE_GPLv2.txt" for details. 7 * 8 * @TAG(GD_GPL) 9 */ 10 11#include <config.h> 12 13#include <linker.h> 14#include <machine/io.h> 15#include <plat/machine/hardware.h> 16#include <plat/machine/ioapic.h> 17 18#define IOAPIC_REGSEL 0x00 19#define IOAPIC_WINDOW 0x10 20 21#define IOAPIC_REG_IOAPICID 0x00 22#define IOAPIC_REG_IOREDTBL 0x10 23 24#define IOREDTBL_LOW(reg) (IOAPIC_REG_IOREDTBL + (reg) * 2) 25#define IOREDTBL_HIGH(reg) (IOREDTBL_LOW(reg) + 1) 26 27#define IOREDTBL_LOW_INTERRUPT_MASK BIT(16) 28#define IOREDTBL_LOW_TRIGGER_MODE_LEVEL BIT(15) 29#define IOREDTBL_LOW_TRIGGER_MODE_SHIFT 15 30#define IOREDTBL_LOW_POLARITY_LOW BIT(13) 31#define IOREDTBL_LOW_POLARITY_SHIFT 13 32#define IOREDTBL_LOW_DEST_MODE_LOGCIAL BIT(11) 33 34#define IOAPICID_ID_BITS 4 35#define IOAPICID_ID_OFFSET 24 36 37#define IOREDTBL_HIGH_RESERVED_BITS 24 38 39/* Cache what we believe is in the low word of the IOREDTBL. This 40 * has all the state of trigger modes etc etc */ 41static uint32_t ioredtbl_state[IOAPIC_IRQ_LINES * CONFIG_MAX_NUM_IOAPIC]; 42 43/* Number of IOAPICs in the system */ 44static uint32_t num_ioapics = 0; 45 46static void ioapic_write(uint32_t ioapic, word_t reg, uint32_t value) 47{ 48 *(volatile uint32_t*)((word_t)(PPTR_IOAPIC_START + ioapic * BIT(PAGE_BITS)) + reg) = value; 49} 50 51static uint32_t ioapic_read(uint32_t ioapic, word_t reg) 52{ 53 return *(volatile uint32_t*)((word_t)(PPTR_IOAPIC_START + ioapic * BIT(PAGE_BITS)) + reg); 54} 55 56static void single_ioapic_init(word_t ioapic, cpu_id_t delivery_cpu) 57{ 58 uint32_t i; 59 60 /* Mask all the IRQs. In doing so we happen to set 61 * the vector to 0, which we can assert against in 62 * mask_interrupt to ensure a vector is assigned 63 * before we unmask */ 64 for (i = 0; i < IOAPIC_IRQ_LINES; i++) { 65 /* Send to desired cpu */ 66 ioapic_write(ioapic, IOAPIC_REGSEL, IOREDTBL_HIGH(i)); 67 ioapic_write(ioapic, IOAPIC_WINDOW, (ioapic_read(ioapic, IOAPIC_WINDOW) & MASK(IOREDTBL_HIGH_RESERVED_BITS)) | (delivery_cpu << IOREDTBL_HIGH_RESERVED_BITS)); 68 /* mask and set 0 vector */ 69 ioredtbl_state[i] = IOREDTBL_LOW_INTERRUPT_MASK; 70 ioapic_write(ioapic, IOAPIC_REGSEL, IOREDTBL_LOW(i)); 71 /* The upper 16 bits are reserved, so we make sure to preserve them */ 72 ioredtbl_state[i] |= ioapic_read(ioapic, IOAPIC_WINDOW) & ~MASK(16); 73 ioapic_write(ioapic, IOAPIC_WINDOW, ioredtbl_state[i]); 74 } 75} 76 77static cpu_id_t ioapic_target_cpu = 0; 78void ioapic_init(uint32_t num_nodes, cpu_id_t *cpu_list, uint32_t num_ioapic) 79{ 80 uint32_t ioapic; 81 num_ioapics = num_ioapic; 82 ioapic_target_cpu = cpu_list[0]; 83 84 for (ioapic = 0; ioapic < num_ioapic; ioapic++) { 85 /* Init this ioapic */ 86 single_ioapic_init(ioapic, cpu_list[0]); 87 } 88} 89 90void ioapic_mask(bool_t mask, uint32_t ioapic, uint32_t pin) 91{ 92 int index = ioapic * IOAPIC_IRQ_LINES + pin; 93 if (ioapic >= num_ioapics || pin >= IOAPIC_IRQ_LINES) { 94 /* silently ignore requests to non existent parts of the interrupt space */ 95 return; 96 } 97 if (mask) { 98 ioredtbl_state[index] |= IOREDTBL_LOW_INTERRUPT_MASK; 99 } else { 100 ioredtbl_state[index] &= ~IOREDTBL_LOW_INTERRUPT_MASK; 101 /* it should not be possible to be unmasking an interrupt, without 102 * it having been mapped to a vector, assert that this is the case */ 103 assert((ioredtbl_state[index] & 0xff) != 0); 104 } 105 ioapic_write(ioapic, IOAPIC_REGSEL, IOREDTBL_LOW(pin)); 106 ioapic_write(ioapic, IOAPIC_WINDOW, ioredtbl_state[index]); 107} 108 109exception_t ioapic_decode_map_pin_to_vector(word_t ioapic, word_t pin, word_t level, 110 word_t polarity, word_t vector) 111{ 112 if (num_ioapics == 0) { 113 userError("System has no IOAPICs"); 114 current_syscall_error.type = seL4_IllegalOperation; 115 return EXCEPTION_SYSCALL_ERROR; 116 } 117 if (ioapic >= num_ioapics) { 118 userError("Invalid IOAPIC %ld, only have %ld", (long)ioapic, (long)num_ioapics); 119 current_syscall_error.type = seL4_RangeError; 120 current_syscall_error.rangeErrorMin = 0; 121 current_syscall_error.rangeErrorMax = num_ioapics - 1; 122 return EXCEPTION_SYSCALL_ERROR; 123 } 124 if (pin >= IOAPIC_IRQ_LINES) { 125 userError("Invalid IOAPIC pin %ld, there are %d pins", (long)pin, IOAPIC_IRQ_LINES); 126 current_syscall_error.type = seL4_RangeError; 127 current_syscall_error.rangeErrorMin = 0; 128 current_syscall_error.rangeErrorMax = IOAPIC_IRQ_LINES - 1; 129 return EXCEPTION_SYSCALL_ERROR; 130 } 131 132 if (level != 0 && level != 1) { 133 userError("Level should be 0 or 1, not %d", (int)level); 134 current_syscall_error.type = seL4_RangeError; 135 current_syscall_error.rangeErrorMin = 0; 136 current_syscall_error.rangeErrorMax = 1; 137 return EXCEPTION_SYSCALL_ERROR; 138 } 139 if (polarity != 0 && polarity != 1) { 140 userError("Polarity should be 0 or 1, not %d", (int)polarity); 141 current_syscall_error.type = seL4_RangeError; 142 current_syscall_error.rangeErrorMin = 0; 143 current_syscall_error.rangeErrorMax = 1; 144 return EXCEPTION_SYSCALL_ERROR; 145 } 146 return EXCEPTION_NONE; 147} 148 149void ioapic_map_pin_to_vector(word_t ioapic, word_t pin, word_t level, 150 word_t polarity, word_t vector) 151{ 152 uint32_t ioredtbl_high = 0; 153 uint32_t index = 0; 154 155 index = ioapic * IOAPIC_IRQ_LINES + pin; 156 ioapic_write(ioapic, IOAPIC_REGSEL, IOREDTBL_HIGH(pin)); 157 ioredtbl_high = ioapic_read(ioapic, IOAPIC_WINDOW) & MASK(IOREDTBL_HIGH_RESERVED_BITS); 158 /* delivery mode: physical mode only, using APIC ID */ 159 ioredtbl_high |= (ioapic_target_cpu << IOREDTBL_HIGH_RESERVED_BITS); 160 ioapic_write(ioapic, IOAPIC_WINDOW, ioredtbl_high); 161 /* we do not need to add IRQ_INT_OFFSET to the vector here */ 162 ioredtbl_state[index] = IOREDTBL_LOW_INTERRUPT_MASK | 163 (level << IOREDTBL_LOW_TRIGGER_MODE_SHIFT) | 164 (polarity << IOREDTBL_LOW_POLARITY_SHIFT) | 165 vector; 166 167 ioapic_write(ioapic, IOAPIC_REGSEL, IOREDTBL_LOW(pin)); 168 /* the upper 16 bits are reserved */ 169 ioredtbl_state[index] |= ioapic_read(ioapic, IOAPIC_WINDOW) & ~MASK(16); 170 ioapic_write(ioapic, IOAPIC_WINDOW, ioredtbl_state[index]); 171} 172