Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

More AP / SP bits for the 34K, the Malta bits and things. Still wants a little polishing.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

+2332 -139
+72
arch/mips/Kconfig
··· 13 13 14 14 source "init/Kconfig" 15 15 16 + config CPU_MIPS32 17 + bool 18 + default y if CPU_MIPS32_R1 || CPU_MIPS32_R2 19 + 20 + config CPU_MIPS64 21 + bool 22 + default y if CPU_MIPS64_R1 || CPU_MIPS64_R2 23 + 24 + config CPU_MIPSR1 25 + bool 26 + default y if CPU_MIPS32_R1 || CPU_MIPS64_R1 27 + 28 + config CPU_MIPSR2 29 + bool 30 + default y if CPU_MIPS32_R2 || CPU_MIPS64_R2 31 + 16 32 config SYS_SUPPORTS_32BIT_KERNEL 17 33 bool 18 34 config SYS_SUPPORTS_64BIT_KERNEL ··· 249 233 bool "Support for Galileo EV64120 Evaluation board (EXPERIMENTAL)" 250 234 depends on EXPERIMENTAL 251 235 select DMA_NONCOHERENT 236 + select IRQ_CPU 252 237 select HW_HAS_PCI 253 238 select MIPS_GT64120 254 239 select SYS_SUPPORTS_32BIT_KERNEL ··· 361 344 select BOOT_ELF32 362 345 select HAVE_STD_PC_SERIAL_PORT 363 346 select DMA_NONCOHERENT 347 + select IRQ_CPU 364 348 select GENERIC_ISA_DMA 365 349 select HW_HAS_PCI 366 350 select I8259 ··· 1295 1277 bool "Enable prefetches" if CPU_SB1 && !CPU_SB1_PASS_2 1296 1278 default y if CPU_MIPS32 || CPU_MIPS64 || CPU_RM7000 || CPU_RM9000 || CPU_R10000 1297 1279 1280 + config MIPS_MT 1281 + bool "Enable MIPS MT" 1282 + 1283 + config MIPS_VPE_LOADER 1284 + bool "VPE loader support." 1285 + depends on MIPS_MT 1286 + help 1287 + Includes a loader for loading an elf relocatable object 1288 + onto another VPE and running it. 1289 + 1290 + config MIPS_VPE_LOADER_TOM 1291 + bool "Load VPE program into memory hidden from linux" 1292 + depends on MIPS_VPE_LOADER 1293 + default y 1294 + help 1295 + The loader can use memory that is present but has been hidden from 1296 + Linux using the kernel command line option "mem=xxMB". It's up to 1297 + you to ensure the amount you put in the option and the space your 1298 + program requires is less or equal to the amount physically present. 1299 + 1300 + # this should possibly be in drivers/char, but it is rather cpu related. Hmmm 1301 + config MIPS_VPE_APSP_API 1302 + bool "Enable support for AP/SP API (RTLX)" 1303 + depends on MIPS_VPE_LOADER 1304 + 1298 1305 config VTAG_ICACHE 1299 1306 bool "Support for Virtual Tagged I-cache" if CPU_MIPS64 || CPU_MIPS32 1300 1307 default y if CPU_SB1 ··· 1377 1334 Say N here for slightly better performance. You must say Y here for 1378 1335 machines which require flushing of write buffers in software. Saying 1379 1336 Y is the safe option; N may result in kernel malfunction and crashes. 1337 + 1338 + menu "MIPSR2 Interrupt handling" 1339 + depends on CPU_MIPSR2 && CPU_ADVANCED 1340 + 1341 + config CPU_MIPSR2_IRQ_VI 1342 + bool "Vectored interrupt mode" 1343 + help 1344 + Vectored interrupt mode allowing faster dispatching of interrupts. 1345 + The board support code needs to be written to take advantage of this 1346 + mode. Compatibility code is included to allow the kernel to run on 1347 + a CPU that does not support vectored interrupts. It's safe to 1348 + say Y here. 1349 + 1350 + config CPU_MIPSR2_IRQ_EI 1351 + bool "External interrupt controller mode" 1352 + help 1353 + Extended interrupt mode takes advantage of an external interrupt 1354 + controller to allow fast dispatching from many possible interrupt 1355 + sources. Say N unless you know that external interrupt support is 1356 + required. 1357 + 1358 + config CPU_MIPSR2_SRS 1359 + bool "Make shadow set registers available for interrupt handlers" 1360 + depends on CPU_MIPSR2_IRQ_VI || CPU_MIPSR2_IRQ_EI 1361 + help 1362 + Allow the kernel to use shadow register sets for fast interrupts. 1363 + Interrupt handlers must be specially written to use shadow sets. 1364 + Say N unless you know that shadow register set upport is needed. 1365 + endmenu 1380 1366 1381 1367 config CPU_HAS_SYNC 1382 1368 bool
+4
arch/mips/kernel/Makefile
··· 34 34 35 35 obj-$(CONFIG_SMP) += smp.o 36 36 37 + obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o 38 + obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o 39 + 37 40 obj-$(CONFIG_NO_ISA) += dma-no-isa.o 38 41 obj-$(CONFIG_I8259) += i8259.o 39 42 obj-$(CONFIG_IRQ_CPU) += irq_cpu.o 40 43 obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o 41 44 obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o 42 45 obj-$(CONFIG_IRQ_MV64340) += irq-mv6434x.o 46 + obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o 43 47 44 48 obj-$(CONFIG_32BIT) += scall32-o32.o 45 49 obj-$(CONFIG_64BIT) += scall64-64.o
+32
arch/mips/kernel/genex.S
··· 148 148 __FINIT 149 149 150 150 /* 151 + * Vectored interrupt handler. 152 + * This prototype is copied to ebase + n*IntCtl.VS and patched 153 + * to invoke the handler 154 + */ 155 + NESTED(except_vec_vi, 0, sp) 156 + SAVE_SOME 157 + SAVE_AT 158 + .set push 159 + .set noreorder 160 + EXPORT(except_vec_vi_lui) 161 + lui v0, 0 /* Patched */ 162 + j except_vec_vi_handler 163 + EXPORT(except_vec_vi_ori) 164 + ori v0, 0 /* Patched */ 165 + .set pop 166 + END(except_vec_vi) 167 + EXPORT(except_vec_vi_end) 168 + 169 + /* 170 + * Common Vectored Interrupt code 171 + * Complete the register saves and invoke the handler which is passed in $v0 172 + */ 173 + NESTED(except_vec_vi_handler, 0, sp) 174 + SAVE_TEMP 175 + SAVE_STATIC 176 + CLI 177 + move a0, sp 178 + jalr v0 179 + j ret_from_irq 180 + END(except_vec_vi_handler) 181 + 182 + /* 151 183 * EJTAG debug exception handler. 152 184 */ 153 185 NESTED(ejtag_debug_handler, PT_SIZE, sp)
+4 -4
arch/mips/kernel/irq-msc01.c
··· 74 74 static void level_mask_and_ack_msc_irq(unsigned int irq) 75 75 { 76 76 mask_msc_irq(irq); 77 - if (!cpu_has_ei) 77 + if (!cpu_has_veic) 78 78 MSCIC_WRITE(MSC01_IC_EOI, 0); 79 79 } 80 80 ··· 84 84 static void edge_mask_and_ack_msc_irq(unsigned int irq) 85 85 { 86 86 mask_msc_irq(irq); 87 - if (!cpu_has_ei) 87 + if (!cpu_has_veic) 88 88 MSCIC_WRITE(MSC01_IC_EOI, 0); 89 89 else { 90 90 u32 r; ··· 166 166 switch (imp->im_type) { 167 167 case MSC01_IRQ_EDGE: 168 168 irq_desc[base+n].handler = &msc_edgeirq_type; 169 - if (cpu_has_ei) 169 + if (cpu_has_veic) 170 170 MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); 171 171 else 172 172 MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); 173 173 break; 174 174 case MSC01_IRQ_LEVEL: 175 175 irq_desc[base+n].handler = &msc_levelirq_type; 176 - if (cpu_has_ei) 176 + if (cpu_has_veic) 177 177 MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); 178 178 else 179 179 MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl);
+341
arch/mips/kernel/rtlx.c
··· 1 + /* 2 + * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. 3 + * 4 + * This program is free software; you can distribute it and/or modify it 5 + * under the terms of the GNU General Public License (Version 2) as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 + * for more details. 12 + * 13 + * You should have received a copy of the GNU General Public License along 14 + * with this program; if not, write to the Free Software Foundation, Inc., 15 + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 16 + * 17 + */ 18 + 19 + #include <linux/kernel.h> 20 + #include <linux/module.h> 21 + #include <linux/fs.h> 22 + #include <linux/init.h> 23 + #include <asm/uaccess.h> 24 + #include <linux/slab.h> 25 + #include <linux/list.h> 26 + #include <linux/vmalloc.h> 27 + #include <linux/elf.h> 28 + #include <linux/seq_file.h> 29 + #include <linux/syscalls.h> 30 + #include <linux/moduleloader.h> 31 + #include <linux/interrupt.h> 32 + #include <linux/poll.h> 33 + #include <linux/sched.h> 34 + #include <linux/wait.h> 35 + #include <asm/mipsmtregs.h> 36 + #include <asm/cacheflush.h> 37 + #include <asm/atomic.h> 38 + #include <asm/cpu.h> 39 + #include <asm/processor.h> 40 + #include <asm/system.h> 41 + #include <asm/rtlx.h> 42 + 43 + #define RTLX_MAJOR 64 44 + #define RTLX_TARG_VPE 1 45 + 46 + struct rtlx_info *rtlx; 47 + static int major; 48 + static char module_name[] = "rtlx"; 49 + static inline int spacefree(int read, int write, int size); 50 + 51 + static struct chan_waitqueues { 52 + wait_queue_head_t rt_queue; 53 + wait_queue_head_t lx_queue; 54 + } channel_wqs[RTLX_CHANNELS]; 55 + 56 + static struct irqaction irq; 57 + static int irq_num; 58 + 59 + extern void *vpe_get_shared(int index); 60 + 61 + static void rtlx_dispatch(struct pt_regs *regs) 62 + { 63 + do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs); 64 + } 65 + 66 + irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs) 67 + { 68 + irqreturn_t r = IRQ_HANDLED; 69 + int i; 70 + 71 + for (i = 0; i < RTLX_CHANNELS; i++) { 72 + struct rtlx_channel *chan = &rtlx->channel[i]; 73 + 74 + if (chan->lx_read != chan->lx_write) 75 + wake_up_interruptible(&channel_wqs[i].lx_queue); 76 + } 77 + 78 + return r; 79 + } 80 + 81 + void dump_rtlx(void) 82 + { 83 + int i; 84 + 85 + printk("id 0x%lx state %d\n", rtlx->id, rtlx->state); 86 + 87 + for (i = 0; i < RTLX_CHANNELS; i++) { 88 + struct rtlx_channel *chan = &rtlx->channel[i]; 89 + 90 + printk(" rt_state %d lx_state %d buffer_size %d\n", 91 + chan->rt_state, chan->lx_state, chan->buffer_size); 92 + 93 + printk(" rt_read %d rt_write %d\n", 94 + chan->rt_read, chan->rt_write); 95 + 96 + printk(" lx_read %d lx_write %d\n", 97 + chan->lx_read, chan->lx_write); 98 + 99 + printk(" rt_buffer <%s>\n", chan->rt_buffer); 100 + printk(" lx_buffer <%s>\n", chan->lx_buffer); 101 + } 102 + } 103 + 104 + /* call when we have the address of the shared structure from the SP side. */ 105 + static int rtlx_init(struct rtlx_info *rtlxi) 106 + { 107 + int i; 108 + 109 + if (rtlxi->id != RTLX_ID) { 110 + printk(KERN_WARNING "no valid RTLX id at 0x%p\n", rtlxi); 111 + return (-ENOEXEC); 112 + } 113 + 114 + /* initialise the wait queues */ 115 + for (i = 0; i < RTLX_CHANNELS; i++) { 116 + init_waitqueue_head(&channel_wqs[i].rt_queue); 117 + init_waitqueue_head(&channel_wqs[i].lx_queue); 118 + } 119 + 120 + /* set up for interrupt handling */ 121 + memset(&irq, 0, sizeof(struct irqaction)); 122 + 123 + if (cpu_has_vint) { 124 + set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch); 125 + } 126 + 127 + irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ; 128 + irq.handler = rtlx_interrupt; 129 + irq.flags = SA_INTERRUPT; 130 + irq.name = "RTLX"; 131 + irq.dev_id = rtlx; 132 + setup_irq(irq_num, &irq); 133 + 134 + rtlx = rtlxi; 135 + return (0); 136 + } 137 + 138 + /* only allow one open process at a time to open each channel */ 139 + static int rtlx_open(struct inode *inode, struct file *filp) 140 + { 141 + int minor, ret; 142 + struct rtlx_channel *chan; 143 + 144 + /* assume only 1 device at the mo. */ 145 + minor = MINOR(inode->i_rdev); 146 + 147 + if (rtlx == NULL) { 148 + struct rtlx_info **p; 149 + if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { 150 + printk(" vpe_get_shared is NULL. Has an SP program been loaded?\n"); 151 + return (-EFAULT); 152 + } 153 + 154 + if (*p == NULL) { 155 + printk(" vpe_shared %p %p\n", p, *p); 156 + return (-EFAULT); 157 + } 158 + 159 + if ((ret = rtlx_init(*p)) < 0) 160 + return (ret); 161 + } 162 + 163 + chan = &rtlx->channel[minor]; 164 + 165 + /* already open? */ 166 + if (chan->lx_state == RTLX_STATE_OPENED) 167 + return (-EBUSY); 168 + 169 + chan->lx_state = RTLX_STATE_OPENED; 170 + return (0); 171 + } 172 + 173 + static int rtlx_release(struct inode *inode, struct file *filp) 174 + { 175 + int minor; 176 + 177 + minor = MINOR(inode->i_rdev); 178 + rtlx->channel[minor].lx_state = RTLX_STATE_UNUSED; 179 + return (0); 180 + } 181 + 182 + static unsigned int rtlx_poll(struct file *file, poll_table * wait) 183 + { 184 + int minor; 185 + unsigned int mask = 0; 186 + struct rtlx_channel *chan; 187 + 188 + minor = MINOR(file->f_dentry->d_inode->i_rdev); 189 + chan = &rtlx->channel[minor]; 190 + 191 + poll_wait(file, &channel_wqs[minor].rt_queue, wait); 192 + poll_wait(file, &channel_wqs[minor].lx_queue, wait); 193 + 194 + /* data available to read? */ 195 + if (chan->lx_read != chan->lx_write) 196 + mask |= POLLIN | POLLRDNORM; 197 + 198 + /* space to write */ 199 + if (spacefree(chan->rt_read, chan->rt_write, chan->buffer_size)) 200 + mask |= POLLOUT | POLLWRNORM; 201 + 202 + return (mask); 203 + } 204 + 205 + static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count, 206 + loff_t * ppos) 207 + { 208 + size_t fl = 0L; 209 + int minor; 210 + struct rtlx_channel *lx; 211 + DECLARE_WAITQUEUE(wait, current); 212 + 213 + minor = MINOR(file->f_dentry->d_inode->i_rdev); 214 + lx = &rtlx->channel[minor]; 215 + 216 + /* data available? */ 217 + if (lx->lx_write == lx->lx_read) { 218 + if (file->f_flags & O_NONBLOCK) 219 + return (0); // -EAGAIN makes cat whinge 220 + 221 + /* go to sleep */ 222 + add_wait_queue(&channel_wqs[minor].lx_queue, &wait); 223 + set_current_state(TASK_INTERRUPTIBLE); 224 + 225 + while (lx->lx_write == lx->lx_read) 226 + schedule(); 227 + 228 + set_current_state(TASK_RUNNING); 229 + remove_wait_queue(&channel_wqs[minor].lx_queue, &wait); 230 + 231 + /* back running */ 232 + } 233 + 234 + /* find out how much in total */ 235 + count = min( count, 236 + (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size); 237 + 238 + /* then how much from the read pointer onwards */ 239 + fl = min( count, (size_t)lx->buffer_size - lx->lx_read); 240 + 241 + copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl); 242 + 243 + /* and if there is anything left at the beginning of the buffer */ 244 + if ( count - fl ) 245 + copy_to_user (buffer + fl, lx->lx_buffer, count - fl); 246 + 247 + /* update the index */ 248 + lx->lx_read += count; 249 + lx->lx_read %= lx->buffer_size; 250 + 251 + return (count); 252 + } 253 + 254 + static inline int spacefree(int read, int write, int size) 255 + { 256 + if (read == write) { 257 + /* never fill the buffer completely, so indexes are always equal if empty 258 + and only empty, or !equal if data available */ 259 + return (size - 1); 260 + } 261 + 262 + return ((read + size - write) % size) - 1; 263 + } 264 + 265 + static ssize_t rtlx_write(struct file *file, const char __user * buffer, 266 + size_t count, loff_t * ppos) 267 + { 268 + int minor; 269 + struct rtlx_channel *rt; 270 + size_t fl; 271 + DECLARE_WAITQUEUE(wait, current); 272 + 273 + minor = MINOR(file->f_dentry->d_inode->i_rdev); 274 + rt = &rtlx->channel[minor]; 275 + 276 + /* any space left... */ 277 + if (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) { 278 + 279 + if (file->f_flags & O_NONBLOCK) 280 + return (-EAGAIN); 281 + 282 + add_wait_queue(&channel_wqs[minor].rt_queue, &wait); 283 + set_current_state(TASK_INTERRUPTIBLE); 284 + 285 + while (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) 286 + schedule(); 287 + 288 + set_current_state(TASK_RUNNING); 289 + remove_wait_queue(&channel_wqs[minor].rt_queue, &wait); 290 + } 291 + 292 + /* total number of bytes to copy */ 293 + count = min( count, (size_t)spacefree(rt->rt_read, rt->rt_write, rt->buffer_size) ); 294 + 295 + /* first bit from write pointer to the end of the buffer, or count */ 296 + fl = min(count, (size_t) rt->buffer_size - rt->rt_write); 297 + 298 + copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl); 299 + 300 + /* if there's any left copy to the beginning of the buffer */ 301 + if( count - fl ) 302 + copy_from_user(rt->rt_buffer, buffer + fl, count - fl); 303 + 304 + rt->rt_write += count; 305 + rt->rt_write %= rt->buffer_size; 306 + 307 + return(count); 308 + } 309 + 310 + static struct file_operations rtlx_fops = { 311 + .owner = THIS_MODULE, 312 + .open = rtlx_open, 313 + .release = rtlx_release, 314 + .write = rtlx_write, 315 + .read = rtlx_read, 316 + .poll = rtlx_poll 317 + }; 318 + 319 + static int rtlx_module_init(void) 320 + { 321 + if ((major = register_chrdev(RTLX_MAJOR, module_name, &rtlx_fops)) < 0) { 322 + printk("rtlx_module_init: unable to register device\n"); 323 + return (-EBUSY); 324 + } 325 + 326 + if (major == 0) 327 + major = RTLX_MAJOR; 328 + 329 + return (0); 330 + } 331 + 332 + static void rtlx_module_exit(void) 333 + { 334 + unregister_chrdev(major, module_name); 335 + } 336 + 337 + module_init(rtlx_module_init); 338 + module_exit(rtlx_module_exit); 339 + MODULE_DESCRIPTION("MIPS RTLX"); 340 + MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc"); 341 + MODULE_LICENSE("GPL");
+214 -13
arch/mips/kernel/traps.c
··· 20 20 #include <linux/smp_lock.h> 21 21 #include <linux/spinlock.h> 22 22 #include <linux/kallsyms.h> 23 + #include <linux/bootmem.h> 23 24 24 25 #include <asm/bootinfo.h> 25 26 #include <asm/branch.h> ··· 65 64 66 65 void (*board_be_init)(void); 67 66 int (*board_be_handler)(struct pt_regs *regs, int is_fixup); 67 + void (*board_nmi_handler_setup)(void); 68 + void (*board_ejtag_handler_setup)(void); 69 + void (*board_bind_eic_interrupt)(int irq, int regset); 68 70 69 71 /* 70 72 * These constant is for searching for possible module text segments. ··· 817 813 (regs->cp0_cause & 0x7f) >> 2); 818 814 } 819 815 816 + asmlinkage void do_default_vi(struct pt_regs *regs) 817 + { 818 + show_regs(regs); 819 + panic("Caught unexpected vectored interrupt."); 820 + } 821 + 820 822 /* 821 823 * Some MIPS CPUs can enable/disable for cache parity detection, but do 822 824 * it different ways. ··· 931 921 while(1) ; 932 922 } 933 923 924 + #define VECTORSPACING 0x100 /* for EI/VI mode */ 925 + 926 + unsigned long ebase; 934 927 unsigned long exception_handlers[32]; 928 + unsigned long vi_handlers[64]; 935 929 936 930 /* 937 931 * As a side effect of the way this is implemented we're limited ··· 949 935 950 936 exception_handlers[n] = handler; 951 937 if (n == 0 && cpu_has_divec) { 952 - *(volatile u32 *)(CAC_BASE + 0x200) = 0x08000000 | 938 + *(volatile u32 *)(ebase + 0x200) = 0x08000000 | 953 939 (0x03ffffff & (handler >> 2)); 954 - flush_icache_range(CAC_BASE + 0x200, CAC_BASE + 0x204); 940 + flush_icache_range(ebase + 0x200, ebase + 0x204); 955 941 } 956 942 return (void *)old_handler; 957 943 } 944 + 945 + #ifdef CONFIG_CPU_MIPSR2 946 + /* 947 + * Shadow register allocation 948 + * FIXME: SMP... 949 + */ 950 + 951 + /* MIPSR2 shadow register sets */ 952 + struct shadow_registers { 953 + spinlock_t sr_lock; /* */ 954 + int sr_supported; /* Number of shadow register sets supported */ 955 + int sr_allocated; /* Bitmap of allocated shadow registers */ 956 + } shadow_registers; 957 + 958 + void mips_srs_init(void) 959 + { 960 + #ifdef CONFIG_CPU_MIPSR2_SRS 961 + shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1; 962 + printk ("%d MIPSR2 register sets available\n", shadow_registers.sr_supported); 963 + #else 964 + shadow_registers.sr_supported = 1; 965 + #endif 966 + shadow_registers.sr_allocated = 1; /* Set 0 used by kernel */ 967 + spin_lock_init(&shadow_registers.sr_lock); 968 + } 969 + 970 + int mips_srs_max(void) 971 + { 972 + return shadow_registers.sr_supported; 973 + } 974 + 975 + int mips_srs_alloc (void) 976 + { 977 + struct shadow_registers *sr = &shadow_registers; 978 + unsigned long flags; 979 + int set; 980 + 981 + spin_lock_irqsave(&sr->sr_lock, flags); 982 + 983 + for (set = 0; set < sr->sr_supported; set++) { 984 + if ((sr->sr_allocated & (1 << set)) == 0) { 985 + sr->sr_allocated |= 1 << set; 986 + spin_unlock_irqrestore(&sr->sr_lock, flags); 987 + return set; 988 + } 989 + } 990 + 991 + /* None available */ 992 + spin_unlock_irqrestore(&sr->sr_lock, flags); 993 + return -1; 994 + } 995 + 996 + void mips_srs_free (int set) 997 + { 998 + struct shadow_registers *sr = &shadow_registers; 999 + unsigned long flags; 1000 + 1001 + spin_lock_irqsave(&sr->sr_lock, flags); 1002 + sr->sr_allocated &= ~(1 << set); 1003 + spin_unlock_irqrestore(&sr->sr_lock, flags); 1004 + } 1005 + 1006 + void *set_vi_srs_handler (int n, void *addr, int srs) 1007 + { 1008 + unsigned long handler; 1009 + unsigned long old_handler = vi_handlers[n]; 1010 + u32 *w; 1011 + unsigned char *b; 1012 + 1013 + if (!cpu_has_veic && !cpu_has_vint) 1014 + BUG(); 1015 + 1016 + if (addr == NULL) { 1017 + handler = (unsigned long) do_default_vi; 1018 + srs = 0; 1019 + } 1020 + else 1021 + handler = (unsigned long) addr; 1022 + vi_handlers[n] = (unsigned long) addr; 1023 + 1024 + b = (unsigned char *)(ebase + 0x200 + n*VECTORSPACING); 1025 + 1026 + if (srs >= mips_srs_max()) 1027 + panic("Shadow register set %d not supported", srs); 1028 + 1029 + if (cpu_has_veic) { 1030 + if (board_bind_eic_interrupt) 1031 + board_bind_eic_interrupt (n, srs); 1032 + } 1033 + else if (cpu_has_vint) { 1034 + /* SRSMap is only defined if shadow sets are implemented */ 1035 + if (mips_srs_max() > 1) 1036 + change_c0_srsmap (0xf << n*4, srs << n*4); 1037 + } 1038 + 1039 + if (srs == 0) { 1040 + /* 1041 + * If no shadow set is selected then use the default handler 1042 + * that does normal register saving and a standard interrupt exit 1043 + */ 1044 + 1045 + extern char except_vec_vi, except_vec_vi_lui; 1046 + extern char except_vec_vi_ori, except_vec_vi_end; 1047 + const int handler_len = &except_vec_vi_end - &except_vec_vi; 1048 + const int lui_offset = &except_vec_vi_lui - &except_vec_vi; 1049 + const int ori_offset = &except_vec_vi_ori - &except_vec_vi; 1050 + 1051 + if (handler_len > VECTORSPACING) { 1052 + /* 1053 + * Sigh... panicing won't help as the console 1054 + * is probably not configured :( 1055 + */ 1056 + panic ("VECTORSPACING too small"); 1057 + } 1058 + 1059 + memcpy (b, &except_vec_vi, handler_len); 1060 + w = (u32 *)(b + lui_offset); 1061 + *w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff); 1062 + w = (u32 *)(b + ori_offset); 1063 + *w = (*w & 0xffff0000) | ((u32)handler & 0xffff); 1064 + flush_icache_range((unsigned long)b, (unsigned long)(b+handler_len)); 1065 + } 1066 + else { 1067 + /* 1068 + * In other cases jump directly to the interrupt handler 1069 + * 1070 + * It is the handlers responsibility to save registers if required 1071 + * (eg hi/lo) and return from the exception using "eret" 1072 + */ 1073 + w = (u32 *)b; 1074 + *w++ = 0x08000000 | (((u32)handler >> 2) & 0x03fffff); /* j handler */ 1075 + *w = 0; 1076 + flush_icache_range((unsigned long)b, (unsigned long)(b+8)); 1077 + } 1078 + 1079 + return (void *)old_handler; 1080 + } 1081 + 1082 + void *set_vi_handler (int n, void *addr) 1083 + { 1084 + return set_vi_srs_handler (n, addr, 0); 1085 + } 1086 + #endif 958 1087 959 1088 /* 960 1089 * This is used by native signal handling ··· 1173 1016 if (cpu_has_dsp) 1174 1017 set_c0_status(ST0_MX); 1175 1018 1019 + #ifdef CONFIG_CPU_MIPSR2 1020 + write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */ 1021 + #endif 1022 + 1176 1023 /* 1177 - * Some MIPS CPUs have a dedicated interrupt vector which reduces the 1178 - * interrupt processing overhead. Use it where available. 1024 + * Interrupt handling. 1179 1025 */ 1026 + if (cpu_has_veic || cpu_has_vint) { 1027 + write_c0_ebase (ebase); 1028 + /* Setting vector spacing enables EI/VI mode */ 1029 + change_c0_intctl (0x3e0, VECTORSPACING); 1030 + } 1180 1031 if (cpu_has_divec) 1181 1032 set_c0_cause(CAUSEF_IV); 1182 1033 ··· 1200 1035 tlb_init(); 1201 1036 } 1202 1037 1038 + /* Install CPU exception handler */ 1039 + void __init set_handler (unsigned long offset, void *addr, unsigned long size) 1040 + { 1041 + memcpy((void *)(ebase + offset), addr, size); 1042 + flush_icache_range(ebase + offset, ebase + offset + size); 1043 + } 1044 + 1045 + /* Install uncached CPU exception handler */ 1046 + void __init set_uncached_handler (unsigned long offset, void *addr, unsigned long size) 1047 + { 1048 + #ifdef CONFIG_32BIT 1049 + unsigned long uncached_ebase = KSEG1ADDR(ebase); 1050 + #endif 1051 + #ifdef CONFIG_64BIT 1052 + unsigned long uncached_ebase = TO_UNCAC(ebase); 1053 + #endif 1054 + 1055 + memcpy((void *)(uncached_ebase + offset), addr, size); 1056 + } 1057 + 1203 1058 void __init trap_init(void) 1204 1059 { 1205 1060 extern char except_vec3_generic, except_vec3_r4000; 1206 - extern char except_vec_ejtag_debug; 1207 1061 extern char except_vec4; 1208 1062 unsigned long i; 1063 + 1064 + if (cpu_has_veic || cpu_has_vint) 1065 + ebase = (unsigned long) alloc_bootmem_low_pages (0x200 + VECTORSPACING*64); 1066 + else 1067 + ebase = CAC_BASE; 1068 + 1069 + #ifdef CONFIG_CPU_MIPSR2 1070 + mips_srs_init(); 1071 + #endif 1209 1072 1210 1073 per_cpu_trap_init(); 1211 1074 ··· 1242 1049 * This will be overriden later as suitable for a particular 1243 1050 * configuration. 1244 1051 */ 1245 - memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80); 1052 + set_handler(0x180, &except_vec3_generic, 0x80); 1246 1053 1247 1054 /* 1248 1055 * Setup default vectors ··· 1254 1061 * Copy the EJTAG debug exception vector handler code to it's final 1255 1062 * destination. 1256 1063 */ 1257 - if (cpu_has_ejtag) 1258 - memcpy((void *)(CAC_BASE + 0x300), &except_vec_ejtag_debug, 0x80); 1064 + if (cpu_has_ejtag && board_ejtag_handler_setup) 1065 + board_ejtag_handler_setup (); 1259 1066 1260 1067 /* 1261 1068 * Only some CPUs have the watch exceptions. ··· 1264 1071 set_except_vector(23, handle_watch); 1265 1072 1266 1073 /* 1267 - * Some MIPS CPUs have a dedicated interrupt vector which reduces the 1268 - * interrupt processing overhead. Use it where available. 1074 + * Initialise interrupt handlers 1269 1075 */ 1270 - if (cpu_has_divec) 1271 - memcpy((void *)(CAC_BASE + 0x200), &except_vec4, 0x8); 1076 + if (cpu_has_veic || cpu_has_vint) { 1077 + int nvec = cpu_has_veic ? 64 : 8; 1078 + for (i = 0; i < nvec; i++) 1079 + set_vi_handler (i, NULL); 1080 + } 1081 + else if (cpu_has_divec) 1082 + set_handler(0x200, &except_vec4, 0x8); 1272 1083 1273 1084 /* 1274 1085 * Some CPUs can enable/disable for cache parity detection, but does ··· 1319 1122 //set_except_vector(15, handle_ndc); 1320 1123 } 1321 1124 1125 + 1126 + if (board_nmi_handler_setup) 1127 + board_nmi_handler_setup(); 1128 + 1322 1129 if (cpu_has_fpu && !cpu_has_nofpuex) 1323 1130 set_except_vector(15, handle_fpe); 1324 1131 ··· 1347 1146 signal32_init(); 1348 1147 #endif 1349 1148 1350 - flush_icache_range(CAC_BASE, CAC_BASE + 0x400); 1149 + flush_icache_range(ebase, ebase + 0x400); 1351 1150 }
+1295
arch/mips/kernel/vpe.c
··· 1 + /* 2 + * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. 3 + * 4 + * This program is free software; you can distribute it and/or modify it 5 + * under the terms of the GNU General Public License (Version 2) as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 + * for more details. 12 + * 13 + * You should have received a copy of the GNU General Public License along 14 + * with this program; if not, write to the Free Software Foundation, Inc., 15 + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 16 + * 17 + */ 18 + 19 + /* 20 + * VPE support module 21 + * 22 + * Provides support for loading a MIPS SP program on VPE1. 23 + * The SP enviroment is rather simple, no tlb's. It needs to be relocatable 24 + * (or partially linked). You should initialise your stack in the startup 25 + * code. This loader looks for the symbol __start and sets up 26 + * execution to resume from there. The MIPS SDE kit contains suitable examples. 27 + * 28 + * To load and run, simply cat a SP 'program file' to /dev/vpe1. 29 + * i.e cat spapp >/dev/vpe1. 30 + * 31 + * You'll need to have the following device files. 32 + * mknod /dev/vpe0 c 63 0 33 + * mknod /dev/vpe1 c 63 1 34 + */ 35 + 36 + #include <linux/kernel.h> 37 + #include <linux/module.h> 38 + #include <linux/fs.h> 39 + #include <linux/init.h> 40 + #include <asm/uaccess.h> 41 + #include <linux/slab.h> 42 + #include <linux/list.h> 43 + #include <linux/vmalloc.h> 44 + #include <linux/elf.h> 45 + #include <linux/seq_file.h> 46 + #include <linux/syscalls.h> 47 + #include <linux/moduleloader.h> 48 + #include <linux/interrupt.h> 49 + #include <linux/poll.h> 50 + #include <linux/bootmem.h> 51 + #include <asm/mipsregs.h> 52 + #include <asm/cacheflush.h> 53 + #include <asm/atomic.h> 54 + #include <asm/cpu.h> 55 + #include <asm/processor.h> 56 + #include <asm/system.h> 57 + 58 + typedef void *vpe_handle; 59 + 60 + // defined here because the kernel module loader doesn't have 61 + // anything to do with it. 62 + #define SHN_MIPS_SCOMMON 0xff03 63 + 64 + #ifndef ARCH_SHF_SMALL 65 + #define ARCH_SHF_SMALL 0 66 + #endif 67 + 68 + /* If this is set, the section belongs in the init part of the module */ 69 + #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) 70 + 71 + // temp number, 72 + #define VPE_MAJOR 63 73 + 74 + static char module_name[] = "vpe"; 75 + static int major = 0; 76 + 77 + /* grab the likely amount of memory we will need. */ 78 + #ifdef CONFIG_MIPS_VPE_LOADER_TOM 79 + #define P_SIZE (2 * 1024 * 1024) 80 + #else 81 + /* add an overhead to the max kmalloc size for non-striped symbols/etc */ 82 + #define P_SIZE (256 * 1024) 83 + #endif 84 + 85 + #define MAX_VPES 16 86 + 87 + enum vpe_state { 88 + VPE_STATE_UNUSED = 0, 89 + VPE_STATE_INUSE, 90 + VPE_STATE_RUNNING 91 + }; 92 + 93 + enum tc_state { 94 + TC_STATE_UNUSED = 0, 95 + TC_STATE_INUSE, 96 + TC_STATE_RUNNING, 97 + TC_STATE_DYNAMIC 98 + }; 99 + 100 + struct vpe; 101 + typedef struct tc { 102 + enum tc_state state; 103 + int index; 104 + 105 + /* parent VPE */ 106 + struct vpe *pvpe; 107 + 108 + /* The list of TC's with this VPE */ 109 + struct list_head tc; 110 + 111 + /* The global list of tc's */ 112 + struct list_head list; 113 + } tc_t; 114 + 115 + typedef struct vpe { 116 + enum vpe_state state; 117 + 118 + /* (device) minor associated with this vpe */ 119 + int minor; 120 + 121 + /* elfloader stuff */ 122 + void *load_addr; 123 + u32 len; 124 + char *pbuffer; 125 + u32 plen; 126 + 127 + unsigned long __start; 128 + 129 + /* tc's associated with this vpe */ 130 + struct list_head tc; 131 + 132 + /* The list of vpe's */ 133 + struct list_head list; 134 + 135 + /* shared symbol address */ 136 + void *shared_ptr; 137 + } vpe_t; 138 + 139 + struct vpecontrol_ { 140 + /* Virtual processing elements */ 141 + struct list_head vpe_list; 142 + 143 + /* Thread contexts */ 144 + struct list_head tc_list; 145 + } vpecontrol; 146 + 147 + static void release_progmem(void *ptr); 148 + static void dump_vpe(vpe_t * v); 149 + extern void save_gp_address(unsigned int secbase, unsigned int rel); 150 + 151 + /* get the vpe associated with this minor */ 152 + struct vpe *get_vpe(int minor) 153 + { 154 + struct vpe *v; 155 + 156 + list_for_each_entry(v, &vpecontrol.vpe_list, list) { 157 + if (v->minor == minor) 158 + return v; 159 + } 160 + 161 + printk(KERN_DEBUG "VPE: get_vpe minor %d not found\n", minor); 162 + return NULL; 163 + } 164 + 165 + /* get the vpe associated with this minor */ 166 + struct tc *get_tc(int index) 167 + { 168 + struct tc *t; 169 + 170 + list_for_each_entry(t, &vpecontrol.tc_list, list) { 171 + if (t->index == index) 172 + return t; 173 + } 174 + 175 + printk(KERN_DEBUG "VPE: get_tc index %d not found\n", index); 176 + 177 + return NULL; 178 + } 179 + 180 + struct tc *get_tc_unused(void) 181 + { 182 + struct tc *t; 183 + 184 + list_for_each_entry(t, &vpecontrol.tc_list, list) { 185 + if (t->state == TC_STATE_UNUSED) 186 + return t; 187 + } 188 + 189 + printk(KERN_DEBUG "VPE: All TC's are in use\n"); 190 + 191 + return NULL; 192 + } 193 + 194 + /* allocate a vpe and associate it with this minor (or index) */ 195 + struct vpe *alloc_vpe(int minor) 196 + { 197 + struct vpe *v; 198 + 199 + if ((v = kmalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) { 200 + printk(KERN_WARNING "VPE: alloc_vpe no mem\n"); 201 + return NULL; 202 + } 203 + 204 + memset(v, 0, sizeof(struct vpe)); 205 + 206 + INIT_LIST_HEAD(&v->tc); 207 + list_add_tail(&v->list, &vpecontrol.vpe_list); 208 + 209 + v->minor = minor; 210 + return v; 211 + } 212 + 213 + /* allocate a tc. At startup only tc0 is running, all other can be halted. */ 214 + struct tc *alloc_tc(int index) 215 + { 216 + struct tc *t; 217 + 218 + if ((t = kmalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) { 219 + printk(KERN_WARNING "VPE: alloc_tc no mem\n"); 220 + return NULL; 221 + } 222 + 223 + memset(t, 0, sizeof(struct tc)); 224 + 225 + INIT_LIST_HEAD(&t->tc); 226 + list_add_tail(&t->list, &vpecontrol.tc_list); 227 + 228 + t->index = index; 229 + 230 + return t; 231 + } 232 + 233 + /* clean up and free everything */ 234 + void release_vpe(struct vpe *v) 235 + { 236 + list_del(&v->list); 237 + if (v->load_addr) 238 + release_progmem(v); 239 + kfree(v); 240 + } 241 + 242 + void dump_mtregs(void) 243 + { 244 + unsigned long val; 245 + 246 + val = read_c0_config3(); 247 + printk("config3 0x%lx MT %ld\n", val, 248 + (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT); 249 + 250 + val = read_c0_mvpconf0(); 251 + printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val, 252 + (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT, 253 + val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT); 254 + 255 + val = read_c0_mvpcontrol(); 256 + printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val, 257 + (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT, 258 + (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT, 259 + (val & MVPCONTROL_EVP)); 260 + 261 + val = read_c0_vpeconf0(); 262 + printk("VPEConf0 0x%lx MVP %ld\n", val, 263 + (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT); 264 + } 265 + 266 + /* Find some VPE program space */ 267 + static void *alloc_progmem(u32 len) 268 + { 269 + #ifdef CONFIG_MIPS_VPE_LOADER_TOM 270 + /* this means you must tell linux to use less memory than you physically have */ 271 + return (void *)((max_pfn * PAGE_SIZE) + KSEG0); 272 + #else 273 + // simple grab some mem for now 274 + return kmalloc(len, GFP_KERNEL); 275 + #endif 276 + } 277 + 278 + static void release_progmem(void *ptr) 279 + { 280 + #ifndef CONFIG_MIPS_VPE_LOADER_TOM 281 + kfree(ptr); 282 + #endif 283 + } 284 + 285 + /* Update size with this section: return offset. */ 286 + static long get_offset(unsigned long *size, Elf_Shdr * sechdr) 287 + { 288 + long ret; 289 + 290 + ret = ALIGN(*size, sechdr->sh_addralign ? : 1); 291 + *size = ret + sechdr->sh_size; 292 + return ret; 293 + } 294 + 295 + /* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld 296 + might -- code, read-only data, read-write data, small data. Tally 297 + sizes, and place the offsets into sh_entsize fields: high bit means it 298 + belongs in init. */ 299 + static void layout_sections(struct module *mod, const Elf_Ehdr * hdr, 300 + Elf_Shdr * sechdrs, const char *secstrings) 301 + { 302 + static unsigned long const masks[][2] = { 303 + /* NOTE: all executable code must be the first section 304 + * in this array; otherwise modify the text_size 305 + * finder in the two loops below */ 306 + {SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL}, 307 + {SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL}, 308 + {SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL}, 309 + {ARCH_SHF_SMALL | SHF_ALLOC, 0} 310 + }; 311 + unsigned int m, i; 312 + 313 + for (i = 0; i < hdr->e_shnum; i++) 314 + sechdrs[i].sh_entsize = ~0UL; 315 + 316 + for (m = 0; m < ARRAY_SIZE(masks); ++m) { 317 + for (i = 0; i < hdr->e_shnum; ++i) { 318 + Elf_Shdr *s = &sechdrs[i]; 319 + 320 + // || strncmp(secstrings + s->sh_name, ".init", 5) == 0) 321 + if ((s->sh_flags & masks[m][0]) != masks[m][0] 322 + || (s->sh_flags & masks[m][1]) 323 + || s->sh_entsize != ~0UL) 324 + continue; 325 + s->sh_entsize = get_offset(&mod->core_size, s); 326 + } 327 + 328 + if (m == 0) 329 + mod->core_text_size = mod->core_size; 330 + 331 + } 332 + } 333 + 334 + 335 + /* from module-elf32.c, but subverted a little */ 336 + 337 + struct mips_hi16 { 338 + struct mips_hi16 *next; 339 + Elf32_Addr *addr; 340 + Elf32_Addr value; 341 + }; 342 + 343 + static struct mips_hi16 *mips_hi16_list; 344 + static unsigned int gp_offs, gp_addr; 345 + 346 + static int apply_r_mips_none(struct module *me, uint32_t *location, 347 + Elf32_Addr v) 348 + { 349 + return 0; 350 + } 351 + 352 + static int apply_r_mips_gprel16(struct module *me, uint32_t *location, 353 + Elf32_Addr v) 354 + { 355 + int rel; 356 + 357 + if( !(*location & 0xffff) ) { 358 + rel = (int)v - gp_addr; 359 + } 360 + else { 361 + /* .sbss + gp(relative) + offset */ 362 + /* kludge! */ 363 + rel = (int)(short)((int)v + gp_offs + 364 + (int)(short)(*location & 0xffff) - gp_addr); 365 + } 366 + 367 + if( (rel > 32768) || (rel < -32768) ) { 368 + printk(KERN_ERR 369 + "apply_r_mips_gprel16: relative address out of range 0x%x %d\n", 370 + rel, rel); 371 + return -ENOEXEC; 372 + } 373 + 374 + *location = (*location & 0xffff0000) | (rel & 0xffff); 375 + 376 + return 0; 377 + } 378 + 379 + static int apply_r_mips_pc16(struct module *me, uint32_t *location, 380 + Elf32_Addr v) 381 + { 382 + int rel; 383 + rel = (((unsigned int)v - (unsigned int)location)); 384 + rel >>= 2; // because the offset is in _instructions_ not bytes. 385 + rel -= 1; // and one instruction less due to the branch delay slot. 386 + 387 + if( (rel > 32768) || (rel < -32768) ) { 388 + printk(KERN_ERR 389 + "apply_r_mips_pc16: relative address out of range 0x%x\n", rel); 390 + return -ENOEXEC; 391 + } 392 + 393 + *location = (*location & 0xffff0000) | (rel & 0xffff); 394 + 395 + return 0; 396 + } 397 + 398 + static int apply_r_mips_32(struct module *me, uint32_t *location, 399 + Elf32_Addr v) 400 + { 401 + *location += v; 402 + 403 + return 0; 404 + } 405 + 406 + static int apply_r_mips_26(struct module *me, uint32_t *location, 407 + Elf32_Addr v) 408 + { 409 + if (v % 4) { 410 + printk(KERN_ERR "module %s: dangerous relocation mod4\n", me->name); 411 + return -ENOEXEC; 412 + } 413 + 414 + /* Not desperately convinced this is a good check of an overflow condition 415 + anyway. But it gets in the way of handling undefined weak symbols which 416 + we want to set to zero. 417 + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { 418 + printk(KERN_ERR 419 + "module %s: relocation overflow\n", 420 + me->name); 421 + return -ENOEXEC; 422 + } 423 + */ 424 + 425 + *location = (*location & ~0x03ffffff) | 426 + ((*location + (v >> 2)) & 0x03ffffff); 427 + return 0; 428 + } 429 + 430 + static int apply_r_mips_hi16(struct module *me, uint32_t *location, 431 + Elf32_Addr v) 432 + { 433 + struct mips_hi16 *n; 434 + 435 + /* 436 + * We cannot relocate this one now because we don't know the value of 437 + * the carry we need to add. Save the information, and let LO16 do the 438 + * actual relocation. 439 + */ 440 + n = kmalloc(sizeof *n, GFP_KERNEL); 441 + if (!n) 442 + return -ENOMEM; 443 + 444 + n->addr = location; 445 + n->value = v; 446 + n->next = mips_hi16_list; 447 + mips_hi16_list = n; 448 + 449 + return 0; 450 + } 451 + 452 + static int apply_r_mips_lo16(struct module *me, uint32_t *location, 453 + Elf32_Addr v) 454 + { 455 + unsigned long insnlo = *location; 456 + Elf32_Addr val, vallo; 457 + 458 + /* Sign extend the addend we extract from the lo insn. */ 459 + vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; 460 + 461 + if (mips_hi16_list != NULL) { 462 + struct mips_hi16 *l; 463 + 464 + l = mips_hi16_list; 465 + while (l != NULL) { 466 + struct mips_hi16 *next; 467 + unsigned long insn; 468 + 469 + /* 470 + * The value for the HI16 had best be the same. 471 + */ 472 + if (v != l->value) { 473 + printk("%d != %d\n", v, l->value); 474 + goto out_danger; 475 + } 476 + 477 + 478 + /* 479 + * Do the HI16 relocation. Note that we actually don't 480 + * need to know anything about the LO16 itself, except 481 + * where to find the low 16 bits of the addend needed 482 + * by the LO16. 483 + */ 484 + insn = *l->addr; 485 + val = ((insn & 0xffff) << 16) + vallo; 486 + val += v; 487 + 488 + /* 489 + * Account for the sign extension that will happen in 490 + * the low bits. 491 + */ 492 + val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff; 493 + 494 + insn = (insn & ~0xffff) | val; 495 + *l->addr = insn; 496 + 497 + next = l->next; 498 + kfree(l); 499 + l = next; 500 + } 501 + 502 + mips_hi16_list = NULL; 503 + } 504 + 505 + /* 506 + * Ok, we're done with the HI16 relocs. Now deal with the LO16. 507 + */ 508 + val = v + vallo; 509 + insnlo = (insnlo & ~0xffff) | (val & 0xffff); 510 + *location = insnlo; 511 + 512 + return 0; 513 + 514 + out_danger: 515 + printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name); 516 + 517 + return -ENOEXEC; 518 + } 519 + 520 + static int (*reloc_handlers[]) (struct module *me, uint32_t *location, 521 + Elf32_Addr v) = { 522 + [R_MIPS_NONE] = apply_r_mips_none, 523 + [R_MIPS_32] = apply_r_mips_32, 524 + [R_MIPS_26] = apply_r_mips_26, 525 + [R_MIPS_HI16] = apply_r_mips_hi16, 526 + [R_MIPS_LO16] = apply_r_mips_lo16, 527 + [R_MIPS_GPREL16] = apply_r_mips_gprel16, 528 + [R_MIPS_PC16] = apply_r_mips_pc16 529 + }; 530 + 531 + 532 + int apply_relocations(Elf32_Shdr *sechdrs, 533 + const char *strtab, 534 + unsigned int symindex, 535 + unsigned int relsec, 536 + struct module *me) 537 + { 538 + Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr; 539 + Elf32_Sym *sym; 540 + uint32_t *location; 541 + unsigned int i; 542 + Elf32_Addr v; 543 + int res; 544 + 545 + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 546 + Elf32_Word r_info = rel[i].r_info; 547 + 548 + /* This is where to make the change */ 549 + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 550 + + rel[i].r_offset; 551 + /* This is the symbol it is referring to */ 552 + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 553 + + ELF32_R_SYM(r_info); 554 + 555 + if (!sym->st_value) { 556 + printk(KERN_DEBUG "%s: undefined weak symbol %s\n", 557 + me->name, strtab + sym->st_name); 558 + /* just print the warning, dont barf */ 559 + } 560 + 561 + v = sym->st_value; 562 + 563 + res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v); 564 + if( res ) { 565 + printk(KERN_DEBUG 566 + "relocation error 0x%x sym refer <%s> value 0x%x " 567 + "type 0x%x r_info 0x%x\n", 568 + (unsigned int)location, strtab + sym->st_name, v, 569 + r_info, ELF32_R_TYPE(r_info)); 570 + } 571 + 572 + if (res) 573 + return res; 574 + } 575 + 576 + return 0; 577 + } 578 + 579 + void save_gp_address(unsigned int secbase, unsigned int rel) 580 + { 581 + gp_addr = secbase + rel; 582 + gp_offs = gp_addr - (secbase & 0xffff0000); 583 + } 584 + /* end module-elf32.c */ 585 + 586 + 587 + 588 + /* Change all symbols so that sh_value encodes the pointer directly. */ 589 + static int simplify_symbols(Elf_Shdr * sechdrs, 590 + unsigned int symindex, 591 + const char *strtab, 592 + const char *secstrings, 593 + unsigned int nsecs, struct module *mod) 594 + { 595 + Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; 596 + unsigned long secbase, bssbase = 0; 597 + unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); 598 + int ret = 0, size; 599 + 600 + /* find the .bss section for COMMON symbols */ 601 + for (i = 0; i < nsecs; i++) { 602 + if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) 603 + bssbase = sechdrs[i].sh_addr; 604 + } 605 + 606 + for (i = 1; i < n; i++) { 607 + switch (sym[i].st_shndx) { 608 + case SHN_COMMON: 609 + /* Allocate space for the symbol in the .bss section. st_value is currently size. 610 + We want it to have the address of the symbol. */ 611 + 612 + size = sym[i].st_value; 613 + sym[i].st_value = bssbase; 614 + 615 + bssbase += size; 616 + break; 617 + 618 + case SHN_ABS: 619 + /* Don't need to do anything */ 620 + break; 621 + 622 + case SHN_UNDEF: 623 + /* ret = -ENOENT; */ 624 + break; 625 + 626 + case SHN_MIPS_SCOMMON: 627 + 628 + printk(KERN_DEBUG 629 + "simplify_symbols: ignoring SHN_MIPS_SCOMMON symbol <%s> st_shndx %d\n", 630 + strtab + sym[i].st_name, sym[i].st_shndx); 631 + 632 + // .sbss section 633 + break; 634 + 635 + default: 636 + secbase = sechdrs[sym[i].st_shndx].sh_addr; 637 + 638 + if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) { 639 + save_gp_address(secbase, sym[i].st_value); 640 + } 641 + 642 + sym[i].st_value += secbase; 643 + break; 644 + } 645 + 646 + } 647 + 648 + return ret; 649 + } 650 + 651 + #ifdef DEBUG_ELFLOADER 652 + static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex, 653 + const char *strtab, struct module *mod) 654 + { 655 + Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; 656 + unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); 657 + 658 + printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n); 659 + for (i = 1; i < n; i++) { 660 + printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i, 661 + strtab + sym[i].st_name, sym[i].st_value); 662 + } 663 + } 664 + #endif 665 + 666 + static void dump_tc(struct tc *t) 667 + { 668 + printk(KERN_WARNING "VPE: TC index %d TCStatus 0x%lx halt 0x%lx\n", 669 + t->index, read_tc_c0_tcstatus(), read_tc_c0_tchalt()); 670 + printk(KERN_WARNING "VPE: tcrestart 0x%lx\n", read_tc_c0_tcrestart()); 671 + } 672 + 673 + static void dump_tclist(void) 674 + { 675 + struct tc *t; 676 + 677 + list_for_each_entry(t, &vpecontrol.tc_list, list) { 678 + dump_tc(t); 679 + } 680 + } 681 + 682 + /* We are prepared so configure and start the VPE... */ 683 + int vpe_run(vpe_t * v) 684 + { 685 + unsigned long val; 686 + struct tc *t; 687 + 688 + /* check we are the Master VPE */ 689 + val = read_c0_vpeconf0(); 690 + if (!(val & VPECONF0_MVP)) { 691 + printk(KERN_WARNING 692 + "VPE: only Master VPE's are allowed to configure MT\n"); 693 + return -1; 694 + } 695 + 696 + /* disable MT (using dvpe) */ 697 + dvpe(); 698 + 699 + /* Put MVPE's into 'configuration state' */ 700 + write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); 701 + 702 + if (!list_empty(&v->tc)) { 703 + if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { 704 + printk(KERN_WARNING "VPE: TC %d is already in use.\n", 705 + t->index); 706 + return -ENOEXEC; 707 + } 708 + } else { 709 + printk(KERN_WARNING "VPE: No TC's associated with VPE %d\n", 710 + v->minor); 711 + return -ENOEXEC; 712 + } 713 + 714 + settc(t->index); 715 + 716 + val = read_vpe_c0_vpeconf0(); 717 + 718 + /* should check it is halted, and not activated */ 719 + if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) { 720 + printk(KERN_WARNING "VPE: TC %d is already doing something!\n", 721 + t->index); 722 + 723 + dump_tclist(); 724 + return -ENOEXEC; 725 + } 726 + 727 + /* Write the address we want it to start running from in the TCPC register. */ 728 + write_tc_c0_tcrestart((unsigned long)v->__start); 729 + 730 + /* write the sivc_info address to tccontext */ 731 + write_tc_c0_tccontext((unsigned long)0); 732 + 733 + /* Set up the XTC bit in vpeconf0 to point at our tc */ 734 + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (t->index << VPECONF0_XTC_SHIFT)); 735 + 736 + /* mark the TC as activated, not interrupt exempt and not dynamically allocatable */ 737 + val = read_tc_c0_tcstatus(); 738 + val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A; 739 + write_tc_c0_tcstatus(val); 740 + 741 + write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); 742 + 743 + /* set up VPE1 */ 744 + write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); // no multiple TC's 745 + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); // enable this VPE 746 + 747 + /* 748 + * The sde-kit passes 'memsize' to __start in $a3, so set something 749 + * here... 750 + * Or set $a3 (register 7) to zero and define DFLT_STACK_SIZE and 751 + * DFLT_HEAP_SIZE when you compile your program 752 + */ 753 + 754 + mttgpr(7, 0); 755 + 756 + /* set config to be the same as vpe0, particularly kseg0 coherency alg */ 757 + write_vpe_c0_config(read_c0_config()); 758 + 759 + /* clear out any left overs from a previous program */ 760 + write_vpe_c0_cause(0); 761 + 762 + /* take system out of configuration state */ 763 + write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); 764 + 765 + /* clear interrupts enabled IE, ERL, EXL, and KSU from c0 status */ 766 + write_vpe_c0_status(read_vpe_c0_status() & ~(ST0_ERL | ST0_KSU | ST0_IE | ST0_EXL)); 767 + 768 + /* set it running */ 769 + evpe(EVPE_ENABLE); 770 + 771 + return 0; 772 + } 773 + 774 + static unsigned long find_vpe_symbols(vpe_t * v, Elf_Shdr * sechdrs, 775 + unsigned int symindex, const char *strtab, 776 + struct module *mod) 777 + { 778 + Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; 779 + unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); 780 + 781 + for (i = 1; i < n; i++) { 782 + if (strcmp(strtab + sym[i].st_name, "__start") == 0) { 783 + v->__start = sym[i].st_value; 784 + } 785 + 786 + if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0) { 787 + v->shared_ptr = (void *)sym[i].st_value; 788 + } 789 + } 790 + 791 + return 0; 792 + } 793 + 794 + /* Allocates a VPE with some program code space(the load address), copies the contents 795 + of the program (p)buffer performing relocatations/etc, free's it when finished. 796 + */ 797 + int vpe_elfload(vpe_t * v) 798 + { 799 + Elf_Ehdr *hdr; 800 + Elf_Shdr *sechdrs; 801 + long err = 0; 802 + char *secstrings, *strtab = NULL; 803 + unsigned int len, i, symindex = 0, strindex = 0; 804 + 805 + struct module mod; // so we can re-use the relocations code 806 + 807 + memset(&mod, 0, sizeof(struct module)); 808 + strcpy(mod.name, "VPE dummy prog module"); 809 + 810 + hdr = (Elf_Ehdr *) v->pbuffer; 811 + len = v->plen; 812 + 813 + /* Sanity checks against insmoding binaries or wrong arch, 814 + weird elf version */ 815 + if (memcmp(hdr->e_ident, ELFMAG, 4) != 0 816 + || hdr->e_type != ET_REL || !elf_check_arch(hdr) 817 + || hdr->e_shentsize != sizeof(*sechdrs)) { 818 + printk(KERN_WARNING 819 + "VPE program, wrong arch or weird elf version\n"); 820 + 821 + return -ENOEXEC; 822 + } 823 + 824 + if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) { 825 + printk(KERN_ERR "VPE program length %u truncated\n", len); 826 + return -ENOEXEC; 827 + } 828 + 829 + /* Convenience variables */ 830 + sechdrs = (void *)hdr + hdr->e_shoff; 831 + secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 832 + sechdrs[0].sh_addr = 0; 833 + 834 + /* And these should exist, but gcc whinges if we don't init them */ 835 + symindex = strindex = 0; 836 + 837 + for (i = 1; i < hdr->e_shnum; i++) { 838 + 839 + if (sechdrs[i].sh_type != SHT_NOBITS 840 + && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) { 841 + printk(KERN_ERR "VPE program length %u truncated\n", 842 + len); 843 + return -ENOEXEC; 844 + } 845 + 846 + /* Mark all sections sh_addr with their address in the 847 + temporary image. */ 848 + sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset; 849 + 850 + /* Internal symbols and strings. */ 851 + if (sechdrs[i].sh_type == SHT_SYMTAB) { 852 + symindex = i; 853 + strindex = sechdrs[i].sh_link; 854 + strtab = (char *)hdr + sechdrs[strindex].sh_offset; 855 + } 856 + } 857 + 858 + layout_sections(&mod, hdr, sechdrs, secstrings); 859 + 860 + v->load_addr = alloc_progmem(mod.core_size); 861 + memset(v->load_addr, 0, mod.core_size); 862 + 863 + printk("VPE elf_loader: loading to %p\n", v->load_addr); 864 + 865 + for (i = 0; i < hdr->e_shnum; i++) { 866 + void *dest; 867 + 868 + if (!(sechdrs[i].sh_flags & SHF_ALLOC)) 869 + continue; 870 + 871 + dest = v->load_addr + sechdrs[i].sh_entsize; 872 + 873 + if (sechdrs[i].sh_type != SHT_NOBITS) 874 + memcpy(dest, (void *)sechdrs[i].sh_addr, 875 + sechdrs[i].sh_size); 876 + /* Update sh_addr to point to copy in image. */ 877 + sechdrs[i].sh_addr = (unsigned long)dest; 878 + } 879 + 880 + /* Fix up syms, so that st_value is a pointer to location. */ 881 + err = 882 + simplify_symbols(sechdrs, symindex, strtab, secstrings, 883 + hdr->e_shnum, &mod); 884 + if (err < 0) { 885 + printk(KERN_WARNING "VPE: unable to simplify symbols\n"); 886 + goto cleanup; 887 + } 888 + 889 + /* Now do relocations. */ 890 + for (i = 1; i < hdr->e_shnum; i++) { 891 + const char *strtab = (char *)sechdrs[strindex].sh_addr; 892 + unsigned int info = sechdrs[i].sh_info; 893 + 894 + /* Not a valid relocation section? */ 895 + if (info >= hdr->e_shnum) 896 + continue; 897 + 898 + /* Don't bother with non-allocated sections */ 899 + if (!(sechdrs[info].sh_flags & SHF_ALLOC)) 900 + continue; 901 + 902 + if (sechdrs[i].sh_type == SHT_REL) 903 + err = 904 + apply_relocations(sechdrs, strtab, symindex, i, &mod); 905 + else if (sechdrs[i].sh_type == SHT_RELA) 906 + err = apply_relocate_add(sechdrs, strtab, symindex, i, 907 + &mod); 908 + if (err < 0) { 909 + printk(KERN_WARNING 910 + "vpe_elfload: error in relocations err %ld\n", 911 + err); 912 + goto cleanup; 913 + } 914 + } 915 + 916 + /* make sure it's physically written out */ 917 + flush_icache_range((unsigned long)v->load_addr, 918 + (unsigned long)v->load_addr + v->len); 919 + 920 + if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { 921 + 922 + printk(KERN_WARNING 923 + "VPE: program doesn't contain __start or vpe_shared symbols\n"); 924 + err = -ENOEXEC; 925 + } 926 + 927 + printk(" elf loaded\n"); 928 + 929 + cleanup: 930 + return err; 931 + } 932 + 933 + static void dump_vpe(vpe_t * v) 934 + { 935 + struct tc *t; 936 + 937 + printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol()); 938 + printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0()); 939 + 940 + list_for_each_entry(t, &vpecontrol.tc_list, list) { 941 + dump_tc(t); 942 + } 943 + } 944 + 945 + /* checks for VPE is unused and gets ready to load program */ 946 + static int vpe_open(struct inode *inode, struct file *filp) 947 + { 948 + int minor; 949 + vpe_t *v; 950 + 951 + /* assume only 1 device at the mo. */ 952 + if ((minor = MINOR(inode->i_rdev)) != 1) { 953 + printk(KERN_WARNING "VPE: only vpe1 is supported\n"); 954 + return -ENODEV; 955 + } 956 + 957 + if ((v = get_vpe(minor)) == NULL) { 958 + printk(KERN_WARNING "VPE: unable to get vpe\n"); 959 + return -ENODEV; 960 + } 961 + 962 + if (v->state != VPE_STATE_UNUSED) { 963 + unsigned long tmp; 964 + struct tc *t; 965 + 966 + printk(KERN_WARNING "VPE: device %d already in use\n", minor); 967 + 968 + dvpe(); 969 + dump_vpe(v); 970 + 971 + printk(KERN_WARNING "VPE: re-initialising %d\n", minor); 972 + 973 + release_progmem(v->load_addr); 974 + 975 + t = get_tc(minor); 976 + settc(minor); 977 + tmp = read_tc_c0_tcstatus(); 978 + 979 + /* mark not allocated and not dynamically allocatable */ 980 + tmp &= ~(TCSTATUS_A | TCSTATUS_DA); 981 + tmp |= TCSTATUS_IXMT; /* interrupt exempt */ 982 + write_tc_c0_tcstatus(tmp); 983 + 984 + write_tc_c0_tchalt(TCHALT_H); 985 + 986 + } 987 + 988 + // allocate it so when we get write ops we know it's expected. 989 + v->state = VPE_STATE_INUSE; 990 + 991 + /* this of-course trashes what was there before... */ 992 + v->pbuffer = vmalloc(P_SIZE); 993 + v->plen = P_SIZE; 994 + v->load_addr = NULL; 995 + v->len = 0; 996 + 997 + return 0; 998 + } 999 + 1000 + static int vpe_release(struct inode *inode, struct file *filp) 1001 + { 1002 + int minor, ret = 0; 1003 + vpe_t *v; 1004 + Elf_Ehdr *hdr; 1005 + 1006 + minor = MINOR(inode->i_rdev); 1007 + if ((v = get_vpe(minor)) == NULL) 1008 + return -ENODEV; 1009 + 1010 + // simple case of fire and forget, so tell the VPE to run... 1011 + 1012 + hdr = (Elf_Ehdr *) v->pbuffer; 1013 + if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) { 1014 + if (vpe_elfload(v) >= 0) 1015 + vpe_run(v); 1016 + else { 1017 + printk(KERN_WARNING "VPE: ELF load failed.\n"); 1018 + ret = -ENOEXEC; 1019 + } 1020 + } else { 1021 + printk(KERN_WARNING "VPE: only elf files are supported\n"); 1022 + ret = -ENOEXEC; 1023 + } 1024 + 1025 + // cleanup any temp buffers 1026 + if (v->pbuffer) 1027 + vfree(v->pbuffer); 1028 + v->plen = 0; 1029 + return ret; 1030 + } 1031 + 1032 + static ssize_t vpe_write(struct file *file, const char __user * buffer, 1033 + size_t count, loff_t * ppos) 1034 + { 1035 + int minor; 1036 + size_t ret = count; 1037 + vpe_t *v; 1038 + 1039 + minor = MINOR(file->f_dentry->d_inode->i_rdev); 1040 + if ((v = get_vpe(minor)) == NULL) 1041 + return -ENODEV; 1042 + 1043 + if (v->pbuffer == NULL) { 1044 + printk(KERN_ERR "vpe_write: no pbuffer\n"); 1045 + return -ENOMEM; 1046 + } 1047 + 1048 + if ((count + v->len) > v->plen) { 1049 + printk(KERN_WARNING 1050 + "VPE Loader: elf size too big. Perhaps strip uneeded symbols\n"); 1051 + return -ENOMEM; 1052 + } 1053 + 1054 + count -= copy_from_user(v->pbuffer + v->len, buffer, count); 1055 + if (!count) { 1056 + printk("vpe_write: copy_to_user failed\n"); 1057 + return -EFAULT; 1058 + } 1059 + 1060 + v->len += count; 1061 + return ret; 1062 + } 1063 + 1064 + static struct file_operations vpe_fops = { 1065 + .owner = THIS_MODULE, 1066 + .open = vpe_open, 1067 + .release = vpe_release, 1068 + .write = vpe_write 1069 + }; 1070 + 1071 + /* module wrapper entry points */ 1072 + /* give me a vpe */ 1073 + vpe_handle vpe_alloc(void) 1074 + { 1075 + int i; 1076 + struct vpe *v; 1077 + 1078 + /* find a vpe */ 1079 + for (i = 1; i < MAX_VPES; i++) { 1080 + if ((v = get_vpe(i)) != NULL) { 1081 + v->state = VPE_STATE_INUSE; 1082 + return v; 1083 + } 1084 + } 1085 + return NULL; 1086 + } 1087 + 1088 + EXPORT_SYMBOL(vpe_alloc); 1089 + 1090 + /* start running from here */ 1091 + int vpe_start(vpe_handle vpe, unsigned long start) 1092 + { 1093 + struct vpe *v = vpe; 1094 + 1095 + v->__start = start; 1096 + return vpe_run(v); 1097 + } 1098 + 1099 + EXPORT_SYMBOL(vpe_start); 1100 + 1101 + /* halt it for now */ 1102 + int vpe_stop(vpe_handle vpe) 1103 + { 1104 + struct vpe *v = vpe; 1105 + struct tc *t; 1106 + unsigned int evpe_flags; 1107 + 1108 + evpe_flags = dvpe(); 1109 + 1110 + if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) { 1111 + 1112 + settc(t->index); 1113 + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); 1114 + } 1115 + 1116 + evpe(evpe_flags); 1117 + 1118 + return 0; 1119 + } 1120 + 1121 + EXPORT_SYMBOL(vpe_stop); 1122 + 1123 + /* I've done with it thank you */ 1124 + int vpe_free(vpe_handle vpe) 1125 + { 1126 + struct vpe *v = vpe; 1127 + struct tc *t; 1128 + unsigned int evpe_flags; 1129 + 1130 + if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { 1131 + return -ENOEXEC; 1132 + } 1133 + 1134 + evpe_flags = dvpe(); 1135 + 1136 + /* Put MVPE's into 'configuration state' */ 1137 + write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); 1138 + 1139 + settc(t->index); 1140 + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); 1141 + 1142 + /* mark the TC unallocated and halt'ed */ 1143 + write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A); 1144 + write_tc_c0_tchalt(TCHALT_H); 1145 + 1146 + v->state = VPE_STATE_UNUSED; 1147 + 1148 + write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); 1149 + evpe(evpe_flags); 1150 + 1151 + return 0; 1152 + } 1153 + 1154 + EXPORT_SYMBOL(vpe_free); 1155 + 1156 + void *vpe_get_shared(int index) 1157 + { 1158 + struct vpe *v; 1159 + 1160 + if ((v = get_vpe(index)) == NULL) { 1161 + printk(KERN_WARNING "vpe: invalid vpe index %d\n", index); 1162 + return NULL; 1163 + } 1164 + 1165 + return v->shared_ptr; 1166 + } 1167 + 1168 + EXPORT_SYMBOL(vpe_get_shared); 1169 + 1170 + static int __init vpe_module_init(void) 1171 + { 1172 + struct vpe *v = NULL; 1173 + struct tc *t; 1174 + unsigned long val; 1175 + int i; 1176 + 1177 + if (!cpu_has_mipsmt) { 1178 + printk("VPE loader: not a MIPS MT capable processor\n"); 1179 + return -ENODEV; 1180 + } 1181 + 1182 + if ((major = register_chrdev(VPE_MAJOR, module_name, &vpe_fops) < 0)) { 1183 + printk("VPE loader: unable to register character device\n"); 1184 + return -EBUSY; 1185 + } 1186 + 1187 + if (major == 0) 1188 + major = VPE_MAJOR; 1189 + 1190 + dmt(); 1191 + dvpe(); 1192 + 1193 + /* Put MVPE's into 'configuration state' */ 1194 + write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); 1195 + 1196 + /* dump_mtregs(); */ 1197 + 1198 + INIT_LIST_HEAD(&vpecontrol.vpe_list); 1199 + INIT_LIST_HEAD(&vpecontrol.tc_list); 1200 + 1201 + val = read_c0_mvpconf0(); 1202 + for (i = 0; i < ((val & MVPCONF0_PTC) + 1); i++) { 1203 + t = alloc_tc(i); 1204 + 1205 + /* VPE's */ 1206 + if (i < ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1) { 1207 + settc(i); 1208 + 1209 + if ((v = alloc_vpe(i)) == NULL) { 1210 + printk(KERN_WARNING "VPE: unable to allocate VPE\n"); 1211 + return -ENODEV; 1212 + } 1213 + 1214 + list_add(&t->tc, &v->tc); /* add the tc to the list of this vpe's tc's. */ 1215 + 1216 + /* deactivate all but vpe0 */ 1217 + if (i != 0) { 1218 + unsigned long tmp = read_vpe_c0_vpeconf0(); 1219 + 1220 + tmp &= ~VPECONF0_VPA; 1221 + 1222 + /* master VPE */ 1223 + tmp |= VPECONF0_MVP; 1224 + write_vpe_c0_vpeconf0(tmp); 1225 + } 1226 + 1227 + /* disable multi-threading with TC's */ 1228 + write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); 1229 + 1230 + if (i != 0) { 1231 + write_vpe_c0_status((read_c0_status() & 1232 + ~(ST0_IM | ST0_IE | ST0_KSU)) 1233 + | ST0_CU0); 1234 + 1235 + /* set config to be the same as vpe0, particularly kseg0 coherency alg */ 1236 + write_vpe_c0_config(read_c0_config()); 1237 + } 1238 + 1239 + } 1240 + 1241 + /* TC's */ 1242 + t->pvpe = v; /* set the parent vpe */ 1243 + 1244 + if (i != 0) { 1245 + unsigned long tmp; 1246 + 1247 + /* tc 0 will of course be running.... */ 1248 + if (i == 0) 1249 + t->state = TC_STATE_RUNNING; 1250 + 1251 + settc(i); 1252 + 1253 + /* bind a TC to each VPE, May as well put all excess TC's 1254 + on the last VPE */ 1255 + if (i >= (((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1)) 1256 + write_tc_c0_tcbind(read_tc_c0_tcbind() | 1257 + ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)); 1258 + else 1259 + write_tc_c0_tcbind(read_tc_c0_tcbind() | i); 1260 + 1261 + tmp = read_tc_c0_tcstatus(); 1262 + 1263 + /* mark not allocated and not dynamically allocatable */ 1264 + tmp &= ~(TCSTATUS_A | TCSTATUS_DA); 1265 + tmp |= TCSTATUS_IXMT; /* interrupt exempt */ 1266 + write_tc_c0_tcstatus(tmp); 1267 + 1268 + write_tc_c0_tchalt(TCHALT_H); 1269 + } 1270 + } 1271 + 1272 + /* release config state */ 1273 + write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); 1274 + 1275 + return 0; 1276 + } 1277 + 1278 + static void __exit vpe_module_exit(void) 1279 + { 1280 + struct vpe *v, *n; 1281 + 1282 + list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) { 1283 + if (v->state != VPE_STATE_UNUSED) { 1284 + release_vpe(v); 1285 + } 1286 + } 1287 + 1288 + unregister_chrdev(major, module_name); 1289 + } 1290 + 1291 + module_init(vpe_module_init); 1292 + module_exit(vpe_module_exit); 1293 + MODULE_DESCRIPTION("MIPS VPE Loader"); 1294 + MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc"); 1295 + MODULE_LICENSE("GPL");
+29
arch/mips/mips-boards/generic/init.c
··· 28 28 #include <asm/gt64120.h> 29 29 #include <asm/io.h> 30 30 #include <asm/system.h> 31 + #include <asm/cacheflush.h> 32 + #include <asm/traps.h> 31 33 32 34 #include <asm/mips-boards/prom.h> 33 35 #include <asm/mips-boards/generic.h> ··· 226 224 } 227 225 #endif 228 226 227 + void __init mips_nmi_setup (void) 228 + { 229 + void *base; 230 + extern char except_vec_nmi; 231 + 232 + base = cpu_has_veic ? 233 + (void *)(CAC_BASE + 0xa80) : 234 + (void *)(CAC_BASE + 0x380); 235 + memcpy(base, &except_vec_nmi, 0x80); 236 + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); 237 + } 238 + 239 + void __init mips_ejtag_setup (void) 240 + { 241 + void *base; 242 + extern char except_vec_ejtag_debug; 243 + 244 + base = cpu_has_veic ? 245 + (void *)(CAC_BASE + 0xa00) : 246 + (void *)(CAC_BASE + 0x300); 247 + memcpy(base, &except_vec_ejtag_debug, 0x80); 248 + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); 249 + } 250 + 229 251 void __init prom_init(void) 230 252 { 231 253 u32 start, map, mask, data; ··· 379 353 while(1); /* We die here... */ 380 354 } 381 355 #endif 356 + board_nmi_handler_setup = mips_nmi_setup; 357 + board_ejtag_handler_setup = mips_ejtag_setup; 358 + 382 359 prom_printf("\nLINUX started...\n"); 383 360 prom_init_cmdline(); 384 361 prom_meminit();
+23 -10
arch/mips/mips-boards/generic/memory.c
··· 22 22 #include <linux/init.h> 23 23 #include <linux/mm.h> 24 24 #include <linux/bootmem.h> 25 + #include <linux/string.h> 25 26 26 27 #include <asm/bootinfo.h> 27 28 #include <asm/page.h> ··· 56 55 { 57 56 char *memsize_str; 58 57 unsigned int memsize; 58 + char cmdline[CL_SIZE], *ptr; 59 59 60 - memsize_str = prom_getenv("memsize"); 61 - if (!memsize_str) { 62 - prom_printf("memsize not set in boot prom, set to default (32Mb)\n"); 63 - memsize = 0x02000000; 64 - } else { 65 - #ifdef DEBUG 66 - prom_printf("prom_memsize = %s\n", memsize_str); 67 - #endif 68 - memsize = simple_strtol(memsize_str, NULL, 0); 60 + /* Check the command line first for a memsize directive */ 61 + strcpy(cmdline, arcs_cmdline); 62 + ptr = strstr(cmdline, "memsize="); 63 + if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' ')) 64 + ptr = strstr(ptr, " memsize="); 65 + 66 + if (ptr) { 67 + memsize = memparse(ptr + 8, &ptr); 69 68 } 70 - 69 + else { 70 + /* otherwise look in the environment */ 71 + memsize_str = prom_getenv("memsize"); 72 + if (!memsize_str) { 73 + prom_printf("memsize not set in boot prom, set to default (32Mb)\n"); 74 + memsize = 0x02000000; 75 + } else { 76 + #ifdef DEBUG 77 + prom_printf("prom_memsize = %s\n", memsize_str); 78 + #endif 79 + memsize = simple_strtol(memsize_str, NULL, 0); 80 + } 81 + } 71 82 memset(mdesc, 0, sizeof(mdesc)); 72 83 73 84 mdesc[0].type = yamon_dontuse;
+59 -57
arch/mips/mips-boards/generic/mipsIRQ.S
··· 29 29 #include <asm/regdef.h> 30 30 #include <asm/stackframe.h> 31 31 32 + #ifdef CONFIG_MIPS_ATLAS 33 + #include <asm/mips-boards/atlasint.h> 34 + #define CASCADE_IRQ MIPSCPU_INT_ATLAS 35 + #define CASCADE_DISPATCH atlas_hw0_irqdispatch 36 + #endif 37 + #ifdef CONFIG_MIPS_MALTA 38 + #include <asm/mips-boards/maltaint.h> 39 + #define CASCADE_IRQ MIPSCPU_INT_I8259A 40 + #define CASCADE_DISPATCH malta_hw0_irqdispatch 41 + #endif 42 + #ifdef CONFIG_MIPS_SEAD 43 + #include <asm/mips-boards/seadint.h> 44 + #endif 45 + 32 46 /* A lot of complication here is taken away because: 33 47 * 34 48 * 1) We handle one interrupt and return, sitting in a loop and moving across ··· 94 80 95 81 mfc0 s0, CP0_CAUSE # get irq bits 96 82 mfc0 s1, CP0_STATUS # get irq mask 83 + andi s0, ST0_IM # CAUSE.CE may be non-zero! 97 84 and s0, s1 98 85 99 - /* First we check for r4k counter/timer IRQ. */ 100 - andi a0, s0, CAUSEF_IP7 101 - beq a0, zero, 1f 102 - andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt 103 - 104 - /* Wheee, a timer interrupt. */ 105 - move a0, sp 106 - jal mips_timer_interrupt 107 - nop 108 - 109 - j ret_from_irq 110 - nop 111 - 112 - 1: 113 - #if defined(CONFIG_MIPS_SEAD) 114 - beq a0, zero, 1f 115 - andi a0, s0, CAUSEF_IP3 # delay slot, check hw1 interrupt 86 + #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) 87 + .set mips32 88 + clz a0, s0 89 + .set mips0 90 + negu a0 91 + addu a0, 31-CAUSEB_IP 92 + bltz a0, spurious 116 93 #else 117 - beq a0, zero, 1f # delay slot, check hw3 interrupt 118 - andi a0, s0, CAUSEF_IP5 94 + beqz s0, spurious 95 + li a0, 7 96 + 97 + and t0, s0, 0xf000 98 + sltiu t0, t0, 1 99 + sll t0, 2 100 + subu a0, t0 101 + sll s0, t0 102 + 103 + and t0, s0, 0xc000 104 + sltiu t0, t0, 1 105 + sll t0, 1 106 + subu a0, t0 107 + sll s0, t0 108 + 109 + and t0, s0, 0x8000 110 + sltiu t0, t0, 1 111 + # sll t0, 0 112 + subu a0, t0 113 + # sll s0, t0 119 114 #endif 120 115 121 - /* Wheee, combined hardware level zero interrupt. */ 122 - #if defined(CONFIG_MIPS_ATLAS) 123 - jal atlas_hw0_irqdispatch 124 - #elif defined(CONFIG_MIPS_MALTA) 125 - jal malta_hw0_irqdispatch 126 - #elif defined(CONFIG_MIPS_SEAD) 127 - jal sead_hw0_irqdispatch 116 + #ifdef CASCADE_IRQ 117 + li a1, CASCADE_IRQ 118 + bne a0, a1, 1f 119 + addu a0, MIPSCPU_INT_BASE 120 + 121 + jal CASCADE_DISPATCH 122 + move a0, sp 123 + 124 + j ret_from_irq 125 + nop 126 + 1: 128 127 #else 129 - #error "MIPS board not supported\n" 128 + addu a0, MIPSCPU_INT_BASE 130 129 #endif 131 - move a0, sp # delay slot 132 130 133 - j ret_from_irq 134 - nop # delay slot 131 + jal do_IRQ 132 + move a1, sp 135 133 136 - 1: 137 - #if defined(CONFIG_MIPS_SEAD) 138 - beq a0, zero, 1f 139 - andi a0, s0, CAUSEF_IP5 # delay slot, check hw3 interrupt 140 - jal sead_hw1_irqdispatch 141 - move a0, sp # delay slot 142 - j ret_from_irq 143 - nop # delay slot 144 - 1: 145 - #endif 146 - #if defined(CONFIG_MIPS_MALTA) 147 - beq a0, zero, 1f # check hw3 (coreHI) interrupt 148 - nop 149 - jal corehi_irqdispatch 150 - move a0, sp 151 134 j ret_from_irq 152 135 nop 153 - 1: 154 - #endif 155 - /* 156 - * Here by mistake? This is possible, what can happen is that by the 157 - * time we take the exception the IRQ pin goes low, so just leave if 158 - * this is the case. 159 - */ 160 - move a1,s0 161 - PRINT("Got interrupt: c0_cause = %08x\n") 162 - mfc0 a1, CP0_EPC 163 - PRINT("c0_epc = %08x\n") 164 136 165 - j ret_from_irq 137 + 138 + spurious: 139 + j spurious_interrupt 166 140 nop 167 141 END(mipsIRQ)
+32 -17
arch/mips/mips-boards/generic/time.c
··· 31 31 32 32 #include <asm/mipsregs.h> 33 33 #include <asm/ptrace.h> 34 + #include <asm/hardirq.h> 35 + #include <asm/irq.h> 34 36 #include <asm/div64.h> 35 37 #include <asm/cpu.h> 36 38 #include <asm/time.h> 37 39 #include <asm/mc146818-time.h> 40 + #include <asm/msc01_ic.h> 38 41 39 42 #include <asm/mips-boards/generic.h> 40 43 #include <asm/mips-boards/prom.h> 44 + #include <asm/mips-boards/maltaint.h> 45 + #include <asm/mc146818-time.h> 41 46 42 47 unsigned long cpu_khz; 43 - 44 - #if defined(CONFIG_MIPS_SEAD) 45 - #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ5) 46 - #else 47 - #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) 48 - #endif 49 48 50 49 #if defined(CONFIG_MIPS_ATLAS) 51 50 static char display_string[] = " LINUX ON ATLAS "; ··· 58 59 static unsigned int display_count = 0; 59 60 #define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) 60 61 61 - #define MIPS_CPU_TIMER_IRQ (NR_IRQS-1) 62 - 63 62 static unsigned int timer_tick_count=0; 63 + static int mips_cpu_timer_irq; 64 64 65 - void mips_timer_interrupt(struct pt_regs *regs) 65 + static void mips_timer_dispatch (struct pt_regs *regs) 66 66 { 67 + do_IRQ (mips_cpu_timer_irq, regs); 68 + } 69 + 70 + irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 71 + { 72 + irqreturn_t r; 73 + 74 + r = timer_interrupt(irq, dev_id, regs); 75 + 67 76 if ((timer_tick_count++ % HZ) == 0) { 68 77 mips_display_message(&display_string[display_count++]); 69 78 if (display_count == MAX_DISPLAY_COUNT) 70 - display_count = 0; 71 - 79 + display_count = 0; 72 80 } 73 81 74 - ll_timer_interrupt(MIPS_CPU_TIMER_IRQ, regs); 82 + return r; 75 83 } 76 84 77 85 /* ··· 146 140 147 141 local_irq_save(flags); 148 142 149 - #if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_MALTA) 150 143 /* Set Data mode - binary. */ 151 144 CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); 152 - #endif 153 145 154 146 est_freq = estimate_cpu_frequency (); 155 147 ··· 161 157 162 158 void __init mips_timer_setup(struct irqaction *irq) 163 159 { 160 + if (cpu_has_veic) { 161 + set_vi_handler (MSC01E_INT_CPUCTR, mips_timer_dispatch); 162 + mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; 163 + } 164 + else { 165 + if (cpu_has_vint) 166 + set_vi_handler (MIPSCPU_INT_CPUCTR, mips_timer_dispatch); 167 + mips_cpu_timer_irq = MIPSCPU_INT_BASE + MIPSCPU_INT_CPUCTR; 168 + } 169 + 170 + 164 171 /* we are using the cpu counter for timer interrupts */ 165 - irq->handler = no_action; /* we use our own handler */ 166 - setup_irq(MIPS_CPU_TIMER_IRQ, irq); 172 + irq->handler = mips_timer_interrupt; /* we use our own handler */ 173 + setup_irq(mips_cpu_timer_irq, irq); 174 + 167 175 168 176 /* to generate the first timer interrupt */ 169 177 write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ); 170 - set_c0_status(ALLINTS); 171 178 }
+105 -31
arch/mips/mips-boards/malta/malta_int.c
··· 30 30 #include <linux/random.h> 31 31 32 32 #include <asm/i8259.h> 33 + #include <asm/irq_cpu.h> 33 34 #include <asm/io.h> 34 35 #include <asm/mips-boards/malta.h> 35 36 #include <asm/mips-boards/maltaint.h> ··· 38 37 #include <asm/gt64120.h> 39 38 #include <asm/mips-boards/generic.h> 40 39 #include <asm/mips-boards/msc01_pci.h> 40 + #include <asm/msc01_ic.h> 41 41 42 42 extern asmlinkage void mipsIRQ(void); 43 + extern void mips_timer_interrupt(void); 43 44 44 45 static DEFINE_SPINLOCK(mips_irq_lock); 45 46 ··· 94 91 return irq; 95 92 } 96 93 97 - static inline int get_int(int *irq) 94 + static inline int get_int(void) 98 95 { 99 96 unsigned long flags; 100 - 97 + int irq; 101 98 spin_lock_irqsave(&mips_irq_lock, flags); 102 99 103 - *irq = mips_pcibios_iack(); 100 + irq = mips_pcibios_iack(); 104 101 105 102 /* 106 103 * IRQ7 is used to detect spurious interrupts. ··· 109 106 * We can differentiate between this situation and a 110 107 * "Normal" IRQ7 by reading the ISR. 111 108 */ 112 - if (*irq == 7) 109 + if (irq == 7) 113 110 { 114 111 outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR, 115 112 PIIX4_ICTLR1_OCW3); 116 113 if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7))) { 117 - spin_unlock_irqrestore(&mips_irq_lock, flags); 114 + irq = -1; /* Spurious interrupt */ 118 115 printk("We got a spurious interrupt from PIIX4.\n"); 119 116 atomic_inc(&irq_err_count); 120 - return -1; /* Spurious interrupt. */ 121 117 } 122 118 } 123 119 124 120 spin_unlock_irqrestore(&mips_irq_lock, flags); 125 121 126 - return 0; 122 + return irq; 127 123 } 128 124 129 125 void malta_hw0_irqdispatch(struct pt_regs *regs) 130 126 { 131 127 int irq; 132 128 133 - if (get_int(&irq)) 134 - return; /* interrupt has already been cleared */ 129 + irq = get_int(); 130 + if (irq < 0) 131 + return; /* interrupt has already been cleared */ 135 132 136 - do_IRQ(irq, regs); 133 + do_IRQ(MALTA_INT_BASE+irq, regs); 137 134 } 138 135 139 136 void corehi_irqdispatch(struct pt_regs *regs) 140 137 { 141 - unsigned int data,datahi; 142 - 143 - /* Mask out corehi interrupt. */ 144 - clear_c0_status(IE_IRQ3); 138 + unsigned int intrcause,datalo,datahi; 139 + unsigned int pcimstat, intisr, inten, intpol, intedge, intsteer, pcicmd, pcibadaddr; 145 140 146 141 printk("CoreHI interrupt, shouldn't happen, so we die here!!!\n"); 147 142 printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\nbadVaddr : %08lx\n" 148 143 , regs->cp0_epc, regs->cp0_status, regs->cp0_cause, regs->cp0_badvaddr); 144 + 145 + /* Read all the registers and then print them as there is a 146 + problem with interspersed printk's upsetting the Bonito controller. 147 + Do it for the others too. 148 + */ 149 + 149 150 switch(mips_revision_corid) { 150 151 case MIPS_REVISION_CORID_CORE_MSC: 151 152 case MIPS_REVISION_CORID_CORE_FPGA2: 152 - case MIPS_REVISION_CORID_CORE_EMUL_MSC: 153 + case MIPS_REVISION_CORID_CORE_EMUL_MSC: 154 + ll_msc_irq(regs); 153 155 break; 154 156 case MIPS_REVISION_CORID_QED_RM5261: 155 157 case MIPS_REVISION_CORID_CORE_LV: 156 158 case MIPS_REVISION_CORID_CORE_FPGA: 157 159 case MIPS_REVISION_CORID_CORE_FPGAR2: 158 - data = GT_READ(GT_INTRCAUSE_OFS); 159 - printk("GT_INTRCAUSE = %08x\n", data); 160 - data = GT_READ(GT_CPUERR_ADDRLO_OFS); 160 + intrcause = GT_READ(GT_INTRCAUSE_OFS); 161 + datalo = GT_READ(GT_CPUERR_ADDRLO_OFS); 161 162 datahi = GT_READ(GT_CPUERR_ADDRHI_OFS); 162 - printk("GT_CPUERR_ADDR = %02x%08x\n", datahi, data); 163 + printk("GT_INTRCAUSE = %08x\n", intrcause); 164 + printk("GT_CPUERR_ADDR = %02x%08x\n", datahi, datalo); 163 165 break; 164 166 case MIPS_REVISION_CORID_BONITO64: 165 167 case MIPS_REVISION_CORID_CORE_20K: 166 168 case MIPS_REVISION_CORID_CORE_EMUL_BON: 167 - data = BONITO_INTISR; 168 - printk("BONITO_INTISR = %08x\n", data); 169 - data = BONITO_INTEN; 170 - printk("BONITO_INTEN = %08x\n", data); 171 - data = BONITO_INTPOL; 172 - printk("BONITO_INTPOL = %08x\n", data); 173 - data = BONITO_INTEDGE; 174 - printk("BONITO_INTEDGE = %08x\n", data); 175 - data = BONITO_INTSTEER; 176 - printk("BONITO_INTSTEER = %08x\n", data); 177 - data = BONITO_PCICMD; 178 - printk("BONITO_PCICMD = %08x\n", data); 169 + pcibadaddr = BONITO_PCIBADADDR; 170 + pcimstat = BONITO_PCIMSTAT; 171 + intisr = BONITO_INTISR; 172 + inten = BONITO_INTEN; 173 + intpol = BONITO_INTPOL; 174 + intedge = BONITO_INTEDGE; 175 + intsteer = BONITO_INTSTEER; 176 + pcicmd = BONITO_PCICMD; 177 + printk("BONITO_INTISR = %08x\n", intisr); 178 + printk("BONITO_INTEN = %08x\n", inten); 179 + printk("BONITO_INTPOL = %08x\n", intpol); 180 + printk("BONITO_INTEDGE = %08x\n", intedge); 181 + printk("BONITO_INTSTEER = %08x\n", intsteer); 182 + printk("BONITO_PCICMD = %08x\n", pcicmd); 183 + printk("BONITO_PCIBADADDR = %08x\n", pcibadaddr); 184 + printk("BONITO_PCIMSTAT = %08x\n", pcimstat); 179 185 break; 180 186 } 181 187 ··· 192 180 die("CoreHi interrupt", regs); 193 181 } 194 182 183 + static struct irqaction i8259irq = { 184 + .handler = no_action, 185 + .name = "XT-PIC cascade" 186 + }; 187 + 188 + static struct irqaction corehi_irqaction = { 189 + .handler = no_action, 190 + .name = "CoreHi" 191 + }; 192 + 193 + msc_irqmap_t __initdata msc_irqmap[] = { 194 + {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, 195 + {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, 196 + }; 197 + int __initdata msc_nr_irqs = sizeof(msc_irqmap)/sizeof(msc_irqmap_t); 198 + 199 + msc_irqmap_t __initdata msc_eicirqmap[] = { 200 + {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, 201 + {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, 202 + {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0}, 203 + {MSC01E_INT_SMI, MSC01_IRQ_LEVEL, 0}, 204 + {MSC01E_INT_COREHI, MSC01_IRQ_LEVEL, 0}, 205 + {MSC01E_INT_CORELO, MSC01_IRQ_LEVEL, 0}, 206 + {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0}, 207 + {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0}, 208 + {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, 209 + {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} 210 + }; 211 + int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t); 212 + 195 213 void __init arch_init_irq(void) 196 214 { 197 215 set_except_vector(0, mipsIRQ); 198 216 init_i8259_irqs(); 217 + 218 + if (!cpu_has_veic) 219 + mips_cpu_irq_init (MIPSCPU_INT_BASE); 220 + 221 + switch(mips_revision_corid) { 222 + case MIPS_REVISION_CORID_CORE_MSC: 223 + case MIPS_REVISION_CORID_CORE_FPGA2: 224 + case MIPS_REVISION_CORID_CORE_EMUL_MSC: 225 + if (cpu_has_veic) 226 + init_msc_irqs (MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs); 227 + else 228 + init_msc_irqs (MSC01C_INT_BASE, msc_irqmap, msc_nr_irqs); 229 + } 230 + 231 + if (cpu_has_veic) { 232 + set_vi_handler (MSC01E_INT_I8259A, malta_hw0_irqdispatch); 233 + set_vi_handler (MSC01E_INT_COREHI, corehi_irqdispatch); 234 + setup_irq (MSC01E_INT_BASE+MSC01E_INT_I8259A, &i8259irq); 235 + setup_irq (MSC01E_INT_BASE+MSC01E_INT_COREHI, &corehi_irqaction); 236 + } 237 + else if (cpu_has_vint) { 238 + set_vi_handler (MIPSCPU_INT_I8259A, malta_hw0_irqdispatch); 239 + set_vi_handler (MIPSCPU_INT_COREHI, corehi_irqdispatch); 240 + 241 + setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq); 242 + setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); 243 + } 244 + else { 245 + set_except_vector(0, mipsIRQ); 246 + setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq); 247 + setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); 248 + } 199 249 }
+1 -2
arch/mips/mm/c-r4k.c
··· 1228 1228 struct cpuinfo_mips *c = &current_cpu_data; 1229 1229 1230 1230 /* Default cache error handler for R4000 and R5000 family */ 1231 - memcpy((void *)(CAC_BASE + 0x100), &except_vec2_generic, 0x80); 1232 - memcpy((void *)(UNCAC_BASE + 0x100), &except_vec2_generic, 0x80); 1231 + set_uncached_handler (0x100, &except_vec2_generic, 0x80); 1233 1232 1234 1233 probe_pcache(); 1235 1234 setup_scache();
+2 -3
arch/mips/mm/c-sb1.c
··· 502 502 extern char handle_vec2_sb1; 503 503 504 504 /* Special cache error handler for SB1 */ 505 - memcpy((void *)(CAC_BASE + 0x100), &except_vec2_sb1, 0x80); 506 - memcpy((void *)(UNCAC_BASE + 0x100), &except_vec2_sb1, 0x80); 507 - memcpy((void *)CKSEG1ADDR(&handle_vec2_sb1), &handle_vec2_sb1, 0x80); 505 + set_uncached_handler (0x100, &except_vec2_sb1, 0x80); 506 + memcpy((void *)KSEG1ADDR(&handle_vec2_sb1), &handle_vec2_sb1, 0x80); 508 507 509 508 probe_cache_sizes(); 510 509
+56 -2
include/asm-mips/mips-boards/maltaint.h
··· 25 25 #ifndef _MIPS_MALTAINT_H 26 26 #define _MIPS_MALTAINT_H 27 27 28 - /* Number of IRQ supported on hw interrupt 0. */ 29 - #define MALTAINT_END 16 28 + /* 29 + * Interrupts 0..15 are used for Malta ISA compatible interrupts 30 + */ 31 + #define MALTA_INT_BASE 0 30 32 33 + /* 34 + * Interrupts 16..23 are used for Malta CPU interrupts (nonEIC mode) 35 + */ 36 + #define MIPSCPU_INT_BASE 16 37 + 38 + /* CPU interrupt offsets */ 39 + #define MIPSCPU_INT_SW0 0 40 + #define MIPSCPU_INT_SW1 1 41 + #define MIPSCPU_INT_MB0 2 42 + #define MIPSCPU_INT_I8259A MIPSCPU_INT_MB0 43 + #define MIPSCPU_INT_MB1 3 44 + #define MIPSCPU_INT_SMI MIPSCPU_INT_MB1 45 + #define MIPSCPU_INT_MB2 4 46 + #define MIPSCPU_INT_MB3 5 47 + #define MIPSCPU_INT_COREHI MIPSCPU_INT_MB3 48 + #define MIPSCPU_INT_MB4 6 49 + #define MIPSCPU_INT_CORELO MIPSCPU_INT_MB4 50 + #define MIPSCPU_INT_CPUCTR 7 51 + 52 + /* 53 + * Interrupts 64..127 are used for Soc-it Classic interrupts 54 + */ 55 + #define MSC01C_INT_BASE 64 56 + 57 + /* SOC-it Classic interrupt offsets */ 58 + #define MSC01C_INT_TMR 0 59 + #define MSC01C_INT_PCI 1 60 + 61 + /* 62 + * Interrupts 64..127 are used for Soc-it EIC interrupts 63 + */ 64 + #define MSC01E_INT_BASE 64 65 + 66 + /* SOC-it EIC interrupt offsets */ 67 + #define MSC01E_INT_SW0 1 68 + #define MSC01E_INT_SW1 2 69 + #define MSC01E_INT_MB0 3 70 + #define MSC01E_INT_I8259A MSC01E_INT_MB0 71 + #define MSC01E_INT_MB1 4 72 + #define MSC01E_INT_SMI MSC01E_INT_MB1 73 + #define MSC01E_INT_MB2 5 74 + #define MSC01E_INT_MB3 6 75 + #define MSC01E_INT_COREHI MSC01E_INT_MB3 76 + #define MSC01E_INT_MB4 7 77 + #define MSC01E_INT_CORELO MSC01E_INT_MB4 78 + #define MSC01E_INT_TMR 8 79 + #define MSC01E_INT_PCI 9 80 + #define MSC01E_INT_PERFCTR 10 81 + #define MSC01E_INT_CPUCTR 11 82 + 83 + #ifndef __ASSEMBLY__ 31 84 extern void maltaint_init(void); 85 + #endif 32 86 33 87 #endif /* !(_MIPS_MALTAINT_H) */
+56
include/asm-mips/rtlx.h
··· 1 + /* 2 + * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. 3 + * 4 + */ 5 + 6 + #ifndef _RTLX_H 7 + #define _RTLX_H_ 8 + 9 + #define LX_NODE_BASE 10 10 + 11 + #define MIPSCPU_INT_BASE 16 12 + #define MIPS_CPU_RTLX_IRQ 0 13 + 14 + #define RTLX_VERSION 1 15 + #define RTLX_xID 0x12345600 16 + #define RTLX_ID (RTLX_xID | RTLX_VERSION) 17 + #define RTLX_CHANNELS 8 18 + 19 + enum rtlx_state { 20 + RTLX_STATE_UNUSED = 0, 21 + RTLX_STATE_INITIALISED, 22 + RTLX_STATE_REMOTE_READY, 23 + RTLX_STATE_OPENED 24 + }; 25 + 26 + #define RTLX_BUFFER_SIZE 1024 27 + /* each channel supports read and write. 28 + linux (vpe0) reads lx_buffer and writes rt_buffer 29 + SP (vpe1) reads rt_buffer and writes lx_buffer 30 + */ 31 + typedef struct rtlx_channel { 32 + enum rtlx_state rt_state; 33 + enum rtlx_state lx_state; 34 + 35 + int buffer_size; 36 + 37 + /* read and write indexes per buffer */ 38 + int rt_write, rt_read; 39 + char *rt_buffer; 40 + 41 + int lx_write, lx_read; 42 + char *lx_buffer; 43 + 44 + void *queues; 45 + 46 + } rtlx_channel_t; 47 + 48 + typedef struct rtlx_info { 49 + unsigned long id; 50 + enum rtlx_state state; 51 + 52 + struct rtlx_channel channel[RTLX_CHANNELS]; 53 + 54 + } rtlx_info_t; 55 + 56 + #endif
+4
include/asm-mips/system.h
··· 431 431 432 432 #define cmpxchg(ptr,old,new) ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr)))) 433 433 434 + extern void set_handler (unsigned long offset, void *addr, unsigned long len); 435 + extern void set_uncached_handler (unsigned long offset, void *addr, unsigned long len); 436 + extern void *set_vi_handler (int n, void *addr); 437 + extern void *set_vi_srs_handler (int n, void *addr, int regset); 434 438 extern void *set_except_vector(int n, void *addr); 435 439 extern void per_cpu_trap_init(void); 436 440
+3
include/asm-mips/traps.h
··· 21 21 extern void (*board_be_init)(void); 22 22 extern int (*board_be_handler)(struct pt_regs *regs, int is_fixup); 23 23 24 + extern void (*board_nmi_handler_setup)(void); 25 + extern void (*board_ejtag_handler_setup)(void); 26 + 24 27 #endif /* _ASM_TRAPS_H */