Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | // SPDX-License-Identifier: GPL-2.0 /* * From coreboot file of same name * * Copyright (C) 2008-2009 coresystems GmbH * Copyright (C) 2014 Google, Inc */ #include <log.h> #include <asm/io.h> #include <asm/lapic.h> #include <asm/msr.h> #include <asm/msr-index.h> #include <asm/post.h> unsigned long lapic_read(unsigned long reg) { return readl(LAPIC_DEFAULT_BASE + reg); } #define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \ sizeof(*(ptr)))) struct __xchg_dummy { unsigned long a[100]; }; #define __xg(x) ((struct __xchg_dummy *)(x)) /* * Note: no "lock" prefix even on SMP. xchg always implies lock anyway. * * Note 2: xchg has side effect, so that attribute volatile is necessary, * but generally the primitive is invalid, *ptr is output argument. */ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) { switch (size) { case 1: __asm__ __volatile__("xchgb %b0,%1" : "=q" (x) : "m" (*__xg(ptr)), "0" (x) : "memory"); break; case 2: __asm__ __volatile__("xchgw %w0,%1" : "=r" (x) : "m" (*__xg(ptr)), "0" (x) : "memory"); break; case 4: __asm__ __volatile__("xchgl %0,%1" : "=r" (x) : "m" (*__xg(ptr)), "0" (x) : "memory"); break; } return x; } void lapic_write(unsigned long reg, unsigned long v) { (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v); } void enable_lapic(void) { if (!IS_ENABLED(CONFIG_INTEL_QUARK)) { msr_t msr; msr = msr_read(MSR_IA32_APICBASE); msr.hi &= 0xffffff00; msr.lo |= MSR_IA32_APICBASE_ENABLE; msr.lo &= ~MSR_IA32_APICBASE_BASE; msr.lo |= LAPIC_DEFAULT_BASE; msr_write(MSR_IA32_APICBASE, msr); } } void disable_lapic(void) { if (!IS_ENABLED(CONFIG_INTEL_QUARK)) { msr_t msr; msr = msr_read(MSR_IA32_APICBASE); msr.lo &= ~MSR_IA32_APICBASE_ENABLE; msr_write(MSR_IA32_APICBASE, msr); } } unsigned long lapicid(void) { return lapic_read(LAPIC_ID) >> 24; } static void lapic_wait_icr_idle(void) { do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY); } int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) { int timeout; unsigned long status; int result; lapic_wait_icr_idle(); lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); lapic_write(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4)); timeout = 0; do { status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK; } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000); result = -1; if (status == LAPIC_ICR_RR_VALID) { *pvalue = lapic_read(LAPIC_RRR); result = 0; } return result; } void lapic_setup(void) { /* Only Pentium Pro and later have those MSR stuff */ debug("Setting up local apic: "); /* Enable the local apic */ enable_lapic(); /* Set Task Priority to 'accept all' */ lapic_write(LAPIC_TASKPRI, lapic_read(LAPIC_TASKPRI) & ~LAPIC_TPRI_MASK); /* Put the local apic in virtual wire mode */ lapic_write(LAPIC_SPIV, (lapic_read(LAPIC_SPIV) & ~(LAPIC_VECTOR_MASK)) | LAPIC_SPIV_ENABLE); lapic_write(LAPIC_LVT0, (lapic_read(LAPIC_LVT0) & ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | LAPIC_DELIVERY_MODE_MASK)) | (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | LAPIC_DELIVERY_MODE_EXTINT)); lapic_write(LAPIC_LVT1, (lapic_read(LAPIC_LVT1) & ~(LAPIC_LVT_MASKED | LAPIC_LVT_LEVEL_TRIGGER | LAPIC_LVT_REMOTE_IRR | LAPIC_INPUT_POLARITY | LAPIC_SEND_PENDING | LAPIC_LVT_RESERVED_1 | LAPIC_DELIVERY_MODE_MASK)) | (LAPIC_LVT_REMOTE_IRR | LAPIC_SEND_PENDING | LAPIC_DELIVERY_MODE_NMI)); debug("apic_id: 0x%02lx, ", lapicid()); debug("done.\n"); post_code(POST_LAPIC); } |