00001 /* 00002 * Copyright (C) 2001-2004 Jakub Jermar 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 00009 * - Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * - Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * - The name of the author may not be used to endorse or promote products 00015 * derived from this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00018 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00019 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00020 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 00021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 00022 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00023 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00024 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00026 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 */ 00028 00042 #include <mm/tlb.h> 00043 #include <mm/asid.h> 00044 #include <arch/mm/tlb.h> 00045 #include <smp/ipi.h> 00046 #include <synch/spinlock.h> 00047 #include <typedefs.h> 00048 #include <atomic.h> 00049 #include <arch/interrupt.h> 00050 #include <config.h> 00051 #include <arch.h> 00052 #include <panic.h> 00053 #include <debug.h> 00054 00060 SPINLOCK_INITIALIZE(tlblock); 00061 00062 void tlb_init(void) 00063 { 00064 tlb_arch_init(); 00065 } 00066 00067 #ifdef CONFIG_SMP 00068 00081 void tlb_shootdown_start(tlb_invalidate_type_t type, asid_t asid, __address page, count_t count) 00082 { 00083 int i; 00084 00085 CPU->tlb_active = 0; 00086 spinlock_lock(&tlblock); 00087 00088 for (i = 0; i < config.cpu_count; i++) { 00089 cpu_t *cpu; 00090 00091 if (i == CPU->id) 00092 continue; 00093 00094 cpu = &cpus[i]; 00095 spinlock_lock(&cpu->lock); 00096 if (cpu->tlb_messages_count == TLB_MESSAGE_QUEUE_LEN) { 00097 /* 00098 * The message queue is full. 00099 * Erase the queue and store one TLB_INVL_ALL message. 00100 */ 00101 cpu->tlb_messages_count = 1; 00102 cpu->tlb_messages[0].type = TLB_INVL_ALL; 00103 cpu->tlb_messages[0].asid = ASID_INVALID; 00104 cpu->tlb_messages[0].page = 0; 00105 cpu->tlb_messages[0].count = 0; 00106 } else { 00107 /* 00108 * Enqueue the message. 00109 */ 00110 cpu->tlb_messages[cpu->tlb_messages_count].type = type; 00111 cpu->tlb_messages[cpu->tlb_messages_count].asid = asid; 00112 cpu->tlb_messages[cpu->tlb_messages_count].page = page; 00113 cpu->tlb_messages[cpu->tlb_messages_count].count = count; 00114 cpu->tlb_messages_count++; 00115 } 00116 spinlock_unlock(&cpu->lock); 00117 } 00118 00119 tlb_shootdown_ipi_send(); 00120 00121 busy_wait: 00122 for (i = 0; i < config.cpu_count; i++) 00123 if (cpus[i].tlb_active) 00124 goto busy_wait; 00125 } 00126 00128 void tlb_shootdown_finalize(void) 00129 { 00130 spinlock_unlock(&tlblock); 00131 CPU->tlb_active = 1; 00132 } 00133 00134 void tlb_shootdown_ipi_send(void) 00135 { 00136 ipi_broadcast(VECTOR_TLB_SHOOTDOWN_IPI); 00137 } 00138 00140 void tlb_shootdown_ipi_recv(void) 00141 { 00142 tlb_invalidate_type_t type; 00143 asid_t asid; 00144 __address page; 00145 count_t count; 00146 int i; 00147 00148 ASSERT(CPU); 00149 00150 CPU->tlb_active = 0; 00151 spinlock_lock(&tlblock); 00152 spinlock_unlock(&tlblock); 00153 00154 spinlock_lock(&CPU->lock); 00155 ASSERT(CPU->tlb_messages_count <= TLB_MESSAGE_QUEUE_LEN); 00156 00157 for (i = 0; i < CPU->tlb_messages_count; CPU->tlb_messages_count--) { 00158 type = CPU->tlb_messages[i].type; 00159 asid = CPU->tlb_messages[i].asid; 00160 page = CPU->tlb_messages[i].page; 00161 count = CPU->tlb_messages[i].count; 00162 00163 switch (type) { 00164 case TLB_INVL_ALL: 00165 tlb_invalidate_all(); 00166 break; 00167 case TLB_INVL_ASID: 00168 tlb_invalidate_asid(asid); 00169 break; 00170 case TLB_INVL_PAGES: 00171 ASSERT(count); 00172 tlb_invalidate_pages(asid, page, count); 00173 break; 00174 default: 00175 panic("unknown type (%d)\n", type); 00176 break; 00177 } 00178 if (type == TLB_INVL_ALL) 00179 break; 00180 } 00181 00182 spinlock_unlock(&CPU->lock); 00183 CPU->tlb_active = 1; 00184 } 00185 00186 #endif /* CONFIG_SMP */ 00187