* git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-2.6-mn10300: (44 commits) MN10300: Save frame pointer in thread_info struct rather than global var MN10300: Change "Matsushita" to "Panasonic". MN10300: Create a defconfig for the ASB2364 board MN10300: Update the ASB2303 defconfig MN10300: ASB2364: Add support for SMSC911X and SMC911X MN10300: ASB2364: Handle the IRQ multiplexer in the FPGA MN10300: Generic time support MN10300: Specify an ELF HWCAP flag for MN10300 Atomic Operations Unit support MN10300: Map userspace atomic op regs as a vmalloc page MN10300: And Panasonic AM34 subarch and implement SMP MN10300: Delete idle_timestamp from irq_cpustat_t MN10300: Make various interrupt priority settings configurable MN10300: Optimise do_csum() MN10300: Implement atomic ops using atomic ops unit MN10300: Make the FPU operate in non-lazy mode under SMP MN10300: SMP TLB flushing MN10300: Use the [ID]PTEL2 registers rather than [ID]PTEL for TLB control MN10300: Make the use of PIDR to mark TLB entries controllable MN10300: Rename __flush_tlb*() to local_flush_tlb*() MN10300: AM34 erratum requires MMUCTR read and write on exception entry ...
Unified · Split
| @@ -53,7 +53,7 @@ targets += arch/$(SRCARCH)/kernel/asm-offsets.s · 52 unmodified lines | ||
| 53 | 53 | # Default sed regexp - multiline due to syntax constraints |
| 54 | 54 | define sed-y |
| 55 | 55 | "/^->/{s:->#\(.*\):/* \1 */:; \ |
| 56 | − s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 (\2) /* \3 */:; \ | |
| 56 | + s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \ | |
| 57 | 57 | s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ |
| 58 | 58 | s:->::; p;}" |
| 59 | 59 | endef |
| @@ -4448,7 +4448,7 @@ L: platform-driver-x86@vger.kernel.org · 4447 unmodified lines | ||
| 4448 | 4448 | S: Maintained |
| 4449 | 4449 | F: drivers/platform/x86/panasonic-laptop.c |
| 4450 | 4450 | |
| 4451 | −PANASONIC MN10300/AM33 PORT | |
| 4451 | +PANASONIC MN10300/AM33/AM34 PORT | |
| 4452 | 4452 | M: David Howells <dhowells@redhat.com> |
| 4453 | 4453 | M: Koichi Yasutake <yasutake.koichi@jp.panasonic.com> |
| 4454 | 4454 | L: linux-am33-list@redhat.com (moderated for non-subscribers) |
| @@ -9,8 +9,19 @@ config MN10300 · 8 unmodified lines | ||
| 9 | 9 | def_bool y |
| 10 | 10 | select HAVE_OPROFILE |
| 11 | 11 | |
| 12 | −config AM33 | |
| 13 | − def_bool y | |
| 12 | +config AM33_2 | |
| 13 | + def_bool n | |
| 14 | + | |
| 15 | +config AM33_3 | |
| 16 | + def_bool n | |
| 17 | + | |
| 18 | +config AM34_2 | |
| 19 | + def_bool n | |
| 20 | + select MN10300_HAS_ATOMIC_OPS_UNIT | |
| 21 | + select MN10300_HAS_CACHE_SNOOP | |
| 22 | + | |
| 23 | +config ERRATUM_NEED_TO_RELOAD_MMUCTR | |
| 24 | + def_bool y if AM33_3 || AM34_2 | |
| 14 | 25 | |
| 15 | 26 | config MMU |
| 16 | 27 | def_bool y |
| @@ -37,7 +48,7 @@ config GENERIC_CALIBRATE_DELAY · 20 unmodified lines | ||
| 37 | 48 | def_bool y |
| 38 | 49 | |
| 39 | 50 | config GENERIC_CMOS_UPDATE |
| 40 | − def_bool y | |
| 51 | + def_bool n | |
| 41 | 52 | |
| 42 | 53 | config GENERIC_FIND_NEXT_BIT |
| 43 | 54 | def_bool y |
| @@ -45,6 +56,27 @@ config GENERIC_FIND_NEXT_BIT · 1 unmodified line | ||
| 45 | 56 | config GENERIC_HWEIGHT |
| 46 | 57 | def_bool y |
| 47 | 58 | |
| 59 | +config GENERIC_TIME | |
| 60 | + def_bool y | |
| 61 | + | |
| 62 | +config GENERIC_CLOCKEVENTS | |
| 63 | + def_bool y | |
| 64 | + | |
| 65 | +config GENERIC_CLOCKEVENTS_BUILD | |
| 66 | + def_bool y | |
| 67 | + depends on GENERIC_CLOCKEVENTS | |
| 68 | + | |
| 69 | +config GENERIC_CLOCKEVENTS_BROADCAST | |
| 70 | + bool | |
| 71 | + | |
| 72 | +config CEVT_MN10300 | |
| 73 | + def_bool y | |
| 74 | + depends on GENERIC_CLOCKEVENTS | |
| 75 | + | |
| 76 | +config CSRC_MN10300 | |
| 77 | + def_bool y | |
| 78 | + depends on GENERIC_TIME | |
| 79 | + | |
| 48 | 80 | config GENERIC_BUG |
| 49 | 81 | def_bool y |
| 50 | 82 | |
| @@ -61,18 +93,14 @@ config GENERIC_HARDIRQS · 10 unmodified lines | ||
| 61 | 93 | config HOTPLUG_CPU |
| 62 | 94 | def_bool n |
| 63 | 95 | |
| 64 | −config HZ | |
| 65 | − int | |
| 66 | − default 1000 | |
| 67 | − | |
| 68 | −mainmenu "Matsushita MN10300/AM33 Kernel Configuration" | |
| 96 | +mainmenu "Panasonic MN10300/AM33 Kernel Configuration" | |
| 69 | 97 | |
| 70 | 98 | source "init/Kconfig" |
| 71 | 99 | |
| 72 | 100 | source "kernel/Kconfig.freezer" |
| 73 | 101 | |
| 74 | 102 | |
| 75 | −menu "Matsushita MN10300 system setup" | |
| 103 | +menu "Panasonic MN10300 system setup" | |
| 76 | 104 | |
| 77 | 105 | choice |
| 78 | 106 | prompt "Unit type" |
| @@ -87,6 +115,10 @@ config MN10300_UNIT_ASB2303 · 8 unmodified lines | ||
| 87 | 115 | config MN10300_UNIT_ASB2305 |
| 88 | 116 | bool "ASB2305" |
| 89 | 117 | |
| 118 | +config MN10300_UNIT_ASB2364 | |
| 119 | + bool "ASB2364" | |
| 120 | + select SMSC911X_ARCH_HOOKS if SMSC911X | |
| 121 | + | |
| 90 | 122 | endchoice |
| 91 | 123 | |
| 92 | 124 | choice |
| @@ -99,57 +131,51 @@ choice · 6 unmodified lines | ||
| 99 | 131 | config MN10300_PROC_MN103E010 |
| 100 | 132 | bool "MN103E010" |
| 101 | 133 | depends on MN10300_UNIT_ASB2303 || MN10300_UNIT_ASB2305 |
| 134 | + select AM33_2 | |
| 135 | + select MN10300_PROC_HAS_TTYSM0 | |
| 136 | + select MN10300_PROC_HAS_TTYSM1 | |
| 137 | + select MN10300_PROC_HAS_TTYSM2 | |
| 138 | + | |
| 139 | +config MN10300_PROC_MN2WS0050 | |
| 140 | + bool "MN2WS0050" | |
| 141 | + depends on MN10300_UNIT_ASB2364 | |
| 142 | + select AM34_2 | |
| 102 | 143 | select MN10300_PROC_HAS_TTYSM0 |
| 103 | 144 | select MN10300_PROC_HAS_TTYSM1 |
| 104 | 145 | select MN10300_PROC_HAS_TTYSM2 |
| 105 | 146 | |
| 106 | 147 | endchoice |
| 107 | 148 | |
| 108 | −choice | |
| 109 | − prompt "Processor core support" | |
| 110 | − default MN10300_CPU_AM33V2 | |
| 149 | +config MN10300_HAS_ATOMIC_OPS_UNIT | |
| 150 | + def_bool n | |
| 111 | 151 | help |
| 112 | − This option specifies the processor core for which the kernel will be | |
| 113 | − compiled. It affects the instruction set used. | |
| 114 | − | |
| 115 | −config MN10300_CPU_AM33V2 | |
| 116 | − bool "AM33v2" | |
| 117 | − | |
| 118 | −endchoice | |
| 152 | + This should be enabled if the processor has an atomic ops unit | |
| 153 | + capable of doing LL/SC equivalent operations. | |
| 119 | 154 | |
| 120 | 155 | config FPU |
| 121 | 156 | bool "FPU present" |
| 122 | 157 | default y |
| 123 | − depends on MN10300_PROC_MN103E010 | |
| 158 | + depends on MN10300_PROC_MN103E010 || MN10300_PROC_MN2WS0050 | |
| 124 | 159 | |
| 125 | −choice | |
| 126 | − prompt "CPU Caching mode" | |
| 127 | − default MN10300_CACHE_WBACK | |
| 160 | +config LAZY_SAVE_FPU | |
| 161 | + bool "Save FPU state lazily" | |
| 162 | + default y | |
| 163 | + depends on FPU && !SMP | |
| 128 | 164 | help |
| 129 | − This option determines the caching mode for the kernel. | |
| 130 | − | |
| 131 | − Write-Back caching mode involves the all reads and writes causing | |
| 132 | − the affected cacheline to be read into the cache first before being | |
| 133 | − operated upon. Memory is not then updated by a write until the cache | |
| 134 | − is filled and a cacheline needs to be displaced from the cache to | |
| 135 | − make room. Only at that point is it written back. | |
| 136 | − | |
| 137 | − Write-Through caching only fetches cachelines from memory on a | |
| 138 | − read. Writes always get written directly to memory. If the affected | |
| 139 | − cacheline is also in cache, it will be updated too. | |
| 140 | − | |
| 141 | − The final option is to turn of caching entirely. | |
| 165 | + Enable this to be lazy in the saving of the FPU state to the owning | |
| 166 | + task's thread struct. This is useful if most tasks on the system | |
| 167 | + don't use the FPU as only those tasks that use it will pass it | |
| 168 | + between them, and the state needn't be saved for a task that isn't | |
| 169 | + using it. | |
| 142 | 170 | |
| 143 | −config MN10300_CACHE_WBACK | |
| 144 | − bool "Write-Back" | |
| 171 | + This can't be so easily used on SMP as the process that owns the FPU | |
| 172 | + state on a CPU may be currently running on another CPU, so for the | |
| 173 | + moment, it is disabled. | |
| 145 | 174 | |
| 146 | −config MN10300_CACHE_WTHRU | |
| 147 | − bool "Write-Through" | |
| 175 | +source "arch/mn10300/mm/Kconfig.cache" | |
| 148 | 176 | |
| 149 | −config MN10300_CACHE_DISABLED | |
| 150 | − bool "Disabled" | |
| 151 | − | |
| 152 | −endchoice | |
| 177 | +config MN10300_TLB_USE_PIDR | |
| 178 | + def_bool y | |
| 153 | 179 | |
| 154 | 180 | menu "Memory layout options" |
| 155 | 181 | |
| @@ -170,24 +196,55 @@ config KERNEL_TEXT_ADDRESS · 14 unmodified lines | ||
| 170 | 196 | |
| 171 | 197 | config KERNEL_ZIMAGE_BASE_ADDRESS |
| 172 | 198 | hex "Base address of compressed vmlinux image" |
| 173 | − default "0x90700000" | |
| 199 | + default "0x50700000" | |
| 174 | 200 | |
| 201 | +config BOOT_STACK_OFFSET | |
| 202 | + hex | |
| 203 | + default "0xF00" if SMP | |
| 204 | + default "0xFF0" if !SMP | |
| 205 | + | |
| 206 | +config BOOT_STACK_SIZE | |
| 207 | + hex | |
| 208 | + depends on SMP | |
| 209 | + default "0x100" | |
| 175 | 210 | endmenu |
| 176 | 211 | |
| 177 | −config PREEMPT | |
| 178 | − bool "Preemptible Kernel" | |
| 179 | − help | |
| 180 | − This option reduces the latency of the kernel when reacting to | |
| 181 | − real-time or interactive events by allowing a low priority process to | |
| 182 | − be preempted even if it is in kernel mode executing a system call. | |
| 183 | − This allows applications to run more reliably even when the system is | |
| 184 | − under load. | |
| 212 | +config SMP | |
| 213 | + bool "Symmetric multi-processing support" | |
| 214 | + default y | |
| 215 | + depends on MN10300_PROC_MN2WS0038 || MN10300_PROC_MN2WS0050 | |
| 216 | + ---help--- | |
| 217 | + This enables support for systems with more than one CPU. If you have | |
| 218 | + a system with only one CPU, like most personal computers, say N. If | |
| 219 | + you have a system with more than one CPU, say Y. | |
| 220 | + | |
| 221 | + If you say N here, the kernel will run on single and multiprocessor | |
| 222 | + machines, but will use only one CPU of a multiprocessor machine. If | |
| 223 | + you say Y here, the kernel will run on many, but not all, | |
| 224 | + singleprocessor machines. On a singleprocessor machine, the kernel | |
| 225 | + will run faster if you say N here. | |
| 185 | 226 | |
| 186 | − Say Y here if you are building a kernel for a desktop, embedded | |
| 187 | − or real-time system. Say N if you are unsure. | |
| 227 | + See also <file:Documentation/i386/IO-APIC.txt>, | |
| 228 | + <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at | |
| 229 | + <http://www.tldp.org/docs.html#howto>. | |
| 230 | + | |
| 231 | + If you don't know what to do here, say N. | |
| 232 | + | |
| 233 | +config NR_CPUS | |
| 234 | + int | |
| 235 | + depends on SMP | |
| 236 | + default "2" | |
| 237 | + | |
| 238 | +config USE_GENERIC_SMP_HELPERS | |
| 239 | + bool | |
| 240 | + depends on SMP | |
| 241 | + default y | |
| 242 | + | |
| 243 | +source "kernel/Kconfig.preempt" | |
| 188 | 244 | |
| 189 | 245 | config MN10300_CURRENT_IN_E2 |
| 190 | 246 | bool "Hold current task address in E2 register" |
| 247 | + depends on !SMP | |
| 191 | 248 | default y |
| 192 | 249 | help |
| 193 | 250 | This option removes the E2/R2 register from the set available to gcc |
| @@ -209,12 +266,15 @@ config MN10300_USING_JTAG · 15 unmodified lines | ||
| 209 | 266 | suppresses the use of certain hardware debugging features, such as |
| 210 | 267 | single-stepping, which are taken over completely by the JTAG unit. |
| 211 | 268 | |
| 269 | +source "kernel/Kconfig.hz" | |
| 270 | +source "kernel/time/Kconfig" | |
| 271 | + | |
| 212 | 272 | config MN10300_RTC |
| 213 | 273 | bool "Using MN10300 RTC" |
| 214 | − depends on MN10300_PROC_MN103E010 | |
| 274 | + depends on MN10300_PROC_MN103E010 || MN10300_PROC_MN2WS0050 | |
| 275 | + select GENERIC_CMOS_UPDATE | |
| 215 | 276 | default n |
| 216 | 277 | help |
| 217 | − | |
| 218 | 278 | This option enables support for the RTC, thus enabling time to be |
| 219 | 279 | tracked, even when system is powered down. This is available on-chip |
| 220 | 280 | on the MN103E010. |
| @@ -306,14 +366,23 @@ config MN10300_TTYSM1 · 85 unmodified lines | ||
| 306 | 366 | |
| 307 | 367 | choice |
| 308 | 368 | prompt "Select the timer to supply the clock for SIF1" |
| 309 | − default MN10300_TTYSM0_TIMER9 | |
| 369 | + default MN10300_TTYSM1_TIMER12 \ | |
| 370 | + if !(AM33_2 || AM33_3) | |
| 371 | + default MN10300_TTYSM1_TIMER9 \ | |
| 372 | + if AM33_2 || AM33_3 | |
| 310 | 373 | depends on MN10300_TTYSM1 |
| 311 | 374 | |
| 375 | +config MN10300_TTYSM1_TIMER12 | |
| 376 | + bool "Use timer 12 (16-bit)" | |
| 377 | + depends on !(AM33_2 || AM33_3) | |
| 378 | + | |
| 312 | 379 | config MN10300_TTYSM1_TIMER9 |
| 313 | 380 | bool "Use timer 9 (16-bit)" |
| 381 | + depends on AM33_2 || AM33_3 | |
| 314 | 382 | |
| 315 | 383 | config MN10300_TTYSM1_TIMER3 |
| 316 | 384 | bool "Use timer 3 (8-bit)" |
| 385 | + depends on AM33_2 || AM33_3 | |
| 317 | 386 | |
| 318 | 387 | endchoice |
| 319 | 388 | |
| @@ -328,17 +397,107 @@ config MN10300_TTYSM2 · 8 unmodified lines | ||
| 328 | 397 | |
| 329 | 398 | choice |
| 330 | 399 | prompt "Select the timer to supply the clock for SIF2" |
| 331 | − default MN10300_TTYSM0_TIMER10 | |
| 400 | + default MN10300_TTYSM2_TIMER3 \ | |
| 401 | + if !(AM33_2 || AM33_3) | |
| 402 | + default MN10300_TTYSM2_TIMER10 \ | |
| 403 | + if AM33_2 || AM33_3 | |
| 332 | 404 | depends on MN10300_TTYSM2 |
| 333 | 405 | |
| 406 | +config MN10300_TTYSM2_TIMER9 | |
| 407 | + bool "Use timer 9 (16-bit)" | |
| 408 | + depends on !(AM33_2 || AM33_3) | |
| 409 | + | |
| 410 | +config MN10300_TTYSM2_TIMER1 | |
| 411 | + bool "Use timer 1 (8-bit)" | |
| 412 | + depends on !(AM33_2 || AM33_3) | |
| 413 | + | |
| 414 | +config MN10300_TTYSM2_TIMER3 | |
| 415 | + bool "Use timer 3 (8-bit)" | |
| 416 | + depends on !(AM33_2 || AM33_3) | |
| 417 | + | |
| 334 | 418 | config MN10300_TTYSM2_TIMER10 |
| 335 | 419 | bool "Use timer 10 (16-bit)" |
| 420 | + depends on AM33_2 || AM33_3 | |
| 336 | 421 | |
| 337 | 422 | endchoice |
| 338 | 423 | |
| 339 | 424 | config MN10300_TTYSM2_CTS |
| 340 | 425 | bool "Enable the use of the CTS line /dev/ttySM2" |
| 341 | − depends on MN10300_TTYSM2 | |
| 426 | + depends on MN10300_TTYSM2 && AM33_2 | |
| 427 | + | |
| 428 | +endmenu | |
| 429 | + | |
| 430 | +menu "Interrupt request priority options" | |
| 431 | + | |
| 432 | +comment "[!] NOTE: A lower number/level indicates a higher priority (0 is highest, 6 is lowest)" | |
| 433 | + | |
| 434 | +comment "____Non-maskable interrupt levels____" | |
| 435 | +comment "The following must be set to a higher priority than local_irq_disable() and on-chip serial" | |
| 436 | + | |
| 437 | +config GDBSTUB_IRQ_LEVEL | |
| 438 | + int "GDBSTUB interrupt priority" | |
| 439 | + depends on GDBSTUB | |
| 440 | + range 0 1 if LINUX_CLI_LEVEL = 2 | |
| 441 | + range 0 2 if LINUX_CLI_LEVEL = 3 | |
| 442 | + range 0 3 if LINUX_CLI_LEVEL = 4 | |
| 443 | + range 0 4 if LINUX_CLI_LEVEL = 5 | |
| 444 | + range 0 5 if LINUX_CLI_LEVEL = 6 | |
| 445 | + default 0 | |
| 446 | + | |
| 447 | +comment "The following must be set to a higher priority than local_irq_disable()" | |
| 448 | + | |
| 449 | +config MN10300_SERIAL_IRQ_LEVEL | |
| 450 | + int "MN10300 on-chip serial interrupt priority" | |
| 451 | + depends on MN10300_TTYSM | |
| 452 | + range 1 1 if LINUX_CLI_LEVEL = 2 | |
| 453 | + range 1 2 if LINUX_CLI_LEVEL = 3 | |
| 454 | + range 1 3 if LINUX_CLI_LEVEL = 4 | |
| 455 | + range 1 4 if LINUX_CLI_LEVEL = 5 | |
| 456 | + range 1 5 if LINUX_CLI_LEVEL = 6 | |
| 457 | + default 1 | |
| 458 | + | |
| 459 | +comment "-" | |
| 460 | +comment "____Maskable interrupt levels____" | |
| 461 | + | |
| 462 | +config LINUX_CLI_LEVEL | |
| 463 | + int "The highest interrupt priority excluded by local_irq_disable() (2-6)" | |
| 464 | + range 2 6 | |
| 465 | + default 2 | |
| 466 | + help | |
| 467 | + local_irq_disable() doesn't actually disable maskable interrupts - | |
| 468 | + what it does is restrict the levels of interrupt which are permitted | |
| 469 | + (a lower level indicates a higher priority) by lowering the value in | |
| 470 | + EPSW.IM from 7. Any interrupt is permitted for which the level is | |
| 471 | + lower than EPSW.IM. | |
| 472 | + | |
| 473 | + Certain interrupts, such as GDBSTUB and virtual MN10300 on-chip | |
| 474 | + serial DMA interrupts are allowed to interrupt normal disabled | |
| 475 | + sections. | |
| 476 | + | |
| 477 | +comment "The following must be set to a equal to or lower priority than LINUX_CLI_LEVEL" | |
| 478 | + | |
| 479 | +config TIMER_IRQ_LEVEL | |
| 480 | + int "Kernel timer interrupt priority" | |
| 481 | + range LINUX_CLI_LEVEL 6 | |
| 482 | + default 4 | |
| 483 | + | |
| 484 | +config PCI_IRQ_LEVEL | |
| 485 | + int "PCI interrupt priority" | |
| 486 | + depends on PCI | |
| 487 | + range LINUX_CLI_LEVEL 6 | |
| 488 | + default 5 | |
| 489 | + | |
| 490 | +config ETHERNET_IRQ_LEVEL | |
| 491 | + int "Ethernet interrupt priority" | |
| 492 | + depends on SMC91X || SMC911X || SMSC911X | |
| 493 | + range LINUX_CLI_LEVEL 6 | |
| 494 | + default 6 | |
| 495 | + | |
| 496 | +config EXT_SERIAL_IRQ_LEVEL | |
| 497 | + int "External serial port interrupt priority" | |
| 498 | + depends on SERIAL_8250 | |
| 499 | + range LINUX_CLI_LEVEL 6 | |
| 500 | + default 6 | |
| 342 | 501 | |
| 343 | 502 | endmenu |
| 344 | 503 | |
| @@ -36,6 +36,9 @@ endif · 35 unmodified lines | ||
| 36 | 36 | ifeq ($(CONFIG_MN10300_PROC_MN103E010),y) |
| 37 | 37 | PROCESSOR := mn103e010 |
| 38 | 38 | endif |
| 39 | +ifeq ($(CONFIG_MN10300_PROC_MN2WS0050),y) | |
| 40 | +PROCESSOR := mn2ws0050 | |
| 41 | +endif | |
| 39 | 42 | |
| 40 | 43 | ifeq ($(CONFIG_MN10300_UNIT_ASB2303),y) |
| 41 | 44 | UNIT := asb2303 |
| @@ -43,6 +46,9 @@ endif · 1 unmodified line | ||
| 43 | 46 | ifeq ($(CONFIG_MN10300_UNIT_ASB2305),y) |
| 44 | 47 | UNIT := asb2305 |
| 45 | 48 | endif |
| 49 | +ifeq ($(CONFIG_MN10300_UNIT_ASB2364),y) | |
| 50 | +UNIT := asb2364 | |
| 51 | +endif | |
| 46 | 52 | |
| 47 | 53 | |
| 48 | 54 | head-y := arch/mn10300/kernel/head.o arch/mn10300/kernel/init_task.o |
| @@ -14,10 +14,29 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | #include <linux/linkage.h> |
| 16 | 16 | #include <asm/cpu-regs.h> |
| 17 | +#include <asm/cache.h> | |
| 18 | +#ifdef CONFIG_SMP | |
| 19 | +#include <proc/smp-regs.h> | |
| 20 | +#endif | |
| 17 | 21 | |
| 18 | 22 | .globl startup_32 |
| 19 | 23 | startup_32: |
| 20 | − # first save off parameters from bootloader | |
| 24 | +#ifdef CONFIG_SMP | |
| 25 | + # | |
| 26 | + # Secondary CPUs jump directly to the kernel entry point | |
| 27 | + # | |
| 28 | + # Must save primary CPU's D0-D2 registers as they hold boot parameters | |
| 29 | + # | |
| 30 | + mov (CPUID), d3 | |
| 31 | + and CPUID_MASK,d3 | |
| 32 | + beq startup_primary | |
| 33 | + mov CONFIG_KERNEL_TEXT_ADDRESS,a0 | |
| 34 | + jmp (a0) | |
| 35 | + | |
| 36 | +startup_primary: | |
| 37 | +#endif /* CONFIG_SMP */ | |
| 38 | + | |
| 39 | + # first save parameters from bootloader | |
| 21 | 40 | mov param_save_area,a0 |
| 22 | 41 | mov d0,(a0) |
| 23 | 42 | mov d1,(4,a0) |
| @@ -37,8 +56,15 @@ startup_32: · 13 unmodified lines | ||
| 37 | 56 | mov (a0),d0 |
| 38 | 57 | btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy |
| 39 | 58 | lne |
| 40 | − mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD,d0 # writethru dcache | |
| 59 | + | |
| 60 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 61 | +#ifdef CONFIG_MN10300_CACHE_WBACK | |
| 62 | + mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0 | |
| 63 | +#else | |
| 64 | + mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0 | |
| 65 | +#endif /* WBACK */ | |
| 41 | 66 | movhu d0,(a0) # enable |
| 67 | +#endif /* !ENABLED */ | |
| 42 | 68 | |
| 43 | 69 | # clear the BSS area |
| 44 | 70 | mov __bss_start,a0 |
| @@ -54,6 +80,9 @@ bssclear_end: · 9 unmodified lines | ||
| 54 | 80 | |
| 55 | 81 | # decompress the kernel |
| 56 | 82 | call decompress_kernel[],0 |
| 83 | +#ifdef CONFIG_MN10300_CACHE_WBACK | |
| 84 | + call mn10300_dcache_flush_inv[],0 | |
| 85 | +#endif | |
| 57 | 86 | |
| 58 | 87 | # disable caches again |
| 59 | 88 | mov CHCTR,a0 |
| @@ -69,10 +98,46 @@ bssclear_end: · 9 unmodified lines | ||
| 69 | 98 | mov (4,a0),d1 |
| 70 | 99 | mov (8,a0),d2 |
| 71 | 100 | |
| 101 | + # jump to the kernel proper entry point | |
| 72 | 102 | mov a3,sp |
| 73 | 103 | mov CONFIG_KERNEL_TEXT_ADDRESS,a0 |
| 74 | 104 | jmp (a0) |
| 75 | 105 | |
| 106 | + | |
| 107 | +############################################################################### | |
| 108 | +# | |
| 109 | +# Cache flush routines | |
| 110 | +# | |
| 111 | +############################################################################### | |
| 112 | +#ifdef CONFIG_MN10300_CACHE_WBACK | |
| 113 | +mn10300_dcache_flush_inv: | |
| 114 | + movhu (CHCTR),d0 | |
| 115 | + btst CHCTR_DCEN,d0 | |
| 116 | + beq mn10300_dcache_flush_inv_end | |
| 117 | + | |
| 118 | + mov L1_CACHE_NENTRIES,d1 | |
| 119 | + clr a1 | |
| 120 | + | |
| 121 | +mn10300_dcache_flush_inv_loop: | |
| 122 | + mov (DCACHE_PURGE_WAY0(0),a1),d0 # unconditional purge | |
| 123 | + mov (DCACHE_PURGE_WAY1(0),a1),d0 # unconditional purge | |
| 124 | + mov (DCACHE_PURGE_WAY2(0),a1),d0 # unconditional purge | |
| 125 | + mov (DCACHE_PURGE_WAY3(0),a1),d0 # unconditional purge | |
| 126 | + | |
| 127 | + add L1_CACHE_BYTES,a1 | |
| 128 | + add -1,d1 | |
| 129 | + bne mn10300_dcache_flush_inv_loop | |
| 130 | + | |
| 131 | +mn10300_dcache_flush_inv_end: | |
| 132 | + ret [],0 | |
| 133 | +#endif /* CONFIG_MN10300_CACHE_WBACK */ | |
| 134 | + | |
| 135 | + | |
| 136 | +############################################################################### | |
| 137 | +# | |
| 138 | +# Data areas | |
| 139 | +# | |
| 140 | +############################################################################### | |
| 76 | 141 | .data |
| 77 | 142 | .align 4 |
| 78 | 143 | param_save_area: |
| @@ -12,6 +12,8 @@ CONFIG_SLAB=y · 11 unmodified lines | ||
| 12 | 12 | CONFIG_PROFILING=y |
| 13 | 13 | # CONFIG_BLOCK is not set |
| 14 | 14 | CONFIG_PREEMPT=y |
| 15 | +CONFIG_NO_HZ=y | |
| 16 | +CONFIG_HIGH_RES_TIMERS=y | |
| 15 | 17 | CONFIG_MN10300_RTC=y |
| 16 | 18 | CONFIG_MN10300_TTYSM_CONSOLE=y |
| 17 | 19 | CONFIG_MN10300_TTYSM0=y |
| @@ -0,0 +1,98 @@ | ||
| 1 | +CONFIG_EXPERIMENTAL=y | |
| 2 | +CONFIG_SYSVIPC=y | |
| 3 | +CONFIG_POSIX_MQUEUE=y | |
| 4 | +CONFIG_BSD_PROCESS_ACCT=y | |
| 5 | +CONFIG_TASKSTATS=y | |
| 6 | +CONFIG_TASK_DELAY_ACCT=y | |
| 7 | +CONFIG_TASK_XACCT=y | |
| 8 | +CONFIG_TASK_IO_ACCOUNTING=y | |
| 9 | +CONFIG_LOG_BUF_SHIFT=14 | |
| 10 | +CONFIG_CGROUPS=y | |
| 11 | +CONFIG_CGROUP_NS=y | |
| 12 | +CONFIG_CGROUP_FREEZER=y | |
| 13 | +CONFIG_CGROUP_DEVICE=y | |
| 14 | +CONFIG_CGROUP_CPUACCT=y | |
| 15 | +CONFIG_RESOURCE_COUNTERS=y | |
| 16 | +CONFIG_RELAY=y | |
| 17 | +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | |
| 18 | +CONFIG_EMBEDDED=y | |
| 19 | +# CONFIG_KALLSYMS is not set | |
| 20 | +# CONFIG_VM_EVENT_COUNTERS is not set | |
| 21 | +CONFIG_SLAB=y | |
| 22 | +CONFIG_PROFILING=y | |
| 23 | +CONFIG_MODULES=y | |
| 24 | +CONFIG_MODULE_UNLOAD=y | |
| 25 | +# CONFIG_BLOCK is not set | |
| 26 | +CONFIG_MN10300_UNIT_ASB2364=y | |
| 27 | +CONFIG_PREEMPT=y | |
| 28 | +# CONFIG_MN10300_USING_JTAG is not set | |
| 29 | +CONFIG_NO_HZ=y | |
| 30 | +CONFIG_HIGH_RES_TIMERS=y | |
| 31 | +CONFIG_MN10300_TTYSM_CONSOLE=y | |
| 32 | +CONFIG_MN10300_TTYSM0=y | |
| 33 | +CONFIG_MN10300_TTYSM0_TIMER2=y | |
| 34 | +CONFIG_MN10300_TTYSM1=y | |
| 35 | +CONFIG_NET=y | |
| 36 | +CONFIG_PACKET=y | |
| 37 | +CONFIG_UNIX=y | |
| 38 | +CONFIG_INET=y | |
| 39 | +CONFIG_IP_MULTICAST=y | |
| 40 | +CONFIG_IP_PNP=y | |
| 41 | +CONFIG_IP_PNP_BOOTP=y | |
| 42 | +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set | |
| 43 | +# CONFIG_INET_XFRM_MODE_TUNNEL is not set | |
| 44 | +# CONFIG_INET_XFRM_MODE_BEET is not set | |
| 45 | +# CONFIG_INET_LRO is not set | |
| 46 | +# CONFIG_INET_DIAG is not set | |
| 47 | +CONFIG_IPV6=y | |
| 48 | +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set | |
| 49 | +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set | |
| 50 | +# CONFIG_INET6_XFRM_MODE_BEET is not set | |
| 51 | +# CONFIG_FIRMWARE_IN_KERNEL is not set | |
| 52 | +CONFIG_CONNECTOR=y | |
| 53 | +CONFIG_MTD=y | |
| 54 | +CONFIG_MTD_DEBUG=y | |
| 55 | +CONFIG_MTD_PARTITIONS=y | |
| 56 | +CONFIG_MTD_REDBOOT_PARTS=y | |
| 57 | +CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y | |
| 58 | +CONFIG_MTD_CHAR=y | |
| 59 | +CONFIG_MTD_CFI=y | |
| 60 | +CONFIG_MTD_JEDECPROBE=y | |
| 61 | +CONFIG_MTD_CFI_ADV_OPTIONS=y | |
| 62 | +CONFIG_MTD_CFI_GEOMETRY=y | |
| 63 | +CONFIG_MTD_CFI_I4=y | |
| 64 | +CONFIG_MTD_CFI_AMDSTD=y | |
| 65 | +CONFIG_MTD_PHYSMAP=y | |
| 66 | +CONFIG_NETDEVICES=y | |
| 67 | +CONFIG_NET_ETHERNET=y | |
| 68 | +CONFIG_SMSC911X=y | |
| 69 | +# CONFIG_NETDEV_1000 is not set | |
| 70 | +# CONFIG_NETDEV_10000 is not set | |
| 71 | +# CONFIG_INPUT_MOUSEDEV is not set | |
| 72 | +# CONFIG_INPUT_KEYBOARD is not set | |
| 73 | +# CONFIG_INPUT_MOUSE is not set | |
| 74 | +# CONFIG_SERIO is not set | |
| 75 | +# CONFIG_VT is not set | |
| 76 | +CONFIG_SERIAL_8250=y | |
| 77 | +CONFIG_SERIAL_8250_CONSOLE=y | |
| 78 | +CONFIG_SERIAL_8250_EXTENDED=y | |
| 79 | +CONFIG_SERIAL_8250_SHARE_IRQ=y | |
| 80 | +# CONFIG_HW_RANDOM is not set | |
| 81 | +# CONFIG_HWMON is not set | |
| 82 | +# CONFIG_HID_SUPPORT is not set | |
| 83 | +# CONFIG_USB_SUPPORT is not set | |
| 84 | +CONFIG_PROC_KCORE=y | |
| 85 | +# CONFIG_PROC_PAGE_MONITOR is not set | |
| 86 | +CONFIG_TMPFS=y | |
| 87 | +CONFIG_TMPFS_POSIX_ACL=y | |
| 88 | +CONFIG_JFFS2_FS=y | |
| 89 | +CONFIG_NFS_FS=y | |
| 90 | +CONFIG_NFS_V3=y | |
| 91 | +CONFIG_ROOT_NFS=y | |
| 92 | +CONFIG_MAGIC_SYSRQ=y | |
| 93 | +CONFIG_STRIP_ASM_SYMS=y | |
| 94 | +CONFIG_DEBUG_KERNEL=y | |
| 95 | +CONFIG_DETECT_HUNG_TASK=y | |
| 96 | +# CONFIG_DEBUG_BUGVERBOSE is not set | |
| 97 | +CONFIG_DEBUG_INFO=y | |
| 98 | +# CONFIG_RCU_CPU_STALL_DETECTOR is not set | |
| @@ -1 +1,351 @@ | ||
| 1 | +/* MN10300 Atomic counter operations | |
| 2 | + * | |
| 3 | + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#ifndef _ASM_ATOMIC_H | |
| 12 | +#define _ASM_ATOMIC_H | |
| 13 | + | |
| 14 | +#include <asm/irqflags.h> | |
| 15 | + | |
| 16 | +#ifndef __ASSEMBLY__ | |
| 17 | + | |
| 18 | +#ifdef CONFIG_SMP | |
| 19 | +#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT | |
| 20 | +static inline | |
| 21 | +unsigned long __xchg(volatile unsigned long *m, unsigned long val) | |
| 22 | +{ | |
| 23 | + unsigned long status; | |
| 24 | + unsigned long oldval; | |
| 25 | + | |
| 26 | + asm volatile( | |
| 27 | + "1: mov %4,(_AAR,%3) \n" | |
| 28 | + " mov (_ADR,%3),%1 \n" | |
| 29 | + " mov %5,(_ADR,%3) \n" | |
| 30 | + " mov (_ADR,%3),%0 \n" /* flush */ | |
| 31 | + " mov (_ASR,%3),%0 \n" | |
| 32 | + " or %0,%0 \n" | |
| 33 | + " bne 1b \n" | |
| 34 | + : "=&r"(status), "=&r"(oldval), "=m"(*m) | |
| 35 | + : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val) | |
| 36 | + : "memory", "cc"); | |
| 37 | + | |
| 38 | + return oldval; | |
| 39 | +} | |
| 40 | + | |
| 41 | +static inline unsigned long __cmpxchg(volatile unsigned long *m, | |
| 42 | + unsigned long old, unsigned long new) | |
| 43 | +{ | |
| 44 | + unsigned long status; | |
| 45 | + unsigned long oldval; | |
| 46 | + | |
| 47 | + asm volatile( | |
| 48 | + "1: mov %4,(_AAR,%3) \n" | |
| 49 | + " mov (_ADR,%3),%1 \n" | |
| 50 | + " cmp %5,%1 \n" | |
| 51 | + " bne 2f \n" | |
| 52 | + " mov %6,(_ADR,%3) \n" | |
| 53 | + "2: mov (_ADR,%3),%0 \n" /* flush */ | |
| 54 | + " mov (_ASR,%3),%0 \n" | |
| 55 | + " or %0,%0 \n" | |
| 56 | + " bne 1b \n" | |
| 57 | + : "=&r"(status), "=&r"(oldval), "=m"(*m) | |
| 58 | + : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), | |
| 59 | + "r"(old), "r"(new) | |
| 60 | + : "memory", "cc"); | |
| 61 | + | |
| 62 | + return oldval; | |
| 63 | +} | |
| 64 | +#else /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */ | |
| 65 | +#error "No SMP atomic operation support!" | |
| 66 | +#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */ | |
| 67 | + | |
| 68 | +#else /* CONFIG_SMP */ | |
| 69 | + | |
| 70 | +/* | |
| 71 | + * Emulate xchg for non-SMP MN10300 | |
| 72 | + */ | |
| 73 | +struct __xchg_dummy { unsigned long a[100]; }; | |
| 74 | +#define __xg(x) ((struct __xchg_dummy *)(x)) | |
| 75 | + | |
| 76 | +static inline | |
| 77 | +unsigned long __xchg(volatile unsigned long *m, unsigned long val) | |
| 78 | +{ | |
| 79 | + unsigned long oldval; | |
| 80 | + unsigned long flags; | |
| 81 | + | |
| 82 | + flags = arch_local_cli_save(); | |
| 83 | + oldval = *m; | |
| 84 | + *m = val; | |
| 85 | + arch_local_irq_restore(flags); | |
| 86 | + return oldval; | |
| 87 | +} | |
| 88 | + | |
| 89 | +/* | |
| 90 | + * Emulate cmpxchg for non-SMP MN10300 | |
| 91 | + */ | |
| 92 | +static inline unsigned long __cmpxchg(volatile unsigned long *m, | |
| 93 | + unsigned long old, unsigned long new) | |
| 94 | +{ | |
| 95 | + unsigned long oldval; | |
| 96 | + unsigned long flags; | |
| 97 | + | |
| 98 | + flags = arch_local_cli_save(); | |
| 99 | + oldval = *m; | |
| 100 | + if (oldval == old) | |
| 101 | + *m = new; | |
| 102 | + arch_local_irq_restore(flags); | |
| 103 | + return oldval; | |
| 104 | +} | |
| 105 | + | |
| 106 | +#endif /* CONFIG_SMP */ | |
| 107 | + | |
| 108 | +#define xchg(ptr, v) \ | |
| 109 | + ((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr), \ | |
| 110 | + (unsigned long)(v))) | |
| 111 | + | |
| 112 | +#define cmpxchg(ptr, o, n) \ | |
| 113 | + ((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \ | |
| 114 | + (unsigned long)(o), \ | |
| 115 | + (unsigned long)(n))) | |
| 116 | + | |
| 117 | +#define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) | |
| 118 | +#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) | |
| 119 | + | |
| 120 | +#endif /* !__ASSEMBLY__ */ | |
| 121 | + | |
| 122 | +#ifndef CONFIG_SMP | |
| 1 | 123 | #include <asm-generic/atomic.h> |
| 124 | +#else | |
| 125 | + | |
| 126 | +/* | |
| 127 | + * Atomic operations that C can't guarantee us. Useful for | |
| 128 | + * resource counting etc.. | |
| 129 | + */ | |
| 130 | + | |
| 131 | +#define ATOMIC_INIT(i) { (i) } | |
| 132 | + | |
| 133 | +#ifdef __KERNEL__ | |
| 134 | + | |
| 135 | +/** | |
| 136 | + * atomic_read - read atomic variable | |
| 137 | + * @v: pointer of type atomic_t | |
| 138 | + * | |
| 139 | + * Atomically reads the value of @v. Note that the guaranteed | |
| 140 | + * useful range of an atomic_t is only 24 bits. | |
| 141 | + */ | |
| 142 | +#define atomic_read(v) ((v)->counter) | |
| 143 | + | |
| 144 | +/** | |
| 145 | + * atomic_set - set atomic variable | |
| 146 | + * @v: pointer of type atomic_t | |
| 147 | + * @i: required value | |
| 148 | + * | |
| 149 | + * Atomically sets the value of @v to @i. Note that the guaranteed | |
| 150 | + * useful range of an atomic_t is only 24 bits. | |
| 151 | + */ | |
| 152 | +#define atomic_set(v, i) (((v)->counter) = (i)) | |
| 153 | + | |
| 154 | +/** | |
| 155 | + * atomic_add_return - add integer to atomic variable | |
| 156 | + * @i: integer value to add | |
| 157 | + * @v: pointer of type atomic_t | |
| 158 | + * | |
| 159 | + * Atomically adds @i to @v and returns the result | |
| 160 | + * Note that the guaranteed useful range of an atomic_t is only 24 bits. | |
| 161 | + */ | |
| 162 | +static inline int atomic_add_return(int i, atomic_t *v) | |
| 163 | +{ | |
| 164 | + int retval; | |
| 165 | +#ifdef CONFIG_SMP | |
| 166 | + int status; | |
| 167 | + | |
| 168 | + asm volatile( | |
| 169 | + "1: mov %4,(_AAR,%3) \n" | |
| 170 | + " mov (_ADR,%3),%1 \n" | |
| 171 | + " add %5,%1 \n" | |
| 172 | + " mov %1,(_ADR,%3) \n" | |
| 173 | + " mov (_ADR,%3),%0 \n" /* flush */ | |
| 174 | + " mov (_ASR,%3),%0 \n" | |
| 175 | + " or %0,%0 \n" | |
| 176 | + " bne 1b \n" | |
| 177 | + : "=&r"(status), "=&r"(retval), "=m"(v->counter) | |
| 178 | + : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) | |
| 179 | + : "memory", "cc"); | |
| 180 | + | |
| 181 | +#else | |
| 182 | + unsigned long flags; | |
| 183 | + | |
| 184 | + flags = arch_local_cli_save(); | |
| 185 | + retval = v->counter; | |
| 186 | + retval += i; | |
| 187 | + v->counter = retval; | |
| 188 | + arch_local_irq_restore(flags); | |
| 189 | +#endif | |
| 190 | + return retval; | |
| 191 | +} | |
| 192 | + | |
| 193 | +/** | |
| 194 | + * atomic_sub_return - subtract integer from atomic variable | |
| 195 | + * @i: integer value to subtract | |
| 196 | + * @v: pointer of type atomic_t | |
| 197 | + * | |
| 198 | + * Atomically subtracts @i from @v and returns the result | |
| 199 | + * Note that the guaranteed useful range of an atomic_t is only 24 bits. | |
| 200 | + */ | |
| 201 | +static inline int atomic_sub_return(int i, atomic_t *v) | |
| 202 | +{ | |
| 203 | + int retval; | |
| 204 | +#ifdef CONFIG_SMP | |
| 205 | + int status; | |
| 206 | + | |
| 207 | + asm volatile( | |
| 208 | + "1: mov %4,(_AAR,%3) \n" | |
| 209 | + " mov (_ADR,%3),%1 \n" | |
| 210 | + " sub %5,%1 \n" | |
| 211 | + " mov %1,(_ADR,%3) \n" | |
| 212 | + " mov (_ADR,%3),%0 \n" /* flush */ | |
| 213 | + " mov (_ASR,%3),%0 \n" | |
| 214 | + " or %0,%0 \n" | |
| 215 | + " bne 1b \n" | |
| 216 | + : "=&r"(status), "=&r"(retval), "=m"(v->counter) | |
| 217 | + : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) | |
| 218 | + : "memory", "cc"); | |
| 219 | + | |
| 220 | +#else | |
| 221 | + unsigned long flags; | |
| 222 | + flags = arch_local_cli_save(); | |
| 223 | + retval = v->counter; | |
| 224 | + retval -= i; | |
| 225 | + v->counter = retval; | |
| 226 | + arch_local_irq_restore(flags); | |
| 227 | +#endif | |
| 228 | + return retval; | |
| 229 | +} | |
| 230 | + | |
| 231 | +static inline int atomic_add_negative(int i, atomic_t *v) | |
| 232 | +{ | |
| 233 | + return atomic_add_return(i, v) < 0; | |
| 234 | +} | |
| 235 | + | |
| 236 | +static inline void atomic_add(int i, atomic_t *v) | |
| 237 | +{ | |
| 238 | + atomic_add_return(i, v); | |
| 239 | +} | |
| 240 | + | |
| 241 | +static inline void atomic_sub(int i, atomic_t *v) | |
| 242 | +{ | |
| 243 | + atomic_sub_return(i, v); | |
| 244 | +} | |
| 245 | + | |
| 246 | +static inline void atomic_inc(atomic_t *v) | |
| 247 | +{ | |
| 248 | + atomic_add_return(1, v); | |
| 249 | +} | |
| 250 | + | |
| 251 | +static inline void atomic_dec(atomic_t *v) | |
| 252 | +{ | |
| 253 | + atomic_sub_return(1, v); | |
| 254 | +} | |
| 255 | + | |
| 256 | +#define atomic_dec_return(v) atomic_sub_return(1, (v)) | |
| 257 | +#define atomic_inc_return(v) atomic_add_return(1, (v)) | |
| 258 | + | |
| 259 | +#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) | |
| 260 | +#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) | |
| 261 | +#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0) | |
| 262 | + | |
| 263 | +#define atomic_add_unless(v, a, u) \ | |
| 264 | +({ \ | |
| 265 | + int c, old; \ | |
| 266 | + c = atomic_read(v); \ | |
| 267 | + while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ | |
| 268 | + c = old; \ | |
| 269 | + c != (u); \ | |
| 270 | +}) | |
| 271 | + | |
| 272 | +#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) | |
| 273 | + | |
| 274 | +/** | |
| 275 | + * atomic_clear_mask - Atomically clear bits in memory | |
| 276 | + * @mask: Mask of the bits to be cleared | |
| 277 | + * @v: pointer to word in memory | |
| 278 | + * | |
| 279 | + * Atomically clears the bits set in mask from the memory word specified. | |
| 280 | + */ | |
| 281 | +static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) | |
| 282 | +{ | |
| 283 | +#ifdef CONFIG_SMP | |
| 284 | + int status; | |
| 285 | + | |
| 286 | + asm volatile( | |
| 287 | + "1: mov %3,(_AAR,%2) \n" | |
| 288 | + " mov (_ADR,%2),%0 \n" | |
| 289 | + " and %4,%0 \n" | |
| 290 | + " mov %0,(_ADR,%2) \n" | |
| 291 | + " mov (_ADR,%2),%0 \n" /* flush */ | |
| 292 | + " mov (_ASR,%2),%0 \n" | |
| 293 | + " or %0,%0 \n" | |
| 294 | + " bne 1b \n" | |
| 295 | + : "=&r"(status), "=m"(*addr) | |
| 296 | + : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(~mask) | |
| 297 | + : "memory", "cc"); | |
| 298 | +#else | |
| 299 | + unsigned long flags; | |
| 300 | + | |
| 301 | + mask = ~mask; | |
| 302 | + flags = arch_local_cli_save(); | |
| 303 | + *addr &= mask; | |
| 304 | + arch_local_irq_restore(flags); | |
| 305 | +#endif | |
| 306 | +} | |
| 307 | + | |
| 308 | +/** | |
| 309 | + * atomic_set_mask - Atomically set bits in memory | |
| 310 | + * @mask: Mask of the bits to be set | |
| 311 | + * @v: pointer to word in memory | |
| 312 | + * | |
| 313 | + * Atomically sets the bits set in mask from the memory word specified. | |
| 314 | + */ | |
| 315 | +static inline void atomic_set_mask(unsigned long mask, unsigned long *addr) | |
| 316 | +{ | |
| 317 | +#ifdef CONFIG_SMP | |
| 318 | + int status; | |
| 319 | + | |
| 320 | + asm volatile( | |
| 321 | + "1: mov %3,(_AAR,%2) \n" | |
| 322 | + " mov (_ADR,%2),%0 \n" | |
| 323 | + " or %4,%0 \n" | |
| 324 | + " mov %0,(_ADR,%2) \n" | |
| 325 | + " mov (_ADR,%2),%0 \n" /* flush */ | |
| 326 | + " mov (_ASR,%2),%0 \n" | |
| 327 | + " or %0,%0 \n" | |
| 328 | + " bne 1b \n" | |
| 329 | + : "=&r"(status), "=m"(*addr) | |
| 330 | + : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(mask) | |
| 331 | + : "memory", "cc"); | |
| 332 | +#else | |
| 333 | + unsigned long flags; | |
| 334 | + | |
| 335 | + flags = arch_local_cli_save(); | |
| 336 | + *addr |= mask; | |
| 337 | + arch_local_irq_restore(flags); | |
| 338 | +#endif | |
| 339 | +} | |
| 340 | + | |
| 341 | +/* Atomic operations are already serializing on MN10300??? */ | |
| 342 | +#define smp_mb__before_atomic_dec() barrier() | |
| 343 | +#define smp_mb__after_atomic_dec() barrier() | |
| 344 | +#define smp_mb__before_atomic_inc() barrier() | |
| 345 | +#define smp_mb__after_atomic_inc() barrier() | |
| 346 | + | |
| 347 | +#include <asm-generic/atomic-long.h> | |
| 348 | + | |
| 349 | +#endif /* __KERNEL__ */ | |
| 350 | +#endif /* CONFIG_SMP */ | |
| 351 | +#endif /* _ASM_ATOMIC_H */ | |
| @@ -57,7 +57,7 @@ · 56 unmodified lines | ||
| 57 | 57 | #define clear_bit(nr, addr) ___clear_bit((nr), (addr)) |
| 58 | 58 | |
| 59 | 59 | |
| 60 | −static inline void __clear_bit(int nr, volatile void *addr) | |
| 60 | +static inline void __clear_bit(unsigned long nr, volatile void *addr) | |
| 61 | 61 | { |
| 62 | 62 | unsigned int *a = (unsigned int *) addr; |
| 63 | 63 | int mask; |
| @@ -70,15 +70,15 @@ static inline void __clear_bit(int nr, volatile void *addr) · 6 unmodified lines | ||
| 70 | 70 | /* |
| 71 | 71 | * test bit |
| 72 | 72 | */ |
| 73 | −static inline int test_bit(int nr, const volatile void *addr) | |
| 73 | +static inline int test_bit(unsigned long nr, const volatile void *addr) | |
| 74 | 74 | { |
| 75 | − return 1UL & (((const unsigned int *) addr)[nr >> 5] >> (nr & 31)); | |
| 75 | + return 1UL & (((const volatile unsigned int *) addr)[nr >> 5] >> (nr & 31)); | |
| 76 | 76 | } |
| 77 | 77 | |
| 78 | 78 | /* |
| 79 | 79 | * change bit |
| 80 | 80 | */ |
| 81 | −static inline void __change_bit(int nr, volatile void *addr) | |
| 81 | +static inline void __change_bit(unsigned long nr, volatile void *addr) | |
| 82 | 82 | { |
| 83 | 83 | int mask; |
| 84 | 84 | unsigned int *a = (unsigned int *) addr; |
| @@ -88,7 +88,7 @@ static inline void __change_bit(int nr, volatile void *addr) · 3 unmodified lines | ||
| 88 | 88 | *a ^= mask; |
| 89 | 89 | } |
| 90 | 90 | |
| 91 | −extern void change_bit(int nr, volatile void *addr); | |
| 91 | +extern void change_bit(unsigned long nr, volatile void *addr); | |
| 92 | 92 | |
| 93 | 93 | /* |
| 94 | 94 | * test and set bit |
| @@ -135,7 +135,7 @@ extern void change_bit(int nr, volatile void *addr); · 40 unmodified lines | ||
| 135 | 135 | /* |
| 136 | 136 | * test and change bit |
| 137 | 137 | */ |
| 138 | −static inline int __test_and_change_bit(int nr, volatile void *addr) | |
| 138 | +static inline int __test_and_change_bit(unsigned long nr, volatile void *addr) | |
| 139 | 139 | { |
| 140 | 140 | int mask, retval; |
| 141 | 141 | unsigned int *a = (unsigned int *)addr; |
| @@ -148,7 +148,7 @@ static inline int __test_and_change_bit(int nr, volatile void *addr) · 6 unmodified lines | ||
| 148 | 148 | return retval; |
| 149 | 149 | } |
| 150 | 150 | |
| 151 | −extern int test_and_change_bit(int nr, volatile void *addr); | |
| 151 | +extern int test_and_change_bit(unsigned long nr, volatile void *addr); | |
| 152 | 152 | |
| 153 | 153 | #include <asm-generic/bitops/lock.h> |
| 154 | 154 | |
| @@ -43,14 +43,18 @@ · 42 unmodified lines | ||
| 43 | 43 | |
| 44 | 44 | /* instruction cache access registers */ |
| 45 | 45 | #define ICACHE_DATA(WAY, ENTRY, OFF) \ |
| 46 | − __SYSREG(0xc8000000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10 + (OFF) * 4, u32) | |
| 46 | + __SYSREG(0xc8000000 + (WAY) * L1_CACHE_WAYDISP + \ | |
| 47 | + (ENTRY) * L1_CACHE_BYTES + (OFF) * 4, u32) | |
| 47 | 48 | #define ICACHE_TAG(WAY, ENTRY) \ |
| 48 | − __SYSREG(0xc8100000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10, u32) | |
| 49 | + __SYSREG(0xc8100000 + (WAY) * L1_CACHE_WAYDISP + \ | |
| 50 | + (ENTRY) * L1_CACHE_BYTES, u32) | |
| 49 | 51 | |
| 50 | −/* instruction cache access registers */ | |
| 52 | +/* data cache access registers */ | |
| 51 | 53 | #define DCACHE_DATA(WAY, ENTRY, OFF) \ |
| 52 | − __SYSREG(0xc8200000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10 + (OFF) * 4, u32) | |
| 54 | + __SYSREG(0xc8200000 + (WAY) * L1_CACHE_WAYDISP + \ | |
| 55 | + (ENTRY) * L1_CACHE_BYTES + (OFF) * 4, u32) | |
| 53 | 56 | #define DCACHE_TAG(WAY, ENTRY) \ |
| 54 | − __SYSREG(0xc8300000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10, u32) | |
| 57 | + __SYSREG(0xc8300000 + (WAY) * L1_CACHE_WAYDISP + \ | |
| 58 | + (ENTRY) * L1_CACHE_BYTES, u32) | |
| 55 | 59 | |
| 56 | 60 | #endif /* _ASM_CACHE_H */ |
| @@ -17,66 +17,55 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/mm.h> |
| 18 | 18 | |
| 19 | 19 | /* |
| 20 | − * virtually-indexed cache management (our cache is physically indexed) | |
| 20 | + * Primitive routines | |
| 21 | 21 | */ |
| 22 | −#define flush_cache_all() do {} while (0) | |
| 23 | −#define flush_cache_mm(mm) do {} while (0) | |
| 24 | −#define flush_cache_dup_mm(mm) do {} while (0) | |
| 25 | −#define flush_cache_range(mm, start, end) do {} while (0) | |
| 26 | −#define flush_cache_page(vma, vmaddr, pfn) do {} while (0) | |
| 27 | −#define flush_cache_vmap(start, end) do {} while (0) | |
| 28 | −#define flush_cache_vunmap(start, end) do {} while (0) | |
| 29 | −#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 | |
| 30 | −#define flush_dcache_page(page) do {} while (0) | |
| 31 | −#define flush_dcache_mmap_lock(mapping) do {} while (0) | |
| 32 | −#define flush_dcache_mmap_unlock(mapping) do {} while (0) | |
| 33 | − | |
| 34 | −/* | |
| 35 | − * physically-indexed cache management | |
| 36 | − */ | |
| 37 | −#ifndef CONFIG_MN10300_CACHE_DISABLED | |
| 38 | − | |
| 39 | −extern void flush_icache_range(unsigned long start, unsigned long end); | |
| 40 | −extern void flush_icache_page(struct vm_area_struct *vma, struct page *pg); | |
| 41 | − | |
| 42 | −#else | |
| 43 | − | |
| 44 | −#define flush_icache_range(start, end) do {} while (0) | |
| 45 | −#define flush_icache_page(vma, pg) do {} while (0) | |
| 46 | − | |
| 47 | −#endif | |
| 48 | − | |
| 49 | −#define flush_icache_user_range(vma, pg, adr, len) \ | |
| 50 | − flush_icache_range(adr, adr + len) | |
| 51 | − | |
| 52 | −#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ | |
| 53 | − do { \ | |
| 54 | − memcpy(dst, src, len); \ | |
| 55 | − flush_icache_page(vma, page); \ | |
| 56 | − } while (0) | |
| 57 | − | |
| 58 | −#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ | |
| 59 | − memcpy(dst, src, len) | |
| 60 | − | |
| 61 | −/* | |
| 62 | − * primitive routines | |
| 63 | − */ | |
| 64 | −#ifndef CONFIG_MN10300_CACHE_DISABLED | |
| 22 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 23 | +extern void mn10300_local_icache_inv(void); | |
| 24 | +extern void mn10300_local_icache_inv_page(unsigned long start); | |
| 25 | +extern void mn10300_local_icache_inv_range(unsigned long start, unsigned long end); | |
| 26 | +extern void mn10300_local_icache_inv_range2(unsigned long start, unsigned long size); | |
| 27 | +extern void mn10300_local_dcache_inv(void); | |
| 28 | +extern void mn10300_local_dcache_inv_page(unsigned long start); | |
| 29 | +extern void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end); | |
| 30 | +extern void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size); | |
| 65 | 31 | extern void mn10300_icache_inv(void); |
| 32 | +extern void mn10300_icache_inv_page(unsigned long start); | |
| 33 | +extern void mn10300_icache_inv_range(unsigned long start, unsigned long end); | |
| 34 | +extern void mn10300_icache_inv_range2(unsigned long start, unsigned long size); | |
| 66 | 35 | extern void mn10300_dcache_inv(void); |
| 67 | −extern void mn10300_dcache_inv_page(unsigned start); | |
| 68 | −extern void mn10300_dcache_inv_range(unsigned start, unsigned end); | |
| 69 | −extern void mn10300_dcache_inv_range2(unsigned start, unsigned size); | |
| 36 | +extern void mn10300_dcache_inv_page(unsigned long start); | |
| 37 | +extern void mn10300_dcache_inv_range(unsigned long start, unsigned long end); | |
| 38 | +extern void mn10300_dcache_inv_range2(unsigned long start, unsigned long size); | |
| 70 | 39 | #ifdef CONFIG_MN10300_CACHE_WBACK |
| 40 | +extern void mn10300_local_dcache_flush(void); | |
| 41 | +extern void mn10300_local_dcache_flush_page(unsigned long start); | |
| 42 | +extern void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end); | |
| 43 | +extern void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size); | |
| 44 | +extern void mn10300_local_dcache_flush_inv(void); | |
| 45 | +extern void mn10300_local_dcache_flush_inv_page(unsigned long start); | |
| 46 | +extern void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end); | |
| 47 | +extern void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size); | |
| 71 | 48 | extern void mn10300_dcache_flush(void); |
| 72 | −extern void mn10300_dcache_flush_page(unsigned start); | |
| 73 | −extern void mn10300_dcache_flush_range(unsigned start, unsigned end); | |
| 74 | −extern void mn10300_dcache_flush_range2(unsigned start, unsigned size); | |
| 49 | +extern void mn10300_dcache_flush_page(unsigned long start); | |
| 50 | +extern void mn10300_dcache_flush_range(unsigned long start, unsigned long end); | |
| 51 | +extern void mn10300_dcache_flush_range2(unsigned long start, unsigned long size); | |
| 75 | 52 | extern void mn10300_dcache_flush_inv(void); |
| 76 | −extern void mn10300_dcache_flush_inv_page(unsigned start); | |
| 77 | −extern void mn10300_dcache_flush_inv_range(unsigned start, unsigned end); | |
| 78 | −extern void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size); | |
| 53 | +extern void mn10300_dcache_flush_inv_page(unsigned long start); | |
| 54 | +extern void mn10300_dcache_flush_inv_range(unsigned long start, unsigned long end); | |
| 55 | +extern void mn10300_dcache_flush_inv_range2(unsigned long start, unsigned long size); | |
| 79 | 56 | #else |
| 57 | +#define mn10300_local_dcache_flush() do {} while (0) | |
| 58 | +#define mn10300_local_dcache_flush_page(start) do {} while (0) | |
| 59 | +#define mn10300_local_dcache_flush_range(start, end) do {} while (0) | |
| 60 | +#define mn10300_local_dcache_flush_range2(start, size) do {} while (0) | |
| 61 | +#define mn10300_local_dcache_flush_inv() \ | |
| 62 | + mn10300_local_dcache_inv() | |
| 63 | +#define mn10300_local_dcache_flush_inv_page(start) \ | |
| 64 | + mn10300_local_dcache_inv_page(start) | |
| 65 | +#define mn10300_local_dcache_flush_inv_range(start, end) \ | |
| 66 | + mn10300_local_dcache_inv_range(start, end) | |
| 67 | +#define mn10300_local_dcache_flush_inv_range2(start, size) \ | |
| 68 | + mn10300_local_dcache_inv_range2(start, size) | |
| 80 | 69 | #define mn10300_dcache_flush() do {} while (0) |
| 81 | 70 | #define mn10300_dcache_flush_page(start) do {} while (0) |
| 82 | 71 | #define mn10300_dcache_flush_range(start, end) do {} while (0) |
| @@ -90,7 +79,26 @@ extern void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size); · 7 unmodified lines | ||
| 90 | 79 | mn10300_dcache_inv_range2((start), (size)) |
| 91 | 80 | #endif /* CONFIG_MN10300_CACHE_WBACK */ |
| 92 | 81 | #else |
| 82 | +#define mn10300_local_icache_inv() do {} while (0) | |
| 83 | +#define mn10300_local_icache_inv_page(start) do {} while (0) | |
| 84 | +#define mn10300_local_icache_inv_range(start, end) do {} while (0) | |
| 85 | +#define mn10300_local_icache_inv_range2(start, size) do {} while (0) | |
| 86 | +#define mn10300_local_dcache_inv() do {} while (0) | |
| 87 | +#define mn10300_local_dcache_inv_page(start) do {} while (0) | |
| 88 | +#define mn10300_local_dcache_inv_range(start, end) do {} while (0) | |
| 89 | +#define mn10300_local_dcache_inv_range2(start, size) do {} while (0) | |
| 90 | +#define mn10300_local_dcache_flush() do {} while (0) | |
| 91 | +#define mn10300_local_dcache_flush_inv_page(start) do {} while (0) | |
| 92 | +#define mn10300_local_dcache_flush_inv() do {} while (0) | |
| 93 | +#define mn10300_local_dcache_flush_inv_range(start, end)do {} while (0) | |
| 94 | +#define mn10300_local_dcache_flush_inv_range2(start, size) do {} while (0) | |
| 95 | +#define mn10300_local_dcache_flush_page(start) do {} while (0) | |
| 96 | +#define mn10300_local_dcache_flush_range(start, end) do {} while (0) | |
| 97 | +#define mn10300_local_dcache_flush_range2(start, size) do {} while (0) | |
| 93 | 98 | #define mn10300_icache_inv() do {} while (0) |
| 99 | +#define mn10300_icache_inv_page(start) do {} while (0) | |
| 100 | +#define mn10300_icache_inv_range(start, end) do {} while (0) | |
| 101 | +#define mn10300_icache_inv_range2(start, size) do {} while (0) | |
| 94 | 102 | #define mn10300_dcache_inv() do {} while (0) |
| 95 | 103 | #define mn10300_dcache_inv_page(start) do {} while (0) |
| 96 | 104 | #define mn10300_dcache_inv_range(start, end) do {} while (0) |
| @@ -103,10 +111,56 @@ extern void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size); · 6 unmodified lines | ||
| 103 | 111 | #define mn10300_dcache_flush_page(start) do {} while (0) |
| 104 | 112 | #define mn10300_dcache_flush_range(start, end) do {} while (0) |
| 105 | 113 | #define mn10300_dcache_flush_range2(start, size) do {} while (0) |
| 106 | −#endif /* CONFIG_MN10300_CACHE_DISABLED */ | |
| 114 | +#endif /* CONFIG_MN10300_CACHE_ENABLED */ | |
| 115 | + | |
| 116 | +/* | |
| 117 | + * Virtually-indexed cache management (our cache is physically indexed) | |
| 118 | + */ | |
| 119 | +#define flush_cache_all() do {} while (0) | |
| 120 | +#define flush_cache_mm(mm) do {} while (0) | |
| 121 | +#define flush_cache_dup_mm(mm) do {} while (0) | |
| 122 | +#define flush_cache_range(mm, start, end) do {} while (0) | |
| 123 | +#define flush_cache_page(vma, vmaddr, pfn) do {} while (0) | |
| 124 | +#define flush_cache_vmap(start, end) do {} while (0) | |
| 125 | +#define flush_cache_vunmap(start, end) do {} while (0) | |
| 126 | +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 | |
| 127 | +#define flush_dcache_page(page) do {} while (0) | |
| 128 | +#define flush_dcache_mmap_lock(mapping) do {} while (0) | |
| 129 | +#define flush_dcache_mmap_unlock(mapping) do {} while (0) | |
| 130 | + | |
| 131 | +/* | |
| 132 | + * Physically-indexed cache management | |
| 133 | + */ | |
| 134 | +#if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) | |
| 135 | +extern void flush_icache_page(struct vm_area_struct *vma, struct page *page); | |
| 136 | +extern void flush_icache_range(unsigned long start, unsigned long end); | |
| 137 | +#elif defined(CONFIG_MN10300_CACHE_INV_ICACHE) | |
| 138 | +static inline void flush_icache_page(struct vm_area_struct *vma, | |
| 139 | + struct page *page) | |
| 140 | +{ | |
| 141 | + mn10300_icache_inv_page(page_to_phys(page)); | |
| 142 | +} | |
| 143 | +extern void flush_icache_range(unsigned long start, unsigned long end); | |
| 144 | +#else | |
| 145 | +#define flush_icache_range(start, end) do {} while (0) | |
| 146 | +#define flush_icache_page(vma, pg) do {} while (0) | |
| 147 | +#endif | |
| 148 | + | |
| 149 | + | |
| 150 | +#define flush_icache_user_range(vma, pg, adr, len) \ | |
| 151 | + flush_icache_range(adr, adr + len) | |
| 152 | + | |
| 153 | +#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ | |
| 154 | + do { \ | |
| 155 | + memcpy(dst, src, len); \ | |
| 156 | + flush_icache_page(vma, page); \ | |
| 157 | + } while (0) | |
| 158 | + | |
| 159 | +#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ | |
| 160 | + memcpy(dst, src, len) | |
| 107 | 161 | |
| 108 | 162 | /* |
| 109 | − * internal debugging function | |
| 163 | + * Internal debugging function | |
| 110 | 164 | */ |
| 111 | 165 | #ifdef CONFIG_DEBUG_PAGEALLOC |
| 112 | 166 | extern void kernel_map_pages(struct page *page, int numpages, int enable); |
| @@ -15,7 +15,6 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <linux/types.h> |
| 16 | 16 | #endif |
| 17 | 17 | |
| 18 | −#ifdef CONFIG_MN10300_CPU_AM33V2 | |
| 19 | 18 | /* we tell the compiler to pretend to be AM33 so that it doesn't try and use |
| 20 | 19 | * the FP regs, but tell the assembler that we're actually allowed AM33v2 |
| 21 | 20 | * instructions */ |
| @@ -24,7 +23,6 @@ asm(" .am33_2\n"); · 2 unmodified lines | ||
| 24 | 23 | #else |
| 25 | 24 | .am33_2 |
| 26 | 25 | #endif |
| 27 | −#endif | |
| 28 | 26 | |
| 29 | 27 | #ifdef __KERNEL__ |
| 30 | 28 | |
| @@ -58,6 +56,9 @@ asm(" .am33_2\n"); · 27 unmodified lines | ||
| 58 | 56 | #define EPSW_nAR 0x00040000 /* register bank control */ |
| 59 | 57 | #define EPSW_ML 0x00080000 /* monitor level */ |
| 60 | 58 | #define EPSW_FE 0x00100000 /* FPU enable */ |
| 59 | +#define EPSW_IM_SHIFT 8 /* EPSW_IM_SHIFT determines the interrupt mode */ | |
| 60 | + | |
| 61 | +#define NUM2EPSW_IM(num) ((num) << EPSW_IM_SHIFT) | |
| 61 | 62 | |
| 62 | 63 | /* FPU registers */ |
| 63 | 64 | #define FPCR_EF_I 0x00000001 /* inexact result FPU exception flag */ |
| @@ -99,9 +100,11 @@ asm(" .am33_2\n"); · 35 unmodified lines | ||
| 99 | 100 | #define CPUREV __SYSREGC(0xc0000050, u32) /* CPU revision register */ |
| 100 | 101 | #define CPUREV_TYPE 0x0000000f /* CPU type */ |
| 101 | 102 | #define CPUREV_TYPE_S 0 |
| 102 | −#define CPUREV_TYPE_AM33V1 0x00000000 /* - AM33 V1 core, AM33/1.00 arch */ | |
| 103 | −#define CPUREV_TYPE_AM33V2 0x00000001 /* - AM33 V2 core, AM33/2.00 arch */ | |
| 104 | −#define CPUREV_TYPE_AM34V1 0x00000002 /* - AM34 V1 core, AM33/2.00 arch */ | |
| 103 | +#define CPUREV_TYPE_AM33_1 0x00000000 /* - AM33-1 core, AM33/1.00 arch */ | |
| 104 | +#define CPUREV_TYPE_AM33_2 0x00000001 /* - AM33-2 core, AM33/2.00 arch */ | |
| 105 | +#define CPUREV_TYPE_AM34_1 0x00000002 /* - AM34-1 core, AM33/2.00 arch */ | |
| 106 | +#define CPUREV_TYPE_AM33_3 0x00000003 /* - AM33-3 core, AM33/2.00 arch */ | |
| 107 | +#define CPUREV_TYPE_AM34_2 0x00000004 /* - AM34-2 core, AM33/3.00 arch */ | |
| 105 | 108 | #define CPUREV_REVISION 0x000000f0 /* CPU revision */ |
| 106 | 109 | #define CPUREV_REVISION_S 4 |
| 107 | 110 | #define CPUREV_ICWAY 0x00000f00 /* number of instruction cache ways */ |
| @@ -180,6 +183,21 @@ asm(" .am33_2\n"); · 72 unmodified lines | ||
| 180 | 183 | #define CHCTR_ICWMD 0x0f00 /* instruction cache way mode */ |
| 181 | 184 | #define CHCTR_DCWMD 0xf000 /* data cache way mode */ |
| 182 | 185 | |
| 186 | +#ifdef CONFIG_AM34_2 | |
| 187 | +#define ICIVCR __SYSREG(0xc0000c00, u32) /* icache area invalidate control */ | |
| 188 | +#define ICIVCR_ICIVBSY 0x00000008 /* icache area invalidate busy */ | |
| 189 | +#define ICIVCR_ICI 0x00000001 /* icache area invalidate */ | |
| 190 | + | |
| 191 | +#define ICIVMR __SYSREG(0xc0000c04, u32) /* icache area invalidate mask */ | |
| 192 | + | |
| 193 | +#define DCPGCR __SYSREG(0xc0000c10, u32) /* data cache area purge control */ | |
| 194 | +#define DCPGCR_DCPGBSY 0x00000008 /* data cache area purge busy */ | |
| 195 | +#define DCPGCR_DCP 0x00000002 /* data cache area purge */ | |
| 196 | +#define DCPGCR_DCI 0x00000001 /* data cache area invalidate */ | |
| 197 | + | |
| 198 | +#define DCPGMR __SYSREG(0xc0000c14, u32) /* data cache area purge mask */ | |
| 199 | +#endif /* CONFIG_AM34_2 */ | |
| 200 | + | |
| 183 | 201 | /* MMU control registers */ |
| 184 | 202 | #define MMUCTR __SYSREG(0xc0000090, u32) /* MMU control register */ |
| 185 | 203 | #define MMUCTR_IRP 0x0000003f /* instruction TLB replace pointer */ |
| @@ -203,6 +221,9 @@ asm(" .am33_2\n"); · 17 unmodified lines | ||
| 203 | 221 | #define MMUCTR_DTL_LOCK0_3 0x03000000 /* - entry 0-3 locked */ |
| 204 | 222 | #define MMUCTR_DTL_LOCK0_7 0x04000000 /* - entry 0-7 locked */ |
| 205 | 223 | #define MMUCTR_DTL_LOCK0_15 0x05000000 /* - entry 0-15 locked */ |
| 224 | +#ifdef CONFIG_AM34_2 | |
| 225 | +#define MMUCTR_WTE 0x80000000 /* write-through cache TLB entry bit enable */ | |
| 226 | +#endif | |
| 206 | 227 | |
| 207 | 228 | #define PIDR __SYSREG(0xc0000094, u16) /* PID register */ |
| 208 | 229 | #define PIDR_PID 0x00ff /* process identifier */ |
| @@ -231,14 +252,6 @@ asm(" .am33_2\n"); · 22 unmodified lines | ||
| 231 | 252 | #define xPTEL_PS_4Mb 0x00000c00 /* - 4Mb page */ |
| 232 | 253 | #define xPTEL_PPN 0xfffff006 /* physical page number */ |
| 233 | 254 | |
| 234 | −#define xPTEL_V_BIT 0 /* bit numbers corresponding to above masks */ | |
| 235 | −#define xPTEL_UNUSED1_BIT 1 | |
| 236 | −#define xPTEL_UNUSED2_BIT 2 | |
| 237 | −#define xPTEL_C_BIT 3 | |
| 238 | −#define xPTEL_PV_BIT 4 | |
| 239 | −#define xPTEL_D_BIT 5 | |
| 240 | −#define xPTEL_G_BIT 9 | |
| 241 | − | |
| 242 | 255 | #define IPTEU __SYSREG(0xc00000a4, u32) /* instruction TLB virtual addr */ |
| 243 | 256 | #define DPTEU __SYSREG(0xc00000b4, u32) /* data TLB virtual addr */ |
| 244 | 257 | #define xPTEU_VPN 0xfffffc00 /* virtual page number */ |
| @@ -262,7 +275,16 @@ asm(" .am33_2\n"); · 17 unmodified lines | ||
| 262 | 275 | #define xPTEL2_PS_128Kb 0x00000100 /* - 128Kb page */ |
| 263 | 276 | #define xPTEL2_PS_1Kb 0x00000200 /* - 1Kb page */ |
| 264 | 277 | #define xPTEL2_PS_4Mb 0x00000300 /* - 4Mb page */ |
| 265 | −#define xPTEL2_PPN 0xfffffc00 /* physical page number */ | |
| 278 | +#define xPTEL2_CWT 0x00000400 /* cacheable write-through */ | |
| 279 | +#define xPTEL2_UNUSED1 0x00000800 /* unused bit (broadcast mask) */ | |
| 280 | +#define xPTEL2_PPN 0xfffff000 /* physical page number */ | |
| 281 | + | |
| 282 | +#define xPTEL2_V_BIT 0 /* bit numbers corresponding to above masks */ | |
| 283 | +#define xPTEL2_C_BIT 1 | |
| 284 | +#define xPTEL2_PV_BIT 2 | |
| 285 | +#define xPTEL2_D_BIT 3 | |
| 286 | +#define xPTEL2_G_BIT 7 | |
| 287 | +#define xPTEL2_UNUSED1_BIT 11 | |
| 266 | 288 | |
| 267 | 289 | #define MMUFCR __SYSREGC(0xc000009c, u32) /* MMU exception cause */ |
| 268 | 290 | #define MMUFCR_IFC __SYSREGC(0xc000009c, u16) /* MMU instruction excep cause */ |
| @@ -285,6 +307,47 @@ asm(" .am33_2\n"); · 16 unmodified lines | ||
| 285 | 307 | #define MMUFCR_xFC_PR_RWK_RWU 0x01c0 /* - R/W kernel and R/W user */ |
| 286 | 308 | #define MMUFCR_xFC_ILLADDR 0x0200 /* illegal address excep flag */ |
| 287 | 309 | |
| 310 | +#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT | |
| 311 | +/* atomic operation registers */ | |
| 312 | +#define AAR __SYSREG(0xc0000a00, u32) /* cacheable address */ | |
| 313 | +#define AAR2 __SYSREG(0xc0000a04, u32) /* uncacheable address */ | |
| 314 | +#define ADR __SYSREG(0xc0000a08, u32) /* data */ | |
| 315 | +#define ASR __SYSREG(0xc0000a0c, u32) /* status */ | |
| 316 | +#define AARU __SYSREG(0xd400aa00, u32) /* user address */ | |
| 317 | +#define ADRU __SYSREG(0xd400aa08, u32) /* user data */ | |
| 318 | +#define ASRU __SYSREG(0xd400aa0c, u32) /* user status */ | |
| 319 | + | |
| 320 | +#define ASR_RW 0x00000008 /* read */ | |
| 321 | +#define ASR_BW 0x00000004 /* bus error */ | |
| 322 | +#define ASR_IW 0x00000002 /* interrupt */ | |
| 323 | +#define ASR_LW 0x00000001 /* bus lock */ | |
| 324 | + | |
| 325 | +#define ASRU_RW ASR_RW /* read */ | |
| 326 | +#define ASRU_BW ASR_BW /* bus error */ | |
| 327 | +#define ASRU_IW ASR_IW /* interrupt */ | |
| 328 | +#define ASRU_LW ASR_LW /* bus lock */ | |
| 329 | + | |
| 330 | +/* in inline ASM, we stick the base pointer in to a reg and use offsets from | |
| 331 | + * it */ | |
| 332 | +#define ATOMIC_OPS_BASE_ADDR 0xc0000a00 | |
| 333 | +#ifndef __ASSEMBLY__ | |
| 334 | +asm( | |
| 335 | + "_AAR = 0\n" | |
| 336 | + "_AAR2 = 4\n" | |
| 337 | + "_ADR = 8\n" | |
| 338 | + "_ASR = 12\n"); | |
| 339 | +#else | |
| 340 | +#define _AAR 0 | |
| 341 | +#define _AAR2 4 | |
| 342 | +#define _ADR 8 | |
| 343 | +#define _ASR 12 | |
| 344 | +#endif | |
| 345 | + | |
| 346 | +/* physical page address for userspace atomic operations registers */ | |
| 347 | +#define USER_ATOMIC_OPS_PAGE_ADDR 0xd400a000 | |
| 348 | + | |
| 349 | +#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */ | |
| 350 | + | |
| 288 | 351 | #endif /* __KERNEL__ */ |
| 289 | 352 | |
| 290 | 353 | #endif /* _ASM_CPU_REGS_H */ |
| @@ -11,91 +11,6 @@ · 10 unmodified lines | ||
| 11 | 11 | #ifndef _ASM_DMACTL_REGS_H |
| 12 | 12 | #define _ASM_DMACTL_REGS_H |
| 13 | 13 | |
| 14 | −#include <asm/cpu-regs.h> | |
| 15 | − | |
| 16 | −#ifdef __KERNEL__ | |
| 17 | − | |
| 18 | −/* DMA registers */ | |
| 19 | −#define DMxCTR(N) __SYSREG(0xd2000000 + ((N) * 0x100), u32) /* control reg */ | |
| 20 | −#define DMxCTR_BG 0x0000001f /* transfer request source */ | |
| 21 | −#define DMxCTR_BG_SOFT 0x00000000 /* - software source */ | |
| 22 | −#define DMxCTR_BG_SC0TX 0x00000002 /* - serial port 0 transmission */ | |
| 23 | −#define DMxCTR_BG_SC0RX 0x00000003 /* - serial port 0 reception */ | |
| 24 | −#define DMxCTR_BG_SC1TX 0x00000004 /* - serial port 1 transmission */ | |
| 25 | −#define DMxCTR_BG_SC1RX 0x00000005 /* - serial port 1 reception */ | |
| 26 | −#define DMxCTR_BG_SC2TX 0x00000006 /* - serial port 2 transmission */ | |
| 27 | −#define DMxCTR_BG_SC2RX 0x00000007 /* - serial port 2 reception */ | |
| 28 | −#define DMxCTR_BG_TM0UFLOW 0x00000008 /* - timer 0 underflow */ | |
| 29 | −#define DMxCTR_BG_TM1UFLOW 0x00000009 /* - timer 1 underflow */ | |
| 30 | −#define DMxCTR_BG_TM2UFLOW 0x0000000a /* - timer 2 underflow */ | |
| 31 | −#define DMxCTR_BG_TM3UFLOW 0x0000000b /* - timer 3 underflow */ | |
| 32 | −#define DMxCTR_BG_TM6ACMPCAP 0x0000000c /* - timer 6A compare/capture */ | |
| 33 | −#define DMxCTR_BG_AFE 0x0000000d /* - analogue front-end interrupt source */ | |
| 34 | −#define DMxCTR_BG_ADC 0x0000000e /* - A/D conversion end interrupt source */ | |
| 35 | −#define DMxCTR_BG_IRDA 0x0000000f /* - IrDA interrupt source */ | |
| 36 | −#define DMxCTR_BG_RTC 0x00000010 /* - RTC interrupt source */ | |
| 37 | −#define DMxCTR_BG_XIRQ0 0x00000011 /* - XIRQ0 pin interrupt source */ | |
| 38 | −#define DMxCTR_BG_XIRQ1 0x00000012 /* - XIRQ1 pin interrupt source */ | |
| 39 | −#define DMxCTR_BG_XDMR0 0x00000013 /* - external request 0 source (XDMR0 pin) */ | |
| 40 | −#define DMxCTR_BG_XDMR1 0x00000014 /* - external request 1 source (XDMR1 pin) */ | |
| 41 | −#define DMxCTR_SAM 0x000000e0 /* DMA transfer src addr mode */ | |
| 42 | −#define DMxCTR_SAM_INCR 0x00000000 /* - increment */ | |
| 43 | −#define DMxCTR_SAM_DECR 0x00000020 /* - decrement */ | |
| 44 | −#define DMxCTR_SAM_FIXED 0x00000040 /* - fixed */ | |
| 45 | −#define DMxCTR_DAM 0x00000000 /* DMA transfer dest addr mode */ | |
| 46 | −#define DMxCTR_DAM_INCR 0x00000000 /* - increment */ | |
| 47 | −#define DMxCTR_DAM_DECR 0x00000100 /* - decrement */ | |
| 48 | −#define DMxCTR_DAM_FIXED 0x00000200 /* - fixed */ | |
| 49 | −#define DMxCTR_TM 0x00001800 /* DMA transfer mode */ | |
| 50 | −#define DMxCTR_TM_BATCH 0x00000000 /* - batch transfer */ | |
| 51 | −#define DMxCTR_TM_INTERM 0x00001000 /* - intermittent transfer */ | |
| 52 | −#define DMxCTR_UT 0x00006000 /* DMA transfer unit */ | |
| 53 | −#define DMxCTR_UT_1 0x00000000 /* - 1 byte */ | |
| 54 | −#define DMxCTR_UT_2 0x00002000 /* - 2 byte */ | |
| 55 | −#define DMxCTR_UT_4 0x00004000 /* - 4 byte */ | |
| 56 | −#define DMxCTR_UT_16 0x00006000 /* - 16 byte */ | |
| 57 | −#define DMxCTR_TEN 0x00010000 /* DMA channel transfer enable */ | |
| 58 | −#define DMxCTR_RQM 0x00060000 /* external request input source mode */ | |
| 59 | −#define DMxCTR_RQM_FALLEDGE 0x00000000 /* - falling edge */ | |
| 60 | −#define DMxCTR_RQM_RISEEDGE 0x00020000 /* - rising edge */ | |
| 61 | −#define DMxCTR_RQM_LOLEVEL 0x00040000 /* - low level */ | |
| 62 | −#define DMxCTR_RQM_HILEVEL 0x00060000 /* - high level */ | |
| 63 | −#define DMxCTR_RQF 0x01000000 /* DMA transfer request flag */ | |
| 64 | −#define DMxCTR_XEND 0x80000000 /* DMA transfer end flag */ | |
| 65 | − | |
| 66 | −#define DMxSRC(N) __SYSREG(0xd2000004 + ((N) * 0x100), u32) /* control reg */ | |
| 67 | − | |
| 68 | −#define DMxDST(N) __SYSREG(0xd2000008 + ((N) * 0x100), u32) /* src addr reg */ | |
| 69 | − | |
| 70 | −#define DMxSIZ(N) __SYSREG(0xd200000c + ((N) * 0x100), u32) /* dest addr reg */ | |
| 71 | −#define DMxSIZ_CT 0x000fffff /* number of bytes to transfer */ | |
| 72 | − | |
| 73 | −#define DMxCYC(N) __SYSREG(0xd2000010 + ((N) * 0x100), u32) /* intermittent | |
| 74 | − * size reg */ | |
| 75 | −#define DMxCYC_CYC 0x000000ff /* number of interrmittent transfers -1 */ | |
| 76 | − | |
| 77 | −#define DM0IRQ 16 /* DMA channel 0 complete IRQ */ | |
| 78 | −#define DM1IRQ 17 /* DMA channel 1 complete IRQ */ | |
| 79 | −#define DM2IRQ 18 /* DMA channel 2 complete IRQ */ | |
| 80 | −#define DM3IRQ 19 /* DMA channel 3 complete IRQ */ | |
| 81 | − | |
| 82 | −#define DM0ICR GxICR(DM0IRQ) /* DMA channel 0 complete intr ctrl reg */ | |
| 83 | −#define DM1ICR GxICR(DM0IR1) /* DMA channel 1 complete intr ctrl reg */ | |
| 84 | −#define DM2ICR GxICR(DM0IR2) /* DMA channel 2 complete intr ctrl reg */ | |
| 85 | −#define DM3ICR GxICR(DM0IR3) /* DMA channel 3 complete intr ctrl reg */ | |
| 86 | − | |
| 87 | −#ifndef __ASSEMBLY__ | |
| 88 | − | |
| 89 | −struct mn10300_dmactl_regs { | |
| 90 | − u32 ctr; | |
| 91 | − const void *src; | |
| 92 | − void *dst; | |
| 93 | − u32 siz; | |
| 94 | − u32 cyc; | |
| 95 | −} __attribute__((aligned(0x100))); | |
| 96 | − | |
| 97 | −#endif /* __ASSEMBLY__ */ | |
| 98 | − | |
| 99 | −#endif /* __KERNEL__ */ | |
| 14 | +#include <proc/dmactl-regs.h> | |
| 100 | 15 | |
| 101 | 16 | #endif /* _ASM_DMACTL_REGS_H */ |
| @@ -31,6 +31,12 @@ · 30 unmodified lines | ||
| 31 | 31 | #define R_MN10300_SYM_DIFF 33 /* Adjustment when relaxing. */ |
| 32 | 32 | #define R_MN10300_ALIGN 34 /* Alignment requirement. */ |
| 33 | 33 | |
| 34 | +/* | |
| 35 | + * AM33/AM34 HW Capabilities | |
| 36 | + */ | |
| 37 | +#define HWCAP_MN10300_ATOMIC_OP_UNIT 1 /* Has AM34 Atomic Operations */ | |
| 38 | + | |
| 39 | + | |
| 34 | 40 | /* |
| 35 | 41 | * ELF register definitions.. |
| 36 | 42 | */ |
| @@ -47,8 +53,6 @@ typedef struct { · 10 unmodified lines | ||
| 47 | 53 | u_int32_t fpcr; |
| 48 | 54 | } elf_fpregset_t; |
| 49 | 55 | |
| 50 | −extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); | |
| 51 | − | |
| 52 | 56 | /* |
| 53 | 57 | * This is used to ensure we don't load something for the wrong architecture |
| 54 | 58 | */ |
| @@ -130,7 +134,11 @@ do { \ · 75 unmodified lines | ||
| 130 | 134 | * instruction set this CPU supports. This could be done in user space, |
| 131 | 135 | * but it's not easy, and we've already done it here. |
| 132 | 136 | */ |
| 137 | +#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT | |
| 138 | +#define ELF_HWCAP (HWCAP_MN10300_ATOMIC_OP_UNIT) | |
| 139 | +#else | |
| 133 | 140 | #define ELF_HWCAP (0) |
| 141 | +#endif | |
| 134 | 142 | |
| 135 | 143 | /* |
| 136 | 144 | * This yields a string that ld.so will use to load implementation |
| @@ -15,8 +15,8 @@ · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | /* |
| 17 | 17 | * define the breakpoint instruction opcode to use |
| 18 | − * - note that the JTAG unit steals 0xFF, so we want to avoid that if we can | |
| 19 | − * (can use 0xF7) | |
| 18 | + * - note that the JTAG unit steals 0xFF, so you can't use JTAG and GDBSTUB at | |
| 19 | + * the same time. | |
| 20 | 20 | */ |
| 21 | 21 | #define GDBSTUB_BKPT 0xFF |
| 22 | 22 | |
| @@ -90,7 +90,6 @@ enum exception_code { · 67 unmodified lines | ||
| 90 | 90 | |
| 91 | 91 | extern void __set_intr_stub(enum exception_code code, void *handler); |
| 92 | 92 | extern void set_intr_stub(enum exception_code code, void *handler); |
| 93 | −extern void set_jtag_stub(enum exception_code code, void *handler); | |
| 94 | 93 | |
| 95 | 94 | struct pt_regs; |
| 96 | 95 | |
| @@ -102,7 +101,6 @@ extern asmlinkage void dtlb_aerror(void); · 5 unmodified lines | ||
| 102 | 101 | extern asmlinkage void raw_bus_error(void); |
| 103 | 102 | extern asmlinkage void double_fault(void); |
| 104 | 103 | extern asmlinkage int system_call(struct pt_regs *); |
| 105 | −extern asmlinkage void fpu_exception(struct pt_regs *, enum exception_code); | |
| 106 | 104 | extern asmlinkage void nmi(struct pt_regs *, enum exception_code); |
| 107 | 105 | extern asmlinkage void uninitialised_exception(struct pt_regs *, |
| 108 | 106 | enum exception_code); |
| @@ -116,6 +114,8 @@ extern void die(const char *, struct pt_regs *, enum exception_code) · 7 unmodified lines | ||
| 116 | 114 | |
| 117 | 115 | extern int die_if_no_fixup(const char *, struct pt_regs *, enum exception_code); |
| 118 | 116 | |
| 117 | +#define NUM2EXCEP_IRQ_LEVEL(num) (EXCEP_IRQ_LEVEL0 + (num) * 8) | |
| 118 | + | |
| 119 | 119 | #endif /* __ASSEMBLY__ */ |
| 120 | 120 | |
| 121 | 121 | #endif /* _ASM_EXCEPTIONS_H */ |
| @@ -12,74 +12,125 @@ · 11 unmodified lines | ||
| 12 | 12 | #ifndef _ASM_FPU_H |
| 13 | 13 | #define _ASM_FPU_H |
| 14 | 14 | |
| 15 | −#include <asm/processor.h> | |
| 15 | +#ifndef __ASSEMBLY__ | |
| 16 | + | |
| 17 | +#include <linux/sched.h> | |
| 18 | +#include <asm/exceptions.h> | |
| 16 | 19 | #include <asm/sigcontext.h> |
| 17 | −#include <asm/user.h> | |
| 18 | 20 | |
| 19 | 21 | #ifdef __KERNEL__ |
| 20 | 22 | |
| 21 | −/* the task that owns the FPU state */ | |
| 23 | +extern asmlinkage void fpu_disabled(void); | |
| 24 | + | |
| 25 | +#ifdef CONFIG_FPU | |
| 26 | + | |
| 27 | +#ifdef CONFIG_LAZY_SAVE_FPU | |
| 28 | +/* the task that currently owns the FPU state */ | |
| 22 | 29 | extern struct task_struct *fpu_state_owner; |
| 30 | +#endif | |
| 23 | 31 | |
| 24 | −#define set_using_fpu(tsk) \ | |
| 25 | −do { \ | |
| 26 | − (tsk)->thread.fpu_flags |= THREAD_USING_FPU; \ | |
| 27 | −} while (0) | |
| 32 | +#if (THREAD_USING_FPU & ~0xff) | |
| 33 | +#error THREAD_USING_FPU must be smaller than 0x100. | |
| 34 | +#endif | |
| 28 | 35 | |
| 29 | −#define clear_using_fpu(tsk) \ | |
| 30 | −do { \ | |
| 31 | − (tsk)->thread.fpu_flags &= ~THREAD_USING_FPU; \ | |
| 32 | −} while (0) | |
| 36 | +static inline void set_using_fpu(struct task_struct *tsk) | |
| 37 | +{ | |
| 38 | + asm volatile( | |
| 39 | + "bset %0,(0,%1)" | |
| 40 | + : | |
| 41 | + : "i"(THREAD_USING_FPU), "a"(&tsk->thread.fpu_flags) | |
| 42 | + : "memory", "cc"); | |
| 43 | +} | |
| 33 | 44 | |
| 34 | −#define is_using_fpu(tsk) ((tsk)->thread.fpu_flags & THREAD_USING_FPU) | |
| 45 | +static inline void clear_using_fpu(struct task_struct *tsk) | |
| 46 | +{ | |
| 47 | + asm volatile( | |
| 48 | + "bclr %0,(0,%1)" | |
| 49 | + : | |
| 50 | + : "i"(THREAD_USING_FPU), "a"(&tsk->thread.fpu_flags) | |
| 51 | + : "memory", "cc"); | |
| 52 | +} | |
| 35 | 53 | |
| 36 | −#define unlazy_fpu(tsk) \ | |
| 37 | −do { \ | |
| 38 | − preempt_disable(); \ | |
| 39 | − if (fpu_state_owner == (tsk)) \ | |
| 40 | − fpu_save(&tsk->thread.fpu_state); \ | |
| 41 | − preempt_enable(); \ | |
| 42 | −} while (0) | |
| 43 | − | |
| 44 | −#define exit_fpu() \ | |
| 45 | −do { \ | |
| 46 | − struct task_struct *__tsk = current; \ | |
| 47 | − preempt_disable(); \ | |
| 48 | − if (fpu_state_owner == __tsk) \ | |
| 49 | − fpu_state_owner = NULL; \ | |
| 50 | − preempt_enable(); \ | |
| 51 | −} while (0) | |
| 52 | − | |
| 53 | −#define flush_fpu() \ | |
| 54 | −do { \ | |
| 55 | − struct task_struct *__tsk = current; \ | |
| 56 | − preempt_disable(); \ | |
| 57 | − if (fpu_state_owner == __tsk) { \ | |
| 58 | − fpu_state_owner = NULL; \ | |
| 59 | − __tsk->thread.uregs->epsw &= ~EPSW_FE; \ | |
| 60 | − } \ | |
| 61 | − preempt_enable(); \ | |
| 62 | − clear_using_fpu(__tsk); \ | |
| 63 | −} while (0) | |
| 54 | +#define is_using_fpu(tsk) ((tsk)->thread.fpu_flags & THREAD_USING_FPU) | |
| 64 | 55 | |
| 65 | −extern asmlinkage void fpu_init_state(void); | |
| 66 | 56 | extern asmlinkage void fpu_kill_state(struct task_struct *); |
| 67 | −extern asmlinkage void fpu_disabled(struct pt_regs *, enum exception_code); | |
| 68 | 57 | extern asmlinkage void fpu_exception(struct pt_regs *, enum exception_code); |
| 69 | − | |
| 70 | −#ifdef CONFIG_FPU | |
| 58 | +extern asmlinkage void fpu_invalid_op(struct pt_regs *, enum exception_code); | |
| 59 | +extern asmlinkage void fpu_init_state(void); | |
| 71 | 60 | extern asmlinkage void fpu_save(struct fpu_state_struct *); |
| 72 | −extern asmlinkage void fpu_restore(struct fpu_state_struct *); | |
| 73 | −#else | |
| 74 | −#define fpu_save(a) | |
| 75 | −#define fpu_restore(a) | |
| 76 | −#endif /* CONFIG_FPU */ | |
| 77 | − | |
| 78 | −/* | |
| 79 | − * signal frame handlers | |
| 80 | − */ | |
| 81 | 61 | extern int fpu_setup_sigcontext(struct fpucontext *buf); |
| 82 | 62 | extern int fpu_restore_sigcontext(struct fpucontext *buf); |
| 83 | 63 | |
| 64 | +static inline void unlazy_fpu(struct task_struct *tsk) | |
| 65 | +{ | |
| 66 | + preempt_disable(); | |
| 67 | +#ifndef CONFIG_LAZY_SAVE_FPU | |
| 68 | + if (tsk->thread.fpu_flags & THREAD_HAS_FPU) { | |
| 69 | + fpu_save(&tsk->thread.fpu_state); | |
| 70 | + tsk->thread.fpu_flags &= ~THREAD_HAS_FPU; | |
| 71 | + tsk->thread.uregs->epsw &= ~EPSW_FE; | |
| 72 | + } | |
| 73 | +#else | |
| 74 | + if (fpu_state_owner == tsk) | |
| 75 | + fpu_save(&tsk->thread.fpu_state); | |
| 76 | +#endif | |
| 77 | + preempt_enable(); | |
| 78 | +} | |
| 79 | + | |
| 80 | +static inline void exit_fpu(void) | |
| 81 | +{ | |
| 82 | +#ifdef CONFIG_LAZY_SAVE_FPU | |
| 83 | + struct task_struct *tsk = current; | |
| 84 | + | |
| 85 | + preempt_disable(); | |
| 86 | + if (fpu_state_owner == tsk) | |
| 87 | + fpu_state_owner = NULL; | |
| 88 | + preempt_enable(); | |
| 89 | +#endif | |
| 90 | +} | |
| 91 | + | |
| 92 | +static inline void flush_fpu(void) | |
| 93 | +{ | |
| 94 | + struct task_struct *tsk = current; | |
| 95 | + | |
| 96 | + preempt_disable(); | |
| 97 | +#ifndef CONFIG_LAZY_SAVE_FPU | |
| 98 | + if (tsk->thread.fpu_flags & THREAD_HAS_FPU) { | |
| 99 | + tsk->thread.fpu_flags &= ~THREAD_HAS_FPU; | |
| 100 | + tsk->thread.uregs->epsw &= ~EPSW_FE; | |
| 101 | + } | |
| 102 | +#else | |
| 103 | + if (fpu_state_owner == tsk) { | |
| 104 | + fpu_state_owner = NULL; | |
| 105 | + tsk->thread.uregs->epsw &= ~EPSW_FE; | |
| 106 | + } | |
| 107 | +#endif | |
| 108 | + preempt_enable(); | |
| 109 | + clear_using_fpu(tsk); | |
| 110 | +} | |
| 111 | + | |
| 112 | +#else /* CONFIG_FPU */ | |
| 113 | + | |
| 114 | +extern asmlinkage | |
| 115 | +void unexpected_fpu_exception(struct pt_regs *, enum exception_code); | |
| 116 | +#define fpu_invalid_op unexpected_fpu_exception | |
| 117 | +#define fpu_exception unexpected_fpu_exception | |
| 118 | + | |
| 119 | +struct task_struct; | |
| 120 | +struct fpu_state_struct; | |
| 121 | +static inline bool is_using_fpu(struct task_struct *tsk) { return false; } | |
| 122 | +static inline void set_using_fpu(struct task_struct *tsk) {} | |
| 123 | +static inline void clear_using_fpu(struct task_struct *tsk) {} | |
| 124 | +static inline void fpu_init_state(void) {} | |
| 125 | +static inline void fpu_save(struct fpu_state_struct *s) {} | |
| 126 | +static inline void fpu_kill_state(struct task_struct *tsk) {} | |
| 127 | +static inline void unlazy_fpu(struct task_struct *tsk) {} | |
| 128 | +static inline void exit_fpu(void) {} | |
| 129 | +static inline void flush_fpu(void) {} | |
| 130 | +static inline int fpu_setup_sigcontext(struct fpucontext *buf) { return 0; } | |
| 131 | +static inline int fpu_restore_sigcontext(struct fpucontext *buf) { return 0; } | |
| 132 | +#endif /* CONFIG_FPU */ | |
| 133 | + | |
| 84 | 134 | #endif /* __KERNEL__ */ |
| 135 | +#endif /* !__ASSEMBLY__ */ | |
| 85 | 136 | #endif /* _ASM_FPU_H */ |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | #ifndef __ASM_OFFSETS_H__ |
| 19 | 19 | #include <asm/asm-offsets.h> |
| 20 | 20 | #endif |
| 21 | +#include <asm/thread_info.h> | |
| 21 | 22 | |
| 22 | 23 | #define pi break |
| 23 | 24 | |
| @@ -37,11 +38,15 @@ · 13 unmodified lines | ||
| 37 | 38 | movm [d2,d3,a2,a3,exreg0,exreg1,exother],(sp) |
| 38 | 39 | mov sp,fp # FRAME pointer in A3 |
| 39 | 40 | add -12,sp # allow for calls to be made |
| 40 | − mov (__frame),a1 | |
| 41 | − mov a1,(REG_NEXT,fp) | |
| 42 | − mov fp,(__frame) | |
| 43 | 41 | |
| 44 | − and ~EPSW_FE,epsw # disable the FPU inside the kernel | |
| 42 | + # push the exception frame onto the front of the list | |
| 43 | + GET_THREAD_INFO a1 | |
| 44 | + mov (TI_frame,a1),a0 | |
| 45 | + mov a0,(REG_NEXT,fp) | |
| 46 | + mov fp,(TI_frame,a1) | |
| 47 | + | |
| 48 | + # disable the FPU inside the kernel | |
| 49 | + and ~EPSW_FE,epsw | |
| 45 | 50 | |
| 46 | 51 | # we may be holding current in E2 |
| 47 | 52 | #ifdef CONFIG_MN10300_CURRENT_IN_E2 |
| @@ -57,10 +62,11 @@ · 9 unmodified lines | ||
| 57 | 62 | .macro RESTORE_ALL |
| 58 | 63 | # peel back the stack to the calling frame |
| 59 | 64 | # - this permits execve() to discard extra frames due to kernel syscalls |
| 60 | − mov (__frame),fp | |
| 65 | + GET_THREAD_INFO a0 | |
| 66 | + mov (TI_frame,a0),fp | |
| 61 | 67 | mov fp,sp |
| 62 | − mov (REG_NEXT,fp),d0 # userspace has regs->next == 0 | |
| 63 | − mov d0,(__frame) | |
| 68 | + mov (REG_NEXT,fp),d0 | |
| 69 | + mov d0,(TI_frame,a0) # userspace has regs->next == 0 | |
| 64 | 70 | |
| 65 | 71 | #ifndef CONFIG_MN10300_USING_JTAG |
| 66 | 72 | mov (REG_EPSW,fp),d0 |
| @@ -110,7 +110,7 @@ extern asmlinkage void gdbstub_exception(struct pt_regs *, enum exception_code); · 109 unmodified lines | ||
| 110 | 110 | extern asmlinkage void __gdbstub_bug_trap(void); |
| 111 | 111 | extern asmlinkage void __gdbstub_pause(void); |
| 112 | 112 | |
| 113 | −#ifndef CONFIG_MN10300_CACHE_DISABLED | |
| 113 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 114 | 114 | extern asmlinkage void gdbstub_purge_cache(void); |
| 115 | 115 | #else |
| 116 | 116 | #define gdbstub_purge_cache() do {} while (0) |
| @@ -19,9 +19,10 @@ · 18 unmodified lines | ||
| 19 | 19 | /* assembly code in softirq.h is sensitive to the offsets of these fields */ |
| 20 | 20 | typedef struct { |
| 21 | 21 | unsigned int __softirq_pending; |
| 22 | − unsigned long idle_timestamp; | |
| 22 | +#ifdef CONFIG_MN10300_WD_TIMER | |
| 23 | 23 | unsigned int __nmi_count; /* arch dependent */ |
| 24 | 24 | unsigned int __irq_count; /* arch dependent */ |
| 25 | +#endif | |
| 25 | 26 | } ____cacheline_aligned irq_cpustat_t; |
| 26 | 27 | |
| 27 | 28 | #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ |
| @@ -87,7 +87,7 @@ static inline unsigned long __kmap_atomic(struct page *page) · 86 unmodified lines | ||
| 87 | 87 | BUG(); |
| 88 | 88 | #endif |
| 89 | 89 | set_pte(kmap_pte - idx, mk_pte(page, kmap_prot)); |
| 90 | − __flush_tlb_one(vaddr); | |
| 90 | + local_flush_tlb_one(vaddr); | |
| 91 | 91 | |
| 92 | 92 | return vaddr; |
| 93 | 93 | } |
| @@ -116,7 +116,7 @@ static inline void __kunmap_atomic(unsigned long vaddr) · 22 unmodified lines | ||
| 116 | 116 | * this pte without first remap it |
| 117 | 117 | */ |
| 118 | 118 | pte_clear(kmap_pte - idx); |
| 119 | − __flush_tlb_one(vaddr); | |
| 119 | + local_flush_tlb_one(vaddr); | |
| 120 | 120 | } |
| 121 | 121 | #endif |
| 122 | 122 | |
| @@ -15,24 +15,19 @@ · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | #ifdef __KERNEL__ |
| 17 | 17 | |
| 18 | −/* interrupt controller registers */ | |
| 19 | −#define GxICR(X) __SYSREG(0xd4000000 + (X) * 4, u16) /* group irq ctrl regs */ | |
| 20 | − | |
| 21 | −#define IAGR __SYSREG(0xd4000100, u16) /* intr acceptance group reg */ | |
| 22 | −#define IAGR_GN 0x00fc /* group number register | |
| 23 | − * (documentation _has_ to be wrong) | |
| 24 | − */ | |
| 18 | +/* | |
| 19 | + * Interrupt controller registers | |
| 20 | + * - Registers 64-191 are at addresses offset from the main array | |
| 21 | + */ | |
| 22 | +#define GxICR(X) \ | |
| 23 | + __SYSREG(0xd4000000 + (X) * 4 + \ | |
| 24 | + (((X) >= 64) && ((X) < 192)) * 0xf00, u16) | |
| 25 | 25 | |
| 26 | −#define EXTMD __SYSREG(0xd4000200, u16) /* external pin intr spec reg */ | |
| 27 | −#define GET_XIRQ_TRIGGER(X) ((EXTMD >> ((X) * 2)) & 3) | |
| 26 | +#define GxICR_u8(X) \ | |
| 27 | + __SYSREG(0xd4000000 + (X) * 4 + \ | |
| 28 | + (((X) >= 64) && ((X) < 192)) * 0xf00, u8) | |
| 28 | 29 | |
| 29 | −#define SET_XIRQ_TRIGGER(X,Y) \ | |
| 30 | −do { \ | |
| 31 | − u16 x = EXTMD; \ | |
| 32 | − x &= ~(3 << ((X) * 2)); \ | |
| 33 | − x |= ((Y) & 3) << ((X) * 2); \ | |
| 34 | − EXTMD = x; \ | |
| 35 | −} while (0) | |
| 30 | +#include <proc/intctl-regs.h> | |
| 36 | 31 | |
| 37 | 32 | #define XIRQ_TRIGGER_LOWLEVEL 0 |
| 38 | 33 | #define XIRQ_TRIGGER_HILEVEL 1 |
| @@ -59,10 +54,18 @@ do { \ · 20 unmodified lines | ||
| 59 | 54 | #define GxICR_LEVEL_5 0x5000 /* - level 5 */ |
| 60 | 55 | #define GxICR_LEVEL_6 0x6000 /* - level 6 */ |
| 61 | 56 | #define GxICR_LEVEL_SHIFT 12 |
| 57 | +#define GxICR_NMI 0x8000 /* nmi request flag */ | |
| 58 | + | |
| 59 | +#define NUM2GxICR_LEVEL(num) ((num) << GxICR_LEVEL_SHIFT) | |
| 62 | 60 | |
| 63 | 61 | #ifndef __ASSEMBLY__ |
| 64 | 62 | extern void set_intr_level(int irq, u16 level); |
| 65 | −extern void set_intr_postackable(int irq); | |
| 63 | +extern void mn10300_intc_set_level(unsigned int irq, unsigned int level); | |
| 64 | +extern void mn10300_intc_clear(unsigned int irq); | |
| 65 | +extern void mn10300_intc_set(unsigned int irq); | |
| 66 | +extern void mn10300_intc_enable(unsigned int irq); | |
| 67 | +extern void mn10300_intc_disable(unsigned int irq); | |
| 68 | +extern void mn10300_set_lateack_irq_type(int irq); | |
| 66 | 69 | #endif |
| 67 | 70 | |
| 68 | 71 | /* external interrupts */ |
| @@ -206,6 +206,19 @@ static inline void outsl(unsigned long addr, const void *buffer, int count) · 205 unmodified lines | ||
| 206 | 206 | #define iowrite32_rep(p, src, count) \ |
| 207 | 207 | outsl((unsigned long) (p), (src), (count)) |
| 208 | 208 | |
| 209 | +#define readsb(p, dst, count) \ | |
| 210 | + insb((unsigned long) (p), (dst), (count)) | |
| 211 | +#define readsw(p, dst, count) \ | |
| 212 | + insw((unsigned long) (p), (dst), (count)) | |
| 213 | +#define readsl(p, dst, count) \ | |
| 214 | + insl((unsigned long) (p), (dst), (count)) | |
| 215 | + | |
| 216 | +#define writesb(p, src, count) \ | |
| 217 | + outsb((unsigned long) (p), (src), (count)) | |
| 218 | +#define writesw(p, src, count) \ | |
| 219 | + outsw((unsigned long) (p), (src), (count)) | |
| 220 | +#define writesl(p, src, count) \ | |
| 221 | + outsl((unsigned long) (p), (src), (count)) | |
| 209 | 222 | |
| 210 | 223 | #define IO_SPACE_LIMIT 0xffffffff |
| 211 | 224 | |
| @@ -21,8 +21,16 @@ · 20 unmodified lines | ||
| 21 | 21 | /* this number is used when no interrupt has been assigned */ |
| 22 | 22 | #define NO_IRQ INT_MAX |
| 23 | 23 | |
| 24 | −/* hardware irq numbers */ | |
| 25 | −#define NR_IRQS GxICR_NUM_IRQS | |
| 24 | +/* | |
| 25 | + * hardware irq numbers | |
| 26 | + * - the ASB2364 has an FPGA with an IRQ multiplexer on it | |
| 27 | + */ | |
| 28 | +#ifdef CONFIG_MN10300_UNIT_ASB2364 | |
| 29 | +#include <unit/irq.h> | |
| 30 | +#else | |
| 31 | +#define NR_CPU_IRQS GxICR_NUM_IRQS | |
| 32 | +#define NR_IRQS NR_CPU_IRQS | |
| 33 | +#endif | |
| 26 | 34 | |
| 27 | 35 | /* external hardware irq numbers */ |
| 28 | 36 | #define NR_XIRQS GxICR_NUM_XIRQS |
| @@ -18,7 +18,11 @@ · 17 unmodified lines | ||
| 18 | 18 | #define ARCH_HAS_OWN_IRQ_REGS |
| 19 | 19 | |
| 20 | 20 | #ifndef __ASSEMBLY__ |
| 21 | −#define get_irq_regs() (__frame) | |
| 21 | +static inline __attribute__((const)) | |
| 22 | +struct pt_regs *get_irq_regs(void) | |
| 23 | +{ | |
| 24 | + return current_frame(); | |
| 25 | +} | |
| 22 | 26 | #endif |
| 23 | 27 | |
| 24 | 28 | #endif /* _ASM_IRQ_REGS_H */ |
| @@ -13,6 +13,9 @@ · 12 unmodified lines | ||
| 13 | 13 | #define _ASM_IRQFLAGS_H |
| 14 | 14 | |
| 15 | 15 | #include <asm/cpu-regs.h> |
| 16 | +#ifndef __ASSEMBLY__ | |
| 17 | +#include <linux/smp.h> | |
| 18 | +#endif | |
| 16 | 19 | |
| 17 | 20 | /* |
| 18 | 21 | * interrupt control |
| @@ -23,11 +26,7 @@ · 4 unmodified lines | ||
| 23 | 26 | * - level 6 - timer interrupt |
| 24 | 27 | * - "enabled": run in IM7 |
| 25 | 28 | */ |
| 26 | −#ifdef CONFIG_MN10300_TTYSM | |
| 27 | −#define MN10300_CLI_LEVEL EPSW_IM_2 | |
| 28 | −#else | |
| 29 | −#define MN10300_CLI_LEVEL EPSW_IM_1 | |
| 30 | −#endif | |
| 29 | +#define MN10300_CLI_LEVEL (CONFIG_LINUX_CLI_LEVEL << EPSW_IM_SHIFT) | |
| 31 | 30 | |
| 32 | 31 | #ifndef __ASSEMBLY__ |
| 33 | 32 | |
| @@ -64,11 +63,12 @@ static inline unsigned long arch_local_irq_save(void) · 30 unmodified lines | ||
| 64 | 63 | /* |
| 65 | 64 | * we make sure arch_irq_enable() doesn't cause priority inversion |
| 66 | 65 | */ |
| 67 | −extern unsigned long __mn10300_irq_enabled_epsw; | |
| 66 | +extern unsigned long __mn10300_irq_enabled_epsw[]; | |
| 68 | 67 | |
| 69 | 68 | static inline void arch_local_irq_enable(void) |
| 70 | 69 | { |
| 71 | 70 | unsigned long tmp; |
| 71 | + int cpu = raw_smp_processor_id(); | |
| 72 | 72 | |
| 73 | 73 | asm volatile( |
| 74 | 74 | " mov epsw,%0 \n" |
| @@ -76,8 +76,8 @@ static inline void arch_local_irq_enable(void) · 1 unmodified line | ||
| 76 | 76 | " or %2,%0 \n" |
| 77 | 77 | " mov %0,epsw \n" |
| 78 | 78 | : "=&d"(tmp) |
| 79 | − : "i"(~EPSW_IM), "r"(__mn10300_irq_enabled_epsw) | |
| 80 | − : "memory"); | |
| 79 | + : "i"(~EPSW_IM), "r"(__mn10300_irq_enabled_epsw[cpu]) | |
| 80 | + : "memory", "cc"); | |
| 81 | 81 | } |
| 82 | 82 | |
| 83 | 83 | static inline void arch_local_irq_restore(unsigned long flags) |
| @@ -94,7 +94,7 @@ static inline void arch_local_irq_restore(unsigned long flags) · 10 unmodified lines | ||
| 94 | 94 | |
| 95 | 95 | static inline bool arch_irqs_disabled_flags(unsigned long flags) |
| 96 | 96 | { |
| 97 | − return (flags & EPSW_IM) <= MN10300_CLI_LEVEL; | |
| 97 | + return (flags & (EPSW_IE | EPSW_IM)) != (EPSW_IE | EPSW_IM_7); | |
| 98 | 98 | } |
| 99 | 99 | |
| 100 | 100 | static inline bool arch_irqs_disabled(void) |
| @@ -109,6 +109,9 @@ static inline bool arch_irqs_disabled(void) · 8 unmodified lines | ||
| 109 | 109 | */ |
| 110 | 110 | static inline void arch_safe_halt(void) |
| 111 | 111 | { |
| 112 | +#ifdef CONFIG_SMP | |
| 113 | + arch_local_irq_enable(); | |
| 114 | +#else | |
| 112 | 115 | asm volatile( |
| 113 | 116 | " or %0,epsw \n" |
| 114 | 117 | " nop \n" |
| @@ -117,7 +120,97 @@ static inline void arch_safe_halt(void) · 2 unmodified lines | ||
| 117 | 120 | : |
| 118 | 121 | : "i"(EPSW_IE|EPSW_IM), "n"(&CPUM), "i"(CPUM_SLEEP) |
| 119 | 122 | : "cc"); |
| 123 | +#endif | |
| 120 | 124 | } |
| 121 | 125 | |
| 126 | +#define __sleep_cpu() \ | |
| 127 | +do { \ | |
| 128 | + asm volatile( \ | |
| 129 | + " bset %1,(%0)\n" \ | |
| 130 | + "1: btst %1,(%0)\n" \ | |
| 131 | + " bne 1b\n" \ | |
| 132 | + : \ | |
| 133 | + : "i"(&CPUM), "i"(CPUM_SLEEP) \ | |
| 134 | + : "cc" \ | |
| 135 | + ); \ | |
| 136 | +} while (0) | |
| 137 | + | |
| 138 | +static inline void arch_local_cli(void) | |
| 139 | +{ | |
| 140 | + asm volatile( | |
| 141 | + " and %0,epsw \n" | |
| 142 | + " nop \n" | |
| 143 | + " nop \n" | |
| 144 | + " nop \n" | |
| 145 | + : | |
| 146 | + : "i"(~EPSW_IE) | |
| 147 | + : "memory" | |
| 148 | + ); | |
| 149 | +} | |
| 150 | + | |
| 151 | +static inline unsigned long arch_local_cli_save(void) | |
| 152 | +{ | |
| 153 | + unsigned long flags = arch_local_save_flags(); | |
| 154 | + arch_local_cli(); | |
| 155 | + return flags; | |
| 156 | +} | |
| 157 | + | |
| 158 | +static inline void arch_local_sti(void) | |
| 159 | +{ | |
| 160 | + asm volatile( | |
| 161 | + " or %0,epsw \n" | |
| 162 | + : | |
| 163 | + : "i"(EPSW_IE) | |
| 164 | + : "memory"); | |
| 165 | +} | |
| 166 | + | |
| 167 | +static inline void arch_local_change_intr_mask_level(unsigned long level) | |
| 168 | +{ | |
| 169 | + asm volatile( | |
| 170 | + " and %0,epsw \n" | |
| 171 | + " or %1,epsw \n" | |
| 172 | + : | |
| 173 | + : "i"(~EPSW_IM), "i"(EPSW_IE | level) | |
| 174 | + : "cc", "memory"); | |
| 175 | +} | |
| 176 | + | |
| 177 | +#else /* !__ASSEMBLY__ */ | |
| 178 | + | |
| 179 | +#define LOCAL_SAVE_FLAGS(reg) \ | |
| 180 | + mov epsw,reg | |
| 181 | + | |
| 182 | +#define LOCAL_IRQ_DISABLE \ | |
| 183 | + and ~EPSW_IM,epsw; \ | |
| 184 | + or EPSW_IE|MN10300_CLI_LEVEL,epsw; \ | |
| 185 | + nop; \ | |
| 186 | + nop; \ | |
| 187 | + nop | |
| 188 | + | |
| 189 | +#define LOCAL_IRQ_ENABLE \ | |
| 190 | + or EPSW_IE|EPSW_IM_7,epsw | |
| 191 | + | |
| 192 | +#define LOCAL_IRQ_RESTORE(reg) \ | |
| 193 | + mov reg,epsw | |
| 194 | + | |
| 195 | +#define LOCAL_CLI_SAVE(reg) \ | |
| 196 | + mov epsw,reg; \ | |
| 197 | + and ~EPSW_IE,epsw; \ | |
| 198 | + nop; \ | |
| 199 | + nop; \ | |
| 200 | + nop | |
| 201 | + | |
| 202 | +#define LOCAL_CLI \ | |
| 203 | + and ~EPSW_IE,epsw; \ | |
| 204 | + nop; \ | |
| 205 | + nop; \ | |
| 206 | + nop | |
| 207 | + | |
| 208 | +#define LOCAL_STI \ | |
| 209 | + or EPSW_IE,epsw | |
| 210 | + | |
| 211 | +#define LOCAL_CHANGE_INTR_MASK_LEVEL(level) \ | |
| 212 | + and ~EPSW_IM,epsw; \ | |
| 213 | + or EPSW_IE|(level),epsw | |
| 214 | + | |
| 122 | 215 | #endif /* __ASSEMBLY__ */ |
| 123 | 216 | #endif /* _ASM_IRQFLAGS_H */ |
| @@ -27,28 +27,38 @@ · 26 unmodified lines | ||
| 27 | 27 | #include <asm/tlbflush.h> |
| 28 | 28 | #include <asm-generic/mm_hooks.h> |
| 29 | 29 | |
| 30 | +#define MMU_CONTEXT_TLBPID_NR 256 | |
| 30 | 31 | #define MMU_CONTEXT_TLBPID_MASK 0x000000ffUL |
| 31 | 32 | #define MMU_CONTEXT_VERSION_MASK 0xffffff00UL |
| 32 | 33 | #define MMU_CONTEXT_FIRST_VERSION 0x00000100UL |
| 33 | 34 | #define MMU_NO_CONTEXT 0x00000000UL |
| 34 | − | |
| 35 | −extern unsigned long mmu_context_cache[NR_CPUS]; | |
| 36 | −#define mm_context(mm) (mm->context.tlbpid[smp_processor_id()]) | |
| 35 | +#define MMU_CONTEXT_TLBPID_LOCK_NR 0 | |
| 37 | 36 | |
| 38 | 37 | #define enter_lazy_tlb(mm, tsk) do {} while (0) |
| 39 | 38 | |
| 39 | +static inline void cpu_ran_vm(int cpu, struct mm_struct *mm) | |
| 40 | +{ | |
| 40 | 41 | #ifdef CONFIG_SMP |
| 41 | −#define cpu_ran_vm(cpu, mm) \ | |
| 42 | − cpumask_set_cpu((cpu), mm_cpumask(mm)) | |
| 43 | −#define cpu_maybe_ran_vm(cpu, mm) \ | |
| 44 | − cpumask_test_and_set_cpu((cpu), mm_cpumask(mm)) | |
| 42 | + cpumask_set_cpu(cpu, mm_cpumask(mm)); | |
| 43 | +#endif | |
| 44 | +} | |
| 45 | + | |
| 46 | +static inline bool cpu_maybe_ran_vm(int cpu, struct mm_struct *mm) | |
| 47 | +{ | |
| 48 | +#ifdef CONFIG_SMP | |
| 49 | + return cpumask_test_and_set_cpu(cpu, mm_cpumask(mm)); | |
| 45 | 50 | #else |
| 46 | −#define cpu_ran_vm(cpu, mm) do {} while (0) | |
| 47 | −#define cpu_maybe_ran_vm(cpu, mm) true | |
| 48 | −#endif /* CONFIG_SMP */ | |
| 51 | + return true; | |
| 52 | +#endif | |
| 53 | +} | |
| 49 | 54 | |
| 50 | −/* | |
| 51 | − * allocate an MMU context | |
| 55 | +#ifdef CONFIG_MN10300_TLB_USE_PIDR | |
| 56 | +extern unsigned long mmu_context_cache[NR_CPUS]; | |
| 57 | +#define mm_context(mm) (mm->context.tlbpid[smp_processor_id()]) | |
| 58 | + | |
| 59 | +/** | |
| 60 | + * allocate_mmu_context - Allocate storage for the arch-specific MMU data | |
| 61 | + * @mm: The userspace VM context being set up | |
| 52 | 62 | */ |
| 53 | 63 | static inline unsigned long allocate_mmu_context(struct mm_struct *mm) |
| 54 | 64 | { |
| @@ -58,7 +68,7 @@ static inline unsigned long allocate_mmu_context(struct mm_struct *mm) · 3 unmodified lines | ||
| 58 | 68 | if (!(mc & MMU_CONTEXT_TLBPID_MASK)) { |
| 59 | 69 | /* we exhausted the TLB PIDs of this version on this CPU, so we |
| 60 | 70 | * flush this CPU's TLB in its entirety and start new cycle */ |
| 61 | − flush_tlb_all(); | |
| 71 | + local_flush_tlb_all(); | |
| 62 | 72 | |
| 63 | 73 | /* fix the TLB version if needed (we avoid version #0 so as to |
| 64 | 74 | * distingush MMU_NO_CONTEXT) */ |
| @@ -100,23 +110,35 @@ static inline int init_new_context(struct task_struct *tsk, · 35 unmodified lines | ||
| 100 | 110 | return 0; |
| 101 | 111 | } |
| 102 | 112 | |
| 103 | −/* | |
| 104 | − * destroy context related info for an mm_struct that is about to be put to | |
| 105 | − * rest | |
| 106 | − */ | |
| 107 | −#define destroy_context(mm) do { } while (0) | |
| 108 | − | |
| 109 | 113 | /* |
| 110 | 114 | * after we have set current->mm to a new value, this activates the context for |
| 111 | 115 | * the new mm so we see the new mappings. |
| 112 | 116 | */ |
| 113 | −static inline void activate_context(struct mm_struct *mm, int cpu) | |
| 117 | +static inline void activate_context(struct mm_struct *mm) | |
| 114 | 118 | { |
| 115 | 119 | PIDR = get_mmu_context(mm) & MMU_CONTEXT_TLBPID_MASK; |
| 116 | 120 | } |
| 121 | +#else /* CONFIG_MN10300_TLB_USE_PIDR */ | |
| 117 | 122 | |
| 118 | −/* | |
| 119 | − * change between virtual memory sets | |
| 123 | +#define init_new_context(tsk, mm) (0) | |
| 124 | +#define activate_context(mm) local_flush_tlb() | |
| 125 | + | |
| 126 | +#endif /* CONFIG_MN10300_TLB_USE_PIDR */ | |
| 127 | + | |
| 128 | +/** | |
| 129 | + * destroy_context - Destroy mm context information | |
| 130 | + * @mm: The MM being destroyed. | |
| 131 | + * | |
| 132 | + * Destroy context related info for an mm_struct that is about to be put to | |
| 133 | + * rest | |
| 134 | + */ | |
| 135 | +#define destroy_context(mm) do {} while (0) | |
| 136 | + | |
| 137 | +/** | |
| 138 | + * switch_mm - Change between userspace virtual memory contexts | |
| 139 | + * @prev: The outgoing MM context. | |
| 140 | + * @next: The incoming MM context. | |
| 141 | + * @tsk: The incoming task. | |
| 120 | 142 | */ |
| 121 | 143 | static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, |
| 122 | 144 | struct task_struct *tsk) |
| @@ -124,11 +146,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, · 1 unmodified line | ||
| 124 | 146 | int cpu = smp_processor_id(); |
| 125 | 147 | |
| 126 | 148 | if (prev != next) { |
| 149 | +#ifdef CONFIG_SMP | |
| 150 | + per_cpu(cpu_tlbstate, cpu).active_mm = next; | |
| 151 | +#endif | |
| 127 | 152 | cpu_ran_vm(cpu, next); |
| 128 | − activate_context(next, cpu); | |
| 129 | 153 | PTBR = (unsigned long) next->pgd; |
| 130 | − } else if (!cpu_maybe_ran_vm(cpu, next)) { | |
| 131 | − activate_context(next, cpu); | |
| 154 | + activate_context(next); | |
| 132 | 155 | } |
| 133 | 156 | } |
| 134 | 157 | |
| @@ -11,7 +11,6 @@ · 10 unmodified lines | ||
| 11 | 11 | #ifndef _ASM_PGALLOC_H |
| 12 | 12 | #define _ASM_PGALLOC_H |
| 13 | 13 | |
| 14 | −#include <asm/processor.h> | |
| 15 | 14 | #include <asm/page.h> |
| 16 | 15 | #include <linux/threads.h> |
| 17 | 16 | #include <linux/mm.h> /* for struct page */ |
| @@ -90,46 +90,58 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; · 89 unmodified lines | ||
| 90 | 90 | * The vmalloc() routines also leaves a hole of 4kB between each vmalloced |
| 91 | 91 | * area to catch addressing errors. |
| 92 | 92 | */ |
| 93 | +#ifndef __ASSEMBLY__ | |
| 94 | +#define VMALLOC_OFFSET (8UL * 1024 * 1024) | |
| 95 | +#define VMALLOC_START (0x70000000UL) | |
| 96 | +#define VMALLOC_END (0x7C000000UL) | |
| 97 | +#else | |
| 93 | 98 | #define VMALLOC_OFFSET (8 * 1024 * 1024) |
| 94 | 99 | #define VMALLOC_START (0x70000000) |
| 95 | 100 | #define VMALLOC_END (0x7C000000) |
| 101 | +#endif | |
| 96 | 102 | |
| 97 | 103 | #ifndef __ASSEMBLY__ |
| 98 | 104 | extern pte_t kernel_vmalloc_ptes[(VMALLOC_END - VMALLOC_START) / PAGE_SIZE]; |
| 99 | 105 | #endif |
| 100 | 106 | |
| 101 | −/* IPTEL/DPTEL bit assignments */ | |
| 102 | −#define _PAGE_BIT_VALID xPTEL_V_BIT | |
| 103 | −#define _PAGE_BIT_ACCESSED xPTEL_UNUSED1_BIT /* mustn't be loaded into IPTEL/DPTEL */ | |
| 104 | −#define _PAGE_BIT_NX xPTEL_UNUSED2_BIT /* mustn't be loaded into IPTEL/DPTEL */ | |
| 105 | −#define _PAGE_BIT_CACHE xPTEL_C_BIT | |
| 106 | −#define _PAGE_BIT_PRESENT xPTEL_PV_BIT | |
| 107 | −#define _PAGE_BIT_DIRTY xPTEL_D_BIT | |
| 108 | −#define _PAGE_BIT_GLOBAL xPTEL_G_BIT | |
| 109 | − | |
| 110 | −#define _PAGE_VALID xPTEL_V | |
| 111 | −#define _PAGE_ACCESSED xPTEL_UNUSED1 | |
| 112 | −#define _PAGE_NX xPTEL_UNUSED2 /* no-execute bit */ | |
| 113 | −#define _PAGE_CACHE xPTEL_C | |
| 114 | −#define _PAGE_PRESENT xPTEL_PV | |
| 115 | −#define _PAGE_DIRTY xPTEL_D | |
| 116 | −#define _PAGE_PROT xPTEL_PR | |
| 117 | −#define _PAGE_PROT_RKNU xPTEL_PR_ROK | |
| 118 | −#define _PAGE_PROT_WKNU xPTEL_PR_RWK | |
| 119 | −#define _PAGE_PROT_RKRU xPTEL_PR_ROK_ROU | |
| 120 | −#define _PAGE_PROT_WKRU xPTEL_PR_RWK_ROU | |
| 121 | −#define _PAGE_PROT_WKWU xPTEL_PR_RWK_RWU | |
| 122 | −#define _PAGE_GLOBAL xPTEL_G | |
| 123 | −#define _PAGE_PSE xPTEL_PS_4Mb /* 4MB page */ | |
| 124 | − | |
| 125 | −#define _PAGE_FILE xPTEL_UNUSED1_BIT /* set:pagecache unset:swap */ | |
| 126 | − | |
| 127 | −#define __PAGE_PROT_UWAUX 0x040 | |
| 128 | −#define __PAGE_PROT_USER 0x080 | |
| 129 | −#define __PAGE_PROT_WRITE 0x100 | |
| 107 | +/* IPTEL2/DPTEL2 bit assignments */ | |
| 108 | +#define _PAGE_BIT_VALID xPTEL2_V_BIT | |
| 109 | +#define _PAGE_BIT_CACHE xPTEL2_C_BIT | |
| 110 | +#define _PAGE_BIT_PRESENT xPTEL2_PV_BIT | |
| 111 | +#define _PAGE_BIT_DIRTY xPTEL2_D_BIT | |
| 112 | +#define _PAGE_BIT_GLOBAL xPTEL2_G_BIT | |
| 113 | +#define _PAGE_BIT_ACCESSED xPTEL2_UNUSED1_BIT /* mustn't be loaded into IPTEL2/DPTEL2 */ | |
| 114 | + | |
| 115 | +#define _PAGE_VALID xPTEL2_V | |
| 116 | +#define _PAGE_CACHE xPTEL2_C | |
| 117 | +#define _PAGE_PRESENT xPTEL2_PV | |
| 118 | +#define _PAGE_DIRTY xPTEL2_D | |
| 119 | +#define _PAGE_PROT xPTEL2_PR | |
| 120 | +#define _PAGE_PROT_RKNU xPTEL2_PR_ROK | |
| 121 | +#define _PAGE_PROT_WKNU xPTEL2_PR_RWK | |
| 122 | +#define _PAGE_PROT_RKRU xPTEL2_PR_ROK_ROU | |
| 123 | +#define _PAGE_PROT_WKRU xPTEL2_PR_RWK_ROU | |
| 124 | +#define _PAGE_PROT_WKWU xPTEL2_PR_RWK_RWU | |
| 125 | +#define _PAGE_GLOBAL xPTEL2_G | |
| 126 | +#define _PAGE_PS_MASK xPTEL2_PS | |
| 127 | +#define _PAGE_PS_4Kb xPTEL2_PS_4Kb | |
| 128 | +#define _PAGE_PS_128Kb xPTEL2_PS_128Kb | |
| 129 | +#define _PAGE_PS_1Kb xPTEL2_PS_1Kb | |
| 130 | +#define _PAGE_PS_4Mb xPTEL2_PS_4Mb | |
| 131 | +#define _PAGE_PSE xPTEL2_PS_4Mb /* 4MB page */ | |
| 132 | +#define _PAGE_CACHE_WT xPTEL2_CWT | |
| 133 | +#define _PAGE_ACCESSED xPTEL2_UNUSED1 | |
| 134 | +#define _PAGE_NX 0 /* no-execute bit */ | |
| 135 | + | |
| 136 | +/* If _PAGE_VALID is clear, we use these: */ | |
| 137 | +#define _PAGE_FILE xPTEL2_C /* set:pagecache unset:swap */ | |
| 138 | +#define _PAGE_PROTNONE 0x000 /* If not present */ | |
| 139 | + | |
| 140 | +#define __PAGE_PROT_UWAUX 0x010 | |
| 141 | +#define __PAGE_PROT_USER 0x020 | |
| 142 | +#define __PAGE_PROT_WRITE 0x040 | |
| 130 | 143 | |
| 131 | 144 | #define _PAGE_PRESENTV (_PAGE_PRESENT|_PAGE_VALID) |
| 132 | −#define _PAGE_PROTNONE 0x000 /* If not present */ | |
| 133 | 145 | |
| 134 | 146 | #ifndef __ASSEMBLY__ |
| 135 | 147 | |
| @@ -170,6 +182,9 @@ extern pte_t kernel_vmalloc_ptes[(VMALLOC_END - VMALLOC_START) / PAGE_SIZE]; · 34 unmodified lines | ||
| 170 | 182 | #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE) |
| 171 | 183 | #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC) |
| 172 | 184 | |
| 185 | +#define __PAGE_USERIO (__PAGE_KERNEL_BASE | _PAGE_PROT_WKWU | _PAGE_NX) | |
| 186 | +#define PAGE_USERIO __pgprot(__PAGE_USERIO) | |
| 187 | + | |
| 173 | 188 | /* |
| 174 | 189 | * Whilst the MN10300 can do page protection for execute (given separate data |
| 175 | 190 | * and insn TLBs), we are not supporting it at the moment. Write permission, |
| @@ -323,11 +338,7 @@ static inline int pte_exec_kernel(pte_t pte) · 147 unmodified lines | ||
| 323 | 338 | return 1; |
| 324 | 339 | } |
| 325 | 340 | |
| 326 | −/* | |
| 327 | − * Bits 0 and 1 are taken, split up the 29 bits of offset | |
| 328 | − * into this range: | |
| 329 | − */ | |
| 330 | −#define PTE_FILE_MAX_BITS 29 | |
| 341 | +#define PTE_FILE_MAX_BITS 30 | |
| 331 | 342 | |
| 332 | 343 | #define pte_to_pgoff(pte) (pte_val(pte) >> 2) |
| 333 | 344 | #define pgoff_to_pte(off) __pte((off) << 2 | _PAGE_FILE) |
| @@ -373,8 +384,13 @@ static inline void ptep_mkdirty(pte_t *ptep) · 39 unmodified lines | ||
| 373 | 384 | * Macro to mark a page protection value as "uncacheable". On processors which |
| 374 | 385 | * do not support it, this is a no-op. |
| 375 | 386 | */ |
| 376 | −#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) | _PAGE_CACHE) | |
| 387 | +#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHE) | |
| 377 | 388 | |
| 389 | +/* | |
| 390 | + * Macro to mark a page protection value as "Write-Through". | |
| 391 | + * On processors which do not support it, this is a no-op. | |
| 392 | + */ | |
| 393 | +#define pgprot_through(prot) __pgprot(pgprot_val(prot) | _PAGE_CACHE_WT) | |
| 378 | 394 | |
| 379 | 395 | /* |
| 380 | 396 | * Conversion functions: convert a page and protection to a page entry, |
| @@ -13,10 +13,13 @@ · 12 unmodified lines | ||
| 13 | 13 | #ifndef _ASM_PROCESSOR_H |
| 14 | 14 | #define _ASM_PROCESSOR_H |
| 15 | 15 | |
| 16 | +#include <linux/threads.h> | |
| 17 | +#include <linux/thread_info.h> | |
| 16 | 18 | #include <asm/page.h> |
| 17 | 19 | #include <asm/ptrace.h> |
| 18 | 20 | #include <asm/cpu-regs.h> |
| 19 | −#include <linux/threads.h> | |
| 21 | +#include <asm/uaccess.h> | |
| 22 | +#include <asm/current.h> | |
| 20 | 23 | |
| 21 | 24 | /* Forward declaration, a strange C thing */ |
| 22 | 25 | struct task_struct; |
| @@ -33,6 +36,8 @@ struct mm_struct; · 10 unmodified lines | ||
| 33 | 36 | __pc; \ |
| 34 | 37 | }) |
| 35 | 38 | |
| 39 | +extern void get_mem_info(unsigned long *mem_base, unsigned long *mem_size); | |
| 40 | + | |
| 36 | 41 | extern void show_registers(struct pt_regs *regs); |
| 37 | 42 | |
| 38 | 43 | /* |
| @@ -43,17 +48,22 @@ extern void show_registers(struct pt_regs *regs); · 4 unmodified lines | ||
| 43 | 48 | |
| 44 | 49 | struct mn10300_cpuinfo { |
| 45 | 50 | int type; |
| 46 | − unsigned long loops_per_sec; | |
| 51 | + unsigned long loops_per_jiffy; | |
| 47 | 52 | char hard_math; |
| 48 | − unsigned long *pgd_quick; | |
| 49 | − unsigned long *pte_quick; | |
| 50 | − unsigned long pgtable_cache_sz; | |
| 51 | 53 | }; |
| 52 | 54 | |
| 53 | 55 | extern struct mn10300_cpuinfo boot_cpu_data; |
| 54 | 56 | |
| 57 | +#ifdef CONFIG_SMP | |
| 58 | +#if CONFIG_NR_CPUS < 2 || CONFIG_NR_CPUS > 8 | |
| 59 | +# error Sorry, NR_CPUS should be 2 to 8 | |
| 60 | +#endif | |
| 61 | +extern struct mn10300_cpuinfo cpu_data[]; | |
| 62 | +#define current_cpu_data cpu_data[smp_processor_id()] | |
| 63 | +#else /* CONFIG_SMP */ | |
| 55 | 64 | #define cpu_data &boot_cpu_data |
| 56 | 65 | #define current_cpu_data boot_cpu_data |
| 66 | +#endif /* CONFIG_SMP */ | |
| 57 | 67 | |
| 58 | 68 | extern void identify_cpu(struct mn10300_cpuinfo *); |
| 59 | 69 | extern void print_cpu_info(struct mn10300_cpuinfo *); |
| @@ -76,10 +86,6 @@ extern void dodgy_tsc(void); · 16 unmodified lines | ||
| 76 | 86 | */ |
| 77 | 87 | #define TASK_UNMAPPED_BASE 0x30000000 |
| 78 | 88 | |
| 79 | −typedef struct { | |
| 80 | − unsigned long seg; | |
| 81 | −} mm_segment_t; | |
| 82 | − | |
| 83 | 89 | struct fpu_state_struct { |
| 84 | 90 | unsigned long fs[32]; /* fpu registers */ |
| 85 | 91 | unsigned long fpcr; /* fpu control register */ |
| @@ -92,20 +98,19 @@ struct thread_struct { · 6 unmodified lines | ||
| 92 | 98 | unsigned long a3; /* kernel FP */ |
| 93 | 99 | unsigned long wchan; |
| 94 | 100 | unsigned long usp; |
| 95 | − struct pt_regs *__frame; | |
| 96 | 101 | unsigned long fpu_flags; |
| 97 | 102 | #define THREAD_USING_FPU 0x00000001 /* T if this task is using the FPU */ |
| 103 | +#define THREAD_HAS_FPU 0x00000002 /* T if this task owns the FPU right now */ | |
| 98 | 104 | struct fpu_state_struct fpu_state; |
| 99 | 105 | }; |
| 100 | 106 | |
| 101 | −#define INIT_THREAD \ | |
| 102 | −{ \ | |
| 103 | − .uregs = init_uregs, \ | |
| 104 | − .pc = 0, \ | |
| 105 | − .sp = 0, \ | |
| 106 | − .a3 = 0, \ | |
| 107 | − .wchan = 0, \ | |
| 108 | − .__frame = NULL, \ | |
| 107 | +#define INIT_THREAD \ | |
| 108 | +{ \ | |
| 109 | + .uregs = init_uregs, \ | |
| 110 | + .pc = 0, \ | |
| 111 | + .sp = 0, \ | |
| 112 | + .a3 = 0, \ | |
| 113 | + .wchan = 0, \ | |
| 109 | 114 | } |
| 110 | 115 | |
| 111 | 116 | #define INIT_MMAP \ |
| @@ -117,13 +122,20 @@ struct thread_struct { · 5 unmodified lines | ||
| 117 | 122 | * - need to discard the frame stacked by the kernel thread invoking the execve |
| 118 | 123 | * syscall (see RESTORE_ALL macro) |
| 119 | 124 | */ |
| 120 | −#define start_thread(regs, new_pc, new_sp) do { \ | |
| 121 | − set_fs(USER_DS); \ | |
| 122 | − __frame = current->thread.uregs; \ | |
| 123 | − __frame->epsw = EPSW_nSL | EPSW_IE | EPSW_IM; \ | |
| 124 | − __frame->pc = new_pc; \ | |
| 125 | − __frame->sp = new_sp; \ | |
| 126 | −} while (0) | |
| 125 | +static inline void start_thread(struct pt_regs *regs, | |
| 126 | + unsigned long new_pc, unsigned long new_sp) | |
| 127 | +{ | |
| 128 | + struct thread_info *ti = current_thread_info(); | |
| 129 | + struct pt_regs *frame0; | |
| 130 | + set_fs(USER_DS); | |
| 131 | + | |
| 132 | + frame0 = thread_info_to_uregs(ti); | |
| 133 | + frame0->epsw = EPSW_nSL | EPSW_IE | EPSW_IM; | |
| 134 | + frame0->pc = new_pc; | |
| 135 | + frame0->sp = new_sp; | |
| 136 | + ti->frame = frame0; | |
| 137 | +} | |
| 138 | + | |
| 127 | 139 | |
| 128 | 140 | /* Free all resources held by a thread. */ |
| 129 | 141 | extern void release_thread(struct task_struct *); |
| @@ -157,7 +169,7 @@ unsigned long get_wchan(struct task_struct *p); · 27 unmodified lines | ||
| 157 | 169 | |
| 158 | 170 | static inline void prefetch(const void *x) |
| 159 | 171 | { |
| 160 | −#ifndef CONFIG_MN10300_CACHE_DISABLED | |
| 172 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 161 | 173 | #ifdef CONFIG_MN10300_PROC_MN103E010 |
| 162 | 174 | asm volatile ("nop; nop; dcpf (%0)" : : "r"(x)); |
| 163 | 175 | #else |
| @@ -168,7 +180,7 @@ static inline void prefetch(const void *x) · 4 unmodified lines | ||
| 168 | 180 | |
| 169 | 181 | static inline void prefetchw(const void *x) |
| 170 | 182 | { |
| 171 | −#ifndef CONFIG_MN10300_CACHE_DISABLED | |
| 183 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 172 | 184 | #ifdef CONFIG_MN10300_PROC_MN103E010 |
| 173 | 185 | asm volatile ("nop; nop; dcpf (%0)" : : "r"(x)); |
| 174 | 186 | #else |
| @@ -40,7 +40,6 @@ · 39 unmodified lines | ||
| 40 | 40 | #define PT_PC 26 |
| 41 | 41 | #define NR_PTREGS 27 |
| 42 | 42 | |
| 43 | −#ifndef __ASSEMBLY__ | |
| 44 | 43 | /* |
| 45 | 44 | * This defines the way registers are stored in the event of an exception |
| 46 | 45 | * - the strange order is due to the MOVM instruction |
| @@ -75,7 +74,6 @@ struct pt_regs { · 28 unmodified lines | ||
| 75 | 74 | unsigned long epsw; |
| 76 | 75 | unsigned long pc; |
| 77 | 76 | }; |
| 78 | −#endif | |
| 79 | 77 | |
| 80 | 78 | /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ |
| 81 | 79 | #define PTRACE_GETREGS 12 |
| @@ -86,12 +84,7 @@ struct pt_regs { · 4 unmodified lines | ||
| 86 | 84 | /* options set using PTRACE_SETOPTIONS */ |
| 87 | 85 | #define PTRACE_O_TRACESYSGOOD 0x00000001 |
| 88 | 86 | |
| 89 | −#if defined(__KERNEL__) | |
| 90 | − | |
| 91 | −extern struct pt_regs *__frame; /* current frame pointer */ | |
| 92 | − | |
| 93 | −#if !defined(__ASSEMBLY__) | |
| 94 | −struct task_struct; | |
| 87 | +#ifdef __KERNEL__ | |
| 95 | 88 | |
| 96 | 89 | #define user_mode(regs) (((regs)->epsw & EPSW_nSL) == EPSW_nSL) |
| 97 | 90 | #define instruction_pointer(regs) ((regs)->pc) |
| @@ -100,9 +93,7 @@ extern void show_regs(struct pt_regs *); · 2 unmodified lines | ||
| 100 | 93 | |
| 101 | 94 | #define arch_has_single_step() (1) |
| 102 | 95 | |
| 103 | −#endif /* !__ASSEMBLY */ | |
| 104 | − | |
| 105 | 96 | #define profile_pc(regs) ((regs)->pc) |
| 106 | 97 | |
| 107 | −#endif /* __KERNEL__ */ | |
| 98 | +#endif /* __KERNEL__ */ | |
| 108 | 99 | #endif /* _ASM_PTRACE_H */ |
| @@ -50,7 +50,7 @@ static inline void mn10300_proc_hard_reset(void) · 49 unmodified lines | ||
| 50 | 50 | RSTCTR |= RSTCTR_CHIPRST; |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | −extern unsigned int watchdog_alert_counter; | |
| 53 | +extern unsigned int watchdog_alert_counter[]; | |
| 54 | 54 | |
| 55 | 55 | extern void watchdog_go(void); |
| 56 | 56 | extern asmlinkage void watchdog_handler(void); |
| @@ -15,25 +15,14 @@ · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | #include <linux/init.h> |
| 17 | 17 | |
| 18 | −extern void check_rtc_time(void); | |
| 19 | 18 | extern void __init calibrate_clock(void); |
| 20 | −extern unsigned long __init get_initial_rtc_time(void); | |
| 21 | 19 | |
| 22 | 20 | #else /* !CONFIG_MN10300_RTC */ |
| 23 | 21 | |
| 24 | −static inline void check_rtc_time(void) | |
| 25 | −{ | |
| 26 | −} | |
| 27 | − | |
| 28 | 22 | static inline void calibrate_clock(void) |
| 29 | 23 | { |
| 30 | 24 | } |
| 31 | 25 | |
| 32 | −static inline unsigned long get_initial_rtc_time(void) | |
| 33 | −{ | |
| 34 | − return 0; | |
| 35 | −} | |
| 36 | − | |
| 37 | 26 | #endif /* !CONFIG_MN10300_RTC */ |
| 38 | 27 | |
| 39 | 28 | #include <asm-generic/rtc.h> |
| @@ -0,0 +1,125 @@ | ||
| 1 | +/* | |
| 2 | + * Helpers used by both rw spinlocks and rw semaphores. | |
| 3 | + * | |
| 4 | + * Based in part on code from semaphore.h and | |
| 5 | + * spinlock.h Copyright 1996 Linus Torvalds. | |
| 6 | + * | |
| 7 | + * Copyright 1999 Red Hat, Inc. | |
| 8 | + * | |
| 9 | + * Written by Benjamin LaHaise. | |
| 10 | + * | |
| 11 | + * Modified by Matsushita Electric Industrial Co., Ltd. | |
| 12 | + * Modifications: | |
| 13 | + * 13-Nov-2006 MEI Temporarily delete lock functions for SMP support. | |
| 14 | + * | |
| 15 | + * This program is free software; you can redistribute it and/or modify it | |
| 16 | + * under the terms of the GNU General Public License as published by the Free | |
| 17 | + * Software Foundation; either version 2 of the License, or (at your option) | |
| 18 | + * any later version. | |
| 19 | + */ | |
| 20 | +#ifndef _ASM_RWLOCK_H | |
| 21 | +#define _ASM_RWLOCK_H | |
| 22 | + | |
| 23 | +#define RW_LOCK_BIAS 0x01000000 | |
| 24 | + | |
| 25 | +#ifndef CONFIG_SMP | |
| 26 | + | |
| 27 | +typedef struct { unsigned long a[100]; } __dummy_lock_t; | |
| 28 | +#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock)) | |
| 29 | + | |
| 30 | +#define RW_LOCK_BIAS_STR "0x01000000" | |
| 31 | + | |
| 32 | +#define __build_read_lock_ptr(rw, helper) \ | |
| 33 | + do { \ | |
| 34 | + asm volatile( \ | |
| 35 | + " mov (%0),d3 \n" \ | |
| 36 | + " sub 1,d3 \n" \ | |
| 37 | + " mov d3,(%0) \n" \ | |
| 38 | + " blt 1f \n" \ | |
| 39 | + " bra 2f \n" \ | |
| 40 | + "1: jmp 3f \n" \ | |
| 41 | + "2: \n" \ | |
| 42 | + " .section .text.lock,\"ax\" \n" \ | |
| 43 | + "3: call "helper"[],0 \n" \ | |
| 44 | + " jmp 2b \n" \ | |
| 45 | + " .previous" \ | |
| 46 | + : \ | |
| 47 | + : "d" (rw) \ | |
| 48 | + : "memory", "d3", "cc"); \ | |
| 49 | + } while (0) | |
| 50 | + | |
| 51 | +#define __build_read_lock_const(rw, helper) \ | |
| 52 | + do { \ | |
| 53 | + asm volatile( \ | |
| 54 | + " mov (%0),d3 \n" \ | |
| 55 | + " sub 1,d3 \n" \ | |
| 56 | + " mov d3,(%0) \n" \ | |
| 57 | + " blt 1f \n" \ | |
| 58 | + " bra 2f \n" \ | |
| 59 | + "1: jmp 3f \n" \ | |
| 60 | + "2: \n" \ | |
| 61 | + " .section .text.lock,\"ax\" \n" \ | |
| 62 | + "3: call "helper"[],0 \n" \ | |
| 63 | + " jmp 2b \n" \ | |
| 64 | + " .previous" \ | |
| 65 | + : \ | |
| 66 | + : "d" (rw) \ | |
| 67 | + : "memory", "d3", "cc"); \ | |
| 68 | + } while (0) | |
| 69 | + | |
| 70 | +#define __build_read_lock(rw, helper) \ | |
| 71 | + do { \ | |
| 72 | + if (__builtin_constant_p(rw)) \ | |
| 73 | + __build_read_lock_const(rw, helper); \ | |
| 74 | + else \ | |
| 75 | + __build_read_lock_ptr(rw, helper); \ | |
| 76 | + } while (0) | |
| 77 | + | |
| 78 | +#define __build_write_lock_ptr(rw, helper) \ | |
| 79 | + do { \ | |
| 80 | + asm volatile( \ | |
| 81 | + " mov (%0),d3 \n" \ | |
| 82 | + " sub 1,d3 \n" \ | |
| 83 | + " mov d3,(%0) \n" \ | |
| 84 | + " blt 1f \n" \ | |
| 85 | + " bra 2f \n" \ | |
| 86 | + "1: jmp 3f \n" \ | |
| 87 | + "2: \n" \ | |
| 88 | + " .section .text.lock,\"ax\" \n" \ | |
| 89 | + "3: call "helper"[],0 \n" \ | |
| 90 | + " jmp 2b \n" \ | |
| 91 | + " .previous" \ | |
| 92 | + : \ | |
| 93 | + : "d" (rw) \ | |
| 94 | + : "memory", "d3", "cc"); \ | |
| 95 | + } while (0) | |
| 96 | + | |
| 97 | +#define __build_write_lock_const(rw, helper) \ | |
| 98 | + do { \ | |
| 99 | + asm volatile( \ | |
| 100 | + " mov (%0),d3 \n" \ | |
| 101 | + " sub 1,d3 \n" \ | |
| 102 | + " mov d3,(%0) \n" \ | |
| 103 | + " blt 1f \n" \ | |
| 104 | + " bra 2f \n" \ | |
| 105 | + "1: jmp 3f \n" \ | |
| 106 | + "2: \n" \ | |
| 107 | + " .section .text.lock,\"ax\" \n" \ | |
| 108 | + "3: call "helper"[],0 \n" \ | |
| 109 | + " jmp 2b \n" \ | |
| 110 | + " .previous" \ | |
| 111 | + : \ | |
| 112 | + : "d" (rw) \ | |
| 113 | + : "memory", "d3", "cc"); \ | |
| 114 | + } while (0) | |
| 115 | + | |
| 116 | +#define __build_write_lock(rw, helper) \ | |
| 117 | + do { \ | |
| 118 | + if (__builtin_constant_p(rw)) \ | |
| 119 | + __build_write_lock_const(rw, helper); \ | |
| 120 | + else \ | |
| 121 | + __build_write_lock_ptr(rw, helper); \ | |
| 122 | + } while (0) | |
| 123 | + | |
| 124 | +#endif /* CONFIG_SMP */ | |
| 125 | +#endif /* _ASM_RWLOCK_H */ | |
| @@ -20,18 +20,25 @@ · 19 unmodified lines | ||
| 20 | 20 | /* serial port 0 */ |
| 21 | 21 | #define SC0CTR __SYSREG(0xd4002000, u16) /* control reg */ |
| 22 | 22 | #define SC01CTR_CK 0x0007 /* clock source select */ |
| 23 | −#define SC0CTR_CK_TM8UFLOW_8 0x0000 /* - 1/8 timer 8 underflow (serial port 0 only) */ | |
| 24 | −#define SC1CTR_CK_TM9UFLOW_8 0x0000 /* - 1/8 timer 9 underflow (serial port 1 only) */ | |
| 25 | 23 | #define SC01CTR_CK_IOCLK_8 0x0001 /* - 1/8 IOCLK */ |
| 26 | 24 | #define SC01CTR_CK_IOCLK_32 0x0002 /* - 1/32 IOCLK */ |
| 25 | +#define SC01CTR_CK_EXTERN_8 0x0006 /* - 1/8 external closk */ | |
| 26 | +#define SC01CTR_CK_EXTERN 0x0007 /* - external closk */ | |
| 27 | +#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3) | |
| 28 | +#define SC0CTR_CK_TM8UFLOW_8 0x0000 /* - 1/8 timer 8 underflow (serial port 0 only) */ | |
| 27 | 29 | #define SC0CTR_CK_TM2UFLOW_2 0x0003 /* - 1/2 timer 2 underflow (serial port 0 only) */ |
| 28 | −#define SC1CTR_CK_TM3UFLOW_2 0x0003 /* - 1/2 timer 3 underflow (serial port 1 only) */ | |
| 29 | −#define SC0CTR_CK_TM0UFLOW_8 0x0004 /* - 1/8 timer 1 underflow (serial port 0 only) */ | |
| 30 | −#define SC1CTR_CK_TM1UFLOW_8 0x0004 /* - 1/8 timer 2 underflow (serial port 1 only) */ | |
| 30 | +#define SC0CTR_CK_TM0UFLOW_8 0x0004 /* - 1/8 timer 0 underflow (serial port 0 only) */ | |
| 31 | 31 | #define SC0CTR_CK_TM2UFLOW_8 0x0005 /* - 1/8 timer 2 underflow (serial port 0 only) */ |
| 32 | +#define SC1CTR_CK_TM9UFLOW_8 0x0000 /* - 1/8 timer 9 underflow (serial port 1 only) */ | |
| 33 | +#define SC1CTR_CK_TM3UFLOW_2 0x0003 /* - 1/2 timer 3 underflow (serial port 1 only) */ | |
| 34 | +#define SC1CTR_CK_TM1UFLOW_8 0x0004 /* - 1/8 timer 1 underflow (serial port 1 only) */ | |
| 32 | 35 | #define SC1CTR_CK_TM3UFLOW_8 0x0005 /* - 1/8 timer 3 underflow (serial port 1 only) */ |
| 33 | −#define SC01CTR_CK_EXTERN_8 0x0006 /* - 1/8 external closk */ | |
| 34 | −#define SC01CTR_CK_EXTERN 0x0007 /* - external closk */ | |
| 36 | +#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | |
| 37 | +#define SC0CTR_CK_TM8UFLOW_8 0x0000 /* - 1/8 timer 8 underflow (serial port 0 only) */ | |
| 38 | +#define SC0CTR_CK_TM0UFLOW_8 0x0004 /* - 1/8 timer 0 underflow (serial port 0 only) */ | |
| 39 | +#define SC0CTR_CK_TM2UFLOW_8 0x0005 /* - 1/8 timer 2 underflow (serial port 0 only) */ | |
| 40 | +#define SC1CTR_CK_TM12UFLOW_8 0x0000 /* - 1/8 timer 12 underflow (serial port 1 only) */ | |
| 41 | +#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | |
| 35 | 42 | #define SC01CTR_STB 0x0008 /* stop bit select */ |
| 36 | 43 | #define SC01CTR_STB_1BIT 0x0000 /* - 1 stop bit */ |
| 37 | 44 | #define SC01CTR_STB_2BIT 0x0008 /* - 2 stop bits */ |
| @@ -100,11 +107,23 @@ · 62 unmodified lines | ||
| 100 | 107 | |
| 101 | 108 | /* serial port 2 */ |
| 102 | 109 | #define SC2CTR __SYSREG(0xd4002020, u16) /* control reg */ |
| 110 | +#ifdef CONFIG_AM33_2 | |
| 103 | 111 | #define SC2CTR_CK 0x0003 /* clock source select */ |
| 104 | 112 | #define SC2CTR_CK_TM10UFLOW 0x0000 /* - timer 10 underflow */ |
| 105 | 113 | #define SC2CTR_CK_TM2UFLOW 0x0001 /* - timer 2 underflow */ |
| 106 | 114 | #define SC2CTR_CK_EXTERN 0x0002 /* - external closk */ |
| 107 | 115 | #define SC2CTR_CK_TM3UFLOW 0x0003 /* - timer 3 underflow */ |
| 116 | +#else /* CONFIG_AM33_2 */ | |
| 117 | +#define SC2CTR_CK 0x0007 /* clock source select */ | |
| 118 | +#define SC2CTR_CK_TM9UFLOW_8 0x0000 /* - 1/8 timer 9 underflow */ | |
| 119 | +#define SC2CTR_CK_IOCLK_8 0x0001 /* - 1/8 IOCLK */ | |
| 120 | +#define SC2CTR_CK_IOCLK_32 0x0002 /* - 1/32 IOCLK */ | |
| 121 | +#define SC2CTR_CK_TM3UFLOW_2 0x0003 /* - 1/2 timer 3 underflow */ | |
| 122 | +#define SC2CTR_CK_TM1UFLOW_8 0x0004 /* - 1/8 timer 1 underflow */ | |
| 123 | +#define SC2CTR_CK_TM3UFLOW_8 0x0005 /* - 1/8 timer 3 underflow */ | |
| 124 | +#define SC2CTR_CK_EXTERN_8 0x0006 /* - 1/8 external closk */ | |
| 125 | +#define SC2CTR_CK_EXTERN 0x0007 /* - external closk */ | |
| 126 | +#endif /* CONFIG_AM33_2 */ | |
| 108 | 127 | #define SC2CTR_STB 0x0008 /* stop bit select */ |
| 109 | 128 | #define SC2CTR_STB_1BIT 0x0000 /* - 1 stop bit */ |
| 110 | 129 | #define SC2CTR_STB_2BIT 0x0008 /* - 2 stop bits */ |
| @@ -134,9 +153,14 @@ · 23 unmodified lines | ||
| 134 | 153 | #define SC2ICR_RES 0x04 /* receive error select */ |
| 135 | 154 | #define SC2ICR_RI 0x01 /* receive interrupt cause */ |
| 136 | 155 | |
| 137 | −#define SC2TXB __SYSREG(0xd4002018, u8) /* transmit buffer reg */ | |
| 138 | −#define SC2RXB __SYSREG(0xd4002019, u8) /* receive buffer reg */ | |
| 139 | −#define SC2STR __SYSREG(0xd400201c, u8) /* status reg */ | |
| 156 | +#define SC2TXB __SYSREG(0xd4002028, u8) /* transmit buffer reg */ | |
| 157 | +#define SC2RXB __SYSREG(0xd4002029, u8) /* receive buffer reg */ | |
| 158 | + | |
| 159 | +#ifdef CONFIG_AM33_2 | |
| 160 | +#define SC2STR __SYSREG(0xd400202c, u8) /* status reg */ | |
| 161 | +#else /* CONFIG_AM33_2 */ | |
| 162 | +#define SC2STR __SYSREG(0xd400202c, u16) /* status reg */ | |
| 163 | +#endif /* CONFIG_AM33_2 */ | |
| 140 | 164 | #define SC2STR_OEF 0x0001 /* overrun error found */ |
| 141 | 165 | #define SC2STR_PEF 0x0002 /* parity error found */ |
| 142 | 166 | #define SC2STR_FEF 0x0004 /* framing error found */ |
| @@ -146,10 +170,17 @@ · 3 unmodified lines | ||
| 146 | 170 | #define SC2STR_RXF 0x0040 /* receive status */ |
| 147 | 171 | #define SC2STR_TXF 0x0080 /* transmit status */ |
| 148 | 172 | |
| 173 | +#ifdef CONFIG_AM33_2 | |
| 149 | 174 | #define SC2TIM __SYSREG(0xd400202d, u8) /* status reg */ |
| 175 | +#endif | |
| 150 | 176 | |
| 177 | +#ifdef CONFIG_AM33_2 | |
| 151 | 178 | #define SC2RXIRQ 24 /* serial 2 Receive IRQ */ |
| 152 | 179 | #define SC2TXIRQ 25 /* serial 2 Transmit IRQ */ |
| 180 | +#else /* CONFIG_AM33_2 */ | |
| 181 | +#define SC2RXIRQ 68 /* serial 2 Receive IRQ */ | |
| 182 | +#define SC2TXIRQ 69 /* serial 2 Transmit IRQ */ | |
| 183 | +#endif /* CONFIG_AM33_2 */ | |
| 153 | 184 | |
| 154 | 185 | #define SC2RXICR GxICR(SC2RXIRQ) /* serial 2 receive intr ctrl reg */ |
| 155 | 186 | #define SC2TXICR GxICR(SC2TXIRQ) /* serial 2 transmit intr ctrl reg */ |
| @@ -9,10 +9,8 @@ · 8 unmodified lines | ||
| 9 | 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | −/* | |
| 13 | − * The ASB2305 has an 18.432 MHz clock the UART | |
| 14 | − */ | |
| 15 | −#define BASE_BAUD (18432000 / 16) | |
| 12 | +#ifndef _ASM_SERIAL_H | |
| 13 | +#define _ASM_SERIAL_H | |
| 16 | 14 | |
| 17 | 15 | /* Standard COM flags (except for COM4, because of the 8514 problem) */ |
| 18 | 16 | #ifdef CONFIG_SERIAL_DETECT_IRQ |
| @@ -34,3 +32,5 @@ · 15 unmodified lines | ||
| 34 | 32 | #endif |
| 35 | 33 | |
| 36 | 34 | #include <unit/serial.h> |
| 35 | + | |
| 36 | +#endif /* _ASM_SERIAL_H */ | |
| @@ -3,6 +3,16 @@ · 2 unmodified lines | ||
| 3 | 3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. |
| 4 | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | 5 | * |
| 6 | + * Modified by Matsushita Electric Industrial Co., Ltd. | |
| 7 | + * Modifications: | |
| 8 | + * 13-Nov-2006 MEI Define IPI-IRQ number and add inline/macro function | |
| 9 | + * for SMP support. | |
| 10 | + * 22-Jan-2007 MEI Add the define related to SMP_BOOT_IRQ. | |
| 11 | + * 23-Feb-2007 MEI Add the define related to SMP icahce invalidate. | |
| 12 | + * 23-Jun-2008 MEI Delete INTC_IPI. | |
| 13 | + * 22-Jul-2008 MEI Add smp_nmi_call_function and related defines. | |
| 14 | + * 04-Aug-2008 MEI Delete USE_DOIRQ_CACHE_IPI. | |
| 15 | + * | |
| 6 | 16 | * This program is free software; you can redistribute it and/or |
| 7 | 17 | * modify it under the terms of the GNU General Public Licence |
| 8 | 18 | * as published by the Free Software Foundation; either version |
| @@ -11,8 +21,85 @@ · 2 unmodified lines | ||
| 11 | 21 | #ifndef _ASM_SMP_H |
| 12 | 22 | #define _ASM_SMP_H |
| 13 | 23 | |
| 14 | −#ifdef CONFIG_SMP | |
| 15 | −#error SMP not yet supported for MN10300 | |
| 24 | +#ifndef __ASSEMBLY__ | |
| 25 | +#include <linux/threads.h> | |
| 26 | +#include <linux/cpumask.h> | |
| 16 | 27 | #endif |
| 17 | 28 | |
| 29 | +#ifdef CONFIG_SMP | |
| 30 | +#include <proc/smp-regs.h> | |
| 31 | + | |
| 32 | +#define RESCHEDULE_IPI 63 | |
| 33 | +#define CALL_FUNC_SINGLE_IPI 192 | |
| 34 | +#define LOCAL_TIMER_IPI 193 | |
| 35 | +#define FLUSH_CACHE_IPI 194 | |
| 36 | +#define CALL_FUNCTION_NMI_IPI 195 | |
| 37 | +#define GDB_NMI_IPI 196 | |
| 38 | + | |
| 39 | +#define SMP_BOOT_IRQ 195 | |
| 40 | + | |
| 41 | +#define RESCHEDULE_GxICR_LV GxICR_LEVEL_6 | |
| 42 | +#define CALL_FUNCTION_GxICR_LV GxICR_LEVEL_4 | |
| 43 | +#define LOCAL_TIMER_GxICR_LV GxICR_LEVEL_4 | |
| 44 | +#define FLUSH_CACHE_GxICR_LV GxICR_LEVEL_0 | |
| 45 | +#define SMP_BOOT_GxICR_LV GxICR_LEVEL_0 | |
| 46 | + | |
| 47 | +#define TIME_OUT_COUNT_BOOT_IPI 100 | |
| 48 | +#define DELAY_TIME_BOOT_IPI 75000 | |
| 49 | + | |
| 50 | + | |
| 51 | +#ifndef __ASSEMBLY__ | |
| 52 | + | |
| 53 | +/** | |
| 54 | + * raw_smp_processor_id - Determine the raw CPU ID of the CPU running it | |
| 55 | + * | |
| 56 | + * What we really want to do is to use the CPUID hardware CPU register to get | |
| 57 | + * this information, but accesses to that aren't cached, and run at system bus | |
| 58 | + * speed, not CPU speed. A copy of this value is, however, stored in the | |
| 59 | + * thread_info struct, and that can be cached. | |
| 60 | + * | |
| 61 | + * An alternate way of dealing with this could be to use the EPSW.S bits to | |
| 62 | + * cache this information for systems with up to four CPUs. | |
| 63 | + */ | |
| 64 | +#if 0 | |
| 65 | +#define raw_smp_processor_id() (CPUID) | |
| 66 | +#else | |
| 67 | +#define raw_smp_processor_id() (current_thread_info()->cpu) | |
| 18 | 68 | #endif |
| 69 | + | |
| 70 | +static inline int cpu_logical_map(int cpu) | |
| 71 | +{ | |
| 72 | + return cpu; | |
| 73 | +} | |
| 74 | + | |
| 75 | +static inline int cpu_number_map(int cpu) | |
| 76 | +{ | |
| 77 | + return cpu; | |
| 78 | +} | |
| 79 | + | |
| 80 | + | |
| 81 | +extern cpumask_t cpu_boot_map; | |
| 82 | + | |
| 83 | +extern void smp_init_cpus(void); | |
| 84 | +extern void smp_cache_interrupt(void); | |
| 85 | +extern void send_IPI_allbutself(int irq); | |
| 86 | +extern int smp_nmi_call_function(smp_call_func_t func, void *info, int wait); | |
| 87 | + | |
| 88 | +extern void arch_send_call_function_single_ipi(int cpu); | |
| 89 | +extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); | |
| 90 | + | |
| 91 | +#ifdef CONFIG_HOTPLUG_CPU | |
| 92 | +extern int __cpu_disable(void); | |
| 93 | +extern void __cpu_die(unsigned int cpu); | |
| 94 | +#endif /* CONFIG_HOTPLUG_CPU */ | |
| 95 | + | |
| 96 | +#endif /* __ASSEMBLY__ */ | |
| 97 | +#else /* CONFIG_SMP */ | |
| 98 | +#ifndef __ASSEMBLY__ | |
| 99 | + | |
| 100 | +static inline void smp_init_cpus(void) {} | |
| 101 | + | |
| 102 | +#endif /* __ASSEMBLY__ */ | |
| 103 | +#endif /* CONFIG_SMP */ | |
| 104 | + | |
| 105 | +#endif /* _ASM_SMP_H */ | |
| @@ -0,0 +1 @@ | ||
| 1 | +#include <unit/smsc911x.h> | |
| @@ -11,6 +11,183 @@ · 10 unmodified lines | ||
| 11 | 11 | #ifndef _ASM_SPINLOCK_H |
| 12 | 12 | #define _ASM_SPINLOCK_H |
| 13 | 13 | |
| 14 | −#error SMP spinlocks not implemented for MN10300 | |
| 14 | +#include <asm/atomic.h> | |
| 15 | +#include <asm/rwlock.h> | |
| 16 | +#include <asm/page.h> | |
| 15 | 17 | |
| 18 | +/* | |
| 19 | + * Simple spin lock operations. There are two variants, one clears IRQ's | |
| 20 | + * on the local processor, one does not. | |
| 21 | + * | |
| 22 | + * We make no fairness assumptions. They have a cost. | |
| 23 | + */ | |
| 24 | + | |
| 25 | +#define arch_spin_is_locked(x) (*(volatile signed char *)(&(x)->slock) != 0) | |
| 26 | +#define arch_spin_unlock_wait(x) do { barrier(); } while (arch_spin_is_locked(x)) | |
| 27 | + | |
| 28 | +static inline void arch_spin_unlock(arch_spinlock_t *lock) | |
| 29 | +{ | |
| 30 | + asm volatile( | |
| 31 | + " bclr 1,(0,%0) \n" | |
| 32 | + : | |
| 33 | + : "a"(&lock->slock) | |
| 34 | + : "memory", "cc"); | |
| 35 | +} | |
| 36 | + | |
| 37 | +static inline int arch_spin_trylock(arch_spinlock_t *lock) | |
| 38 | +{ | |
| 39 | + int ret; | |
| 40 | + | |
| 41 | + asm volatile( | |
| 42 | + " mov 1,%0 \n" | |
| 43 | + " bset %0,(%1) \n" | |
| 44 | + " bne 1f \n" | |
| 45 | + " clr %0 \n" | |
| 46 | + "1: xor 1,%0 \n" | |
| 47 | + : "=d"(ret) | |
| 48 | + : "a"(&lock->slock) | |
| 49 | + : "memory", "cc"); | |
| 50 | + | |
| 51 | + return ret; | |
| 52 | +} | |
| 53 | + | |
| 54 | +static inline void arch_spin_lock(arch_spinlock_t *lock) | |
| 55 | +{ | |
| 56 | + asm volatile( | |
| 57 | + "1: bset 1,(0,%0) \n" | |
| 58 | + " bne 1b \n" | |
| 59 | + : | |
| 60 | + : "a"(&lock->slock) | |
| 61 | + : "memory", "cc"); | |
| 62 | +} | |
| 63 | + | |
| 64 | +static inline void arch_spin_lock_flags(arch_spinlock_t *lock, | |
| 65 | + unsigned long flags) | |
| 66 | +{ | |
| 67 | + int temp; | |
| 68 | + | |
| 69 | + asm volatile( | |
| 70 | + "1: bset 1,(0,%2) \n" | |
| 71 | + " beq 3f \n" | |
| 72 | + " mov %1,epsw \n" | |
| 73 | + "2: mov (0,%2),%0 \n" | |
| 74 | + " or %0,%0 \n" | |
| 75 | + " bne 2b \n" | |
| 76 | + " mov %3,%0 \n" | |
| 77 | + " mov %0,epsw \n" | |
| 78 | + " nop \n" | |
| 79 | + " nop \n" | |
| 80 | + " bra 1b\n" | |
| 81 | + "3: \n" | |
| 82 | + : "=&d" (temp) | |
| 83 | + : "d" (flags), "a"(&lock->slock), "i"(EPSW_IE | MN10300_CLI_LEVEL) | |
| 84 | + : "memory", "cc"); | |
| 85 | +} | |
| 86 | + | |
| 87 | +#ifdef __KERNEL__ | |
| 88 | + | |
| 89 | +/* | |
| 90 | + * Read-write spinlocks, allowing multiple readers | |
| 91 | + * but only one writer. | |
| 92 | + * | |
| 93 | + * NOTE! it is quite common to have readers in interrupts | |
| 94 | + * but no interrupt writers. For those circumstances we | |
| 95 | + * can "mix" irq-safe locks - any writer needs to get a | |
| 96 | + * irq-safe write-lock, but readers can get non-irqsafe | |
| 97 | + * read-locks. | |
| 98 | + */ | |
| 99 | + | |
| 100 | +/** | |
| 101 | + * read_can_lock - would read_trylock() succeed? | |
| 102 | + * @lock: the rwlock in question. | |
| 103 | + */ | |
| 104 | +#define arch_read_can_lock(x) ((int)(x)->lock > 0) | |
| 105 | + | |
| 106 | +/** | |
| 107 | + * write_can_lock - would write_trylock() succeed? | |
| 108 | + * @lock: the rwlock in question. | |
| 109 | + */ | |
| 110 | +#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) | |
| 111 | + | |
| 112 | +/* | |
| 113 | + * On mn10300, we implement read-write locks as a 32-bit counter | |
| 114 | + * with the high bit (sign) being the "contended" bit. | |
| 115 | + */ | |
| 116 | +static inline void arch_read_lock(arch_rwlock_t *rw) | |
| 117 | +{ | |
| 118 | +#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT | |
| 119 | + __build_read_lock(rw, "__read_lock_failed"); | |
| 120 | +#else | |
| 121 | + { | |
| 122 | + atomic_t *count = (atomic_t *)rw; | |
| 123 | + while (atomic_dec_return(count) < 0) | |
| 124 | + atomic_inc(count); | |
| 125 | + } | |
| 126 | +#endif | |
| 127 | +} | |
| 128 | + | |
| 129 | +static inline void arch_write_lock(arch_rwlock_t *rw) | |
| 130 | +{ | |
| 131 | +#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT | |
| 132 | + __build_write_lock(rw, "__write_lock_failed"); | |
| 133 | +#else | |
| 134 | + { | |
| 135 | + atomic_t *count = (atomic_t *)rw; | |
| 136 | + while (!atomic_sub_and_test(RW_LOCK_BIAS, count)) | |
| 137 | + atomic_add(RW_LOCK_BIAS, count); | |
| 138 | + } | |
| 139 | +#endif | |
| 140 | +} | |
| 141 | + | |
| 142 | +static inline void arch_read_unlock(arch_rwlock_t *rw) | |
| 143 | +{ | |
| 144 | +#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT | |
| 145 | + __build_read_unlock(rw); | |
| 146 | +#else | |
| 147 | + { | |
| 148 | + atomic_t *count = (atomic_t *)rw; | |
| 149 | + atomic_inc(count); | |
| 150 | + } | |
| 151 | +#endif | |
| 152 | +} | |
| 153 | + | |
| 154 | +static inline void arch_write_unlock(arch_rwlock_t *rw) | |
| 155 | +{ | |
| 156 | +#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT | |
| 157 | + __build_write_unlock(rw); | |
| 158 | +#else | |
| 159 | + { | |
| 160 | + atomic_t *count = (atomic_t *)rw; | |
| 161 | + atomic_add(RW_LOCK_BIAS, count); | |
| 162 | + } | |
| 163 | +#endif | |
| 164 | +} | |
| 165 | + | |
| 166 | +static inline int arch_read_trylock(arch_rwlock_t *lock) | |
| 167 | +{ | |
| 168 | + atomic_t *count = (atomic_t *)lock; | |
| 169 | + atomic_dec(count); | |
| 170 | + if (atomic_read(count) >= 0) | |
| 171 | + return 1; | |
| 172 | + atomic_inc(count); | |
| 173 | + return 0; | |
| 174 | +} | |
| 175 | + | |
| 176 | +static inline int arch_write_trylock(arch_rwlock_t *lock) | |
| 177 | +{ | |
| 178 | + atomic_t *count = (atomic_t *)lock; | |
| 179 | + if (atomic_sub_and_test(RW_LOCK_BIAS, count)) | |
| 180 | + return 1; | |
| 181 | + atomic_add(RW_LOCK_BIAS, count); | |
| 182 | + return 0; | |
| 183 | +} | |
| 184 | + | |
| 185 | +#define arch_read_lock_flags(lock, flags) arch_read_lock(lock) | |
| 186 | +#define arch_write_lock_flags(lock, flags) arch_write_lock(lock) | |
| 187 | + | |
| 188 | +#define _raw_spin_relax(lock) cpu_relax() | |
| 189 | +#define _raw_read_relax(lock) cpu_relax() | |
| 190 | +#define _raw_write_relax(lock) cpu_relax() | |
| 191 | + | |
| 192 | +#endif /* __KERNEL__ */ | |
| 16 | 193 | #endif /* _ASM_SPINLOCK_H */ |
| @@ -0,0 +1,20 @@ | ||
| 1 | +#ifndef _ASM_SPINLOCK_TYPES_H | |
| 2 | +#define _ASM_SPINLOCK_TYPES_H | |
| 3 | + | |
| 4 | +#ifndef __LINUX_SPINLOCK_TYPES_H | |
| 5 | +# error "please don't include this file directly" | |
| 6 | +#endif | |
| 7 | + | |
| 8 | +typedef struct arch_spinlock { | |
| 9 | + unsigned int slock; | |
| 10 | +} arch_spinlock_t; | |
| 11 | + | |
| 12 | +#define __ARCH_SPIN_LOCK_UNLOCKED { 0 } | |
| 13 | + | |
| 14 | +typedef struct { | |
| 15 | + unsigned int lock; | |
| 16 | +} arch_rwlock_t; | |
| 17 | + | |
| 18 | +#define __ARCH_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } | |
| 19 | + | |
| 20 | +#endif /* _ASM_SPINLOCK_TYPES_H */ | |
| @@ -12,12 +12,29 @@ · 11 unmodified lines | ||
| 12 | 12 | #define _ASM_SYSTEM_H |
| 13 | 13 | |
| 14 | 14 | #include <asm/cpu-regs.h> |
| 15 | +#include <asm/intctl-regs.h> | |
| 15 | 16 | |
| 16 | 17 | #ifdef __KERNEL__ |
| 17 | 18 | #ifndef __ASSEMBLY__ |
| 18 | 19 | |
| 19 | 20 | #include <linux/kernel.h> |
| 20 | 21 | #include <linux/irqflags.h> |
| 22 | +#include <asm/atomic.h> | |
| 23 | + | |
| 24 | +#if !defined(CONFIG_LAZY_SAVE_FPU) | |
| 25 | +struct fpu_state_struct; | |
| 26 | +extern asmlinkage void fpu_save(struct fpu_state_struct *); | |
| 27 | +#define switch_fpu(prev, next) \ | |
| 28 | + do { \ | |
| 29 | + if ((prev)->thread.fpu_flags & THREAD_HAS_FPU) { \ | |
| 30 | + (prev)->thread.fpu_flags &= ~THREAD_HAS_FPU; \ | |
| 31 | + (prev)->thread.uregs->epsw &= ~EPSW_FE; \ | |
| 32 | + fpu_save(&(prev)->thread.fpu_state); \ | |
| 33 | + } \ | |
| 34 | + } while (0) | |
| 35 | +#else | |
| 36 | +#define switch_fpu(prev, next) do {} while (0) | |
| 37 | +#endif | |
| 21 | 38 | |
| 22 | 39 | struct task_struct; |
| 23 | 40 | struct thread_struct; |
| @@ -30,6 +47,7 @@ struct task_struct *__switch_to(struct thread_struct *prev, · 6 unmodified lines | ||
| 30 | 47 | /* context switching is now performed out-of-line in switch_to.S */ |
| 31 | 48 | #define switch_to(prev, next, last) \ |
| 32 | 49 | do { \ |
| 50 | + switch_fpu(prev, next); \ | |
| 33 | 51 | current->thread.wchan = (u_long) __builtin_return_address(0); \ |
| 34 | 52 | (last) = __switch_to(&(prev)->thread, &(next)->thread, (prev)); \ |
| 35 | 53 | mb(); \ |
| @@ -40,8 +58,6 @@ do { \ · 4 unmodified lines | ||
| 40 | 58 | |
| 41 | 59 | #define nop() asm volatile ("nop") |
| 42 | 60 | |
| 43 | −#endif /* !__ASSEMBLY__ */ | |
| 44 | − | |
| 45 | 61 | /* |
| 46 | 62 | * Force strict CPU ordering. |
| 47 | 63 | * And yes, this is required on UP too when we're talking |
| @@ -68,64 +84,19 @@ do { \ · 20 unmodified lines | ||
| 68 | 84 | #define smp_mb() mb() |
| 69 | 85 | #define smp_rmb() rmb() |
| 70 | 86 | #define smp_wmb() wmb() |
| 71 | −#else | |
| 87 | +#define set_mb(var, value) do { xchg(&var, value); } while (0) | |
| 88 | +#else /* CONFIG_SMP */ | |
| 72 | 89 | #define smp_mb() barrier() |
| 73 | 90 | #define smp_rmb() barrier() |
| 74 | 91 | #define smp_wmb() barrier() |
| 75 | −#endif | |
| 76 | − | |
| 77 | 92 | #define set_mb(var, value) do { var = value; mb(); } while (0) |
| 93 | +#endif /* CONFIG_SMP */ | |
| 94 | + | |
| 78 | 95 | #define set_wmb(var, value) do { var = value; wmb(); } while (0) |
| 79 | 96 | |
| 80 | 97 | #define read_barrier_depends() do {} while (0) |
| 81 | 98 | #define smp_read_barrier_depends() do {} while (0) |
| 82 | 99 | |
| 83 | −/*****************************************************************************/ | |
| 84 | −/* | |
| 85 | − * MN10300 doesn't actually have an exchange instruction | |
| 86 | − */ | |
| 87 | −#ifndef __ASSEMBLY__ | |
| 88 | − | |
| 89 | −struct __xchg_dummy { unsigned long a[100]; }; | |
| 90 | −#define __xg(x) ((struct __xchg_dummy *)(x)) | |
| 91 | − | |
| 92 | −static inline | |
| 93 | −unsigned long __xchg(volatile unsigned long *m, unsigned long val) | |
| 94 | −{ | |
| 95 | − unsigned long retval; | |
| 96 | − unsigned long flags; | |
| 97 | − | |
| 98 | − local_irq_save(flags); | |
| 99 | − retval = *m; | |
| 100 | − *m = val; | |
| 101 | − local_irq_restore(flags); | |
| 102 | − return retval; | |
| 103 | −} | |
| 104 | − | |
| 105 | −#define xchg(ptr, v) \ | |
| 106 | − ((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr), \ | |
| 107 | − (unsigned long)(v))) | |
| 108 | − | |
| 109 | −static inline unsigned long __cmpxchg(volatile unsigned long *m, | |
| 110 | − unsigned long old, unsigned long new) | |
| 111 | −{ | |
| 112 | − unsigned long retval; | |
| 113 | − unsigned long flags; | |
| 114 | − | |
| 115 | − local_irq_save(flags); | |
| 116 | − retval = *m; | |
| 117 | − if (retval == old) | |
| 118 | − *m = new; | |
| 119 | − local_irq_restore(flags); | |
| 120 | − return retval; | |
| 121 | −} | |
| 122 | − | |
| 123 | −#define cmpxchg(ptr, o, n) \ | |
| 124 | − ((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \ | |
| 125 | − (unsigned long)(o), \ | |
| 126 | − (unsigned long)(n))) | |
| 127 | − | |
| 128 | 100 | #endif /* !__ASSEMBLY__ */ |
| 129 | − | |
| 130 | 101 | #endif /* __KERNEL__ */ |
| 131 | 102 | #endif /* _ASM_SYSTEM_H */ |
| @@ -16,10 +16,6 @@ · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | #include <asm/page.h> |
| 18 | 18 | |
| 19 | −#ifndef __ASSEMBLY__ | |
| 20 | −#include <asm/processor.h> | |
| 21 | −#endif | |
| 22 | − | |
| 23 | 19 | #define PREEMPT_ACTIVE 0x10000000 |
| 24 | 20 | |
| 25 | 21 | #ifdef CONFIG_4KSTACKS |
| @@ -38,10 +34,14 @@ · 12 unmodified lines | ||
| 38 | 34 | * must also be changed |
| 39 | 35 | */ |
| 40 | 36 | #ifndef __ASSEMBLY__ |
| 37 | +typedef struct { | |
| 38 | + unsigned long seg; | |
| 39 | +} mm_segment_t; | |
| 41 | 40 | |
| 42 | 41 | struct thread_info { |
| 43 | 42 | struct task_struct *task; /* main task structure */ |
| 44 | 43 | struct exec_domain *exec_domain; /* execution domain */ |
| 44 | + struct pt_regs *frame; /* current exception frame */ | |
| 45 | 45 | unsigned long flags; /* low level flags */ |
| 46 | 46 | __u32 cpu; /* current CPU */ |
| 47 | 47 | __s32 preempt_count; /* 0 => preemptable, <0 => BUG */ |
| @@ -55,6 +55,10 @@ struct thread_info { · 7 unmodified lines | ||
| 55 | 55 | __u8 supervisor_stack[0]; |
| 56 | 56 | }; |
| 57 | 57 | |
| 58 | +#define thread_info_to_uregs(ti) \ | |
| 59 | + ((struct pt_regs *) \ | |
| 60 | + ((unsigned long)ti + THREAD_SIZE - sizeof(struct pt_regs))) | |
| 61 | + | |
| 58 | 62 | #else /* !__ASSEMBLY__ */ |
| 59 | 63 | |
| 60 | 64 | #ifndef __ASM_OFFSETS_H__ |
| @@ -102,6 +106,12 @@ struct thread_info *current_thread_info(void) · 41 unmodified lines | ||
| 102 | 106 | return ti; |
| 103 | 107 | } |
| 104 | 108 | |
| 109 | +static inline __attribute__((const)) | |
| 110 | +struct pt_regs *current_frame(void) | |
| 111 | +{ | |
| 112 | + return current_thread_info()->frame; | |
| 113 | +} | |
| 114 | + | |
| 105 | 115 | /* how to get the current stack pointer from C */ |
| 106 | 116 | static inline unsigned long current_stack_pointer(void) |
| 107 | 117 | { |
| @@ -17,21 +17,27 @@ · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | #ifdef __KERNEL__ |
| 19 | 19 | |
| 20 | −/* timer prescalar control */ | |
| 20 | +/* | |
| 21 | + * Timer prescalar control | |
| 22 | + */ | |
| 21 | 23 | #define TMPSCNT __SYSREG(0xd4003071, u8) /* timer prescaler control */ |
| 22 | 24 | #define TMPSCNT_ENABLE 0x80 /* timer prescaler enable */ |
| 23 | 25 | #define TMPSCNT_DISABLE 0x00 /* timer prescaler disable */ |
| 24 | 26 | |
| 25 | −/* 8 bit timers */ | |
| 27 | +/* | |
| 28 | + * 8-bit timers | |
| 29 | + */ | |
| 26 | 30 | #define TM0MD __SYSREG(0xd4003000, u8) /* timer 0 mode register */ |
| 27 | 31 | #define TM0MD_SRC 0x07 /* timer source */ |
| 28 | 32 | #define TM0MD_SRC_IOCLK 0x00 /* - IOCLK */ |
| 29 | 33 | #define TM0MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */ |
| 30 | 34 | #define TM0MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */ |
| 31 | −#define TM0MD_SRC_TM2IO 0x03 /* - TM2IO pin input */ | |
| 32 | 35 | #define TM0MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ |
| 33 | 36 | #define TM0MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ |
| 37 | +#if defined(CONFIG_AM33_2) | |
| 38 | +#define TM0MD_SRC_TM2IO 0x03 /* - TM2IO pin input */ | |
| 34 | 39 | #define TM0MD_SRC_TM0IO 0x07 /* - TM0IO pin input */ |
| 40 | +#endif /* CONFIG_AM33_2 */ | |
| 35 | 41 | #define TM0MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ |
| 36 | 42 | #define TM0MD_COUNT_ENABLE 0x80 /* timer count enable */ |
| 37 | 43 | |
| @@ -43,7 +49,9 @@ · 5 unmodified lines | ||
| 43 | 49 | #define TM1MD_SRC_TM0CASCADE 0x03 /* - cascade with timer 0 */ |
| 44 | 50 | #define TM1MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ |
| 45 | 51 | #define TM1MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ |
| 52 | +#if defined(CONFIG_AM33_2) | |
| 46 | 53 | #define TM1MD_SRC_TM1IO 0x07 /* - TM1IO pin input */ |
| 54 | +#endif /* CONFIG_AM33_2 */ | |
| 47 | 55 | #define TM1MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ |
| 48 | 56 | #define TM1MD_COUNT_ENABLE 0x80 /* timer count enable */ |
| 49 | 57 | |
| @@ -55,7 +63,9 @@ · 5 unmodified lines | ||
| 55 | 63 | #define TM2MD_SRC_TM1CASCADE 0x03 /* - cascade with timer 1 */ |
| 56 | 64 | #define TM2MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ |
| 57 | 65 | #define TM2MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ |
| 66 | +#if defined(CONFIG_AM33_2) | |
| 58 | 67 | #define TM2MD_SRC_TM2IO 0x07 /* - TM2IO pin input */ |
| 68 | +#endif /* CONFIG_AM33_2 */ | |
| 59 | 69 | #define TM2MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ |
| 60 | 70 | #define TM2MD_COUNT_ENABLE 0x80 /* timer count enable */ |
| 61 | 71 | |
| @@ -64,11 +74,13 @@ · 2 unmodified lines | ||
| 64 | 74 | #define TM3MD_SRC_IOCLK 0x00 /* - IOCLK */ |
| 65 | 75 | #define TM3MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */ |
| 66 | 76 | #define TM3MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */ |
| 67 | −#define TM3MD_SRC_TM1CASCADE 0x03 /* - cascade with timer 2 */ | |
| 77 | +#define TM3MD_SRC_TM2CASCADE 0x03 /* - cascade with timer 2 */ | |
| 68 | 78 | #define TM3MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ |
| 69 | 79 | #define TM3MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ |
| 70 | 80 | #define TM3MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ |
| 81 | +#if defined(CONFIG_AM33_2) | |
| 71 | 82 | #define TM3MD_SRC_TM3IO 0x07 /* - TM3IO pin input */ |
| 83 | +#endif /* CONFIG_AM33_2 */ | |
| 72 | 84 | #define TM3MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ |
| 73 | 85 | #define TM3MD_COUNT_ENABLE 0x80 /* timer count enable */ |
| 74 | 86 | |
| @@ -96,7 +108,9 @@ · 21 unmodified lines | ||
| 96 | 108 | #define TM2ICR GxICR(TM2IRQ) /* timer 2 uflow intr ctrl reg */ |
| 97 | 109 | #define TM3ICR GxICR(TM3IRQ) /* timer 3 uflow intr ctrl reg */ |
| 98 | 110 | |
| 99 | −/* 16-bit timers 4,5 & 7-11 */ | |
| 111 | +/* | |
| 112 | + * 16-bit timers 4,5 & 7-15 | |
| 113 | + */ | |
| 100 | 114 | #define TM4MD __SYSREG(0xd4003080, u8) /* timer 4 mode register */ |
| 101 | 115 | #define TM4MD_SRC 0x07 /* timer source */ |
| 102 | 116 | #define TM4MD_SRC_IOCLK 0x00 /* - IOCLK */ |
| @@ -105,7 +119,9 @@ · 2 unmodified lines | ||
| 105 | 119 | #define TM4MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ |
| 106 | 120 | #define TM4MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ |
| 107 | 121 | #define TM4MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ |
| 122 | +#if defined(CONFIG_AM33_2) | |
| 108 | 123 | #define TM4MD_SRC_TM4IO 0x07 /* - TM4IO pin input */ |
| 124 | +#endif /* CONFIG_AM33_2 */ | |
| 109 | 125 | #define TM4MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ |
| 110 | 126 | #define TM4MD_COUNT_ENABLE 0x80 /* timer count enable */ |
| 111 | 127 | |
| @@ -118,7 +134,11 @@ · 6 unmodified lines | ||
| 118 | 134 | #define TM5MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ |
| 119 | 135 | #define TM5MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ |
| 120 | 136 | #define TM5MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ |
| 137 | +#if defined(CONFIG_AM33_2) | |
| 121 | 138 | #define TM5MD_SRC_TM5IO 0x07 /* - TM5IO pin input */ |
| 139 | +#else /* !CONFIG_AM33_2 */ | |
| 140 | +#define TM5MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */ | |
| 141 | +#endif /* CONFIG_AM33_2 */ | |
| 122 | 142 | #define TM5MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ |
| 123 | 143 | #define TM5MD_COUNT_ENABLE 0x80 /* timer count enable */ |
| 124 | 144 | |
| @@ -130,7 +150,9 @@ · 5 unmodified lines | ||
| 130 | 150 | #define TM7MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ |
| 131 | 151 | #define TM7MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ |
| 132 | 152 | #define TM7MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ |
| 153 | +#if defined(CONFIG_AM33_2) | |
| 133 | 154 | #define TM7MD_SRC_TM7IO 0x07 /* - TM7IO pin input */ |
| 155 | +#endif /* CONFIG_AM33_2 */ | |
| 134 | 156 | #define TM7MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ |
| 135 | 157 | #define TM7MD_COUNT_ENABLE 0x80 /* timer count enable */ |
| 136 | 158 | |
| @@ -143,7 +165,11 @@ · 6 unmodified lines | ||
| 143 | 165 | #define TM8MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ |
| 144 | 166 | #define TM8MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ |
| 145 | 167 | #define TM8MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ |
| 168 | +#if defined(CONFIG_AM33_2) | |
| 146 | 169 | #define TM8MD_SRC_TM8IO 0x07 /* - TM8IO pin input */ |
| 170 | +#else /* !CONFIG_AM33_2 */ | |
| 171 | +#define TM8MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */ | |
| 172 | +#endif /* CONFIG_AM33_2 */ | |
| 147 | 173 | #define TM8MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ |
| 148 | 174 | #define TM8MD_COUNT_ENABLE 0x80 /* timer count enable */ |
| 149 | 175 | |
| @@ -156,7 +182,11 @@ · 6 unmodified lines | ||
| 156 | 182 | #define TM9MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ |
| 157 | 183 | #define TM9MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ |
| 158 | 184 | #define TM9MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ |
| 185 | +#if defined(CONFIG_AM33_2) | |
| 159 | 186 | #define TM9MD_SRC_TM9IO 0x07 /* - TM9IO pin input */ |
| 187 | +#else /* !CONFIG_AM33_2 */ | |
| 188 | +#define TM9MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */ | |
| 189 | +#endif /* CONFIG_AM33_2 */ | |
| 160 | 190 | #define TM9MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ |
| 161 | 191 | #define TM9MD_COUNT_ENABLE 0x80 /* timer count enable */ |
| 162 | 192 | |
| @@ -169,7 +199,11 @@ · 6 unmodified lines | ||
| 169 | 199 | #define TM10MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ |
| 170 | 200 | #define TM10MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ |
| 171 | 201 | #define TM10MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ |
| 202 | +#if defined(CONFIG_AM33_2) | |
| 172 | 203 | #define TM10MD_SRC_TM10IO 0x07 /* - TM10IO pin input */ |
| 204 | +#else /* !CONFIG_AM33_2 */ | |
| 205 | +#define TM10MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */ | |
| 206 | +#endif /* CONFIG_AM33_2 */ | |
| 173 | 207 | #define TM10MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ |
| 174 | 208 | #define TM10MD_COUNT_ENABLE 0x80 /* timer count enable */ |
| 175 | 209 | |
| @@ -178,32 +212,101 @@ · 2 unmodified lines | ||
| 178 | 212 | #define TM11MD_SRC_IOCLK 0x00 /* - IOCLK */ |
| 179 | 213 | #define TM11MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */ |
| 180 | 214 | #define TM11MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */ |
| 181 | −#define TM11MD_SRC_TM7CASCADE 0x03 /* - cascade with timer 7 */ | |
| 182 | 215 | #define TM11MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ |
| 183 | 216 | #define TM11MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ |
| 184 | 217 | #define TM11MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ |
| 218 | +#if defined(CONFIG_AM33_2) | |
| 185 | 219 | #define TM11MD_SRC_TM11IO 0x07 /* - TM11IO pin input */ |
| 220 | +#else /* !CONFIG_AM33_2 */ | |
| 221 | +#define TM11MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */ | |
| 222 | +#endif /* CONFIG_AM33_2 */ | |
| 186 | 223 | #define TM11MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ |
| 187 | 224 | #define TM11MD_COUNT_ENABLE 0x80 /* timer count enable */ |
| 188 | 225 | |
| 226 | +#if defined(CONFIG_AM34_2) | |
| 227 | +#define TM12MD __SYSREG(0xd4003180, u8) /* timer 11 mode register */ | |
| 228 | +#define TM12MD_SRC 0x07 /* timer source */ | |
| 229 | +#define TM12MD_SRC_IOCLK 0x00 /* - IOCLK */ | |
| 230 | +#define TM12MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */ | |
| 231 | +#define TM12MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */ | |
| 232 | +#define TM12MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ | |
| 233 | +#define TM12MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ | |
| 234 | +#define TM12MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ | |
| 235 | +#define TM12MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */ | |
| 236 | +#define TM12MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ | |
| 237 | +#define TM12MD_COUNT_ENABLE 0x80 /* timer count enable */ | |
| 238 | + | |
| 239 | +#define TM13MD __SYSREG(0xd4003182, u8) /* timer 11 mode register */ | |
| 240 | +#define TM13MD_SRC 0x07 /* timer source */ | |
| 241 | +#define TM13MD_SRC_IOCLK 0x00 /* - IOCLK */ | |
| 242 | +#define TM13MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */ | |
| 243 | +#define TM13MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */ | |
| 244 | +#define TM13MD_SRC_TM12CASCADE 0x03 /* - cascade with timer 12 */ | |
| 245 | +#define TM13MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ | |
| 246 | +#define TM13MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ | |
| 247 | +#define TM13MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ | |
| 248 | +#define TM13MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */ | |
| 249 | +#define TM13MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ | |
| 250 | +#define TM13MD_COUNT_ENABLE 0x80 /* timer count enable */ | |
| 251 | + | |
| 252 | +#define TM14MD __SYSREG(0xd4003184, u8) /* timer 11 mode register */ | |
| 253 | +#define TM14MD_SRC 0x07 /* timer source */ | |
| 254 | +#define TM14MD_SRC_IOCLK 0x00 /* - IOCLK */ | |
| 255 | +#define TM14MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */ | |
| 256 | +#define TM14MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */ | |
| 257 | +#define TM14MD_SRC_TM13CASCADE 0x03 /* - cascade with timer 13 */ | |
| 258 | +#define TM14MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ | |
| 259 | +#define TM14MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ | |
| 260 | +#define TM14MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ | |
| 261 | +#define TM14MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */ | |
| 262 | +#define TM14MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ | |
| 263 | +#define TM14MD_COUNT_ENABLE 0x80 /* timer count enable */ | |
| 264 | + | |
| 265 | +#define TM15MD __SYSREG(0xd4003186, u8) /* timer 11 mode register */ | |
| 266 | +#define TM15MD_SRC 0x07 /* timer source */ | |
| 267 | +#define TM15MD_SRC_IOCLK 0x00 /* - IOCLK */ | |
| 268 | +#define TM15MD_SRC_IOCLK_8 0x01 /* - 1/8 IOCLK */ | |
| 269 | +#define TM15MD_SRC_IOCLK_32 0x02 /* - 1/32 IOCLK */ | |
| 270 | +#define TM15MD_SRC_TM0UFLOW 0x04 /* - timer 0 underflow */ | |
| 271 | +#define TM15MD_SRC_TM1UFLOW 0x05 /* - timer 1 underflow */ | |
| 272 | +#define TM15MD_SRC_TM2UFLOW 0x06 /* - timer 2 underflow */ | |
| 273 | +#define TM15MD_SRC_TM7UFLOW 0x07 /* - timer 7 underflow */ | |
| 274 | +#define TM15MD_INIT_COUNTER 0x40 /* initialize TMnBC = TMnBR */ | |
| 275 | +#define TM15MD_COUNT_ENABLE 0x80 /* timer count enable */ | |
| 276 | +#endif /* CONFIG_AM34_2 */ | |
| 277 | + | |
| 278 | + | |
| 189 | 279 | #define TM4BR __SYSREG(0xd4003090, u16) /* timer 4 base register */ |
| 190 | 280 | #define TM5BR __SYSREG(0xd4003092, u16) /* timer 5 base register */ |
| 281 | +#define TM45BR __SYSREG(0xd4003090, u32) /* timer 4:5 base register */ | |
| 191 | 282 | #define TM7BR __SYSREG(0xd4003096, u16) /* timer 7 base register */ |
| 192 | 283 | #define TM8BR __SYSREG(0xd4003098, u16) /* timer 8 base register */ |
| 193 | 284 | #define TM9BR __SYSREG(0xd400309a, u16) /* timer 9 base register */ |
| 285 | +#define TM89BR __SYSREG(0xd4003098, u32) /* timer 8:9 base register */ | |
| 194 | 286 | #define TM10BR __SYSREG(0xd400309c, u16) /* timer 10 base register */ |
| 195 | 287 | #define TM11BR __SYSREG(0xd400309e, u16) /* timer 11 base register */ |
| 196 | −#define TM45BR __SYSREG(0xd4003090, u32) /* timer 4:5 base register */ | |
| 288 | +#if defined(CONFIG_AM34_2) | |
| 289 | +#define TM12BR __SYSREG(0xd4003190, u16) /* timer 12 base register */ | |
| 290 | +#define TM13BR __SYSREG(0xd4003192, u16) /* timer 13 base register */ | |
| 291 | +#define TM14BR __SYSREG(0xd4003194, u16) /* timer 14 base register */ | |
| 292 | +#define TM15BR __SYSREG(0xd4003196, u16) /* timer 15 base register */ | |
| 293 | +#endif /* CONFIG_AM34_2 */ | |
| 197 | 294 | |
| 198 | 295 | #define TM4BC __SYSREG(0xd40030a0, u16) /* timer 4 binary counter */ |
| 199 | 296 | #define TM5BC __SYSREG(0xd40030a2, u16) /* timer 5 binary counter */ |
| 200 | 297 | #define TM45BC __SYSREG(0xd40030a0, u32) /* timer 4:5 binary counter */ |
| 201 | − | |
| 202 | 298 | #define TM7BC __SYSREG(0xd40030a6, u16) /* timer 7 binary counter */ |
| 203 | 299 | #define TM8BC __SYSREG(0xd40030a8, u16) /* timer 8 binary counter */ |
| 204 | 300 | #define TM9BC __SYSREG(0xd40030aa, u16) /* timer 9 binary counter */ |
| 301 | +#define TM89BC __SYSREG(0xd40030a8, u32) /* timer 8:9 binary counter */ | |
| 205 | 302 | #define TM10BC __SYSREG(0xd40030ac, u16) /* timer 10 binary counter */ |
| 206 | 303 | #define TM11BC __SYSREG(0xd40030ae, u16) /* timer 11 binary counter */ |
| 304 | +#if defined(CONFIG_AM34_2) | |
| 305 | +#define TM12BC __SYSREG(0xd40031a0, u16) /* timer 12 binary counter */ | |
| 306 | +#define TM13BC __SYSREG(0xd40031a2, u16) /* timer 13 binary counter */ | |
| 307 | +#define TM14BC __SYSREG(0xd40031a4, u16) /* timer 14 binary counter */ | |
| 308 | +#define TM15BC __SYSREG(0xd40031a6, u16) /* timer 15 binary counter */ | |
| 309 | +#endif /* CONFIG_AM34_2 */ | |
| 207 | 310 | |
| 208 | 311 | #define TM4IRQ 6 /* timer 4 IRQ */ |
| 209 | 312 | #define TM5IRQ 7 /* timer 5 IRQ */ |
| @@ -212,6 +315,12 @@ · 2 unmodified lines | ||
| 212 | 315 | #define TM9IRQ 13 /* timer 9 IRQ */ |
| 213 | 316 | #define TM10IRQ 14 /* timer 10 IRQ */ |
| 214 | 317 | #define TM11IRQ 15 /* timer 11 IRQ */ |
| 318 | +#if defined(CONFIG_AM34_2) | |
| 319 | +#define TM12IRQ 64 /* timer 12 IRQ */ | |
| 320 | +#define TM13IRQ 65 /* timer 13 IRQ */ | |
| 321 | +#define TM14IRQ 66 /* timer 14 IRQ */ | |
| 322 | +#define TM15IRQ 67 /* timer 15 IRQ */ | |
| 323 | +#endif /* CONFIG_AM34_2 */ | |
| 215 | 324 | |
| 216 | 325 | #define TM4ICR GxICR(TM4IRQ) /* timer 4 uflow intr ctrl reg */ |
| 217 | 326 | #define TM5ICR GxICR(TM5IRQ) /* timer 5 uflow intr ctrl reg */ |
| @@ -220,8 +329,16 @@ · 2 unmodified lines | ||
| 220 | 329 | #define TM9ICR GxICR(TM9IRQ) /* timer 9 uflow intr ctrl reg */ |
| 221 | 330 | #define TM10ICR GxICR(TM10IRQ) /* timer 10 uflow intr ctrl reg */ |
| 222 | 331 | #define TM11ICR GxICR(TM11IRQ) /* timer 11 uflow intr ctrl reg */ |
| 223 | − | |
| 224 | −/* 16-bit timer 6 */ | |
| 332 | +#if defined(CONFIG_AM34_2) | |
| 333 | +#define TM12ICR GxICR(TM12IRQ) /* timer 12 uflow intr ctrl reg */ | |
| 334 | +#define TM13ICR GxICR(TM13IRQ) /* timer 13 uflow intr ctrl reg */ | |
| 335 | +#define TM14ICR GxICR(TM14IRQ) /* timer 14 uflow intr ctrl reg */ | |
| 336 | +#define TM15ICR GxICR(TM15IRQ) /* timer 15 uflow intr ctrl reg */ | |
| 337 | +#endif /* CONFIG_AM34_2 */ | |
| 338 | + | |
| 339 | +/* | |
| 340 | + * 16-bit timer 6 | |
| 341 | + */ | |
| 225 | 342 | #define TM6MD __SYSREG(0xd4003084, u16) /* timer6 mode register */ |
| 226 | 343 | #define TM6MD_SRC 0x0007 /* timer source */ |
| 227 | 344 | #define TM6MD_SRC_IOCLK 0x0000 /* - IOCLK */ |
| @@ -229,10 +346,14 @@ · 1 unmodified line | ||
| 229 | 346 | #define TM6MD_SRC_IOCLK_32 0x0002 /* - 1/32 IOCLK */ |
| 230 | 347 | #define TM6MD_SRC_TM0UFLOW 0x0004 /* - timer 0 underflow */ |
| 231 | 348 | #define TM6MD_SRC_TM1UFLOW 0x0005 /* - timer 1 underflow */ |
| 232 | −#define TM6MD_SRC_TM6IOB_BOTH 0x0006 /* - TM6IOB pin input (both edges) */ | |
| 349 | +#define TM6MD_SRC_TM2UFLOW 0x0006 /* - timer 2 underflow */ | |
| 350 | +#if defined(CONFIG_AM33_2) | |
| 351 | +/* #define TM6MD_SRC_TM6IOB_BOTH 0x0006 */ /* - TM6IOB pin input (both edges) */ | |
| 233 | 352 | #define TM6MD_SRC_TM6IOB_SINGLE 0x0007 /* - TM6IOB pin input (single edge) */ |
| 234 | −#define TM6MD_CLR_ENABLE 0x0010 /* clear count enable */ | |
| 353 | +#endif /* CONFIG_AM33_2 */ | |
| 235 | 354 | #define TM6MD_ONESHOT_ENABLE 0x0040 /* oneshot count */ |
| 355 | +#define TM6MD_CLR_ENABLE 0x0010 /* clear count enable */ | |
| 356 | +#if defined(CONFIG_AM33_2) | |
| 236 | 357 | #define TM6MD_TRIG_ENABLE 0x0080 /* TM6IOB pin trigger enable */ |
| 237 | 358 | #define TM6MD_PWM 0x3800 /* PWM output mode */ |
| 238 | 359 | #define TM6MD_PWM_DIS 0x0000 /* - disabled */ |
| @@ -240,10 +361,15 @@ · 1 unmodified line | ||
| 240 | 361 | #define TM6MD_PWM_11BIT 0x1800 /* - 11 bits mode */ |
| 241 | 362 | #define TM6MD_PWM_12BIT 0x3000 /* - 12 bits mode */ |
| 242 | 363 | #define TM6MD_PWM_14BIT 0x3800 /* - 14 bits mode */ |
| 364 | +#endif /* CONFIG_AM33_2 */ | |
| 365 | + | |
| 243 | 366 | #define TM6MD_INIT_COUNTER 0x4000 /* initialize TMnBC to zero */ |
| 244 | 367 | #define TM6MD_COUNT_ENABLE 0x8000 /* timer count enable */ |
| 245 | 368 | |
| 246 | 369 | #define TM6MDA __SYSREG(0xd40030b4, u8) /* timer6 cmp/cap A mode reg */ |
| 370 | +#define TM6MDA_MODE_CMP_SINGLE 0x00 /* - compare, single buffer mode */ | |
| 371 | +#define TM6MDA_MODE_CMP_DOUBLE 0x40 /* - compare, double buffer mode */ | |
| 372 | +#if defined(CONFIG_AM33_2) | |
| 247 | 373 | #define TM6MDA_OUT 0x07 /* output select */ |
| 248 | 374 | #define TM6MDA_OUT_SETA_RESETB 0x00 /* - set at match A, reset at match B */ |
| 249 | 375 | #define TM6MDA_OUT_SETA_RESETOV 0x01 /* - set at match A, reset at overflow */ |
| @@ -251,30 +377,35 @@ · 1 unmodified line | ||
| 251 | 377 | #define TM6MDA_OUT_RESETA 0x03 /* - reset at match A */ |
| 252 | 378 | #define TM6MDA_OUT_TOGGLE 0x04 /* - toggle on match A */ |
| 253 | 379 | #define TM6MDA_MODE 0xc0 /* compare A register mode */ |
| 254 | −#define TM6MDA_MODE_CMP_SINGLE 0x00 /* - compare, single buffer mode */ | |
| 255 | −#define TM6MDA_MODE_CMP_DOUBLE 0x40 /* - compare, double buffer mode */ | |
| 256 | 380 | #define TM6MDA_MODE_CAP_S_EDGE 0x80 /* - capture, single edge mode */ |
| 257 | 381 | #define TM6MDA_MODE_CAP_D_EDGE 0xc0 /* - capture, double edge mode */ |
| 258 | 382 | #define TM6MDA_EDGE 0x20 /* compare A edge select */ |
| 259 | 383 | #define TM6MDA_EDGE_FALLING 0x00 /* capture on falling edge */ |
| 260 | 384 | #define TM6MDA_EDGE_RISING 0x20 /* capture on rising edge */ |
| 261 | 385 | #define TM6MDA_CAPTURE_ENABLE 0x10 /* capture enable */ |
| 386 | +#else /* !CONFIG_AM33_2 */ | |
| 387 | +#define TM6MDA_MODE 0x40 /* compare A register mode */ | |
| 388 | +#endif /* CONFIG_AM33_2 */ | |
| 262 | 389 | |
| 263 | 390 | #define TM6MDB __SYSREG(0xd40030b5, u8) /* timer6 cmp/cap B mode reg */ |
| 391 | +#define TM6MDB_MODE_CMP_SINGLE 0x00 /* - compare, single buffer mode */ | |
| 392 | +#define TM6MDB_MODE_CMP_DOUBLE 0x40 /* - compare, double buffer mode */ | |
| 393 | +#if defined(CONFIG_AM33_2) | |
| 264 | 394 | #define TM6MDB_OUT 0x07 /* output select */ |
| 265 | 395 | #define TM6MDB_OUT_SETB_RESETA 0x00 /* - set at match B, reset at match A */ |
| 266 | 396 | #define TM6MDB_OUT_SETB_RESETOV 0x01 /* - set at match B */ |
| 267 | 397 | #define TM6MDB_OUT_RESETB 0x03 /* - reset at match B */ |
| 268 | 398 | #define TM6MDB_OUT_TOGGLE 0x04 /* - toggle on match B */ |
| 269 | 399 | #define TM6MDB_MODE 0xc0 /* compare B register mode */ |
| 270 | −#define TM6MDB_MODE_CMP_SINGLE 0x00 /* - compare, single buffer mode */ | |
| 271 | −#define TM6MDB_MODE_CMP_DOUBLE 0x40 /* - compare, double buffer mode */ | |
| 272 | 400 | #define TM6MDB_MODE_CAP_S_EDGE 0x80 /* - capture, single edge mode */ |
| 273 | 401 | #define TM6MDB_MODE_CAP_D_EDGE 0xc0 /* - capture, double edge mode */ |
| 274 | 402 | #define TM6MDB_EDGE 0x20 /* compare B edge select */ |
| 275 | 403 | #define TM6MDB_EDGE_FALLING 0x00 /* capture on falling edge */ |
| 276 | 404 | #define TM6MDB_EDGE_RISING 0x20 /* capture on rising edge */ |
| 277 | 405 | #define TM6MDB_CAPTURE_ENABLE 0x10 /* capture enable */ |
| 406 | +#else /* !CONFIG_AM33_2 */ | |
| 407 | +#define TM6MDB_MODE 0x40 /* compare B register mode */ | |
| 408 | +#endif /* CONFIG_AM33_2 */ | |
| 278 | 409 | |
| 279 | 410 | #define TM6CA __SYSREG(0xd40030c4, u16) /* timer6 cmp/capture reg A */ |
| 280 | 411 | #define TM6CB __SYSREG(0xd40030d4, u16) /* timer6 cmp/capture reg B */ |
| @@ -288,6 +419,34 @@ · 7 unmodified lines | ||
| 288 | 419 | #define TM6AICR GxICR(TM6AIRQ) /* timer 6A intr control reg */ |
| 289 | 420 | #define TM6BICR GxICR(TM6BIRQ) /* timer 6B intr control reg */ |
| 290 | 421 | |
| 422 | +#if defined(CONFIG_AM34_2) | |
| 423 | +/* | |
| 424 | + * MTM: OS Tick-Timer | |
| 425 | + */ | |
| 426 | +#define TMTMD __SYSREG(0xd4004100, u8) /* Tick Timer mode register */ | |
| 427 | +#define TMTMD_TMTLDE 0x40 /* initialize TMTBC = TMTBR */ | |
| 428 | +#define TMTMD_TMTCNE 0x80 /* timer count enable */ | |
| 429 | + | |
| 430 | +#define TMTBR __SYSREG(0xd4004110, u32) /* Tick Timer mode reg */ | |
| 431 | +#define TMTBC __SYSREG(0xd4004120, u32) /* Tick Timer mode reg */ | |
| 432 | + | |
| 433 | +/* | |
| 434 | + * MTM: OS Timestamp-Timer | |
| 435 | + */ | |
| 436 | +#define TMSMD __SYSREG(0xd4004140, u8) /* Tick Timer mode register */ | |
| 437 | +#define TMSMD_TMSLDE 0x40 /* initialize TMSBC = TMSBR */ | |
| 438 | +#define TMSMD_TMSCNE 0x80 /* timer count enable */ | |
| 439 | + | |
| 440 | +#define TMSBR __SYSREG(0xd4004150, u32) /* Tick Timer mode register */ | |
| 441 | +#define TMSBC __SYSREG(0xd4004160, u32) /* Tick Timer mode register */ | |
| 442 | + | |
| 443 | +#define TMTIRQ 119 /* OS Tick timer IRQ */ | |
| 444 | +#define TMSIRQ 120 /* Timestamp timer IRQ */ | |
| 445 | + | |
| 446 | +#define TMTICR GxICR(TMTIRQ) /* OS Tick timer uflow intr ctrl reg */ | |
| 447 | +#define TMSICR GxICR(TMSIRQ) /* Timestamp timer uflow intr ctrl reg */ | |
| 448 | +#endif /* CONFIG_AM34_2 */ | |
| 449 | + | |
| 291 | 450 | #endif /* __KERNEL__ */ |
| 292 | 451 | |
| 293 | 452 | #endif /* _ASM_TIMER_REGS_H */ |
| @@ -16,18 +16,30 @@ · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | #define TICK_SIZE (tick_nsec / 1000) |
| 18 | 18 | |
| 19 | −#define CLOCK_TICK_RATE 1193180 /* Underlying HZ - this should probably be set | |
| 20 | − * to something appropriate, but what? */ | |
| 21 | − | |
| 22 | −extern cycles_t cacheflush_time; | |
| 19 | +#define CLOCK_TICK_RATE MN10300_JCCLK /* Underlying HZ */ | |
| 23 | 20 | |
| 24 | 21 | #ifdef __KERNEL__ |
| 25 | 22 | |
| 23 | +extern cycles_t cacheflush_time; | |
| 24 | + | |
| 26 | 25 | static inline cycles_t get_cycles(void) |
| 27 | 26 | { |
| 28 | 27 | return read_timestamp_counter(); |
| 29 | 28 | } |
| 30 | 29 | |
| 30 | +extern int init_clockevents(void); | |
| 31 | +extern int init_clocksource(void); | |
| 32 | + | |
| 33 | +static inline void setup_jiffies_interrupt(int irq, | |
| 34 | + struct irqaction *action) | |
| 35 | +{ | |
| 36 | + u16 tmp; | |
| 37 | + setup_irq(irq, action); | |
| 38 | + set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL)); | |
| 39 | + GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST; | |
| 40 | + tmp = GxICR(irq); | |
| 41 | +} | |
| 42 | + | |
| 31 | 43 | #endif /* __KERNEL__ */ |
| 32 | 44 | |
| 33 | 45 | #endif /* _ASM_TIMEX_H */ |
| @@ -11,24 +11,78 @@ · 10 unmodified lines | ||
| 11 | 11 | #ifndef _ASM_TLBFLUSH_H |
| 12 | 12 | #define _ASM_TLBFLUSH_H |
| 13 | 13 | |
| 14 | +#include <linux/mm.h> | |
| 14 | 15 | #include <asm/processor.h> |
| 15 | 16 | |
| 16 | −#define __flush_tlb() \ | |
| 17 | −do { \ | |
| 18 | − int w; \ | |
| 19 | − __asm__ __volatile__ \ | |
| 20 | − (" mov %1,%0 \n" \ | |
| 21 | − " or %2,%0 \n" \ | |
| 22 | − " mov %0,%1 \n" \ | |
| 23 | − : "=d"(w) \ | |
| 24 | − : "m"(MMUCTR), "i"(MMUCTR_IIV|MMUCTR_DIV) \ | |
| 25 | − : "cc", "memory" \ | |
| 26 | − ); \ | |
| 27 | −} while (0) | |
| 17 | +struct tlb_state { | |
| 18 | + struct mm_struct *active_mm; | |
| 19 | + int state; | |
| 20 | +}; | |
| 21 | +DECLARE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate); | |
| 28 | 22 | |
| 29 | −#define __flush_tlb_all() __flush_tlb() | |
| 30 | −#define __flush_tlb_one(addr) __flush_tlb() | |
| 23 | +/** | |
| 24 | + * local_flush_tlb - Flush the current MM's entries from the local CPU's TLBs | |
| 25 | + */ | |
| 26 | +static inline void local_flush_tlb(void) | |
| 27 | +{ | |
| 28 | + int w; | |
| 29 | + asm volatile( | |
| 30 | + " mov %1,%0 \n" | |
| 31 | + " or %2,%0 \n" | |
| 32 | + " mov %0,%1 \n" | |
| 33 | + : "=d"(w) | |
| 34 | + : "m"(MMUCTR), "i"(MMUCTR_IIV|MMUCTR_DIV) | |
| 35 | + : "cc", "memory"); | |
| 36 | +} | |
| 37 | + | |
| 38 | +/** | |
| 39 | + * local_flush_tlb_all - Flush all entries from the local CPU's TLBs | |
| 40 | + */ | |
| 41 | +static inline void local_flush_tlb_all(void) | |
| 42 | +{ | |
| 43 | + local_flush_tlb(); | |
| 44 | +} | |
| 31 | 45 | |
| 46 | +/** | |
| 47 | + * local_flush_tlb_one - Flush one entry from the local CPU's TLBs | |
| 48 | + */ | |
| 49 | +static inline void local_flush_tlb_one(unsigned long addr) | |
| 50 | +{ | |
| 51 | + local_flush_tlb(); | |
| 52 | +} | |
| 53 | + | |
| 54 | +/** | |
| 55 | + * local_flush_tlb_page - Flush a page's entry from the local CPU's TLBs | |
| 56 | + * @mm: The MM to flush for | |
| 57 | + * @addr: The address of the target page in RAM (not its page struct) | |
| 58 | + */ | |
| 59 | +static inline | |
| 60 | +void local_flush_tlb_page(struct mm_struct *mm, unsigned long addr) | |
| 61 | +{ | |
| 62 | + unsigned long pteu, flags, cnx; | |
| 63 | + | |
| 64 | + addr &= PAGE_MASK; | |
| 65 | + | |
| 66 | + local_irq_save(flags); | |
| 67 | + | |
| 68 | + cnx = 1; | |
| 69 | +#ifdef CONFIG_MN10300_TLB_USE_PIDR | |
| 70 | + cnx = mm->context.tlbpid[smp_processor_id()]; | |
| 71 | +#endif | |
| 72 | + if (cnx) { | |
| 73 | + pteu = addr; | |
| 74 | +#ifdef CONFIG_MN10300_TLB_USE_PIDR | |
| 75 | + pteu |= cnx & xPTEU_PID; | |
| 76 | +#endif | |
| 77 | + IPTEU = pteu; | |
| 78 | + DPTEU = pteu; | |
| 79 | + if (IPTEL & xPTEL_V) | |
| 80 | + IPTEL = 0; | |
| 81 | + if (DPTEL & xPTEL_V) | |
| 82 | + DPTEL = 0; | |
| 83 | + } | |
| 84 | + local_irq_restore(flags); | |
| 85 | +} | |
| 32 | 86 | |
| 33 | 87 | /* |
| 34 | 88 | * TLB flushing: |
| @@ -40,41 +94,61 @@ do { \ · 5 unmodified lines | ||
| 40 | 94 | * - flush_tlb_range(mm, start, end) flushes a range of pages |
| 41 | 95 | * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables |
| 42 | 96 | */ |
| 43 | −#define flush_tlb_all() \ | |
| 44 | −do { \ | |
| 45 | − preempt_disable(); \ | |
| 46 | − __flush_tlb_all(); \ | |
| 47 | − preempt_enable(); \ | |
| 48 | −} while (0) | |
| 49 | − | |
| 50 | −#define flush_tlb_mm(mm) \ | |
| 51 | −do { \ | |
| 52 | − preempt_disable(); \ | |
| 53 | − __flush_tlb_all(); \ | |
| 54 | − preempt_enable(); \ | |
| 55 | −} while (0) | |
| 56 | − | |
| 57 | −#define flush_tlb_range(vma, start, end) \ | |
| 58 | −do { \ | |
| 59 | − unsigned long __s __attribute__((unused)) = (start); \ | |
| 60 | − unsigned long __e __attribute__((unused)) = (end); \ | |
| 61 | − preempt_disable(); \ | |
| 62 | − __flush_tlb_all(); \ | |
| 63 | − preempt_enable(); \ | |
| 64 | −} while (0) | |
| 65 | − | |
| 66 | − | |
| 67 | −#define __flush_tlb_global() flush_tlb_all() | |
| 68 | −#define flush_tlb() flush_tlb_all() | |
| 69 | −#define flush_tlb_kernel_range(start, end) \ | |
| 70 | −do { \ | |
| 71 | − unsigned long __s __attribute__((unused)) = (start); \ | |
| 72 | − unsigned long __e __attribute__((unused)) = (end); \ | |
| 73 | − flush_tlb_all(); \ | |
| 74 | −} while (0) | |
| 75 | − | |
| 76 | −extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr); | |
| 77 | − | |
| 78 | −#define flush_tlb_pgtables(mm, start, end) do {} while (0) | |
| 97 | +#ifdef CONFIG_SMP | |
| 98 | + | |
| 99 | +#include <asm/smp.h> | |
| 100 | + | |
| 101 | +extern void flush_tlb_all(void); | |
| 102 | +extern void flush_tlb_current_task(void); | |
| 103 | +extern void flush_tlb_mm(struct mm_struct *); | |
| 104 | +extern void flush_tlb_page(struct vm_area_struct *, unsigned long); | |
| 105 | + | |
| 106 | +#define flush_tlb() flush_tlb_current_task() | |
| 107 | + | |
| 108 | +static inline void flush_tlb_range(struct vm_area_struct *vma, | |
| 109 | + unsigned long start, unsigned long end) | |
| 110 | +{ | |
| 111 | + flush_tlb_mm(vma->vm_mm); | |
| 112 | +} | |
| 113 | + | |
| 114 | +#else /* CONFIG_SMP */ | |
| 115 | + | |
| 116 | +static inline void flush_tlb_all(void) | |
| 117 | +{ | |
| 118 | + preempt_disable(); | |
| 119 | + local_flush_tlb_all(); | |
| 120 | + preempt_enable(); | |
| 121 | +} | |
| 122 | + | |
| 123 | +static inline void flush_tlb_mm(struct mm_struct *mm) | |
| 124 | +{ | |
| 125 | + preempt_disable(); | |
| 126 | + local_flush_tlb_all(); | |
| 127 | + preempt_enable(); | |
| 128 | +} | |
| 129 | + | |
| 130 | +static inline void flush_tlb_range(struct vm_area_struct *vma, | |
| 131 | + unsigned long start, unsigned long end) | |
| 132 | +{ | |
| 133 | + preempt_disable(); | |
| 134 | + local_flush_tlb_all(); | |
| 135 | + preempt_enable(); | |
| 136 | +} | |
| 137 | + | |
| 138 | +#define flush_tlb_page(vma, addr) local_flush_tlb_page((vma)->vm_mm, addr) | |
| 139 | +#define flush_tlb() flush_tlb_all() | |
| 140 | + | |
| 141 | +#endif /* CONFIG_SMP */ | |
| 142 | + | |
| 143 | +static inline void flush_tlb_kernel_range(unsigned long start, | |
| 144 | + unsigned long end) | |
| 145 | +{ | |
| 146 | + flush_tlb_all(); | |
| 147 | +} | |
| 148 | + | |
| 149 | +static inline void flush_tlb_pgtables(struct mm_struct *mm, | |
| 150 | + unsigned long start, unsigned long end) | |
| 151 | +{ | |
| 152 | +} | |
| 79 | 153 | |
| 80 | 154 | #endif /* _ASM_TLBFLUSH_H */ |
| @@ -14,9 +14,8 @@ · 13 unmodified lines | ||
| 14 | 14 | /* |
| 15 | 15 | * User space memory access functions |
| 16 | 16 | */ |
| 17 | −#include <linux/sched.h> | |
| 17 | +#include <linux/thread_info.h> | |
| 18 | 18 | #include <asm/page.h> |
| 19 | −#include <asm/pgtable.h> | |
| 20 | 19 | #include <asm/errno.h> |
| 21 | 20 | |
| 22 | 21 | #define VERIFY_READ 0 |
| @@ -29,7 +28,6 @@ · 6 unmodified lines | ||
| 29 | 28 | * |
| 30 | 29 | * For historical reasons, these macros are grossly misnamed. |
| 31 | 30 | */ |
| 32 | − | |
| 33 | 31 | #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) |
| 34 | 32 | |
| 35 | 33 | #define KERNEL_XDS MAKE_MM_SEG(0xBFFFFFFF) |
| @@ -377,7 +375,7 @@ unsigned long __generic_copy_to_user_nocheck(void *to, const void *from, · 341 unmodified lines | ||
| 377 | 375 | |
| 378 | 376 | |
| 379 | 377 | #if 0 |
| 380 | −#error don't use - these macros don't increment to & from pointers | |
| 378 | +#error "don't use - these macros don't increment to & from pointers" | |
| 381 | 379 | /* Optimize just a little bit when we know the size of the move. */ |
| 382 | 380 | #define __constant_copy_user(to, from, size) \ |
| 383 | 381 | do { \ |
| @@ -3,13 +3,16 @@ · 2 unmodified lines | ||
| 3 | 3 | # |
| 4 | 4 | extra-y := head.o init_task.o vmlinux.lds |
| 5 | 5 | |
| 6 | −obj-y := process.o signal.o entry.o fpu.o traps.o irq.o \ | |
| 6 | +fpu-obj-y := fpu-nofpu.o fpu-nofpu-low.o | |
| 7 | +fpu-obj-$(CONFIG_FPU) := fpu.o fpu-low.o | |
| 8 | + | |
| 9 | +obj-y := process.o signal.o entry.o traps.o irq.o \ | |
| 7 | 10 | ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \ |
| 8 | − switch_to.o mn10300_ksyms.o kernel_execve.o | |
| 11 | + switch_to.o mn10300_ksyms.o kernel_execve.o $(fpu-obj-y) | |
| 9 | 12 | |
| 10 | −obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o | |
| 13 | +obj-$(CONFIG_SMP) += smp.o smp-low.o | |
| 11 | 14 | |
| 12 | −obj-$(CONFIG_FPU) += fpu-low.o | |
| 15 | +obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o | |
| 13 | 16 | |
| 14 | 17 | obj-$(CONFIG_MN10300_TTYSM) += mn10300-serial.o mn10300-serial-low.o \ |
| 15 | 18 | mn10300-debug.o |
| @@ -17,7 +20,7 @@ obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-low.o · 1 unmodified line | ||
| 17 | 20 | obj-$(CONFIG_GDBSTUB_ON_TTYSx) += gdb-io-serial.o gdb-io-serial-low.o |
| 18 | 21 | obj-$(CONFIG_GDBSTUB_ON_TTYSMx) += gdb-io-ttysm.o gdb-io-ttysm-low.o |
| 19 | 22 | |
| 20 | −ifneq ($(CONFIG_MN10300_CACHE_DISABLED),y) | |
| 23 | +ifeq ($(CONFIG_MN10300_CACHE_ENABLED),y) | |
| 21 | 24 | obj-$(CONFIG_GDBSTUB) += gdb-cache.o |
| 22 | 25 | endif |
| 23 | 26 | |
| @@ -25,3 +28,5 @@ obj-$(CONFIG_MN10300_RTC) += rtc.o · 1 unmodified line | ||
| 25 | 28 | obj-$(CONFIG_PROFILE) += profile.o profile-low.o |
| 26 | 29 | obj-$(CONFIG_MODULES) += module.o |
| 27 | 30 | obj-$(CONFIG_KPROBES) += kprobes.o |
| 31 | +obj-$(CONFIG_CSRC_MN10300) += csrc-mn10300.o | |
| 32 | +obj-$(CONFIG_CEVT_MN10300) += cevt-mn10300.o | |
| @@ -23,6 +23,7 @@ void foo(void) · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | OFFSET(TI_task, thread_info, task); |
| 25 | 25 | OFFSET(TI_exec_domain, thread_info, exec_domain); |
| 26 | + OFFSET(TI_frame, thread_info, frame); | |
| 26 | 27 | OFFSET(TI_flags, thread_info, flags); |
| 27 | 28 | OFFSET(TI_cpu, thread_info, cpu); |
| 28 | 29 | OFFSET(TI_preempt_count, thread_info, preempt_count); |
| @@ -66,7 +67,15 @@ void foo(void) · 37 unmodified lines | ||
| 66 | 67 | OFFSET(THREAD_SP, thread_struct, sp); |
| 67 | 68 | OFFSET(THREAD_A3, thread_struct, a3); |
| 68 | 69 | OFFSET(THREAD_USP, thread_struct, usp); |
| 69 | − OFFSET(THREAD_FRAME, thread_struct, __frame); | |
| 70 | +#ifdef CONFIG_FPU | |
| 71 | + OFFSET(THREAD_FPU_FLAGS, thread_struct, fpu_flags); | |
| 72 | + OFFSET(THREAD_FPU_STATE, thread_struct, fpu_state); | |
| 73 | + DEFINE(__THREAD_USING_FPU, THREAD_USING_FPU); | |
| 74 | + DEFINE(__THREAD_HAS_FPU, THREAD_HAS_FPU); | |
| 75 | +#endif /* CONFIG_FPU */ | |
| 76 | + BLANK(); | |
| 77 | + | |
| 78 | + OFFSET(TASK_THREAD, task_struct, thread); | |
| 70 | 79 | BLANK(); |
| 71 | 80 | |
| 72 | 81 | DEFINE(CLONE_VM_asm, CLONE_VM); |
| @@ -0,0 +1,131 @@ | ||
| 1 | +/* MN10300 clockevents | |
| 2 | + * | |
| 3 | + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by Mark Salter (msalter@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#include <linux/clockchips.h> | |
| 12 | +#include <linux/interrupt.h> | |
| 13 | +#include <linux/percpu.h> | |
| 14 | +#include <linux/smp.h> | |
| 15 | +#include <asm/timex.h> | |
| 16 | +#include "internal.h" | |
| 17 | + | |
| 18 | +#ifdef CONFIG_SMP | |
| 19 | +#if (CONFIG_NR_CPUS > 2) && !defined(CONFIG_GEENERIC_CLOCKEVENTS_BROADCAST) | |
| 20 | +#error "This doesn't scale well! Need per-core local timers." | |
| 21 | +#endif | |
| 22 | +#else /* CONFIG_SMP */ | |
| 23 | +#define stop_jiffies_counter1() | |
| 24 | +#define reload_jiffies_counter1(x) | |
| 25 | +#define TMJC1IRQ TMJCIRQ | |
| 26 | +#endif | |
| 27 | + | |
| 28 | + | |
| 29 | +static int next_event(unsigned long delta, | |
| 30 | + struct clock_event_device *evt) | |
| 31 | +{ | |
| 32 | + unsigned int cpu = smp_processor_id(); | |
| 33 | + | |
| 34 | + if (cpu == 0) { | |
| 35 | + stop_jiffies_counter(); | |
| 36 | + reload_jiffies_counter(delta - 1); | |
| 37 | + } else { | |
| 38 | + stop_jiffies_counter1(); | |
| 39 | + reload_jiffies_counter1(delta - 1); | |
| 40 | + } | |
| 41 | + return 0; | |
| 42 | +} | |
| 43 | + | |
| 44 | +static void set_clock_mode(enum clock_event_mode mode, | |
| 45 | + struct clock_event_device *evt) | |
| 46 | +{ | |
| 47 | + /* Nothing to do ... */ | |
| 48 | +} | |
| 49 | + | |
| 50 | +static DEFINE_PER_CPU(struct clock_event_device, mn10300_clockevent_device); | |
| 51 | +static DEFINE_PER_CPU(struct irqaction, timer_irq); | |
| 52 | + | |
| 53 | +static irqreturn_t timer_interrupt(int irq, void *dev_id) | |
| 54 | +{ | |
| 55 | + struct clock_event_device *cd; | |
| 56 | + unsigned int cpu = smp_processor_id(); | |
| 57 | + | |
| 58 | + if (cpu == 0) | |
| 59 | + stop_jiffies_counter(); | |
| 60 | + else | |
| 61 | + stop_jiffies_counter1(); | |
| 62 | + | |
| 63 | + cd = &per_cpu(mn10300_clockevent_device, cpu); | |
| 64 | + cd->event_handler(cd); | |
| 65 | + | |
| 66 | + return IRQ_HANDLED; | |
| 67 | +} | |
| 68 | + | |
| 69 | +static void event_handler(struct clock_event_device *dev) | |
| 70 | +{ | |
| 71 | +} | |
| 72 | + | |
| 73 | +int __init init_clockevents(void) | |
| 74 | +{ | |
| 75 | + struct clock_event_device *cd; | |
| 76 | + struct irqaction *iact; | |
| 77 | + unsigned int cpu = smp_processor_id(); | |
| 78 | + | |
| 79 | + cd = &per_cpu(mn10300_clockevent_device, cpu); | |
| 80 | + | |
| 81 | + if (cpu == 0) { | |
| 82 | + stop_jiffies_counter(); | |
| 83 | + cd->irq = TMJCIRQ; | |
| 84 | + } else { | |
| 85 | + stop_jiffies_counter1(); | |
| 86 | + cd->irq = TMJC1IRQ; | |
| 87 | + } | |
| 88 | + | |
| 89 | + cd->name = "Timestamp"; | |
| 90 | + cd->features = CLOCK_EVT_FEAT_ONESHOT; | |
| 91 | + | |
| 92 | + /* Calculate the min / max delta */ | |
| 93 | + clockevent_set_clock(cd, MN10300_JCCLK); | |
| 94 | + | |
| 95 | + cd->max_delta_ns = clockevent_delta2ns(TMJCBR_MAX, cd); | |
| 96 | + cd->min_delta_ns = clockevent_delta2ns(100, cd); | |
| 97 | + | |
| 98 | + cd->rating = 200; | |
| 99 | + cd->cpumask = cpumask_of(smp_processor_id()); | |
| 100 | + cd->set_mode = set_clock_mode; | |
| 101 | + cd->event_handler = event_handler; | |
| 102 | + cd->set_next_event = next_event; | |
| 103 | + | |
| 104 | + iact = &per_cpu(timer_irq, cpu); | |
| 105 | + iact->flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER; | |
| 106 | + iact->handler = timer_interrupt; | |
| 107 | + | |
| 108 | + clockevents_register_device(cd); | |
| 109 | + | |
| 110 | +#if defined(CONFIG_SMP) && !defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) | |
| 111 | + /* setup timer irq affinity so it only runs on this cpu */ | |
| 112 | + { | |
| 113 | + struct irq_desc *desc; | |
| 114 | + desc = irq_to_desc(cd->irq); | |
| 115 | + cpumask_copy(desc->affinity, cpumask_of(cpu)); | |
| 116 | + iact->flags |= IRQF_NOBALANCING; | |
| 117 | + } | |
| 118 | +#endif | |
| 119 | + | |
| 120 | + if (cpu == 0) { | |
| 121 | + reload_jiffies_counter(MN10300_JC_PER_HZ - 1); | |
| 122 | + iact->name = "CPU0 Timer"; | |
| 123 | + } else { | |
| 124 | + reload_jiffies_counter1(MN10300_JC_PER_HZ - 1); | |
| 125 | + iact->name = "CPU1 Timer"; | |
| 126 | + } | |
| 127 | + | |
| 128 | + setup_jiffies_interrupt(cd->irq, iact); | |
| 129 | + | |
| 130 | + return 0; | |
| 131 | +} | |
| @@ -0,0 +1,35 @@ | ||
| 1 | +/* MN10300 clocksource | |
| 2 | + * | |
| 3 | + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by Mark Salter (msalter@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#include <linux/clocksource.h> | |
| 12 | +#include <linux/init.h> | |
| 13 | +#include <asm/timex.h> | |
| 14 | +#include "internal.h" | |
| 15 | + | |
| 16 | +static cycle_t mn10300_read(struct clocksource *cs) | |
| 17 | +{ | |
| 18 | + return read_timestamp_counter(); | |
| 19 | +} | |
| 20 | + | |
| 21 | +static struct clocksource clocksource_mn10300 = { | |
| 22 | + .name = "TSC", | |
| 23 | + .rating = 200, | |
| 24 | + .read = mn10300_read, | |
| 25 | + .mask = CLOCKSOURCE_MASK(32), | |
| 26 | + .flags = CLOCK_SOURCE_IS_CONTINUOUS, | |
| 27 | +}; | |
| 28 | + | |
| 29 | +int __init init_clocksource(void) | |
| 30 | +{ | |
| 31 | + startup_timestamp_counter(); | |
| 32 | + clocksource_set_clock(&clocksource_mn10300, MN10300_TSCCLK); | |
| 33 | + clocksource_register(&clocksource_mn10300); | |
| 34 | + return 0; | |
| 35 | +} | |
| @@ -28,25 +28,17 @@ · 27 unmodified lines | ||
| 28 | 28 | #include <asm/asm-offsets.h> |
| 29 | 29 | #include <asm/frame.inc> |
| 30 | 30 | |
| 31 | +#if defined(CONFIG_SMP) && defined(CONFIG_GDBSTUB) | |
| 32 | +#include <asm/gdb-stub.h> | |
| 33 | +#endif /* CONFIG_SMP && CONFIG_GDBSTUB */ | |
| 34 | + | |
| 31 | 35 | #ifdef CONFIG_PREEMPT |
| 32 | −#define preempt_stop __cli | |
| 36 | +#define preempt_stop LOCAL_IRQ_DISABLE | |
| 33 | 37 | #else |
| 34 | 38 | #define preempt_stop |
| 35 | 39 | #define resume_kernel restore_all |
| 36 | 40 | #endif |
| 37 | 41 | |
| 38 | − .macro __cli | |
| 39 | − and ~EPSW_IM,epsw | |
| 40 | − or EPSW_IE|MN10300_CLI_LEVEL,epsw | |
| 41 | − nop | |
| 42 | − nop | |
| 43 | − nop | |
| 44 | − .endm | |
| 45 | − .macro __sti | |
| 46 | − or EPSW_IE|EPSW_IM_7,epsw | |
| 47 | − .endm | |
| 48 | − | |
| 49 | − | |
| 50 | 42 | .am33_2 |
| 51 | 43 | |
| 52 | 44 | ############################################################################### |
| @@ -88,7 +80,7 @@ syscall_call: · 35 unmodified lines | ||
| 88 | 80 | syscall_exit: |
| 89 | 81 | # make sure we don't miss an interrupt setting need_resched or |
| 90 | 82 | # sigpending between sampling and the rti |
| 91 | − __cli | |
| 83 | + LOCAL_IRQ_DISABLE | |
| 92 | 84 | mov (TI_flags,a2),d2 |
| 93 | 85 | btst _TIF_ALLWORK_MASK,d2 |
| 94 | 86 | bne syscall_exit_work |
| @@ -105,7 +97,7 @@ restore_all: · 10 unmodified lines | ||
| 105 | 97 | syscall_exit_work: |
| 106 | 98 | btst _TIF_SYSCALL_TRACE,d2 |
| 107 | 99 | beq work_pending |
| 108 | − __sti # could let syscall_trace_exit() call | |
| 100 | + LOCAL_IRQ_ENABLE # could let syscall_trace_exit() call | |
| 109 | 101 | # schedule() instead |
| 110 | 102 | mov fp,d0 |
| 111 | 103 | call syscall_trace_exit[],0 # do_syscall_trace(regs) |
| @@ -121,7 +113,7 @@ work_resched: · 9 unmodified lines | ||
| 121 | 113 | |
| 122 | 114 | # make sure we don't miss an interrupt setting need_resched or |
| 123 | 115 | # sigpending between sampling and the rti |
| 124 | − __cli | |
| 116 | + LOCAL_IRQ_DISABLE | |
| 125 | 117 | |
| 126 | 118 | # is there any work to be done other than syscall tracing? |
| 127 | 119 | mov (TI_flags,a2),d2 |
| @@ -168,7 +160,7 @@ ret_from_intr: · 40 unmodified lines | ||
| 168 | 160 | ENTRY(resume_userspace) |
| 169 | 161 | # make sure we don't miss an interrupt setting need_resched or |
| 170 | 162 | # sigpending between sampling and the rti |
| 171 | − __cli | |
| 163 | + LOCAL_IRQ_DISABLE | |
| 172 | 164 | |
| 173 | 165 | # is there any work to be done on int/exception return? |
| 174 | 166 | mov (TI_flags,a2),d2 |
| @@ -178,7 +170,7 @@ ENTRY(resume_userspace) · 3 unmodified lines | ||
| 178 | 170 | |
| 179 | 171 | #ifdef CONFIG_PREEMPT |
| 180 | 172 | ENTRY(resume_kernel) |
| 181 | − __cli | |
| 173 | + LOCAL_IRQ_DISABLE | |
| 182 | 174 | mov (TI_preempt_count,a2),d0 # non-zero preempt_count ? |
| 183 | 175 | cmp 0,d0 |
| 184 | 176 | bne restore_all |
| @@ -214,31 +206,6 @@ ENTRY(irq_handler) · 29 unmodified lines | ||
| 214 | 206 | |
| 215 | 207 | jmp ret_from_intr |
| 216 | 208 | |
| 217 | −############################################################################### | |
| 218 | −# | |
| 219 | −# Monitor Signal handler entry point | |
| 220 | −# | |
| 221 | −############################################################################### | |
| 222 | −ENTRY(monitor_signal) | |
| 223 | − movbu (0xae000001),d1 | |
| 224 | − cmp 1,d1 | |
| 225 | − beq monsignal | |
| 226 | − ret [],0 | |
| 227 | − | |
| 228 | −monsignal: | |
| 229 | − or EPSW_NMID,epsw | |
| 230 | − mov d0,a0 | |
| 231 | − mov a0,sp | |
| 232 | − mov (REG_EPSW,fp),d1 | |
| 233 | − and ~EPSW_nSL,d1 | |
| 234 | − mov d1,(REG_EPSW,fp) | |
| 235 | − movm (sp),[d2,d3,a2,a3,exreg0,exreg1,exother] | |
| 236 | − mov (sp),a1 | |
| 237 | − mov a1,usp | |
| 238 | − movm (sp),[other] | |
| 239 | − add 4,sp | |
| 240 | −here: jmp 0x8e000008-here+0x8e000008 | |
| 241 | − | |
| 242 | 209 | ############################################################################### |
| 243 | 210 | # |
| 244 | 211 | # Double Fault handler entry point |
| @@ -276,6 +243,10 @@ double_fault_loop: · 31 unmodified lines | ||
| 276 | 243 | ENTRY(raw_bus_error) |
| 277 | 244 | add -4,sp |
| 278 | 245 | mov d0,(sp) |
| 246 | +#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR) | |
| 247 | + mov (MMUCTR),d0 | |
| 248 | + mov d0,(MMUCTR) | |
| 249 | +#endif | |
| 279 | 250 | mov (BCBERR),d0 # what |
| 280 | 251 | btst BCBERR_BEMR_DMA,d0 # see if it was an external bus error |
| 281 | 252 | beq __common_exception_aux # it wasn't |
| @@ -302,11 +273,88 @@ ENTRY(nmi_handler) · 20 unmodified lines | ||
| 302 | 273 | add -4,sp |
| 303 | 274 | mov d0,(sp) |
| 304 | 275 | mov (TBR),d0 |
| 276 | + | |
| 277 | +#ifdef CONFIG_SMP | |
| 278 | + add -4,sp | |
| 279 | + mov d0,(sp) # save d0(TBR) | |
| 280 | + movhu (NMIAGR),d0 | |
| 281 | + and NMIAGR_GN,d0 | |
| 282 | + lsr 0x2,d0 | |
| 283 | + cmp CALL_FUNCTION_NMI_IPI,d0 | |
| 284 | + bne 5f # if not call function, jump | |
| 285 | + | |
| 286 | + # function call nmi ipi | |
| 287 | + add 4,sp # no need to store TBR | |
| 288 | + mov GxICR_DETECT,d0 # clear NMI request | |
| 289 | + movbu d0,(GxICR(CALL_FUNCTION_NMI_IPI)) | |
| 290 | + movhu (GxICR(CALL_FUNCTION_NMI_IPI)),d0 | |
| 291 | + and ~EPSW_NMID,epsw # enable NMI | |
| 292 | + | |
| 293 | + mov (sp),d0 # restore d0 | |
| 294 | + SAVE_ALL | |
| 295 | + call smp_nmi_call_function_interrupt[],0 | |
| 296 | + RESTORE_ALL | |
| 297 | + | |
| 298 | +5: | |
| 299 | +#ifdef CONFIG_GDBSTUB | |
| 300 | + cmp GDB_NMI_IPI,d0 | |
| 301 | + bne 3f # if not gdb nmi ipi, jump | |
| 302 | + | |
| 303 | + # gdb nmi ipi | |
| 304 | + add 4,sp # no need to store TBR | |
| 305 | + mov GxICR_DETECT,d0 # clear NMI | |
| 306 | + movbu d0,(GxICR(GDB_NMI_IPI)) | |
| 307 | + movhu (GxICR(GDB_NMI_IPI)),d0 | |
| 308 | + and ~EPSW_NMID,epsw # enable NMI | |
| 309 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 310 | + mov (gdbstub_nmi_opr_type),d0 | |
| 311 | + cmp GDBSTUB_NMI_CACHE_PURGE,d0 | |
| 312 | + bne 4f # if not gdb cache purge, jump | |
| 313 | + | |
| 314 | + # gdb cache purge nmi ipi | |
| 315 | + add -20,sp | |
| 316 | + mov d1,(4,sp) | |
| 317 | + mov a0,(8,sp) | |
| 318 | + mov a1,(12,sp) | |
| 319 | + mov mdr,d0 | |
| 320 | + mov d0,(16,sp) | |
| 321 | + call gdbstub_local_purge_cache[],0 | |
| 322 | + mov 0x1,d0 | |
| 323 | + mov (CPUID),d1 | |
| 324 | + asl d1,d0 | |
| 325 | + mov gdbstub_nmi_cpumask,a0 | |
| 326 | + bclr d0,(a0) | |
| 327 | + mov (4,sp),d1 | |
| 328 | + mov (8,sp),a0 | |
| 329 | + mov (12,sp),a1 | |
| 330 | + mov (16,sp),d0 | |
| 331 | + mov d0,mdr | |
| 332 | + add 20,sp | |
| 333 | + mov (sp),d0 | |
| 334 | + add 4,sp | |
| 335 | + rti | |
| 336 | +4: | |
| 337 | +#endif /* CONFIG_MN10300_CACHE_ENABLED */ | |
| 338 | + # gdb wait nmi ipi | |
| 339 | + mov (sp),d0 | |
| 340 | + SAVE_ALL | |
| 341 | + call gdbstub_nmi_wait[],0 | |
| 342 | + RESTORE_ALL | |
| 343 | +3: | |
| 344 | +#endif /* CONFIG_GDBSTUB */ | |
| 345 | + mov (sp),d0 # restore TBR to d0 | |
| 346 | + add 4,sp | |
| 347 | +#endif /* CONFIG_SMP */ | |
| 348 | + | |
| 305 | 349 | bra __common_exception_nonmi |
| 306 | 350 | |
| 307 | 351 | ENTRY(__common_exception) |
| 308 | 352 | add -4,sp |
| 309 | 353 | mov d0,(sp) |
| 354 | +#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR) | |
| 355 | + mov (MMUCTR),d0 | |
| 356 | + mov d0,(MMUCTR) | |
| 357 | +#endif | |
| 310 | 358 | |
| 311 | 359 | __common_exception_aux: |
| 312 | 360 | mov (TBR),d0 |
| @@ -331,15 +379,21 @@ __common_exception_nonmi: · 18 unmodified lines | ||
| 331 | 379 | mov d0,(REG_ORIG_D0,fp) |
| 332 | 380 | |
| 333 | 381 | #ifdef CONFIG_GDBSTUB |
| 382 | +#ifdef CONFIG_SMP | |
| 383 | + call gdbstub_busy_check[],0 | |
| 384 | + and d0,d0 # check return value | |
| 385 | + beq 2f | |
| 386 | +#else /* CONFIG_SMP */ | |
| 334 | 387 | btst 0x01,(gdbstub_busy) |
| 335 | 388 | beq 2f |
| 389 | +#endif /* CONFIG_SMP */ | |
| 336 | 390 | and ~EPSW_IE,epsw |
| 337 | 391 | mov fp,d0 |
| 338 | 392 | mov a2,d1 |
| 339 | 393 | call gdbstub_exception[],0 # gdbstub itself caused an exception |
| 340 | 394 | bra restore_all |
| 341 | 395 | 2: |
| 342 | −#endif | |
| 396 | +#endif /* CONFIG_GDBSTUB */ | |
| 343 | 397 | |
| 344 | 398 | mov fp,d0 # arg 0: stacked register file |
| 345 | 399 | mov a2,d1 # arg 1: exception number |
| @@ -374,11 +428,7 @@ ENTRY(set_excp_vector) · 28 unmodified lines | ||
| 374 | 428 | add exception_table,d0 |
| 375 | 429 | mov d1,(d0) |
| 376 | 430 | mov 4,d1 |
| 377 | −#if defined(CONFIG_MN10300_CACHE_WBACK) | |
| 378 | − jmp mn10300_dcache_flush_inv_range2 | |
| 379 | −#else | |
| 380 | 431 | ret [],0 |
| 381 | −#endif | |
| 382 | 432 | |
| 383 | 433 | ############################################################################### |
| 384 | 434 | # |
| @@ -8,25 +8,14 @@ · 7 unmodified lines | ||
| 8 | 8 | * as published by the Free Software Foundation; either version |
| 9 | 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | 10 | */ |
| 11 | +#include <linux/linkage.h> | |
| 11 | 12 | #include <asm/cpu-regs.h> |
| 13 | +#include <asm/smp.h> | |
| 14 | +#include <asm/thread_info.h> | |
| 15 | +#include <asm/asm-offsets.h> | |
| 16 | +#include <asm/frame.inc> | |
| 12 | 17 | |
| 13 | −############################################################################### | |
| 14 | −# | |
| 15 | −# void fpu_init_state(void) | |
| 16 | −# - initialise the FPU | |
| 17 | −# | |
| 18 | −############################################################################### | |
| 19 | − .globl fpu_init_state | |
| 20 | − .type fpu_init_state,@function | |
| 21 | −fpu_init_state: | |
| 22 | − mov epsw,d0 | |
| 23 | − or EPSW_FE,epsw | |
| 24 | − | |
| 25 | −#ifdef CONFIG_MN10300_PROC_MN103E010 | |
| 26 | − nop | |
| 27 | − nop | |
| 28 | − nop | |
| 29 | −#endif | |
| 18 | +.macro FPU_INIT_STATE_ALL | |
| 30 | 19 | fmov 0,fs0 |
| 31 | 20 | fmov fs0,fs1 |
| 32 | 21 | fmov fs0,fs2 |
| @@ -60,7 +49,100 @@ fpu_init_state: · 27 unmodified lines | ||
| 60 | 49 | fmov fs0,fs30 |
| 61 | 50 | fmov fs0,fs31 |
| 62 | 51 | fmov FPCR_INIT,fpcr |
| 52 | +.endm | |
| 53 | + | |
| 54 | +.macro FPU_SAVE_ALL areg,dreg | |
| 55 | + fmov fs0,(\areg+) | |
| 56 | + fmov fs1,(\areg+) | |
| 57 | + fmov fs2,(\areg+) | |
| 58 | + fmov fs3,(\areg+) | |
| 59 | + fmov fs4,(\areg+) | |
| 60 | + fmov fs5,(\areg+) | |
| 61 | + fmov fs6,(\areg+) | |
| 62 | + fmov fs7,(\areg+) | |
| 63 | + fmov fs8,(\areg+) | |
| 64 | + fmov fs9,(\areg+) | |
| 65 | + fmov fs10,(\areg+) | |
| 66 | + fmov fs11,(\areg+) | |
| 67 | + fmov fs12,(\areg+) | |
| 68 | + fmov fs13,(\areg+) | |
| 69 | + fmov fs14,(\areg+) | |
| 70 | + fmov fs15,(\areg+) | |
| 71 | + fmov fs16,(\areg+) | |
| 72 | + fmov fs17,(\areg+) | |
| 73 | + fmov fs18,(\areg+) | |
| 74 | + fmov fs19,(\areg+) | |
| 75 | + fmov fs20,(\areg+) | |
| 76 | + fmov fs21,(\areg+) | |
| 77 | + fmov fs22,(\areg+) | |
| 78 | + fmov fs23,(\areg+) | |
| 79 | + fmov fs24,(\areg+) | |
| 80 | + fmov fs25,(\areg+) | |
| 81 | + fmov fs26,(\areg+) | |
| 82 | + fmov fs27,(\areg+) | |
| 83 | + fmov fs28,(\areg+) | |
| 84 | + fmov fs29,(\areg+) | |
| 85 | + fmov fs30,(\areg+) | |
| 86 | + fmov fs31,(\areg+) | |
| 87 | + fmov fpcr,\dreg | |
| 88 | + mov \dreg,(\areg) | |
| 89 | +.endm | |
| 90 | + | |
| 91 | +.macro FPU_RESTORE_ALL areg,dreg | |
| 92 | + fmov (\areg+),fs0 | |
| 93 | + fmov (\areg+),fs1 | |
| 94 | + fmov (\areg+),fs2 | |
| 95 | + fmov (\areg+),fs3 | |
| 96 | + fmov (\areg+),fs4 | |
| 97 | + fmov (\areg+),fs5 | |
| 98 | + fmov (\areg+),fs6 | |
| 99 | + fmov (\areg+),fs7 | |
| 100 | + fmov (\areg+),fs8 | |
| 101 | + fmov (\areg+),fs9 | |
| 102 | + fmov (\areg+),fs10 | |
| 103 | + fmov (\areg+),fs11 | |
| 104 | + fmov (\areg+),fs12 | |
| 105 | + fmov (\areg+),fs13 | |
| 106 | + fmov (\areg+),fs14 | |
| 107 | + fmov (\areg+),fs15 | |
| 108 | + fmov (\areg+),fs16 | |
| 109 | + fmov (\areg+),fs17 | |
| 110 | + fmov (\areg+),fs18 | |
| 111 | + fmov (\areg+),fs19 | |
| 112 | + fmov (\areg+),fs20 | |
| 113 | + fmov (\areg+),fs21 | |
| 114 | + fmov (\areg+),fs22 | |
| 115 | + fmov (\areg+),fs23 | |
| 116 | + fmov (\areg+),fs24 | |
| 117 | + fmov (\areg+),fs25 | |
| 118 | + fmov (\areg+),fs26 | |
| 119 | + fmov (\areg+),fs27 | |
| 120 | + fmov (\areg+),fs28 | |
| 121 | + fmov (\areg+),fs29 | |
| 122 | + fmov (\areg+),fs30 | |
| 123 | + fmov (\areg+),fs31 | |
| 124 | + mov (\areg),\dreg | |
| 125 | + fmov \dreg,fpcr | |
| 126 | +.endm | |
| 63 | 127 | |
| 128 | +############################################################################### | |
| 129 | +# | |
| 130 | +# void fpu_init_state(void) | |
| 131 | +# - initialise the FPU | |
| 132 | +# | |
| 133 | +############################################################################### | |
| 134 | + .globl fpu_init_state | |
| 135 | + .type fpu_init_state,@function | |
| 136 | +fpu_init_state: | |
| 137 | + mov epsw,d0 | |
| 138 | + or EPSW_FE,epsw | |
| 139 | + | |
| 140 | +#ifdef CONFIG_MN10300_PROC_MN103E010 | |
| 141 | + nop | |
| 142 | + nop | |
| 143 | + nop | |
| 144 | +#endif | |
| 145 | + FPU_INIT_STATE_ALL | |
| 64 | 146 | #ifdef CONFIG_MN10300_PROC_MN103E010 |
| 65 | 147 | nop |
| 66 | 148 | nop |
| @@ -89,40 +171,7 @@ fpu_save: · 22 unmodified lines | ||
| 89 | 171 | nop |
| 90 | 172 | #endif |
| 91 | 173 | mov d0,a0 |
| 92 | − fmov fs0,(a0+) | |
| 93 | − fmov fs1,(a0+) | |
| 94 | − fmov fs2,(a0+) | |
| 95 | − fmov fs3,(a0+) | |
| 96 | − fmov fs4,(a0+) | |
| 97 | − fmov fs5,(a0+) | |
| 98 | − fmov fs6,(a0+) | |
| 99 | − fmov fs7,(a0+) | |
| 100 | − fmov fs8,(a0+) | |
| 101 | − fmov fs9,(a0+) | |
| 102 | − fmov fs10,(a0+) | |
| 103 | − fmov fs11,(a0+) | |
| 104 | − fmov fs12,(a0+) | |
| 105 | − fmov fs13,(a0+) | |
| 106 | − fmov fs14,(a0+) | |
| 107 | − fmov fs15,(a0+) | |
| 108 | − fmov fs16,(a0+) | |
| 109 | − fmov fs17,(a0+) | |
| 110 | − fmov fs18,(a0+) | |
| 111 | − fmov fs19,(a0+) | |
| 112 | − fmov fs20,(a0+) | |
| 113 | − fmov fs21,(a0+) | |
| 114 | − fmov fs22,(a0+) | |
| 115 | − fmov fs23,(a0+) | |
| 116 | − fmov fs24,(a0+) | |
| 117 | − fmov fs25,(a0+) | |
| 118 | − fmov fs26,(a0+) | |
| 119 | − fmov fs27,(a0+) | |
| 120 | − fmov fs28,(a0+) | |
| 121 | − fmov fs29,(a0+) | |
| 122 | − fmov fs30,(a0+) | |
| 123 | − fmov fs31,(a0+) | |
| 124 | − fmov fpcr,d0 | |
| 125 | − mov d0,(a0) | |
| 174 | + FPU_SAVE_ALL a0,d0 | |
| 126 | 175 | #ifdef CONFIG_MN10300_PROC_MN103E010 |
| 127 | 176 | nop |
| 128 | 177 | nop |
| @@ -135,63 +184,75 @@ fpu_save: · 6 unmodified lines | ||
| 135 | 184 | |
| 136 | 185 | ############################################################################### |
| 137 | 186 | # |
| 138 | −# void fpu_restore(struct fpu_state_struct *) | |
| 139 | −# - restore the fpu state | |
| 140 | −# - note that an FPU Operational exception might occur during this process | |
| 187 | +# void fpu_disabled(void) | |
| 188 | +# - handle an exception due to the FPU being disabled | |
| 189 | +# when CONFIG_FPU is enabled | |
| 141 | 190 | # |
| 142 | 191 | ############################################################################### |
| 143 | − .globl fpu_restore | |
| 144 | − .type fpu_restore,@function | |
| 145 | −fpu_restore: | |
| 146 | − mov epsw,d1 | |
| 147 | − or EPSW_FE,epsw /* enable the FPU so we can access it */ | |
| 148 | − | |
| 149 | −#ifdef CONFIG_MN10300_PROC_MN103E010 | |
| 192 | + .type fpu_disabled,@function | |
| 193 | + .globl fpu_disabled | |
| 194 | +fpu_disabled: | |
| 195 | + or EPSW_nAR|EPSW_FE,epsw | |
| 150 | 196 | nop |
| 151 | 197 | nop |
| 152 | −#endif | |
| 153 | − mov d0,a0 | |
| 154 | − fmov (a0+),fs0 | |
| 155 | − fmov (a0+),fs1 | |
| 156 | − fmov (a0+),fs2 | |
| 157 | − fmov (a0+),fs3 | |
| 158 | − fmov (a0+),fs4 | |
| 159 | − fmov (a0+),fs5 | |
| 160 | − fmov (a0+),fs6 | |
| 161 | − fmov (a0+),fs7 | |
| 162 | − fmov (a0+),fs8 | |
| 163 | − fmov (a0+),fs9 | |
| 164 | − fmov (a0+),fs10 | |
| 165 | − fmov (a0+),fs11 | |
| 166 | − fmov (a0+),fs12 | |
| 167 | − fmov (a0+),fs13 | |
| 168 | − fmov (a0+),fs14 | |
| 169 | − fmov (a0+),fs15 | |
| 170 | − fmov (a0+),fs16 | |
| 171 | − fmov (a0+),fs17 | |
| 172 | − fmov (a0+),fs18 | |
| 173 | − fmov (a0+),fs19 | |
| 174 | − fmov (a0+),fs20 | |
| 175 | − fmov (a0+),fs21 | |
| 176 | − fmov (a0+),fs22 | |
| 177 | − fmov (a0+),fs23 | |
| 178 | − fmov (a0+),fs24 | |
| 179 | − fmov (a0+),fs25 | |
| 180 | − fmov (a0+),fs26 | |
| 181 | − fmov (a0+),fs27 | |
| 182 | − fmov (a0+),fs28 | |
| 183 | − fmov (a0+),fs29 | |
| 184 | − fmov (a0+),fs30 | |
| 185 | − fmov (a0+),fs31 | |
| 186 | − mov (a0),d0 | |
| 187 | − fmov d0,fpcr | |
| 188 | −#ifdef CONFIG_MN10300_PROC_MN103E010 | |
| 189 | 198 | nop |
| 199 | + | |
| 200 | + mov sp,a1 | |
| 201 | + mov (a1),d1 /* get epsw of user context */ | |
| 202 | + and ~(THREAD_SIZE-1),a1 /* a1: (thread_info *ti) */ | |
| 203 | + mov (TI_task,a1),a2 /* a2: (task_struct *tsk) */ | |
| 204 | + btst EPSW_nSL,d1 | |
| 205 | + beq fpu_used_in_kernel | |
| 206 | + | |
| 207 | + or EPSW_FE,d1 | |
| 208 | + mov d1,(sp) | |
| 209 | + mov (TASK_THREAD+THREAD_FPU_FLAGS,a2),d1 | |
| 210 | +#ifndef CONFIG_LAZY_SAVE_FPU | |
| 211 | + or __THREAD_HAS_FPU,d1 | |
| 212 | + mov d1,(TASK_THREAD+THREAD_FPU_FLAGS,a2) | |
| 213 | +#else /* !CONFIG_LAZY_SAVE_FPU */ | |
| 214 | + mov (fpu_state_owner),a0 | |
| 215 | + cmp 0,a0 | |
| 216 | + beq fpu_regs_save_end | |
| 217 | + | |
| 218 | + mov (TASK_THREAD+THREAD_UREGS,a0),a1 | |
| 219 | + add TASK_THREAD+THREAD_FPU_STATE,a0 | |
| 220 | + FPU_SAVE_ALL a0,d0 | |
| 221 | + | |
| 222 | + mov (REG_EPSW,a1),d0 | |
| 223 | + and ~EPSW_FE,d0 | |
| 224 | + mov d0,(REG_EPSW,a1) | |
| 225 | + | |
| 226 | +fpu_regs_save_end: | |
| 227 | + mov a2,(fpu_state_owner) | |
| 228 | +#endif /* !CONFIG_LAZY_SAVE_FPU */ | |
| 229 | + | |
| 230 | + btst __THREAD_USING_FPU,d1 | |
| 231 | + beq fpu_regs_init | |
| 232 | + add TASK_THREAD+THREAD_FPU_STATE,a2 | |
| 233 | + FPU_RESTORE_ALL a2,d0 | |
| 234 | + rti | |
| 235 | + | |
| 236 | +fpu_regs_init: | |
| 237 | + FPU_INIT_STATE_ALL | |
| 238 | + add TASK_THREAD+THREAD_FPU_FLAGS,a2 | |
| 239 | + bset __THREAD_USING_FPU,(0,a2) | |
| 240 | + rti | |
| 241 | + | |
| 242 | +fpu_used_in_kernel: | |
| 243 | + and ~(EPSW_nAR|EPSW_FE),epsw | |
| 190 | 244 | nop |
| 191 | 245 | nop |
| 192 | −#endif | |
| 193 | 246 | |
| 194 | − mov d1,epsw | |
| 195 | − ret [],0 | |
| 247 | + add -4,sp | |
| 248 | + SAVE_ALL | |
| 249 | + mov -1,d0 | |
| 250 | + mov d0,(REG_ORIG_D0,fp) | |
| 251 | + | |
| 252 | + and ~EPSW_NMID,epsw | |
| 253 | + | |
| 254 | + mov fp,d0 | |
| 255 | + call fpu_disabled_in_kernel[],0 | |
| 256 | + jmp ret_from_exception | |
| 196 | 257 | |
| 197 | − .size fpu_restore,.-fpu_restore | |
| 258 | + .size fpu_disabled,.-fpu_disabled | |
| @@ -0,0 +1,39 @@ | ||
| 1 | +/* MN10300 Low level FPU management operations | |
| 2 | + * | |
| 3 | + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#include <linux/linkage.h> | |
| 12 | +#include <asm/cpu-regs.h> | |
| 13 | +#include <asm/smp.h> | |
| 14 | +#include <asm/thread_info.h> | |
| 15 | +#include <asm/asm-offsets.h> | |
| 16 | +#include <asm/frame.inc> | |
| 17 | + | |
| 18 | +############################################################################### | |
| 19 | +# | |
| 20 | +# void fpu_disabled(void) | |
| 21 | +# - handle an exception due to the FPU being disabled | |
| 22 | +# when CONFIG_FPU is disabled | |
| 23 | +# | |
| 24 | +############################################################################### | |
| 25 | + .type fpu_disabled,@function | |
| 26 | + .globl fpu_disabled | |
| 27 | +fpu_disabled: | |
| 28 | + add -4,sp | |
| 29 | + SAVE_ALL | |
| 30 | + mov -1,d0 | |
| 31 | + mov d0,(REG_ORIG_D0,fp) | |
| 32 | + | |
| 33 | + and ~EPSW_NMID,epsw | |
| 34 | + | |
| 35 | + mov fp,d0 | |
| 36 | + call unexpected_fpu_exception[],0 | |
| 37 | + jmp ret_from_exception | |
| 38 | + | |
| 39 | + .size fpu_disabled,.-fpu_disabled | |
| @@ -0,0 +1,30 @@ | ||
| 1 | +/* MN10300 FPU management | |
| 2 | + * | |
| 3 | + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#include <asm/fpu.h> | |
| 12 | + | |
| 13 | +/* | |
| 14 | + * handle an FPU operational exception | |
| 15 | + * - there's a possibility that if the FPU is asynchronous, the signal might | |
| 16 | + * be meant for a process other than the current one | |
| 17 | + */ | |
| 18 | +asmlinkage | |
| 19 | +void unexpected_fpu_exception(struct pt_regs *regs, enum exception_code code) | |
| 20 | +{ | |
| 21 | + panic("An FPU exception was received, but there's no FPU enabled."); | |
| 22 | +} | |
| 23 | + | |
| 24 | +/* | |
| 25 | + * fill in the FPU structure for a core dump | |
| 26 | + */ | |
| 27 | +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpreg) | |
| 28 | +{ | |
| 29 | + return 0; /* not valid */ | |
| 30 | +} | |
| @@ -12,56 +12,19 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <asm/fpu.h> |
| 13 | 13 | #include <asm/elf.h> |
| 14 | 14 | #include <asm/exceptions.h> |
| 15 | +#include <asm/system.h> | |
| 15 | 16 | |
| 17 | +#ifdef CONFIG_LAZY_SAVE_FPU | |
| 16 | 18 | struct task_struct *fpu_state_owner; |
| 19 | +#endif | |
| 17 | 20 | |
| 18 | 21 | /* |
| 19 | − * handle an exception due to the FPU being disabled | |
| 22 | + * error functions in FPU disabled exception | |
| 20 | 23 | */ |
| 21 | −asmlinkage void fpu_disabled(struct pt_regs *regs, enum exception_code code) | |
| 24 | +asmlinkage void fpu_disabled_in_kernel(struct pt_regs *regs) | |
| 22 | 25 | { |
| 23 | − struct task_struct *tsk = current; | |
| 24 | − | |
| 25 | − if (!user_mode(regs)) | |
| 26 | − die_if_no_fixup("An FPU Disabled exception happened in" | |
| 27 | − " kernel space\n", | |
| 28 | − regs, code); | |
| 29 | − | |
| 30 | −#ifdef CONFIG_FPU | |
| 31 | − preempt_disable(); | |
| 32 | − | |
| 33 | − /* transfer the last process's FPU state to memory */ | |
| 34 | − if (fpu_state_owner) { | |
| 35 | − fpu_save(&fpu_state_owner->thread.fpu_state); | |
| 36 | − fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE; | |
| 37 | − } | |
| 38 | − | |
| 39 | − /* the current process now owns the FPU state */ | |
| 40 | − fpu_state_owner = tsk; | |
| 41 | − regs->epsw |= EPSW_FE; | |
| 42 | − | |
| 43 | − /* load the FPU with the current process's FPU state or invent a new | |
| 44 | − * clean one if the process doesn't have one */ | |
| 45 | − if (is_using_fpu(tsk)) { | |
| 46 | − fpu_restore(&tsk->thread.fpu_state); | |
| 47 | − } else { | |
| 48 | − fpu_init_state(); | |
| 49 | − set_using_fpu(tsk); | |
| 50 | − } | |
| 51 | − | |
| 52 | − preempt_enable(); | |
| 53 | −#else | |
| 54 | − { | |
| 55 | − siginfo_t info; | |
| 56 | − | |
| 57 | − info.si_signo = SIGFPE; | |
| 58 | − info.si_errno = 0; | |
| 59 | − info.si_addr = (void *) tsk->thread.uregs->pc; | |
| 60 | − info.si_code = FPE_FLTINV; | |
| 61 | − | |
| 62 | − force_sig_info(SIGFPE, &info, tsk); | |
| 63 | − } | |
| 64 | −#endif /* CONFIG_FPU */ | |
| 26 | + die_if_no_fixup("An FPU Disabled exception happened in kernel space\n", | |
| 27 | + regs, EXCEP_FPU_DISABLED); | |
| 65 | 28 | } |
| 66 | 29 | |
| 67 | 30 | /* |
| @@ -71,15 +34,16 @@ asmlinkage void fpu_disabled(struct pt_regs *regs, enum exception_code code) · 3 unmodified lines | ||
| 71 | 34 | */ |
| 72 | 35 | asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code) |
| 73 | 36 | { |
| 74 | − struct task_struct *tsk = fpu_state_owner; | |
| 37 | + struct task_struct *tsk = current; | |
| 75 | 38 | siginfo_t info; |
| 39 | + u32 fpcr; | |
| 76 | 40 | |
| 77 | 41 | if (!user_mode(regs)) |
| 78 | 42 | die_if_no_fixup("An FPU Operation exception happened in" |
| 79 | 43 | " kernel space\n", |
| 80 | 44 | regs, code); |
| 81 | 45 | |
| 82 | − if (!tsk) | |
| 46 | + if (!is_using_fpu(tsk)) | |
| 83 | 47 | die_if_no_fixup("An FPU Operation exception happened," |
| 84 | 48 | " but the FPU is not in use", |
| 85 | 49 | regs, code); |
| @@ -89,48 +53,45 @@ asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code) · 3 unmodified lines | ||
| 89 | 53 | info.si_addr = (void *) tsk->thread.uregs->pc; |
| 90 | 54 | info.si_code = FPE_FLTINV; |
| 91 | 55 | |
| 92 | −#ifdef CONFIG_FPU | |
| 93 | − { | |
| 94 | − u32 fpcr; | |
| 56 | + unlazy_fpu(tsk); | |
| 95 | 57 | |
| 96 | − /* get FPCR (we need to enable the FPU whilst we do this) */ | |
| 97 | − asm volatile(" or %1,epsw \n" | |
| 98 | −#ifdef CONFIG_MN10300_PROC_MN103E010 | |
| 99 | − " nop \n" | |
| 100 | − " nop \n" | |
| 101 | − " nop \n" | |
| 102 | −#endif | |
| 103 | − " fmov fpcr,%0 \n" | |
| 104 | −#ifdef CONFIG_MN10300_PROC_MN103E010 | |
| 105 | − " nop \n" | |
| 106 | − " nop \n" | |
| 107 | − " nop \n" | |
| 108 | −#endif | |
| 109 | − " and %2,epsw \n" | |
| 110 | − : "=&d"(fpcr) | |
| 111 | − : "i"(EPSW_FE), "i"(~EPSW_FE) | |
| 112 | − ); | |
| 113 | − | |
| 114 | − if (fpcr & FPCR_EC_Z) | |
| 115 | − info.si_code = FPE_FLTDIV; | |
| 116 | − else if (fpcr & FPCR_EC_O) | |
| 117 | − info.si_code = FPE_FLTOVF; | |
| 118 | − else if (fpcr & FPCR_EC_U) | |
| 119 | − info.si_code = FPE_FLTUND; | |
| 120 | − else if (fpcr & FPCR_EC_I) | |
| 121 | − info.si_code = FPE_FLTRES; | |
| 122 | − } | |
| 123 | −#endif | |
| 58 | + fpcr = tsk->thread.fpu_state.fpcr; | |
| 59 | + | |
| 60 | + if (fpcr & FPCR_EC_Z) | |
| 61 | + info.si_code = FPE_FLTDIV; | |
| 62 | + else if (fpcr & FPCR_EC_O) | |
| 63 | + info.si_code = FPE_FLTOVF; | |
| 64 | + else if (fpcr & FPCR_EC_U) | |
| 65 | + info.si_code = FPE_FLTUND; | |
| 66 | + else if (fpcr & FPCR_EC_I) | |
| 67 | + info.si_code = FPE_FLTRES; | |
| 124 | 68 | |
| 125 | 69 | force_sig_info(SIGFPE, &info, tsk); |
| 126 | 70 | } |
| 127 | 71 | |
| 72 | +/* | |
| 73 | + * handle an FPU invalid_op exception | |
| 74 | + * - Derived from DO_EINFO() macro in arch/mn10300/kernel/traps.c | |
| 75 | + */ | |
| 76 | +asmlinkage void fpu_invalid_op(struct pt_regs *regs, enum exception_code code) | |
| 77 | +{ | |
| 78 | + siginfo_t info; | |
| 79 | + | |
| 80 | + if (!user_mode(regs)) | |
| 81 | + die_if_no_fixup("FPU invalid opcode", regs, code); | |
| 82 | + | |
| 83 | + info.si_signo = SIGILL; | |
| 84 | + info.si_errno = 0; | |
| 85 | + info.si_code = ILL_COPROC; | |
| 86 | + info.si_addr = (void *) regs->pc; | |
| 87 | + force_sig_info(info.si_signo, &info, current); | |
| 88 | +} | |
| 89 | + | |
| 128 | 90 | /* |
| 129 | 91 | * save the FPU state to a signal context |
| 130 | 92 | */ |
| 131 | 93 | int fpu_setup_sigcontext(struct fpucontext *fpucontext) |
| 132 | 94 | { |
| 133 | −#ifdef CONFIG_FPU | |
| 134 | 95 | struct task_struct *tsk = current; |
| 135 | 96 | |
| 136 | 97 | if (!is_using_fpu(tsk)) |
| @@ -142,11 +103,19 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext) · 5 unmodified lines | ||
| 142 | 103 | */ |
| 143 | 104 | preempt_disable(); |
| 144 | 105 | |
| 106 | +#ifndef CONFIG_LAZY_SAVE_FPU | |
| 107 | + if (tsk->thread.fpu_flags & THREAD_HAS_FPU) { | |
| 108 | + fpu_save(&tsk->thread.fpu_state); | |
| 109 | + tsk->thread.uregs->epsw &= ~EPSW_FE; | |
| 110 | + tsk->thread.fpu_flags &= ~THREAD_HAS_FPU; | |
| 111 | + } | |
| 112 | +#else /* !CONFIG_LAZY_SAVE_FPU */ | |
| 145 | 113 | if (fpu_state_owner == tsk) { |
| 146 | 114 | fpu_save(&tsk->thread.fpu_state); |
| 147 | 115 | fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE; |
| 148 | 116 | fpu_state_owner = NULL; |
| 149 | 117 | } |
| 118 | +#endif /* !CONFIG_LAZY_SAVE_FPU */ | |
| 150 | 119 | |
| 151 | 120 | preempt_enable(); |
| 152 | 121 | |
| @@ -161,9 +130,6 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext) · 8 unmodified lines | ||
| 161 | 130 | return -1; |
| 162 | 131 | |
| 163 | 132 | return 1; |
| 164 | −#else | |
| 165 | − return 0; | |
| 166 | −#endif | |
| 167 | 133 | } |
| 168 | 134 | |
| 169 | 135 | /* |
| @@ -171,17 +137,23 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext) · 1 unmodified line | ||
| 171 | 137 | */ |
| 172 | 138 | void fpu_kill_state(struct task_struct *tsk) |
| 173 | 139 | { |
| 174 | −#ifdef CONFIG_FPU | |
| 175 | 140 | /* disown anything left in the FPU */ |
| 176 | 141 | preempt_disable(); |
| 177 | 142 | |
| 143 | +#ifndef CONFIG_LAZY_SAVE_FPU | |
| 144 | + if (tsk->thread.fpu_flags & THREAD_HAS_FPU) { | |
| 145 | + tsk->thread.uregs->epsw &= ~EPSW_FE; | |
| 146 | + tsk->thread.fpu_flags &= ~THREAD_HAS_FPU; | |
| 147 | + } | |
| 148 | +#else /* !CONFIG_LAZY_SAVE_FPU */ | |
| 178 | 149 | if (fpu_state_owner == tsk) { |
| 179 | 150 | fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE; |
| 180 | 151 | fpu_state_owner = NULL; |
| 181 | 152 | } |
| 153 | +#endif /* !CONFIG_LAZY_SAVE_FPU */ | |
| 182 | 154 | |
| 183 | 155 | preempt_enable(); |
| 184 | −#endif | |
| 156 | + | |
| 185 | 157 | /* we no longer have a valid current FPU state */ |
| 186 | 158 | clear_using_fpu(tsk); |
| 187 | 159 | } |
| @@ -195,8 +167,7 @@ int fpu_restore_sigcontext(struct fpucontext *fpucontext) · 7 unmodified lines | ||
| 195 | 167 | int ret; |
| 196 | 168 | |
| 197 | 169 | /* load up the old FPU state */ |
| 198 | − ret = copy_from_user(&tsk->thread.fpu_state, | |
| 199 | − fpucontext, | |
| 170 | + ret = copy_from_user(&tsk->thread.fpu_state, fpucontext, | |
| 200 | 171 | min(sizeof(struct fpu_state_struct), |
| 201 | 172 | sizeof(struct fpucontext))); |
| 202 | 173 | if (!ret) |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <asm/thread_info.h> |
| 19 | 19 | #include <asm/frame.inc> |
| 20 | 20 | #include <asm/intctl-regs.h> |
| 21 | +#include <asm/irqflags.h> | |
| 21 | 22 | #include <unit/serial.h> |
| 22 | 23 | |
| 23 | 24 | .text |
| @@ -69,7 +70,7 @@ gdbstub_io_rx_overflow: · 45 unmodified lines | ||
| 69 | 70 | bra gdbstub_io_rx_done |
| 70 | 71 | |
| 71 | 72 | gdbstub_io_rx_enter: |
| 72 | − or EPSW_IE|EPSW_IM_1,epsw | |
| 73 | + LOCAL_CHANGE_INTR_MASK_LEVEL(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL+1)) | |
| 73 | 74 | add -4,sp |
| 74 | 75 | SAVE_ALL |
| 75 | 76 | |
| @@ -80,7 +81,7 @@ gdbstub_io_rx_enter: · 4 unmodified lines | ||
| 80 | 81 | mov fp,d0 |
| 81 | 82 | call gdbstub_rx_irq[],0 # gdbstub_rx_irq(regs,excep) |
| 82 | 83 | |
| 83 | − and ~EPSW_IE,epsw | |
| 84 | + LOCAL_CLI | |
| 84 | 85 | bclr 0x01,(gdbstub_busy) |
| 85 | 86 | |
| 86 | 87 | .globl gdbstub_return |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | #include <asm/exceptions.h> |
| 24 | 24 | #include <asm/serial-regs.h> |
| 25 | 25 | #include <unit/serial.h> |
| 26 | +#include <asm/smp.h> | |
| 26 | 27 | |
| 27 | 28 | /* |
| 28 | 29 | * initialise the GDB stub |
| @@ -45,22 +46,34 @@ void gdbstub_io_init(void) · 16 unmodified lines | ||
| 45 | 46 | XIRQxICR(GDBPORT_SERIAL_IRQ) = 0; |
| 46 | 47 | tmp = XIRQxICR(GDBPORT_SERIAL_IRQ); |
| 47 | 48 | |
| 49 | +#if CONFIG_GDBSTUB_IRQ_LEVEL == 0 | |
| 48 | 50 | IVAR0 = EXCEP_IRQ_LEVEL0; |
| 49 | − set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler); | |
| 51 | +#elif CONFIG_GDBSTUB_IRQ_LEVEL == 1 | |
| 52 | + IVAR1 = EXCEP_IRQ_LEVEL1; | |
| 53 | +#elif CONFIG_GDBSTUB_IRQ_LEVEL == 2 | |
| 54 | + IVAR2 = EXCEP_IRQ_LEVEL2; | |
| 55 | +#elif CONFIG_GDBSTUB_IRQ_LEVEL == 3 | |
| 56 | + IVAR3 = EXCEP_IRQ_LEVEL3; | |
| 57 | +#elif CONFIG_GDBSTUB_IRQ_LEVEL == 4 | |
| 58 | + IVAR4 = EXCEP_IRQ_LEVEL4; | |
| 59 | +#elif CONFIG_GDBSTUB_IRQ_LEVEL == 5 | |
| 60 | + IVAR5 = EXCEP_IRQ_LEVEL5; | |
| 61 | +#else | |
| 62 | +#error "Unknown irq level for gdbstub." | |
| 63 | +#endif | |
| 64 | + | |
| 65 | + set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL), | |
| 66 | + gdbstub_io_rx_handler); | |
| 50 | 67 | |
| 51 | 68 | XIRQxICR(GDBPORT_SERIAL_IRQ) &= ~GxICR_REQUEST; |
| 52 | − XIRQxICR(GDBPORT_SERIAL_IRQ) = GxICR_ENABLE | GxICR_LEVEL_0; | |
| 69 | + XIRQxICR(GDBPORT_SERIAL_IRQ) = | |
| 70 | + GxICR_ENABLE | NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL); | |
| 53 | 71 | tmp = XIRQxICR(GDBPORT_SERIAL_IRQ); |
| 54 | 72 | |
| 55 | 73 | GDBPORT_SERIAL_IER = UART_IER_RDI | UART_IER_RLSI; |
| 56 | 74 | |
| 57 | 75 | /* permit level 0 IRQs to take place */ |
| 58 | − asm volatile( | |
| 59 | − " and %0,epsw \n" | |
| 60 | − " or %1,epsw \n" | |
| 61 | − : | |
| 62 | − : "i"(~EPSW_IM), "i"(EPSW_IE | EPSW_IM_1) | |
| 63 | − ); | |
| 76 | + local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); | |
| 64 | 77 | } |
| 65 | 78 | |
| 66 | 79 | /* |
| @@ -87,6 +100,9 @@ int gdbstub_io_rx_char(unsigned char *_ch, int nonblock) · 20 unmodified lines | ||
| 87 | 100 | { |
| 88 | 101 | unsigned ix; |
| 89 | 102 | u8 ch, st; |
| 103 | +#if defined(CONFIG_MN10300_WD_TIMER) | |
| 104 | + int cpu; | |
| 105 | +#endif | |
| 90 | 106 | |
| 91 | 107 | *_ch = 0xff; |
| 92 | 108 | |
| @@ -104,8 +120,9 @@ int gdbstub_io_rx_char(unsigned char *_ch, int nonblock) · 11 unmodified lines | ||
| 104 | 120 | if (nonblock) |
| 105 | 121 | return -EAGAIN; |
| 106 | 122 | #ifdef CONFIG_MN10300_WD_TIMER |
| 107 | − watchdog_alert_counter = 0; | |
| 108 | −#endif /* CONFIG_MN10300_WD_TIMER */ | |
| 123 | + for (cpu = 0; cpu < NR_CPUS; cpu++) | |
| 124 | + watchdog_alert_counter[cpu] = 0; | |
| 125 | +#endif | |
| 109 | 126 | goto try_again; |
| 110 | 127 | } |
| 111 | 128 | |
| @@ -58,9 +58,12 @@ void __init gdbstub_io_init(void) · 57 unmodified lines | ||
| 58 | 58 | gdbstub_io_set_baud(115200); |
| 59 | 59 | |
| 60 | 60 | /* we want to get serial receive interrupts */ |
| 61 | − set_intr_level(gdbstub_port->rx_irq, GxICR_LEVEL_0); | |
| 62 | − set_intr_level(gdbstub_port->tx_irq, GxICR_LEVEL_0); | |
| 63 | − set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler); | |
| 61 | + set_intr_level(gdbstub_port->rx_irq, | |
| 62 | + NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL)); | |
| 63 | + set_intr_level(gdbstub_port->tx_irq, | |
| 64 | + NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL)); | |
| 65 | + set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL), | |
| 66 | + gdbstub_io_rx_handler); | |
| 64 | 67 | |
| 65 | 68 | *gdbstub_port->rx_icr |= GxICR_ENABLE; |
| 66 | 69 | tmp = *gdbstub_port->rx_icr; |
| @@ -84,12 +87,7 @@ void __init gdbstub_io_init(void) · 17 unmodified lines | ||
| 84 | 87 | tmp = *gdbstub_port->_control; |
| 85 | 88 | |
| 86 | 89 | /* permit level 0 IRQs only */ |
| 87 | − asm volatile( | |
| 88 | − " and %0,epsw \n" | |
| 89 | − " or %1,epsw \n" | |
| 90 | − : | |
| 91 | − : "i"(~EPSW_IM), "i"(EPSW_IE|EPSW_IM_1) | |
| 92 | − ); | |
| 90 | + local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); | |
| 93 | 91 | } |
| 94 | 92 | |
| 95 | 93 | /* |
| @@ -184,6 +182,9 @@ int gdbstub_io_rx_char(unsigned char *_ch, int nonblock) · 88 unmodified lines | ||
| 184 | 182 | { |
| 185 | 183 | unsigned ix; |
| 186 | 184 | u8 ch, st; |
| 185 | +#if defined(CONFIG_MN10300_WD_TIMER) | |
| 186 | + int cpu; | |
| 187 | +#endif | |
| 187 | 188 | |
| 188 | 189 | *_ch = 0xff; |
| 189 | 190 | |
| @@ -201,8 +202,9 @@ try_again: · 11 unmodified lines | ||
| 201 | 202 | if (nonblock) |
| 202 | 203 | return -EAGAIN; |
| 203 | 204 | #ifdef CONFIG_MN10300_WD_TIMER |
| 204 | − watchdog_alert_counter = 0; | |
| 205 | −#endif /* CONFIG_MN10300_WD_TIMER */ | |
| 205 | + for (cpu = 0; cpu < NR_CPUS; cpu++) | |
| 206 | + watchdog_alert_counter[cpu] = 0; | |
| 207 | +#endif | |
| 206 | 208 | goto try_again; |
| 207 | 209 | } |
| 208 | 210 | |
| @@ -440,15 +440,11 @@ static const unsigned char gdbstub_insn_sizes[256] = · 439 unmodified lines | ||
| 440 | 440 | |
| 441 | 441 | static int __gdbstub_mark_bp(u8 *addr, int ix) |
| 442 | 442 | { |
| 443 | − if (addr < (u8 *) 0x70000000UL) | |
| 444 | − return 0; | |
| 445 | − /* 70000000-7fffffff: vmalloc area */ | |
| 446 | − if (addr < (u8 *) 0x80000000UL) | |
| 443 | + /* vmalloc area */ | |
| 444 | + if (((u8 *) VMALLOC_START <= addr) && (addr < (u8 *) VMALLOC_END)) | |
| 447 | 445 | goto okay; |
| 448 | − if (addr < (u8 *) 0x8c000000UL) | |
| 449 | − return 0; | |
| 450 | − /* 8c000000-93ffffff: SRAM, SDRAM */ | |
| 451 | − if (addr < (u8 *) 0x94000000UL) | |
| 446 | + /* SRAM, SDRAM */ | |
| 447 | + if (((u8 *) 0x80000000UL <= addr) && (addr < (u8 *) 0xa0000000UL)) | |
| 452 | 448 | goto okay; |
| 453 | 449 | return 0; |
| 454 | 450 | |
| @@ -1197,9 +1193,8 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep) · 742 unmodified lines | ||
| 1197 | 1193 | mn10300_set_gdbleds(1); |
| 1198 | 1194 | |
| 1199 | 1195 | asm volatile("mov mdr,%0" : "=d"(mdr)); |
| 1200 | − asm volatile("mov epsw,%0" : "=d"(epsw)); | |
| 1201 | − asm volatile("mov %0,epsw" | |
| 1202 | − :: "d"((epsw & ~EPSW_IM) | EPSW_IE | EPSW_IM_1)); | |
| 1196 | + local_save_flags(epsw); | |
| 1197 | + local_change_intr_mask_level(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1)); | |
| 1203 | 1198 | |
| 1204 | 1199 | gdbstub_store_fpu(); |
| 1205 | 1200 | |
| @@ -19,6 +19,12 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <asm/frame.inc> |
| 20 | 20 | #include <asm/param.h> |
| 21 | 21 | #include <unit/serial.h> |
| 22 | +#ifdef CONFIG_SMP | |
| 23 | +#include <asm/smp.h> | |
| 24 | +#include <asm/intctl-regs.h> | |
| 25 | +#include <asm/cpu-regs.h> | |
| 26 | +#include <proc/smp-regs.h> | |
| 27 | +#endif /* CONFIG_SMP */ | |
| 22 | 28 | |
| 23 | 29 | __HEAD |
| 24 | 30 | |
| @@ -30,17 +36,51 @@ · 5 unmodified lines | ||
| 30 | 36 | .globl _start |
| 31 | 37 | .type _start,@function |
| 32 | 38 | _start: |
| 39 | +#ifdef CONFIG_SMP | |
| 40 | + # | |
| 41 | + # If this is a secondary CPU (AP), then deal with that elsewhere | |
| 42 | + # | |
| 43 | + mov (CPUID),d3 | |
| 44 | + and CPUID_MASK,d3 | |
| 45 | + bne startup_secondary | |
| 46 | + | |
| 47 | + # | |
| 48 | + # We're dealing with the primary CPU (BP) here, then. | |
| 49 | + # Keep BP's D0,D1,D2 register for boot check. | |
| 50 | + # | |
| 51 | + | |
| 52 | + # Set up the Boot IPI for each secondary CPU | |
| 53 | + mov 0x1,a0 | |
| 54 | +loop_set_secondary_icr: | |
| 55 | + mov a0,a1 | |
| 56 | + asl CROSS_ICR_CPU_SHIFT,a1 | |
| 57 | + add CROSS_GxICR(SMP_BOOT_IRQ,0),a1 | |
| 58 | + movhu (a1),d3 | |
| 59 | + or GxICR_ENABLE|GxICR_LEVEL_0,d3 | |
| 60 | + movhu d3,(a1) | |
| 61 | + movhu (a1),d3 # flush | |
| 62 | + inc a0 | |
| 63 | + cmp NR_CPUS,a0 | |
| 64 | + bne loop_set_secondary_icr | |
| 65 | +#endif /* CONFIG_SMP */ | |
| 66 | + | |
| 33 | 67 | # save commandline pointer |
| 34 | 68 | mov d0,a3 |
| 35 | 69 | |
| 36 | 70 | # preload the PGD pointer register |
| 37 | 71 | mov swapper_pg_dir,d0 |
| 38 | 72 | mov d0,(PTBR) |
| 73 | + clr d0 | |
| 74 | + movbu d0,(PIDR) | |
| 39 | 75 | |
| 40 | 76 | # turn on the TLBs |
| 41 | 77 | mov MMUCTR_IIV|MMUCTR_DIV,d0 |
| 42 | 78 | mov d0,(MMUCTR) |
| 79 | +#ifdef CONFIG_AM34_2 | |
| 80 | + mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE|MMUCTR_WTE,d0 | |
| 81 | +#else | |
| 43 | 82 | mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0 |
| 83 | +#endif | |
| 44 | 84 | mov d0,(MMUCTR) |
| 45 | 85 | |
| 46 | 86 | # turn on AM33v2 exception handling mode and set the trap table base |
| @@ -51,6 +91,11 @@ _start: · 4 unmodified lines | ||
| 51 | 91 | mov d0,(TBR) |
| 52 | 92 | |
| 53 | 93 | # invalidate and enable both of the caches |
| 94 | +#ifdef CONFIG_SMP | |
| 95 | + mov ECHCTR,a0 | |
| 96 | + clr d0 | |
| 97 | + mov d0,(a0) | |
| 98 | +#endif | |
| 54 | 99 | mov CHCTR,a0 |
| 55 | 100 | clr d0 |
| 56 | 101 | movhu d0,(a0) # turn off first |
| @@ -61,18 +106,18 @@ _start: · 4 unmodified lines | ||
| 61 | 106 | btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy |
| 62 | 107 | lne |
| 63 | 108 | |
| 64 | −#ifndef CONFIG_MN10300_CACHE_DISABLED | |
| 109 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 65 | 110 | #ifdef CONFIG_MN10300_CACHE_WBACK |
| 66 | 111 | #ifndef CONFIG_MN10300_CACHE_WBACK_NOWRALLOC |
| 67 | 112 | mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0 |
| 68 | 113 | #else |
| 69 | 114 | mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK|CHCTR_DCALMD,d0 |
| 70 | −#endif /* CACHE_DISABLED */ | |
| 115 | +#endif /* NOWRALLOC */ | |
| 71 | 116 | #else |
| 72 | 117 | mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0 |
| 73 | 118 | #endif /* WBACK */ |
| 74 | 119 | movhu d0,(a0) # enable |
| 75 | −#endif /* NOWRALLOC */ | |
| 120 | +#endif /* ENABLED */ | |
| 76 | 121 | |
| 77 | 122 | # turn on RTS on the debug serial port if applicable |
| 78 | 123 | #ifdef CONFIG_MN10300_UNIT_ASB2305 |
| @@ -206,6 +251,44 @@ __no_parameters: · 127 unmodified lines | ||
| 206 | 251 | call processor_init[],0 |
| 207 | 252 | call unit_init[],0 |
| 208 | 253 | |
| 254 | +#ifdef CONFIG_SMP | |
| 255 | + # mark the primary CPU in cpu_boot_map | |
| 256 | + mov cpu_boot_map,a0 | |
| 257 | + mov 0x1,d0 | |
| 258 | + mov d0,(a0) | |
| 259 | + | |
| 260 | + # signal each secondary CPU to begin booting | |
| 261 | + mov 0x1,d2 # CPU ID | |
| 262 | + | |
| 263 | +loop_request_boot_secondary: | |
| 264 | + mov d2,a0 | |
| 265 | + # send SMP_BOOT_IPI to secondary CPU | |
| 266 | + asl CROSS_ICR_CPU_SHIFT,a0 | |
| 267 | + add CROSS_GxICR(SMP_BOOT_IRQ,0),a0 | |
| 268 | + movhu (a0),d0 | |
| 269 | + or GxICR_REQUEST|GxICR_DETECT,d0 | |
| 270 | + movhu d0,(a0) | |
| 271 | + movhu (a0),d0 # flush | |
| 272 | + | |
| 273 | + # wait up to 100ms for AP's IPI to be received | |
| 274 | + clr d3 | |
| 275 | +wait_on_secondary_boot: | |
| 276 | + mov DELAY_TIME_BOOT_IPI,d0 | |
| 277 | + call __delay[],0 | |
| 278 | + inc d3 | |
| 279 | + mov cpu_boot_map,a0 | |
| 280 | + mov (a0),d0 | |
| 281 | + lsr d2,d0 | |
| 282 | + btst 0x1,d0 | |
| 283 | + bne 1f | |
| 284 | + cmp TIME_OUT_COUNT_BOOT_IPI,d3 | |
| 285 | + bne wait_on_secondary_boot | |
| 286 | +1: | |
| 287 | + inc d2 | |
| 288 | + cmp NR_CPUS,d2 | |
| 289 | + bne loop_request_boot_secondary | |
| 290 | +#endif /* CONFIG_SMP */ | |
| 291 | + | |
| 209 | 292 | #ifdef CONFIG_GDBSTUB |
| 210 | 293 | call gdbstub_init[],0 |
| 211 | 294 | |
| @@ -217,7 +300,118 @@ __gdbstub_pause: · 5 unmodified lines | ||
| 217 | 300 | #endif |
| 218 | 301 | |
| 219 | 302 | jmp start_kernel |
| 220 | − .size _start, _start-. | |
| 303 | + .size _start,.-_start | |
| 304 | + | |
| 305 | +############################################################################### | |
| 306 | +# | |
| 307 | +# Secondary CPU boot point | |
| 308 | +# | |
| 309 | +############################################################################### | |
| 310 | +#ifdef CONFIG_SMP | |
| 311 | +startup_secondary: | |
| 312 | + # preload the PGD pointer register | |
| 313 | + mov swapper_pg_dir,d0 | |
| 314 | + mov d0,(PTBR) | |
| 315 | + clr d0 | |
| 316 | + movbu d0,(PIDR) | |
| 317 | + | |
| 318 | + # turn on the TLBs | |
| 319 | + mov MMUCTR_IIV|MMUCTR_DIV,d0 | |
| 320 | + mov d0,(MMUCTR) | |
| 321 | +#ifdef CONFIG_AM34_2 | |
| 322 | + mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE|MMUCTR_WTE,d0 | |
| 323 | +#else | |
| 324 | + mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0 | |
| 325 | +#endif | |
| 326 | + mov d0,(MMUCTR) | |
| 327 | + | |
| 328 | + # turn on AM33v2 exception handling mode and set the trap table base | |
| 329 | + movhu (CPUP),d0 | |
| 330 | + or CPUP_EXM_AM33V2,d0 | |
| 331 | + movhu d0,(CPUP) | |
| 332 | + | |
| 333 | + # set the interrupt vector table | |
| 334 | + mov CONFIG_INTERRUPT_VECTOR_BASE,d0 | |
| 335 | + mov d0,(TBR) | |
| 336 | + | |
| 337 | + # invalidate and enable both of the caches | |
| 338 | + mov ECHCTR,a0 | |
| 339 | + clr d0 | |
| 340 | + mov d0,(a0) | |
| 341 | + mov CHCTR,a0 | |
| 342 | + clr d0 | |
| 343 | + movhu d0,(a0) # turn off first | |
| 344 | + mov CHCTR_ICINV|CHCTR_DCINV,d0 | |
| 345 | + movhu d0,(a0) | |
| 346 | + setlb | |
| 347 | + mov (a0),d0 | |
| 348 | + btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy (use CPU loop buffer) | |
| 349 | + lne | |
| 350 | + | |
| 351 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 352 | +#ifdef CONFIG_MN10300_CACHE_WBACK | |
| 353 | +#ifndef CONFIG_MN10300_CACHE_WBACK_NOWRALLOC | |
| 354 | + mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0 | |
| 355 | +#else | |
| 356 | + mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK|CHCTR_DCALMD,d0 | |
| 357 | +#endif /* !NOWRALLOC */ | |
| 358 | +#else | |
| 359 | + mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0 | |
| 360 | +#endif /* WBACK */ | |
| 361 | + movhu d0,(a0) # enable | |
| 362 | +#endif /* ENABLED */ | |
| 363 | + | |
| 364 | + # Clear the boot IPI interrupt for this CPU | |
| 365 | + movhu (GxICR(SMP_BOOT_IRQ)),d0 | |
| 366 | + and ~GxICR_REQUEST,d0 | |
| 367 | + movhu d0,(GxICR(SMP_BOOT_IRQ)) | |
| 368 | + movhu (GxICR(SMP_BOOT_IRQ)),d0 # flush | |
| 369 | + | |
| 370 | + /* get stack */ | |
| 371 | + mov CONFIG_INTERRUPT_VECTOR_BASE + CONFIG_BOOT_STACK_OFFSET,a0 | |
| 372 | + mov (CPUID),d0 | |
| 373 | + and CPUID_MASK,d0 | |
| 374 | + mulu CONFIG_BOOT_STACK_SIZE,d0 | |
| 375 | + sub d0,a0 | |
| 376 | + mov a0,sp | |
| 377 | + | |
| 378 | + # init interrupt for AP | |
| 379 | + call smp_prepare_cpu_init[],0 | |
| 380 | + | |
| 381 | + # mark this secondary CPU in cpu_boot_map | |
| 382 | + mov (CPUID),d0 | |
| 383 | + mov 0x1,d1 | |
| 384 | + asl d0,d1 | |
| 385 | + mov cpu_boot_map,a0 | |
| 386 | + bset d1,(a0) | |
| 387 | + | |
| 388 | + or EPSW_IE|EPSW_IM_1,epsw # permit level 0 interrupts | |
| 389 | + nop | |
| 390 | + nop | |
| 391 | +#ifdef CONFIG_MN10300_CACHE_WBACK | |
| 392 | + # flush the local cache if it's in writeback mode | |
| 393 | + call mn10300_local_dcache_flush_inv[],0 | |
| 394 | + setlb | |
| 395 | + mov (CHCTR),d0 | |
| 396 | + btst CHCTR_DCBUSY,d0 # wait till not busy (use CPU loop buffer) | |
| 397 | + lne | |
| 398 | +#endif | |
| 399 | + | |
| 400 | + # now sleep waiting for further instructions | |
| 401 | +secondary_sleep: | |
| 402 | + mov CPUM_SLEEP,d0 | |
| 403 | + movhu d0,(CPUM) | |
| 404 | + nop | |
| 405 | + nop | |
| 406 | + bra secondary_sleep | |
| 407 | + .size startup_secondary,.-startup_secondary | |
| 408 | +#endif /* CONFIG_SMP */ | |
| 409 | + | |
| 410 | +############################################################################### | |
| 411 | +# | |
| 412 | +# | |
| 413 | +# | |
| 414 | +############################################################################### | |
| 221 | 415 | ENTRY(__head_end) |
| 222 | 416 | |
| 223 | 417 | /* |
| @@ -9,6 +9,9 @@ · 8 unmodified lines | ||
| 9 | 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | +struct clocksource; | |
| 13 | +struct clock_event_device; | |
| 14 | + | |
| 12 | 15 | /* |
| 13 | 16 | * kthread.S |
| 14 | 17 | */ |
| @@ -18,3 +21,25 @@ extern int kernel_thread_helper(int); · 3 unmodified lines | ||
| 18 | 21 | * entry.S |
| 19 | 22 | */ |
| 20 | 23 | extern void ret_from_fork(struct task_struct *) __attribute__((noreturn)); |
| 24 | + | |
| 25 | +/* | |
| 26 | + * smp-low.S | |
| 27 | + */ | |
| 28 | +#ifdef CONFIG_SMP | |
| 29 | +extern void mn10300_low_ipi_handler(void); | |
| 30 | +#endif | |
| 31 | + | |
| 32 | +/* | |
| 33 | + * time.c | |
| 34 | + */ | |
| 35 | +extern irqreturn_t local_timer_interrupt(void); | |
| 36 | + | |
| 37 | +/* | |
| 38 | + * time.c | |
| 39 | + */ | |
| 40 | +#ifdef CONFIG_CEVT_MN10300 | |
| 41 | +extern void clockevent_set_clock(struct clock_event_device *, unsigned int); | |
| 42 | +#endif | |
| 43 | +#ifdef CONFIG_CSRC_MN10300 | |
| 44 | +extern void clocksource_set_clock(struct clocksource *, unsigned int); | |
| 45 | +#endif | |
| @@ -12,11 +12,26 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <linux/interrupt.h> |
| 13 | 13 | #include <linux/kernel_stat.h> |
| 14 | 14 | #include <linux/seq_file.h> |
| 15 | +#include <linux/cpumask.h> | |
| 15 | 16 | #include <asm/setup.h> |
| 17 | +#include <asm/serial-regs.h> | |
| 16 | 18 | |
| 17 | −unsigned long __mn10300_irq_enabled_epsw = EPSW_IE | EPSW_IM_7; | |
| 19 | +unsigned long __mn10300_irq_enabled_epsw[NR_CPUS] __cacheline_aligned_in_smp = { | |
| 20 | + [0 ... NR_CPUS - 1] = EPSW_IE | EPSW_IM_7 | |
| 21 | +}; | |
| 18 | 22 | EXPORT_SYMBOL(__mn10300_irq_enabled_epsw); |
| 19 | 23 | |
| 24 | +#ifdef CONFIG_SMP | |
| 25 | +static char irq_affinity_online[NR_IRQS] = { | |
| 26 | + [0 ... NR_IRQS - 1] = 0 | |
| 27 | +}; | |
| 28 | + | |
| 29 | +#define NR_IRQ_WORDS ((NR_IRQS + 31) / 32) | |
| 30 | +static unsigned long irq_affinity_request[NR_IRQ_WORDS] = { | |
| 31 | + [0 ... NR_IRQ_WORDS - 1] = 0 | |
| 32 | +}; | |
| 33 | +#endif /* CONFIG_SMP */ | |
| 34 | + | |
| 20 | 35 | atomic_t irq_err_count; |
| 21 | 36 | |
| 22 | 37 | /* |
| @@ -24,30 +39,67 @@ atomic_t irq_err_count; · 1 unmodified line | ||
| 24 | 39 | */ |
| 25 | 40 | static void mn10300_cpupic_ack(unsigned int irq) |
| 26 | 41 | { |
| 42 | + unsigned long flags; | |
| 27 | 43 | u16 tmp; |
| 28 | − *(volatile u8 *) &GxICR(irq) = GxICR_DETECT; | |
| 44 | + | |
| 45 | + flags = arch_local_cli_save(); | |
| 46 | + GxICR_u8(irq) = GxICR_DETECT; | |
| 29 | 47 | tmp = GxICR(irq); |
| 48 | + arch_local_irq_restore(flags); | |
| 30 | 49 | } |
| 31 | 50 | |
| 32 | −static void mn10300_cpupic_mask(unsigned int irq) | |
| 51 | +static void __mask_and_set_icr(unsigned int irq, | |
| 52 | + unsigned int mask, unsigned int set) | |
| 33 | 53 | { |
| 34 | − u16 tmp = GxICR(irq); | |
| 35 | − GxICR(irq) = (tmp & GxICR_LEVEL); | |
| 54 | + unsigned long flags; | |
| 55 | + u16 tmp; | |
| 56 | + | |
| 57 | + flags = arch_local_cli_save(); | |
| 58 | + tmp = GxICR(irq); | |
| 59 | + GxICR(irq) = (tmp & mask) | set; | |
| 36 | 60 | tmp = GxICR(irq); |
| 61 | + arch_local_irq_restore(flags); | |
| 62 | +} | |
| 63 | + | |
| 64 | +static void mn10300_cpupic_mask(unsigned int irq) | |
| 65 | +{ | |
| 66 | + __mask_and_set_icr(irq, GxICR_LEVEL, 0); | |
| 37 | 67 | } |
| 38 | 68 | |
| 39 | 69 | static void mn10300_cpupic_mask_ack(unsigned int irq) |
| 40 | 70 | { |
| 41 | − u16 tmp = GxICR(irq); | |
| 42 | − GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT; | |
| 43 | − tmp = GxICR(irq); | |
| 71 | +#ifdef CONFIG_SMP | |
| 72 | + unsigned long flags; | |
| 73 | + u16 tmp; | |
| 74 | + | |
| 75 | + flags = arch_local_cli_save(); | |
| 76 | + | |
| 77 | + if (!test_and_clear_bit(irq, irq_affinity_request)) { | |
| 78 | + tmp = GxICR(irq); | |
| 79 | + GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT; | |
| 80 | + tmp = GxICR(irq); | |
| 81 | + } else { | |
| 82 | + u16 tmp2; | |
| 83 | + tmp = GxICR(irq); | |
| 84 | + GxICR(irq) = (tmp & GxICR_LEVEL); | |
| 85 | + tmp2 = GxICR(irq); | |
| 86 | + | |
| 87 | + irq_affinity_online[irq] = | |
| 88 | + any_online_cpu(*irq_desc[irq].affinity); | |
| 89 | + CROSS_GxICR(irq, irq_affinity_online[irq]) = | |
| 90 | + (tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT; | |
| 91 | + tmp = CROSS_GxICR(irq, irq_affinity_online[irq]); | |
| 92 | + } | |
| 93 | + | |
| 94 | + arch_local_irq_restore(flags); | |
| 95 | +#else /* CONFIG_SMP */ | |
| 96 | + __mask_and_set_icr(irq, GxICR_LEVEL, GxICR_DETECT); | |
| 97 | +#endif /* CONFIG_SMP */ | |
| 44 | 98 | } |
| 45 | 99 | |
| 46 | 100 | static void mn10300_cpupic_unmask(unsigned int irq) |
| 47 | 101 | { |
| 48 | − u16 tmp = GxICR(irq); | |
| 49 | − GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE; | |
| 50 | − tmp = GxICR(irq); | |
| 102 | + __mask_and_set_icr(irq, GxICR_LEVEL, GxICR_ENABLE); | |
| 51 | 103 | } |
| 52 | 104 | |
| 53 | 105 | static void mn10300_cpupic_unmask_clear(unsigned int irq) |
| @@ -56,11 +108,89 @@ static void mn10300_cpupic_unmask_clear(unsigned int irq) · 2 unmodified lines | ||
| 56 | 108 | * device has ceased to assert its interrupt line and the interrupt |
| 57 | 109 | * channel has been disabled in the PIC, so for level-triggered |
| 58 | 110 | * interrupts we need to clear the request bit when we re-enable */ |
| 59 | − u16 tmp = GxICR(irq); | |
| 60 | − GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT; | |
| 61 | − tmp = GxICR(irq); | |
| 111 | +#ifdef CONFIG_SMP | |
| 112 | + unsigned long flags; | |
| 113 | + u16 tmp; | |
| 114 | + | |
| 115 | + flags = arch_local_cli_save(); | |
| 116 | + | |
| 117 | + if (!test_and_clear_bit(irq, irq_affinity_request)) { | |
| 118 | + tmp = GxICR(irq); | |
| 119 | + GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT; | |
| 120 | + tmp = GxICR(irq); | |
| 121 | + } else { | |
| 122 | + tmp = GxICR(irq); | |
| 123 | + | |
| 124 | + irq_affinity_online[irq] = any_online_cpu(*irq_desc[irq].affinity); | |
| 125 | + CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT; | |
| 126 | + tmp = CROSS_GxICR(irq, irq_affinity_online[irq]); | |
| 127 | + } | |
| 128 | + | |
| 129 | + arch_local_irq_restore(flags); | |
| 130 | +#else /* CONFIG_SMP */ | |
| 131 | + __mask_and_set_icr(irq, GxICR_LEVEL, GxICR_ENABLE | GxICR_DETECT); | |
| 132 | +#endif /* CONFIG_SMP */ | |
| 62 | 133 | } |
| 63 | 134 | |
| 135 | +#ifdef CONFIG_SMP | |
| 136 | +static int | |
| 137 | +mn10300_cpupic_setaffinity(unsigned int irq, const struct cpumask *mask) | |
| 138 | +{ | |
| 139 | + unsigned long flags; | |
| 140 | + int err; | |
| 141 | + | |
| 142 | + flags = arch_local_cli_save(); | |
| 143 | + | |
| 144 | + /* check irq no */ | |
| 145 | + switch (irq) { | |
| 146 | + case TMJCIRQ: | |
| 147 | + case RESCHEDULE_IPI: | |
| 148 | + case CALL_FUNC_SINGLE_IPI: | |
| 149 | + case LOCAL_TIMER_IPI: | |
| 150 | + case FLUSH_CACHE_IPI: | |
| 151 | + case CALL_FUNCTION_NMI_IPI: | |
| 152 | + case GDB_NMI_IPI: | |
| 153 | +#ifdef CONFIG_MN10300_TTYSM0 | |
| 154 | + case SC0RXIRQ: | |
| 155 | + case SC0TXIRQ: | |
| 156 | +#ifdef CONFIG_MN10300_TTYSM0_TIMER8 | |
| 157 | + case TM8IRQ: | |
| 158 | +#elif CONFIG_MN10300_TTYSM0_TIMER2 | |
| 159 | + case TM2IRQ: | |
| 160 | +#endif /* CONFIG_MN10300_TTYSM0_TIMER8 */ | |
| 161 | +#endif /* CONFIG_MN10300_TTYSM0 */ | |
| 162 | + | |
| 163 | +#ifdef CONFIG_MN10300_TTYSM1 | |
| 164 | + case SC1RXIRQ: | |
| 165 | + case SC1TXIRQ: | |
| 166 | +#ifdef CONFIG_MN10300_TTYSM1_TIMER12 | |
| 167 | + case TM12IRQ: | |
| 168 | +#elif CONFIG_MN10300_TTYSM1_TIMER9 | |
| 169 | + case TM9IRQ: | |
| 170 | +#elif CONFIG_MN10300_TTYSM1_TIMER3 | |
| 171 | + case TM3IRQ: | |
| 172 | +#endif /* CONFIG_MN10300_TTYSM1_TIMER12 */ | |
| 173 | +#endif /* CONFIG_MN10300_TTYSM1 */ | |
| 174 | + | |
| 175 | +#ifdef CONFIG_MN10300_TTYSM2 | |
| 176 | + case SC2RXIRQ: | |
| 177 | + case SC2TXIRQ: | |
| 178 | + case TM10IRQ: | |
| 179 | +#endif /* CONFIG_MN10300_TTYSM2 */ | |
| 180 | + err = -1; | |
| 181 | + break; | |
| 182 | + | |
| 183 | + default: | |
| 184 | + set_bit(irq, irq_affinity_request); | |
| 185 | + err = 0; | |
| 186 | + break; | |
| 187 | + } | |
| 188 | + | |
| 189 | + arch_local_irq_restore(flags); | |
| 190 | + return err; | |
| 191 | +} | |
| 192 | +#endif /* CONFIG_SMP */ | |
| 193 | + | |
| 64 | 194 | /* |
| 65 | 195 | * MN10300 PIC level-triggered IRQ handling. |
| 66 | 196 | * |
| @@ -79,6 +209,9 @@ static struct irq_chip mn10300_cpu_pic_level = { · 12 unmodified lines | ||
| 79 | 209 | .mask = mn10300_cpupic_mask, |
| 80 | 210 | .mask_ack = mn10300_cpupic_mask, |
| 81 | 211 | .unmask = mn10300_cpupic_unmask_clear, |
| 212 | +#ifdef CONFIG_SMP | |
| 213 | + .set_affinity = mn10300_cpupic_setaffinity, | |
| 214 | +#endif | |
| 82 | 215 | }; |
| 83 | 216 | |
| 84 | 217 | /* |
| @@ -94,6 +227,9 @@ static struct irq_chip mn10300_cpu_pic_edge = { · 9 unmodified lines | ||
| 94 | 227 | .mask = mn10300_cpupic_mask, |
| 95 | 228 | .mask_ack = mn10300_cpupic_mask_ack, |
| 96 | 229 | .unmask = mn10300_cpupic_unmask, |
| 230 | +#ifdef CONFIG_SMP | |
| 231 | + .set_affinity = mn10300_cpupic_setaffinity, | |
| 232 | +#endif | |
| 97 | 233 | }; |
| 98 | 234 | |
| 99 | 235 | /* |
| @@ -111,14 +247,34 @@ void ack_bad_irq(int irq) · 11 unmodified lines | ||
| 111 | 247 | */ |
| 112 | 248 | void set_intr_level(int irq, u16 level) |
| 113 | 249 | { |
| 114 | − u16 tmp; | |
| 250 | + BUG_ON(in_interrupt()); | |
| 115 | 251 | |
| 116 | − if (in_interrupt()) | |
| 117 | − BUG(); | |
| 252 | + __mask_and_set_icr(irq, GxICR_ENABLE, level); | |
| 253 | +} | |
| 118 | 254 | |
| 119 | − tmp = GxICR(irq); | |
| 120 | − GxICR(irq) = (tmp & GxICR_ENABLE) | level; | |
| 121 | − tmp = GxICR(irq); | |
| 255 | +void mn10300_intc_set_level(unsigned int irq, unsigned int level) | |
| 256 | +{ | |
| 257 | + set_intr_level(irq, NUM2GxICR_LEVEL(level) & GxICR_LEVEL); | |
| 258 | +} | |
| 259 | + | |
| 260 | +void mn10300_intc_clear(unsigned int irq) | |
| 261 | +{ | |
| 262 | + __mask_and_set_icr(irq, GxICR_LEVEL | GxICR_ENABLE, GxICR_DETECT); | |
| 263 | +} | |
| 264 | + | |
| 265 | +void mn10300_intc_set(unsigned int irq) | |
| 266 | +{ | |
| 267 | + __mask_and_set_icr(irq, 0, GxICR_REQUEST | GxICR_DETECT); | |
| 268 | +} | |
| 269 | + | |
| 270 | +void mn10300_intc_enable(unsigned int irq) | |
| 271 | +{ | |
| 272 | + mn10300_cpupic_unmask(irq); | |
| 273 | +} | |
| 274 | + | |
| 275 | +void mn10300_intc_disable(unsigned int irq) | |
| 276 | +{ | |
| 277 | + mn10300_cpupic_mask(irq); | |
| 122 | 278 | } |
| 123 | 279 | |
| 124 | 280 | /* |
| @@ -126,7 +282,7 @@ void set_intr_level(int irq, u16 level) · 1 unmodified line | ||
| 126 | 282 | * than before |
| 127 | 283 | * - see Documentation/mn10300/features.txt |
| 128 | 284 | */ |
| 129 | −void set_intr_postackable(int irq) | |
| 285 | +void mn10300_set_lateack_irq_type(int irq) | |
| 130 | 286 | { |
| 131 | 287 | set_irq_chip_and_handler(irq, &mn10300_cpu_pic_level, |
| 132 | 288 | handle_level_irq); |
| @@ -147,6 +303,7 @@ void __init init_IRQ(void) · 14 unmodified lines | ||
| 147 | 303 | * interrupts */ |
| 148 | 304 | set_irq_chip_and_handler(irq, &mn10300_cpu_pic_edge, |
| 149 | 305 | handle_level_irq); |
| 306 | + | |
| 150 | 307 | unit_init_IRQ(); |
| 151 | 308 | } |
| 152 | 309 | |
| @@ -156,20 +313,22 @@ void __init init_IRQ(void) · 3 unmodified lines | ||
| 156 | 313 | asmlinkage void do_IRQ(void) |
| 157 | 314 | { |
| 158 | 315 | unsigned long sp, epsw, irq_disabled_epsw, old_irq_enabled_epsw; |
| 316 | + unsigned int cpu_id = smp_processor_id(); | |
| 159 | 317 | int irq; |
| 160 | 318 | |
| 161 | 319 | sp = current_stack_pointer(); |
| 162 | − if (sp - (sp & ~(THREAD_SIZE - 1)) < STACK_WARN) | |
| 163 | − BUG(); | |
| 320 | + BUG_ON(sp - (sp & ~(THREAD_SIZE - 1)) < STACK_WARN); | |
| 164 | 321 | |
| 165 | 322 | /* make sure local_irq_enable() doesn't muck up the interrupt priority |
| 166 | 323 | * setting in EPSW */ |
| 167 | − old_irq_enabled_epsw = __mn10300_irq_enabled_epsw; | |
| 324 | + old_irq_enabled_epsw = __mn10300_irq_enabled_epsw[cpu_id]; | |
| 168 | 325 | local_save_flags(epsw); |
| 169 | − __mn10300_irq_enabled_epsw = EPSW_IE | (EPSW_IM & epsw); | |
| 326 | + __mn10300_irq_enabled_epsw[cpu_id] = EPSW_IE | (EPSW_IM & epsw); | |
| 170 | 327 | irq_disabled_epsw = EPSW_IE | MN10300_CLI_LEVEL; |
| 171 | 328 | |
| 172 | − __IRQ_STAT(smp_processor_id(), __irq_count)++; | |
| 329 | +#ifdef CONFIG_MN10300_WD_TIMER | |
| 330 | + __IRQ_STAT(cpu_id, __irq_count)++; | |
| 331 | +#endif | |
| 173 | 332 | |
| 174 | 333 | irq_enter(); |
| 175 | 334 | |
| @@ -189,7 +348,7 @@ asmlinkage void do_IRQ(void) · 13 unmodified lines | ||
| 189 | 348 | local_irq_restore(epsw); |
| 190 | 349 | } |
| 191 | 350 | |
| 192 | − __mn10300_irq_enabled_epsw = old_irq_enabled_epsw; | |
| 351 | + __mn10300_irq_enabled_epsw[cpu_id] = old_irq_enabled_epsw; | |
| 193 | 352 | |
| 194 | 353 | irq_exit(); |
| 195 | 354 | } |
| @@ -222,9 +381,16 @@ int show_interrupts(struct seq_file *p, void *v) · 26 unmodified lines | ||
| 222 | 381 | seq_printf(p, "%3d: ", i); |
| 223 | 382 | for_each_present_cpu(cpu) |
| 224 | 383 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu)); |
| 225 | − seq_printf(p, " %14s.%u", irq_desc[i].chip->name, | |
| 226 | − (GxICR(i) & GxICR_LEVEL) >> | |
| 227 | − GxICR_LEVEL_SHIFT); | |
| 384 | + | |
| 385 | + if (i < NR_CPU_IRQS) | |
| 386 | + seq_printf(p, " %14s.%u", | |
| 387 | + irq_desc[i].chip->name, | |
| 388 | + (GxICR(i) & GxICR_LEVEL) >> | |
| 389 | + GxICR_LEVEL_SHIFT); | |
| 390 | + else | |
| 391 | + seq_printf(p, " %14s", | |
| 392 | + irq_desc[i].chip->name); | |
| 393 | + | |
| 228 | 394 | seq_printf(p, " %s", action->name); |
| 229 | 395 | |
| 230 | 396 | for (action = action->next; |
| @@ -240,11 +406,13 @@ int show_interrupts(struct seq_file *p, void *v) · 9 unmodified lines | ||
| 240 | 406 | |
| 241 | 407 | /* polish off with NMI and error counters */ |
| 242 | 408 | case NR_IRQS: |
| 409 | +#ifdef CONFIG_MN10300_WD_TIMER | |
| 243 | 410 | seq_printf(p, "NMI: "); |
| 244 | 411 | for (j = 0; j < NR_CPUS; j++) |
| 245 | 412 | if (cpu_online(j)) |
| 246 | 413 | seq_printf(p, "%10u ", nmi_count(j)); |
| 247 | 414 | seq_putc(p, '\n'); |
| 415 | +#endif | |
| 248 | 416 | |
| 249 | 417 | seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); |
| 250 | 418 | break; |
| @@ -252,3 +420,51 @@ int show_interrupts(struct seq_file *p, void *v) · 1 unmodified line | ||
| 252 | 420 | |
| 253 | 421 | return 0; |
| 254 | 422 | } |
| 423 | + | |
| 424 | +#ifdef CONFIG_HOTPLUG_CPU | |
| 425 | +void migrate_irqs(void) | |
| 426 | +{ | |
| 427 | + irq_desc_t *desc; | |
| 428 | + int irq; | |
| 429 | + unsigned int self, new; | |
| 430 | + unsigned long flags; | |
| 431 | + | |
| 432 | + self = smp_processor_id(); | |
| 433 | + for (irq = 0; irq < NR_IRQS; irq++) { | |
| 434 | + desc = irq_desc + irq; | |
| 435 | + | |
| 436 | + if (desc->status == IRQ_PER_CPU) | |
| 437 | + continue; | |
| 438 | + | |
| 439 | + if (cpu_isset(self, irq_desc[irq].affinity) && | |
| 440 | + !cpus_intersects(irq_affinity[irq], cpu_online_map)) { | |
| 441 | + int cpu_id; | |
| 442 | + cpu_id = first_cpu(cpu_online_map); | |
| 443 | + cpu_set(cpu_id, irq_desc[irq].affinity); | |
| 444 | + } | |
| 445 | + /* We need to operate irq_affinity_online atomically. */ | |
| 446 | + arch_local_cli_save(flags); | |
| 447 | + if (irq_affinity_online[irq] == self) { | |
| 448 | + u16 x, tmp; | |
| 449 | + | |
| 450 | + x = GxICR(irq); | |
| 451 | + GxICR(irq) = x & GxICR_LEVEL; | |
| 452 | + tmp = GxICR(irq); | |
| 453 | + | |
| 454 | + new = any_online_cpu(irq_desc[irq].affinity); | |
| 455 | + irq_affinity_online[irq] = new; | |
| 456 | + | |
| 457 | + CROSS_GxICR(irq, new) = | |
| 458 | + (x & GxICR_LEVEL) | GxICR_DETECT; | |
| 459 | + tmp = CROSS_GxICR(irq, new); | |
| 460 | + | |
| 461 | + x &= GxICR_LEVEL | GxICR_ENABLE; | |
| 462 | + if (GxICR(irq) & GxICR_REQUEST) { | |
| 463 | + x |= GxICR_REQUEST | GxICR_DETECT; | |
| 464 | + CROSS_GxICR(irq, new) = x; | |
| 465 | + tmp = CROSS_GxICR(irq, new); | |
| 466 | + } | |
| 467 | + arch_local_irq_restore(flags); | |
| 468 | + } | |
| 469 | +} | |
| 470 | +#endif /* CONFIG_HOTPLUG_CPU */ | |
| @@ -377,8 +377,10 @@ void __kprobes arch_arm_kprobe(struct kprobe *p) · 376 unmodified lines | ||
| 377 | 377 | |
| 378 | 378 | void __kprobes arch_disarm_kprobe(struct kprobe *p) |
| 379 | 379 | { |
| 380 | +#ifndef CONFIG_MN10300_CACHE_SNOOP | |
| 380 | 381 | mn10300_dcache_flush(); |
| 381 | 382 | mn10300_icache_inv(); |
| 383 | +#endif | |
| 382 | 384 | } |
| 383 | 385 | |
| 384 | 386 | void arch_remove_kprobe(struct kprobe *p) |
| @@ -390,8 +392,10 @@ void __kprobes disarm_kprobe(struct kprobe *p, struct pt_regs *regs) · 5 unmodified lines | ||
| 390 | 392 | { |
| 391 | 393 | *p->addr = p->opcode; |
| 392 | 394 | regs->pc = (unsigned long) p->addr; |
| 395 | +#ifndef CONFIG_MN10300_CACHE_SNOOP | |
| 393 | 396 | mn10300_dcache_flush(); |
| 394 | 397 | mn10300_icache_inv(); |
| 398 | +#endif | |
| 395 | 399 | } |
| 396 | 400 | |
| 397 | 401 | static inline |
| @@ -39,7 +39,7 @@ · 38 unmodified lines | ||
| 39 | 39 | ############################################################################### |
| 40 | 40 | .balign L1_CACHE_BYTES |
| 41 | 41 | ENTRY(mn10300_serial_vdma_interrupt) |
| 42 | − or EPSW_IE,psw # permit overriding by | |
| 42 | +# or EPSW_IE,psw # permit overriding by | |
| 43 | 43 | # debugging interrupts |
| 44 | 44 | movm [d2,d3,a2,a3,exreg0],(sp) |
| 45 | 45 | |
| @@ -164,7 +164,7 @@ mnsc_vdma_tx_noint: · 118 unmodified lines | ||
| 164 | 164 | rti |
| 165 | 165 | |
| 166 | 166 | mnsc_vdma_tx_empty: |
| 167 | − mov +(GxICR_LEVEL_1|GxICR_DETECT),d2 | |
| 167 | + mov +(NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)|GxICR_DETECT),d2 | |
| 168 | 168 | movhu d2,(e3) # disable the interrupt |
| 169 | 169 | movhu (e3),d2 # flush |
| 170 | 170 | |
| @@ -175,7 +175,7 @@ mnsc_vdma_tx_break: · 4 unmodified lines | ||
| 175 | 175 | movhu (SCxCTR,e2),d2 # turn on break mode |
| 176 | 176 | or SC01CTR_BKE,d2 |
| 177 | 177 | movhu d2,(SCxCTR,e2) |
| 178 | − mov +(GxICR_LEVEL_1|GxICR_DETECT),d2 | |
| 178 | + mov +(NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)|GxICR_DETECT),d2 | |
| 179 | 179 | movhu d2,(e3) # disable transmit interrupts on this |
| 180 | 180 | # channel |
| 181 | 181 | movhu (e3),d2 # flush |
| @@ -44,6 +44,11 @@ static const char serial_revdate[] = "2007-11-06"; · 43 unmodified lines | ||
| 44 | 44 | #include <unit/timex.h> |
| 45 | 45 | #include "mn10300-serial.h" |
| 46 | 46 | |
| 47 | +#ifdef CONFIG_SMP | |
| 48 | +#undef GxICR | |
| 49 | +#define GxICR(X) CROSS_GxICR(X, 0) | |
| 50 | +#endif /* CONFIG_SMP */ | |
| 51 | + | |
| 47 | 52 | #define kenter(FMT, ...) \ |
| 48 | 53 | printk(KERN_DEBUG "-->%s(" FMT ")\n", __func__, ##__VA_ARGS__) |
| 49 | 54 | #define _enter(FMT, ...) \ |
| @@ -57,6 +62,11 @@ static const char serial_revdate[] = "2007-11-06"; · 7 unmodified lines | ||
| 57 | 62 | #define _proto(FMT, ...) \ |
| 58 | 63 | no_printk(KERN_DEBUG "### MNSERIAL " FMT " ###\n", ##__VA_ARGS__) |
| 59 | 64 | |
| 65 | +#ifndef CODMSB | |
| 66 | +/* c_cflag bit meaning */ | |
| 67 | +#define CODMSB 004000000000 /* change Transfer bit-order */ | |
| 68 | +#endif | |
| 69 | + | |
| 60 | 70 | #define NR_UARTS 3 |
| 61 | 71 | |
| 62 | 72 | #ifdef CONFIG_MN10300_TTYSM_CONSOLE |
| @@ -152,26 +162,35 @@ struct mn10300_serial_port mn10300_serial_port_sif0 = { · 89 unmodified lines | ||
| 152 | 162 | .name = "ttySM0", |
| 153 | 163 | ._iobase = &SC0CTR, |
| 154 | 164 | ._control = &SC0CTR, |
| 155 | − ._status = (volatile u8 *) &SC0STR, | |
| 165 | + ._status = (volatile u8 *)&SC0STR, | |
| 156 | 166 | ._intr = &SC0ICR, |
| 157 | 167 | ._rxb = &SC0RXB, |
| 158 | 168 | ._txb = &SC0TXB, |
| 159 | 169 | .rx_name = "ttySM0:Rx", |
| 160 | 170 | .tx_name = "ttySM0:Tx", |
| 161 | −#ifdef CONFIG_MN10300_TTYSM0_TIMER8 | |
| 171 | +#if defined(CONFIG_MN10300_TTYSM0_TIMER8) | |
| 162 | 172 | .tm_name = "ttySM0:Timer8", |
| 163 | 173 | ._tmxmd = &TM8MD, |
| 164 | 174 | ._tmxbr = &TM8BR, |
| 165 | 175 | ._tmicr = &TM8ICR, |
| 166 | 176 | .tm_irq = TM8IRQ, |
| 167 | 177 | .div_timer = MNSCx_DIV_TIMER_16BIT, |
| 168 | −#else /* CONFIG_MN10300_TTYSM0_TIMER2 */ | |
| 178 | +#elif defined(CONFIG_MN10300_TTYSM0_TIMER0) | |
| 179 | + .tm_name = "ttySM0:Timer0", | |
| 180 | + ._tmxmd = &TM0MD, | |
| 181 | + ._tmxbr = (volatile u16 *)&TM0BR, | |
| 182 | + ._tmicr = &TM0ICR, | |
| 183 | + .tm_irq = TM0IRQ, | |
| 184 | + .div_timer = MNSCx_DIV_TIMER_8BIT, | |
| 185 | +#elif defined(CONFIG_MN10300_TTYSM0_TIMER2) | |
| 169 | 186 | .tm_name = "ttySM0:Timer2", |
| 170 | 187 | ._tmxmd = &TM2MD, |
| 171 | − ._tmxbr = (volatile u16 *) &TM2BR, | |
| 188 | + ._tmxbr = (volatile u16 *)&TM2BR, | |
| 172 | 189 | ._tmicr = &TM2ICR, |
| 173 | 190 | .tm_irq = TM2IRQ, |
| 174 | 191 | .div_timer = MNSCx_DIV_TIMER_8BIT, |
| 192 | +#else | |
| 193 | +#error "Unknown config for ttySM0" | |
| 175 | 194 | #endif |
| 176 | 195 | .rx_irq = SC0RXIRQ, |
| 177 | 196 | .tx_irq = SC0TXIRQ, |
| @@ -205,26 +224,35 @@ struct mn10300_serial_port mn10300_serial_port_sif1 = { · 27 unmodified lines | ||
| 205 | 224 | .name = "ttySM1", |
| 206 | 225 | ._iobase = &SC1CTR, |
| 207 | 226 | ._control = &SC1CTR, |
| 208 | − ._status = (volatile u8 *) &SC1STR, | |
| 227 | + ._status = (volatile u8 *)&SC1STR, | |
| 209 | 228 | ._intr = &SC1ICR, |
| 210 | 229 | ._rxb = &SC1RXB, |
| 211 | 230 | ._txb = &SC1TXB, |
| 212 | 231 | .rx_name = "ttySM1:Rx", |
| 213 | 232 | .tx_name = "ttySM1:Tx", |
| 214 | −#ifdef CONFIG_MN10300_TTYSM1_TIMER9 | |
| 233 | +#if defined(CONFIG_MN10300_TTYSM1_TIMER9) | |
| 215 | 234 | .tm_name = "ttySM1:Timer9", |
| 216 | 235 | ._tmxmd = &TM9MD, |
| 217 | 236 | ._tmxbr = &TM9BR, |
| 218 | 237 | ._tmicr = &TM9ICR, |
| 219 | 238 | .tm_irq = TM9IRQ, |
| 220 | 239 | .div_timer = MNSCx_DIV_TIMER_16BIT, |
| 221 | −#else /* CONFIG_MN10300_TTYSM1_TIMER3 */ | |
| 240 | +#elif defined(CONFIG_MN10300_TTYSM1_TIMER3) | |
| 222 | 241 | .tm_name = "ttySM1:Timer3", |
| 223 | 242 | ._tmxmd = &TM3MD, |
| 224 | − ._tmxbr = (volatile u16 *) &TM3BR, | |
| 243 | + ._tmxbr = (volatile u16 *)&TM3BR, | |
| 225 | 244 | ._tmicr = &TM3ICR, |
| 226 | 245 | .tm_irq = TM3IRQ, |
| 227 | 246 | .div_timer = MNSCx_DIV_TIMER_8BIT, |
| 247 | +#elif defined(CONFIG_MN10300_TTYSM1_TIMER12) | |
| 248 | + .tm_name = "ttySM1/Timer12", | |
| 249 | + ._tmxmd = &TM12MD, | |
| 250 | + ._tmxbr = &TM12BR, | |
| 251 | + ._tmicr = &TM12ICR, | |
| 252 | + .tm_irq = TM12IRQ, | |
| 253 | + .div_timer = MNSCx_DIV_TIMER_16BIT, | |
| 254 | +#else | |
| 255 | +#error "Unknown config for ttySM1" | |
| 228 | 256 | #endif |
| 229 | 257 | .rx_irq = SC1RXIRQ, |
| 230 | 258 | .tx_irq = SC1TXIRQ, |
| @@ -260,20 +288,45 @@ struct mn10300_serial_port mn10300_serial_port_sif2 = { · 29 unmodified lines | ||
| 260 | 288 | .uart.lock = |
| 261 | 289 | __SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif2.uart.lock), |
| 262 | 290 | .name = "ttySM2", |
| 263 | − .rx_name = "ttySM2:Rx", | |
| 264 | − .tx_name = "ttySM2:Tx", | |
| 265 | − .tm_name = "ttySM2:Timer10", | |
| 266 | 291 | ._iobase = &SC2CTR, |
| 267 | 292 | ._control = &SC2CTR, |
| 268 | − ._status = &SC2STR, | |
| 293 | + ._status = (volatile u8 *)&SC2STR, | |
| 269 | 294 | ._intr = &SC2ICR, |
| 270 | 295 | ._rxb = &SC2RXB, |
| 271 | 296 | ._txb = &SC2TXB, |
| 297 | + .rx_name = "ttySM2:Rx", | |
| 298 | + .tx_name = "ttySM2:Tx", | |
| 299 | +#if defined(CONFIG_MN10300_TTYSM2_TIMER10) | |
| 300 | + .tm_name = "ttySM2/Timer10", | |
| 272 | 301 | ._tmxmd = &TM10MD, |
| 273 | 302 | ._tmxbr = &TM10BR, |
| 274 | 303 | ._tmicr = &TM10ICR, |
| 275 | 304 | .tm_irq = TM10IRQ, |
| 276 | 305 | .div_timer = MNSCx_DIV_TIMER_16BIT, |
| 306 | +#elif defined(CONFIG_MN10300_TTYSM2_TIMER9) | |
| 307 | + .tm_name = "ttySM2/Timer9", | |
| 308 | + ._tmxmd = &TM9MD, | |
| 309 | + ._tmxbr = &TM9BR, | |
| 310 | + ._tmicr = &TM9ICR, | |
| 311 | + .tm_irq = TM9IRQ, | |
| 312 | + .div_timer = MNSCx_DIV_TIMER_16BIT, | |
| 313 | +#elif defined(CONFIG_MN10300_TTYSM2_TIMER1) | |
| 314 | + .tm_name = "ttySM2/Timer1", | |
| 315 | + ._tmxmd = &TM1MD, | |
| 316 | + ._tmxbr = (volatile u16 *)&TM1BR, | |
| 317 | + ._tmicr = &TM1ICR, | |
| 318 | + .tm_irq = TM1IRQ, | |
| 319 | + .div_timer = MNSCx_DIV_TIMER_8BIT, | |
| 320 | +#elif defined(CONFIG_MN10300_TTYSM2_TIMER3) | |
| 321 | + .tm_name = "ttySM2/Timer3", | |
| 322 | + ._tmxmd = &TM3MD, | |
| 323 | + ._tmxbr = (volatile u16 *)&TM3BR, | |
| 324 | + ._tmicr = &TM3ICR, | |
| 325 | + .tm_irq = TM3IRQ, | |
| 326 | + .div_timer = MNSCx_DIV_TIMER_8BIT, | |
| 327 | +#else | |
| 328 | +#error "Unknown config for ttySM2" | |
| 329 | +#endif | |
| 277 | 330 | .rx_irq = SC2RXIRQ, |
| 278 | 331 | .tx_irq = SC2TXIRQ, |
| 279 | 332 | .rx_icr = &GxICR(SC2RXIRQ), |
| @@ -322,9 +375,13 @@ struct mn10300_serial_port *mn10300_serial_ports[NR_UARTS + 1] = { · 42 unmodified lines | ||
| 322 | 375 | */ |
| 323 | 376 | static void mn10300_serial_mask_ack(unsigned int irq) |
| 324 | 377 | { |
| 378 | + unsigned long flags; | |
| 325 | 379 | u16 tmp; |
| 380 | + | |
| 381 | + flags = arch_local_cli_save(); | |
| 326 | 382 | GxICR(irq) = GxICR_LEVEL_6; |
| 327 | 383 | tmp = GxICR(irq); /* flush write buffer */ |
| 384 | + arch_local_irq_restore(flags); | |
| 328 | 385 | } |
| 329 | 386 | |
| 330 | 387 | static void mn10300_serial_nop(unsigned int irq) |
| @@ -348,23 +405,36 @@ struct mn10300_serial_int mn10300_serial_int_tbl[NR_IRQS]; · 17 unmodified lines | ||
| 348 | 405 | |
| 349 | 406 | static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port) |
| 350 | 407 | { |
| 408 | + unsigned long flags; | |
| 351 | 409 | u16 x; |
| 352 | − *port->tx_icr = GxICR_LEVEL_1 | GxICR_DETECT; | |
| 410 | + | |
| 411 | + flags = arch_local_cli_save(); | |
| 412 | + *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); | |
| 353 | 413 | x = *port->tx_icr; |
| 414 | + arch_local_irq_restore(flags); | |
| 354 | 415 | } |
| 355 | 416 | |
| 356 | 417 | static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port) |
| 357 | 418 | { |
| 419 | + unsigned long flags; | |
| 358 | 420 | u16 x; |
| 359 | − *port->tx_icr = GxICR_LEVEL_1 | GxICR_ENABLE; | |
| 421 | + | |
| 422 | + flags = arch_local_cli_save(); | |
| 423 | + *port->tx_icr = | |
| 424 | + NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) | GxICR_ENABLE; | |
| 360 | 425 | x = *port->tx_icr; |
| 426 | + arch_local_irq_restore(flags); | |
| 361 | 427 | } |
| 362 | 428 | |
| 363 | 429 | static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port) |
| 364 | 430 | { |
| 431 | + unsigned long flags; | |
| 365 | 432 | u16 x; |
| 366 | − *port->rx_icr = GxICR_LEVEL_1 | GxICR_DETECT; | |
| 433 | + | |
| 434 | + flags = arch_local_cli_save(); | |
| 435 | + *port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); | |
| 367 | 436 | x = *port->rx_icr; |
| 437 | + arch_local_irq_restore(flags); | |
| 368 | 438 | } |
| 369 | 439 | |
| 370 | 440 | /* |
| @@ -650,7 +720,7 @@ static unsigned int mn10300_serial_tx_empty(struct uart_port *_port) · 279 unmodified lines | ||
| 650 | 720 | static void mn10300_serial_set_mctrl(struct uart_port *_port, |
| 651 | 721 | unsigned int mctrl) |
| 652 | 722 | { |
| 653 | − struct mn10300_serial_port *port = | |
| 723 | + struct mn10300_serial_port *port __attribute__ ((unused)) = | |
| 654 | 724 | container_of(_port, struct mn10300_serial_port, uart); |
| 655 | 725 | |
| 656 | 726 | _enter("%s,%x", port->name, mctrl); |
| @@ -706,6 +776,7 @@ static void mn10300_serial_start_tx(struct uart_port *_port) · 49 unmodified lines | ||
| 706 | 776 | UART_XMIT_SIZE)); |
| 707 | 777 | |
| 708 | 778 | /* kick the virtual DMA controller */ |
| 779 | + arch_local_cli(); | |
| 709 | 780 | x = *port->tx_icr; |
| 710 | 781 | x |= GxICR_ENABLE; |
| 711 | 782 | |
| @@ -716,10 +787,14 @@ static void mn10300_serial_start_tx(struct uart_port *_port) · 4 unmodified lines | ||
| 716 | 787 | |
| 717 | 788 | _debug("CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx", |
| 718 | 789 | *port->_control, *port->_intr, *port->_status, |
| 719 | − *port->_tmxmd, *port->_tmxbr, *port->tx_icr); | |
| 790 | + *port->_tmxmd, | |
| 791 | + (port->div_timer == MNSCx_DIV_TIMER_8BIT) ? | |
| 792 | + *(volatile u8 *)port->_tmxbr : *port->_tmxbr, | |
| 793 | + *port->tx_icr); | |
| 720 | 794 | |
| 721 | 795 | *port->tx_icr = x; |
| 722 | 796 | x = *port->tx_icr; |
| 797 | + arch_local_sti(); | |
| 723 | 798 | } |
| 724 | 799 | |
| 725 | 800 | /* |
| @@ -842,8 +917,10 @@ static int mn10300_serial_startup(struct uart_port *_port) · 116 unmodified lines | ||
| 842 | 917 | pint->port = port; |
| 843 | 918 | pint->vdma = mn10300_serial_vdma_tx_handler; |
| 844 | 919 | |
| 845 | − set_intr_level(port->rx_irq, GxICR_LEVEL_1); | |
| 846 | − set_intr_level(port->tx_irq, GxICR_LEVEL_1); | |
| 920 | + set_intr_level(port->rx_irq, | |
| 921 | + NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)); | |
| 922 | + set_intr_level(port->tx_irq, | |
| 923 | + NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)); | |
| 847 | 924 | set_irq_chip(port->tm_irq, &mn10300_serial_pic); |
| 848 | 925 | |
| 849 | 926 | if (request_irq(port->rx_irq, mn10300_serial_interrupt, |
| @@ -876,6 +953,7 @@ error: · 26 unmodified lines | ||
| 876 | 953 | */ |
| 877 | 954 | static void mn10300_serial_shutdown(struct uart_port *_port) |
| 878 | 955 | { |
| 956 | + u16 x; | |
| 879 | 957 | struct mn10300_serial_port *port = |
| 880 | 958 | container_of(_port, struct mn10300_serial_port, uart); |
| 881 | 959 | |
| @@ -897,8 +975,12 @@ static void mn10300_serial_shutdown(struct uart_port *_port) · 15 unmodified lines | ||
| 897 | 975 | free_irq(port->rx_irq, port); |
| 898 | 976 | free_irq(port->tx_irq, port); |
| 899 | 977 | |
| 900 | − *port->rx_icr = GxICR_LEVEL_1; | |
| 901 | − *port->tx_icr = GxICR_LEVEL_1; | |
| 978 | + arch_local_cli(); | |
| 979 | + *port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); | |
| 980 | + x = *port->rx_icr; | |
| 981 | + *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); | |
| 982 | + x = *port->tx_icr; | |
| 983 | + arch_local_sti(); | |
| 902 | 984 | } |
| 903 | 985 | |
| 904 | 986 | /* |
| @@ -947,11 +1029,66 @@ static void mn10300_serial_change_speed(struct mn10300_serial_port *port, · 42 unmodified lines | ||
| 947 | 1029 | /* Determine divisor based on baud rate */ |
| 948 | 1030 | battempt = 0; |
| 949 | 1031 | |
| 950 | − if (div_timer == MNSCx_DIV_TIMER_16BIT) | |
| 951 | − scxctr |= SC0CTR_CK_TM8UFLOW_8; /* ( == SC1CTR_CK_TM9UFLOW_8 | |
| 952 | − * == SC2CTR_CK_TM10UFLOW) */ | |
| 953 | − else if (div_timer == MNSCx_DIV_TIMER_8BIT) | |
| 1032 | + switch (port->uart.line) { | |
| 1033 | +#ifdef CONFIG_MN10300_TTYSM0 | |
| 1034 | + case 0: /* ttySM0 */ | |
| 1035 | +#if defined(CONFIG_MN10300_TTYSM0_TIMER8) | |
| 1036 | + scxctr |= SC0CTR_CK_TM8UFLOW_8; | |
| 1037 | +#elif defined(CONFIG_MN10300_TTYSM0_TIMER0) | |
| 1038 | + scxctr |= SC0CTR_CK_TM0UFLOW_8; | |
| 1039 | +#elif defined(CONFIG_MN10300_TTYSM0_TIMER2) | |
| 954 | 1040 | scxctr |= SC0CTR_CK_TM2UFLOW_8; |
| 1041 | +#else | |
| 1042 | +#error "Unknown config for ttySM0" | |
| 1043 | +#endif | |
| 1044 | + break; | |
| 1045 | +#endif /* CONFIG_MN10300_TTYSM0 */ | |
| 1046 | + | |
| 1047 | +#ifdef CONFIG_MN10300_TTYSM1 | |
| 1048 | + case 1: /* ttySM1 */ | |
| 1049 | +#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3) | |
| 1050 | +#if defined(CONFIG_MN10300_TTYSM1_TIMER9) | |
| 1051 | + scxctr |= SC1CTR_CK_TM9UFLOW_8; | |
| 1052 | +#elif defined(CONFIG_MN10300_TTYSM1_TIMER3) | |
| 1053 | + scxctr |= SC1CTR_CK_TM3UFLOW_8; | |
| 1054 | +#else | |
| 1055 | +#error "Unknown config for ttySM1" | |
| 1056 | +#endif | |
| 1057 | +#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | |
| 1058 | +#if defined(CONFIG_MN10300_TTYSM1_TIMER12) | |
| 1059 | + scxctr |= SC1CTR_CK_TM12UFLOW_8; | |
| 1060 | +#else | |
| 1061 | +#error "Unknown config for ttySM1" | |
| 1062 | +#endif | |
| 1063 | +#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | |
| 1064 | + break; | |
| 1065 | +#endif /* CONFIG_MN10300_TTYSM1 */ | |
| 1066 | + | |
| 1067 | +#ifdef CONFIG_MN10300_TTYSM2 | |
| 1068 | + case 2: /* ttySM2 */ | |
| 1069 | +#if defined(CONFIG_AM33_2) | |
| 1070 | +#if defined(CONFIG_MN10300_TTYSM2_TIMER10) | |
| 1071 | + scxctr |= SC2CTR_CK_TM10UFLOW; | |
| 1072 | +#else | |
| 1073 | +#error "Unknown config for ttySM2" | |
| 1074 | +#endif | |
| 1075 | +#else /* CONFIG_AM33_2 */ | |
| 1076 | +#if defined(CONFIG_MN10300_TTYSM2_TIMER9) | |
| 1077 | + scxctr |= SC2CTR_CK_TM9UFLOW_8; | |
| 1078 | +#elif defined(CONFIG_MN10300_TTYSM2_TIMER1) | |
| 1079 | + scxctr |= SC2CTR_CK_TM1UFLOW_8; | |
| 1080 | +#elif defined(CONFIG_MN10300_TTYSM2_TIMER3) | |
| 1081 | + scxctr |= SC2CTR_CK_TM3UFLOW_8; | |
| 1082 | +#else | |
| 1083 | +#error "Unknown config for ttySM2" | |
| 1084 | +#endif | |
| 1085 | +#endif /* CONFIG_AM33_2 */ | |
| 1086 | + break; | |
| 1087 | +#endif /* CONFIG_MN10300_TTYSM2 */ | |
| 1088 | + | |
| 1089 | + default: | |
| 1090 | + break; | |
| 1091 | + } | |
| 955 | 1092 | |
| 956 | 1093 | try_alternative: |
| 957 | 1094 | baud = uart_get_baud_rate(&port->uart, new, old, 0, |
| @@ -1195,6 +1332,12 @@ static void mn10300_serial_set_termios(struct uart_port *_port, · 237 unmodified lines | ||
| 1195 | 1332 | ctr &= ~SC2CTR_TWE; |
| 1196 | 1333 | *port->_control = ctr; |
| 1197 | 1334 | } |
| 1335 | + | |
| 1336 | + /* change Transfer bit-order (LSB/MSB) */ | |
| 1337 | + if (new->c_cflag & CODMSB) | |
| 1338 | + *port->_control |= SC01CTR_OD_MSBFIRST; /* MSB MODE */ | |
| 1339 | + else | |
| 1340 | + *port->_control &= ~SC01CTR_OD_MSBFIRST; /* LSB MODE */ | |
| 1198 | 1341 | } |
| 1199 | 1342 | |
| 1200 | 1343 | /* |
| @@ -1302,11 +1445,16 @@ static int __init mn10300_serial_init(void) · 101 unmodified lines | ||
| 1302 | 1445 | printk(KERN_INFO "%s version %s (%s)\n", |
| 1303 | 1446 | serial_name, serial_version, serial_revdate); |
| 1304 | 1447 | |
| 1305 | −#ifdef CONFIG_MN10300_TTYSM2 | |
| 1306 | − SC2TIM = 8; /* make the baud base of timer 2 IOCLK/8 */ | |
| 1448 | +#if defined(CONFIG_MN10300_TTYSM2) && defined(CONFIG_AM33_2) | |
| 1449 | + { | |
| 1450 | + int tmp; | |
| 1451 | + SC2TIM = 8; /* make the baud base of timer 2 IOCLK/8 */ | |
| 1452 | + tmp = SC2TIM; | |
| 1453 | + } | |
| 1307 | 1454 | #endif |
| 1308 | 1455 | |
| 1309 | − set_intr_stub(EXCEP_IRQ_LEVEL1, mn10300_serial_vdma_interrupt); | |
| 1456 | + set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL), | |
| 1457 | + mn10300_serial_vdma_interrupt); | |
| 1310 | 1458 | |
| 1311 | 1459 | ret = uart_register_driver(&mn10300_serial_driver); |
| 1312 | 1460 | if (!ret) { |
| @@ -1366,9 +1514,11 @@ static void mn10300_serial_console_write(struct console *co, · 53 unmodified lines | ||
| 1366 | 1514 | port = mn10300_serial_ports[co->index]; |
| 1367 | 1515 | |
| 1368 | 1516 | /* firstly hijack the serial port from the "virtual DMA" controller */ |
| 1517 | + arch_local_cli(); | |
| 1369 | 1518 | txicr = *port->tx_icr; |
| 1370 | − *port->tx_icr = GxICR_LEVEL_1; | |
| 1519 | + *port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL); | |
| 1371 | 1520 | tmp = *port->tx_icr; |
| 1521 | + arch_local_sti(); | |
| 1372 | 1522 | |
| 1373 | 1523 | /* the transmitter may be disabled */ |
| 1374 | 1524 | scxctr = *port->_control; |
| @@ -1422,8 +1572,10 @@ static void mn10300_serial_console_write(struct console *co, · 47 unmodified lines | ||
| 1422 | 1572 | if (!(scxctr & SC01CTR_TXE)) |
| 1423 | 1573 | *port->_control = scxctr; |
| 1424 | 1574 | |
| 1575 | + arch_local_cli(); | |
| 1425 | 1576 | *port->tx_icr = txicr; |
| 1426 | 1577 | tmp = *port->tx_icr; |
| 1578 | + arch_local_sti(); | |
| 1427 | 1579 | } |
| 1428 | 1580 | |
| 1429 | 1581 | /* |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | #include <asm/intctl-regs.h> |
| 17 | 17 | #include <asm/timer-regs.h> |
| 18 | 18 | #include <asm/frame.inc> |
| 19 | +#include <linux/threads.h> | |
| 19 | 20 | |
| 20 | 21 | .text |
| 21 | 22 | |
| @@ -53,7 +54,13 @@ watchdog_handler: · 31 unmodified lines | ||
| 53 | 54 | .type touch_nmi_watchdog,@function |
| 54 | 55 | touch_nmi_watchdog: |
| 55 | 56 | clr d0 |
| 56 | − mov d0,(watchdog_alert_counter) | |
| 57 | + clr d1 | |
| 58 | + mov watchdog_alert_counter, a0 | |
| 59 | + setlb | |
| 60 | + mov d0, (a0+) | |
| 61 | + inc d1 | |
| 62 | + cmp NR_CPUS, d1 | |
| 63 | + lne | |
| 57 | 64 | ret [],0 |
| 58 | 65 | |
| 59 | 66 | .size touch_nmi_watchdog,.-touch_nmi_watchdog |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | static DEFINE_SPINLOCK(watchdog_print_lock); |
| 31 | 31 | static unsigned int watchdog; |
| 32 | 32 | static unsigned int watchdog_hz = 1; |
| 33 | −unsigned int watchdog_alert_counter; | |
| 33 | +unsigned int watchdog_alert_counter[NR_CPUS]; | |
| 34 | 34 | |
| 35 | 35 | EXPORT_SYMBOL(touch_nmi_watchdog); |
| 36 | 36 | |
| @@ -39,9 +39,6 @@ EXPORT_SYMBOL(touch_nmi_watchdog); · 2 unmodified lines | ||
| 39 | 39 | * is to check its timer makes IRQ counts. If they are not |
| 40 | 40 | * changing then that CPU has some problem. |
| 41 | 41 | * |
| 42 | − * as these watchdog NMI IRQs are generated on every CPU, we only | |
| 43 | − * have to check the current processor. | |
| 44 | − * | |
| 45 | 42 | * since NMIs dont listen to _any_ locks, we have to be extremely |
| 46 | 43 | * careful not to rely on unsafe variables. The printk might lock |
| 47 | 44 | * up though, so we have to break up any console locks first ... |
| @@ -69,8 +66,8 @@ int __init check_watchdog(void) · 21 unmodified lines | ||
| 69 | 66 | |
| 70 | 67 | printk(KERN_INFO "OK.\n"); |
| 71 | 68 | |
| 72 | − /* now that we know it works we can reduce NMI frequency to | |
| 73 | − * something more reasonable; makes a difference in some configs | |
| 69 | + /* now that we know it works we can reduce NMI frequency to something | |
| 70 | + * more reasonable; makes a difference in some configs | |
| 74 | 71 | */ |
| 75 | 72 | watchdog_hz = 1; |
| 76 | 73 | |
| @@ -121,15 +118,22 @@ void __init watchdog_go(void) · 44 unmodified lines | ||
| 121 | 118 | } |
| 122 | 119 | } |
| 123 | 120 | |
| 121 | +#ifdef CONFIG_SMP | |
| 122 | +static void watchdog_dump_register(void *dummy) | |
| 123 | +{ | |
| 124 | + printk(KERN_ERR "--- Register Dump (CPU%d) ---\n", CPUID); | |
| 125 | + show_registers(current_frame()); | |
| 126 | +} | |
| 127 | +#endif | |
| 128 | + | |
| 124 | 129 | asmlinkage |
| 125 | 130 | void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep) |
| 126 | 131 | { |
| 127 | − | |
| 128 | 132 | /* |
| 129 | 133 | * Since current-> is always on the stack, and we always switch |
| 130 | 134 | * the stack NMI-atomically, it's safe to use smp_processor_id(). |
| 131 | 135 | */ |
| 132 | − int sum, cpu = smp_processor_id(); | |
| 136 | + int sum, cpu; | |
| 133 | 137 | int irq = NMIIRQ; |
| 134 | 138 | u8 wdt, tmp; |
| 135 | 139 | |
| @@ -138,43 +142,61 @@ void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep) · 2 unmodified lines | ||
| 138 | 142 | tmp = WDCTR; |
| 139 | 143 | NMICR = NMICR_WDIF; |
| 140 | 144 | |
| 141 | − nmi_count(cpu)++; | |
| 145 | + nmi_count(smp_processor_id())++; | |
| 142 | 146 | kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); |
| 143 | − sum = irq_stat[cpu].__irq_count; | |
| 144 | − | |
| 145 | − if (last_irq_sums[cpu] == sum) { | |
| 146 | − /* | |
| 147 | − * Ayiee, looks like this CPU is stuck ... | |
| 148 | − * wait a few IRQs (5 seconds) before doing the oops ... | |
| 149 | − */ | |
| 150 | − watchdog_alert_counter++; | |
| 151 | − if (watchdog_alert_counter == 5 * watchdog_hz) { | |
| 152 | − spin_lock(&watchdog_print_lock); | |
| 147 | + | |
| 148 | + for_each_online_cpu(cpu) { | |
| 149 | + | |
| 150 | + sum = irq_stat[cpu].__irq_count; | |
| 151 | + | |
| 152 | + if ((last_irq_sums[cpu] == sum) | |
| 153 | +#if defined(CONFIG_GDBSTUB) && defined(CONFIG_SMP) | |
| 154 | + && !(CHK_GDBSTUB_BUSY() | |
| 155 | + || atomic_read(&cpu_doing_single_step)) | |
| 156 | +#endif | |
| 157 | + ) { | |
| 153 | 158 | /* |
| 154 | − * We are in trouble anyway, lets at least try | |
| 155 | − * to get a message out. | |
| 159 | + * Ayiee, looks like this CPU is stuck ... | |
| 160 | + * wait a few IRQs (5 seconds) before doing the oops ... | |
| 156 | 161 | */ |
| 157 | − bust_spinlocks(1); | |
| 158 | − printk(KERN_ERR | |
| 159 | − "NMI Watchdog detected LOCKUP on CPU%d," | |
| 160 | − " pc %08lx, registers:\n", | |
| 161 | − cpu, regs->pc); | |
| 162 | − show_registers(regs); | |
| 163 | − printk("console shuts up ...\n"); | |
| 164 | − console_silent(); | |
| 165 | − spin_unlock(&watchdog_print_lock); | |
| 166 | − bust_spinlocks(0); | |
| 162 | + watchdog_alert_counter[cpu]++; | |
| 163 | + if (watchdog_alert_counter[cpu] == 5 * watchdog_hz) { | |
| 164 | + spin_lock(&watchdog_print_lock); | |
| 165 | + /* | |
| 166 | + * We are in trouble anyway, lets at least try | |
| 167 | + * to get a message out. | |
| 168 | + */ | |
| 169 | + bust_spinlocks(1); | |
| 170 | + printk(KERN_ERR | |
| 171 | + "NMI Watchdog detected LOCKUP on CPU%d," | |
| 172 | + " pc %08lx, registers:\n", | |
| 173 | + cpu, regs->pc); | |
| 174 | +#ifdef CONFIG_SMP | |
| 175 | + printk(KERN_ERR | |
| 176 | + "--- Register Dump (CPU%d) ---\n", | |
| 177 | + CPUID); | |
| 178 | +#endif | |
| 179 | + show_registers(regs); | |
| 180 | +#ifdef CONFIG_SMP | |
| 181 | + smp_nmi_call_function(watchdog_dump_register, | |
| 182 | + NULL, 1); | |
| 183 | +#endif | |
| 184 | + printk(KERN_NOTICE "console shuts up ...\n"); | |
| 185 | + console_silent(); | |
| 186 | + spin_unlock(&watchdog_print_lock); | |
| 187 | + bust_spinlocks(0); | |
| 167 | 188 | #ifdef CONFIG_GDBSTUB |
| 168 | − if (gdbstub_busy) | |
| 169 | − gdbstub_exception(regs, excep); | |
| 170 | − else | |
| 171 | − gdbstub_intercept(regs, excep); | |
| 189 | + if (CHK_GDBSTUB_BUSY_AND_ACTIVE()) | |
| 190 | + gdbstub_exception(regs, excep); | |
| 191 | + else | |
| 192 | + gdbstub_intercept(regs, excep); | |
| 172 | 193 | #endif |
| 173 | − do_exit(SIGSEGV); | |
| 194 | + do_exit(SIGSEGV); | |
| 195 | + } | |
| 196 | + } else { | |
| 197 | + last_irq_sums[cpu] = sum; | |
| 198 | + watchdog_alert_counter[cpu] = 0; | |
| 174 | 199 | } |
| 175 | − } else { | |
| 176 | − last_irq_sums[cpu] = sum; | |
| 177 | − watchdog_alert_counter = 0; | |
| 178 | 200 | } |
| 179 | 201 | |
| 180 | 202 | WDCTR = wdt | WDCTR_WDRST; |
| @@ -57,6 +57,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk) · 56 unmodified lines | ||
| 57 | 57 | void (*pm_power_off)(void); |
| 58 | 58 | EXPORT_SYMBOL(pm_power_off); |
| 59 | 59 | |
| 60 | +#if !defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU) | |
| 60 | 61 | /* |
| 61 | 62 | * we use this if we don't have any better idle routine |
| 62 | 63 | */ |
| @@ -69,6 +70,35 @@ static void default_idle(void) · 6 unmodified lines | ||
| 69 | 70 | local_irq_enable(); |
| 70 | 71 | } |
| 71 | 72 | |
| 73 | +#else /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU */ | |
| 74 | +/* | |
| 75 | + * On SMP it's slightly faster (but much more power-consuming!) | |
| 76 | + * to poll the ->work.need_resched flag instead of waiting for the | |
| 77 | + * cross-CPU IPI to arrive. Use this option with caution. | |
| 78 | + */ | |
| 79 | +static inline void poll_idle(void) | |
| 80 | +{ | |
| 81 | + int oldval; | |
| 82 | + | |
| 83 | + local_irq_enable(); | |
| 84 | + | |
| 85 | + /* | |
| 86 | + * Deal with another CPU just having chosen a thread to | |
| 87 | + * run here: | |
| 88 | + */ | |
| 89 | + oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); | |
| 90 | + | |
| 91 | + if (!oldval) { | |
| 92 | + set_thread_flag(TIF_POLLING_NRFLAG); | |
| 93 | + while (!need_resched()) | |
| 94 | + cpu_relax(); | |
| 95 | + clear_thread_flag(TIF_POLLING_NRFLAG); | |
| 96 | + } else { | |
| 97 | + set_need_resched(); | |
| 98 | + } | |
| 99 | +} | |
| 100 | +#endif /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU */ | |
| 101 | + | |
| 72 | 102 | /* |
| 73 | 103 | * the idle thread |
| 74 | 104 | * - there's no useful work to be done, so just try to conserve power and have |
| @@ -77,8 +107,6 @@ static void default_idle(void) · 2 unmodified lines | ||
| 77 | 107 | */ |
| 78 | 108 | void cpu_idle(void) |
| 79 | 109 | { |
| 80 | − int cpu = smp_processor_id(); | |
| 81 | − | |
| 82 | 110 | /* endless idle loop with no priority at all */ |
| 83 | 111 | for (;;) { |
| 84 | 112 | while (!need_resched()) { |
| @@ -86,10 +114,13 @@ void cpu_idle(void) · 1 unmodified line | ||
| 86 | 114 | |
| 87 | 115 | smp_rmb(); |
| 88 | 116 | idle = pm_idle; |
| 89 | − if (!idle) | |
| 117 | + if (!idle) { | |
| 118 | +#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU) | |
| 119 | + idle = poll_idle; | |
| 120 | +#else /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */ | |
| 90 | 121 | idle = default_idle; |
| 91 | − | |
| 92 | − irq_stat[cpu].idle_timestamp = jiffies; | |
| 122 | +#endif /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */ | |
| 123 | + } | |
| 93 | 124 | idle(); |
| 94 | 125 | } |
| 95 | 126 | |
| @@ -197,6 +228,7 @@ int copy_thread(unsigned long clone_flags, · 101 unmodified lines | ||
| 197 | 228 | unsigned long c_usp, unsigned long ustk_size, |
| 198 | 229 | struct task_struct *p, struct pt_regs *kregs) |
| 199 | 230 | { |
| 231 | + struct thread_info *ti = task_thread_info(p); | |
| 200 | 232 | struct pt_regs *c_uregs, *c_kregs, *uregs; |
| 201 | 233 | unsigned long c_ksp; |
| 202 | 234 | |
| @@ -217,7 +249,7 @@ int copy_thread(unsigned long clone_flags, · 14 unmodified lines | ||
| 217 | 249 | |
| 218 | 250 | /* the new TLS pointer is passed in as arg #5 to sys_clone() */ |
| 219 | 251 | if (clone_flags & CLONE_SETTLS) |
| 220 | − c_uregs->e2 = __frame->d3; | |
| 252 | + c_uregs->e2 = current_frame()->d3; | |
| 221 | 253 | |
| 222 | 254 | /* set up the return kernel frame if called from kernel_thread() */ |
| 223 | 255 | c_kregs = c_uregs; |
| @@ -235,7 +267,7 @@ int copy_thread(unsigned long clone_flags, · 11 unmodified lines | ||
| 235 | 267 | } |
| 236 | 268 | |
| 237 | 269 | /* set up things up so the scheduler can start the new task */ |
| 238 | − p->thread.__frame = c_kregs; | |
| 270 | + ti->frame = c_kregs; | |
| 239 | 271 | p->thread.a3 = (unsigned long) c_kregs; |
| 240 | 272 | p->thread.sp = c_ksp; |
| 241 | 273 | p->thread.pc = (unsigned long) ret_from_fork; |
| @@ -247,25 +279,26 @@ int copy_thread(unsigned long clone_flags, · 5 unmodified lines | ||
| 247 | 279 | |
| 248 | 280 | /* |
| 249 | 281 | * clone a process |
| 250 | − * - tlsptr is retrieved by copy_thread() from __frame->d3 | |
| 282 | + * - tlsptr is retrieved by copy_thread() from current_frame()->d3 | |
| 251 | 283 | */ |
| 252 | 284 | asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, |
| 253 | 285 | int __user *parent_tidptr, int __user *child_tidptr, |
| 254 | 286 | int __user *tlsptr) |
| 255 | 287 | { |
| 256 | − return do_fork(clone_flags, newsp ?: __frame->sp, __frame, 0, | |
| 257 | − parent_tidptr, child_tidptr); | |
| 288 | + return do_fork(clone_flags, newsp ?: current_frame()->sp, | |
| 289 | + current_frame(), 0, parent_tidptr, child_tidptr); | |
| 258 | 290 | } |
| 259 | 291 | |
| 260 | 292 | asmlinkage long sys_fork(void) |
| 261 | 293 | { |
| 262 | − return do_fork(SIGCHLD, __frame->sp, __frame, 0, NULL, NULL); | |
| 294 | + return do_fork(SIGCHLD, current_frame()->sp, | |
| 295 | + current_frame(), 0, NULL, NULL); | |
| 263 | 296 | } |
| 264 | 297 | |
| 265 | 298 | asmlinkage long sys_vfork(void) |
| 266 | 299 | { |
| 267 | − return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, __frame->sp, __frame, | |
| 268 | − 0, NULL, NULL); | |
| 300 | + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, current_frame()->sp, | |
| 301 | + current_frame(), 0, NULL, NULL); | |
| 269 | 302 | } |
| 270 | 303 | |
| 271 | 304 | asmlinkage long sys_execve(const char __user *name, |
| @@ -279,7 +312,7 @@ asmlinkage long sys_execve(const char __user *name, · 7 unmodified lines | ||
| 279 | 312 | error = PTR_ERR(filename); |
| 280 | 313 | if (IS_ERR(filename)) |
| 281 | 314 | return error; |
| 282 | − error = do_execve(filename, argv, envp, __frame); | |
| 315 | + error = do_execve(filename, argv, envp, current_frame()); | |
| 283 | 316 | putname(filename); |
| 284 | 317 | return error; |
| 285 | 318 | } |
| @@ -41,7 +41,7 @@ static __init int profile_init(void) · 40 unmodified lines | ||
| 41 | 41 | tmp = TM11ICR; |
| 42 | 42 | |
| 43 | 43 | printk(KERN_INFO "Profiling initiated on timer 11, priority 0, %uHz\n", |
| 44 | − mn10300_ioclk / 8 / (TM11BR + 1)); | |
| 44 | + MN10300_IOCLK / 8 / (TM11BR + 1)); | |
| 45 | 45 | printk(KERN_INFO "Profile histogram stored %p-%p\n", |
| 46 | 46 | prof_buffer, (u8 *)(prof_buffer + prof_len) - 1); |
| 47 | 47 | |
| @@ -20,18 +20,22 @@ · 19 unmodified lines | ||
| 20 | 20 | DEFINE_SPINLOCK(rtc_lock); |
| 21 | 21 | EXPORT_SYMBOL(rtc_lock); |
| 22 | 22 | |
| 23 | −/* time for RTC to update itself in ioclks */ | |
| 24 | −static unsigned long mn10300_rtc_update_period; | |
| 25 | − | |
| 23 | +/* | |
| 24 | + * Read the current RTC time | |
| 25 | + */ | |
| 26 | 26 | void read_persistent_clock(struct timespec *ts) |
| 27 | 27 | { |
| 28 | 28 | struct rtc_time tm; |
| 29 | 29 | |
| 30 | 30 | get_rtc_time(&tm); |
| 31 | 31 | |
| 32 | − ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday, | |
| 33 | − tm.tm_hour, tm.tm_min, tm.tm_sec); | |
| 34 | 32 | ts->tv_nsec = 0; |
| 33 | + ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday, | |
| 34 | + tm.tm_hour, tm.tm_min, tm.tm_sec); | |
| 35 | + | |
| 36 | + /* if rtc is way off in the past, set something reasonable */ | |
| 37 | + if (ts->tv_sec < 0) | |
| 38 | + ts->tv_sec = mktime(2009, 1, 1, 12, 0, 0); | |
| 35 | 39 | } |
| 36 | 40 | |
| 37 | 41 | /* |
| @@ -115,39 +119,14 @@ int update_persistent_clock(struct timespec now) · 77 unmodified lines | ||
| 115 | 119 | */ |
| 116 | 120 | void __init calibrate_clock(void) |
| 117 | 121 | { |
| 118 | − unsigned long count0, counth, count1; | |
| 119 | 122 | unsigned char status; |
| 120 | 123 | |
| 121 | 124 | /* make sure the RTC is running and is set to operate in 24hr mode */ |
| 122 | 125 | status = RTSRC; |
| 123 | 126 | RTCRB |= RTCRB_SET; |
| 124 | 127 | RTCRB |= RTCRB_TM_24HR; |
| 128 | + RTCRB &= ~RTCRB_DM_BINARY; | |
| 125 | 129 | RTCRA |= RTCRA_DVR; |
| 126 | 130 | RTCRA &= ~RTCRA_DVR; |
| 127 | 131 | RTCRB &= ~RTCRB_SET; |
| 128 | − | |
| 129 | − /* work out the clock speed by counting clock cycles between ends of | |
| 130 | − * the RTC update cycle - track the RTC through one complete update | |
| 131 | − * cycle (1 second) | |
| 132 | − */ | |
| 133 | − startup_timestamp_counter(); | |
| 134 | − | |
| 135 | − while (!(RTCRA & RTCRA_UIP)) {} | |
| 136 | − while ((RTCRA & RTCRA_UIP)) {} | |
| 137 | − | |
| 138 | − count0 = TMTSCBC; | |
| 139 | − | |
| 140 | − while (!(RTCRA & RTCRA_UIP)) {} | |
| 141 | − | |
| 142 | − counth = TMTSCBC; | |
| 143 | − | |
| 144 | − while ((RTCRA & RTCRA_UIP)) {} | |
| 145 | − | |
| 146 | − count1 = TMTSCBC; | |
| 147 | − | |
| 148 | − shutdown_timestamp_counter(); | |
| 149 | − | |
| 150 | − MN10300_TSCCLK = count0 - count1; /* the timers count down */ | |
| 151 | − mn10300_rtc_update_period = counth - count1; | |
| 152 | − MN10300_TSC_PER_HZ = MN10300_TSCCLK / HZ; | |
| 153 | 132 | } |
| @@ -22,6 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <linux/init.h> |
| 23 | 23 | #include <linux/bootmem.h> |
| 24 | 24 | #include <linux/seq_file.h> |
| 25 | +#include <linux/cpu.h> | |
| 25 | 26 | #include <asm/processor.h> |
| 26 | 27 | #include <linux/console.h> |
| 27 | 28 | #include <asm/uaccess.h> |
| @@ -30,7 +31,6 @@ · 2 unmodified lines | ||
| 30 | 31 | #include <asm/io.h> |
| 31 | 32 | #include <asm/smp.h> |
| 32 | 33 | #include <proc/proc.h> |
| 33 | −#include <asm/busctl-regs.h> | |
| 34 | 34 | #include <asm/fpu.h> |
| 35 | 35 | #include <asm/sections.h> |
| 36 | 36 | |
| @@ -64,11 +64,13 @@ unsigned long memory_size; · 27 unmodified lines | ||
| 64 | 64 | struct thread_info *__current_ti = &init_thread_union.thread_info; |
| 65 | 65 | struct task_struct *__current = &init_task; |
| 66 | 66 | |
| 67 | −#define mn10300_known_cpus 3 | |
| 67 | +#define mn10300_known_cpus 5 | |
| 68 | 68 | static const char *const mn10300_cputypes[] = { |
| 69 | − "am33v1", | |
| 70 | − "am33v2", | |
| 71 | − "am34v1", | |
| 69 | + "am33-1", | |
| 70 | + "am33-2", | |
| 71 | + "am34-1", | |
| 72 | + "am33-3", | |
| 73 | + "am34-2", | |
| 72 | 74 | "unknown" |
| 73 | 75 | }; |
| 74 | 76 | |
| @@ -123,6 +125,7 @@ void __init setup_arch(char **cmdline_p) · 48 unmodified lines | ||
| 123 | 125 | |
| 124 | 126 | cpu_init(); |
| 125 | 127 | unit_setup(); |
| 128 | + smp_init_cpus(); | |
| 126 | 129 | parse_mem_cmdline(cmdline_p); |
| 127 | 130 | |
| 128 | 131 | init_mm.start_code = (unsigned long)&_text; |
| @@ -179,57 +182,55 @@ void __init setup_arch(char **cmdline_p) · 50 unmodified lines | ||
| 179 | 182 | void __init cpu_init(void) |
| 180 | 183 | { |
| 181 | 184 | unsigned long cpurev = CPUREV, type; |
| 182 | − unsigned long base, size; | |
| 183 | 185 | |
| 184 | 186 | type = (CPUREV & CPUREV_TYPE) >> CPUREV_TYPE_S; |
| 185 | 187 | if (type > mn10300_known_cpus) |
| 186 | 188 | type = mn10300_known_cpus; |
| 187 | 189 | |
| 188 | − printk(KERN_INFO "Matsushita %s, rev %ld\n", | |
| 190 | + printk(KERN_INFO "Panasonic %s, rev %ld\n", | |
| 189 | 191 | mn10300_cputypes[type], |
| 190 | 192 | (cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S); |
| 191 | 193 | |
| 192 | − /* determine the memory size and base from the memory controller regs */ | |
| 193 | − memory_size = 0; | |
| 194 | − | |
| 195 | − base = SDBASE(0); | |
| 196 | − if (base & SDBASE_CE) { | |
| 197 | − size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT; | |
| 198 | − size = ~size + 1; | |
| 199 | − base &= SDBASE_CBA; | |
| 194 | + get_mem_info(&phys_memory_base, &memory_size); | |
| 195 | + phys_memory_end = phys_memory_base + memory_size; | |
| 200 | 196 | |
| 201 | − printk(KERN_INFO "SDRAM[0]: %luMb @%08lx\n", size >> 20, base); | |
| 202 | − memory_size += size; | |
| 203 | − phys_memory_base = base; | |
| 204 | − } | |
| 197 | + fpu_init_state(); | |
| 198 | +} | |
| 205 | 199 | |
| 206 | − base = SDBASE(1); | |
| 207 | − if (base & SDBASE_CE) { | |
| 208 | − size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT; | |
| 209 | − size = ~size + 1; | |
| 210 | − base &= SDBASE_CBA; | |
| 200 | +static struct cpu cpu_devices[NR_CPUS]; | |
| 211 | 201 | |
| 212 | − printk(KERN_INFO "SDRAM[1]: %luMb @%08lx\n", size >> 20, base); | |
| 213 | − memory_size += size; | |
| 214 | − if (phys_memory_base == 0) | |
| 215 | − phys_memory_base = base; | |
| 216 | − } | |
| 202 | +static int __init topology_init(void) | |
| 203 | +{ | |
| 204 | + int i; | |
| 217 | 205 | |
| 218 | − phys_memory_end = phys_memory_base + memory_size; | |
| 206 | + for_each_present_cpu(i) | |
| 207 | + register_cpu(&cpu_devices[i], i); | |
| 219 | 208 | |
| 220 | −#ifdef CONFIG_FPU | |
| 221 | − fpu_init_state(); | |
| 222 | −#endif | |
| 209 | + return 0; | |
| 223 | 210 | } |
| 224 | 211 | |
| 212 | +subsys_initcall(topology_init); | |
| 213 | + | |
| 225 | 214 | /* |
| 226 | 215 | * Get CPU information for use by the procfs. |
| 227 | 216 | */ |
| 228 | 217 | static int show_cpuinfo(struct seq_file *m, void *v) |
| 229 | 218 | { |
| 219 | +#ifdef CONFIG_SMP | |
| 220 | + struct mn10300_cpuinfo *c = v; | |
| 221 | + unsigned long cpu_id = c - cpu_data; | |
| 222 | + unsigned long cpurev = c->type, type, icachesz, dcachesz; | |
| 223 | +#else /* CONFIG_SMP */ | |
| 224 | + unsigned long cpu_id = 0; | |
| 230 | 225 | unsigned long cpurev = CPUREV, type, icachesz, dcachesz; |
| 226 | +#endif /* CONFIG_SMP */ | |
| 231 | 227 | |
| 232 | − type = (CPUREV & CPUREV_TYPE) >> CPUREV_TYPE_S; | |
| 228 | +#ifdef CONFIG_SMP | |
| 229 | + if (!cpu_online(cpu_id)) | |
| 230 | + return 0; | |
| 231 | +#endif | |
| 232 | + | |
| 233 | + type = (cpurev & CPUREV_TYPE) >> CPUREV_TYPE_S; | |
| 233 | 234 | if (type > mn10300_known_cpus) |
| 234 | 235 | type = mn10300_known_cpus; |
| 235 | 236 | |
| @@ -244,13 +245,14 @@ static int show_cpuinfo(struct seq_file *m, void *v) · 8 unmodified lines | ||
| 244 | 245 | 1024; |
| 245 | 246 | |
| 246 | 247 | seq_printf(m, |
| 247 | − "processor : 0\n" | |
| 248 | − "vendor_id : Matsushita\n" | |
| 248 | + "processor : %ld\n" | |
| 249 | + "vendor_id : " PROCESSOR_VENDOR_NAME "\n" | |
| 249 | 250 | "cpu core : %s\n" |
| 250 | 251 | "cpu rev : %lu\n" |
| 251 | 252 | "model name : " PROCESSOR_MODEL_NAME "\n" |
| 252 | 253 | "icache size: %lu\n" |
| 253 | 254 | "dcache size: %lu\n", |
| 255 | + cpu_id, | |
| 254 | 256 | mn10300_cputypes[type], |
| 255 | 257 | (cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S, |
| 256 | 258 | icachesz, |
| @@ -262,8 +264,13 @@ static int show_cpuinfo(struct seq_file *m, void *v) · 5 unmodified lines | ||
| 262 | 264 | "bogomips : %lu.%02lu\n\n", |
| 263 | 265 | MN10300_IOCLK / 1000000, |
| 264 | 266 | (MN10300_IOCLK / 10000) % 100, |
| 267 | +#ifdef CONFIG_SMP | |
| 268 | + c->loops_per_jiffy / (500000 / HZ), | |
| 269 | + (c->loops_per_jiffy / (5000 / HZ)) % 100 | |
| 270 | +#else /* CONFIG_SMP */ | |
| 265 | 271 | loops_per_jiffy / (500000 / HZ), |
| 266 | 272 | (loops_per_jiffy / (5000 / HZ)) % 100 |
| 273 | +#endif /* CONFIG_SMP */ | |
| 267 | 274 | ); |
| 268 | 275 | |
| 269 | 276 | return 0; |
| @@ -91,7 +91,7 @@ asmlinkage long sys_sigaction(int sig, · 90 unmodified lines | ||
| 91 | 91 | */ |
| 92 | 92 | asmlinkage long sys_sigaltstack(const stack_t __user *uss, stack_t *uoss) |
| 93 | 93 | { |
| 94 | − return do_sigaltstack(uss, uoss, __frame->sp); | |
| 94 | + return do_sigaltstack(uss, uoss, current_frame()->sp); | |
| 95 | 95 | } |
| 96 | 96 | |
| 97 | 97 | /* |
| @@ -156,10 +156,11 @@ badframe: · 58 unmodified lines | ||
| 156 | 156 | */ |
| 157 | 157 | asmlinkage long sys_sigreturn(void) |
| 158 | 158 | { |
| 159 | − struct sigframe __user *frame = (struct sigframe __user *) __frame->sp; | |
| 159 | + struct sigframe __user *frame; | |
| 160 | 160 | sigset_t set; |
| 161 | 161 | long d0; |
| 162 | 162 | |
| 163 | + frame = (struct sigframe __user *) current_frame()->sp; | |
| 163 | 164 | if (verify_area(VERIFY_READ, frame, sizeof(*frame))) |
| 164 | 165 | goto badframe; |
| 165 | 166 | if (__get_user(set.sig[0], &frame->sc.oldmask)) |
| @@ -176,7 +177,7 @@ asmlinkage long sys_sigreturn(void) · 10 unmodified lines | ||
| 176 | 177 | recalc_sigpending(); |
| 177 | 178 | spin_unlock_irq(¤t->sighand->siglock); |
| 178 | 179 | |
| 179 | − if (restore_sigcontext(__frame, &frame->sc, &d0)) | |
| 180 | + if (restore_sigcontext(current_frame(), &frame->sc, &d0)) | |
| 180 | 181 | goto badframe; |
| 181 | 182 | |
| 182 | 183 | return d0; |
| @@ -191,11 +192,11 @@ badframe: · 8 unmodified lines | ||
| 191 | 192 | */ |
| 192 | 193 | asmlinkage long sys_rt_sigreturn(void) |
| 193 | 194 | { |
| 194 | − struct rt_sigframe __user *frame = | |
| 195 | − (struct rt_sigframe __user *) __frame->sp; | |
| 195 | + struct rt_sigframe __user *frame; | |
| 196 | 196 | sigset_t set; |
| 197 | − unsigned long d0; | |
| 197 | + long d0; | |
| 198 | 198 | |
| 199 | + frame = (struct rt_sigframe __user *) current_frame()->sp; | |
| 199 | 200 | if (verify_area(VERIFY_READ, frame, sizeof(*frame))) |
| 200 | 201 | goto badframe; |
| 201 | 202 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
| @@ -207,10 +208,11 @@ asmlinkage long sys_rt_sigreturn(void) · 5 unmodified lines | ||
| 207 | 208 | recalc_sigpending(); |
| 208 | 209 | spin_unlock_irq(¤t->sighand->siglock); |
| 209 | 210 | |
| 210 | − if (restore_sigcontext(__frame, &frame->uc.uc_mcontext, &d0)) | |
| 211 | + if (restore_sigcontext(current_frame(), &frame->uc.uc_mcontext, &d0)) | |
| 211 | 212 | goto badframe; |
| 212 | 213 | |
| 213 | − if (do_sigaltstack(&frame->uc.uc_stack, NULL, __frame->sp) == -EFAULT) | |
| 214 | + if (do_sigaltstack(&frame->uc.uc_stack, NULL, current_frame()->sp) == | |
| 215 | + -EFAULT) | |
| 214 | 216 | goto badframe; |
| 215 | 217 | |
| 216 | 218 | return d0; |
| @@ -572,7 +574,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) · 355 unmodified lines | ||
| 572 | 574 | |
| 573 | 575 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 574 | 576 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 575 | − tracehook_notify_resume(__frame); | |
| 577 | + tracehook_notify_resume(current_frame()); | |
| 576 | 578 | if (current->replacement_session_keyring) |
| 577 | 579 | key_replace_session_keyring(); |
| 578 | 580 | } |
| @@ -0,0 +1,97 @@ | ||
| 1 | +/* SMP IPI low-level handler | |
| 2 | + * | |
| 3 | + * Copyright (C) 2006-2007 Matsushita Electric Industrial Co., Ltd. | |
| 4 | + * All Rights Reserved. | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the License, or (at your option) any later version. | |
| 10 | + * | |
| 11 | + */ | |
| 12 | + | |
| 13 | +#include <linux/sys.h> | |
| 14 | +#include <linux/linkage.h> | |
| 15 | +#include <asm/smp.h> | |
| 16 | +#include <asm/system.h> | |
| 17 | +#include <asm/thread_info.h> | |
| 18 | +#include <asm/cpu-regs.h> | |
| 19 | +#include <proc/smp-regs.h> | |
| 20 | +#include <asm/asm-offsets.h> | |
| 21 | +#include <asm/frame.inc> | |
| 22 | + | |
| 23 | + .am33_2 | |
| 24 | + | |
| 25 | +############################################################################### | |
| 26 | +# | |
| 27 | +# IPI interrupt handler | |
| 28 | +# | |
| 29 | +############################################################################### | |
| 30 | + .globl mn10300_low_ipi_handler | |
| 31 | +mn10300_low_ipi_handler: | |
| 32 | + add -4,sp | |
| 33 | + mov d0,(sp) | |
| 34 | + movhu (IAGR),d0 | |
| 35 | + and IAGR_GN,d0 | |
| 36 | + lsr 0x2,d0 | |
| 37 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 38 | + cmp FLUSH_CACHE_IPI,d0 | |
| 39 | + beq mn10300_flush_cache_ipi | |
| 40 | +#endif | |
| 41 | + cmp SMP_BOOT_IRQ,d0 | |
| 42 | + beq mn10300_smp_boot_ipi | |
| 43 | + /* OTHERS */ | |
| 44 | + mov (sp),d0 | |
| 45 | + add 4,sp | |
| 46 | +#ifdef CONFIG_GDBSTUB | |
| 47 | + jmp gdbstub_io_rx_handler | |
| 48 | +#else | |
| 49 | + jmp end | |
| 50 | +#endif | |
| 51 | + | |
| 52 | +############################################################################### | |
| 53 | +# | |
| 54 | +# Cache flush IPI interrupt handler | |
| 55 | +# | |
| 56 | +############################################################################### | |
| 57 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 58 | +mn10300_flush_cache_ipi: | |
| 59 | + mov (sp),d0 | |
| 60 | + add 4,sp | |
| 61 | + | |
| 62 | + /* FLUSH_CACHE_IPI */ | |
| 63 | + add -4,sp | |
| 64 | + SAVE_ALL | |
| 65 | + mov GxICR_DETECT,d2 | |
| 66 | + movbu d2,(GxICR(FLUSH_CACHE_IPI)) # ACK the interrupt | |
| 67 | + movhu (GxICR(FLUSH_CACHE_IPI)),d2 | |
| 68 | + call smp_cache_interrupt[],0 | |
| 69 | + RESTORE_ALL | |
| 70 | + jmp end | |
| 71 | +#endif | |
| 72 | + | |
| 73 | +############################################################################### | |
| 74 | +# | |
| 75 | +# SMP boot CPU IPI interrupt handler | |
| 76 | +# | |
| 77 | +############################################################################### | |
| 78 | +mn10300_smp_boot_ipi: | |
| 79 | + /* clear interrupt */ | |
| 80 | + movhu (GxICR(SMP_BOOT_IRQ)),d0 | |
| 81 | + and ~GxICR_REQUEST,d0 | |
| 82 | + movhu d0,(GxICR(SMP_BOOT_IRQ)) | |
| 83 | + mov (sp),d0 | |
| 84 | + add 4,sp | |
| 85 | + | |
| 86 | + # get stack | |
| 87 | + mov (CPUID),a0 | |
| 88 | + add -1,a0 | |
| 89 | + add a0,a0 | |
| 90 | + add a0,a0 | |
| 91 | + mov (start_stack,a0),a0 | |
| 92 | + mov a0,sp | |
| 93 | + jmp initialize_secondary | |
| 94 | + | |
| 95 | + | |
| 96 | +# Jump here after RTI to suppress the icache lookahead | |
| 97 | +end: | |
| @@ -0,0 +1,1152 @@ | ||
| 1 | +/* SMP support routines. | |
| 2 | + * | |
| 3 | + * Copyright (C) 2006-2008 Panasonic Corporation | |
| 4 | + * All Rights Reserved. | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * version 2 as published by the Free Software Foundation. | |
| 9 | + * | |
| 10 | + * This program is distributed in the hope that it will be useful, | |
| 11 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | + * GNU General Public License for more details. | |
| 14 | + */ | |
| 15 | + | |
| 16 | +#include <linux/interrupt.h> | |
| 17 | +#include <linux/spinlock.h> | |
| 18 | +#include <linux/init.h> | |
| 19 | +#include <linux/jiffies.h> | |
| 20 | +#include <linux/cpumask.h> | |
| 21 | +#include <linux/err.h> | |
| 22 | +#include <linux/kernel.h> | |
| 23 | +#include <linux/delay.h> | |
| 24 | +#include <linux/sched.h> | |
| 25 | +#include <linux/profile.h> | |
| 26 | +#include <linux/smp.h> | |
| 27 | +#include <asm/tlbflush.h> | |
| 28 | +#include <asm/system.h> | |
| 29 | +#include <asm/bitops.h> | |
| 30 | +#include <asm/processor.h> | |
| 31 | +#include <asm/bug.h> | |
| 32 | +#include <asm/exceptions.h> | |
| 33 | +#include <asm/hardirq.h> | |
| 34 | +#include <asm/fpu.h> | |
| 35 | +#include <asm/mmu_context.h> | |
| 36 | +#include <asm/thread_info.h> | |
| 37 | +#include <asm/cpu-regs.h> | |
| 38 | +#include <asm/intctl-regs.h> | |
| 39 | +#include "internal.h" | |
| 40 | + | |
| 41 | +#ifdef CONFIG_HOTPLUG_CPU | |
| 42 | +#include <linux/cpu.h> | |
| 43 | +#include <asm/cacheflush.h> | |
| 44 | + | |
| 45 | +static unsigned long sleep_mode[NR_CPUS]; | |
| 46 | + | |
| 47 | +static void run_sleep_cpu(unsigned int cpu); | |
| 48 | +static void run_wakeup_cpu(unsigned int cpu); | |
| 49 | +#endif /* CONFIG_HOTPLUG_CPU */ | |
| 50 | + | |
| 51 | +/* | |
| 52 | + * Debug Message function | |
| 53 | + */ | |
| 54 | + | |
| 55 | +#undef DEBUG_SMP | |
| 56 | +#ifdef DEBUG_SMP | |
| 57 | +#define Dprintk(fmt, ...) printk(KERN_DEBUG fmt, ##__VA_ARGS__) | |
| 58 | +#else | |
| 59 | +#define Dprintk(fmt, ...) no_printk(KERN_DEBUG fmt, ##__VA_ARGS__) | |
| 60 | +#endif | |
| 61 | + | |
| 62 | +/* timeout value in msec for smp_nmi_call_function. zero is no timeout. */ | |
| 63 | +#define CALL_FUNCTION_NMI_IPI_TIMEOUT 0 | |
| 64 | + | |
| 65 | +/* | |
| 66 | + * Structure and data for smp_nmi_call_function(). | |
| 67 | + */ | |
| 68 | +struct nmi_call_data_struct { | |
| 69 | + smp_call_func_t func; | |
| 70 | + void *info; | |
| 71 | + cpumask_t started; | |
| 72 | + cpumask_t finished; | |
| 73 | + int wait; | |
| 74 | + char size_alignment[0] | |
| 75 | + __attribute__ ((__aligned__(SMP_CACHE_BYTES))); | |
| 76 | +} __attribute__ ((__aligned__(SMP_CACHE_BYTES))); | |
| 77 | + | |
| 78 | +static DEFINE_SPINLOCK(smp_nmi_call_lock); | |
| 79 | +static struct nmi_call_data_struct *nmi_call_data; | |
| 80 | + | |
| 81 | +/* | |
| 82 | + * Data structures and variables | |
| 83 | + */ | |
| 84 | +static cpumask_t cpu_callin_map; /* Bitmask of callin CPUs */ | |
| 85 | +static cpumask_t cpu_callout_map; /* Bitmask of callout CPUs */ | |
| 86 | +cpumask_t cpu_boot_map; /* Bitmask of boot APs */ | |
| 87 | +unsigned long start_stack[NR_CPUS - 1]; | |
| 88 | + | |
| 89 | +/* | |
| 90 | + * Per CPU parameters | |
| 91 | + */ | |
| 92 | +struct mn10300_cpuinfo cpu_data[NR_CPUS] __cacheline_aligned; | |
| 93 | + | |
| 94 | +static int cpucount; /* The count of boot CPUs */ | |
| 95 | +static cpumask_t smp_commenced_mask; | |
| 96 | +cpumask_t cpu_initialized __initdata = CPU_MASK_NONE; | |
| 97 | + | |
| 98 | +/* | |
| 99 | + * Function Prototypes | |
| 100 | + */ | |
| 101 | +static int do_boot_cpu(int); | |
| 102 | +static void smp_show_cpu_info(int cpu_id); | |
| 103 | +static void smp_callin(void); | |
| 104 | +static void smp_online(void); | |
| 105 | +static void smp_store_cpu_info(int); | |
| 106 | +static void smp_cpu_init(void); | |
| 107 | +static void smp_tune_scheduling(void); | |
| 108 | +static void send_IPI_mask(const cpumask_t *cpumask, int irq); | |
| 109 | +static void init_ipi(void); | |
| 110 | + | |
| 111 | +/* | |
| 112 | + * IPI Initialization interrupt definitions | |
| 113 | + */ | |
| 114 | +static void mn10300_ipi_disable(unsigned int irq); | |
| 115 | +static void mn10300_ipi_enable(unsigned int irq); | |
| 116 | +static void mn10300_ipi_ack(unsigned int irq); | |
| 117 | +static void mn10300_ipi_nop(unsigned int irq); | |
| 118 | + | |
| 119 | +static struct irq_chip mn10300_ipi_type = { | |
| 120 | + .name = "cpu_ipi", | |
| 121 | + .disable = mn10300_ipi_disable, | |
| 122 | + .enable = mn10300_ipi_enable, | |
| 123 | + .ack = mn10300_ipi_ack, | |
| 124 | + .eoi = mn10300_ipi_nop | |
| 125 | +}; | |
| 126 | + | |
| 127 | +static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id); | |
| 128 | +static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id); | |
| 129 | + | |
| 130 | +static struct irqaction reschedule_ipi = { | |
| 131 | + .handler = smp_reschedule_interrupt, | |
| 132 | + .name = "smp reschedule IPI" | |
| 133 | +}; | |
| 134 | +static struct irqaction call_function_ipi = { | |
| 135 | + .handler = smp_call_function_interrupt, | |
| 136 | + .name = "smp call function IPI" | |
| 137 | +}; | |
| 138 | + | |
| 139 | +#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) | |
| 140 | +static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id); | |
| 141 | +static struct irqaction local_timer_ipi = { | |
| 142 | + .handler = smp_ipi_timer_interrupt, | |
| 143 | + .flags = IRQF_DISABLED, | |
| 144 | + .name = "smp local timer IPI" | |
| 145 | +}; | |
| 146 | +#endif | |
| 147 | + | |
| 148 | +/** | |
| 149 | + * init_ipi - Initialise the IPI mechanism | |
| 150 | + */ | |
| 151 | +static void init_ipi(void) | |
| 152 | +{ | |
| 153 | + unsigned long flags; | |
| 154 | + u16 tmp16; | |
| 155 | + | |
| 156 | + /* set up the reschedule IPI */ | |
| 157 | + set_irq_chip_and_handler(RESCHEDULE_IPI, | |
| 158 | + &mn10300_ipi_type, handle_percpu_irq); | |
| 159 | + setup_irq(RESCHEDULE_IPI, &reschedule_ipi); | |
| 160 | + set_intr_level(RESCHEDULE_IPI, RESCHEDULE_GxICR_LV); | |
| 161 | + mn10300_ipi_enable(RESCHEDULE_IPI); | |
| 162 | + | |
| 163 | + /* set up the call function IPI */ | |
| 164 | + set_irq_chip_and_handler(CALL_FUNC_SINGLE_IPI, | |
| 165 | + &mn10300_ipi_type, handle_percpu_irq); | |
| 166 | + setup_irq(CALL_FUNC_SINGLE_IPI, &call_function_ipi); | |
| 167 | + set_intr_level(CALL_FUNC_SINGLE_IPI, CALL_FUNCTION_GxICR_LV); | |
| 168 | + mn10300_ipi_enable(CALL_FUNC_SINGLE_IPI); | |
| 169 | + | |
| 170 | + /* set up the local timer IPI */ | |
| 171 | +#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || \ | |
| 172 | + defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) | |
| 173 | + set_irq_chip_and_handler(LOCAL_TIMER_IPI, | |
| 174 | + &mn10300_ipi_type, handle_percpu_irq); | |
| 175 | + setup_irq(LOCAL_TIMER_IPI, &local_timer_ipi); | |
| 176 | + set_intr_level(LOCAL_TIMER_IPI, LOCAL_TIMER_GxICR_LV); | |
| 177 | + mn10300_ipi_enable(LOCAL_TIMER_IPI); | |
| 178 | +#endif | |
| 179 | + | |
| 180 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 181 | + /* set up the cache flush IPI */ | |
| 182 | + flags = arch_local_cli_save(); | |
| 183 | + __set_intr_stub(NUM2EXCEP_IRQ_LEVEL(FLUSH_CACHE_GxICR_LV), | |
| 184 | + mn10300_low_ipi_handler); | |
| 185 | + GxICR(FLUSH_CACHE_IPI) = FLUSH_CACHE_GxICR_LV | GxICR_DETECT; | |
| 186 | + mn10300_ipi_enable(FLUSH_CACHE_IPI); | |
| 187 | + arch_local_irq_restore(flags); | |
| 188 | +#endif | |
| 189 | + | |
| 190 | + /* set up the NMI call function IPI */ | |
| 191 | + flags = arch_local_cli_save(); | |
| 192 | + GxICR(CALL_FUNCTION_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT; | |
| 193 | + tmp16 = GxICR(CALL_FUNCTION_NMI_IPI); | |
| 194 | + arch_local_irq_restore(flags); | |
| 195 | + | |
| 196 | + /* set up the SMP boot IPI */ | |
| 197 | + flags = arch_local_cli_save(); | |
| 198 | + __set_intr_stub(NUM2EXCEP_IRQ_LEVEL(SMP_BOOT_GxICR_LV), | |
| 199 | + mn10300_low_ipi_handler); | |
| 200 | + arch_local_irq_restore(flags); | |
| 201 | +} | |
| 202 | + | |
| 203 | +/** | |
| 204 | + * mn10300_ipi_shutdown - Shut down handling of an IPI | |
| 205 | + * @irq: The IPI to be shut down. | |
| 206 | + */ | |
| 207 | +static void mn10300_ipi_shutdown(unsigned int irq) | |
| 208 | +{ | |
| 209 | + unsigned long flags; | |
| 210 | + u16 tmp; | |
| 211 | + | |
| 212 | + flags = arch_local_cli_save(); | |
| 213 | + | |
| 214 | + tmp = GxICR(irq); | |
| 215 | + GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT; | |
| 216 | + tmp = GxICR(irq); | |
| 217 | + | |
| 218 | + arch_local_irq_restore(flags); | |
| 219 | +} | |
| 220 | + | |
| 221 | +/** | |
| 222 | + * mn10300_ipi_enable - Enable an IPI | |
| 223 | + * @irq: The IPI to be enabled. | |
| 224 | + */ | |
| 225 | +static void mn10300_ipi_enable(unsigned int irq) | |
| 226 | +{ | |
| 227 | + unsigned long flags; | |
| 228 | + u16 tmp; | |
| 229 | + | |
| 230 | + flags = arch_local_cli_save(); | |
| 231 | + | |
| 232 | + tmp = GxICR(irq); | |
| 233 | + GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE; | |
| 234 | + tmp = GxICR(irq); | |
| 235 | + | |
| 236 | + arch_local_irq_restore(flags); | |
| 237 | +} | |
| 238 | + | |
| 239 | +/** | |
| 240 | + * mn10300_ipi_disable - Disable an IPI | |
| 241 | + * @irq: The IPI to be disabled. | |
| 242 | + */ | |
| 243 | +static void mn10300_ipi_disable(unsigned int irq) | |
| 244 | +{ | |
| 245 | + unsigned long flags; | |
| 246 | + u16 tmp; | |
| 247 | + | |
| 248 | + flags = arch_local_cli_save(); | |
| 249 | + | |
| 250 | + tmp = GxICR(irq); | |
| 251 | + GxICR(irq) = tmp & GxICR_LEVEL; | |
| 252 | + tmp = GxICR(irq); | |
| 253 | + | |
| 254 | + arch_local_irq_restore(flags); | |
| 255 | +} | |
| 256 | + | |
| 257 | +/** | |
| 258 | + * mn10300_ipi_ack - Acknowledge an IPI interrupt in the PIC | |
| 259 | + * @irq: The IPI to be acknowledged. | |
| 260 | + * | |
| 261 | + * Clear the interrupt detection flag for the IPI on the appropriate interrupt | |
| 262 | + * channel in the PIC. | |
| 263 | + */ | |
| 264 | +static void mn10300_ipi_ack(unsigned int irq) | |
| 265 | +{ | |
| 266 | + unsigned long flags; | |
| 267 | + u16 tmp; | |
| 268 | + | |
| 269 | + flags = arch_local_cli_save(); | |
| 270 | + GxICR_u8(irq) = GxICR_DETECT; | |
| 271 | + tmp = GxICR(irq); | |
| 272 | + arch_local_irq_restore(flags); | |
| 273 | +} | |
| 274 | + | |
| 275 | +/** | |
| 276 | + * mn10300_ipi_nop - Dummy IPI action | |
| 277 | + * @irq: The IPI to be acted upon. | |
| 278 | + */ | |
| 279 | +static void mn10300_ipi_nop(unsigned int irq) | |
| 280 | +{ | |
| 281 | +} | |
| 282 | + | |
| 283 | +/** | |
| 284 | + * send_IPI_mask - Send IPIs to all CPUs in list | |
| 285 | + * @cpumask: The list of CPUs to target. | |
| 286 | + * @irq: The IPI request to be sent. | |
| 287 | + * | |
| 288 | + * Send the specified IPI to all the CPUs in the list, not waiting for them to | |
| 289 | + * finish before returning. The caller is responsible for synchronisation if | |
| 290 | + * that is needed. | |
| 291 | + */ | |
| 292 | +static void send_IPI_mask(const cpumask_t *cpumask, int irq) | |
| 293 | +{ | |
| 294 | + int i; | |
| 295 | + u16 tmp; | |
| 296 | + | |
| 297 | + for (i = 0; i < NR_CPUS; i++) { | |
| 298 | + if (cpu_isset(i, *cpumask)) { | |
| 299 | + /* send IPI */ | |
| 300 | + tmp = CROSS_GxICR(irq, i); | |
| 301 | + CROSS_GxICR(irq, i) = | |
| 302 | + tmp | GxICR_REQUEST | GxICR_DETECT; | |
| 303 | + tmp = CROSS_GxICR(irq, i); /* flush write buffer */ | |
| 304 | + } | |
| 305 | + } | |
| 306 | +} | |
| 307 | + | |
| 308 | +/** | |
| 309 | + * send_IPI_self - Send an IPI to this CPU. | |
| 310 | + * @irq: The IPI request to be sent. | |
| 311 | + * | |
| 312 | + * Send the specified IPI to the current CPU. | |
| 313 | + */ | |
| 314 | +void send_IPI_self(int irq) | |
| 315 | +{ | |
| 316 | + send_IPI_mask(cpumask_of(smp_processor_id()), irq); | |
| 317 | +} | |
| 318 | + | |
| 319 | +/** | |
| 320 | + * send_IPI_allbutself - Send IPIs to all the other CPUs. | |
| 321 | + * @irq: The IPI request to be sent. | |
| 322 | + * | |
| 323 | + * Send the specified IPI to all CPUs in the system barring the current one, | |
| 324 | + * not waiting for them to finish before returning. The caller is responsible | |
| 325 | + * for synchronisation if that is needed. | |
| 326 | + */ | |
| 327 | +void send_IPI_allbutself(int irq) | |
| 328 | +{ | |
| 329 | + cpumask_t cpumask; | |
| 330 | + | |
| 331 | + cpumask = cpu_online_map; | |
| 332 | + cpu_clear(smp_processor_id(), cpumask); | |
| 333 | + send_IPI_mask(&cpumask, irq); | |
| 334 | +} | |
| 335 | + | |
| 336 | +void arch_send_call_function_ipi_mask(const struct cpumask *mask) | |
| 337 | +{ | |
| 338 | + BUG(); | |
| 339 | + /*send_IPI_mask(mask, CALL_FUNCTION_IPI);*/ | |
| 340 | +} | |
| 341 | + | |
| 342 | +void arch_send_call_function_single_ipi(int cpu) | |
| 343 | +{ | |
| 344 | + send_IPI_mask(cpumask_of(cpu), CALL_FUNC_SINGLE_IPI); | |
| 345 | +} | |
| 346 | + | |
| 347 | +/** | |
| 348 | + * smp_send_reschedule - Send reschedule IPI to a CPU | |
| 349 | + * @cpu: The CPU to target. | |
| 350 | + */ | |
| 351 | +void smp_send_reschedule(int cpu) | |
| 352 | +{ | |
| 353 | + send_IPI_mask(cpumask_of(cpu), RESCHEDULE_IPI); | |
| 354 | +} | |
| 355 | + | |
| 356 | +/** | |
| 357 | + * smp_nmi_call_function - Send a call function NMI IPI to all CPUs | |
| 358 | + * @func: The function to ask to be run. | |
| 359 | + * @info: The context data to pass to that function. | |
| 360 | + * @wait: If true, wait (atomically) until function is run on all CPUs. | |
| 361 | + * | |
| 362 | + * Send a non-maskable request to all CPUs in the system, requesting them to | |
| 363 | + * run the specified function with the given context data, and, potentially, to | |
| 364 | + * wait for completion of that function on all CPUs. | |
| 365 | + * | |
| 366 | + * Returns 0 if successful, -ETIMEDOUT if we were asked to wait, but hit the | |
| 367 | + * timeout. | |
| 368 | + */ | |
| 369 | +int smp_nmi_call_function(smp_call_func_t func, void *info, int wait) | |
| 370 | +{ | |
| 371 | + struct nmi_call_data_struct data; | |
| 372 | + unsigned long flags; | |
| 373 | + unsigned int cnt; | |
| 374 | + int cpus, ret = 0; | |
| 375 | + | |
| 376 | + cpus = num_online_cpus() - 1; | |
| 377 | + if (cpus < 1) | |
| 378 | + return 0; | |
| 379 | + | |
| 380 | + data.func = func; | |
| 381 | + data.info = info; | |
| 382 | + data.started = cpu_online_map; | |
| 383 | + cpu_clear(smp_processor_id(), data.started); | |
| 384 | + data.wait = wait; | |
| 385 | + if (wait) | |
| 386 | + data.finished = data.started; | |
| 387 | + | |
| 388 | + spin_lock_irqsave(&smp_nmi_call_lock, flags); | |
| 389 | + nmi_call_data = &data; | |
| 390 | + smp_mb(); | |
| 391 | + | |
| 392 | + /* Send a message to all other CPUs and wait for them to respond */ | |
| 393 | + send_IPI_allbutself(CALL_FUNCTION_NMI_IPI); | |
| 394 | + | |
| 395 | + /* Wait for response */ | |
| 396 | + if (CALL_FUNCTION_NMI_IPI_TIMEOUT > 0) { | |
| 397 | + for (cnt = 0; | |
| 398 | + cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT && | |
| 399 | + !cpus_empty(data.started); | |
| 400 | + cnt++) | |
| 401 | + mdelay(1); | |
| 402 | + | |
| 403 | + if (wait && cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT) { | |
| 404 | + for (cnt = 0; | |
| 405 | + cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT && | |
| 406 | + !cpus_empty(data.finished); | |
| 407 | + cnt++) | |
| 408 | + mdelay(1); | |
| 409 | + } | |
| 410 | + | |
| 411 | + if (cnt >= CALL_FUNCTION_NMI_IPI_TIMEOUT) | |
| 412 | + ret = -ETIMEDOUT; | |
| 413 | + | |
| 414 | + } else { | |
| 415 | + /* If timeout value is zero, wait until cpumask has been | |
| 416 | + * cleared */ | |
| 417 | + while (!cpus_empty(data.started)) | |
| 418 | + barrier(); | |
| 419 | + if (wait) | |
| 420 | + while (!cpus_empty(data.finished)) | |
| 421 | + barrier(); | |
| 422 | + } | |
| 423 | + | |
| 424 | + spin_unlock_irqrestore(&smp_nmi_call_lock, flags); | |
| 425 | + return ret; | |
| 426 | +} | |
| 427 | + | |
| 428 | +/** | |
| 429 | + * stop_this_cpu - Callback to stop a CPU. | |
| 430 | + * @unused: Callback context (ignored). | |
| 431 | + */ | |
| 432 | +void stop_this_cpu(void *unused) | |
| 433 | +{ | |
| 434 | + static volatile int stopflag; | |
| 435 | + unsigned long flags; | |
| 436 | + | |
| 437 | +#ifdef CONFIG_GDBSTUB | |
| 438 | + /* In case of single stepping smp_send_stop by other CPU, | |
| 439 | + * clear procindebug to avoid deadlock. | |
| 440 | + */ | |
| 441 | + atomic_set(&procindebug[smp_processor_id()], 0); | |
| 442 | +#endif /* CONFIG_GDBSTUB */ | |
| 443 | + | |
| 444 | + flags = arch_local_cli_save(); | |
| 445 | + cpu_clear(smp_processor_id(), cpu_online_map); | |
| 446 | + | |
| 447 | + while (!stopflag) | |
| 448 | + cpu_relax(); | |
| 449 | + | |
| 450 | + cpu_set(smp_processor_id(), cpu_online_map); | |
| 451 | + arch_local_irq_restore(flags); | |
| 452 | +} | |
| 453 | + | |
| 454 | +/** | |
| 455 | + * smp_send_stop - Send a stop request to all CPUs. | |
| 456 | + */ | |
| 457 | +void smp_send_stop(void) | |
| 458 | +{ | |
| 459 | + smp_nmi_call_function(stop_this_cpu, NULL, 0); | |
| 460 | +} | |
| 461 | + | |
| 462 | +/** | |
| 463 | + * smp_reschedule_interrupt - Reschedule IPI handler | |
| 464 | + * @irq: The interrupt number. | |
| 465 | + * @dev_id: The device ID. | |
| 466 | + * | |
| 467 | + * We need do nothing here, since the scheduling will be effected on our way | |
| 468 | + * back through entry.S. | |
| 469 | + * | |
| 470 | + * Returns IRQ_HANDLED to indicate we handled the interrupt successfully. | |
| 471 | + */ | |
| 472 | +static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id) | |
| 473 | +{ | |
| 474 | + /* do nothing */ | |
| 475 | + return IRQ_HANDLED; | |
| 476 | +} | |
| 477 | + | |
| 478 | +/** | |
| 479 | + * smp_call_function_interrupt - Call function IPI handler | |
| 480 | + * @irq: The interrupt number. | |
| 481 | + * @dev_id: The device ID. | |
| 482 | + * | |
| 483 | + * Returns IRQ_HANDLED to indicate we handled the interrupt successfully. | |
| 484 | + */ | |
| 485 | +static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id) | |
| 486 | +{ | |
| 487 | + /* generic_smp_call_function_interrupt(); */ | |
| 488 | + generic_smp_call_function_single_interrupt(); | |
| 489 | + return IRQ_HANDLED; | |
| 490 | +} | |
| 491 | + | |
| 492 | +/** | |
| 493 | + * smp_nmi_call_function_interrupt - Non-maskable call function IPI handler | |
| 494 | + */ | |
| 495 | +void smp_nmi_call_function_interrupt(void) | |
| 496 | +{ | |
| 497 | + smp_call_func_t func = nmi_call_data->func; | |
| 498 | + void *info = nmi_call_data->info; | |
| 499 | + int wait = nmi_call_data->wait; | |
| 500 | + | |
| 501 | + /* Notify the initiating CPU that I've grabbed the data and am about to | |
| 502 | + * execute the function | |
| 503 | + */ | |
| 504 | + smp_mb(); | |
| 505 | + cpu_clear(smp_processor_id(), nmi_call_data->started); | |
| 506 | + (*func)(info); | |
| 507 | + | |
| 508 | + if (wait) { | |
| 509 | + smp_mb(); | |
| 510 | + cpu_clear(smp_processor_id(), nmi_call_data->finished); | |
| 511 | + } | |
| 512 | +} | |
| 513 | + | |
| 514 | +#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || \ | |
| 515 | + defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) | |
| 516 | +/** | |
| 517 | + * smp_ipi_timer_interrupt - Local timer IPI handler | |
| 518 | + * @irq: The interrupt number. | |
| 519 | + * @dev_id: The device ID. | |
| 520 | + * | |
| 521 | + * Returns IRQ_HANDLED to indicate we handled the interrupt successfully. | |
| 522 | + */ | |
| 523 | +static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id) | |
| 524 | +{ | |
| 525 | + return local_timer_interrupt(); | |
| 526 | +} | |
| 527 | +#endif | |
| 528 | + | |
| 529 | +void __init smp_init_cpus(void) | |
| 530 | +{ | |
| 531 | + int i; | |
| 532 | + for (i = 0; i < NR_CPUS; i++) { | |
| 533 | + set_cpu_possible(i, true); | |
| 534 | + set_cpu_present(i, true); | |
| 535 | + } | |
| 536 | +} | |
| 537 | + | |
| 538 | +/** | |
| 539 | + * smp_cpu_init - Initialise AP in start_secondary. | |
| 540 | + * | |
| 541 | + * For this Application Processor, set up init_mm, initialise FPU and set | |
| 542 | + * interrupt level 0-6 setting. | |
| 543 | + */ | |
| 544 | +static void __init smp_cpu_init(void) | |
| 545 | +{ | |
| 546 | + unsigned long flags; | |
| 547 | + int cpu_id = smp_processor_id(); | |
| 548 | + u16 tmp16; | |
| 549 | + | |
| 550 | + if (test_and_set_bit(cpu_id, &cpu_initialized)) { | |
| 551 | + printk(KERN_WARNING "CPU#%d already initialized!\n", cpu_id); | |
| 552 | + for (;;) | |
| 553 | + local_irq_enable(); | |
| 554 | + } | |
| 555 | + printk(KERN_INFO "Initializing CPU#%d\n", cpu_id); | |
| 556 | + | |
| 557 | + atomic_inc(&init_mm.mm_count); | |
| 558 | + current->active_mm = &init_mm; | |
| 559 | + BUG_ON(current->mm); | |
| 560 | + | |
| 561 | + enter_lazy_tlb(&init_mm, current); | |
| 562 | + | |
| 563 | + /* Force FPU initialization */ | |
| 564 | + clear_using_fpu(current); | |
| 565 | + | |
| 566 | + GxICR(CALL_FUNC_SINGLE_IPI) = CALL_FUNCTION_GxICR_LV | GxICR_DETECT; | |
| 567 | + mn10300_ipi_enable(CALL_FUNC_SINGLE_IPI); | |
| 568 | + | |
| 569 | + GxICR(LOCAL_TIMER_IPI) = LOCAL_TIMER_GxICR_LV | GxICR_DETECT; | |
| 570 | + mn10300_ipi_enable(LOCAL_TIMER_IPI); | |
| 571 | + | |
| 572 | + GxICR(RESCHEDULE_IPI) = RESCHEDULE_GxICR_LV | GxICR_DETECT; | |
| 573 | + mn10300_ipi_enable(RESCHEDULE_IPI); | |
| 574 | + | |
| 575 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 576 | + GxICR(FLUSH_CACHE_IPI) = FLUSH_CACHE_GxICR_LV | GxICR_DETECT; | |
| 577 | + mn10300_ipi_enable(FLUSH_CACHE_IPI); | |
| 578 | +#endif | |
| 579 | + | |
| 580 | + mn10300_ipi_shutdown(SMP_BOOT_IRQ); | |
| 581 | + | |
| 582 | + /* Set up the non-maskable call function IPI */ | |
| 583 | + flags = arch_local_cli_save(); | |
| 584 | + GxICR(CALL_FUNCTION_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT; | |
| 585 | + tmp16 = GxICR(CALL_FUNCTION_NMI_IPI); | |
| 586 | + arch_local_irq_restore(flags); | |
| 587 | +} | |
| 588 | + | |
| 589 | +/** | |
| 590 | + * smp_prepare_cpu_init - Initialise CPU in startup_secondary | |
| 591 | + * | |
| 592 | + * Set interrupt level 0-6 setting and init ICR of gdbstub. | |
| 593 | + */ | |
| 594 | +void smp_prepare_cpu_init(void) | |
| 595 | +{ | |
| 596 | + int loop; | |
| 597 | + | |
| 598 | + /* Set the interrupt vector registers */ | |
| 599 | + IVAR0 = EXCEP_IRQ_LEVEL0; | |
| 600 | + IVAR1 = EXCEP_IRQ_LEVEL1; | |
| 601 | + IVAR2 = EXCEP_IRQ_LEVEL2; | |
| 602 | + IVAR3 = EXCEP_IRQ_LEVEL3; | |
| 603 | + IVAR4 = EXCEP_IRQ_LEVEL4; | |
| 604 | + IVAR5 = EXCEP_IRQ_LEVEL5; | |
| 605 | + IVAR6 = EXCEP_IRQ_LEVEL6; | |
| 606 | + | |
| 607 | + /* Disable all interrupts and set to priority 6 (lowest) */ | |
| 608 | + for (loop = 0; loop < GxICR_NUM_IRQS; loop++) | |
| 609 | + GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT; | |
| 610 | + | |
| 611 | +#ifdef CONFIG_GDBSTUB | |
| 612 | + /* initialise GDB-stub */ | |
| 613 | + do { | |
| 614 | + unsigned long flags; | |
| 615 | + u16 tmp16; | |
| 616 | + | |
| 617 | + flags = arch_local_cli_save(); | |
| 618 | + GxICR(GDB_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT; | |
| 619 | + tmp16 = GxICR(GDB_NMI_IPI); | |
| 620 | + arch_local_irq_restore(flags); | |
| 621 | + } while (0); | |
| 622 | +#endif | |
| 623 | +} | |
| 624 | + | |
| 625 | +/** | |
| 626 | + * start_secondary - Activate a secondary CPU (AP) | |
| 627 | + * @unused: Thread parameter (ignored). | |
| 628 | + */ | |
| 629 | +int __init start_secondary(void *unused) | |
| 630 | +{ | |
| 631 | + smp_cpu_init(); | |
| 632 | + smp_callin(); | |
| 633 | + while (!cpu_isset(smp_processor_id(), smp_commenced_mask)) | |
| 634 | + cpu_relax(); | |
| 635 | + | |
| 636 | + local_flush_tlb(); | |
| 637 | + preempt_disable(); | |
| 638 | + smp_online(); | |
| 639 | + | |
| 640 | +#ifdef CONFIG_GENERIC_CLOCKEVENTS | |
| 641 | + init_clockevents(); | |
| 642 | +#endif | |
| 643 | + cpu_idle(); | |
| 644 | + return 0; | |
| 645 | +} | |
| 646 | + | |
| 647 | +/** | |
| 648 | + * smp_prepare_cpus - Boot up secondary CPUs (APs) | |
| 649 | + * @max_cpus: Maximum number of CPUs to boot. | |
| 650 | + * | |
| 651 | + * Call do_boot_cpu, and boot up APs. | |
| 652 | + */ | |
| 653 | +void __init smp_prepare_cpus(unsigned int max_cpus) | |
| 654 | +{ | |
| 655 | + int phy_id; | |
| 656 | + | |
| 657 | + /* Setup boot CPU information */ | |
| 658 | + smp_store_cpu_info(0); | |
| 659 | + smp_tune_scheduling(); | |
| 660 | + | |
| 661 | + init_ipi(); | |
| 662 | + | |
| 663 | + /* If SMP should be disabled, then finish */ | |
| 664 | + if (max_cpus == 0) { | |
| 665 | + printk(KERN_INFO "SMP mode deactivated.\n"); | |
| 666 | + goto smp_done; | |
| 667 | + } | |
| 668 | + | |
| 669 | + /* Boot secondary CPUs (for which phy_id > 0) */ | |
| 670 | + for (phy_id = 0; phy_id < NR_CPUS; phy_id++) { | |
| 671 | + /* Don't boot primary CPU */ | |
| 672 | + if (max_cpus <= cpucount + 1) | |
| 673 | + continue; | |
| 674 | + if (phy_id != 0) | |
| 675 | + do_boot_cpu(phy_id); | |
| 676 | + set_cpu_possible(phy_id, true); | |
| 677 | + smp_show_cpu_info(phy_id); | |
| 678 | + } | |
| 679 | + | |
| 680 | +smp_done: | |
| 681 | + Dprintk("Boot done.\n"); | |
| 682 | +} | |
| 683 | + | |
| 684 | +/** | |
| 685 | + * smp_store_cpu_info - Save a CPU's information | |
| 686 | + * @cpu: The CPU to save for. | |
| 687 | + * | |
| 688 | + * Save boot_cpu_data and jiffy for the specified CPU. | |
| 689 | + */ | |
| 690 | +static void __init smp_store_cpu_info(int cpu) | |
| 691 | +{ | |
| 692 | + struct mn10300_cpuinfo *ci = &cpu_data[cpu]; | |
| 693 | + | |
| 694 | + *ci = boot_cpu_data; | |
| 695 | + ci->loops_per_jiffy = loops_per_jiffy; | |
| 696 | + ci->type = CPUREV; | |
| 697 | +} | |
| 698 | + | |
| 699 | +/** | |
| 700 | + * smp_tune_scheduling - Set time slice value | |
| 701 | + * | |
| 702 | + * Nothing to do here. | |
| 703 | + */ | |
| 704 | +static void __init smp_tune_scheduling(void) | |
| 705 | +{ | |
| 706 | +} | |
| 707 | + | |
| 708 | +/** | |
| 709 | + * do_boot_cpu: Boot up one CPU | |
| 710 | + * @phy_id: Physical ID of CPU to boot. | |
| 711 | + * | |
| 712 | + * Send an IPI to a secondary CPU to boot it. Returns 0 on success, 1 | |
| 713 | + * otherwise. | |
| 714 | + */ | |
| 715 | +static int __init do_boot_cpu(int phy_id) | |
| 716 | +{ | |
| 717 | + struct task_struct *idle; | |
| 718 | + unsigned long send_status, callin_status; | |
| 719 | + int timeout, cpu_id; | |
| 720 | + | |
| 721 | + send_status = GxICR_REQUEST; | |
| 722 | + callin_status = 0; | |
| 723 | + timeout = 0; | |
| 724 | + cpu_id = phy_id; | |
| 725 | + | |
| 726 | + cpucount++; | |
| 727 | + | |
| 728 | + /* Create idle thread for this CPU */ | |
| 729 | + idle = fork_idle(cpu_id); | |
| 730 | + if (IS_ERR(idle)) | |
| 731 | + panic("Failed fork for CPU#%d.", cpu_id); | |
| 732 | + | |
| 733 | + idle->thread.pc = (unsigned long)start_secondary; | |
| 734 | + | |
| 735 | + printk(KERN_NOTICE "Booting CPU#%d\n", cpu_id); | |
| 736 | + start_stack[cpu_id - 1] = idle->thread.sp; | |
| 737 | + | |
| 738 | + task_thread_info(idle)->cpu = cpu_id; | |
| 739 | + | |
| 740 | + /* Send boot IPI to AP */ | |
| 741 | + send_IPI_mask(cpumask_of(phy_id), SMP_BOOT_IRQ); | |
| 742 | + | |
| 743 | + Dprintk("Waiting for send to finish...\n"); | |
| 744 | + | |
| 745 | + /* Wait for AP's IPI receive in 100[ms] */ | |
| 746 | + do { | |
| 747 | + udelay(1000); | |
| 748 | + send_status = | |
| 749 | + CROSS_GxICR(SMP_BOOT_IRQ, phy_id) & GxICR_REQUEST; | |
| 750 | + } while (send_status == GxICR_REQUEST && timeout++ < 100); | |
| 751 | + | |
| 752 | + Dprintk("Waiting for cpu_callin_map.\n"); | |
| 753 | + | |
| 754 | + if (send_status == 0) { | |
| 755 | + /* Allow AP to start initializing */ | |
| 756 | + cpu_set(cpu_id, cpu_callout_map); | |
| 757 | + | |
| 758 | + /* Wait for setting cpu_callin_map */ | |
| 759 | + timeout = 0; | |
| 760 | + do { | |
| 761 | + udelay(1000); | |
| 762 | + callin_status = cpu_isset(cpu_id, cpu_callin_map); | |
| 763 | + } while (callin_status == 0 && timeout++ < 5000); | |
| 764 | + | |
| 765 | + if (callin_status == 0) | |
| 766 | + Dprintk("Not responding.\n"); | |
| 767 | + } else { | |
| 768 | + printk(KERN_WARNING "IPI not delivered.\n"); | |
| 769 | + } | |
| 770 | + | |
| 771 | + if (send_status == GxICR_REQUEST || callin_status == 0) { | |
| 772 | + cpu_clear(cpu_id, cpu_callout_map); | |
| 773 | + cpu_clear(cpu_id, cpu_callin_map); | |
| 774 | + cpu_clear(cpu_id, cpu_initialized); | |
| 775 | + cpucount--; | |
| 776 | + return 1; | |
| 777 | + } | |
| 778 | + return 0; | |
| 779 | +} | |
| 780 | + | |
| 781 | +/** | |
| 782 | + * smp_show_cpu_info - Show SMP CPU information | |
| 783 | + * @cpu: The CPU of interest. | |
| 784 | + */ | |
| 785 | +static void __init smp_show_cpu_info(int cpu) | |
| 786 | +{ | |
| 787 | + struct mn10300_cpuinfo *ci = &cpu_data[cpu]; | |
| 788 | + | |
| 789 | + printk(KERN_INFO | |
| 790 | + "CPU#%d : ioclk speed: %lu.%02luMHz : bogomips : %lu.%02lu\n", | |
| 791 | + cpu, | |
| 792 | + MN10300_IOCLK / 1000000, | |
| 793 | + (MN10300_IOCLK / 10000) % 100, | |
| 794 | + ci->loops_per_jiffy / (500000 / HZ), | |
| 795 | + (ci->loops_per_jiffy / (5000 / HZ)) % 100); | |
| 796 | +} | |
| 797 | + | |
| 798 | +/** | |
| 799 | + * smp_callin - Set cpu_callin_map of the current CPU ID | |
| 800 | + */ | |
| 801 | +static void __init smp_callin(void) | |
| 802 | +{ | |
| 803 | + unsigned long timeout; | |
| 804 | + int cpu; | |
| 805 | + | |
| 806 | + cpu = smp_processor_id(); | |
| 807 | + timeout = jiffies + (2 * HZ); | |
| 808 | + | |
| 809 | + if (cpu_isset(cpu, cpu_callin_map)) { | |
| 810 | + printk(KERN_ERR "CPU#%d already present.\n", cpu); | |
| 811 | + BUG(); | |
| 812 | + } | |
| 813 | + Dprintk("CPU#%d waiting for CALLOUT\n", cpu); | |
| 814 | + | |
| 815 | + /* Wait for AP startup 2s total */ | |
| 816 | + while (time_before(jiffies, timeout)) { | |
| 817 | + if (cpu_isset(cpu, cpu_callout_map)) | |
| 818 | + break; | |
| 819 | + cpu_relax(); | |
| 820 | + } | |
| 821 | + | |
| 822 | + if (!time_before(jiffies, timeout)) { | |
| 823 | + printk(KERN_ERR | |
| 824 | + "BUG: CPU#%d started up but did not get a callout!\n", | |
| 825 | + cpu); | |
| 826 | + BUG(); | |
| 827 | + } | |
| 828 | + | |
| 829 | +#ifdef CONFIG_CALIBRATE_DELAY | |
| 830 | + calibrate_delay(); /* Get our bogomips */ | |
| 831 | +#endif | |
| 832 | + | |
| 833 | + /* Save our processor parameters */ | |
| 834 | + smp_store_cpu_info(cpu); | |
| 835 | + | |
| 836 | + /* Allow the boot processor to continue */ | |
| 837 | + cpu_set(cpu, cpu_callin_map); | |
| 838 | +} | |
| 839 | + | |
| 840 | +/** | |
| 841 | + * smp_online - Set cpu_online_map | |
| 842 | + */ | |
| 843 | +static void __init smp_online(void) | |
| 844 | +{ | |
| 845 | + int cpu; | |
| 846 | + | |
| 847 | + cpu = smp_processor_id(); | |
| 848 | + | |
| 849 | + local_irq_enable(); | |
| 850 | + | |
| 851 | + cpu_set(cpu, cpu_online_map); | |
| 852 | + smp_wmb(); | |
| 853 | +} | |
| 854 | + | |
| 855 | +/** | |
| 856 | + * smp_cpus_done - | |
| 857 | + * @max_cpus: Maximum CPU count. | |
| 858 | + * | |
| 859 | + * Do nothing. | |
| 860 | + */ | |
| 861 | +void __init smp_cpus_done(unsigned int max_cpus) | |
| 862 | +{ | |
| 863 | +} | |
| 864 | + | |
| 865 | +/* | |
| 866 | + * smp_prepare_boot_cpu - Set up stuff for the boot processor. | |
| 867 | + * | |
| 868 | + * Set up the cpu_online_map, cpu_callout_map and cpu_callin_map of the boot | |
| 869 | + * processor (CPU 0). | |
| 870 | + */ | |
| 871 | +void __devinit smp_prepare_boot_cpu(void) | |
| 872 | +{ | |
| 873 | + cpu_set(0, cpu_callout_map); | |
| 874 | + cpu_set(0, cpu_callin_map); | |
| 875 | + current_thread_info()->cpu = 0; | |
| 876 | +} | |
| 877 | + | |
| 878 | +/* | |
| 879 | + * initialize_secondary - Initialise a secondary CPU (Application Processor). | |
| 880 | + * | |
| 881 | + * Set SP register and jump to thread's PC address. | |
| 882 | + */ | |
| 883 | +void initialize_secondary(void) | |
| 884 | +{ | |
| 885 | + asm volatile ( | |
| 886 | + "mov %0,sp \n" | |
| 887 | + "jmp (%1) \n" | |
| 888 | + : | |
| 889 | + : "a"(current->thread.sp), "a"(current->thread.pc)); | |
| 890 | +} | |
| 891 | + | |
| 892 | +/** | |
| 893 | + * __cpu_up - Set smp_commenced_mask for the nominated CPU | |
| 894 | + * @cpu: The target CPU. | |
| 895 | + */ | |
| 896 | +int __devinit __cpu_up(unsigned int cpu) | |
| 897 | +{ | |
| 898 | + int timeout; | |
| 899 | + | |
| 900 | +#ifdef CONFIG_HOTPLUG_CPU | |
| 901 | + if (num_online_cpus() == 1) | |
| 902 | + disable_hlt(); | |
| 903 | + if (sleep_mode[cpu]) | |
| 904 | + run_wakeup_cpu(cpu); | |
| 905 | +#endif /* CONFIG_HOTPLUG_CPU */ | |
| 906 | + | |
| 907 | + cpu_set(cpu, smp_commenced_mask); | |
| 908 | + | |
| 909 | + /* Wait 5s total for a response */ | |
| 910 | + for (timeout = 0 ; timeout < 5000 ; timeout++) { | |
| 911 | + if (cpu_isset(cpu, cpu_online_map)) | |
| 912 | + break; | |
| 913 | + udelay(1000); | |
| 914 | + } | |
| 915 | + | |
| 916 | + BUG_ON(!cpu_isset(cpu, cpu_online_map)); | |
| 917 | + return 0; | |
| 918 | +} | |
| 919 | + | |
| 920 | +/** | |
| 921 | + * setup_profiling_timer - Set up the profiling timer | |
| 922 | + * @multiplier - The frequency multiplier to use | |
| 923 | + * | |
| 924 | + * The frequency of the profiling timer can be changed by writing a multiplier | |
| 925 | + * value into /proc/profile. | |
| 926 | + */ | |
| 927 | +int setup_profiling_timer(unsigned int multiplier) | |
| 928 | +{ | |
| 929 | + return -EINVAL; | |
| 930 | +} | |
| 931 | + | |
| 932 | +/* | |
| 933 | + * CPU hotplug routines | |
| 934 | + */ | |
| 935 | +#ifdef CONFIG_HOTPLUG_CPU | |
| 936 | + | |
| 937 | +static DEFINE_PER_CPU(struct cpu, cpu_devices); | |
| 938 | + | |
| 939 | +static int __init topology_init(void) | |
| 940 | +{ | |
| 941 | + int cpu, ret; | |
| 942 | + | |
| 943 | + for_each_cpu(cpu) { | |
| 944 | + ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL); | |
| 945 | + if (ret) | |
| 946 | + printk(KERN_WARNING | |
| 947 | + "topology_init: register_cpu %d failed (%d)\n", | |
| 948 | + cpu, ret); | |
| 949 | + } | |
| 950 | + return 0; | |
| 951 | +} | |
| 952 | + | |
| 953 | +subsys_initcall(topology_init); | |
| 954 | + | |
| 955 | +int __cpu_disable(void) | |
| 956 | +{ | |
| 957 | + int cpu = smp_processor_id(); | |
| 958 | + if (cpu == 0) | |
| 959 | + return -EBUSY; | |
| 960 | + | |
| 961 | + migrate_irqs(); | |
| 962 | + cpu_clear(cpu, current->active_mm->cpu_vm_mask); | |
| 963 | + return 0; | |
| 964 | +} | |
| 965 | + | |
| 966 | +void __cpu_die(unsigned int cpu) | |
| 967 | +{ | |
| 968 | + run_sleep_cpu(cpu); | |
| 969 | + | |
| 970 | + if (num_online_cpus() == 1) | |
| 971 | + enable_hlt(); | |
| 972 | +} | |
| 973 | + | |
| 974 | +#ifdef CONFIG_MN10300_CACHE_ENABLED | |
| 975 | +static inline void hotplug_cpu_disable_cache(void) | |
| 976 | +{ | |
| 977 | + int tmp; | |
| 978 | + asm volatile( | |
| 979 | + " movhu (%1),%0 \n" | |
| 980 | + " and %2,%0 \n" | |
| 981 | + " movhu %0,(%1) \n" | |
| 982 | + "1: movhu (%1),%0 \n" | |
| 983 | + " btst %3,%0 \n" | |
| 984 | + " bne 1b \n" | |
| 985 | + : "=&r"(tmp) | |
| 986 | + : "a"(&CHCTR), | |
| 987 | + "i"(~(CHCTR_ICEN | CHCTR_DCEN)), | |
| 988 | + "i"(CHCTR_ICBUSY | CHCTR_DCBUSY) | |
| 989 | + : "memory", "cc"); | |
| 990 | +} | |
| 991 | + | |
| 992 | +static inline void hotplug_cpu_enable_cache(void) | |
| 993 | +{ | |
| 994 | + int tmp; | |
| 995 | + asm volatile( | |
| 996 | + "movhu (%1),%0 \n" | |
| 997 | + "or %2,%0 \n" | |
| 998 | + "movhu %0,(%1) \n" | |
| 999 | + : "=&r"(tmp) | |
| 1000 | + : "a"(&CHCTR), | |
| 1001 | + "i"(CHCTR_ICEN | CHCTR_DCEN) | |
| 1002 | + : "memory", "cc"); | |
| 1003 | +} | |
| 1004 | + | |
| 1005 | +static inline void hotplug_cpu_invalidate_cache(void) | |
| 1006 | +{ | |
| 1007 | + int tmp; | |
| 1008 | + asm volatile ( | |
| 1009 | + "movhu (%1),%0 \n" | |
| 1010 | + "or %2,%0 \n" | |
| 1011 | + "movhu %0,(%1) \n" | |
| 1012 | + : "=&r"(tmp) | |
| 1013 | + : "a"(&CHCTR), | |
| 1014 | + "i"(CHCTR_ICINV | CHCTR_DCINV) | |
| 1015 | + : "cc"); | |
| 1016 | +} | |
| 1017 | + | |
| 1018 | +#else /* CONFIG_MN10300_CACHE_ENABLED */ | |
| 1019 | +#define hotplug_cpu_disable_cache() do {} while (0) | |
| 1020 | +#define hotplug_cpu_enable_cache() do {} while (0) | |
| 1021 | +#define hotplug_cpu_invalidate_cache() do {} while (0) | |
| 1022 | +#endif /* CONFIG_MN10300_CACHE_ENABLED */ | |
| 1023 | + | |
| 1024 | +/** | |
| 1025 | + * hotplug_cpu_nmi_call_function - Call a function on other CPUs for hotplug | |
| 1026 | + * @cpumask: List of target CPUs. | |
| 1027 | + * @func: The function to call on those CPUs. | |
| 1028 | + * @info: The context data for the function to be called. | |
| 1029 | + * @wait: Whether to wait for the calls to complete. | |
| 1030 | + * | |
| 1031 | + * Non-maskably call a function on another CPU for hotplug purposes. | |
| 1032 | + * | |
| 1033 | + * This function must be called with maskable interrupts disabled. | |
| 1034 | + */ | |
| 1035 | +static int hotplug_cpu_nmi_call_function(cpumask_t cpumask, | |
| 1036 | + smp_call_func_t func, void *info, | |
| 1037 | + int wait) | |
| 1038 | +{ | |
| 1039 | + /* | |
| 1040 | + * The address and the size of nmi_call_func_mask_data | |
| 1041 | + * need to be aligned on L1_CACHE_BYTES. | |
| 1042 | + */ | |
| 1043 | + static struct nmi_call_data_struct nmi_call_func_mask_data | |
| 1044 | + __cacheline_aligned; | |
| 1045 | + unsigned long start, end; | |
| 1046 | + | |
| 1047 | + start = (unsigned long)&nmi_call_func_mask_data; | |
| 1048 | + end = start + sizeof(struct nmi_call_data_struct); | |
| 1049 | + | |
| 1050 | + nmi_call_func_mask_data.func = func; | |
| 1051 | + nmi_call_func_mask_data.info = info; | |
| 1052 | + nmi_call_func_mask_data.started = cpumask; | |
| 1053 | + nmi_call_func_mask_data.wait = wait; | |
| 1054 | + if (wait) | |
| 1055 | + nmi_call_func_mask_data.finished = cpumask; | |
| 1056 | + | |
| 1057 | + spin_lock(&smp_nmi_call_lock); | |
| 1058 | + nmi_call_data = &nmi_call_func_mask_data; | |
| 1059 | + mn10300_local_dcache_flush_range(start, end); | |
| 1060 | + smp_wmb(); | |
| 1061 | + | |
| 1062 | + send_IPI_mask(cpumask, CALL_FUNCTION_NMI_IPI); | |
| 1063 | + | |
| 1064 | + do { | |
| 1065 | + mn10300_local_dcache_inv_range(start, end); | |
| 1066 | + barrier(); | |
| 1067 | + } while (!cpus_empty(nmi_call_func_mask_data.started)); | |
| 1068 | + | |
| 1069 | + if (wait) { | |
| 1070 | + do { | |
| 1071 | + mn10300_local_dcache_inv_range(start, end); | |
| 1072 | + barrier(); | |
| 1073 | + } while (!cpus_empty(nmi_call_func_mask_data.finished)); | |
| 1074 | + } | |
| 1075 | + | |
| 1076 | + spin_unlock(&smp_nmi_call_lock); | |
| 1077 | + return 0; | |
| 1078 | +} | |
| 1079 | + | |
| 1080 | +static void restart_wakeup_cpu(void) | |
| 1081 | +{ | |
| 1082 | + unsigned int cpu = smp_processor_id(); | |
| 1083 | + | |
| 1084 | + cpu_set(cpu, cpu_callin_map); | |
| 1085 | + local_flush_tlb(); | |
| 1086 | + cpu_set(cpu, cpu_online_map); | |
| 1087 | + smp_wmb(); | |
| 1088 | +} | |
| 1089 | + | |
| 1090 | +static void prepare_sleep_cpu(void *unused) | |
| 1091 | +{ | |
| 1092 | + sleep_mode[smp_processor_id()] = 1; | |
| 1093 | + smp_mb(); | |
| 1094 | + mn10300_local_dcache_flush_inv(); | |
| 1095 | + hotplug_cpu_disable_cache(); | |
| 1096 | + hotplug_cpu_invalidate_cache(); | |
| 1097 | +} | |
| 1098 | + | |
| 1099 | +/* when this function called, IE=0, NMID=0. */ | |
| 1100 | +static void sleep_cpu(void *unused) | |
| 1101 | +{ | |
| 1102 | + unsigned int cpu_id = smp_processor_id(); | |
| 1103 | + /* | |
| 1104 | + * CALL_FUNCTION_NMI_IPI for wakeup_cpu() shall not be requested, | |
| 1105 | + * before this cpu goes in SLEEP mode. | |
| 1106 | + */ | |
| 1107 | + do { | |
| 1108 | + smp_mb(); | |
| 1109 | + __sleep_cpu(); | |
| 1110 | + } while (sleep_mode[cpu_id]); | |
| 1111 | + restart_wakeup_cpu(); | |
| 1112 | +} | |
| 1113 | + | |
| 1114 | +static void run_sleep_cpu(unsigned int cpu) | |
| 1115 | +{ | |
| 1116 | + unsigned long flags; | |
| 1117 | + cpumask_t cpumask = cpumask_of(cpu); | |
| 1118 | + | |
| 1119 | + flags = arch_local_cli_save(); | |
| 1120 | + hotplug_cpu_nmi_call_function(cpumask, prepare_sleep_cpu, NULL, 1); | |
| 1121 | + hotplug_cpu_nmi_call_function(cpumask, sleep_cpu, NULL, 0); | |
| 1122 | + udelay(1); /* delay for the cpu to sleep. */ | |
| 1123 | + arch_local_irq_restore(flags); | |
| 1124 | +} | |
| 1125 | + | |
| 1126 | +static void wakeup_cpu(void) | |
| 1127 | +{ | |
| 1128 | + hotplug_cpu_invalidate_cache(); | |
| 1129 | + hotplug_cpu_enable_cache(); | |
| 1130 | + smp_mb(); | |
| 1131 | + sleep_mode[smp_processor_id()] = 0; | |
| 1132 | +} | |
| 1133 | + | |
| 1134 | +static void run_wakeup_cpu(unsigned int cpu) | |
| 1135 | +{ | |
| 1136 | + unsigned long flags; | |
| 1137 | + | |
| 1138 | + flags = arch_local_cli_save(); | |
| 1139 | +#if NR_CPUS == 2 | |
| 1140 | + mn10300_local_dcache_flush_inv(); | |
| 1141 | +#else | |
| 1142 | + /* | |
| 1143 | + * Before waking up the cpu, | |
| 1144 | + * all online cpus should stop and flush D-Cache for global data. | |
| 1145 | + */ | |
| 1146 | +#error not support NR_CPUS > 2, when CONFIG_HOTPLUG_CPU=y. | |
| 1147 | +#endif | |
| 1148 | + hotplug_cpu_nmi_call_function(cpumask_of(cpu), wakeup_cpu, NULL, 1); | |
| 1149 | + arch_local_irq_restore(flags); | |
| 1150 | +} | |
| 1151 | + | |
| 1152 | +#endif /* CONFIG_HOTPLUG_CPU */ | |
| @@ -15,6 +15,9 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <linux/linkage.h> |
| 16 | 16 | #include <asm/thread_info.h> |
| 17 | 17 | #include <asm/cpu-regs.h> |
| 18 | +#ifdef CONFIG_SMP | |
| 19 | +#include <proc/smp-regs.h> | |
| 20 | +#endif /* CONFIG_SMP */ | |
| 18 | 21 | |
| 19 | 22 | .text |
| 20 | 23 | |
| @@ -35,8 +38,6 @@ ENTRY(__switch_to) · 14 unmodified lines | ||
| 35 | 38 | mov d1,a1 |
| 36 | 39 | |
| 37 | 40 | # save prev context |
| 38 | − mov (__frame),d0 | |
| 39 | − mov d0,(THREAD_FRAME,a0) | |
| 40 | 41 | mov __switch_back,d0 |
| 41 | 42 | mov d0,(THREAD_PC,a0) |
| 42 | 43 | mov sp,a2 |
| @@ -58,8 +59,6 @@ ENTRY(__switch_to) · 15 unmodified lines | ||
| 58 | 59 | mov a2,e2 |
| 59 | 60 | #endif |
| 60 | 61 | |
| 61 | − mov (THREAD_FRAME,a1),a2 | |
| 62 | − mov a2,(__frame) | |
| 63 | 62 | mov (THREAD_PC,a1),a2 |
| 64 | 63 | mov d2,d0 # for ret_from_fork |
| 65 | 64 | mov d0,a0 # for __switch_to |
| @@ -17,29 +17,18 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/smp.h> |
| 18 | 18 | #include <linux/profile.h> |
| 19 | 19 | #include <linux/cnt32_to_63.h> |
| 20 | +#include <linux/clocksource.h> | |
| 21 | +#include <linux/clockchips.h> | |
| 20 | 22 | #include <asm/irq.h> |
| 21 | 23 | #include <asm/div64.h> |
| 22 | 24 | #include <asm/processor.h> |
| 23 | 25 | #include <asm/intctl-regs.h> |
| 24 | 26 | #include <asm/rtc.h> |
| 25 | − | |
| 26 | −#ifdef CONFIG_MN10300_RTC | |
| 27 | −unsigned long mn10300_ioclk; /* system I/O clock frequency */ | |
| 28 | −unsigned long mn10300_iobclk; /* system I/O clock frequency */ | |
| 29 | −unsigned long mn10300_tsc_per_HZ; /* number of ioclks per jiffy */ | |
| 30 | −#endif /* CONFIG_MN10300_RTC */ | |
| 27 | +#include "internal.h" | |
| 31 | 28 | |
| 32 | 29 | static unsigned long mn10300_last_tsc; /* time-stamp counter at last time |
| 33 | 30 | * interrupt occurred */ |
| 34 | 31 | |
| 35 | −static irqreturn_t timer_interrupt(int irq, void *dev_id); | |
| 36 | − | |
| 37 | −static struct irqaction timer_irq = { | |
| 38 | − .handler = timer_interrupt, | |
| 39 | − .flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER, | |
| 40 | − .name = "timer", | |
| 41 | −}; | |
| 42 | − | |
| 43 | 32 | static unsigned long sched_clock_multiplier; |
| 44 | 33 | |
| 45 | 34 | /* |
| @@ -54,9 +43,12 @@ unsigned long long sched_clock(void) · 8 unmodified lines | ||
| 54 | 43 | unsigned long tsc, tmp; |
| 55 | 44 | unsigned product[3]; /* 96-bit intermediate value */ |
| 56 | 45 | |
| 46 | + /* cnt32_to_63() is not safe with preemption */ | |
| 47 | + preempt_disable(); | |
| 48 | + | |
| 57 | 49 | /* read the TSC value |
| 58 | 50 | */ |
| 59 | − tsc = 0 - get_cycles(); /* get_cycles() counts down */ | |
| 51 | + tsc = get_cycles(); | |
| 60 | 52 | |
| 61 | 53 | /* expand to 64-bits. |
| 62 | 54 | * - sched_clock() must be called once a minute or better or the |
| @@ -64,6 +56,8 @@ unsigned long long sched_clock(void) · 1 unmodified line | ||
| 64 | 56 | */ |
| 65 | 57 | tsc64.ll = cnt32_to_63(tsc) & 0x7fffffffffffffffULL; |
| 66 | 58 | |
| 59 | + preempt_enable(); | |
| 60 | + | |
| 67 | 61 | /* scale the 64-bit TSC value to a nanosecond value via a 96-bit |
| 68 | 62 | * intermediate |
| 69 | 63 | */ |
| @@ -90,6 +84,20 @@ static void __init mn10300_sched_clock_init(void) · 20 unmodified lines | ||
| 90 | 84 | __muldiv64u(NSEC_PER_SEC, 1 << 16, MN10300_TSCCLK); |
| 91 | 85 | } |
| 92 | 86 | |
| 87 | +/** | |
| 88 | + * local_timer_interrupt - Local timer interrupt handler | |
| 89 | + * | |
| 90 | + * Handle local timer interrupts for this CPU. They may have been propagated | |
| 91 | + * to this CPU from the CPU that actually gets them by way of an IPI. | |
| 92 | + */ | |
| 93 | +irqreturn_t local_timer_interrupt(void) | |
| 94 | +{ | |
| 95 | + profile_tick(CPU_PROFILING); | |
| 96 | + update_process_times(user_mode(get_irq_regs())); | |
| 97 | + return IRQ_HANDLED; | |
| 98 | +} | |
| 99 | + | |
| 100 | +#ifndef CONFIG_GENERIC_TIME | |
| 93 | 101 | /* |
| 94 | 102 | * advance the kernel's time keeping clocks (xtime and jiffies) |
| 95 | 103 | * - we use Timer 0 & 1 cascaded as a clock to nudge us the next time |
| @@ -98,27 +106,73 @@ static void __init mn10300_sched_clock_init(void) · 2 unmodified lines | ||
| 98 | 106 | static irqreturn_t timer_interrupt(int irq, void *dev_id) |
| 99 | 107 | { |
| 100 | 108 | unsigned tsc, elapse; |
| 109 | + irqreturn_t ret; | |
| 101 | 110 | |
| 102 | 111 | write_seqlock(&xtime_lock); |
| 103 | 112 | |
| 104 | 113 | while (tsc = get_cycles(), |
| 105 | − elapse = mn10300_last_tsc - tsc, /* time elapsed since last | |
| 114 | + elapse = tsc - mn10300_last_tsc, /* time elapsed since last | |
| 106 | 115 | * tick */ |
| 107 | 116 | elapse > MN10300_TSC_PER_HZ |
| 108 | 117 | ) { |
| 109 | − mn10300_last_tsc -= MN10300_TSC_PER_HZ; | |
| 118 | + mn10300_last_tsc += MN10300_TSC_PER_HZ; | |
| 110 | 119 | |
| 111 | 120 | /* advance the kernel's time tracking system */ |
| 112 | − profile_tick(CPU_PROFILING); | |
| 113 | 121 | do_timer(1); |
| 114 | 122 | } |
| 115 | 123 | |
| 116 | 124 | write_sequnlock(&xtime_lock); |
| 117 | 125 | |
| 118 | − update_process_times(user_mode(get_irq_regs())); | |
| 126 | + ret = local_timer_interrupt(); | |
| 127 | +#ifdef CONFIG_SMP | |
| 128 | + send_IPI_allbutself(LOCAL_TIMER_IPI); | |
| 129 | +#endif | |
| 130 | + return ret; | |
| 131 | +} | |
| 119 | 132 | |
| 120 | − return IRQ_HANDLED; | |
| 133 | +static struct irqaction timer_irq = { | |
| 134 | + .handler = timer_interrupt, | |
| 135 | + .flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER, | |
| 136 | + .name = "timer", | |
| 137 | +}; | |
| 138 | +#endif /* CONFIG_GENERIC_TIME */ | |
| 139 | + | |
| 140 | +#ifdef CONFIG_CSRC_MN10300 | |
| 141 | +void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock) | |
| 142 | +{ | |
| 143 | + u64 temp; | |
| 144 | + u32 shift; | |
| 145 | + | |
| 146 | + /* Find a shift value */ | |
| 147 | + for (shift = 32; shift > 0; shift--) { | |
| 148 | + temp = (u64) NSEC_PER_SEC << shift; | |
| 149 | + do_div(temp, clock); | |
| 150 | + if ((temp >> 32) == 0) | |
| 151 | + break; | |
| 152 | + } | |
| 153 | + cs->shift = shift; | |
| 154 | + cs->mult = (u32) temp; | |
| 121 | 155 | } |
| 156 | +#endif | |
| 157 | + | |
| 158 | +#if CONFIG_CEVT_MN10300 | |
| 159 | +void __cpuinit clockevent_set_clock(struct clock_event_device *cd, | |
| 160 | + unsigned int clock) | |
| 161 | +{ | |
| 162 | + u64 temp; | |
| 163 | + u32 shift; | |
| 164 | + | |
| 165 | + /* Find a shift value */ | |
| 166 | + for (shift = 32; shift > 0; shift--) { | |
| 167 | + temp = (u64) clock << shift; | |
| 168 | + do_div(temp, NSEC_PER_SEC); | |
| 169 | + if ((temp >> 32) == 0) | |
| 170 | + break; | |
| 171 | + } | |
| 172 | + cd->shift = shift; | |
| 173 | + cd->mult = (u32) temp; | |
| 174 | +} | |
| 175 | +#endif | |
| 122 | 176 | |
| 123 | 177 | /* |
| 124 | 178 | * initialise the various timers used by the main part of the kernel |
| @@ -131,21 +185,25 @@ void __init time_init(void) · 6 unmodified lines | ||
| 131 | 185 | */ |
| 132 | 186 | TMPSCNT |= TMPSCNT_ENABLE; |
| 133 | 187 | |
| 188 | +#ifdef CONFIG_GENERIC_TIME | |
| 189 | + init_clocksource(); | |
| 190 | +#else | |
| 134 | 191 | startup_timestamp_counter(); |
| 192 | +#endif | |
| 135 | 193 | |
| 136 | 194 | printk(KERN_INFO |
| 137 | 195 | "timestamp counter I/O clock running at %lu.%02lu" |
| 138 | 196 | " (calibrated against RTC)\n", |
| 139 | 197 | MN10300_TSCCLK / 1000000, (MN10300_TSCCLK / 10000) % 100); |
| 140 | 198 | |
| 141 | − mn10300_last_tsc = TMTSCBC; | |
| 142 | − | |
| 143 | − /* use timer 0 & 1 cascaded to tick at as close to HZ as possible */ | |
| 144 | − setup_irq(TMJCIRQ, &timer_irq); | |
| 199 | + mn10300_last_tsc = read_timestamp_counter(); | |
| 145 | 200 | |
| 146 | − set_intr_level(TMJCIRQ, TMJCICR_LEVEL); | |
| 147 | − | |
| 148 | − startup_jiffies_counter(); | |
| 201 | +#ifdef CONFIG_GENERIC_CLOCKEVENTS | |
| 202 | + init_clockevents(); | |
| 203 | +#else | |
| 204 | + reload_jiffies_counter(MN10300_JC_PER_HZ - 1); | |
| 205 | + setup_jiffies_interrupt(TMJCIRQ, &timer_irq, CONFIG_TIMER_IRQ_LEVEL); | |
| 206 | +#endif | |
| 149 | 207 | |
| 150 | 208 | #ifdef CONFIG_MN10300_WD_TIMER |
| 151 | 209 | /* start the watchdog timer */ |
| @@ -45,9 +45,6 @@ · 44 unmodified lines | ||
| 45 | 45 | #error "INTERRUPT_VECTOR_BASE not aligned to 16MiB boundary!" |
| 46 | 46 | #endif |
| 47 | 47 | |
| 48 | −struct pt_regs *__frame; /* current frame pointer */ | |
| 49 | −EXPORT_SYMBOL(__frame); | |
| 50 | − | |
| 51 | 48 | int kstack_depth_to_print = 24; |
| 52 | 49 | |
| 53 | 50 | spinlock_t die_lock = __SPIN_LOCK_UNLOCKED(die_lock); |
| @@ -101,7 +98,6 @@ DO_EINFO(SIGILL, {}, "invalid opcode", invalid_op, ILL_ILLOPC); · 47 unmodified lines | ||
| 101 | 98 | DO_EINFO(SIGILL, {}, "invalid ex opcode", invalid_exop, ILL_ILLOPC); |
| 102 | 99 | DO_EINFO(SIGBUS, {}, "invalid address", mem_error, BUS_ADRERR); |
| 103 | 100 | DO_EINFO(SIGBUS, {}, "bus error", bus_error, BUS_ADRERR); |
| 104 | −DO_EINFO(SIGILL, {}, "FPU invalid opcode", fpu_invalid_op, ILL_COPROC); | |
| 105 | 101 | |
| 106 | 102 | DO_ERROR(SIGTRAP, |
| 107 | 103 | #ifndef CONFIG_MN10300_USING_JTAG |
| @@ -222,11 +218,14 @@ void show_registers_only(struct pt_regs *regs) · 114 unmodified lines | ||
| 222 | 218 | printk(KERN_EMERG "threadinfo=%p task=%p)\n", |
| 223 | 219 | current_thread_info(), current); |
| 224 | 220 | |
| 225 | − if ((unsigned long) current >= 0x90000000UL && | |
| 226 | − (unsigned long) current < 0x94000000UL) | |
| 221 | + if ((unsigned long) current >= PAGE_OFFSET && | |
| 222 | + (unsigned long) current < (unsigned long)high_memory) | |
| 227 | 223 | printk(KERN_EMERG "Process %s (pid: %d)\n", |
| 228 | 224 | current->comm, current->pid); |
| 229 | 225 | |
| 226 | +#ifdef CONFIG_SMP | |
| 227 | + printk(KERN_EMERG "CPUID: %08x\n", CPUID); | |
| 228 | +#endif | |
| 230 | 229 | printk(KERN_EMERG "CPUP: %04hx\n", CPUP); |
| 231 | 230 | printk(KERN_EMERG "TBR: %08x\n", TBR); |
| 232 | 231 | printk(KERN_EMERG "DEAR: %08x\n", DEAR); |
| @@ -522,8 +521,12 @@ void __init set_intr_stub(enum exception_code code, void *handler) · 289 unmodified lines | ||
| 522 | 521 | { |
| 523 | 522 | unsigned long addr; |
| 524 | 523 | u8 *vector = (u8 *)(CONFIG_INTERRUPT_VECTOR_BASE + code); |
| 524 | + unsigned long flags; | |
| 525 | 525 | |
| 526 | 526 | addr = (unsigned long) handler - (unsigned long) vector; |
| 527 | + | |
| 528 | + flags = arch_local_cli_save(); | |
| 529 | + | |
| 527 | 530 | vector[0] = 0xdc; /* JMP handler */ |
| 528 | 531 | vector[1] = addr; |
| 529 | 532 | vector[2] = addr >> 8; |
| @@ -533,30 +536,12 @@ void __init set_intr_stub(enum exception_code code, void *handler) · 3 unmodified lines | ||
| 533 | 536 | vector[6] = 0xcb; |
| 534 | 537 | vector[7] = 0xcb; |
| 535 | 538 | |
| 536 | − mn10300_dcache_flush_inv(); | |
| 537 | − mn10300_icache_inv(); | |
| 538 | −} | |
| 539 | − | |
| 540 | −/* | |
| 541 | − * set an interrupt stub to invoke the JTAG unit and then jump to a handler | |
| 542 | − */ | |
| 543 | −void __init set_jtag_stub(enum exception_code code, void *handler) | |
| 544 | −{ | |
| 545 | − unsigned long addr; | |
| 546 | − u8 *vector = (u8 *)(CONFIG_INTERRUPT_VECTOR_BASE + code); | |
| 547 | − | |
| 548 | − addr = (unsigned long) handler - ((unsigned long) vector + 1); | |
| 549 | − vector[0] = 0xff; /* PI to jump into JTAG debugger */ | |
| 550 | − vector[1] = 0xdc; /* jmp handler */ | |
| 551 | − vector[2] = addr; | |
| 552 | − vector[3] = addr >> 8; | |
| 553 | − vector[4] = addr >> 16; | |
| 554 | − vector[5] = addr >> 24; | |
| 555 | − vector[6] = 0xcb; | |
| 556 | − vector[7] = 0xcb; | |
| 539 | + arch_local_irq_restore(flags); | |
| 557 | 540 | |
| 541 | +#ifndef CONFIG_MN10300_CACHE_SNOOP | |
| 558 | 542 | mn10300_dcache_flush_inv(); |
| 559 | − flush_icache_range((unsigned long) vector, (unsigned long) vector + 8); | |
| 543 | + mn10300_icache_inv(); | |
| 544 | +#endif | |
| 560 | 545 | } |
| 561 | 546 | |
| 562 | 547 | /* |
| @@ -581,7 +566,6 @@ void __init trap_init(void) · 18 unmodified lines | ||
| 581 | 566 | set_excp_vector(EXCEP_PRIVINSACC, insn_acc_error); |
| 582 | 567 | set_excp_vector(EXCEP_PRIVDATACC, data_acc_error); |
| 583 | 568 | set_excp_vector(EXCEP_DATINSACC, insn_acc_error); |
| 584 | − set_excp_vector(EXCEP_FPU_DISABLED, fpu_disabled); | |
| 585 | 569 | set_excp_vector(EXCEP_FPU_UNIMPINS, fpu_invalid_op); |
| 586 | 570 | set_excp_vector(EXCEP_FPU_OPERATION, fpu_exception); |
| 587 | 571 | |
| @@ -15,7 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | /* |
| 16 | 16 | * try flipping a bit using BSET and BCLR |
| 17 | 17 | */ |
| 18 | −void change_bit(int nr, volatile void *addr) | |
| 18 | +void change_bit(unsigned long nr, volatile void *addr) | |
| 19 | 19 | { |
| 20 | 20 | if (test_bit(nr, addr)) |
| 21 | 21 | goto try_clear_bit; |
| @@ -34,7 +34,7 @@ try_clear_bit: · 12 unmodified lines | ||
| 34 | 34 | /* |
| 35 | 35 | * try flipping a bit using BSET and BCLR and returning the old value |
| 36 | 36 | */ |
| 37 | −int test_and_change_bit(int nr, volatile void *addr) | |
| 37 | +int test_and_change_bit(unsigned long nr, volatile void *addr) | |
| 38 | 38 | { |
| 39 | 39 | if (test_bit(nr, addr)) |
| 40 | 40 | goto try_clear_bit; |
| @@ -38,14 +38,14 @@ EXPORT_SYMBOL(__delay); · 37 unmodified lines | ||
| 38 | 38 | */ |
| 39 | 39 | void __udelay(unsigned long usecs) |
| 40 | 40 | { |
| 41 | − signed long ioclk, stop; | |
| 41 | + unsigned long start, stop, cnt; | |
| 42 | 42 | |
| 43 | 43 | /* usecs * CLK / 1E6 */ |
| 44 | 44 | stop = __muldiv64u(usecs, MN10300_TSCCLK, 1000000); |
| 45 | − stop = TMTSCBC - stop; | |
| 45 | + start = TMTSCBC; | |
| 46 | 46 | |
| 47 | 47 | do { |
| 48 | − ioclk = TMTSCBC; | |
| 49 | − } while (stop < ioclk); | |
| 48 | + cnt = start - TMTSCBC; | |
| 49 | + } while (cnt < stop); | |
| 50 | 50 | } |
| 51 | 51 | EXPORT_SYMBOL(__udelay); |
| @@ -10,26 +10,25 @@ · 9 unmodified lines | ||
| 10 | 10 | */ |
| 11 | 11 | #include <asm/cache.h> |
| 12 | 12 | |
| 13 | − .section .text | |
| 14 | − .balign L1_CACHE_BYTES | |
| 13 | + .section .text | |
| 14 | + .balign L1_CACHE_BYTES | |
| 15 | 15 | |
| 16 | 16 | ############################################################################### |
| 17 | 17 | # |
| 18 | −# unsigned int do_csum(const unsigned char *buff, size_t len) | |
| 18 | +# unsigned int do_csum(const unsigned char *buff, int len) | |
| 19 | 19 | # |
| 20 | 20 | ############################################################################### |
| 21 | 21 | .globl do_csum |
| 22 | − .type do_csum,@function | |
| 22 | + .type do_csum,@function | |
| 23 | 23 | do_csum: |
| 24 | 24 | movm [d2,d3],(sp) |
| 25 | − mov d0,(12,sp) | |
| 26 | − mov d1,(16,sp) | |
| 27 | 25 | mov d1,d2 # count |
| 28 | 26 | mov d0,a0 # buff |
| 27 | + mov a0,a1 | |
| 29 | 28 | clr d1 # accumulator |
| 30 | 29 | |
| 31 | 30 | cmp +0,d2 |
| 32 | − beq do_csum_done # return if zero-length buffer | |
| 31 | + ble do_csum_done # check for zero length or negative | |
| 33 | 32 | |
| 34 | 33 | # 4-byte align the buffer pointer |
| 35 | 34 | btst +3,a0 |
| @@ -41,17 +40,15 @@ do_csum: · 5 unmodified lines | ||
| 41 | 40 | inc a0 |
| 42 | 41 | asl +8,d0 |
| 43 | 42 | add d0,d1 |
| 44 | − addc +0,d1 | |
| 45 | 43 | add -1,d2 |
| 46 | −do_csum_addr_not_odd: | |
| 47 | 44 | |
| 45 | +do_csum_addr_not_odd: | |
| 48 | 46 | cmp +2,d2 |
| 49 | 47 | bcs do_csum_fewer_than_4 |
| 50 | 48 | btst +2,a0 |
| 51 | 49 | beq do_csum_now_4b_aligned |
| 52 | 50 | movhu (a0+),d0 |
| 53 | 51 | add d0,d1 |
| 54 | − addc +0,d1 | |
| 55 | 52 | add -2,d2 |
| 56 | 53 | cmp +4,d2 |
| 57 | 54 | bcs do_csum_fewer_than_4 |
| @@ -66,20 +63,20 @@ do_csum_now_4b_aligned: · 8 unmodified lines | ||
| 66 | 63 | |
| 67 | 64 | do_csum_loop: |
| 68 | 65 | mov (a0+),d0 |
| 69 | − add d0,d1 | |
| 70 | 66 | mov (a0+),e0 |
| 71 | − addc e0,d1 | |
| 72 | 67 | mov (a0+),e1 |
| 73 | − addc e1,d1 | |
| 74 | 68 | mov (a0+),e3 |
| 69 | + add d0,d1 | |
| 70 | + addc e0,d1 | |
| 71 | + addc e1,d1 | |
| 75 | 72 | addc e3,d1 |
| 76 | 73 | mov (a0+),d0 |
| 77 | − addc d0,d1 | |
| 78 | 74 | mov (a0+),e0 |
| 79 | − addc e0,d1 | |
| 80 | 75 | mov (a0+),e1 |
| 81 | − addc e1,d1 | |
| 82 | 76 | mov (a0+),e3 |
| 77 | + addc d0,d1 | |
| 78 | + addc e0,d1 | |
| 79 | + addc e1,d1 | |
| 83 | 80 | addc e3,d1 |
| 84 | 81 | addc +0,d1 |
| 85 | 82 | |
| @@ -94,12 +91,12 @@ do_csum_remainder: · 8 unmodified lines | ||
| 94 | 91 | cmp +16,d2 |
| 95 | 92 | bcs do_csum_fewer_than_16 |
| 96 | 93 | mov (a0+),d0 |
| 97 | − add d0,d1 | |
| 98 | 94 | mov (a0+),e0 |
| 99 | − addc e0,d1 | |
| 100 | 95 | mov (a0+),e1 |
| 101 | − addc e1,d1 | |
| 102 | 96 | mov (a0+),e3 |
| 97 | + add d0,d1 | |
| 98 | + addc e0,d1 | |
| 99 | + addc e1,d1 | |
| 103 | 100 | addc e3,d1 |
| 104 | 101 | addc +0,d1 |
| 105 | 102 | add -16,d2 |
| @@ -131,9 +128,9 @@ do_csum_fewer_than_4: · 25 unmodified lines | ||
| 131 | 128 | xor_cmp d0,d0,+2,d2 |
| 132 | 129 | bcs do_csum_fewer_than_2 |
| 133 | 130 | movhu (a0+),d0 |
| 134 | −do_csum_fewer_than_2: | |
| 135 | 131 | and +1,d2 |
| 136 | 132 | beq do_csum_add_last_bit |
| 133 | +do_csum_fewer_than_2: | |
| 137 | 134 | movbu (a0),d3 |
| 138 | 135 | add d3,d0 |
| 139 | 136 | do_csum_add_last_bit: |
| @@ -142,21 +139,19 @@ do_csum_add_last_bit: · 2 unmodified lines | ||
| 142 | 139 | |
| 143 | 140 | do_csum_done: |
| 144 | 141 | # compress the checksum down to 16 bits |
| 145 | − mov +0xffff0000,d2 | |
| 146 | − and d1,d2 | |
| 142 | + mov +0xffff0000,d0 | |
| 143 | + and d1,d0 | |
| 147 | 144 | asl +16,d1 |
| 148 | − add d2,d1,d0 | |
| 145 | + add d1,d0 | |
| 149 | 146 | addc +0xffff,d0 |
| 150 | 147 | lsr +16,d0 |
| 151 | 148 | |
| 152 | 149 | # flip the halves of the word result if the buffer was oddly aligned |
| 153 | − mov (12,sp),d1 | |
| 154 | − and +1,d1 | |
| 150 | + and +1,a1 | |
| 155 | 151 | beq do_csum_not_oddly_aligned |
| 156 | 152 | swaph d0,d0 # exchange bits 15:8 with 7:0 |
| 157 | 153 | |
| 158 | 154 | do_csum_not_oddly_aligned: |
| 159 | 155 | ret [d2,d3],8 |
| 160 | 156 | |
| 161 | −do_csum_end: | |
| 162 | − .size do_csum, do_csum_end-do_csum | |
| 157 | + .size do_csum, .-do_csum | |
| @@ -0,0 +1,101 @@ | ||
| 1 | +# | |
| 2 | +# MN10300 CPU cache options | |
| 3 | +# | |
| 4 | + | |
| 5 | +choice | |
| 6 | + prompt "CPU Caching mode" | |
| 7 | + default MN10300_CACHE_WBACK | |
| 8 | + help | |
| 9 | + This option determines the caching mode for the kernel. | |
| 10 | + | |
| 11 | + Write-Back caching mode involves the all reads and writes causing | |
| 12 | + the affected cacheline to be read into the cache first before being | |
| 13 | + operated upon. Memory is not then updated by a write until the cache | |
| 14 | + is filled and a cacheline needs to be displaced from the cache to | |
| 15 | + make room. Only at that point is it written back. | |
| 16 | + | |
| 17 | + Write-Through caching only fetches cachelines from memory on a | |
| 18 | + read. Writes always get written directly to memory. If the affected | |
| 19 | + cacheline is also in cache, it will be updated too. | |
| 20 | + | |
| 21 | + The final option is to turn of caching entirely. | |
| 22 | + | |
| 23 | +config MN10300_CACHE_WBACK | |
| 24 | + bool "Write-Back" | |
| 25 | + help | |
| 26 | + The dcache operates in delayed write-back mode. It must be manually | |
| 27 | + flushed if writes are made that subsequently need to be executed or | |
| 28 | + to be DMA'd by a device. | |
| 29 | + | |
| 30 | +config MN10300_CACHE_WTHRU | |
| 31 | + bool "Write-Through" | |
| 32 | + help | |
| 33 | + The dcache operates in immediate write-through mode. Writes are | |
| 34 | + committed to RAM immediately in addition to being stored in the | |
| 35 | + cache. This means that the written data is immediately available for | |
| 36 | + execution or DMA. | |
| 37 | + | |
| 38 | + This is not available for use with an SMP kernel if cache flushing | |
| 39 | + and invalidation by automatic purge register is not selected. | |
| 40 | + | |
| 41 | +config MN10300_CACHE_DISABLED | |
| 42 | + bool "Disabled" | |
| 43 | + help | |
| 44 | + The icache and dcache are disabled. | |
| 45 | + | |
| 46 | +endchoice | |
| 47 | + | |
| 48 | +config MN10300_CACHE_ENABLED | |
| 49 | + def_bool y if !MN10300_CACHE_DISABLED | |
| 50 | + | |
| 51 | + | |
| 52 | +choice | |
| 53 | + prompt "CPU cache flush/invalidate method" | |
| 54 | + default MN10300_CACHE_MANAGE_BY_TAG if !AM34_2 | |
| 55 | + default MN10300_CACHE_MANAGE_BY_REG if AM34_2 | |
| 56 | + depends on MN10300_CACHE_ENABLED | |
| 57 | + help | |
| 58 | + This determines the method by which CPU cache flushing and | |
| 59 | + invalidation is performed. | |
| 60 | + | |
| 61 | +config MN10300_CACHE_MANAGE_BY_TAG | |
| 62 | + bool "Use the cache tag registers directly" | |
| 63 | + depends on !(SMP && MN10300_CACHE_WTHRU) | |
| 64 | + | |
| 65 | +config MN10300_CACHE_MANAGE_BY_REG | |
| 66 | + bool "Flush areas by way of automatic purge registers (AM34 only)" | |
| 67 | + depends on AM34_2 | |
| 68 | + | |
| 69 | +endchoice | |
| 70 | + | |
| 71 | +config MN10300_CACHE_INV_BY_TAG | |
| 72 | + def_bool y if MN10300_CACHE_MANAGE_BY_TAG && MN10300_CACHE_ENABLED | |
| 73 | + | |
| 74 | +config MN10300_CACHE_INV_BY_REG | |
| 75 | + def_bool y if MN10300_CACHE_MANAGE_BY_REG && MN10300_CACHE_ENABLED | |
| 76 | + | |
| 77 | +config MN10300_CACHE_FLUSH_BY_TAG | |
| 78 | + def_bool y if MN10300_CACHE_MANAGE_BY_TAG && MN10300_CACHE_WBACK | |
| 79 | + | |
| 80 | +config MN10300_CACHE_FLUSH_BY_REG | |
| 81 | + def_bool y if MN10300_CACHE_MANAGE_BY_REG && MN10300_CACHE_WBACK | |
| 82 | + | |
| 83 | + | |
| 84 | +config MN10300_HAS_CACHE_SNOOP | |
| 85 | + def_bool n | |
| 86 | + | |
| 87 | +config MN10300_CACHE_SNOOP | |
| 88 | + bool "Use CPU Cache Snooping" | |
| 89 | + depends on MN10300_CACHE_ENABLED && MN10300_HAS_CACHE_SNOOP | |
| 90 | + default y | |
| 91 | + | |
| 92 | +config MN10300_CACHE_FLUSH_ICACHE | |
| 93 | + def_bool y if MN10300_CACHE_WBACK && !MN10300_CACHE_SNOOP | |
| 94 | + help | |
| 95 | + Set if we need the dcache flushing before the icache is invalidated. | |
| 96 | + | |
| 97 | +config MN10300_CACHE_INV_ICACHE | |
| 98 | + def_bool y if MN10300_CACHE_WTHRU && !MN10300_CACHE_SNOOP | |
| 99 | + help | |
| 100 | + Set if we need the icache to be invalidated, even if the dcache is in | |
| 101 | + write-through mode and doesn't need flushing. | |
| @@ -2,11 +2,21 @@ · 1 unmodified line | ||
| 2 | 2 | # Makefile for the MN10300-specific memory management code |
| 3 | 3 | # |
| 4 | 4 | |
| 5 | −cacheflush-y := cache.o cache-mn10300.o | |
| 6 | −cacheflush-$(CONFIG_MN10300_CACHE_WBACK) += cache-flush-mn10300.o | |
| 5 | +cache-smp-wback-$(CONFIG_MN10300_CACHE_WBACK) := cache-smp-flush.o | |
| 6 | + | |
| 7 | +cacheflush-y := cache.o | |
| 8 | +cacheflush-$(CONFIG_SMP) += cache-smp.o cache-smp-inv.o $(cache-smp-wback-y) | |
| 9 | +cacheflush-$(CONFIG_MN10300_CACHE_INV_ICACHE) += cache-inv-icache.o | |
| 10 | +cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_ICACHE) += cache-flush-icache.o | |
| 11 | +cacheflush-$(CONFIG_MN10300_CACHE_INV_BY_TAG) += cache-inv-by-tag.o | |
| 12 | +cacheflush-$(CONFIG_MN10300_CACHE_INV_BY_REG) += cache-inv-by-reg.o | |
| 13 | +cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_TAG) += cache-flush-by-tag.o | |
| 14 | +cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_REG) += cache-flush-by-reg.o | |
| 7 | 15 | |
| 8 | 16 | cacheflush-$(CONFIG_MN10300_CACHE_DISABLED) := cache-disabled.o |
| 9 | 17 | |
| 10 | 18 | obj-y := \ |
| 11 | 19 | init.o fault.o pgtable.o extable.o tlb-mn10300.o mmu-context.o \ |
| 12 | 20 | misalignment.o dma-alloc.o $(cacheflush-y) |
| 21 | + | |
| 22 | +obj-$(CONFIG_SMP) += tlb-smp.o | |
| @@ -0,0 +1,308 @@ | ||
| 1 | +/* MN10300 CPU core caching routines, using indirect regs on cache controller | |
| 2 | + * | |
| 3 | + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <linux/sys.h> | |
| 13 | +#include <linux/linkage.h> | |
| 14 | +#include <asm/smp.h> | |
| 15 | +#include <asm/page.h> | |
| 16 | +#include <asm/cache.h> | |
| 17 | +#include <asm/irqflags.h> | |
| 18 | + | |
| 19 | + .am33_2 | |
| 20 | + | |
| 21 | +#ifndef CONFIG_SMP | |
| 22 | + .globl mn10300_dcache_flush | |
| 23 | + .globl mn10300_dcache_flush_page | |
| 24 | + .globl mn10300_dcache_flush_range | |
| 25 | + .globl mn10300_dcache_flush_range2 | |
| 26 | + .globl mn10300_dcache_flush_inv | |
| 27 | + .globl mn10300_dcache_flush_inv_page | |
| 28 | + .globl mn10300_dcache_flush_inv_range | |
| 29 | + .globl mn10300_dcache_flush_inv_range2 | |
| 30 | + | |
| 31 | +mn10300_dcache_flush = mn10300_local_dcache_flush | |
| 32 | +mn10300_dcache_flush_page = mn10300_local_dcache_flush_page | |
| 33 | +mn10300_dcache_flush_range = mn10300_local_dcache_flush_range | |
| 34 | +mn10300_dcache_flush_range2 = mn10300_local_dcache_flush_range2 | |
| 35 | +mn10300_dcache_flush_inv = mn10300_local_dcache_flush_inv | |
| 36 | +mn10300_dcache_flush_inv_page = mn10300_local_dcache_flush_inv_page | |
| 37 | +mn10300_dcache_flush_inv_range = mn10300_local_dcache_flush_inv_range | |
| 38 | +mn10300_dcache_flush_inv_range2 = mn10300_local_dcache_flush_inv_range2 | |
| 39 | + | |
| 40 | +#endif /* !CONFIG_SMP */ | |
| 41 | + | |
| 42 | +############################################################################### | |
| 43 | +# | |
| 44 | +# void mn10300_local_dcache_flush(void) | |
| 45 | +# Flush the entire data cache back to RAM | |
| 46 | +# | |
| 47 | +############################################################################### | |
| 48 | + ALIGN | |
| 49 | + .globl mn10300_local_dcache_flush | |
| 50 | + .type mn10300_local_dcache_flush,@function | |
| 51 | +mn10300_local_dcache_flush: | |
| 52 | + movhu (CHCTR),d0 | |
| 53 | + btst CHCTR_DCEN,d0 | |
| 54 | + beq mn10300_local_dcache_flush_end | |
| 55 | + | |
| 56 | + mov DCPGCR,a0 | |
| 57 | + | |
| 58 | + LOCAL_CLI_SAVE(d1) | |
| 59 | + | |
| 60 | + # wait for busy bit of area purge | |
| 61 | + setlb | |
| 62 | + mov (a0),d0 | |
| 63 | + btst DCPGCR_DCPGBSY,d0 | |
| 64 | + lne | |
| 65 | + | |
| 66 | + # set mask | |
| 67 | + clr d0 | |
| 68 | + mov d0,(DCPGMR) | |
| 69 | + | |
| 70 | + # area purge | |
| 71 | + # | |
| 72 | + # DCPGCR = DCPGCR_DCP | |
| 73 | + # | |
| 74 | + mov DCPGCR_DCP,d0 | |
| 75 | + mov d0,(a0) | |
| 76 | + | |
| 77 | + # wait for busy bit of area purge | |
| 78 | + setlb | |
| 79 | + mov (a0),d0 | |
| 80 | + btst DCPGCR_DCPGBSY,d0 | |
| 81 | + lne | |
| 82 | + | |
| 83 | + LOCAL_IRQ_RESTORE(d1) | |
| 84 | + | |
| 85 | +mn10300_local_dcache_flush_end: | |
| 86 | + ret [],0 | |
| 87 | + .size mn10300_local_dcache_flush,.-mn10300_local_dcache_flush | |
| 88 | + | |
| 89 | +############################################################################### | |
| 90 | +# | |
| 91 | +# void mn10300_local_dcache_flush_page(unsigned long start) | |
| 92 | +# void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end) | |
| 93 | +# void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size) | |
| 94 | +# Flush a range of addresses on a page in the dcache | |
| 95 | +# | |
| 96 | +############################################################################### | |
| 97 | + ALIGN | |
| 98 | + .globl mn10300_local_dcache_flush_page | |
| 99 | + .globl mn10300_local_dcache_flush_range | |
| 100 | + .globl mn10300_local_dcache_flush_range2 | |
| 101 | + .type mn10300_local_dcache_flush_page,@function | |
| 102 | + .type mn10300_local_dcache_flush_range,@function | |
| 103 | + .type mn10300_local_dcache_flush_range2,@function | |
| 104 | +mn10300_local_dcache_flush_page: | |
| 105 | + and ~(PAGE_SIZE-1),d0 | |
| 106 | + mov PAGE_SIZE,d1 | |
| 107 | +mn10300_local_dcache_flush_range2: | |
| 108 | + add d0,d1 | |
| 109 | +mn10300_local_dcache_flush_range: | |
| 110 | + movm [d2,d3,a2],(sp) | |
| 111 | + | |
| 112 | + movhu (CHCTR),d2 | |
| 113 | + btst CHCTR_DCEN,d2 | |
| 114 | + beq mn10300_local_dcache_flush_range_end | |
| 115 | + | |
| 116 | + # calculate alignsize | |
| 117 | + # | |
| 118 | + # alignsize = L1_CACHE_BYTES; | |
| 119 | + # for (i = (end - start - 1) / L1_CACHE_BYTES ; i > 0; i >>= 1) | |
| 120 | + # alignsize <<= 1; | |
| 121 | + # d2 = alignsize; | |
| 122 | + # | |
| 123 | + mov L1_CACHE_BYTES,d2 | |
| 124 | + sub d0,d1,d3 | |
| 125 | + add -1,d3 | |
| 126 | + lsr L1_CACHE_SHIFT,d3 | |
| 127 | + beq 2f | |
| 128 | +1: | |
| 129 | + add d2,d2 | |
| 130 | + lsr 1,d3 | |
| 131 | + bne 1b | |
| 132 | +2: | |
| 133 | + mov d1,a1 # a1 = end | |
| 134 | + | |
| 135 | + LOCAL_CLI_SAVE(d3) | |
| 136 | + mov DCPGCR,a0 | |
| 137 | + | |
| 138 | + # wait for busy bit of area purge | |
| 139 | + setlb | |
| 140 | + mov (a0),d1 | |
| 141 | + btst DCPGCR_DCPGBSY,d1 | |
| 142 | + lne | |
| 143 | + | |
| 144 | + # determine the mask | |
| 145 | + mov d2,d1 | |
| 146 | + add -1,d1 | |
| 147 | + not d1 # d1 = mask = ~(alignsize-1) | |
| 148 | + mov d1,(DCPGMR) | |
| 149 | + | |
| 150 | + and d1,d0,a2 # a2 = mask & start | |
| 151 | + | |
| 152 | +dcpgloop: | |
| 153 | + # area purge | |
| 154 | + mov a2,d0 | |
| 155 | + or DCPGCR_DCP,d0 | |
| 156 | + mov d0,(a0) # DCPGCR = (mask & start) | DCPGCR_DCP | |
| 157 | + | |
| 158 | + # wait for busy bit of area purge | |
| 159 | + setlb | |
| 160 | + mov (a0),d1 | |
| 161 | + btst DCPGCR_DCPGBSY,d1 | |
| 162 | + lne | |
| 163 | + | |
| 164 | + # check purge of end address | |
| 165 | + add d2,a2 # a2 += alignsize | |
| 166 | + cmp a1,a2 # if (a2 < end) goto dcpgloop | |
| 167 | + bns dcpgloop | |
| 168 | + | |
| 169 | + LOCAL_IRQ_RESTORE(d3) | |
| 170 | + | |
| 171 | +mn10300_local_dcache_flush_range_end: | |
| 172 | + ret [d2,d3,a2],12 | |
| 173 | + | |
| 174 | + .size mn10300_local_dcache_flush_page,.-mn10300_local_dcache_flush_page | |
| 175 | + .size mn10300_local_dcache_flush_range,.-mn10300_local_dcache_flush_range | |
| 176 | + .size mn10300_local_dcache_flush_range2,.-mn10300_local_dcache_flush_range2 | |
| 177 | + | |
| 178 | +############################################################################### | |
| 179 | +# | |
| 180 | +# void mn10300_local_dcache_flush_inv(void) | |
| 181 | +# Flush the entire data cache and invalidate all entries | |
| 182 | +# | |
| 183 | +############################################################################### | |
| 184 | + ALIGN | |
| 185 | + .globl mn10300_local_dcache_flush_inv | |
| 186 | + .type mn10300_local_dcache_flush_inv,@function | |
| 187 | +mn10300_local_dcache_flush_inv: | |
| 188 | + movhu (CHCTR),d0 | |
| 189 | + btst CHCTR_DCEN,d0 | |
| 190 | + beq mn10300_local_dcache_flush_inv_end | |
| 191 | + | |
| 192 | + mov DCPGCR,a0 | |
| 193 | + | |
| 194 | + LOCAL_CLI_SAVE(d1) | |
| 195 | + | |
| 196 | + # wait for busy bit of area purge & invalidate | |
| 197 | + setlb | |
| 198 | + mov (a0),d0 | |
| 199 | + btst DCPGCR_DCPGBSY,d0 | |
| 200 | + lne | |
| 201 | + | |
| 202 | + # set the mask to cover everything | |
| 203 | + clr d0 | |
| 204 | + mov d0,(DCPGMR) | |
| 205 | + | |
| 206 | + # area purge & invalidate | |
| 207 | + mov DCPGCR_DCP|DCPGCR_DCI,d0 | |
| 208 | + mov d0,(a0) | |
| 209 | + | |
| 210 | + # wait for busy bit of area purge & invalidate | |
| 211 | + setlb | |
| 212 | + mov (a0),d0 | |
| 213 | + btst DCPGCR_DCPGBSY,d0 | |
| 214 | + lne | |
| 215 | + | |
| 216 | + LOCAL_IRQ_RESTORE(d1) | |
| 217 | + | |
| 218 | +mn10300_local_dcache_flush_inv_end: | |
| 219 | + ret [],0 | |
| 220 | + .size mn10300_local_dcache_flush_inv,.-mn10300_local_dcache_flush_inv | |
| 221 | + | |
| 222 | +############################################################################### | |
| 223 | +# | |
| 224 | +# void mn10300_local_dcache_flush_inv_page(unsigned long start) | |
| 225 | +# void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end) | |
| 226 | +# void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size) | |
| 227 | +# Flush and invalidate a range of addresses on a page in the dcache | |
| 228 | +# | |
| 229 | +############################################################################### | |
| 230 | + ALIGN | |
| 231 | + .globl mn10300_local_dcache_flush_inv_page | |
| 232 | + .globl mn10300_local_dcache_flush_inv_range | |
| 233 | + .globl mn10300_local_dcache_flush_inv_range2 | |
| 234 | + .type mn10300_local_dcache_flush_inv_page,@function | |
| 235 | + .type mn10300_local_dcache_flush_inv_range,@function | |
| 236 | + .type mn10300_local_dcache_flush_inv_range2,@function | |
| 237 | +mn10300_local_dcache_flush_inv_page: | |
| 238 | + and ~(PAGE_SIZE-1),d0 | |
| 239 | + mov PAGE_SIZE,d1 | |
| 240 | +mn10300_local_dcache_flush_inv_range2: | |
| 241 | + add d0,d1 | |
| 242 | +mn10300_local_dcache_flush_inv_range: | |
| 243 | + movm [d2,d3,a2],(sp) | |
| 244 | + | |
| 245 | + movhu (CHCTR),d2 | |
| 246 | + btst CHCTR_DCEN,d2 | |
| 247 | + beq mn10300_local_dcache_flush_inv_range_end | |
| 248 | + | |
| 249 | + # calculate alignsize | |
| 250 | + # | |
| 251 | + # alignsize = L1_CACHE_BYTES; | |
| 252 | + # for (i = (end - start - 1) / L1_CACHE_BYTES; i > 0; i >>= 1) | |
| 253 | + # alignsize <<= 1; | |
| 254 | + # d2 = alignsize | |
| 255 | + # | |
| 256 | + mov L1_CACHE_BYTES,d2 | |
| 257 | + sub d0,d1,d3 | |
| 258 | + add -1,d3 | |
| 259 | + lsr L1_CACHE_SHIFT,d3 | |
| 260 | + beq 2f | |
| 261 | +1: | |
| 262 | + add d2,d2 | |
| 263 | + lsr 1,d3 | |
| 264 | + bne 1b | |
| 265 | +2: | |
| 266 | + mov d1,a1 # a1 = end | |
| 267 | + | |
| 268 | + LOCAL_CLI_SAVE(d3) | |
| 269 | + mov DCPGCR,a0 | |
| 270 | + | |
| 271 | + # wait for busy bit of area purge & invalidate | |
| 272 | + setlb | |
| 273 | + mov (a0),d1 | |
| 274 | + btst DCPGCR_DCPGBSY,d1 | |
| 275 | + lne | |
| 276 | + | |
| 277 | + # set the mask | |
| 278 | + mov d2,d1 | |
| 279 | + add -1,d1 | |
| 280 | + not d1 # d1 = mask = ~(alignsize-1) | |
| 281 | + mov d1,(DCPGMR) | |
| 282 | + | |
| 283 | + and d1,d0,a2 # a2 = mask & start | |
| 284 | + | |
| 285 | +dcpgivloop: | |
| 286 | + # area purge & invalidate | |
| 287 | + mov a2,d0 | |
| 288 | + or DCPGCR_DCP|DCPGCR_DCI,d0 | |
| 289 | + mov d0,(a0) # DCPGCR = (mask & start)|DCPGCR_DCP|DCPGCR_DCI | |
| 290 | + | |
| 291 | + # wait for busy bit of area purge & invalidate | |
| 292 | + setlb | |
| 293 | + mov (a0),d1 | |
| 294 | + btst DCPGCR_DCPGBSY,d1 | |
| 295 | + lne | |
| 296 | + | |
| 297 | + # check purge & invalidate of end address | |
| 298 | + add d2,a2 # a2 += alignsize | |
| 299 | + cmp a1,a2 # if (a2 < end) goto dcpgivloop | |
| 300 | + bns dcpgivloop | |
| 301 | + | |
| 302 | + LOCAL_IRQ_RESTORE(d3) | |
| 303 | + | |
| 304 | +mn10300_local_dcache_flush_inv_range_end: | |
| 305 | + ret [d2,d3,a2],12 | |
| 306 | + .size mn10300_local_dcache_flush_inv_page,.-mn10300_local_dcache_flush_inv_page | |
| 307 | + .size mn10300_local_dcache_flush_inv_range,.-mn10300_local_dcache_flush_inv_range | |
| 308 | + .size mn10300_local_dcache_flush_inv_range2,.-mn10300_local_dcache_flush_inv_range2 | |
| @@ -0,0 +1,251 @@ | ||
| 1 | +/* MN10300 CPU core caching routines, using direct tag flushing | |
| 2 | + * | |
| 3 | + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <linux/sys.h> | |
| 13 | +#include <linux/linkage.h> | |
| 14 | +#include <asm/smp.h> | |
| 15 | +#include <asm/page.h> | |
| 16 | +#include <asm/cache.h> | |
| 17 | +#include <asm/irqflags.h> | |
| 18 | + | |
| 19 | + .am33_2 | |
| 20 | + | |
| 21 | +#ifndef CONFIG_SMP | |
| 22 | + .globl mn10300_dcache_flush | |
| 23 | + .globl mn10300_dcache_flush_page | |
| 24 | + .globl mn10300_dcache_flush_range | |
| 25 | + .globl mn10300_dcache_flush_range2 | |
| 26 | + .globl mn10300_dcache_flush_inv | |
| 27 | + .globl mn10300_dcache_flush_inv_page | |
| 28 | + .globl mn10300_dcache_flush_inv_range | |
| 29 | + .globl mn10300_dcache_flush_inv_range2 | |
| 30 | + | |
| 31 | +mn10300_dcache_flush = mn10300_local_dcache_flush | |
| 32 | +mn10300_dcache_flush_page = mn10300_local_dcache_flush_page | |
| 33 | +mn10300_dcache_flush_range = mn10300_local_dcache_flush_range | |
| 34 | +mn10300_dcache_flush_range2 = mn10300_local_dcache_flush_range2 | |
| 35 | +mn10300_dcache_flush_inv = mn10300_local_dcache_flush_inv | |
| 36 | +mn10300_dcache_flush_inv_page = mn10300_local_dcache_flush_inv_page | |
| 37 | +mn10300_dcache_flush_inv_range = mn10300_local_dcache_flush_inv_range | |
| 38 | +mn10300_dcache_flush_inv_range2 = mn10300_local_dcache_flush_inv_range2 | |
| 39 | + | |
| 40 | +#endif /* !CONFIG_SMP */ | |
| 41 | + | |
| 42 | +############################################################################### | |
| 43 | +# | |
| 44 | +# void mn10300_local_dcache_flush(void) | |
| 45 | +# Flush the entire data cache back to RAM | |
| 46 | +# | |
| 47 | +############################################################################### | |
| 48 | + ALIGN | |
| 49 | + .globl mn10300_local_dcache_flush | |
| 50 | + .type mn10300_local_dcache_flush,@function | |
| 51 | +mn10300_local_dcache_flush: | |
| 52 | + movhu (CHCTR),d0 | |
| 53 | + btst CHCTR_DCEN,d0 | |
| 54 | + beq mn10300_local_dcache_flush_end | |
| 55 | + | |
| 56 | + # read the addresses tagged in the cache's tag RAM and attempt to flush | |
| 57 | + # those addresses specifically | |
| 58 | + # - we rely on the hardware to filter out invalid tag entry addresses | |
| 59 | + mov DCACHE_TAG(0,0),a0 # dcache tag RAM access address | |
| 60 | + mov DCACHE_PURGE(0,0),a1 # dcache purge request address | |
| 61 | + mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of entries | |
| 62 | + | |
| 63 | +mn10300_local_dcache_flush_loop: | |
| 64 | + mov (a0),d0 | |
| 65 | + and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 | |
| 66 | + or L1_CACHE_TAG_VALID,d0 # retain valid entries in the | |
| 67 | + # cache | |
| 68 | + mov d0,(a1) # conditional purge | |
| 69 | + | |
| 70 | + add L1_CACHE_BYTES,a0 | |
| 71 | + add L1_CACHE_BYTES,a1 | |
| 72 | + add -1,d1 | |
| 73 | + bne mn10300_local_dcache_flush_loop | |
| 74 | + | |
| 75 | +mn10300_local_dcache_flush_end: | |
| 76 | + ret [],0 | |
| 77 | + .size mn10300_local_dcache_flush,.-mn10300_local_dcache_flush | |
| 78 | + | |
| 79 | +############################################################################### | |
| 80 | +# | |
| 81 | +# void mn10300_local_dcache_flush_page(unsigned long start) | |
| 82 | +# void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end) | |
| 83 | +# void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size) | |
| 84 | +# Flush a range of addresses on a page in the dcache | |
| 85 | +# | |
| 86 | +############################################################################### | |
| 87 | + ALIGN | |
| 88 | + .globl mn10300_local_dcache_flush_page | |
| 89 | + .globl mn10300_local_dcache_flush_range | |
| 90 | + .globl mn10300_local_dcache_flush_range2 | |
| 91 | + .type mn10300_local_dcache_flush_page,@function | |
| 92 | + .type mn10300_local_dcache_flush_range,@function | |
| 93 | + .type mn10300_local_dcache_flush_range2,@function | |
| 94 | +mn10300_local_dcache_flush_page: | |
| 95 | + and ~(PAGE_SIZE-1),d0 | |
| 96 | + mov PAGE_SIZE,d1 | |
| 97 | +mn10300_local_dcache_flush_range2: | |
| 98 | + add d0,d1 | |
| 99 | +mn10300_local_dcache_flush_range: | |
| 100 | + movm [d2],(sp) | |
| 101 | + | |
| 102 | + movhu (CHCTR),d2 | |
| 103 | + btst CHCTR_DCEN,d2 | |
| 104 | + beq mn10300_local_dcache_flush_range_end | |
| 105 | + | |
| 106 | + sub d0,d1,a0 | |
| 107 | + cmp MN10300_DCACHE_FLUSH_BORDER,a0 | |
| 108 | + ble 1f | |
| 109 | + | |
| 110 | + movm (sp),[d2] | |
| 111 | + bra mn10300_local_dcache_flush | |
| 112 | +1: | |
| 113 | + | |
| 114 | + # round start addr down | |
| 115 | + and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 | |
| 116 | + mov d0,a1 | |
| 117 | + | |
| 118 | + add L1_CACHE_BYTES,d1 # round end addr up | |
| 119 | + and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 | |
| 120 | + | |
| 121 | + # write a request to flush all instances of an address from the cache | |
| 122 | + mov DCACHE_PURGE(0,0),a0 | |
| 123 | + mov a1,d0 | |
| 124 | + and L1_CACHE_TAG_ENTRY,d0 | |
| 125 | + add d0,a0 # starting dcache purge control | |
| 126 | + # reg address | |
| 127 | + | |
| 128 | + sub a1,d1 | |
| 129 | + lsr L1_CACHE_SHIFT,d1 # total number of entries to | |
| 130 | + # examine | |
| 131 | + | |
| 132 | + or L1_CACHE_TAG_VALID,a1 # retain valid entries in the | |
| 133 | + # cache | |
| 134 | + | |
| 135 | +mn10300_local_dcache_flush_range_loop: | |
| 136 | + mov a1,(L1_CACHE_WAYDISP*0,a0) # conditionally purge this line | |
| 137 | + # all ways | |
| 138 | + | |
| 139 | + add L1_CACHE_BYTES,a0 | |
| 140 | + add L1_CACHE_BYTES,a1 | |
| 141 | + and ~L1_CACHE_WAYDISP,a0 # make sure way stay on way 0 | |
| 142 | + add -1,d1 | |
| 143 | + bne mn10300_local_dcache_flush_range_loop | |
| 144 | + | |
| 145 | +mn10300_local_dcache_flush_range_end: | |
| 146 | + ret [d2],4 | |
| 147 | + | |
| 148 | + .size mn10300_local_dcache_flush_page,.-mn10300_local_dcache_flush_page | |
| 149 | + .size mn10300_local_dcache_flush_range,.-mn10300_local_dcache_flush_range | |
| 150 | + .size mn10300_local_dcache_flush_range2,.-mn10300_local_dcache_flush_range2 | |
| 151 | + | |
| 152 | +############################################################################### | |
| 153 | +# | |
| 154 | +# void mn10300_local_dcache_flush_inv(void) | |
| 155 | +# Flush the entire data cache and invalidate all entries | |
| 156 | +# | |
| 157 | +############################################################################### | |
| 158 | + ALIGN | |
| 159 | + .globl mn10300_local_dcache_flush_inv | |
| 160 | + .type mn10300_local_dcache_flush_inv,@function | |
| 161 | +mn10300_local_dcache_flush_inv: | |
| 162 | + movhu (CHCTR),d0 | |
| 163 | + btst CHCTR_DCEN,d0 | |
| 164 | + beq mn10300_local_dcache_flush_inv_end | |
| 165 | + | |
| 166 | + mov L1_CACHE_NENTRIES,d1 | |
| 167 | + clr a1 | |
| 168 | + | |
| 169 | +mn10300_local_dcache_flush_inv_loop: | |
| 170 | + mov (DCACHE_PURGE_WAY0(0),a1),d0 # unconditional purge | |
| 171 | + mov (DCACHE_PURGE_WAY1(0),a1),d0 # unconditional purge | |
| 172 | + mov (DCACHE_PURGE_WAY2(0),a1),d0 # unconditional purge | |
| 173 | + mov (DCACHE_PURGE_WAY3(0),a1),d0 # unconditional purge | |
| 174 | + | |
| 175 | + add L1_CACHE_BYTES,a1 | |
| 176 | + add -1,d1 | |
| 177 | + bne mn10300_local_dcache_flush_inv_loop | |
| 178 | + | |
| 179 | +mn10300_local_dcache_flush_inv_end: | |
| 180 | + ret [],0 | |
| 181 | + .size mn10300_local_dcache_flush_inv,.-mn10300_local_dcache_flush_inv | |
| 182 | + | |
| 183 | +############################################################################### | |
| 184 | +# | |
| 185 | +# void mn10300_local_dcache_flush_inv_page(unsigned long start) | |
| 186 | +# void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end) | |
| 187 | +# void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size) | |
| 188 | +# Flush and invalidate a range of addresses on a page in the dcache | |
| 189 | +# | |
| 190 | +############################################################################### | |
| 191 | + ALIGN | |
| 192 | + .globl mn10300_local_dcache_flush_inv_page | |
| 193 | + .globl mn10300_local_dcache_flush_inv_range | |
| 194 | + .globl mn10300_local_dcache_flush_inv_range2 | |
| 195 | + .type mn10300_local_dcache_flush_inv_page,@function | |
| 196 | + .type mn10300_local_dcache_flush_inv_range,@function | |
| 197 | + .type mn10300_local_dcache_flush_inv_range2,@function | |
| 198 | +mn10300_local_dcache_flush_inv_page: | |
| 199 | + and ~(PAGE_SIZE-1),d0 | |
| 200 | + mov PAGE_SIZE,d1 | |
| 201 | +mn10300_local_dcache_flush_inv_range2: | |
| 202 | + add d0,d1 | |
| 203 | +mn10300_local_dcache_flush_inv_range: | |
| 204 | + movm [d2],(sp) | |
| 205 | + | |
| 206 | + movhu (CHCTR),d2 | |
| 207 | + btst CHCTR_DCEN,d2 | |
| 208 | + beq mn10300_local_dcache_flush_inv_range_end | |
| 209 | + | |
| 210 | + sub d0,d1,a0 | |
| 211 | + cmp MN10300_DCACHE_FLUSH_INV_BORDER,a0 | |
| 212 | + ble 1f | |
| 213 | + | |
| 214 | + movm (sp),[d2] | |
| 215 | + bra mn10300_local_dcache_flush_inv | |
| 216 | +1: | |
| 217 | + | |
| 218 | + and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start | |
| 219 | + # addr down | |
| 220 | + mov d0,a1 | |
| 221 | + | |
| 222 | + add L1_CACHE_BYTES,d1 # round end addr up | |
| 223 | + and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 | |
| 224 | + | |
| 225 | + # write a request to flush and invalidate all instances of an address | |
| 226 | + # from the cache | |
| 227 | + mov DCACHE_PURGE(0,0),a0 | |
| 228 | + mov a1,d0 | |
| 229 | + and L1_CACHE_TAG_ENTRY,d0 | |
| 230 | + add d0,a0 # starting dcache purge control | |
| 231 | + # reg address | |
| 232 | + | |
| 233 | + sub a1,d1 | |
| 234 | + lsr L1_CACHE_SHIFT,d1 # total number of entries to | |
| 235 | + # examine | |
| 236 | + | |
| 237 | +mn10300_local_dcache_flush_inv_range_loop: | |
| 238 | + mov a1,(L1_CACHE_WAYDISP*0,a0) # conditionally purge this line | |
| 239 | + # in all ways | |
| 240 | + | |
| 241 | + add L1_CACHE_BYTES,a0 | |
| 242 | + add L1_CACHE_BYTES,a1 | |
| 243 | + and ~L1_CACHE_WAYDISP,a0 # make sure way stay on way 0 | |
| 244 | + add -1,d1 | |
| 245 | + bne mn10300_local_dcache_flush_inv_range_loop | |
| 246 | + | |
| 247 | +mn10300_local_dcache_flush_inv_range_end: | |
| 248 | + ret [d2],4 | |
| 249 | + .size mn10300_local_dcache_flush_inv_page,.-mn10300_local_dcache_flush_inv_page | |
| 250 | + .size mn10300_local_dcache_flush_inv_range,.-mn10300_local_dcache_flush_inv_range | |
| 251 | + .size mn10300_local_dcache_flush_inv_range2,.-mn10300_local_dcache_flush_inv_range2 | |
| @@ -0,0 +1,155 @@ | ||
| 1 | +/* Flush dcache and invalidate icache when the dcache is in writeback mode | |
| 2 | + * | |
| 3 | + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#include <linux/module.h> | |
| 12 | +#include <linux/mm.h> | |
| 13 | +#include <asm/cacheflush.h> | |
| 14 | +#include <asm/smp.h> | |
| 15 | +#include "cache-smp.h" | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * flush_icache_page - Flush a page from the dcache and invalidate the icache | |
| 19 | + * @vma: The VMA the page is part of. | |
| 20 | + * @page: The page to be flushed. | |
| 21 | + * | |
| 22 | + * Write a page back from the dcache and invalidate the icache so that we can | |
| 23 | + * run code from it that we've just written into it | |
| 24 | + */ | |
| 25 | +void flush_icache_page(struct vm_area_struct *vma, struct page *page) | |
| 26 | +{ | |
| 27 | + unsigned long start = page_to_phys(page); | |
| 28 | + unsigned long flags; | |
| 29 | + | |
| 30 | + flags = smp_lock_cache(); | |
| 31 | + | |
| 32 | + mn10300_local_dcache_flush_page(start); | |
| 33 | + mn10300_local_icache_inv_page(start); | |
| 34 | + | |
| 35 | + smp_cache_call(SMP_IDCACHE_INV_FLUSH_RANGE, start, start + PAGE_SIZE); | |
| 36 | + smp_unlock_cache(flags); | |
| 37 | +} | |
| 38 | +EXPORT_SYMBOL(flush_icache_page); | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * flush_icache_page_range - Flush dcache and invalidate icache for part of a | |
| 42 | + * single page | |
| 43 | + * @start: The starting virtual address of the page part. | |
| 44 | + * @end: The ending virtual address of the page part. | |
| 45 | + * | |
| 46 | + * Flush the dcache and invalidate the icache for part of a single page, as | |
| 47 | + * determined by the virtual addresses given. The page must be in the paged | |
| 48 | + * area. | |
| 49 | + */ | |
| 50 | +static void flush_icache_page_range(unsigned long start, unsigned long end) | |
| 51 | +{ | |
| 52 | + unsigned long addr, size, off; | |
| 53 | + struct page *page; | |
| 54 | + pgd_t *pgd; | |
| 55 | + pud_t *pud; | |
| 56 | + pmd_t *pmd; | |
| 57 | + pte_t *ppte, pte; | |
| 58 | + | |
| 59 | + /* work out how much of the page to flush */ | |
| 60 | + off = start & ~PAGE_MASK; | |
| 61 | + size = end - start; | |
| 62 | + | |
| 63 | + /* get the physical address the page is mapped to from the page | |
| 64 | + * tables */ | |
| 65 | + pgd = pgd_offset(current->mm, start); | |
| 66 | + if (!pgd || !pgd_val(*pgd)) | |
| 67 | + return; | |
| 68 | + | |
| 69 | + pud = pud_offset(pgd, start); | |
| 70 | + if (!pud || !pud_val(*pud)) | |
| 71 | + return; | |
| 72 | + | |
| 73 | + pmd = pmd_offset(pud, start); | |
| 74 | + if (!pmd || !pmd_val(*pmd)) | |
| 75 | + return; | |
| 76 | + | |
| 77 | + ppte = pte_offset_map(pmd, start); | |
| 78 | + if (!ppte) | |
| 79 | + return; | |
| 80 | + pte = *ppte; | |
| 81 | + pte_unmap(ppte); | |
| 82 | + | |
| 83 | + if (pte_none(pte)) | |
| 84 | + return; | |
| 85 | + | |
| 86 | + page = pte_page(pte); | |
| 87 | + if (!page) | |
| 88 | + return; | |
| 89 | + | |
| 90 | + addr = page_to_phys(page); | |
| 91 | + | |
| 92 | + /* flush the dcache and invalidate the icache coverage on that | |
| 93 | + * region */ | |
| 94 | + mn10300_local_dcache_flush_range2(addr + off, size); | |
| 95 | + mn10300_local_icache_inv_range2(addr + off, size); | |
| 96 | + smp_cache_call(SMP_IDCACHE_INV_FLUSH_RANGE, start, end); | |
| 97 | +} | |
| 98 | + | |
| 99 | +/** | |
| 100 | + * flush_icache_range - Globally flush dcache and invalidate icache for region | |
| 101 | + * @start: The starting virtual address of the region. | |
| 102 | + * @end: The ending virtual address of the region. | |
| 103 | + * | |
| 104 | + * This is used by the kernel to globally flush some code it has just written | |
| 105 | + * from the dcache back to RAM and then to globally invalidate the icache over | |
| 106 | + * that region so that that code can be run on all CPUs in the system. | |
| 107 | + */ | |
| 108 | +void flush_icache_range(unsigned long start, unsigned long end) | |
| 109 | +{ | |
| 110 | + unsigned long start_page, end_page; | |
| 111 | + unsigned long flags; | |
| 112 | + | |
| 113 | + flags = smp_lock_cache(); | |
| 114 | + | |
| 115 | + if (end > 0x80000000UL) { | |
| 116 | + /* addresses above 0xa0000000 do not go through the cache */ | |
| 117 | + if (end > 0xa0000000UL) { | |
| 118 | + end = 0xa0000000UL; | |
| 119 | + if (start >= end) | |
| 120 | + goto done; | |
| 121 | + } | |
| 122 | + | |
| 123 | + /* kernel addresses between 0x80000000 and 0x9fffffff do not | |
| 124 | + * require page tables, so we just map such addresses | |
| 125 | + * directly */ | |
| 126 | + start_page = (start >= 0x80000000UL) ? start : 0x80000000UL; | |
| 127 | + mn10300_local_dcache_flush_range(start_page, end); | |
| 128 | + mn10300_local_icache_inv_range(start_page, end); | |
| 129 | + smp_cache_call(SMP_IDCACHE_INV_FLUSH_RANGE, start_page, end); | |
| 130 | + if (start_page == start) | |
| 131 | + goto done; | |
| 132 | + end = start_page; | |
| 133 | + } | |
| 134 | + | |
| 135 | + start_page = start & PAGE_MASK; | |
| 136 | + end_page = (end - 1) & PAGE_MASK; | |
| 137 | + | |
| 138 | + if (start_page == end_page) { | |
| 139 | + /* the first and last bytes are on the same page */ | |
| 140 | + flush_icache_page_range(start, end); | |
| 141 | + } else if (start_page + 1 == end_page) { | |
| 142 | + /* split over two virtually contiguous pages */ | |
| 143 | + flush_icache_page_range(start, end_page); | |
| 144 | + flush_icache_page_range(end_page, end); | |
| 145 | + } else { | |
| 146 | + /* more than 2 pages; just flush the entire cache */ | |
| 147 | + mn10300_dcache_flush(); | |
| 148 | + mn10300_icache_inv(); | |
| 149 | + smp_cache_call(SMP_IDCACHE_INV_FLUSH, 0, 0); | |
| 150 | + } | |
| 151 | + | |
| 152 | +done: | |
| 153 | + smp_unlock_cache(flags); | |
| 154 | +} | |
| 155 | +EXPORT_SYMBOL(flush_icache_range); | |
| @@ -1,192 +0,0 @@ | ||
| 1 | −/* MN10300 CPU core caching routines | |
| 2 | − * | |
| 3 | − * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 4 | − * Written by David Howells (dhowells@redhat.com) | |
| 5 | − * | |
| 6 | − * This program is free software; you can redistribute it and/or | |
| 7 | − * modify it under the terms of the GNU General Public Licence | |
| 8 | − * as published by the Free Software Foundation; either version | |
| 9 | − * 2 of the Licence, or (at your option) any later version. | |
| 10 | − */ | |
| 11 | − | |
| 12 | −#include <linux/sys.h> | |
| 13 | −#include <linux/linkage.h> | |
| 14 | −#include <asm/smp.h> | |
| 15 | −#include <asm/page.h> | |
| 16 | −#include <asm/cache.h> | |
| 17 | − | |
| 18 | − .am33_2 | |
| 19 | − .globl mn10300_dcache_flush | |
| 20 | − .globl mn10300_dcache_flush_page | |
| 21 | − .globl mn10300_dcache_flush_range | |
| 22 | − .globl mn10300_dcache_flush_range2 | |
| 23 | − .globl mn10300_dcache_flush_inv | |
| 24 | − .globl mn10300_dcache_flush_inv_page | |
| 25 | − .globl mn10300_dcache_flush_inv_range | |
| 26 | − .globl mn10300_dcache_flush_inv_range2 | |
| 27 | − | |
| 28 | −############################################################################### | |
| 29 | −# | |
| 30 | −# void mn10300_dcache_flush(void) | |
| 31 | −# Flush the entire data cache back to RAM | |
| 32 | −# | |
| 33 | −############################################################################### | |
| 34 | − ALIGN | |
| 35 | −mn10300_dcache_flush: | |
| 36 | − movhu (CHCTR),d0 | |
| 37 | − btst CHCTR_DCEN,d0 | |
| 38 | − beq mn10300_dcache_flush_end | |
| 39 | − | |
| 40 | − # read the addresses tagged in the cache's tag RAM and attempt to flush | |
| 41 | − # those addresses specifically | |
| 42 | − # - we rely on the hardware to filter out invalid tag entry addresses | |
| 43 | − mov DCACHE_TAG(0,0),a0 # dcache tag RAM access address | |
| 44 | − mov DCACHE_PURGE(0,0),a1 # dcache purge request address | |
| 45 | − mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of entries | |
| 46 | − | |
| 47 | −mn10300_dcache_flush_loop: | |
| 48 | − mov (a0),d0 | |
| 49 | − and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 | |
| 50 | − or L1_CACHE_TAG_VALID,d0 # retain valid entries in the | |
| 51 | − # cache | |
| 52 | − mov d0,(a1) # conditional purge | |
| 53 | − | |
| 54 | −mn10300_dcache_flush_skip: | |
| 55 | − add L1_CACHE_BYTES,a0 | |
| 56 | − add L1_CACHE_BYTES,a1 | |
| 57 | − add -1,d1 | |
| 58 | − bne mn10300_dcache_flush_loop | |
| 59 | − | |
| 60 | −mn10300_dcache_flush_end: | |
| 61 | − ret [],0 | |
| 62 | − | |
| 63 | −############################################################################### | |
| 64 | −# | |
| 65 | −# void mn10300_dcache_flush_page(unsigned start) | |
| 66 | −# void mn10300_dcache_flush_range(unsigned start, unsigned end) | |
| 67 | −# void mn10300_dcache_flush_range2(unsigned start, unsigned size) | |
| 68 | −# Flush a range of addresses on a page in the dcache | |
| 69 | −# | |
| 70 | −############################################################################### | |
| 71 | − ALIGN | |
| 72 | −mn10300_dcache_flush_page: | |
| 73 | − mov PAGE_SIZE,d1 | |
| 74 | −mn10300_dcache_flush_range2: | |
| 75 | − add d0,d1 | |
| 76 | −mn10300_dcache_flush_range: | |
| 77 | − movm [d2,d3],(sp) | |
| 78 | − | |
| 79 | − movhu (CHCTR),d2 | |
| 80 | − btst CHCTR_DCEN,d2 | |
| 81 | − beq mn10300_dcache_flush_range_end | |
| 82 | − | |
| 83 | − # round start addr down | |
| 84 | − and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 | |
| 85 | − mov d0,a1 | |
| 86 | − | |
| 87 | − add L1_CACHE_BYTES,d1 # round end addr up | |
| 88 | − and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 | |
| 89 | − | |
| 90 | − # write a request to flush all instances of an address from the cache | |
| 91 | − mov DCACHE_PURGE(0,0),a0 | |
| 92 | − mov a1,d0 | |
| 93 | − and L1_CACHE_TAG_ENTRY,d0 | |
| 94 | − add d0,a0 # starting dcache purge control | |
| 95 | − # reg address | |
| 96 | − | |
| 97 | − sub a1,d1 | |
| 98 | − lsr L1_CACHE_SHIFT,d1 # total number of entries to | |
| 99 | − # examine | |
| 100 | − | |
| 101 | − or L1_CACHE_TAG_VALID,a1 # retain valid entries in the | |
| 102 | − # cache | |
| 103 | − | |
| 104 | −mn10300_dcache_flush_range_loop: | |
| 105 | − mov a1,(L1_CACHE_WAYDISP*0,a0) # conditionally purge this line | |
| 106 | − # all ways | |
| 107 | − | |
| 108 | − add L1_CACHE_BYTES,a0 | |
| 109 | − add L1_CACHE_BYTES,a1 | |
| 110 | − and ~L1_CACHE_WAYDISP,a0 # make sure way stay on way 0 | |
| 111 | − add -1,d1 | |
| 112 | − bne mn10300_dcache_flush_range_loop | |
| 113 | − | |
| 114 | −mn10300_dcache_flush_range_end: | |
| 115 | − ret [d2,d3],8 | |
| 116 | − | |
| 117 | −############################################################################### | |
| 118 | −# | |
| 119 | −# void mn10300_dcache_flush_inv(void) | |
| 120 | −# Flush the entire data cache and invalidate all entries | |
| 121 | −# | |
| 122 | −############################################################################### | |
| 123 | − ALIGN | |
| 124 | −mn10300_dcache_flush_inv: | |
| 125 | − movhu (CHCTR),d0 | |
| 126 | − btst CHCTR_DCEN,d0 | |
| 127 | − beq mn10300_dcache_flush_inv_end | |
| 128 | − | |
| 129 | − # hit each line in the dcache with an unconditional purge | |
| 130 | − mov DCACHE_PURGE(0,0),a1 # dcache purge request address | |
| 131 | − mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of entries | |
| 132 | − | |
| 133 | −mn10300_dcache_flush_inv_loop: | |
| 134 | − mov (a1),d0 # unconditional purge | |
| 135 | − | |
| 136 | − add L1_CACHE_BYTES,a1 | |
| 137 | − add -1,d1 | |
| 138 | − bne mn10300_dcache_flush_inv_loop | |
| 139 | − | |
| 140 | −mn10300_dcache_flush_inv_end: | |
| 141 | − ret [],0 | |
| 142 | − | |
| 143 | −############################################################################### | |
| 144 | −# | |
| 145 | −# void mn10300_dcache_flush_inv_page(unsigned start) | |
| 146 | −# void mn10300_dcache_flush_inv_range(unsigned start, unsigned end) | |
| 147 | −# void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size) | |
| 148 | −# Flush and invalidate a range of addresses on a page in the dcache | |
| 149 | −# | |
| 150 | −############################################################################### | |
| 151 | − ALIGN | |
| 152 | −mn10300_dcache_flush_inv_page: | |
| 153 | − mov PAGE_SIZE,d1 | |
| 154 | −mn10300_dcache_flush_inv_range2: | |
| 155 | − add d0,d1 | |
| 156 | −mn10300_dcache_flush_inv_range: | |
| 157 | − movm [d2,d3],(sp) | |
| 158 | − movhu (CHCTR),d2 | |
| 159 | − btst CHCTR_DCEN,d2 | |
| 160 | − beq mn10300_dcache_flush_inv_range_end | |
| 161 | − | |
| 162 | − and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start | |
| 163 | − # addr down | |
| 164 | − mov d0,a1 | |
| 165 | − | |
| 166 | − add L1_CACHE_BYTES,d1 # round end addr up | |
| 167 | − and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 | |
| 168 | − | |
| 169 | − # write a request to flush and invalidate all instances of an address | |
| 170 | − # from the cache | |
| 171 | − mov DCACHE_PURGE(0,0),a0 | |
| 172 | − mov a1,d0 | |
| 173 | − and L1_CACHE_TAG_ENTRY,d0 | |
| 174 | − add d0,a0 # starting dcache purge control | |
| 175 | − # reg address | |
| 176 | − | |
| 177 | − sub a1,d1 | |
| 178 | − lsr L1_CACHE_SHIFT,d1 # total number of entries to | |
| 179 | − # examine | |
| 180 | − | |
| 181 | −mn10300_dcache_flush_inv_range_loop: | |
| 182 | − mov a1,(L1_CACHE_WAYDISP*0,a0) # conditionally purge this line | |
| 183 | − # in all ways | |
| 184 | − | |
| 185 | − add L1_CACHE_BYTES,a0 | |
| 186 | − add L1_CACHE_BYTES,a1 | |
| 187 | − and ~L1_CACHE_WAYDISP,a0 # make sure way stay on way 0 | |
| 188 | − add -1,d1 | |
| 189 | − bne mn10300_dcache_flush_inv_range_loop | |
| 190 | − | |
| 191 | −mn10300_dcache_flush_inv_range_end: | |
| 192 | − ret [d2,d3],8 | |
| @@ -0,0 +1,356 @@ | ||
| 1 | +/* MN10300 CPU cache invalidation routines, using automatic purge registers | |
| 2 | + * | |
| 3 | + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#include <linux/sys.h> | |
| 12 | +#include <linux/linkage.h> | |
| 13 | +#include <asm/smp.h> | |
| 14 | +#include <asm/page.h> | |
| 15 | +#include <asm/cache.h> | |
| 16 | +#include <asm/irqflags.h> | |
| 17 | +#include <asm/cacheflush.h> | |
| 18 | + | |
| 19 | +#define mn10300_local_dcache_inv_range_intr_interval \ | |
| 20 | + +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1) | |
| 21 | + | |
| 22 | +#if mn10300_local_dcache_inv_range_intr_interval > 0xff | |
| 23 | +#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less | |
| 24 | +#endif | |
| 25 | + | |
| 26 | + .am33_2 | |
| 27 | + | |
| 28 | +#ifndef CONFIG_SMP | |
| 29 | + .globl mn10300_icache_inv | |
| 30 | + .globl mn10300_icache_inv_page | |
| 31 | + .globl mn10300_icache_inv_range | |
| 32 | + .globl mn10300_icache_inv_range2 | |
| 33 | + .globl mn10300_dcache_inv | |
| 34 | + .globl mn10300_dcache_inv_page | |
| 35 | + .globl mn10300_dcache_inv_range | |
| 36 | + .globl mn10300_dcache_inv_range2 | |
| 37 | + | |
| 38 | +mn10300_icache_inv = mn10300_local_icache_inv | |
| 39 | +mn10300_icache_inv_page = mn10300_local_icache_inv_page | |
| 40 | +mn10300_icache_inv_range = mn10300_local_icache_inv_range | |
| 41 | +mn10300_icache_inv_range2 = mn10300_local_icache_inv_range2 | |
| 42 | +mn10300_dcache_inv = mn10300_local_dcache_inv | |
| 43 | +mn10300_dcache_inv_page = mn10300_local_dcache_inv_page | |
| 44 | +mn10300_dcache_inv_range = mn10300_local_dcache_inv_range | |
| 45 | +mn10300_dcache_inv_range2 = mn10300_local_dcache_inv_range2 | |
| 46 | + | |
| 47 | +#endif /* !CONFIG_SMP */ | |
| 48 | + | |
| 49 | +############################################################################### | |
| 50 | +# | |
| 51 | +# void mn10300_local_icache_inv(void) | |
| 52 | +# Invalidate the entire icache | |
| 53 | +# | |
| 54 | +############################################################################### | |
| 55 | + ALIGN | |
| 56 | + .globl mn10300_local_icache_inv | |
| 57 | + .type mn10300_local_icache_inv,@function | |
| 58 | +mn10300_local_icache_inv: | |
| 59 | + mov CHCTR,a0 | |
| 60 | + | |
| 61 | + movhu (a0),d0 | |
| 62 | + btst CHCTR_ICEN,d0 | |
| 63 | + beq mn10300_local_icache_inv_end | |
| 64 | + | |
| 65 | + # invalidate | |
| 66 | + or CHCTR_ICINV,d0 | |
| 67 | + movhu d0,(a0) | |
| 68 | + movhu (a0),d0 | |
| 69 | + | |
| 70 | +mn10300_local_icache_inv_end: | |
| 71 | + ret [],0 | |
| 72 | + .size mn10300_local_icache_inv,.-mn10300_local_icache_inv | |
| 73 | + | |
| 74 | +############################################################################### | |
| 75 | +# | |
| 76 | +# void mn10300_local_dcache_inv(void) | |
| 77 | +# Invalidate the entire dcache | |
| 78 | +# | |
| 79 | +############################################################################### | |
| 80 | + ALIGN | |
| 81 | + .globl mn10300_local_dcache_inv | |
| 82 | + .type mn10300_local_dcache_inv,@function | |
| 83 | +mn10300_local_dcache_inv: | |
| 84 | + mov CHCTR,a0 | |
| 85 | + | |
| 86 | + movhu (a0),d0 | |
| 87 | + btst CHCTR_DCEN,d0 | |
| 88 | + beq mn10300_local_dcache_inv_end | |
| 89 | + | |
| 90 | + # invalidate | |
| 91 | + or CHCTR_DCINV,d0 | |
| 92 | + movhu d0,(a0) | |
| 93 | + movhu (a0),d0 | |
| 94 | + | |
| 95 | +mn10300_local_dcache_inv_end: | |
| 96 | + ret [],0 | |
| 97 | + .size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv | |
| 98 | + | |
| 99 | +############################################################################### | |
| 100 | +# | |
| 101 | +# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end) | |
| 102 | +# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size) | |
| 103 | +# void mn10300_local_dcache_inv_page(unsigned long start) | |
| 104 | +# Invalidate a range of addresses on a page in the dcache | |
| 105 | +# | |
| 106 | +############################################################################### | |
| 107 | + ALIGN | |
| 108 | + .globl mn10300_local_dcache_inv_page | |
| 109 | + .globl mn10300_local_dcache_inv_range | |
| 110 | + .globl mn10300_local_dcache_inv_range2 | |
| 111 | + .type mn10300_local_dcache_inv_page,@function | |
| 112 | + .type mn10300_local_dcache_inv_range,@function | |
| 113 | + .type mn10300_local_dcache_inv_range2,@function | |
| 114 | +mn10300_local_dcache_inv_page: | |
| 115 | + and ~(PAGE_SIZE-1),d0 | |
| 116 | + mov PAGE_SIZE,d1 | |
| 117 | +mn10300_local_dcache_inv_range2: | |
| 118 | + add d0,d1 | |
| 119 | +mn10300_local_dcache_inv_range: | |
| 120 | + # If we are in writeback mode we check the start and end alignments, | |
| 121 | + # and if they're not cacheline-aligned, we must flush any bits outside | |
| 122 | + # the range that share cachelines with stuff inside the range | |
| 123 | +#ifdef CONFIG_MN10300_CACHE_WBACK | |
| 124 | + btst ~(L1_CACHE_BYTES-1),d0 | |
| 125 | + bne 1f | |
| 126 | + btst ~(L1_CACHE_BYTES-1),d1 | |
| 127 | + beq 2f | |
| 128 | +1: | |
| 129 | + bra mn10300_local_dcache_flush_inv_range | |
| 130 | +2: | |
| 131 | +#endif /* CONFIG_MN10300_CACHE_WBACK */ | |
| 132 | + | |
| 133 | + movm [d2,d3,a2],(sp) | |
| 134 | + | |
| 135 | + mov CHCTR,a0 | |
| 136 | + movhu (a0),d2 | |
| 137 | + btst CHCTR_DCEN,d2 | |
| 138 | + beq mn10300_local_dcache_inv_range_end | |
| 139 | + | |
| 140 | + # round the addresses out to be full cachelines, unless we're in | |
| 141 | + # writeback mode, in which case we would be in flush and invalidate by | |
| 142 | + # now | |
| 143 | +#ifndef CONFIG_MN10300_CACHE_WBACK | |
| 144 | + and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start | |
| 145 | + # addr down | |
| 146 | + | |
| 147 | + mov L1_CACHE_BYTES-1,d2 | |
| 148 | + add d2,d1 | |
| 149 | + and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 # round end addr up | |
| 150 | +#endif /* !CONFIG_MN10300_CACHE_WBACK */ | |
| 151 | + | |
| 152 | + sub d0,d1,d2 # calculate the total size | |
| 153 | + mov d0,a2 # A2 = start address | |
| 154 | + mov d1,a1 # A1 = end address | |
| 155 | + | |
| 156 | + LOCAL_CLI_SAVE(d3) | |
| 157 | + | |
| 158 | + mov DCPGCR,a0 # make sure the purger isn't busy | |
| 159 | + setlb | |
| 160 | + mov (a0),d0 | |
| 161 | + btst DCPGCR_DCPGBSY,d0 | |
| 162 | + lne | |
| 163 | + | |
| 164 | + # skip initial address alignment calculation if address is zero | |
| 165 | + mov d2,d1 | |
| 166 | + cmp 0,a2 | |
| 167 | + beq 1f | |
| 168 | + | |
| 169 | +dcivloop: | |
| 170 | + /* calculate alignsize | |
| 171 | + * | |
| 172 | + * alignsize = L1_CACHE_BYTES; | |
| 173 | + * while (! start & alignsize) { | |
| 174 | + * alignsize <<=1; | |
| 175 | + * } | |
| 176 | + * d1 = alignsize; | |
| 177 | + */ | |
| 178 | + mov L1_CACHE_BYTES,d1 | |
| 179 | + lsr 1,d1 | |
| 180 | + setlb | |
| 181 | + add d1,d1 | |
| 182 | + mov d1,d0 | |
| 183 | + and a2,d0 | |
| 184 | + leq | |
| 185 | + | |
| 186 | +1: | |
| 187 | + /* calculate invsize | |
| 188 | + * | |
| 189 | + * if (totalsize > alignsize) { | |
| 190 | + * invsize = alignsize; | |
| 191 | + * } else { | |
| 192 | + * invsize = totalsize; | |
| 193 | + * tmp = 0x80000000; | |
| 194 | + * while (! invsize & tmp) { | |
| 195 | + * tmp >>= 1; | |
| 196 | + * } | |
| 197 | + * invsize = tmp; | |
| 198 | + * } | |
| 199 | + * d1 = invsize | |
| 200 | + */ | |
| 201 | + cmp d2,d1 | |
| 202 | + bns 2f | |
| 203 | + mov d2,d1 | |
| 204 | + | |
| 205 | + mov 0x80000000,d0 # start from 31bit=1 | |
| 206 | + setlb | |
| 207 | + lsr 1,d0 | |
| 208 | + mov d0,e0 | |
| 209 | + and d1,e0 | |
| 210 | + leq | |
| 211 | + mov d0,d1 | |
| 212 | + | |
| 213 | +2: | |
| 214 | + /* set mask | |
| 215 | + * | |
| 216 | + * mask = ~(invsize-1); | |
| 217 | + * DCPGMR = mask; | |
| 218 | + */ | |
| 219 | + mov d1,d0 | |
| 220 | + add -1,d0 | |
| 221 | + not d0 | |
| 222 | + mov d0,(DCPGMR) | |
| 223 | + | |
| 224 | + # invalidate area | |
| 225 | + mov a2,d0 | |
| 226 | + or DCPGCR_DCI,d0 | |
| 227 | + mov d0,(a0) # DCPGCR = (mask & start) | DCPGCR_DCI | |
| 228 | + | |
| 229 | + setlb # wait for the purge to complete | |
| 230 | + mov (a0),d0 | |
| 231 | + btst DCPGCR_DCPGBSY,d0 | |
| 232 | + lne | |
| 233 | + | |
| 234 | + sub d1,d2 # decrease size remaining | |
| 235 | + add d1,a2 # increase next start address | |
| 236 | + | |
| 237 | + /* check invalidating of end address | |
| 238 | + * | |
| 239 | + * a2 = a2 + invsize | |
| 240 | + * if (a2 < end) { | |
| 241 | + * goto dcivloop; | |
| 242 | + * } */ | |
| 243 | + cmp a1,a2 | |
| 244 | + bns dcivloop | |
| 245 | + | |
| 246 | + LOCAL_IRQ_RESTORE(d3) | |
| 247 | + | |
| 248 | +mn10300_local_dcache_inv_range_end: | |
| 249 | + ret [d2,d3,a2],12 | |
| 250 | + .size mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page | |
| 251 | + .size mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range | |
| 252 | + .size mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2 | |
| 253 | + | |
| 254 | +############################################################################### | |
| 255 | +# | |
| 256 | +# void mn10300_local_icache_inv_page(unsigned long start) | |
| 257 | +# void mn10300_local_icache_inv_range2(unsigned long start, unsigned long size) | |
| 258 | +# void mn10300_local_icache_inv_range(unsigned long start, unsigned long end) | |
| 259 | +# Invalidate a range of addresses on a page in the icache | |
| 260 | +# | |
| 261 | +############################################################################### | |
| 262 | + ALIGN | |
| 263 | + .globl mn10300_local_icache_inv_page | |
| 264 | + .globl mn10300_local_icache_inv_range | |
| 265 | + .globl mn10300_local_icache_inv_range2 | |
| 266 | + .type mn10300_local_icache_inv_page,@function | |
| 267 | + .type mn10300_local_icache_inv_range,@function | |
| 268 | + .type mn10300_local_icache_inv_range2,@function | |
| 269 | +mn10300_local_icache_inv_page: | |
| 270 | + and ~(PAGE_SIZE-1),d0 | |
| 271 | + mov PAGE_SIZE,d1 | |
| 272 | +mn10300_local_icache_inv_range2: | |
| 273 | + add d0,d1 | |
| 274 | +mn10300_local_icache_inv_range: | |
| 275 | + movm [d2,d3,a2],(sp) | |
| 276 | + | |
| 277 | + mov CHCTR,a0 | |
| 278 | + movhu (a0),d2 | |
| 279 | + btst CHCTR_ICEN,d2 | |
| 280 | + beq mn10300_local_icache_inv_range_reg_end | |
| 281 | + | |
| 282 | + /* calculate alignsize | |
| 283 | + * | |
| 284 | + * alignsize = L1_CACHE_BYTES; | |
| 285 | + * for (i = (end - start - 1) / L1_CACHE_BYTES ; i > 0; i >>= 1) { | |
| 286 | + * alignsize <<= 1; | |
| 287 | + * } | |
| 288 | + * d2 = alignsize; | |
| 289 | + */ | |
| 290 | + mov L1_CACHE_BYTES,d2 | |
| 291 | + sub d0,d1,d3 | |
| 292 | + add -1,d3 | |
| 293 | + lsr L1_CACHE_SHIFT,d3 | |
| 294 | + beq 2f | |
| 295 | +1: | |
| 296 | + add d2,d2 | |
| 297 | + lsr 1,d3 | |
| 298 | + bne 1b | |
| 299 | +2: | |
| 300 | + | |
| 301 | + /* a1 = end */ | |
| 302 | + mov d1,a1 | |
| 303 | + | |
| 304 | + LOCAL_CLI_SAVE(d3) | |
| 305 | + | |
| 306 | + mov ICIVCR,a0 | |
| 307 | + /* wait for busy bit of area invalidation */ | |
| 308 | + setlb | |
| 309 | + mov (a0),d1 | |
| 310 | + btst ICIVCR_ICIVBSY,d1 | |
| 311 | + lne | |
| 312 | + | |
| 313 | + /* set mask | |
| 314 | + * | |
| 315 | + * mask = ~(alignsize-1); | |
| 316 | + * ICIVMR = mask; | |
| 317 | + */ | |
| 318 | + mov d2,d1 | |
| 319 | + add -1,d1 | |
| 320 | + not d1 | |
| 321 | + mov d1,(ICIVMR) | |
| 322 | + /* a2 = mask & start */ | |
| 323 | + and d1,d0,a2 | |
| 324 | + | |
| 325 | +icivloop: | |
| 326 | + /* area invalidate | |
| 327 | + * | |
| 328 | + * ICIVCR = (mask & start) | ICIVCR_ICI | |
| 329 | + */ | |
| 330 | + mov a2,d0 | |
| 331 | + or ICIVCR_ICI,d0 | |
| 332 | + mov d0,(a0) | |
| 333 | + | |
| 334 | + /* wait for busy bit of area invalidation */ | |
| 335 | + setlb | |
| 336 | + mov (a0),d1 | |
| 337 | + btst ICIVCR_ICIVBSY,d1 | |
| 338 | + lne | |
| 339 | + | |
| 340 | + /* check invalidating of end address | |
| 341 | + * | |
| 342 | + * a2 = a2 + alignsize | |
| 343 | + * if (a2 < end) { | |
| 344 | + * goto icivloop; | |
| 345 | + * } */ | |
| 346 | + add d2,a2 | |
| 347 | + cmp a1,a2 | |
| 348 | + bns icivloop | |
| 349 | + | |
| 350 | + LOCAL_IRQ_RESTORE(d3) | |
| 351 | + | |
| 352 | +mn10300_local_icache_inv_range_reg_end: | |
| 353 | + ret [d2,d3,a2],12 | |
| 354 | + .size mn10300_local_icache_inv_page,.-mn10300_local_icache_inv_page | |
| 355 | + .size mn10300_local_icache_inv_range,.-mn10300_local_icache_inv_range | |
| 356 | + .size mn10300_local_icache_inv_range2,.-mn10300_local_icache_inv_range2 | |
| @@ -0,0 +1,348 @@ | ||
| 1 | +/* MN10300 CPU core caching routines | |
| 2 | + * | |
| 3 | + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#include <linux/sys.h> | |
| 12 | +#include <linux/linkage.h> | |
| 13 | +#include <asm/smp.h> | |
| 14 | +#include <asm/page.h> | |
| 15 | +#include <asm/cache.h> | |
| 16 | +#include <asm/irqflags.h> | |
| 17 | +#include <asm/cacheflush.h> | |
| 18 | + | |
| 19 | +#define mn10300_local_dcache_inv_range_intr_interval \ | |
| 20 | + +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1) | |
| 21 | + | |
| 22 | +#if mn10300_local_dcache_inv_range_intr_interval > 0xff | |
| 23 | +#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less | |
| 24 | +#endif | |
| 25 | + | |
| 26 | + .am33_2 | |
| 27 | + | |
| 28 | + .globl mn10300_local_icache_inv_page | |
| 29 | + .globl mn10300_local_icache_inv_range | |
| 30 | + .globl mn10300_local_icache_inv_range2 | |
| 31 | + | |
| 32 | +mn10300_local_icache_inv_page = mn10300_local_icache_inv | |
| 33 | +mn10300_local_icache_inv_range = mn10300_local_icache_inv | |
| 34 | +mn10300_local_icache_inv_range2 = mn10300_local_icache_inv | |
| 35 | + | |
| 36 | +#ifndef CONFIG_SMP | |
| 37 | + .globl mn10300_icache_inv | |
| 38 | + .globl mn10300_icache_inv_page | |
| 39 | + .globl mn10300_icache_inv_range | |
| 40 | + .globl mn10300_icache_inv_range2 | |
| 41 | + .globl mn10300_dcache_inv | |
| 42 | + .globl mn10300_dcache_inv_page | |
| 43 | + .globl mn10300_dcache_inv_range | |
| 44 | + .globl mn10300_dcache_inv_range2 | |
| 45 | + | |
| 46 | +mn10300_icache_inv = mn10300_local_icache_inv | |
| 47 | +mn10300_icache_inv_page = mn10300_local_icache_inv_page | |
| 48 | +mn10300_icache_inv_range = mn10300_local_icache_inv_range | |
| 49 | +mn10300_icache_inv_range2 = mn10300_local_icache_inv_range2 | |
| 50 | +mn10300_dcache_inv = mn10300_local_dcache_inv | |
| 51 | +mn10300_dcache_inv_page = mn10300_local_dcache_inv_page | |
| 52 | +mn10300_dcache_inv_range = mn10300_local_dcache_inv_range | |
| 53 | +mn10300_dcache_inv_range2 = mn10300_local_dcache_inv_range2 | |
| 54 | + | |
| 55 | +#endif /* !CONFIG_SMP */ | |
| 56 | + | |
| 57 | +############################################################################### | |
| 58 | +# | |
| 59 | +# void mn10300_local_icache_inv(void) | |
| 60 | +# Invalidate the entire icache | |
| 61 | +# | |
| 62 | +############################################################################### | |
| 63 | + ALIGN | |
| 64 | + .globl mn10300_local_icache_inv | |
| 65 | + .type mn10300_local_icache_inv,@function | |
| 66 | +mn10300_local_icache_inv: | |
| 67 | + mov CHCTR,a0 | |
| 68 | + | |
| 69 | + movhu (a0),d0 | |
| 70 | + btst CHCTR_ICEN,d0 | |
| 71 | + beq mn10300_local_icache_inv_end | |
| 72 | + | |
| 73 | +#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3) | |
| 74 | + LOCAL_CLI_SAVE(d1) | |
| 75 | + | |
| 76 | + # disable the icache | |
| 77 | + and ~CHCTR_ICEN,d0 | |
| 78 | + movhu d0,(a0) | |
| 79 | + | |
| 80 | + # and wait for it to calm down | |
| 81 | + setlb | |
| 82 | + movhu (a0),d0 | |
| 83 | + btst CHCTR_ICBUSY,d0 | |
| 84 | + lne | |
| 85 | + | |
| 86 | + # invalidate | |
| 87 | + or CHCTR_ICINV,d0 | |
| 88 | + movhu d0,(a0) | |
| 89 | + | |
| 90 | + # wait for the cache to finish | |
| 91 | + mov CHCTR,a0 | |
| 92 | + setlb | |
| 93 | + movhu (a0),d0 | |
| 94 | + btst CHCTR_ICBUSY,d0 | |
| 95 | + lne | |
| 96 | + | |
| 97 | + # and reenable it | |
| 98 | + and ~CHCTR_ICINV,d0 | |
| 99 | + or CHCTR_ICEN,d0 | |
| 100 | + movhu d0,(a0) | |
| 101 | + movhu (a0),d0 | |
| 102 | + | |
| 103 | + LOCAL_IRQ_RESTORE(d1) | |
| 104 | +#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | |
| 105 | + # invalidate | |
| 106 | + or CHCTR_ICINV,d0 | |
| 107 | + movhu d0,(a0) | |
| 108 | + movhu (a0),d0 | |
| 109 | +#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | |
| 110 | + | |
| 111 | +mn10300_local_icache_inv_end: | |
| 112 | + ret [],0 | |
| 113 | + .size mn10300_local_icache_inv,.-mn10300_local_icache_inv | |
| 114 | + | |
| 115 | +############################################################################### | |
| 116 | +# | |
| 117 | +# void mn10300_local_dcache_inv(void) | |
| 118 | +# Invalidate the entire dcache | |
| 119 | +# | |
| 120 | +############################################################################### | |
| 121 | + ALIGN | |
| 122 | + .globl mn10300_local_dcache_inv | |
| 123 | + .type mn10300_local_dcache_inv,@function | |
| 124 | +mn10300_local_dcache_inv: | |
| 125 | + mov CHCTR,a0 | |
| 126 | + | |
| 127 | + movhu (a0),d0 | |
| 128 | + btst CHCTR_DCEN,d0 | |
| 129 | + beq mn10300_local_dcache_inv_end | |
| 130 | + | |
| 131 | +#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3) | |
| 132 | + LOCAL_CLI_SAVE(d1) | |
| 133 | + | |
| 134 | + # disable the dcache | |
| 135 | + and ~CHCTR_DCEN,d0 | |
| 136 | + movhu d0,(a0) | |
| 137 | + | |
| 138 | + # and wait for it to calm down | |
| 139 | + setlb | |
| 140 | + movhu (a0),d0 | |
| 141 | + btst CHCTR_DCBUSY,d0 | |
| 142 | + lne | |
| 143 | + | |
| 144 | + # invalidate | |
| 145 | + or CHCTR_DCINV,d0 | |
| 146 | + movhu d0,(a0) | |
| 147 | + | |
| 148 | + # wait for the cache to finish | |
| 149 | + mov CHCTR,a0 | |
| 150 | + setlb | |
| 151 | + movhu (a0),d0 | |
| 152 | + btst CHCTR_DCBUSY,d0 | |
| 153 | + lne | |
| 154 | + | |
| 155 | + # and reenable it | |
| 156 | + and ~CHCTR_DCINV,d0 | |
| 157 | + or CHCTR_DCEN,d0 | |
| 158 | + movhu d0,(a0) | |
| 159 | + movhu (a0),d0 | |
| 160 | + | |
| 161 | + LOCAL_IRQ_RESTORE(d1) | |
| 162 | +#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | |
| 163 | + # invalidate | |
| 164 | + or CHCTR_DCINV,d0 | |
| 165 | + movhu d0,(a0) | |
| 166 | + movhu (a0),d0 | |
| 167 | +#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */ | |
| 168 | + | |
| 169 | +mn10300_local_dcache_inv_end: | |
| 170 | + ret [],0 | |
| 171 | + .size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv | |
| 172 | + | |
| 173 | +############################################################################### | |
| 174 | +# | |
| 175 | +# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end) | |
| 176 | +# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size) | |
| 177 | +# void mn10300_local_dcache_inv_page(unsigned long start) | |
| 178 | +# Invalidate a range of addresses on a page in the dcache | |
| 179 | +# | |
| 180 | +############################################################################### | |
| 181 | + ALIGN | |
| 182 | + .globl mn10300_local_dcache_inv_page | |
| 183 | + .globl mn10300_local_dcache_inv_range | |
| 184 | + .globl mn10300_local_dcache_inv_range2 | |
| 185 | + .type mn10300_local_dcache_inv_page,@function | |
| 186 | + .type mn10300_local_dcache_inv_range,@function | |
| 187 | + .type mn10300_local_dcache_inv_range2,@function | |
| 188 | +mn10300_local_dcache_inv_page: | |
| 189 | + and ~(PAGE_SIZE-1),d0 | |
| 190 | + mov PAGE_SIZE,d1 | |
| 191 | +mn10300_local_dcache_inv_range2: | |
| 192 | + add d0,d1 | |
| 193 | +mn10300_local_dcache_inv_range: | |
| 194 | + # If we are in writeback mode we check the start and end alignments, | |
| 195 | + # and if they're not cacheline-aligned, we must flush any bits outside | |
| 196 | + # the range that share cachelines with stuff inside the range | |
| 197 | +#ifdef CONFIG_MN10300_CACHE_WBACK | |
| 198 | + btst ~(L1_CACHE_BYTES-1),d0 | |
| 199 | + bne 1f | |
| 200 | + btst ~(L1_CACHE_BYTES-1),d1 | |
| 201 | + beq 2f | |
| 202 | +1: | |
| 203 | + bra mn10300_local_dcache_flush_inv_range | |
| 204 | +2: | |
| 205 | +#endif /* CONFIG_MN10300_CACHE_WBACK */ | |
| 206 | + | |
| 207 | + movm [d2,d3,a2],(sp) | |
| 208 | + | |
| 209 | + mov CHCTR,a2 | |
| 210 | + movhu (a2),d2 | |
| 211 | + btst CHCTR_DCEN,d2 | |
| 212 | + beq mn10300_local_dcache_inv_range_end | |
| 213 | + | |
| 214 | +#ifndef CONFIG_MN10300_CACHE_WBACK | |
| 215 | + and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start | |
| 216 | + # addr down | |
| 217 | + | |
| 218 | + add L1_CACHE_BYTES,d1 # round end addr up | |
| 219 | + and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 | |
| 220 | +#endif /* !CONFIG_MN10300_CACHE_WBACK */ | |
| 221 | + mov d0,a1 | |
| 222 | + | |
| 223 | + clr d2 # we're going to clear tag RAM | |
| 224 | + # entries | |
| 225 | + | |
| 226 | + # read the tags from the tag RAM, and if they indicate a valid dirty | |
| 227 | + # cache line then invalidate that line | |
| 228 | + mov DCACHE_TAG(0,0),a0 | |
| 229 | + mov a1,d0 | |
| 230 | + and L1_CACHE_TAG_ENTRY,d0 | |
| 231 | + add d0,a0 # starting dcache tag RAM | |
| 232 | + # access address | |
| 233 | + | |
| 234 | + sub a1,d1 | |
| 235 | + lsr L1_CACHE_SHIFT,d1 # total number of entries to | |
| 236 | + # examine | |
| 237 | + | |
| 238 | + and ~(L1_CACHE_DISPARITY-1),a1 # determine comparator base | |
| 239 | + | |
| 240 | +mn10300_local_dcache_inv_range_outer_loop: | |
| 241 | + LOCAL_CLI_SAVE(d3) | |
| 242 | + | |
| 243 | + # disable the dcache | |
| 244 | + movhu (a2),d0 | |
| 245 | + and ~CHCTR_DCEN,d0 | |
| 246 | + movhu d0,(a2) | |
| 247 | + | |
| 248 | + # and wait for it to calm down | |
| 249 | + setlb | |
| 250 | + movhu (a2),d0 | |
| 251 | + btst CHCTR_DCBUSY,d0 | |
| 252 | + lne | |
| 253 | + | |
| 254 | +mn10300_local_dcache_inv_range_loop: | |
| 255 | + | |
| 256 | + # process the way 0 slot | |
| 257 | + mov (L1_CACHE_WAYDISP*0,a0),d0 # read the tag in the way 0 slot | |
| 258 | + btst L1_CACHE_TAG_VALID,d0 | |
| 259 | + beq mn10300_local_dcache_inv_range_skip_0 # jump if this cacheline | |
| 260 | + # is not valid | |
| 261 | + | |
| 262 | + xor a1,d0 | |
| 263 | + lsr 12,d0 | |
| 264 | + bne mn10300_local_dcache_inv_range_skip_0 # jump if not this cacheline | |
| 265 | + | |
| 266 | + mov d2,(L1_CACHE_WAYDISP*0,a0) # kill the tag | |
| 267 | + | |
| 268 | +mn10300_local_dcache_inv_range_skip_0: | |
| 269 | + | |
| 270 | + # process the way 1 slot | |
| 271 | + mov (L1_CACHE_WAYDISP*1,a0),d0 # read the tag in the way 1 slot | |
| 272 | + btst L1_CACHE_TAG_VALID,d0 | |
| 273 | + beq mn10300_local_dcache_inv_range_skip_1 # jump if this cacheline | |
| 274 | + # is not valid | |
| 275 | + | |
| 276 | + xor a1,d0 | |
| 277 | + lsr 12,d0 | |
| 278 | + bne mn10300_local_dcache_inv_range_skip_1 # jump if not this cacheline | |
| 279 | + | |
| 280 | + mov d2,(L1_CACHE_WAYDISP*1,a0) # kill the tag | |
| 281 | + | |
| 282 | +mn10300_local_dcache_inv_range_skip_1: | |
| 283 | + | |
| 284 | + # process the way 2 slot | |
| 285 | + mov (L1_CACHE_WAYDISP*2,a0),d0 # read the tag in the way 2 slot | |
| 286 | + btst L1_CACHE_TAG_VALID,d0 | |
| 287 | + beq mn10300_local_dcache_inv_range_skip_2 # jump if this cacheline | |
| 288 | + # is not valid | |
| 289 | + | |
| 290 | + xor a1,d0 | |
| 291 | + lsr 12,d0 | |
| 292 | + bne mn10300_local_dcache_inv_range_skip_2 # jump if not this cacheline | |
| 293 | + | |
| 294 | + mov d2,(L1_CACHE_WAYDISP*2,a0) # kill the tag | |
| 295 | + | |
| 296 | +mn10300_local_dcache_inv_range_skip_2: | |
| 297 | + | |
| 298 | + # process the way 3 slot | |
| 299 | + mov (L1_CACHE_WAYDISP*3,a0),d0 # read the tag in the way 3 slot | |
| 300 | + btst L1_CACHE_TAG_VALID,d0 | |
| 301 | + beq mn10300_local_dcache_inv_range_skip_3 # jump if this cacheline | |
| 302 | + # is not valid | |
| 303 | + | |
| 304 | + xor a1,d0 | |
| 305 | + lsr 12,d0 | |
| 306 | + bne mn10300_local_dcache_inv_range_skip_3 # jump if not this cacheline | |
| 307 | + | |
| 308 | + mov d2,(L1_CACHE_WAYDISP*3,a0) # kill the tag | |
| 309 | + | |
| 310 | +mn10300_local_dcache_inv_range_skip_3: | |
| 311 | + | |
| 312 | + # approx every N steps we re-enable the cache and see if there are any | |
| 313 | + # interrupts to be processed | |
| 314 | + # we also break out if we've reached the end of the loop | |
| 315 | + # (the bottom nibble of the count is zero in both cases) | |
| 316 | + add L1_CACHE_BYTES,a0 | |
| 317 | + add L1_CACHE_BYTES,a1 | |
| 318 | + and ~L1_CACHE_WAYDISP,a0 | |
| 319 | + add -1,d1 | |
| 320 | + btst mn10300_local_dcache_inv_range_intr_interval,d1 | |
| 321 | + bne mn10300_local_dcache_inv_range_loop | |
| 322 | + | |
| 323 | + # wait for the cache to finish what it's doing | |
| 324 | + setlb | |
| 325 | + movhu (a2),d0 | |
| 326 | + btst CHCTR_DCBUSY,d0 | |
| 327 | + lne | |
| 328 | + | |
| 329 | + # and reenable it | |
| 330 | + or CHCTR_DCEN,d0 | |
| 331 | + movhu d0,(a2) | |
| 332 | + movhu (a2),d0 | |
| 333 | + | |
| 334 | + # re-enable interrupts | |
| 335 | + # - we don't bother with delay NOPs as we'll have enough instructions | |
| 336 | + # before we disable interrupts again to give the interrupts a chance | |
| 337 | + # to happen | |
| 338 | + LOCAL_IRQ_RESTORE(d3) | |
| 339 | + | |
| 340 | + # go around again if the counter hasn't yet reached zero | |
| 341 | + add 0,d1 | |
| 342 | + bne mn10300_local_dcache_inv_range_outer_loop | |
| 343 | + | |
| 344 | +mn10300_local_dcache_inv_range_end: | |
| 345 | + ret [d2,d3,a2],12 | |
| 346 | + .size mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page | |
| 347 | + .size mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range | |
| 348 | + .size mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2 | |
| @@ -0,0 +1,129 @@ | ||
| 1 | +/* Invalidate icache when dcache doesn't need invalidation as it's in | |
| 2 | + * write-through mode | |
| 3 | + * | |
| 4 | + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | |
| 5 | + * Written by David Howells (dhowells@redhat.com) | |
| 6 | + * | |
| 7 | + * This program is free software; you can redistribute it and/or | |
| 8 | + * modify it under the terms of the GNU General Public Licence | |
| 9 | + * as published by the Free Software Foundation; either version | |
| 10 | + * 2 of the Licence, or (at your option) any later version. | |
| 11 | + */ | |
| 12 | +#include <linux/module.h> | |
| 13 | +#include <linux/mm.h> | |
| 14 | +#include <asm/cacheflush.h> | |
| 15 | +#include <asm/smp.h> | |
| 16 | +#include "cache-smp.h" | |
| 17 | + | |
| 18 | +/** | |
| 19 | + * flush_icache_page_range - Flush dcache and invalidate icache for part of a | |
| 20 | + * single page | |
| 21 | + * @start: The starting virtual address of the page part. | |
| 22 | + * @end: The ending virtual address of the page part. | |
| 23 | + * | |
| 24 | + * Invalidate the icache for part of a single page, as determined by the | |
| 25 | + * virtual addresses given. The page must be in the paged area. The dcache is | |
| 26 | + * not flushed as the cache must be in write-through mode to get here. | |
| 27 | + */ | |
| 28 | +static void flush_icache_page_range(unsigned long start, unsigned long end) | |
| 29 | +{ | |
| 30 | + unsigned long addr, size, off; | |
| 31 | + struct page *page; | |
| 32 | + pgd_t *pgd; | |
| 33 | + pud_t *pud; | |
| 34 | + pmd_t *pmd; | |
| 35 | + pte_t *ppte, pte; | |
| 36 | + | |
| 37 | + /* work out how much of the page to flush */ | |
| 38 | + off = start & ~PAGE_MASK; | |
| 39 | + size = end - start; | |
| 40 | + | |
| 41 | + /* get the physical address the page is mapped to from the page | |
| 42 | + * tables */ | |
| 43 | + pgd = pgd_offset(current->mm, start); | |
| 44 | + if (!pgd || !pgd_val(*pgd)) | |
| 45 | + return; | |
| 46 | + | |
| 47 | + pud = pud_offset(pgd, start); | |
| 48 | + if (!pud || !pud_val(*pud)) | |
| 49 | + return; | |
| 50 | + | |
| 51 | + pmd = pmd_offset(pud, start); | |
| 52 | + if (!pmd || !pmd_val(*pmd)) | |
| 53 | + return; | |
| 54 | + | |
| 55 | + ppte = pte_offset_map(pmd, start); | |
| 56 | + if (!ppte) | |
| 57 | + return; | |
| 58 | + pte = *ppte; | |
| 59 | + pte_unmap(ppte); | |
| 60 | + | |
| 61 | + if (pte_none(pte)) | |
| 62 | + return; | |
| 63 | + | |
| 64 | + page = pte_page(pte); | |
| 65 | + if (!page) | |
| 66 | + return; | |
| 67 | + | |
| 68 | + addr = page_to_phys(page); | |
| 69 | + | |
| 70 | + /* invalidate the icache coverage on that region */ | |
| 71 | + mn10300_local_icache_inv_range2(addr + off, size); | |
| 72 | + smp_cache_call(SMP_ICACHE_INV_FLUSH_RANGE, start, end); | |
| 73 | +} | |
| 74 | + | |
| 75 | +/** | |
| 76 | + * flush_icache_range - Globally flush dcache and invalidate icache for region | |
| 77 | + * @start: The starting virtual address of the region. | |
| 78 | + * @end: The ending virtual address of the region. | |
| 79 | + * | |
| 80 | + * This is used by the kernel to globally flush some code it has just written | |
| 81 | + * from the dcache back to RAM and then to globally invalidate the icache over | |
| 82 | + * that region so that that code can be run on all CPUs in the system. | |
| 83 | + */ | |
| 84 | +void flush_icache_range(unsigned long start, unsigned long end) | |
| 85 | +{ | |
| 86 | + unsigned long start_page, end_page; | |
| 87 | + unsigned long flags; | |
| 88 | + | |
| 89 | + flags = smp_lock_cache(); | |
| 90 | + | |
| 91 | + if (end > 0x80000000UL) { | |
| 92 | + /* addresses above 0xa0000000 do not go through the cache */ | |
| 93 | + if (end > 0xa0000000UL) { | |
| 94 | + end = 0xa0000000UL; | |
| 95 | + if (start >= end) | |
| 96 | + goto done; | |
| 97 | + } | |
| 98 | + | |
| 99 | + /* kernel addresses between 0x80000000 and 0x9fffffff do not | |
| 100 | + * require page tables, so we just map such addresses | |
| 101 | + * directly */ | |
| 102 | + start_page = (start >= 0x80000000UL) ? start : 0x80000000UL; | |
| 103 | + mn10300_icache_inv_range(start_page, end); | |
| 104 | + smp_cache_call(SMP_ICACHE_INV_FLUSH_RANGE, start, end); | |
| 105 | + if (start_page == start) | |
| 106 | + goto done; | |
| 107 | + end = start_page; | |
| 108 | + } | |
| 109 | + | |
| 110 | + start_page = start & PAGE_MASK; | |
| 111 | + end_page = (end - 1) & PAGE_MASK; | |
| 112 | + | |
| 113 | + if (start_page == end_page) { | |
| 114 | + /* the first and last bytes are on the same page */ | |
| 115 | + flush_icache_page_range(start, end); | |
| 116 | + } else if (start_page + 1 == end_page) { | |
| 117 | + /* split over two virtually contiguous pages */ | |
| 118 | + flush_icache_page_range(start, end_page); | |
| 119 | + flush_icache_page_range(end_page, end); | |
| 120 | + } else { | |
| 121 | + /* more than 2 pages; just flush the entire cache */ | |
| 122 | + mn10300_local_icache_inv(); | |
| 123 | + smp_cache_call(SMP_ICACHE_INV, 0, 0); | |
| 124 | + } | |
| 125 | + | |
| 126 | +done: | |
| 127 | + smp_unlock_cache(flags); | |
| 128 | +} | |
| 129 | +EXPORT_SYMBOL(flush_icache_range); | |
| @@ -1,289 +0,0 @@ | ||
| 1 | −/* MN10300 CPU core caching routines | |
| 2 | − * | |
| 3 | − * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 4 | − * Written by David Howells (dhowells@redhat.com) | |
| 5 | − * | |
| 6 | − * This program is free software; you can redistribute it and/or | |
| 7 | − * modify it under the terms of the GNU General Public Licence | |
| 8 | − * as published by the Free Software Foundation; either version | |
| 9 | − * 2 of the Licence, or (at your option) any later version. | |
| 10 | − */ | |
| 11 | −#include <linux/sys.h> | |
| 12 | −#include <linux/linkage.h> | |
| 13 | −#include <asm/smp.h> | |
| 14 | −#include <asm/page.h> | |
| 15 | −#include <asm/cache.h> | |
| 16 | − | |
| 17 | −#define mn10300_dcache_inv_range_intr_interval \ | |
| 18 | − +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1) | |
| 19 | − | |
| 20 | −#if mn10300_dcache_inv_range_intr_interval > 0xff | |
| 21 | −#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less | |
| 22 | −#endif | |
| 23 | − | |
| 24 | − .am33_2 | |
| 25 | − | |
| 26 | − .globl mn10300_icache_inv | |
| 27 | − .globl mn10300_dcache_inv | |
| 28 | − .globl mn10300_dcache_inv_range | |
| 29 | − .globl mn10300_dcache_inv_range2 | |
| 30 | − .globl mn10300_dcache_inv_page | |
| 31 | − | |
| 32 | −############################################################################### | |
| 33 | −# | |
| 34 | −# void mn10300_icache_inv(void) | |
| 35 | −# Invalidate the entire icache | |
| 36 | −# | |
| 37 | −############################################################################### | |
| 38 | − ALIGN | |
| 39 | −mn10300_icache_inv: | |
| 40 | − mov CHCTR,a0 | |
| 41 | − | |
| 42 | − movhu (a0),d0 | |
| 43 | − btst CHCTR_ICEN,d0 | |
| 44 | − beq mn10300_icache_inv_end | |
| 45 | − | |
| 46 | − mov epsw,d1 | |
| 47 | − and ~EPSW_IE,epsw | |
| 48 | − nop | |
| 49 | − nop | |
| 50 | − | |
| 51 | − # disable the icache | |
| 52 | − and ~CHCTR_ICEN,d0 | |
| 53 | − movhu d0,(a0) | |
| 54 | − | |
| 55 | − # and wait for it to calm down | |
| 56 | − setlb | |
| 57 | − movhu (a0),d0 | |
| 58 | − btst CHCTR_ICBUSY,d0 | |
| 59 | − lne | |
| 60 | − | |
| 61 | − # invalidate | |
| 62 | − or CHCTR_ICINV,d0 | |
| 63 | − movhu d0,(a0) | |
| 64 | − | |
| 65 | − # wait for the cache to finish | |
| 66 | − mov CHCTR,a0 | |
| 67 | − setlb | |
| 68 | − movhu (a0),d0 | |
| 69 | − btst CHCTR_ICBUSY,d0 | |
| 70 | − lne | |
| 71 | − | |
| 72 | − # and reenable it | |
| 73 | − and ~CHCTR_ICINV,d0 | |
| 74 | − or CHCTR_ICEN,d0 | |
| 75 | − movhu d0,(a0) | |
| 76 | − movhu (a0),d0 | |
| 77 | − | |
| 78 | − mov d1,epsw | |
| 79 | − | |
| 80 | −mn10300_icache_inv_end: | |
| 81 | − ret [],0 | |
| 82 | − | |
| 83 | −############################################################################### | |
| 84 | −# | |
| 85 | −# void mn10300_dcache_inv(void) | |
| 86 | −# Invalidate the entire dcache | |
| 87 | −# | |
| 88 | −############################################################################### | |
| 89 | − ALIGN | |
| 90 | −mn10300_dcache_inv: | |
| 91 | − mov CHCTR,a0 | |
| 92 | − | |
| 93 | − movhu (a0),d0 | |
| 94 | − btst CHCTR_DCEN,d0 | |
| 95 | − beq mn10300_dcache_inv_end | |
| 96 | − | |
| 97 | − mov epsw,d1 | |
| 98 | − and ~EPSW_IE,epsw | |
| 99 | − nop | |
| 100 | − nop | |
| 101 | − | |
| 102 | − # disable the dcache | |
| 103 | − and ~CHCTR_DCEN,d0 | |
| 104 | − movhu d0,(a0) | |
| 105 | − | |
| 106 | − # and wait for it to calm down | |
| 107 | − setlb | |
| 108 | − movhu (a0),d0 | |
| 109 | − btst CHCTR_DCBUSY,d0 | |
| 110 | − lne | |
| 111 | − | |
| 112 | − # invalidate | |
| 113 | − or CHCTR_DCINV,d0 | |
| 114 | − movhu d0,(a0) | |
| 115 | − | |
| 116 | − # wait for the cache to finish | |
| 117 | − mov CHCTR,a0 | |
| 118 | − setlb | |
| 119 | − movhu (a0),d0 | |
| 120 | − btst CHCTR_DCBUSY,d0 | |
| 121 | − lne | |
| 122 | − | |
| 123 | − # and reenable it | |
| 124 | − and ~CHCTR_DCINV,d0 | |
| 125 | − or CHCTR_DCEN,d0 | |
| 126 | − movhu d0,(a0) | |
| 127 | − movhu (a0),d0 | |
| 128 | − | |
| 129 | − mov d1,epsw | |
| 130 | − | |
| 131 | −mn10300_dcache_inv_end: | |
| 132 | − ret [],0 | |
| 133 | − | |
| 134 | −############################################################################### | |
| 135 | −# | |
| 136 | −# void mn10300_dcache_inv_range(unsigned start, unsigned end) | |
| 137 | −# void mn10300_dcache_inv_range2(unsigned start, unsigned size) | |
| 138 | −# void mn10300_dcache_inv_page(unsigned start) | |
| 139 | −# Invalidate a range of addresses on a page in the dcache | |
| 140 | −# | |
| 141 | −############################################################################### | |
| 142 | − ALIGN | |
| 143 | −mn10300_dcache_inv_page: | |
| 144 | − mov PAGE_SIZE,d1 | |
| 145 | −mn10300_dcache_inv_range2: | |
| 146 | − add d0,d1 | |
| 147 | −mn10300_dcache_inv_range: | |
| 148 | − movm [d2,d3,a2],(sp) | |
| 149 | − mov CHCTR,a2 | |
| 150 | − | |
| 151 | − movhu (a2),d2 | |
| 152 | − btst CHCTR_DCEN,d2 | |
| 153 | − beq mn10300_dcache_inv_range_end | |
| 154 | − | |
| 155 | − and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start | |
| 156 | − # addr down | |
| 157 | − mov d0,a1 | |
| 158 | − | |
| 159 | − add L1_CACHE_BYTES,d1 # round end addr up | |
| 160 | − and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1 | |
| 161 | − | |
| 162 | − clr d2 # we're going to clear tag ram | |
| 163 | − # entries | |
| 164 | − | |
| 165 | − # read the tags from the tag RAM, and if they indicate a valid dirty | |
| 166 | − # cache line then invalidate that line | |
| 167 | − mov DCACHE_TAG(0,0),a0 | |
| 168 | − mov a1,d0 | |
| 169 | − and L1_CACHE_TAG_ENTRY,d0 | |
| 170 | − add d0,a0 # starting dcache tag RAM | |
| 171 | − # access address | |
| 172 | − | |
| 173 | − sub a1,d1 | |
| 174 | − lsr L1_CACHE_SHIFT,d1 # total number of entries to | |
| 175 | − # examine | |
| 176 | − | |
| 177 | − and ~(L1_CACHE_DISPARITY-1),a1 # determine comparator base | |
| 178 | − | |
| 179 | −mn10300_dcache_inv_range_outer_loop: | |
| 180 | − # disable interrupts | |
| 181 | − mov epsw,d3 | |
| 182 | − and ~EPSW_IE,epsw | |
| 183 | − nop # note that reading CHCTR and | |
| 184 | − # AND'ing D0 occupy two delay | |
| 185 | − # slots after disabling | |
| 186 | − # interrupts | |
| 187 | − | |
| 188 | − # disable the dcache | |
| 189 | − movhu (a2),d0 | |
| 190 | − and ~CHCTR_DCEN,d0 | |
| 191 | − movhu d0,(a2) | |
| 192 | − | |
| 193 | − # and wait for it to calm down | |
| 194 | − setlb | |
| 195 | − movhu (a2),d0 | |
| 196 | − btst CHCTR_DCBUSY,d0 | |
| 197 | − lne | |
| 198 | − | |
| 199 | −mn10300_dcache_inv_range_loop: | |
| 200 | − | |
| 201 | − # process the way 0 slot | |
| 202 | − mov (L1_CACHE_WAYDISP*0,a0),d0 # read the tag in the way 0 slot | |
| 203 | − btst L1_CACHE_TAG_VALID,d0 | |
| 204 | − beq mn10300_dcache_inv_range_skip_0 # jump if this cacheline is not | |
| 205 | − # valid | |
| 206 | − | |
| 207 | − xor a1,d0 | |
| 208 | − lsr 12,d0 | |
| 209 | − bne mn10300_dcache_inv_range_skip_0 # jump if not this cacheline | |
| 210 | − | |
| 211 | − mov d2,(a0) # kill the tag | |
| 212 | − | |
| 213 | −mn10300_dcache_inv_range_skip_0: | |
| 214 | − | |
| 215 | − # process the way 1 slot | |
| 216 | − mov (L1_CACHE_WAYDISP*1,a0),d0 # read the tag in the way 1 slot | |
| 217 | − btst L1_CACHE_TAG_VALID,d0 | |
| 218 | − beq mn10300_dcache_inv_range_skip_1 # jump if this cacheline is not | |
| 219 | − # valid | |
| 220 | − | |
| 221 | − xor a1,d0 | |
| 222 | − lsr 12,d0 | |
| 223 | − bne mn10300_dcache_inv_range_skip_1 # jump if not this cacheline | |
| 224 | − | |
| 225 | − mov d2,(a0) # kill the tag | |
| 226 | − | |
| 227 | −mn10300_dcache_inv_range_skip_1: | |
| 228 | − | |
| 229 | − # process the way 2 slot | |
| 230 | − mov (L1_CACHE_WAYDISP*2,a0),d0 # read the tag in the way 2 slot | |
| 231 | − btst L1_CACHE_TAG_VALID,d0 | |
| 232 | − beq mn10300_dcache_inv_range_skip_2 # jump if this cacheline is not | |
| 233 | − # valid | |
| 234 | − | |
| 235 | − xor a1,d0 | |
| 236 | − lsr 12,d0 | |
| 237 | − bne mn10300_dcache_inv_range_skip_2 # jump if not this cacheline | |
| 238 | − | |
| 239 | − mov d2,(a0) # kill the tag | |
| 240 | − | |
| 241 | −mn10300_dcache_inv_range_skip_2: | |
| 242 | − | |
| 243 | − # process the way 3 slot | |
| 244 | − mov (L1_CACHE_WAYDISP*3,a0),d0 # read the tag in the way 3 slot | |
| 245 | − btst L1_CACHE_TAG_VALID,d0 | |
| 246 | − beq mn10300_dcache_inv_range_skip_3 # jump if this cacheline is not | |
| 247 | − # valid | |
| 248 | − | |
| 249 | − xor a1,d0 | |
| 250 | − lsr 12,d0 | |
| 251 | − bne mn10300_dcache_inv_range_skip_3 # jump if not this cacheline | |
| 252 | − | |
| 253 | − mov d2,(a0) # kill the tag | |
| 254 | − | |
| 255 | −mn10300_dcache_inv_range_skip_3: | |
| 256 | − | |
| 257 | − # approx every N steps we re-enable the cache and see if there are any | |
| 258 | − # interrupts to be processed | |
| 259 | − # we also break out if we've reached the end of the loop | |
| 260 | − # (the bottom nibble of the count is zero in both cases) | |
| 261 | − add L1_CACHE_BYTES,a0 | |
| 262 | − add L1_CACHE_BYTES,a1 | |
| 263 | − add -1,d1 | |
| 264 | − btst mn10300_dcache_inv_range_intr_interval,d1 | |
| 265 | − bne mn10300_dcache_inv_range_loop | |
| 266 | − | |
| 267 | − # wait for the cache to finish what it's doing | |
| 268 | − setlb | |
| 269 | − movhu (a2),d0 | |
| 270 | − btst CHCTR_DCBUSY,d0 | |
| 271 | − lne | |
| 272 | − | |
| 273 | − # and reenable it | |
| 274 | − or CHCTR_DCEN,d0 | |
| 275 | − movhu d0,(a2) | |
| 276 | − movhu (a2),d0 | |
| 277 | − | |
| 278 | − # re-enable interrupts | |
| 279 | − # - we don't bother with delay NOPs as we'll have enough instructions | |
| 280 | − # before we disable interrupts again to give the interrupts a chance | |
| 281 | − # to happen | |
| 282 | − mov d3,epsw | |
| 283 | − | |
| 284 | − # go around again if the counter hasn't yet reached zero | |
| 285 | − add 0,d1 | |
| 286 | − bne mn10300_dcache_inv_range_outer_loop | |
| 287 | − | |
| 288 | −mn10300_dcache_inv_range_end: | |
| 289 | − ret [d2,d3,a2],12 | |
| @@ -0,0 +1,156 @@ | ||
| 1 | +/* Functions for global dcache flush when writeback caching in SMP | |
| 2 | + * | |
| 3 | + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#include <linux/mm.h> | |
| 12 | +#include <asm/cacheflush.h> | |
| 13 | +#include "cache-smp.h" | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * mn10300_dcache_flush - Globally flush data cache | |
| 17 | + * | |
| 18 | + * Flush the data cache on all CPUs. | |
| 19 | + */ | |
| 20 | +void mn10300_dcache_flush(void) | |
| 21 | +{ | |
| 22 | + unsigned long flags; | |
| 23 | + | |
| 24 | + flags = smp_lock_cache(); | |
| 25 | + mn10300_local_dcache_flush(); | |
| 26 | + smp_cache_call(SMP_DCACHE_FLUSH, 0, 0); | |
| 27 | + smp_unlock_cache(flags); | |
| 28 | +} | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * mn10300_dcache_flush_page - Globally flush a page of data cache | |
| 32 | + * @start: The address of the page of memory to be flushed. | |
| 33 | + * | |
| 34 | + * Flush a range of addresses in the data cache on all CPUs covering | |
| 35 | + * the page that includes the given address. | |
| 36 | + */ | |
| 37 | +void mn10300_dcache_flush_page(unsigned long start) | |
| 38 | +{ | |
| 39 | + unsigned long flags; | |
| 40 | + | |
| 41 | + start &= ~(PAGE_SIZE-1); | |
| 42 | + | |
| 43 | + flags = smp_lock_cache(); | |
| 44 | + mn10300_local_dcache_flush_page(start); | |
| 45 | + smp_cache_call(SMP_DCACHE_FLUSH_RANGE, start, start + PAGE_SIZE); | |
| 46 | + smp_unlock_cache(flags); | |
| 47 | +} | |
| 48 | + | |
| 49 | +/** | |
| 50 | + * mn10300_dcache_flush_range - Globally flush range of data cache | |
| 51 | + * @start: The start address of the region to be flushed. | |
| 52 | + * @end: The end address of the region to be flushed. | |
| 53 | + * | |
| 54 | + * Flush a range of addresses in the data cache on all CPUs, between start and | |
| 55 | + * end-1 inclusive. | |
| 56 | + */ | |
| 57 | +void mn10300_dcache_flush_range(unsigned long start, unsigned long end) | |
| 58 | +{ | |
| 59 | + unsigned long flags; | |
| 60 | + | |
| 61 | + flags = smp_lock_cache(); | |
| 62 | + mn10300_local_dcache_flush_range(start, end); | |
| 63 | + smp_cache_call(SMP_DCACHE_FLUSH_RANGE, start, end); | |
| 64 | + smp_unlock_cache(flags); | |
| 65 | +} | |
| 66 | + | |
| 67 | +/** | |
| 68 | + * mn10300_dcache_flush_range2 - Globally flush range of data cache | |
| 69 | + * @start: The start address of the region to be flushed. | |
| 70 | + * @size: The size of the region to be flushed. | |
| 71 | + * | |
| 72 | + * Flush a range of addresses in the data cache on all CPUs, between start and | |
| 73 | + * start+size-1 inclusive. | |
| 74 | + */ | |
| 75 | +void mn10300_dcache_flush_range2(unsigned long start, unsigned long size) | |
| 76 | +{ | |
| 77 | + unsigned long flags; | |
| 78 | + | |
| 79 | + flags = smp_lock_cache(); | |
| 80 | + mn10300_local_dcache_flush_range2(start, size); | |
| 81 | + smp_cache_call(SMP_DCACHE_FLUSH_RANGE, start, start + size); | |
| 82 | + smp_unlock_cache(flags); | |
| 83 | +} | |
| 84 | + | |
| 85 | +/** | |
| 86 | + * mn10300_dcache_flush_inv - Globally flush and invalidate data cache | |
| 87 | + * | |
| 88 | + * Flush and invalidate the data cache on all CPUs. | |
| 89 | + */ | |
| 90 | +void mn10300_dcache_flush_inv(void) | |
| 91 | +{ | |
| 92 | + unsigned long flags; | |
| 93 | + | |
| 94 | + flags = smp_lock_cache(); | |
| 95 | + mn10300_local_dcache_flush_inv(); | |
| 96 | + smp_cache_call(SMP_DCACHE_FLUSH_INV, 0, 0); | |
| 97 | + smp_unlock_cache(flags); | |
| 98 | +} | |
| 99 | + | |
| 100 | +/** | |
| 101 | + * mn10300_dcache_flush_inv_page - Globally flush and invalidate a page of data | |
| 102 | + * cache | |
| 103 | + * @start: The address of the page of memory to be flushed and invalidated. | |
| 104 | + * | |
| 105 | + * Flush and invalidate a range of addresses in the data cache on all CPUs | |
| 106 | + * covering the page that includes the given address. | |
| 107 | + */ | |
| 108 | +void mn10300_dcache_flush_inv_page(unsigned long start) | |
| 109 | +{ | |
| 110 | + unsigned long flags; | |
| 111 | + | |
| 112 | + start &= ~(PAGE_SIZE-1); | |
| 113 | + | |
| 114 | + flags = smp_lock_cache(); | |
| 115 | + mn10300_local_dcache_flush_inv_page(start); | |
| 116 | + smp_cache_call(SMP_DCACHE_FLUSH_INV_RANGE, start, start + PAGE_SIZE); | |
| 117 | + smp_unlock_cache(flags); | |
| 118 | +} | |
| 119 | + | |
| 120 | +/** | |
| 121 | + * mn10300_dcache_flush_inv_range - Globally flush and invalidate range of data | |
| 122 | + * cache | |
| 123 | + * @start: The start address of the region to be flushed and invalidated. | |
| 124 | + * @end: The end address of the region to be flushed and invalidated. | |
| 125 | + * | |
| 126 | + * Flush and invalidate a range of addresses in the data cache on all CPUs, | |
| 127 | + * between start and end-1 inclusive. | |
| 128 | + */ | |
| 129 | +void mn10300_dcache_flush_inv_range(unsigned long start, unsigned long end) | |
| 130 | +{ | |
| 131 | + unsigned long flags; | |
| 132 | + | |
| 133 | + flags = smp_lock_cache(); | |
| 134 | + mn10300_local_dcache_flush_inv_range(start, end); | |
| 135 | + smp_cache_call(SMP_DCACHE_FLUSH_INV_RANGE, start, end); | |
| 136 | + smp_unlock_cache(flags); | |
| 137 | +} | |
| 138 | + | |
| 139 | +/** | |
| 140 | + * mn10300_dcache_flush_inv_range2 - Globally flush and invalidate range of data | |
| 141 | + * cache | |
| 142 | + * @start: The start address of the region to be flushed and invalidated. | |
| 143 | + * @size: The size of the region to be flushed and invalidated. | |
| 144 | + * | |
| 145 | + * Flush and invalidate a range of addresses in the data cache on all CPUs, | |
| 146 | + * between start and start+size-1 inclusive. | |
| 147 | + */ | |
| 148 | +void mn10300_dcache_flush_inv_range2(unsigned long start, unsigned long size) | |
| 149 | +{ | |
| 150 | + unsigned long flags; | |
| 151 | + | |
| 152 | + flags = smp_lock_cache(); | |
| 153 | + mn10300_local_dcache_flush_inv_range2(start, size); | |
| 154 | + smp_cache_call(SMP_DCACHE_FLUSH_INV_RANGE, start, start + size); | |
| 155 | + smp_unlock_cache(flags); | |
| 156 | +} | |
| @@ -0,0 +1,153 @@ | ||
| 1 | +/* Functions for global i/dcache invalidation when caching in SMP | |
| 2 | + * | |
| 3 | + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#include <linux/mm.h> | |
| 12 | +#include <asm/cacheflush.h> | |
| 13 | +#include "cache-smp.h" | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * mn10300_icache_inv - Globally invalidate instruction cache | |
| 17 | + * | |
| 18 | + * Invalidate the instruction cache on all CPUs. | |
| 19 | + */ | |
| 20 | +void mn10300_icache_inv(void) | |
| 21 | +{ | |
| 22 | + unsigned long flags; | |
| 23 | + | |
| 24 | + flags = smp_lock_cache(); | |
| 25 | + mn10300_local_icache_inv(); | |
| 26 | + smp_cache_call(SMP_ICACHE_INV, 0, 0); | |
| 27 | + smp_unlock_cache(flags); | |
| 28 | +} | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * mn10300_icache_inv_page - Globally invalidate a page of instruction cache | |
| 32 | + * @start: The address of the page of memory to be invalidated. | |
| 33 | + * | |
| 34 | + * Invalidate a range of addresses in the instruction cache on all CPUs | |
| 35 | + * covering the page that includes the given address. | |
| 36 | + */ | |
| 37 | +void mn10300_icache_inv_page(unsigned long start) | |
| 38 | +{ | |
| 39 | + unsigned long flags; | |
| 40 | + | |
| 41 | + start &= ~(PAGE_SIZE-1); | |
| 42 | + | |
| 43 | + flags = smp_lock_cache(); | |
| 44 | + mn10300_local_icache_inv_page(start); | |
| 45 | + smp_cache_call(SMP_ICACHE_INV_RANGE, start, start + PAGE_SIZE); | |
| 46 | + smp_unlock_cache(flags); | |
| 47 | +} | |
| 48 | + | |
| 49 | +/** | |
| 50 | + * mn10300_icache_inv_range - Globally invalidate range of instruction cache | |
| 51 | + * @start: The start address of the region to be invalidated. | |
| 52 | + * @end: The end address of the region to be invalidated. | |
| 53 | + * | |
| 54 | + * Invalidate a range of addresses in the instruction cache on all CPUs, | |
| 55 | + * between start and end-1 inclusive. | |
| 56 | + */ | |
| 57 | +void mn10300_icache_inv_range(unsigned long start, unsigned long end) | |
| 58 | +{ | |
| 59 | + unsigned long flags; | |
| 60 | + | |
| 61 | + flags = smp_lock_cache(); | |
| 62 | + mn10300_local_icache_inv_range(start, end); | |
| 63 | + smp_cache_call(SMP_ICACHE_INV_RANGE, start, end); | |
| 64 | + smp_unlock_cache(flags); | |
| 65 | +} | |
| 66 | + | |
| 67 | +/** | |
| 68 | + * mn10300_icache_inv_range2 - Globally invalidate range of instruction cache | |
| 69 | + * @start: The start address of the region to be invalidated. | |
| 70 | + * @size: The size of the region to be invalidated. | |
| 71 | + * | |
| 72 | + * Invalidate a range of addresses in the instruction cache on all CPUs, | |
| 73 | + * between start and start+size-1 inclusive. | |
| 74 | + */ | |
| 75 | +void mn10300_icache_inv_range2(unsigned long start, unsigned long size) | |
| 76 | +{ | |
| 77 | + unsigned long flags; | |
| 78 | + | |
| 79 | + flags = smp_lock_cache(); | |
| 80 | + mn10300_local_icache_inv_range2(start, size); | |
| 81 | + smp_cache_call(SMP_ICACHE_INV_RANGE, start, start + size); | |
| 82 | + smp_unlock_cache(flags); | |
| 83 | +} | |
| 84 | + | |
| 85 | +/** | |
| 86 | + * mn10300_dcache_inv - Globally invalidate data cache | |
| 87 | + * | |
| 88 | + * Invalidate the data cache on all CPUs. | |
| 89 | + */ | |
| 90 | +void mn10300_dcache_inv(void) | |
| 91 | +{ | |
| 92 | + unsigned long flags; | |
| 93 | + | |
| 94 | + flags = smp_lock_cache(); | |
| 95 | + mn10300_local_dcache_inv(); | |
| 96 | + smp_cache_call(SMP_DCACHE_INV, 0, 0); | |
| 97 | + smp_unlock_cache(flags); | |
| 98 | +} | |
| 99 | + | |
| 100 | +/** | |
| 101 | + * mn10300_dcache_inv_page - Globally invalidate a page of data cache | |
| 102 | + * @start: The address of the page of memory to be invalidated. | |
| 103 | + * | |
| 104 | + * Invalidate a range of addresses in the data cache on all CPUs covering the | |
| 105 | + * page that includes the given address. | |
| 106 | + */ | |
| 107 | +void mn10300_dcache_inv_page(unsigned long start) | |
| 108 | +{ | |
| 109 | + unsigned long flags; | |
| 110 | + | |
| 111 | + start &= ~(PAGE_SIZE-1); | |
| 112 | + | |
| 113 | + flags = smp_lock_cache(); | |
| 114 | + mn10300_local_dcache_inv_page(start); | |
| 115 | + smp_cache_call(SMP_DCACHE_INV_RANGE, start, start + PAGE_SIZE); | |
| 116 | + smp_unlock_cache(flags); | |
| 117 | +} | |
| 118 | + | |
| 119 | +/** | |
| 120 | + * mn10300_dcache_inv_range - Globally invalidate range of data cache | |
| 121 | + * @start: The start address of the region to be invalidated. | |
| 122 | + * @end: The end address of the region to be invalidated. | |
| 123 | + * | |
| 124 | + * Invalidate a range of addresses in the data cache on all CPUs, between start | |
| 125 | + * and end-1 inclusive. | |
| 126 | + */ | |
| 127 | +void mn10300_dcache_inv_range(unsigned long start, unsigned long end) | |
| 128 | +{ | |
| 129 | + unsigned long flags; | |
| 130 | + | |
| 131 | + flags = smp_lock_cache(); | |
| 132 | + mn10300_local_dcache_inv_range(start, end); | |
| 133 | + smp_cache_call(SMP_DCACHE_INV_RANGE, start, end); | |
| 134 | + smp_unlock_cache(flags); | |
| 135 | +} | |
| 136 | + | |
| 137 | +/** | |
| 138 | + * mn10300_dcache_inv_range2 - Globally invalidate range of data cache | |
| 139 | + * @start: The start address of the region to be invalidated. | |
| 140 | + * @size: The size of the region to be invalidated. | |
| 141 | + * | |
| 142 | + * Invalidate a range of addresses in the data cache on all CPUs, between start | |
| 143 | + * and start+size-1 inclusive. | |
| 144 | + */ | |
| 145 | +void mn10300_dcache_inv_range2(unsigned long start, unsigned long size) | |
| 146 | +{ | |
| 147 | + unsigned long flags; | |
| 148 | + | |
| 149 | + flags = smp_lock_cache(); | |
| 150 | + mn10300_local_dcache_inv_range2(start, size); | |
| 151 | + smp_cache_call(SMP_DCACHE_INV_RANGE, start, start + size); | |
| 152 | + smp_unlock_cache(flags); | |
| 153 | +} | |
| @@ -0,0 +1,105 @@ | ||
| 1 | +/* SMP global caching code | |
| 2 | + * | |
| 3 | + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#include <linux/module.h> | |
| 12 | +#include <linux/mm.h> | |
| 13 | +#include <linux/mman.h> | |
| 14 | +#include <linux/threads.h> | |
| 15 | +#include <linux/interrupt.h> | |
| 16 | +#include <asm/page.h> | |
| 17 | +#include <asm/pgtable.h> | |
| 18 | +#include <asm/processor.h> | |
| 19 | +#include <asm/cacheflush.h> | |
| 20 | +#include <asm/io.h> | |
| 21 | +#include <asm/uaccess.h> | |
| 22 | +#include <asm/smp.h> | |
| 23 | +#include "cache-smp.h" | |
| 24 | + | |
| 25 | +DEFINE_SPINLOCK(smp_cache_lock); | |
| 26 | +static unsigned long smp_cache_mask; | |
| 27 | +static unsigned long smp_cache_start; | |
| 28 | +static unsigned long smp_cache_end; | |
| 29 | +static cpumask_t smp_cache_ipi_map; /* Bitmask of cache IPI done CPUs */ | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * smp_cache_interrupt - Handle IPI request to flush caches. | |
| 33 | + * | |
| 34 | + * Handle a request delivered by IPI to flush the current CPU's | |
| 35 | + * caches. The parameters are stored in smp_cache_*. | |
| 36 | + */ | |
| 37 | +void smp_cache_interrupt(void) | |
| 38 | +{ | |
| 39 | + unsigned long opr_mask = smp_cache_mask; | |
| 40 | + | |
| 41 | + switch ((enum smp_dcache_ops)(opr_mask & SMP_DCACHE_OP_MASK)) { | |
| 42 | + case SMP_DCACHE_NOP: | |
| 43 | + break; | |
| 44 | + case SMP_DCACHE_INV: | |
| 45 | + mn10300_local_dcache_inv(); | |
| 46 | + break; | |
| 47 | + case SMP_DCACHE_INV_RANGE: | |
| 48 | + mn10300_local_dcache_inv_range(smp_cache_start, smp_cache_end); | |
| 49 | + break; | |
| 50 | + case SMP_DCACHE_FLUSH: | |
| 51 | + mn10300_local_dcache_flush(); | |
| 52 | + break; | |
| 53 | + case SMP_DCACHE_FLUSH_RANGE: | |
| 54 | + mn10300_local_dcache_flush_range(smp_cache_start, | |
| 55 | + smp_cache_end); | |
| 56 | + break; | |
| 57 | + case SMP_DCACHE_FLUSH_INV: | |
| 58 | + mn10300_local_dcache_flush_inv(); | |
| 59 | + break; | |
| 60 | + case SMP_DCACHE_FLUSH_INV_RANGE: | |
| 61 | + mn10300_local_dcache_flush_inv_range(smp_cache_start, | |
| 62 | + smp_cache_end); | |
| 63 | + break; | |
| 64 | + } | |
| 65 | + | |
| 66 | + switch ((enum smp_icache_ops)(opr_mask & SMP_ICACHE_OP_MASK)) { | |
| 67 | + case SMP_ICACHE_NOP: | |
| 68 | + break; | |
| 69 | + case SMP_ICACHE_INV: | |
| 70 | + mn10300_local_icache_inv(); | |
| 71 | + break; | |
| 72 | + case SMP_ICACHE_INV_RANGE: | |
| 73 | + mn10300_local_icache_inv_range(smp_cache_start, smp_cache_end); | |
| 74 | + break; | |
| 75 | + } | |
| 76 | + | |
| 77 | + cpu_clear(smp_processor_id(), smp_cache_ipi_map); | |
| 78 | +} | |
| 79 | + | |
| 80 | +/** | |
| 81 | + * smp_cache_call - Issue an IPI to request the other CPUs flush caches | |
| 82 | + * @opr_mask: Cache operation flags | |
| 83 | + * @start: Start address of request | |
| 84 | + * @end: End address of request | |
| 85 | + * | |
| 86 | + * Send cache flush IPI to other CPUs. This invokes smp_cache_interrupt() | |
| 87 | + * above on those other CPUs and then waits for them to finish. | |
| 88 | + * | |
| 89 | + * The caller must hold smp_cache_lock. | |
| 90 | + */ | |
| 91 | +void smp_cache_call(unsigned long opr_mask, | |
| 92 | + unsigned long start, unsigned long end) | |
| 93 | +{ | |
| 94 | + smp_cache_mask = opr_mask; | |
| 95 | + smp_cache_start = start; | |
| 96 | + smp_cache_end = end; | |
| 97 | + smp_cache_ipi_map = cpu_online_map; | |
| 98 | + cpu_clear(smp_processor_id(), smp_cache_ipi_map); | |
| 99 | + | |
| 100 | + send_IPI_allbutself(FLUSH_CACHE_IPI); | |
| 101 | + | |
| 102 | + while (!cpus_empty(smp_cache_ipi_map)) | |
| 103 | + /* nothing. lockup detection does not belong here */ | |
| 104 | + mb(); | |
| 105 | +} | |
| @@ -0,0 +1,69 @@ | ||
| 1 | +/* SMP caching definitions | |
| 2 | + * | |
| 3 | + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | + | |
| 13 | +/* | |
| 14 | + * Operation requests for smp_cache_call(). | |
| 15 | + * | |
| 16 | + * One of smp_icache_ops and one of smp_dcache_ops can be OR'd together. | |
| 17 | + */ | |
| 18 | +enum smp_icache_ops { | |
| 19 | + SMP_ICACHE_NOP = 0x0000, | |
| 20 | + SMP_ICACHE_INV = 0x0001, | |
| 21 | + SMP_ICACHE_INV_RANGE = 0x0002, | |
| 22 | +}; | |
| 23 | +#define SMP_ICACHE_OP_MASK 0x0003 | |
| 24 | + | |
| 25 | +enum smp_dcache_ops { | |
| 26 | + SMP_DCACHE_NOP = 0x0000, | |
| 27 | + SMP_DCACHE_INV = 0x0004, | |
| 28 | + SMP_DCACHE_INV_RANGE = 0x0008, | |
| 29 | + SMP_DCACHE_FLUSH = 0x000c, | |
| 30 | + SMP_DCACHE_FLUSH_RANGE = 0x0010, | |
| 31 | + SMP_DCACHE_FLUSH_INV = 0x0014, | |
| 32 | + SMP_DCACHE_FLUSH_INV_RANGE = 0x0018, | |
| 33 | +}; | |
| 34 | +#define SMP_DCACHE_OP_MASK 0x001c | |
| 35 | + | |
| 36 | +#define SMP_IDCACHE_INV_FLUSH (SMP_ICACHE_INV | SMP_DCACHE_FLUSH) | |
| 37 | +#define SMP_IDCACHE_INV_FLUSH_RANGE (SMP_ICACHE_INV_RANGE | SMP_DCACHE_FLUSH_RANGE) | |
| 38 | + | |
| 39 | +/* | |
| 40 | + * cache-smp.c | |
| 41 | + */ | |
| 42 | +#ifdef CONFIG_SMP | |
| 43 | +extern spinlock_t smp_cache_lock; | |
| 44 | + | |
| 45 | +extern void smp_cache_call(unsigned long opr_mask, | |
| 46 | + unsigned long addr, unsigned long end); | |
| 47 | + | |
| 48 | +static inline unsigned long smp_lock_cache(void) | |
| 49 | + __acquires(&smp_cache_lock) | |
| 50 | +{ | |
| 51 | + unsigned long flags; | |
| 52 | + spin_lock_irqsave(&smp_cache_lock, flags); | |
| 53 | + return flags; | |
| 54 | +} | |
| 55 | + | |
| 56 | +static inline void smp_unlock_cache(unsigned long flags) | |
| 57 | + __releases(&smp_cache_lock) | |
| 58 | +{ | |
| 59 | + spin_unlock_irqrestore(&smp_cache_lock, flags); | |
| 60 | +} | |
| 61 | + | |
| 62 | +#else | |
| 63 | +static inline unsigned long smp_lock_cache(void) { return 0; } | |
| 64 | +static inline void smp_unlock_cache(unsigned long flags) {} | |
| 65 | +static inline void smp_cache_call(unsigned long opr_mask, | |
| 66 | + unsigned long addr, unsigned long end) | |
| 67 | +{ | |
| 68 | +} | |
| 69 | +#endif /* CONFIG_SMP */ | |
| @@ -18,8 +18,13 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <asm/cacheflush.h> |
| 19 | 19 | #include <asm/io.h> |
| 20 | 20 | #include <asm/uaccess.h> |
| 21 | +#include <asm/smp.h> | |
| 22 | +#include "cache-smp.h" | |
| 21 | 23 | |
| 22 | 24 | EXPORT_SYMBOL(mn10300_icache_inv); |
| 25 | +EXPORT_SYMBOL(mn10300_icache_inv_range); | |
| 26 | +EXPORT_SYMBOL(mn10300_icache_inv_range2); | |
| 27 | +EXPORT_SYMBOL(mn10300_icache_inv_page); | |
| 23 | 28 | EXPORT_SYMBOL(mn10300_dcache_inv); |
| 24 | 29 | EXPORT_SYMBOL(mn10300_dcache_inv_range); |
| 25 | 30 | EXPORT_SYMBOL(mn10300_dcache_inv_range2); |
| @@ -36,96 +41,6 @@ EXPORT_SYMBOL(mn10300_dcache_flush_range2); · 10 unmodified lines | ||
| 36 | 41 | EXPORT_SYMBOL(mn10300_dcache_flush_page); |
| 37 | 42 | #endif |
| 38 | 43 | |
| 39 | −/* | |
| 40 | − * write a page back from the dcache and invalidate the icache so that we can | |
| 41 | − * run code from it that we've just written into it | |
| 42 | − */ | |
| 43 | −void flush_icache_page(struct vm_area_struct *vma, struct page *page) | |
| 44 | −{ | |
| 45 | − mn10300_dcache_flush_page(page_to_phys(page)); | |
| 46 | − mn10300_icache_inv(); | |
| 47 | −} | |
| 48 | −EXPORT_SYMBOL(flush_icache_page); | |
| 49 | − | |
| 50 | −/* | |
| 51 | − * write some code we've just written back from the dcache and invalidate the | |
| 52 | − * icache so that we can run that code | |
| 53 | − */ | |
| 54 | −void flush_icache_range(unsigned long start, unsigned long end) | |
| 55 | −{ | |
| 56 | −#ifdef CONFIG_MN10300_CACHE_WBACK | |
| 57 | − unsigned long addr, size, base, off; | |
| 58 | − struct page *page; | |
| 59 | − pgd_t *pgd; | |
| 60 | − pud_t *pud; | |
| 61 | − pmd_t *pmd; | |
| 62 | − pte_t *ppte, pte; | |
| 63 | − | |
| 64 | − if (end > 0x80000000UL) { | |
| 65 | − /* addresses above 0xa0000000 do not go through the cache */ | |
| 66 | − if (end > 0xa0000000UL) { | |
| 67 | − end = 0xa0000000UL; | |
| 68 | − if (start >= end) | |
| 69 | − return; | |
| 70 | − } | |
| 71 | − | |
| 72 | − /* kernel addresses between 0x80000000 and 0x9fffffff do not | |
| 73 | − * require page tables, so we just map such addresses directly */ | |
| 74 | − base = (start >= 0x80000000UL) ? start : 0x80000000UL; | |
| 75 | − mn10300_dcache_flush_range(base, end); | |
| 76 | − if (base == start) | |
| 77 | − goto invalidate; | |
| 78 | − end = base; | |
| 79 | − } | |
| 80 | − | |
| 81 | − for (; start < end; start += size) { | |
| 82 | − /* work out how much of the page to flush */ | |
| 83 | − off = start & (PAGE_SIZE - 1); | |
| 84 | − | |
| 85 | − size = end - start; | |
| 86 | − if (size > PAGE_SIZE - off) | |
| 87 | − size = PAGE_SIZE - off; | |
| 88 | − | |
| 89 | − /* get the physical address the page is mapped to from the page | |
| 90 | − * tables */ | |
| 91 | − pgd = pgd_offset(current->mm, start); | |
| 92 | − if (!pgd || !pgd_val(*pgd)) | |
| 93 | − continue; | |
| 94 | − | |
| 95 | − pud = pud_offset(pgd, start); | |
| 96 | − if (!pud || !pud_val(*pud)) | |
| 97 | − continue; | |
| 98 | − | |
| 99 | − pmd = pmd_offset(pud, start); | |
| 100 | − if (!pmd || !pmd_val(*pmd)) | |
| 101 | − continue; | |
| 102 | − | |
| 103 | − ppte = pte_offset_map(pmd, start); | |
| 104 | − if (!ppte) | |
| 105 | − continue; | |
| 106 | − pte = *ppte; | |
| 107 | − pte_unmap(ppte); | |
| 108 | − | |
| 109 | − if (pte_none(pte)) | |
| 110 | − continue; | |
| 111 | − | |
| 112 | − page = pte_page(pte); | |
| 113 | − if (!page) | |
| 114 | − continue; | |
| 115 | − | |
| 116 | − addr = page_to_phys(page); | |
| 117 | − | |
| 118 | − /* flush the dcache and invalidate the icache coverage on that | |
| 119 | − * region */ | |
| 120 | − mn10300_dcache_flush_range2(addr + off, size); | |
| 121 | − } | |
| 122 | −#endif | |
| 123 | − | |
| 124 | −invalidate: | |
| 125 | − mn10300_icache_inv(); | |
| 126 | −} | |
| 127 | −EXPORT_SYMBOL(flush_icache_range); | |
| 128 | − | |
| 129 | 44 | /* |
| 130 | 45 | * allow userspace to flush the instruction cache |
| 131 | 46 | */ |
| @@ -39,10 +39,6 @@ void bust_spinlocks(int yes) · 38 unmodified lines | ||
| 39 | 39 | { |
| 40 | 40 | if (yes) { |
| 41 | 41 | oops_in_progress = 1; |
| 42 | −#ifdef CONFIG_SMP | |
| 43 | − /* Many serial drivers do __global_cli() */ | |
| 44 | − global_irq_lock = 0; | |
| 45 | −#endif | |
| 46 | 42 | } else { |
| 47 | 43 | int loglevel_save = console_loglevel; |
| 48 | 44 | #ifdef CONFIG_VT |
| @@ -100,8 +96,6 @@ static void print_pagetable_entries(pgd_t *pgdir, unsigned long address) · 51 unmodified lines | ||
| 100 | 96 | } |
| 101 | 97 | #endif |
| 102 | 98 | |
| 103 | −asmlinkage void monitor_signal(struct pt_regs *); | |
| 104 | − | |
| 105 | 99 | /* |
| 106 | 100 | * This routine handles page faults. It determines the address, |
| 107 | 101 | * and the problem, and then passes it off to one of the appropriate |
| @@ -279,7 +273,6 @@ good_area: · 171 unmodified lines | ||
| 279 | 273 | */ |
| 280 | 274 | bad_area: |
| 281 | 275 | up_read(&mm->mmap_sem); |
| 282 | − monitor_signal(regs); | |
| 283 | 276 | |
| 284 | 277 | /* User mode accesses just cause a SIGSEGV */ |
| 285 | 278 | if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) { |
| @@ -292,7 +285,6 @@ bad_area: · 6 unmodified lines | ||
| 292 | 285 | } |
| 293 | 286 | |
| 294 | 287 | no_context: |
| 295 | − monitor_signal(regs); | |
| 296 | 288 | /* Are we prepared to handle this kernel fault? */ |
| 297 | 289 | if (fixup_exception(regs)) |
| 298 | 290 | return; |
| @@ -338,14 +330,13 @@ no_context: · 39 unmodified lines | ||
| 338 | 330 | */ |
| 339 | 331 | out_of_memory: |
| 340 | 332 | up_read(&mm->mmap_sem); |
| 341 | − if ((fault_code & MMUFCR_xFC_ACCESS) != MMUFCR_xFC_ACCESS_USR) | |
| 342 | − goto no_context; | |
| 343 | − pagefault_out_of_memory(); | |
| 344 | − return; | |
| 333 | + printk(KERN_ALERT "VM: killing process %s\n", tsk->comm); | |
| 334 | + if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) | |
| 335 | + do_exit(SIGKILL); | |
| 336 | + goto no_context; | |
| 345 | 337 | |
| 346 | 338 | do_sigbus: |
| 347 | 339 | up_read(&mm->mmap_sem); |
| 348 | − monitor_signal(regs); | |
| 349 | 340 | |
| 350 | 341 | /* |
| 351 | 342 | * Send a sigbus, regardless of whether we were in kernel |
| @@ -41,6 +41,10 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | unsigned long highstart_pfn, highend_pfn; |
| 43 | 43 | |
| 44 | +#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT | |
| 45 | +static struct vm_struct user_iomap_vm; | |
| 46 | +#endif | |
| 47 | + | |
| 44 | 48 | /* |
| 45 | 49 | * set up paging |
| 46 | 50 | */ |
| @@ -73,7 +77,24 @@ void __init paging_init(void) · 26 unmodified lines | ||
| 73 | 77 | /* pass the memory from the bootmem allocator to the main allocator */ |
| 74 | 78 | free_area_init(zones_size); |
| 75 | 79 | |
| 76 | − __flush_tlb_all(); | |
| 80 | +#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT | |
| 81 | + /* The Atomic Operation Unit registers need to be mapped to userspace | |
| 82 | + * for all processes. The following uses vm_area_register_early() to | |
| 83 | + * reserve the first page of the vmalloc area and sets the pte for that | |
| 84 | + * page. | |
| 85 | + * | |
| 86 | + * glibc hardcodes this virtual mapping, so we're pretty much stuck with | |
| 87 | + * it from now on. | |
| 88 | + */ | |
| 89 | + user_iomap_vm.flags = VM_USERMAP; | |
| 90 | + user_iomap_vm.size = 1 << PAGE_SHIFT; | |
| 91 | + vm_area_register_early(&user_iomap_vm, PAGE_SIZE); | |
| 92 | + ppte = kernel_vmalloc_ptes; | |
| 93 | + set_pte(ppte, pfn_pte(USER_ATOMIC_OPS_PAGE_ADDR >> PAGE_SHIFT, | |
| 94 | + PAGE_USERIO)); | |
| 95 | +#endif | |
| 96 | + | |
| 97 | + local_flush_tlb_all(); | |
| 77 | 98 | } |
| 78 | 99 | |
| 79 | 100 | /* |
| @@ -84,8 +105,7 @@ void __init mem_init(void) · 4 unmodified lines | ||
| 84 | 105 | int codesize, reservedpages, datasize, initsize; |
| 85 | 106 | int tmp; |
| 86 | 107 | |
| 87 | − if (!mem_map) | |
| 88 | − BUG(); | |
| 108 | + BUG_ON(!mem_map); | |
| 89 | 109 | |
| 90 | 110 | #define START_PFN (contig_page_data.bdata->node_min_pfn) |
| 91 | 111 | #define MAX_LOW_PFN (contig_page_data.bdata->node_low_pfn) |
| @@ -449,8 +449,7 @@ found_opcode: · 448 unmodified lines | ||
| 449 | 449 | regs->pc, opcode, pop->opcode, pop->params[0], pop->params[1]); |
| 450 | 450 | |
| 451 | 451 | tmp = format_tbl[pop->format].opsz; |
| 452 | − if (tmp > noc) | |
| 453 | − BUG(); /* match was less complete than it ought to have been */ | |
| 452 | + BUG_ON(tmp > noc); /* match was less complete than it ought to have been */ | |
| 454 | 453 | |
| 455 | 454 | if (tmp < noc) { |
| 456 | 455 | tmp = noc - tmp; |
| @@ -13,40 +13,15 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <asm/mmu_context.h> |
| 14 | 14 | #include <asm/tlbflush.h> |
| 15 | 15 | |
| 16 | +#ifdef CONFIG_MN10300_TLB_USE_PIDR | |
| 16 | 17 | /* |
| 17 | 18 | * list of the MMU contexts last allocated on each CPU |
| 18 | 19 | */ |
| 19 | 20 | unsigned long mmu_context_cache[NR_CPUS] = { |
| 20 | − [0 ... NR_CPUS - 1] = MMU_CONTEXT_FIRST_VERSION * 2 - 1, | |
| 21 | + [0 ... NR_CPUS - 1] = | |
| 22 | + MMU_CONTEXT_FIRST_VERSION * 2 - (1 - MMU_CONTEXT_TLBPID_LOCK_NR), | |
| 21 | 23 | }; |
| 22 | − | |
| 23 | −/* | |
| 24 | − * flush the specified TLB entry | |
| 25 | − */ | |
| 26 | −void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) | |
| 27 | −{ | |
| 28 | − unsigned long pteu, cnx, flags; | |
| 29 | − | |
| 30 | − addr &= PAGE_MASK; | |
| 31 | − | |
| 32 | − /* make sure the context doesn't migrate and defend against | |
| 33 | − * interference from vmalloc'd regions */ | |
| 34 | − local_irq_save(flags); | |
| 35 | − | |
| 36 | − cnx = mm_context(vma->vm_mm); | |
| 37 | − | |
| 38 | − if (cnx != MMU_NO_CONTEXT) { | |
| 39 | − pteu = addr | (cnx & 0x000000ffUL); | |
| 40 | − IPTEU = pteu; | |
| 41 | − DPTEU = pteu; | |
| 42 | − if (IPTEL & xPTEL_V) | |
| 43 | − IPTEL = 0; | |
| 44 | − if (DPTEL & xPTEL_V) | |
| 45 | − DPTEL = 0; | |
| 46 | − } | |
| 47 | − | |
| 48 | − local_irq_restore(flags); | |
| 49 | −} | |
| 24 | +#endif /* CONFIG_MN10300_TLB_USE_PIDR */ | |
| 50 | 25 | |
| 51 | 26 | /* |
| 52 | 27 | * preemptively set a TLB entry |
| @@ -63,10 +38,16 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t *pte · 10 unmodified lines | ||
| 63 | 38 | * interference from vmalloc'd regions */ |
| 64 | 39 | local_irq_save(flags); |
| 65 | 40 | |
| 41 | + cnx = ~MMU_NO_CONTEXT; | |
| 42 | +#ifdef CONFIG_MN10300_TLB_USE_PIDR | |
| 66 | 43 | cnx = mm_context(vma->vm_mm); |
| 44 | +#endif | |
| 67 | 45 | |
| 68 | 46 | if (cnx != MMU_NO_CONTEXT) { |
| 69 | − pteu = addr | (cnx & 0x000000ffUL); | |
| 47 | + pteu = addr; | |
| 48 | +#ifdef CONFIG_MN10300_TLB_USE_PIDR | |
| 49 | + pteu |= cnx & MMU_CONTEXT_TLBPID_MASK; | |
| 50 | +#endif | |
| 70 | 51 | if (!(pte_val(pte) & _PAGE_NX)) { |
| 71 | 52 | IPTEU = pteu; |
| 72 | 53 | if (IPTEL & xPTEL_V) |
| @@ -59,7 +59,7 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags) · 58 unmodified lines | ||
| 59 | 59 | * It's enough to flush this one mapping. |
| 60 | 60 | * (PGE mappings get flushed as well) |
| 61 | 61 | */ |
| 62 | − __flush_tlb_one(vaddr); | |
| 62 | + local_flush_tlb_one(vaddr); | |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | 65 | pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) |
| @@ -27,7 +27,6 @@ · 26 unmodified lines | ||
| 27 | 27 | ############################################################################### |
| 28 | 28 | .type itlb_miss,@function |
| 29 | 29 | ENTRY(itlb_miss) |
| 30 | − and ~EPSW_NMID,epsw | |
| 31 | 30 | #ifdef CONFIG_GDBSTUB |
| 32 | 31 | movm [d2,d3,a2],(sp) |
| 33 | 32 | #else |
| @@ -38,6 +37,12 @@ ENTRY(itlb_miss) · 4 unmodified lines | ||
| 38 | 37 | nop |
| 39 | 38 | #endif |
| 40 | 39 | |
| 40 | +#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR) | |
| 41 | + mov (MMUCTR),d2 | |
| 42 | + mov d2,(MMUCTR) | |
| 43 | +#endif | |
| 44 | + | |
| 45 | + and ~EPSW_NMID,epsw | |
| 41 | 46 | mov (IPTEU),d3 |
| 42 | 47 | mov (PTBR),a2 |
| 43 | 48 | mov d3,d2 |
| @@ -56,10 +61,16 @@ ENTRY(itlb_miss) · 12 unmodified lines | ||
| 56 | 61 | btst _PAGE_VALID,d2 |
| 57 | 62 | beq itlb_miss_fault # jump if doesn't point to a page |
| 58 | 63 | # (might be a swap id) |
| 64 | +#if ((_PAGE_ACCESSED & 0xffffff00) == 0) | |
| 59 | 65 | bset _PAGE_ACCESSED,(0,a2) |
| 60 | − and ~(xPTEL_UNUSED1|xPTEL_UNUSED2),d2 | |
| 66 | +#elif ((_PAGE_ACCESSED & 0xffff00ff) == 0) | |
| 67 | + bset +(_PAGE_ACCESSED >> 8),(1,a2) | |
| 68 | +#else | |
| 69 | +#error "_PAGE_ACCESSED value is out of range" | |
| 70 | +#endif | |
| 71 | + and ~xPTEL2_UNUSED1,d2 | |
| 61 | 72 | itlb_miss_set: |
| 62 | − mov d2,(IPTEL) # change the TLB | |
| 73 | + mov d2,(IPTEL2) # change the TLB | |
| 63 | 74 | #ifdef CONFIG_GDBSTUB |
| 64 | 75 | movm (sp),[d2,d3,a2] |
| 65 | 76 | #endif |
| @@ -79,7 +90,6 @@ itlb_miss_fault: · 13 unmodified lines | ||
| 79 | 90 | ############################################################################### |
| 80 | 91 | .type dtlb_miss,@function |
| 81 | 92 | ENTRY(dtlb_miss) |
| 82 | − and ~EPSW_NMID,epsw | |
| 83 | 93 | #ifdef CONFIG_GDBSTUB |
| 84 | 94 | movm [d2,d3,a2],(sp) |
| 85 | 95 | #else |
| @@ -90,6 +100,12 @@ ENTRY(dtlb_miss) · 4 unmodified lines | ||
| 90 | 100 | nop |
| 91 | 101 | #endif |
| 92 | 102 | |
| 103 | +#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR) | |
| 104 | + mov (MMUCTR),d2 | |
| 105 | + mov d2,(MMUCTR) | |
| 106 | +#endif | |
| 107 | + | |
| 108 | + and ~EPSW_NMID,epsw | |
| 93 | 109 | mov (DPTEU),d3 |
| 94 | 110 | mov (PTBR),a2 |
| 95 | 111 | mov d3,d2 |
| @@ -108,10 +124,16 @@ ENTRY(dtlb_miss) · 12 unmodified lines | ||
| 108 | 124 | btst _PAGE_VALID,d2 |
| 109 | 125 | beq dtlb_miss_fault # jump if doesn't point to a page |
| 110 | 126 | # (might be a swap id) |
| 127 | +#if ((_PAGE_ACCESSED & 0xffffff00) == 0) | |
| 111 | 128 | bset _PAGE_ACCESSED,(0,a2) |
| 112 | − and ~(xPTEL_UNUSED1|xPTEL_UNUSED2),d2 | |
| 129 | +#elif ((_PAGE_ACCESSED & 0xffff00ff) == 0) | |
| 130 | + bset +(_PAGE_ACCESSED >> 8),(1,a2) | |
| 131 | +#else | |
| 132 | +#error "_PAGE_ACCESSED value is out of range" | |
| 133 | +#endif | |
| 134 | + and ~xPTEL2_UNUSED1,d2 | |
| 113 | 135 | dtlb_miss_set: |
| 114 | − mov d2,(DPTEL) # change the TLB | |
| 136 | + mov d2,(DPTEL2) # change the TLB | |
| 115 | 137 | #ifdef CONFIG_GDBSTUB |
| 116 | 138 | movm (sp),[d2,d3,a2] |
| 117 | 139 | #endif |
| @@ -130,9 +152,15 @@ dtlb_miss_fault: · 12 unmodified lines | ||
| 130 | 152 | ############################################################################### |
| 131 | 153 | .type itlb_aerror,@function |
| 132 | 154 | ENTRY(itlb_aerror) |
| 133 | − and ~EPSW_NMID,epsw | |
| 134 | 155 | add -4,sp |
| 135 | 156 | SAVE_ALL |
| 157 | + | |
| 158 | +#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR) | |
| 159 | + mov (MMUCTR),d1 | |
| 160 | + mov d1,(MMUCTR) | |
| 161 | +#endif | |
| 162 | + | |
| 163 | + and ~EPSW_NMID,epsw | |
| 136 | 164 | add -4,sp # need to pass three params |
| 137 | 165 | |
| 138 | 166 | # calculate the fault code |
| @@ -140,15 +168,13 @@ ENTRY(itlb_aerror) · 1 unmodified line | ||
| 140 | 168 | or 0x00010000,d1 # it's an instruction fetch |
| 141 | 169 | |
| 142 | 170 | # determine the page address |
| 143 | − mov (IPTEU),a2 | |
| 144 | − mov a2,d0 | |
| 171 | + mov (IPTEU),d0 | |
| 145 | 172 | and PAGE_MASK,d0 |
| 146 | 173 | mov d0,(12,sp) |
| 147 | 174 | |
| 148 | 175 | clr d0 |
| 149 | − mov d0,(IPTEL) | |
| 176 | + mov d0,(IPTEL2) | |
| 150 | 177 | |
| 151 | − and ~EPSW_NMID,epsw | |
| 152 | 178 | or EPSW_IE,epsw |
| 153 | 179 | mov fp,d0 |
| 154 | 180 | call do_page_fault[],0 # do_page_fault(regs,code,addr |
| @@ -163,10 +189,16 @@ ENTRY(itlb_aerror) · 8 unmodified lines | ||
| 163 | 189 | ############################################################################### |
| 164 | 190 | .type dtlb_aerror,@function |
| 165 | 191 | ENTRY(dtlb_aerror) |
| 166 | − and ~EPSW_NMID,epsw | |
| 167 | 192 | add -4,sp |
| 168 | 193 | SAVE_ALL |
| 194 | + | |
| 195 | +#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR) | |
| 196 | + mov (MMUCTR),d1 | |
| 197 | + mov d1,(MMUCTR) | |
| 198 | +#endif | |
| 199 | + | |
| 169 | 200 | add -4,sp # need to pass three params |
| 201 | + and ~EPSW_NMID,epsw | |
| 170 | 202 | |
| 171 | 203 | # calculate the fault code |
| 172 | 204 | movhu (MMUFCR_DFC),d1 |
| @@ -178,9 +210,8 @@ ENTRY(dtlb_aerror) · 5 unmodified lines | ||
| 178 | 210 | mov d0,(12,sp) |
| 179 | 211 | |
| 180 | 212 | clr d0 |
| 181 | − mov d0,(DPTEL) | |
| 213 | + mov d0,(DPTEL2) | |
| 182 | 214 | |
| 183 | − and ~EPSW_NMID,epsw | |
| 184 | 215 | or EPSW_IE,epsw |
| 185 | 216 | mov fp,d0 |
| 186 | 217 | call do_page_fault[],0 # do_page_fault(regs,code,addr |
| @@ -0,0 +1,214 @@ | ||
| 1 | +/* SMP TLB support routines. | |
| 2 | + * | |
| 3 | + * Copyright (C) 2006-2008 Panasonic Corporation | |
| 4 | + * All Rights Reserved. | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * version 2 as published by the Free Software Foundation. | |
| 9 | + * | |
| 10 | + * This program is distributed in the hope that it will be useful, | |
| 11 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | + * GNU General Public License for more details. | |
| 14 | + */ | |
| 15 | +#include <linux/interrupt.h> | |
| 16 | +#include <linux/spinlock.h> | |
| 17 | +#include <linux/init.h> | |
| 18 | +#include <linux/jiffies.h> | |
| 19 | +#include <linux/cpumask.h> | |
| 20 | +#include <linux/err.h> | |
| 21 | +#include <linux/kernel.h> | |
| 22 | +#include <linux/delay.h> | |
| 23 | +#include <linux/sched.h> | |
| 24 | +#include <linux/profile.h> | |
| 25 | +#include <linux/smp.h> | |
| 26 | +#include <asm/tlbflush.h> | |
| 27 | +#include <asm/system.h> | |
| 28 | +#include <asm/bitops.h> | |
| 29 | +#include <asm/processor.h> | |
| 30 | +#include <asm/bug.h> | |
| 31 | +#include <asm/exceptions.h> | |
| 32 | +#include <asm/hardirq.h> | |
| 33 | +#include <asm/fpu.h> | |
| 34 | +#include <asm/mmu_context.h> | |
| 35 | +#include <asm/thread_info.h> | |
| 36 | +#include <asm/cpu-regs.h> | |
| 37 | +#include <asm/intctl-regs.h> | |
| 38 | + | |
| 39 | +/* | |
| 40 | + * For flush TLB | |
| 41 | + */ | |
| 42 | +#define FLUSH_ALL 0xffffffff | |
| 43 | + | |
| 44 | +static cpumask_t flush_cpumask; | |
| 45 | +static struct mm_struct *flush_mm; | |
| 46 | +static unsigned long flush_va; | |
| 47 | +static DEFINE_SPINLOCK(tlbstate_lock); | |
| 48 | + | |
| 49 | +DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) = { | |
| 50 | + &init_mm, 0 | |
| 51 | +}; | |
| 52 | + | |
| 53 | +static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, | |
| 54 | + unsigned long va); | |
| 55 | +static void do_flush_tlb_all(void *info); | |
| 56 | + | |
| 57 | +/** | |
| 58 | + * smp_flush_tlb - Callback to invalidate the TLB. | |
| 59 | + * @unused: Callback context (ignored). | |
| 60 | + */ | |
| 61 | +void smp_flush_tlb(void *unused) | |
| 62 | +{ | |
| 63 | + unsigned long cpu_id; | |
| 64 | + | |
| 65 | + cpu_id = get_cpu(); | |
| 66 | + | |
| 67 | + if (!cpu_isset(cpu_id, flush_cpumask)) | |
| 68 | + /* This was a BUG() but until someone can quote me the line | |
| 69 | + * from the intel manual that guarantees an IPI to multiple | |
| 70 | + * CPUs is retried _only_ on the erroring CPUs its staying as a | |
| 71 | + * return | |
| 72 | + * | |
| 73 | + * BUG(); | |
| 74 | + */ | |
| 75 | + goto out; | |
| 76 | + | |
| 77 | + if (flush_va == FLUSH_ALL) | |
| 78 | + local_flush_tlb(); | |
| 79 | + else | |
| 80 | + local_flush_tlb_page(flush_mm, flush_va); | |
| 81 | + | |
| 82 | + smp_mb__before_clear_bit(); | |
| 83 | + cpu_clear(cpu_id, flush_cpumask); | |
| 84 | + smp_mb__after_clear_bit(); | |
| 85 | +out: | |
| 86 | + put_cpu(); | |
| 87 | +} | |
| 88 | + | |
| 89 | +/** | |
| 90 | + * flush_tlb_others - Tell the specified CPUs to invalidate their TLBs | |
| 91 | + * @cpumask: The list of CPUs to target. | |
| 92 | + * @mm: The VM context to flush from (if va!=FLUSH_ALL). | |
| 93 | + * @va: Virtual address to flush or FLUSH_ALL to flush everything. | |
| 94 | + */ | |
| 95 | +static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, | |
| 96 | + unsigned long va) | |
| 97 | +{ | |
| 98 | + cpumask_t tmp; | |
| 99 | + | |
| 100 | + /* A couple of sanity checks (to be removed): | |
| 101 | + * - mask must not be empty | |
| 102 | + * - current CPU must not be in mask | |
| 103 | + * - we do not send IPIs to as-yet unbooted CPUs. | |
| 104 | + */ | |
| 105 | + BUG_ON(!mm); | |
| 106 | + BUG_ON(cpus_empty(cpumask)); | |
| 107 | + BUG_ON(cpu_isset(smp_processor_id(), cpumask)); | |
| 108 | + | |
| 109 | + cpus_and(tmp, cpumask, cpu_online_map); | |
| 110 | + BUG_ON(!cpus_equal(cpumask, tmp)); | |
| 111 | + | |
| 112 | + /* I'm not happy about this global shared spinlock in the MM hot path, | |
| 113 | + * but we'll see how contended it is. | |
| 114 | + * | |
| 115 | + * Temporarily this turns IRQs off, so that lockups are detected by the | |
| 116 | + * NMI watchdog. | |
| 117 | + */ | |
| 118 | + spin_lock(&tlbstate_lock); | |
| 119 | + | |
| 120 | + flush_mm = mm; | |
| 121 | + flush_va = va; | |
| 122 | +#if NR_CPUS <= BITS_PER_LONG | |
| 123 | + atomic_set_mask(cpumask.bits[0], &flush_cpumask.bits[0]); | |
| 124 | +#else | |
| 125 | +#error Not supported. | |
| 126 | +#endif | |
| 127 | + | |
| 128 | + /* FIXME: if NR_CPUS>=3, change send_IPI_mask */ | |
| 129 | + smp_call_function(smp_flush_tlb, NULL, 1); | |
| 130 | + | |
| 131 | + while (!cpus_empty(flush_cpumask)) | |
| 132 | + /* Lockup detection does not belong here */ | |
| 133 | + smp_mb(); | |
| 134 | + | |
| 135 | + flush_mm = NULL; | |
| 136 | + flush_va = 0; | |
| 137 | + spin_unlock(&tlbstate_lock); | |
| 138 | +} | |
| 139 | + | |
| 140 | +/** | |
| 141 | + * flush_tlb_mm - Invalidate TLB of specified VM context | |
| 142 | + * @mm: The VM context to invalidate. | |
| 143 | + */ | |
| 144 | +void flush_tlb_mm(struct mm_struct *mm) | |
| 145 | +{ | |
| 146 | + cpumask_t cpu_mask; | |
| 147 | + | |
| 148 | + preempt_disable(); | |
| 149 | + cpu_mask = mm->cpu_vm_mask; | |
| 150 | + cpu_clear(smp_processor_id(), cpu_mask); | |
| 151 | + | |
| 152 | + local_flush_tlb(); | |
| 153 | + if (!cpus_empty(cpu_mask)) | |
| 154 | + flush_tlb_others(cpu_mask, mm, FLUSH_ALL); | |
| 155 | + | |
| 156 | + preempt_enable(); | |
| 157 | +} | |
| 158 | + | |
| 159 | +/** | |
| 160 | + * flush_tlb_current_task - Invalidate TLB of current task | |
| 161 | + */ | |
| 162 | +void flush_tlb_current_task(void) | |
| 163 | +{ | |
| 164 | + struct mm_struct *mm = current->mm; | |
| 165 | + cpumask_t cpu_mask; | |
| 166 | + | |
| 167 | + preempt_disable(); | |
| 168 | + cpu_mask = mm->cpu_vm_mask; | |
| 169 | + cpu_clear(smp_processor_id(), cpu_mask); | |
| 170 | + | |
| 171 | + local_flush_tlb(); | |
| 172 | + if (!cpus_empty(cpu_mask)) | |
| 173 | + flush_tlb_others(cpu_mask, mm, FLUSH_ALL); | |
| 174 | + | |
| 175 | + preempt_enable(); | |
| 176 | +} | |
| 177 | + | |
| 178 | +/** | |
| 179 | + * flush_tlb_page - Invalidate TLB of page | |
| 180 | + * @vma: The VM context to invalidate the page for. | |
| 181 | + * @va: The virtual address of the page to invalidate. | |
| 182 | + */ | |
| 183 | +void flush_tlb_page(struct vm_area_struct *vma, unsigned long va) | |
| 184 | +{ | |
| 185 | + struct mm_struct *mm = vma->vm_mm; | |
| 186 | + cpumask_t cpu_mask; | |
| 187 | + | |
| 188 | + preempt_disable(); | |
| 189 | + cpu_mask = mm->cpu_vm_mask; | |
| 190 | + cpu_clear(smp_processor_id(), cpu_mask); | |
| 191 | + | |
| 192 | + local_flush_tlb_page(mm, va); | |
| 193 | + if (!cpus_empty(cpu_mask)) | |
| 194 | + flush_tlb_others(cpu_mask, mm, va); | |
| 195 | + | |
| 196 | + preempt_enable(); | |
| 197 | +} | |
| 198 | + | |
| 199 | +/** | |
| 200 | + * do_flush_tlb_all - Callback to completely invalidate a TLB | |
| 201 | + * @unused: Callback context (ignored). | |
| 202 | + */ | |
| 203 | +static void do_flush_tlb_all(void *unused) | |
| 204 | +{ | |
| 205 | + local_flush_tlb_all(); | |
| 206 | +} | |
| 207 | + | |
| 208 | +/** | |
| 209 | + * flush_tlb_all - Completely invalidate TLBs on all CPUs | |
| 210 | + */ | |
| 211 | +void flush_tlb_all(void) | |
| 212 | +{ | |
| 213 | + on_each_cpu(do_flush_tlb_all, 0, 1); | |
| 214 | +} | |
| @@ -30,4 +30,13 @@ · 29 unmodified lines | ||
| 30 | 30 | */ |
| 31 | 31 | #define MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL 4 |
| 32 | 32 | |
| 33 | +/* | |
| 34 | + * The size of range at which it becomes more economical to just flush the | |
| 35 | + * whole cache rather than trying to flush the specified range. | |
| 36 | + */ | |
| 37 | +#define MN10300_DCACHE_FLUSH_BORDER \ | |
| 38 | + +(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES) | |
| 39 | +#define MN10300_DCACHE_FLUSH_INV_BORDER \ | |
| 40 | + +(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES) | |
| 41 | + | |
| 33 | 42 | #endif /* _ASM_PROC_CACHE_H */ |
| @@ -13,6 +13,4 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | #include <unit/clock.h> |
| 15 | 15 | |
| 16 | −#define MN10300_WDCLK MN10300_IOCLK | |
| 17 | − | |
| 18 | 16 | #endif /* _ASM_PROC_CLOCK_H */ |
| @@ -0,0 +1,102 @@ | ||
| 1 | +/* MN103E010 on-board DMA controller registers | |
| 2 | + * | |
| 3 | + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#ifndef _ASM_PROC_DMACTL_REGS_H | |
| 13 | +#define _ASM_PROC_DMACTL_REGS_H | |
| 14 | + | |
| 15 | +#include <asm/cpu-regs.h> | |
| 16 | + | |
| 17 | +#ifdef __KERNEL__ | |
| 18 | + | |
| 19 | +/* DMA registers */ | |
| 20 | +#define DMxCTR(N) __SYSREG(0xd2000000 + ((N) * 0x100), u32) /* control reg */ | |
| 21 | +#define DMxCTR_BG 0x0000001f /* transfer request source */ | |
| 22 | +#define DMxCTR_BG_SOFT 0x00000000 /* - software source */ | |
| 23 | +#define DMxCTR_BG_SC0TX 0x00000002 /* - serial port 0 transmission */ | |
| 24 | +#define DMxCTR_BG_SC0RX 0x00000003 /* - serial port 0 reception */ | |
| 25 | +#define DMxCTR_BG_SC1TX 0x00000004 /* - serial port 1 transmission */ | |
| 26 | +#define DMxCTR_BG_SC1RX 0x00000005 /* - serial port 1 reception */ | |
| 27 | +#define DMxCTR_BG_SC2TX 0x00000006 /* - serial port 2 transmission */ | |
| 28 | +#define DMxCTR_BG_SC2RX 0x00000007 /* - serial port 2 reception */ | |
| 29 | +#define DMxCTR_BG_TM0UFLOW 0x00000008 /* - timer 0 underflow */ | |
| 30 | +#define DMxCTR_BG_TM1UFLOW 0x00000009 /* - timer 1 underflow */ | |
| 31 | +#define DMxCTR_BG_TM2UFLOW 0x0000000a /* - timer 2 underflow */ | |
| 32 | +#define DMxCTR_BG_TM3UFLOW 0x0000000b /* - timer 3 underflow */ | |
| 33 | +#define DMxCTR_BG_TM6ACMPCAP 0x0000000c /* - timer 6A compare/capture */ | |
| 34 | +#define DMxCTR_BG_AFE 0x0000000d /* - analogue front-end interrupt source */ | |
| 35 | +#define DMxCTR_BG_ADC 0x0000000e /* - A/D conversion end interrupt source */ | |
| 36 | +#define DMxCTR_BG_IRDA 0x0000000f /* - IrDA interrupt source */ | |
| 37 | +#define DMxCTR_BG_RTC 0x00000010 /* - RTC interrupt source */ | |
| 38 | +#define DMxCTR_BG_XIRQ0 0x00000011 /* - XIRQ0 pin interrupt source */ | |
| 39 | +#define DMxCTR_BG_XIRQ1 0x00000012 /* - XIRQ1 pin interrupt source */ | |
| 40 | +#define DMxCTR_BG_XDMR0 0x00000013 /* - external request 0 source (XDMR0 pin) */ | |
| 41 | +#define DMxCTR_BG_XDMR1 0x00000014 /* - external request 1 source (XDMR1 pin) */ | |
| 42 | +#define DMxCTR_SAM 0x000000e0 /* DMA transfer src addr mode */ | |
| 43 | +#define DMxCTR_SAM_INCR 0x00000000 /* - increment */ | |
| 44 | +#define DMxCTR_SAM_DECR 0x00000020 /* - decrement */ | |
| 45 | +#define DMxCTR_SAM_FIXED 0x00000040 /* - fixed */ | |
| 46 | +#define DMxCTR_DAM 0x00000000 /* DMA transfer dest addr mode */ | |
| 47 | +#define DMxCTR_DAM_INCR 0x00000000 /* - increment */ | |
| 48 | +#define DMxCTR_DAM_DECR 0x00000100 /* - decrement */ | |
| 49 | +#define DMxCTR_DAM_FIXED 0x00000200 /* - fixed */ | |
| 50 | +#define DMxCTR_TM 0x00001800 /* DMA transfer mode */ | |
| 51 | +#define DMxCTR_TM_BATCH 0x00000000 /* - batch transfer */ | |
| 52 | +#define DMxCTR_TM_INTERM 0x00001000 /* - intermittent transfer */ | |
| 53 | +#define DMxCTR_UT 0x00006000 /* DMA transfer unit */ | |
| 54 | +#define DMxCTR_UT_1 0x00000000 /* - 1 byte */ | |
| 55 | +#define DMxCTR_UT_2 0x00002000 /* - 2 byte */ | |
| 56 | +#define DMxCTR_UT_4 0x00004000 /* - 4 byte */ | |
| 57 | +#define DMxCTR_UT_16 0x00006000 /* - 16 byte */ | |
| 58 | +#define DMxCTR_TEN 0x00010000 /* DMA channel transfer enable */ | |
| 59 | +#define DMxCTR_RQM 0x00060000 /* external request input source mode */ | |
| 60 | +#define DMxCTR_RQM_FALLEDGE 0x00000000 /* - falling edge */ | |
| 61 | +#define DMxCTR_RQM_RISEEDGE 0x00020000 /* - rising edge */ | |
| 62 | +#define DMxCTR_RQM_LOLEVEL 0x00040000 /* - low level */ | |
| 63 | +#define DMxCTR_RQM_HILEVEL 0x00060000 /* - high level */ | |
| 64 | +#define DMxCTR_RQF 0x01000000 /* DMA transfer request flag */ | |
| 65 | +#define DMxCTR_XEND 0x80000000 /* DMA transfer end flag */ | |
| 66 | + | |
| 67 | +#define DMxSRC(N) __SYSREG(0xd2000004 + ((N) * 0x100), u32) /* control reg */ | |
| 68 | + | |
| 69 | +#define DMxDST(N) __SYSREG(0xd2000008 + ((N) * 0x100), u32) /* src addr reg */ | |
| 70 | + | |
| 71 | +#define DMxSIZ(N) __SYSREG(0xd200000c + ((N) * 0x100), u32) /* dest addr reg */ | |
| 72 | +#define DMxSIZ_CT 0x000fffff /* number of bytes to transfer */ | |
| 73 | + | |
| 74 | +#define DMxCYC(N) __SYSREG(0xd2000010 + ((N) * 0x100), u32) /* intermittent | |
| 75 | + * size reg */ | |
| 76 | +#define DMxCYC_CYC 0x000000ff /* number of interrmittent transfers -1 */ | |
| 77 | + | |
| 78 | +#define DM0IRQ 16 /* DMA channel 0 complete IRQ */ | |
| 79 | +#define DM1IRQ 17 /* DMA channel 1 complete IRQ */ | |
| 80 | +#define DM2IRQ 18 /* DMA channel 2 complete IRQ */ | |
| 81 | +#define DM3IRQ 19 /* DMA channel 3 complete IRQ */ | |
| 82 | + | |
| 83 | +#define DM0ICR GxICR(DM0IRQ) /* DMA channel 0 complete intr ctrl reg */ | |
| 84 | +#define DM1ICR GxICR(DM0IR1) /* DMA channel 1 complete intr ctrl reg */ | |
| 85 | +#define DM2ICR GxICR(DM0IR2) /* DMA channel 2 complete intr ctrl reg */ | |
| 86 | +#define DM3ICR GxICR(DM0IR3) /* DMA channel 3 complete intr ctrl reg */ | |
| 87 | + | |
| 88 | +#ifndef __ASSEMBLY__ | |
| 89 | + | |
| 90 | +struct mn10300_dmactl_regs { | |
| 91 | + u32 ctr; | |
| 92 | + const void *src; | |
| 93 | + void *dst; | |
| 94 | + u32 siz; | |
| 95 | + u32 cyc; | |
| 96 | +} __attribute__((aligned(0x100))); | |
| 97 | + | |
| 98 | +#endif /* __ASSEMBLY__ */ | |
| 99 | + | |
| 100 | +#endif /* __KERNEL__ */ | |
| 101 | + | |
| 102 | +#endif /* _ASM_PROC_DMACTL_REGS_H */ | |
| @@ -0,0 +1,29 @@ | ||
| 1 | +#ifndef _ASM_PROC_INTCTL_REGS_H | |
| 2 | +#define _ASM_PROC_INTCTL_REGS_H | |
| 3 | + | |
| 4 | +#ifndef _ASM_INTCTL_REGS_H | |
| 5 | +# error "please don't include this file directly" | |
| 6 | +#endif | |
| 7 | + | |
| 8 | +/* intr acceptance group reg */ | |
| 9 | +#define IAGR __SYSREG(0xd4000100, u16) | |
| 10 | + | |
| 11 | +/* group number register */ | |
| 12 | +#define IAGR_GN 0x00fc | |
| 13 | + | |
| 14 | +#define __GET_XIRQ_TRIGGER(X, Z) (((Z) >> ((X) * 2)) & 3) | |
| 15 | + | |
| 16 | +#define __SET_XIRQ_TRIGGER(X, Y, Z) \ | |
| 17 | +({ \ | |
| 18 | + typeof(Z) x = (Z); \ | |
| 19 | + x &= ~(3 << ((X) * 2)); \ | |
| 20 | + x |= ((Y) & 3) << ((X) * 2); \ | |
| 21 | + (Z) = x; \ | |
| 22 | +}) | |
| 23 | + | |
| 24 | +/* external pin intr spec reg */ | |
| 25 | +#define EXTMD __SYSREG(0xd4000200, u16) | |
| 26 | +#define GET_XIRQ_TRIGGER(X) __GET_XIRQ_TRIGGER(X, EXTMD) | |
| 27 | +#define SET_XIRQ_TRIGGER(X, Y) __SET_XIRQ_TRIGGER(X, Y, EXTMD) | |
| 28 | + | |
| 29 | +#endif /* _ASM_PROC_INTCTL_REGS_H */ | |
| @@ -12,7 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | #ifndef _ASM_PROC_PROC_H |
| 13 | 13 | #define _ASM_PROC_PROC_H |
| 14 | 14 | |
| 15 | −#define PROCESSOR_VENDOR_NAME "Matsushita" | |
| 15 | +#define PROCESSOR_VENDOR_NAME "Panasonic" | |
| 16 | 16 | #define PROCESSOR_MODEL_NAME "mn103e010" |
| 17 | 17 | |
| 18 | 18 | #endif /* _ASM_PROC_PROC_H */ |
| @@ -9,7 +9,9 @@ · 8 unmodified lines | ||
| 9 | 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | 10 | */ |
| 11 | 11 | #include <linux/kernel.h> |
| 12 | +#include <asm/fpu.h> | |
| 12 | 13 | #include <asm/rtc.h> |
| 14 | +#include <asm/busctl-regs.h> | |
| 13 | 15 | |
| 14 | 16 | /* |
| 15 | 17 | * initialise the on-silicon processor peripherals |
| @@ -28,6 +30,7 @@ asmlinkage void __init processor_init(void) · 12 unmodified lines | ||
| 28 | 30 | __set_intr_stub(EXCEP_DAERROR, dtlb_aerror); |
| 29 | 31 | __set_intr_stub(EXCEP_BUSERROR, raw_bus_error); |
| 30 | 32 | __set_intr_stub(EXCEP_DOUBLE_FAULT, double_fault); |
| 33 | + __set_intr_stub(EXCEP_FPU_DISABLED, fpu_disabled); | |
| 31 | 34 | __set_intr_stub(EXCEP_SYSCALL0, system_call); |
| 32 | 35 | |
| 33 | 36 | __set_intr_stub(EXCEP_NMI, nmi_handler); |
| @@ -73,3 +76,37 @@ asmlinkage void __init processor_init(void) · 39 unmodified lines | ||
| 73 | 76 | |
| 74 | 77 | calibrate_clock(); |
| 75 | 78 | } |
| 79 | + | |
| 80 | +/* | |
| 81 | + * determine the memory size and base from the memory controller regs | |
| 82 | + */ | |
| 83 | +void __init get_mem_info(unsigned long *mem_base, unsigned long *mem_size) | |
| 84 | +{ | |
| 85 | + unsigned long base, size; | |
| 86 | + | |
| 87 | + *mem_base = 0; | |
| 88 | + *mem_size = 0; | |
| 89 | + | |
| 90 | + base = SDBASE(0); | |
| 91 | + if (base & SDBASE_CE) { | |
| 92 | + size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT; | |
| 93 | + size = ~size + 1; | |
| 94 | + base &= SDBASE_CBA; | |
| 95 | + | |
| 96 | + printk(KERN_INFO "SDRAM[0]: %luMb @%08lx\n", size >> 20, base); | |
| 97 | + *mem_size += size; | |
| 98 | + *mem_base = base; | |
| 99 | + } | |
| 100 | + | |
| 101 | + base = SDBASE(1); | |
| 102 | + if (base & SDBASE_CE) { | |
| 103 | + size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT; | |
| 104 | + size = ~size + 1; | |
| 105 | + base &= SDBASE_CBA; | |
| 106 | + | |
| 107 | + printk(KERN_INFO "SDRAM[1]: %luMb @%08lx\n", size >> 20, base); | |
| 108 | + *mem_size += size; | |
| 109 | + if (*mem_base == 0) | |
| 110 | + *mem_base = base; | |
| 111 | + } | |
| 112 | +} | |
| @@ -0,0 +1,5 @@ | ||
| 1 | +# | |
| 2 | +# Makefile for the linux kernel. | |
| 3 | +# | |
| 4 | + | |
| 5 | +obj-y := proc-init.o | |
| @@ -0,0 +1,48 @@ | ||
| 1 | +/* Cache specification | |
| 2 | + * | |
| 3 | + * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * Modified by Matsushita Electric Industrial Co., Ltd. | |
| 7 | + * Modifications: | |
| 8 | + * 13-Nov-2006 MEI Add L1_CACHE_SHIFT_MAX definition. | |
| 9 | + * 29-Jul-2008 MEI Add define for MN10300_HAS_AREAPURGE_REG. | |
| 10 | + * | |
| 11 | + * This program is free software; you can redistribute it and/or | |
| 12 | + * modify it under the terms of the GNU General Public License | |
| 13 | + * as published by the Free Software Foundation; either version | |
| 14 | + * 2 of the License, or (at your option) any later version. | |
| 15 | + */ | |
| 16 | +#ifndef _ASM_PROC_CACHE_H | |
| 17 | +#define _ASM_PROC_CACHE_H | |
| 18 | + | |
| 19 | +/* | |
| 20 | + * L1 cache | |
| 21 | + */ | |
| 22 | +#define L1_CACHE_NWAYS 4 /* number of ways in caches */ | |
| 23 | +#define L1_CACHE_NENTRIES 128 /* number of entries in each way */ | |
| 24 | +#define L1_CACHE_BYTES 32 /* bytes per entry */ | |
| 25 | +#define L1_CACHE_SHIFT 5 /* shift for bytes per entry */ | |
| 26 | +#define L1_CACHE_WAYDISP 0x1000 /* distance from one way to the next */ | |
| 27 | + | |
| 28 | +#define L1_CACHE_TAG_VALID 0x00000001 /* cache tag valid bit */ | |
| 29 | +#define L1_CACHE_TAG_DIRTY 0x00000008 /* data cache tag dirty bit */ | |
| 30 | +#define L1_CACHE_TAG_ENTRY 0x00000fe0 /* cache tag entry address mask */ | |
| 31 | +#define L1_CACHE_TAG_ADDRESS 0xfffff000 /* cache tag line address mask */ | |
| 32 | + | |
| 33 | +/* | |
| 34 | + * specification of the interval between interrupt checking intervals whilst | |
| 35 | + * managing the cache with the interrupts disabled | |
| 36 | + */ | |
| 37 | +#define MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL 4 | |
| 38 | + | |
| 39 | +/* | |
| 40 | + * The size of range at which it becomes more economical to just flush the | |
| 41 | + * whole cache rather than trying to flush the specified range. | |
| 42 | + */ | |
| 43 | +#define MN10300_DCACHE_FLUSH_BORDER \ | |
| 44 | + +(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES) | |
| 45 | +#define MN10300_DCACHE_FLUSH_INV_BORDER \ | |
| 46 | + +(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES) | |
| 47 | + | |
| 48 | +#endif /* _ASM_PROC_CACHE_H */ | |
| @@ -0,0 +1,20 @@ | ||
| 1 | +/* clock.h: proc-specific clocks | |
| 2 | + * | |
| 3 | + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * Modified by Matsushita Electric Industrial Co., Ltd. | |
| 7 | + * Modifications: | |
| 8 | + * 23-Feb-2007 MEI Delete define for watchdog timer. | |
| 9 | + * | |
| 10 | + * This program is free software; you can redistribute it and/or | |
| 11 | + * modify it under the terms of the GNU General Public License | |
| 12 | + * as published by the Free Software Foundation; either version | |
| 13 | + * 2 of the License, or (at your option) any later version. | |
| 14 | + */ | |
| 15 | +#ifndef _ASM_PROC_CLOCK_H | |
| 16 | +#define _ASM_PROC_CLOCK_H | |
| 17 | + | |
| 18 | +#include <unit/clock.h> | |
| 19 | + | |
| 20 | +#endif /* _ASM_PROC_CLOCK_H */ | |
| @@ -0,0 +1,103 @@ | ||
| 1 | +/* MN2WS0050 on-board DMA controller registers | |
| 2 | + * | |
| 3 | + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * version 2 as published by the Free Software Foundation. | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#ifndef _ASM_PROC_DMACTL_REGS_H | |
| 12 | +#define _ASM_PROC_DMACTL_REGS_H | |
| 13 | + | |
| 14 | +#include <asm/cpu-regs.h> | |
| 15 | + | |
| 16 | +#ifdef __KERNEL__ | |
| 17 | + | |
| 18 | +/* DMA registers */ | |
| 19 | +#define DMxCTR(N) __SYSREG(0xd4005000+(N*0x100), u32) /* control reg */ | |
| 20 | +#define DMxCTR_BG 0x0000001f /* transfer request source */ | |
| 21 | +#define DMxCTR_BG_SOFT 0x00000000 /* - software source */ | |
| 22 | +#define DMxCTR_BG_SC0TX 0x00000002 /* - serial port 0 transmission */ | |
| 23 | +#define DMxCTR_BG_SC0RX 0x00000003 /* - serial port 0 reception */ | |
| 24 | +#define DMxCTR_BG_SC1TX 0x00000004 /* - serial port 1 transmission */ | |
| 25 | +#define DMxCTR_BG_SC1RX 0x00000005 /* - serial port 1 reception */ | |
| 26 | +#define DMxCTR_BG_SC2TX 0x00000006 /* - serial port 2 transmission */ | |
| 27 | +#define DMxCTR_BG_SC2RX 0x00000007 /* - serial port 2 reception */ | |
| 28 | +#define DMxCTR_BG_TM0UFLOW 0x00000008 /* - timer 0 underflow */ | |
| 29 | +#define DMxCTR_BG_TM1UFLOW 0x00000009 /* - timer 1 underflow */ | |
| 30 | +#define DMxCTR_BG_TM2UFLOW 0x0000000a /* - timer 2 underflow */ | |
| 31 | +#define DMxCTR_BG_TM3UFLOW 0x0000000b /* - timer 3 underflow */ | |
| 32 | +#define DMxCTR_BG_TM6ACMPCAP 0x0000000c /* - timer 6A compare/capture */ | |
| 33 | +#define DMxCTR_BG_RYBY 0x0000000d /* - NAND Flash RY/BY request source */ | |
| 34 | +#define DMxCTR_BG_RMC 0x0000000e /* - remote controller output */ | |
| 35 | +#define DMxCTR_BG_XIRQ12 0x00000011 /* - XIRQ12 pin interrupt source */ | |
| 36 | +#define DMxCTR_BG_XIRQ13 0x00000012 /* - XIRQ13 pin interrupt source */ | |
| 37 | +#define DMxCTR_BG_TCK 0x00000014 /* - tick timer underflow */ | |
| 38 | +#define DMxCTR_BG_SC4TX 0x00000019 /* - serial port4 transmission */ | |
| 39 | +#define DMxCTR_BG_SC4RX 0x0000001a /* - serial port4 reception */ | |
| 40 | +#define DMxCTR_BG_SC5TX 0x0000001b /* - serial port5 transmission */ | |
| 41 | +#define DMxCTR_BG_SC5RX 0x0000001c /* - serial port5 reception */ | |
| 42 | +#define DMxCTR_BG_SC6TX 0x0000001d /* - serial port6 transmission */ | |
| 43 | +#define DMxCTR_BG_SC6RX 0x0000001e /* - serial port6 reception */ | |
| 44 | +#define DMxCTR_BG_TMSUFLOW 0x0000001f /* - timestamp timer underflow */ | |
| 45 | +#define DMxCTR_SAM 0x00000060 /* DMA transfer src addr mode */ | |
| 46 | +#define DMxCTR_SAM_INCR 0x00000000 /* - increment */ | |
| 47 | +#define DMxCTR_SAM_DECR 0x00000020 /* - decrement */ | |
| 48 | +#define DMxCTR_SAM_FIXED 0x00000040 /* - fixed */ | |
| 49 | +#define DMxCTR_DAM 0x00000300 /* DMA transfer dest addr mode */ | |
| 50 | +#define DMxCTR_DAM_INCR 0x00000000 /* - increment */ | |
| 51 | +#define DMxCTR_DAM_DECR 0x00000100 /* - decrement */ | |
| 52 | +#define DMxCTR_DAM_FIXED 0x00000200 /* - fixed */ | |
| 53 | +#define DMxCTR_UT 0x00006000 /* DMA transfer unit */ | |
| 54 | +#define DMxCTR_UT_1 0x00000000 /* - 1 byte */ | |
| 55 | +#define DMxCTR_UT_2 0x00002000 /* - 2 byte */ | |
| 56 | +#define DMxCTR_UT_4 0x00004000 /* - 4 byte */ | |
| 57 | +#define DMxCTR_UT_16 0x00006000 /* - 16 byte */ | |
| 58 | +#define DMxCTR_RRE 0x00008000 /* DMA round robin enable */ | |
| 59 | +#define DMxCTR_TEN 0x00010000 /* DMA channel transfer enable */ | |
| 60 | +#define DMxCTR_RQM 0x00060000 /* external request input source mode */ | |
| 61 | +#define DMxCTR_RQM_FALLEDGE 0x00000000 /* - falling edge */ | |
| 62 | +#define DMxCTR_RQM_RISEEDGE 0x00020000 /* - rising edge */ | |
| 63 | +#define DMxCTR_RQM_LOLEVEL 0x00040000 /* - low level */ | |
| 64 | +#define DMxCTR_RQM_HILEVEL 0x00060000 /* - high level */ | |
| 65 | +#define DMxCTR_RQF 0x01000000 /* DMA transfer request flag */ | |
| 66 | +#define DMxCTR_PERR 0x40000000 /* DMA transfer parameter error flag */ | |
| 67 | +#define DMxCTR_XEND 0x80000000 /* DMA transfer end flag */ | |
| 68 | + | |
| 69 | +#define DMxSRC(N) __SYSREG(0xd4005004+(N*0x100), u32) /* control reg */ | |
| 70 | + | |
| 71 | +#define DMxDST(N) __SYSREG(0xd4005008+(N*0x100), u32) /* source addr reg */ | |
| 72 | + | |
| 73 | +#define DMxSIZ(N) __SYSREG(0xd400500c+(N*0x100), u32) /* dest addr reg */ | |
| 74 | +#define DMxSIZ_CT 0x000fffff /* number of bytes to transfer */ | |
| 75 | + | |
| 76 | +#define DMxCYC(N) __SYSREG(0xd4005010+(N*0x100), u32) /* intermittent size reg */ | |
| 77 | +#define DMxCYC_CYC 0x000000ff /* number of interrmittent transfers -1 */ | |
| 78 | + | |
| 79 | +#define DM0IRQ 16 /* DMA channel 0 complete IRQ */ | |
| 80 | +#define DM1IRQ 17 /* DMA channel 1 complete IRQ */ | |
| 81 | +#define DM2IRQ 18 /* DMA channel 2 complete IRQ */ | |
| 82 | +#define DM3IRQ 19 /* DMA channel 3 complete IRQ */ | |
| 83 | + | |
| 84 | +#define DM0ICR GxICR(DM0IRQ) /* DMA channel 0 complete intr ctrl reg */ | |
| 85 | +#define DM1ICR GxICR(DM0IR1) /* DMA channel 1 complete intr ctrl reg */ | |
| 86 | +#define DM2ICR GxICR(DM0IR2) /* DMA channel 2 complete intr ctrl reg */ | |
| 87 | +#define DM3ICR GxICR(DM0IR3) /* DMA channel 3 complete intr ctrl reg */ | |
| 88 | + | |
| 89 | +#ifndef __ASSEMBLY__ | |
| 90 | + | |
| 91 | +struct mn10300_dmactl_regs { | |
| 92 | + u32 ctr; | |
| 93 | + const void *src; | |
| 94 | + void *dst; | |
| 95 | + u32 siz; | |
| 96 | + u32 cyc; | |
| 97 | +} __attribute__((aligned(0x100))); | |
| 98 | + | |
| 99 | +#endif /* __ASSEMBLY__ */ | |
| 100 | + | |
| 101 | +#endif /* __KERNEL__ */ | |
| 102 | + | |
| 103 | +#endif /* _ASM_PROC_DMACTL_REGS_H */ | |
| @@ -0,0 +1,29 @@ | ||
| 1 | +#ifndef _ASM_PROC_INTCTL_REGS_H | |
| 2 | +#define _ASM_PROC_INTCTL_REGS_H | |
| 3 | + | |
| 4 | +#ifndef _ASM_INTCTL_REGS_H | |
| 5 | +# error "please don't include this file directly" | |
| 6 | +#endif | |
| 7 | + | |
| 8 | +/* intr acceptance group reg */ | |
| 9 | +#define IAGR __SYSREG(0xd4000100, u16) | |
| 10 | + | |
| 11 | +/* group number register */ | |
| 12 | +#define IAGR_GN 0x003fc | |
| 13 | + | |
| 14 | +#define __GET_XIRQ_TRIGGER(X, Z) (((Z) >> ((X) * 2)) & 3) | |
| 15 | + | |
| 16 | +#define __SET_XIRQ_TRIGGER(X, Y, Z) \ | |
| 17 | +({ \ | |
| 18 | + typeof(Z) x = (Z); \ | |
| 19 | + x &= ~(3 << ((X) * 2)); \ | |
| 20 | + x |= ((Y) & 3) << ((X) * 2); \ | |
| 21 | + (Z) = x; \ | |
| 22 | +}) | |
| 23 | + | |
| 24 | +/* external pin intr spec reg */ | |
| 25 | +#define EXTMD0 __SYSREG(0xd4000200, u32) | |
| 26 | +#define GET_XIRQ_TRIGGER(X) __GET_XIRQ_TRIGGER(X, EXTMD0) | |
| 27 | +#define SET_XIRQ_TRIGGER(X, Y) __SET_XIRQ_TRIGGER(X, Y, EXTMD0) | |
| 28 | + | |
| 29 | +#endif /* _ASM_PROC_INTCTL_REGS_H */ | |
| @@ -0,0 +1,49 @@ | ||
| 1 | +/* MN2WS0050 on-board interrupt controller registers | |
| 2 | + * | |
| 3 | + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * Modified by Matsushita Electric Industrial Co., Ltd. | |
| 7 | + * Modifications: | |
| 8 | + * 13-Nov-2006 MEI Define extended IRQ number for SMP support. | |
| 9 | + * | |
| 10 | + * This program is free software; you can redistribute it and/or | |
| 11 | + * modify it under the terms of the GNU General Public License | |
| 12 | + * as published by the Free Software Foundation; either version | |
| 13 | + * 2 of the License, or (at your option) any later version. | |
| 14 | + */ | |
| 15 | + | |
| 16 | +#ifndef _PROC_IRQ_H | |
| 17 | +#define _PROC_IRQ_H | |
| 18 | + | |
| 19 | +#ifdef __KERNEL__ | |
| 20 | + | |
| 21 | +#define GxICR_NUM_IRQS 163 | |
| 22 | +#ifdef CONFIG_SMP | |
| 23 | +#define GxICR_NUM_EXT_IRQS 197 | |
| 24 | +#endif /* CONFIG_SMP */ | |
| 25 | + | |
| 26 | +#define GxICR_NUM_XIRQS 16 | |
| 27 | + | |
| 28 | +#define XIRQ0 34 | |
| 29 | +#define XIRQ1 35 | |
| 30 | +#define XIRQ2 36 | |
| 31 | +#define XIRQ3 37 | |
| 32 | +#define XIRQ4 38 | |
| 33 | +#define XIRQ5 39 | |
| 34 | +#define XIRQ6 40 | |
| 35 | +#define XIRQ7 41 | |
| 36 | +#define XIRQ8 42 | |
| 37 | +#define XIRQ9 43 | |
| 38 | +#define XIRQ10 44 | |
| 39 | +#define XIRQ11 45 | |
| 40 | +#define XIRQ12 46 | |
| 41 | +#define XIRQ13 47 | |
| 42 | +#define XIRQ14 48 | |
| 43 | +#define XIRQ15 49 | |
| 44 | + | |
| 45 | +#define XIRQ2IRQ(num) (XIRQ0 + num) | |
| 46 | + | |
| 47 | +#endif /* __KERNEL__ */ | |
| 48 | + | |
| 49 | +#endif /* _PROC_IRQ_H */ | |
| @@ -0,0 +1,120 @@ | ||
| 1 | +/* NAND flash interface register definitions | |
| 2 | + * | |
| 3 | + * Copyright (C) 2008-2009 Panasonic Corporation | |
| 4 | + * All Rights Reserved. | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * version 2 as published by the Free Software Foundation. | |
| 9 | + * | |
| 10 | + * This program is distributed in the hope that it will be useful, | |
| 11 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | + * GNU General Public License for more details. | |
| 14 | + */ | |
| 15 | + | |
| 16 | +#ifndef _PROC_NAND_REGS_H_ | |
| 17 | +#define _PROC_NAND_REGS_H_ | |
| 18 | + | |
| 19 | +/* command register */ | |
| 20 | +#define FCOMMAND_0 __SYSREG(0xd8f00000, u8) /* fcommand[24:31] */ | |
| 21 | +#define FCOMMAND_1 __SYSREG(0xd8f00001, u8) /* fcommand[16:23] */ | |
| 22 | +#define FCOMMAND_2 __SYSREG(0xd8f00002, u8) /* fcommand[8:15] */ | |
| 23 | +#define FCOMMAND_3 __SYSREG(0xd8f00003, u8) /* fcommand[0:7] */ | |
| 24 | + | |
| 25 | +/* for dma 16 byte trans, use FCOMMAND2 register */ | |
| 26 | +#define FCOMMAND2_0 __SYSREG(0xd8f00110, u8) /* fcommand2[24:31] */ | |
| 27 | +#define FCOMMAND2_1 __SYSREG(0xd8f00111, u8) /* fcommand2[16:23] */ | |
| 28 | +#define FCOMMAND2_2 __SYSREG(0xd8f00112, u8) /* fcommand2[8:15] */ | |
| 29 | +#define FCOMMAND2_3 __SYSREG(0xd8f00113, u8) /* fcommand2[0:7] */ | |
| 30 | + | |
| 31 | +#define FCOMMAND_FIEN 0x80 /* nand flash I/F enable */ | |
| 32 | +#define FCOMMAND_BW_8BIT 0x00 /* 8bit bus width */ | |
| 33 | +#define FCOMMAND_BW_16BIT 0x40 /* 16bit bus width */ | |
| 34 | +#define FCOMMAND_BLOCKSZ_SMALL 0x00 /* small block */ | |
| 35 | +#define FCOMMAND_BLOCKSZ_LARGE 0x20 /* large block */ | |
| 36 | +#define FCOMMAND_DMASTART 0x10 /* dma start */ | |
| 37 | +#define FCOMMAND_RYBY 0x08 /* ready/busy flag */ | |
| 38 | +#define FCOMMAND_RYBYINTMSK 0x04 /* mask ready/busy interrupt */ | |
| 39 | +#define FCOMMAND_XFWP 0x02 /* write protect enable */ | |
| 40 | +#define FCOMMAND_XFCE 0x01 /* flash device disable */ | |
| 41 | +#define FCOMMAND_SEQKILL 0x10 /* stop seq-read */ | |
| 42 | +#define FCOMMAND_ANUM 0x07 /* address cycle */ | |
| 43 | +#define FCOMMAND_ANUM_NONE 0x00 /* address cycle none */ | |
| 44 | +#define FCOMMAND_ANUM_1CYC 0x01 /* address cycle 1cycle */ | |
| 45 | +#define FCOMMAND_ANUM_2CYC 0x02 /* address cycle 2cycle */ | |
| 46 | +#define FCOMMAND_ANUM_3CYC 0x03 /* address cycle 3cycle */ | |
| 47 | +#define FCOMMAND_ANUM_4CYC 0x04 /* address cycle 4cycle */ | |
| 48 | +#define FCOMMAND_ANUM_5CYC 0x05 /* address cycle 5cycle */ | |
| 49 | +#define FCOMMAND_FCMD_READ0 0x00 /* read1 command */ | |
| 50 | +#define FCOMMAND_FCMD_SEQIN 0x80 /* page program 1st command */ | |
| 51 | +#define FCOMMAND_FCMD_PAGEPROG 0x10 /* page program 2nd command */ | |
| 52 | +#define FCOMMAND_FCMD_RESET 0xff /* reset command */ | |
| 53 | +#define FCOMMAND_FCMD_ERASE1 0x60 /* erase 1st command */ | |
| 54 | +#define FCOMMAND_FCMD_ERASE2 0xd0 /* erase 2nd command */ | |
| 55 | +#define FCOMMAND_FCMD_STATUS 0x70 /* read status command */ | |
| 56 | +#define FCOMMAND_FCMD_READID 0x90 /* read id command */ | |
| 57 | +#define FCOMMAND_FCMD_READOOB 0x50 /* read3 command */ | |
| 58 | +/* address register */ | |
| 59 | +#define FADD __SYSREG(0xd8f00004, u32) | |
| 60 | +/* address register 2 */ | |
| 61 | +#define FADD2 __SYSREG(0xd8f00008, u32) | |
| 62 | +/* error judgement register */ | |
| 63 | +#define FJUDGE __SYSREG(0xd8f0000c, u32) | |
| 64 | +#define FJUDGE_NOERR 0x0 /* no error */ | |
| 65 | +#define FJUDGE_1BITERR 0x1 /* 1bit error in data area */ | |
| 66 | +#define FJUDGE_PARITYERR 0x2 /* parity error */ | |
| 67 | +#define FJUDGE_UNCORRECTABLE 0x3 /* uncorrectable error */ | |
| 68 | +#define FJUDGE_ERRJDG_MSK 0x3 /* mask of judgement result */ | |
| 69 | +/* 1st ECC store register */ | |
| 70 | +#define FECC11 __SYSREG(0xd8f00010, u32) | |
| 71 | +/* 2nd ECC store register */ | |
| 72 | +#define FECC12 __SYSREG(0xd8f00014, u32) | |
| 73 | +/* 3rd ECC store register */ | |
| 74 | +#define FECC21 __SYSREG(0xd8f00018, u32) | |
| 75 | +/* 4th ECC store register */ | |
| 76 | +#define FECC22 __SYSREG(0xd8f0001c, u32) | |
| 77 | +/* 5th ECC store register */ | |
| 78 | +#define FECC31 __SYSREG(0xd8f00020, u32) | |
| 79 | +/* 6th ECC store register */ | |
| 80 | +#define FECC32 __SYSREG(0xd8f00024, u32) | |
| 81 | +/* 7th ECC store register */ | |
| 82 | +#define FECC41 __SYSREG(0xd8f00028, u32) | |
| 83 | +/* 8th ECC store register */ | |
| 84 | +#define FECC42 __SYSREG(0xd8f0002c, u32) | |
| 85 | +/* data register */ | |
| 86 | +#define FDATA __SYSREG(0xd8f00030, u32) | |
| 87 | +/* access pulse register */ | |
| 88 | +#define FPWS __SYSREG(0xd8f00100, u32) | |
| 89 | +#define FPWS_PWS1W_2CLK 0x00000000 /* write pulse width 1clock */ | |
| 90 | +#define FPWS_PWS1W_3CLK 0x01000000 /* write pulse width 2clock */ | |
| 91 | +#define FPWS_PWS1W_4CLK 0x02000000 /* write pulse width 4clock */ | |
| 92 | +#define FPWS_PWS1W_5CLK 0x03000000 /* write pulse width 5clock */ | |
| 93 | +#define FPWS_PWS1W_6CLK 0x04000000 /* write pulse width 6clock */ | |
| 94 | +#define FPWS_PWS1W_7CLK 0x05000000 /* write pulse width 7clock */ | |
| 95 | +#define FPWS_PWS1W_8CLK 0x06000000 /* write pulse width 8clock */ | |
| 96 | +#define FPWS_PWS1R_3CLK 0x00010000 /* read pulse width 3clock */ | |
| 97 | +#define FPWS_PWS1R_4CLK 0x00020000 /* read pulse width 4clock */ | |
| 98 | +#define FPWS_PWS1R_5CLK 0x00030000 /* read pulse width 5clock */ | |
| 99 | +#define FPWS_PWS1R_6CLK 0x00040000 /* read pulse width 6clock */ | |
| 100 | +#define FPWS_PWS1R_7CLK 0x00050000 /* read pulse width 7clock */ | |
| 101 | +#define FPWS_PWS1R_8CLK 0x00060000 /* read pulse width 8clock */ | |
| 102 | +#define FPWS_PWS2W_2CLK 0x00000100 /* write pulse interval 2clock */ | |
| 103 | +#define FPWS_PWS2W_3CLK 0x00000200 /* write pulse interval 3clock */ | |
| 104 | +#define FPWS_PWS2W_4CLK 0x00000300 /* write pulse interval 4clock */ | |
| 105 | +#define FPWS_PWS2W_5CLK 0x00000400 /* write pulse interval 5clock */ | |
| 106 | +#define FPWS_PWS2W_6CLK 0x00000500 /* write pulse interval 6clock */ | |
| 107 | +#define FPWS_PWS2R_2CLK 0x00000001 /* read pulse interval 2clock */ | |
| 108 | +#define FPWS_PWS2R_3CLK 0x00000002 /* read pulse interval 3clock */ | |
| 109 | +#define FPWS_PWS2R_4CLK 0x00000003 /* read pulse interval 4clock */ | |
| 110 | +#define FPWS_PWS2R_5CLK 0x00000004 /* read pulse interval 5clock */ | |
| 111 | +#define FPWS_PWS2R_6CLK 0x00000005 /* read pulse interval 6clock */ | |
| 112 | +/* command register 2 */ | |
| 113 | +#define FCOMMAND2 __SYSREG(0xd8f00110, u32) | |
| 114 | +/* transfer frequency register */ | |
| 115 | +#define FNUM __SYSREG(0xd8f00114, u32) | |
| 116 | +#define FSDATA_ADDR 0xd8f00400 | |
| 117 | +/* active data register */ | |
| 118 | +#define FSDATA __SYSREG(FSDATA_ADDR, u32) | |
| 119 | + | |
| 120 | +#endif /* _PROC_NAND_REGS_H_ */ | |
| @@ -0,0 +1,18 @@ | ||
| 1 | +/* proc.h: MN2WS0050 processor description | |
| 2 | + * | |
| 3 | + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the License, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#ifndef _ASM_PROC_PROC_H | |
| 13 | +#define _ASM_PROC_PROC_H | |
| 14 | + | |
| 15 | +#define PROCESSOR_VENDOR_NAME "Panasonic" | |
| 16 | +#define PROCESSOR_MODEL_NAME "mn2ws0050" | |
| 17 | + | |
| 18 | +#endif /* _ASM_PROC_PROC_H */ | |
| @@ -0,0 +1,51 @@ | ||
| 1 | +/* MN10300/AM33v2 Microcontroller SMP registers | |
| 2 | + * | |
| 3 | + * Copyright (C) 2006 Matsushita Electric Industrial Co., Ltd. | |
| 4 | + * All Rights Reserved. | |
| 5 | + * Created: | |
| 6 | + * 13-Nov-2006 MEI Add extended cache and atomic operation register | |
| 7 | + * for SMP support. | |
| 8 | + * 23-Feb-2007 MEI Add define for gdbstub SMP. | |
| 9 | + * | |
| 10 | + * This program is free software; you can redistribute it and/or | |
| 11 | + * modify it under the terms of the GNU General Public License | |
| 12 | + * as published by the Free Software Foundation; either version | |
| 13 | + * 2 of the License, or (at your option) any later version. | |
| 14 | + */ | |
| 15 | + | |
| 16 | +#ifndef _ASM_PROC_SMP_REGS_H | |
| 17 | +#define _ASM_PROC_SMP_REGS_H | |
| 18 | + | |
| 19 | +#ifdef __KERNEL__ | |
| 20 | + | |
| 21 | +#ifndef __ASSEMBLY__ | |
| 22 | +#include <linux/types.h> | |
| 23 | +#endif | |
| 24 | +#include <asm/cpu-regs.h> | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * Reference to the interrupt controllers of other CPUs | |
| 28 | + */ | |
| 29 | +#define CROSS_ICR_CPU_SHIFT 16 | |
| 30 | + | |
| 31 | +#define CROSS_GxICR(X, CPU) __SYSREG(0xc4000000 + (X) * 4 + \ | |
| 32 | + ((X) >= 64 && (X) < 192) * 0xf00 + ((CPU) << CROSS_ICR_CPU_SHIFT), u16) | |
| 33 | +#define CROSS_GxICR_u8(X, CPU) __SYSREG(0xc4000000 + (X) * 4 + \ | |
| 34 | + (((X) >= 64) && ((X) < 192)) * 0xf00 + ((CPU) << CROSS_ICR_CPU_SHIFT), u8) | |
| 35 | + | |
| 36 | +/* CPU ID register */ | |
| 37 | +#define CPUID __SYSREGC(0xc0000054, u32) | |
| 38 | +#define CPUID_MASK 0x00000007 /* CPU ID mask */ | |
| 39 | + | |
| 40 | +/* extended cache control register */ | |
| 41 | +#define ECHCTR __SYSREG(0xc0000c20, u32) | |
| 42 | +#define ECHCTR_IBCM 0x00000001 /* instruction cache broad cast mask */ | |
| 43 | +#define ECHCTR_DBCM 0x00000002 /* data cache broad cast mask */ | |
| 44 | +#define ECHCTR_ISPM 0x00000004 /* instruction cache snoop mask */ | |
| 45 | +#define ECHCTR_DSPM 0x00000008 /* data cache snoop mask */ | |
| 46 | + | |
| 47 | +#define NMIAGR __SYSREG(0xd400013c, u16) | |
| 48 | +#define NMIAGR_GN 0x03fc | |
| 49 | + | |
| 50 | +#endif /* __KERNEL__ */ | |
| 51 | +#endif /* _ASM_PROC_SMP_REGS_H */ | |
| @@ -0,0 +1,134 @@ | ||
| 1 | +/* MN2WS0050 processor initialisation | |
| 2 | + * | |
| 3 | + * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the License, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#include <linux/sched.h> | |
| 12 | +#include <linux/kernel.h> | |
| 13 | +#include <linux/init.h> | |
| 14 | +#include <linux/delay.h> | |
| 15 | +#include <linux/interrupt.h> | |
| 16 | + | |
| 17 | +#include <asm/processor.h> | |
| 18 | +#include <asm/system.h> | |
| 19 | +#include <asm/uaccess.h> | |
| 20 | +#include <asm/io.h> | |
| 21 | +#include <asm/atomic.h> | |
| 22 | +#include <asm/smp.h> | |
| 23 | +#include <asm/pgalloc.h> | |
| 24 | +#include <asm/busctl-regs.h> | |
| 25 | +#include <unit/timex.h> | |
| 26 | +#include <asm/fpu.h> | |
| 27 | +#include <asm/rtc.h> | |
| 28 | + | |
| 29 | +#define MEMCONF __SYSREGC(0xdf800400, u32) | |
| 30 | + | |
| 31 | +/* | |
| 32 | + * initialise the on-silicon processor peripherals | |
| 33 | + */ | |
| 34 | +asmlinkage void __init processor_init(void) | |
| 35 | +{ | |
| 36 | + int loop; | |
| 37 | + | |
| 38 | + /* set up the exception table first */ | |
| 39 | + for (loop = 0x000; loop < 0x400; loop += 8) | |
| 40 | + __set_intr_stub(loop, __common_exception); | |
| 41 | + | |
| 42 | + __set_intr_stub(EXCEP_ITLBMISS, itlb_miss); | |
| 43 | + __set_intr_stub(EXCEP_DTLBMISS, dtlb_miss); | |
| 44 | + __set_intr_stub(EXCEP_IAERROR, itlb_aerror); | |
| 45 | + __set_intr_stub(EXCEP_DAERROR, dtlb_aerror); | |
| 46 | + __set_intr_stub(EXCEP_BUSERROR, raw_bus_error); | |
| 47 | + __set_intr_stub(EXCEP_DOUBLE_FAULT, double_fault); | |
| 48 | + __set_intr_stub(EXCEP_FPU_DISABLED, fpu_disabled); | |
| 49 | + __set_intr_stub(EXCEP_SYSCALL0, system_call); | |
| 50 | + | |
| 51 | + __set_intr_stub(EXCEP_NMI, nmi_handler); | |
| 52 | + __set_intr_stub(EXCEP_WDT, nmi_handler); | |
| 53 | + __set_intr_stub(EXCEP_IRQ_LEVEL0, irq_handler); | |
| 54 | + __set_intr_stub(EXCEP_IRQ_LEVEL1, irq_handler); | |
| 55 | + __set_intr_stub(EXCEP_IRQ_LEVEL2, irq_handler); | |
| 56 | + __set_intr_stub(EXCEP_IRQ_LEVEL3, irq_handler); | |
| 57 | + __set_intr_stub(EXCEP_IRQ_LEVEL4, irq_handler); | |
| 58 | + __set_intr_stub(EXCEP_IRQ_LEVEL5, irq_handler); | |
| 59 | + __set_intr_stub(EXCEP_IRQ_LEVEL6, irq_handler); | |
| 60 | + | |
| 61 | + IVAR0 = EXCEP_IRQ_LEVEL0; | |
| 62 | + IVAR1 = EXCEP_IRQ_LEVEL1; | |
| 63 | + IVAR2 = EXCEP_IRQ_LEVEL2; | |
| 64 | + IVAR3 = EXCEP_IRQ_LEVEL3; | |
| 65 | + IVAR4 = EXCEP_IRQ_LEVEL4; | |
| 66 | + IVAR5 = EXCEP_IRQ_LEVEL5; | |
| 67 | + IVAR6 = EXCEP_IRQ_LEVEL6; | |
| 68 | + | |
| 69 | +#ifndef CONFIG_MN10300_HAS_CACHE_SNOOP | |
| 70 | + mn10300_dcache_flush_inv(); | |
| 71 | + mn10300_icache_inv(); | |
| 72 | +#endif | |
| 73 | + | |
| 74 | + /* disable all interrupts and set to priority 6 (lowest) */ | |
| 75 | +#ifdef CONFIG_SMP | |
| 76 | + for (loop = 0; loop < GxICR_NUM_IRQS; loop++) | |
| 77 | + GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT; | |
| 78 | +#else /* !CONFIG_SMP */ | |
| 79 | + for (loop = 0; loop < NR_IRQS; loop++) | |
| 80 | + GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT; | |
| 81 | +#endif /* !CONFIG_SMP */ | |
| 82 | + | |
| 83 | + /* clear the timers */ | |
| 84 | + TM0MD = 0; | |
| 85 | + TM1MD = 0; | |
| 86 | + TM2MD = 0; | |
| 87 | + TM3MD = 0; | |
| 88 | + TM4MD = 0; | |
| 89 | + TM5MD = 0; | |
| 90 | + TM6MD = 0; | |
| 91 | + TM6MDA = 0; | |
| 92 | + TM6MDB = 0; | |
| 93 | + TM7MD = 0; | |
| 94 | + TM8MD = 0; | |
| 95 | + TM9MD = 0; | |
| 96 | + TM10MD = 0; | |
| 97 | + TM11MD = 0; | |
| 98 | + TM12MD = 0; | |
| 99 | + TM13MD = 0; | |
| 100 | + TM14MD = 0; | |
| 101 | + TM15MD = 0; | |
| 102 | + | |
| 103 | + calibrate_clock(); | |
| 104 | +} | |
| 105 | + | |
| 106 | +/* | |
| 107 | + * determine the memory size and base from the memory controller regs | |
| 108 | + */ | |
| 109 | +void __init get_mem_info(unsigned long *mem_base, unsigned long *mem_size) | |
| 110 | +{ | |
| 111 | + unsigned long memconf = MEMCONF; | |
| 112 | + unsigned long size = 0; /* order: MByte */ | |
| 113 | + | |
| 114 | + *mem_base = 0x90000000; /* fixed address */ | |
| 115 | + | |
| 116 | + switch (memconf & 0x00000003) { | |
| 117 | + case 0x01: | |
| 118 | + size = 256 / 8; /* 256 Mbit per chip */ | |
| 119 | + break; | |
| 120 | + case 0x02: | |
| 121 | + size = 512 / 8; /* 512 Mbit per chip */ | |
| 122 | + break; | |
| 123 | + case 0x03: | |
| 124 | + size = 1024 / 8; /* 1 Gbit per chip */ | |
| 125 | + break; | |
| 126 | + default: | |
| 127 | + panic("Invalid SDRAM size"); | |
| 128 | + break; | |
| 129 | + } | |
| 130 | + | |
| 131 | + printk(KERN_INFO "DDR2-SDRAM: %luMB x 2 @%08lx\n", size, *mem_base); | |
| 132 | + | |
| 133 | + *mem_size = (size * 2) << 20; | |
| 134 | +} | |
| @@ -14,32 +14,11 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | #ifndef __ASSEMBLY__ |
| 16 | 16 | |
| 17 | −#ifdef CONFIG_MN10300_RTC | |
| 18 | − | |
| 19 | −extern unsigned long mn10300_ioclk; /* IOCLK (crystal speed) in HZ */ | |
| 20 | −extern unsigned long mn10300_iobclk; | |
| 21 | −extern unsigned long mn10300_tsc_per_HZ; | |
| 22 | − | |
| 23 | −#define MN10300_IOCLK mn10300_ioclk | |
| 24 | −/* If this processors has a another clock, uncomment the below. */ | |
| 25 | −/* #define MN10300_IOBCLK mn10300_iobclk */ | |
| 26 | − | |
| 27 | −#else /* !CONFIG_MN10300_RTC */ | |
| 28 | − | |
| 29 | 17 | #define MN10300_IOCLK 33333333UL |
| 30 | 18 | /* #define MN10300_IOBCLK 66666666UL */ |
| 31 | 19 | |
| 32 | −#endif /* !CONFIG_MN10300_RTC */ | |
| 33 | − | |
| 34 | −#define MN10300_JCCLK MN10300_IOCLK | |
| 35 | −#define MN10300_TSCCLK MN10300_IOCLK | |
| 36 | − | |
| 37 | −#ifdef CONFIG_MN10300_RTC | |
| 38 | −#define MN10300_TSC_PER_HZ mn10300_tsc_per_HZ | |
| 39 | −#else /* !CONFIG_MN10300_RTC */ | |
| 40 | −#define MN10300_TSC_PER_HZ (MN10300_TSCCLK/HZ) | |
| 41 | −#endif /* !CONFIG_MN10300_RTC */ | |
| 42 | − | |
| 43 | 20 | #endif /* !__ASSEMBLY__ */ |
| 44 | 21 | |
| 22 | +#define MN10300_WDCLK MN10300_IOCLK | |
| 23 | + | |
| 45 | 24 | #endif /* _ASM_UNIT_CLOCK_H */ |
| @@ -21,6 +21,11 @@ · 20 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | #define SERIAL_IRQ XIRQ0 /* Dual serial (PC16552) (Hi) */ |
| 23 | 23 | |
| 24 | +/* | |
| 25 | + * The ASB2303 has an 18.432 MHz clock the UART | |
| 26 | + */ | |
| 27 | +#define BASE_BAUD (18432000 / 16) | |
| 28 | + | |
| 24 | 29 | /* |
| 25 | 30 | * dispose of the /dev/ttyS0 and /dev/ttyS1 serial ports |
| 26 | 31 | */ |
| @@ -1,6 +1,6 @@ | ||
| 1 | −/* ASB2303-specific timer specifcations | |
| 1 | +/* ASB2303-specific timer specifications | |
| 2 | 2 | * |
| 3 | − * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 3 | + * Copyright (C) 2007, 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | 5 | * |
| 6 | 6 | * This program is free software; you can redistribute it and/or |
| @@ -17,67 +17,72 @@ · 10 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | #include <asm/timer-regs.h> |
| 19 | 19 | #include <unit/clock.h> |
| 20 | +#include <asm/param.h> | |
| 20 | 21 | |
| 21 | 22 | /* |
| 22 | 23 | * jiffies counter specifications |
| 23 | 24 | */ |
| 24 | 25 | |
| 25 | 26 | #define TMJCBR_MAX 0xffff |
| 26 | −#define TMJCBC TM01BC | |
| 27 | − | |
| 28 | −#define TMJCMD TM01MD | |
| 29 | −#define TMJCBR TM01BR | |
| 30 | 27 | #define TMJCIRQ TM1IRQ |
| 31 | 28 | #define TMJCICR TM1ICR |
| 32 | −#define TMJCICR_LEVEL GxICR_LEVEL_5 | |
| 33 | 29 | |
| 34 | 30 | #ifndef __ASSEMBLY__ |
| 35 | 31 | |
| 36 | −static inline void startup_jiffies_counter(void) | |
| 32 | +#define MN10300_SRC_IOCLK MN10300_IOCLK | |
| 33 | + | |
| 34 | +#ifndef HZ | |
| 35 | +# error HZ undeclared. | |
| 36 | +#endif /* !HZ */ | |
| 37 | +/* use as little prescaling as possible to avoid losing accuracy */ | |
| 38 | +#if (MN10300_SRC_IOCLK + HZ / 2) / HZ - 1 <= TMJCBR_MAX | |
| 39 | +# define IOCLK_PRESCALE 1 | |
| 40 | +# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK | |
| 41 | +# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK | |
| 42 | +#elif (MN10300_SRC_IOCLK / 8 + HZ / 2) / HZ - 1 <= TMJCBR_MAX | |
| 43 | +# define IOCLK_PRESCALE 8 | |
| 44 | +# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK_8 | |
| 45 | +# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK_8 | |
| 46 | +#elif (MN10300_SRC_IOCLK / 32 + HZ / 2) / HZ - 1 <= TMJCBR_MAX | |
| 47 | +# define IOCLK_PRESCALE 32 | |
| 48 | +# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK_32 | |
| 49 | +# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK_32 | |
| 50 | +#else | |
| 51 | +# error You lose. | |
| 52 | +#endif | |
| 53 | + | |
| 54 | +#define MN10300_JCCLK (MN10300_SRC_IOCLK / IOCLK_PRESCALE) | |
| 55 | +#define MN10300_TSCCLK (MN10300_SRC_IOCLK / IOCLK_PRESCALE) | |
| 56 | + | |
| 57 | +#define MN10300_JC_PER_HZ ((MN10300_JCCLK + HZ / 2) / HZ) | |
| 58 | +#define MN10300_TSC_PER_HZ ((MN10300_TSCCLK + HZ / 2) / HZ) | |
| 59 | + | |
| 60 | +static inline void stop_jiffies_counter(void) | |
| 37 | 61 | { |
| 38 | − unsigned rate; | |
| 39 | − u16 md, t16; | |
| 40 | − | |
| 41 | − /* use as little prescaling as possible to avoid losing accuracy */ | |
| 42 | − md = TM0MD_SRC_IOCLK; | |
| 43 | − rate = MN10300_JCCLK / HZ; | |
| 44 | − | |
| 45 | − if (rate > TMJCBR_MAX) { | |
| 46 | − md = TM0MD_SRC_IOCLK_8; | |
| 47 | − rate = MN10300_JCCLK / 8 / HZ; | |
| 48 | − | |
| 49 | − if (rate > TMJCBR_MAX) { | |
| 50 | − md = TM0MD_SRC_IOCLK_32; | |
| 51 | − rate = MN10300_JCCLK / 32 / HZ; | |
| 52 | − | |
| 53 | − if (rate > TMJCBR_MAX) | |
| 54 | − BUG(); | |
| 55 | − } | |
| 56 | − } | |
| 62 | + u16 tmp; | |
| 63 | + TM01MD = JC_TIMER_CLKSRC | TM1MD_SRC_TM0CASCADE << 8; | |
| 64 | + tmp = TM01MD; | |
| 65 | +} | |
| 57 | 66 | |
| 58 | − TMJCBR = rate - 1; | |
| 59 | − t16 = TMJCBR; | |
| 67 | +static inline void reload_jiffies_counter(u32 cnt) | |
| 68 | +{ | |
| 69 | + u32 tmp; | |
| 60 | 70 | |
| 61 | − TMJCMD = | |
| 62 | − md | | |
| 63 | − TM1MD_SRC_TM0CASCADE << 8 | | |
| 64 | − TM0MD_INIT_COUNTER | | |
| 65 | − TM1MD_INIT_COUNTER << 8; | |
| 71 | + TM01BR = cnt; | |
| 72 | + tmp = TM01BR; | |
| 66 | 73 | |
| 67 | − TMJCMD = | |
| 68 | − md | | |
| 69 | − TM1MD_SRC_TM0CASCADE << 8 | | |
| 70 | − TM0MD_COUNT_ENABLE | | |
| 71 | − TM1MD_COUNT_ENABLE << 8; | |
| 74 | + TM01MD = JC_TIMER_CLKSRC | \ | |
| 75 | + TM1MD_SRC_TM0CASCADE << 8 | \ | |
| 76 | + TM0MD_INIT_COUNTER | \ | |
| 77 | + TM1MD_INIT_COUNTER << 8; | |
| 72 | 78 | |
| 73 | − t16 = TMJCMD; | |
| 74 | 79 | |
| 75 | − TMJCICR |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST; | |
| 76 | − t16 = TMJCICR; | |
| 77 | −} | |
| 80 | + TM01MD = JC_TIMER_CLKSRC | \ | |
| 81 | + TM1MD_SRC_TM0CASCADE << 8 | \ | |
| 82 | + TM0MD_COUNT_ENABLE | \ | |
| 83 | + TM1MD_COUNT_ENABLE << 8; | |
| 78 | 84 | |
| 79 | −static inline void shutdown_jiffies_counter(void) | |
| 80 | −{ | |
| 85 | + tmp = TM01MD; | |
| 81 | 86 | } |
| 82 | 87 | |
| 83 | 88 | #endif /* !__ASSEMBLY__ */ |
| @@ -94,29 +99,39 @@ static inline void shutdown_jiffies_counter(void) · 10 unmodified lines | ||
| 94 | 99 | |
| 95 | 100 | static inline void startup_timestamp_counter(void) |
| 96 | 101 | { |
| 102 | + u32 t32; | |
| 103 | + | |
| 97 | 104 | /* set up timer 4 & 5 cascaded as a 32-bit counter to count real time |
| 98 | 105 | * - count down from 4Gig-1 to 0 and wrap at IOCLK rate |
| 99 | 106 | */ |
| 100 | 107 | TM45BR = TMTSCBR_MAX; |
| 108 | + t32 = TM45BR; | |
| 101 | 109 | |
| 102 | − TM4MD = TM4MD_SRC_IOCLK; | |
| 110 | + TM4MD = TSC_TIMER_CLKSRC; | |
| 103 | 111 | TM4MD |= TM4MD_INIT_COUNTER; |
| 104 | 112 | TM4MD &= ~TM4MD_INIT_COUNTER; |
| 105 | 113 | TM4ICR = 0; |
| 114 | + t32 = TM4ICR; | |
| 106 | 115 | |
| 107 | 116 | TM5MD = TM5MD_SRC_TM4CASCADE; |
| 108 | 117 | TM5MD |= TM5MD_INIT_COUNTER; |
| 109 | 118 | TM5MD &= ~TM5MD_INIT_COUNTER; |
| 110 | 119 | TM5ICR = 0; |
| 120 | + t32 = TM5ICR; | |
| 111 | 121 | |
| 112 | 122 | TM5MD |= TM5MD_COUNT_ENABLE; |
| 113 | 123 | TM4MD |= TM4MD_COUNT_ENABLE; |
| 124 | + t32 = TM5MD; | |
| 125 | + t32 = TM4MD; | |
| 114 | 126 | } |
| 115 | 127 | |
| 116 | 128 | static inline void shutdown_timestamp_counter(void) |
| 117 | 129 | { |
| 130 | + u8 t8; | |
| 118 | 131 | TM4MD = 0; |
| 119 | 132 | TM5MD = 0; |
| 133 | + t8 = TM4MD; | |
| 134 | + t8 = TM5MD; | |
| 120 | 135 | } |
| 121 | 136 | |
| 122 | 137 | /* |
| @@ -127,7 +142,7 @@ typedef unsigned long cycles_t; · 4 unmodified lines | ||
| 127 | 142 | |
| 128 | 143 | static inline cycles_t read_timestamp_counter(void) |
| 129 | 144 | { |
| 130 | − return (cycles_t)TMTSCBC; | |
| 145 | + return (cycles_t)~TMTSCBC; | |
| 131 | 146 | } |
| 132 | 147 | |
| 133 | 148 | #endif /* !__ASSEMBLY__ */ |
| @@ -31,6 +31,14 @@ asmlinkage void __init unit_init(void) · 30 unmodified lines | ||
| 31 | 31 | SET_XIRQ_TRIGGER(3, XIRQ_TRIGGER_HILEVEL); |
| 32 | 32 | SET_XIRQ_TRIGGER(4, XIRQ_TRIGGER_LOWLEVEL); |
| 33 | 33 | SET_XIRQ_TRIGGER(5, XIRQ_TRIGGER_LOWLEVEL); |
| 34 | + | |
| 35 | +#ifdef CONFIG_EXT_SERIAL_IRQ_LEVEL | |
| 36 | + set_intr_level(XIRQ0, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL)); | |
| 37 | +#endif | |
| 38 | + | |
| 39 | +#ifdef CONFIG_ETHERNET_IRQ_LEVEL | |
| 40 | + set_intr_level(XIRQ3, NUM2GxICR_LEVEL(CONFIG_ETHERNET_IRQ_LEVEL)); | |
| 41 | +#endif | |
| 34 | 42 | } |
| 35 | 43 | |
| 36 | 44 | /* |
| @@ -51,7 +59,7 @@ void __init unit_init_IRQ(void) · 14 unmodified lines | ||
| 51 | 59 | switch (GET_XIRQ_TRIGGER(extnum)) { |
| 52 | 60 | case XIRQ_TRIGGER_HILEVEL: |
| 53 | 61 | case XIRQ_TRIGGER_LOWLEVEL: |
| 54 | − set_intr_postackable(XIRQ2IRQ(extnum)); | |
| 62 | + mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum)); | |
| 55 | 63 | break; |
| 56 | 64 | default: |
| 57 | 65 | break; |
| @@ -14,32 +14,11 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | #ifndef __ASSEMBLY__ |
| 16 | 16 | |
| 17 | −#ifdef CONFIG_MN10300_RTC | |
| 18 | − | |
| 19 | −extern unsigned long mn10300_ioclk; /* IOCLK (crystal speed) in HZ */ | |
| 20 | −extern unsigned long mn10300_iobclk; | |
| 21 | −extern unsigned long mn10300_tsc_per_HZ; | |
| 22 | − | |
| 23 | −#define MN10300_IOCLK mn10300_ioclk | |
| 24 | −/* If this processors has a another clock, uncomment the below. */ | |
| 25 | −/* #define MN10300_IOBCLK mn10300_iobclk */ | |
| 26 | − | |
| 27 | −#else /* !CONFIG_MN10300_RTC */ | |
| 28 | − | |
| 29 | 17 | #define MN10300_IOCLK 33333333UL |
| 30 | 18 | /* #define MN10300_IOBCLK 66666666UL */ |
| 31 | 19 | |
| 32 | −#endif /* !CONFIG_MN10300_RTC */ | |
| 33 | − | |
| 34 | −#define MN10300_JCCLK MN10300_IOCLK | |
| 35 | −#define MN10300_TSCCLK MN10300_IOCLK | |
| 36 | − | |
| 37 | −#ifdef CONFIG_MN10300_RTC | |
| 38 | −#define MN10300_TSC_PER_HZ mn10300_tsc_per_HZ | |
| 39 | −#else /* !CONFIG_MN10300_RTC */ | |
| 40 | −#define MN10300_TSC_PER_HZ (MN10300_TSCCLK/HZ) | |
| 41 | −#endif /* !CONFIG_MN10300_RTC */ | |
| 42 | − | |
| 43 | 20 | #endif /* !__ASSEMBLY__ */ |
| 44 | 21 | |
| 22 | +#define MN10300_WDCLK MN10300_IOCLK | |
| 23 | + | |
| 45 | 24 | #endif /* _ASM_UNIT_CLOCK_H */ |
| @@ -20,6 +20,11 @@ · 19 unmodified lines | ||
| 20 | 20 | |
| 21 | 21 | #define SERIAL_IRQ XIRQ0 /* Dual serial (PC16552) (Hi) */ |
| 22 | 22 | |
| 23 | +/* | |
| 24 | + * The ASB2305 has an 18.432 MHz clock the UART | |
| 25 | + */ | |
| 26 | +#define BASE_BAUD (18432000 / 16) | |
| 27 | + | |
| 23 | 28 | /* |
| 24 | 29 | * dispose of the /dev/ttyS0 serial port |
| 25 | 30 | */ |
| @@ -1,6 +1,6 @@ | ||
| 1 | −/* ASB2305 timer specifcations | |
| 1 | +/* ASB2305-specific timer specifications | |
| 2 | 2 | * |
| 3 | − * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
| 3 | + * Copyright (C) 2007, 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | 5 | * |
| 6 | 6 | * This program is free software; you can redistribute it and/or |
| @@ -17,67 +17,72 @@ · 10 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | #include <asm/timer-regs.h> |
| 19 | 19 | #include <unit/clock.h> |
| 20 | +#include <asm/param.h> | |
| 20 | 21 | |
| 21 | 22 | /* |
| 22 | 23 | * jiffies counter specifications |
| 23 | 24 | */ |
| 24 | 25 | |
| 25 | 26 | #define TMJCBR_MAX 0xffff |
| 26 | −#define TMJCBC TM01BC | |
| 27 | − | |
| 28 | −#define TMJCMD TM01MD | |
| 29 | −#define TMJCBR TM01BR | |
| 30 | 27 | #define TMJCIRQ TM1IRQ |
| 31 | 28 | #define TMJCICR TM1ICR |
| 32 | −#define TMJCICR_LEVEL GxICR_LEVEL_5 | |
| 33 | 29 | |
| 34 | 30 | #ifndef __ASSEMBLY__ |
| 35 | 31 | |
| 36 | −static inline void startup_jiffies_counter(void) | |
| 32 | +#define MN10300_SRC_IOCLK MN10300_IOCLK | |
| 33 | + | |
| 34 | +#ifndef HZ | |
| 35 | +# error HZ undeclared. | |
| 36 | +#endif /* !HZ */ | |
| 37 | +/* use as little prescaling as possible to avoid losing accuracy */ | |
| 38 | +#if (MN10300_SRC_IOCLK + HZ / 2) / HZ - 1 <= TMJCBR_MAX | |
| 39 | +# define IOCLK_PRESCALE 1 | |
| 40 | +# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK | |
| 41 | +# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK | |
| 42 | +#elif (MN10300_SRC_IOCLK / 8 + HZ / 2) / HZ - 1 <= TMJCBR_MAX | |
| 43 | +# define IOCLK_PRESCALE 8 | |
| 44 | +# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK_8 | |
| 45 | +# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK_8 | |
| 46 | +#elif (MN10300_SRC_IOCLK / 32 + HZ / 2) / HZ - 1 <= TMJCBR_MAX | |
| 47 | +# define IOCLK_PRESCALE 32 | |
| 48 | +# define JC_TIMER_CLKSRC TM0MD_SRC_IOCLK_32 | |
| 49 | +# define TSC_TIMER_CLKSRC TM4MD_SRC_IOCLK_32 | |
| 50 | +#else | |
| 51 | +# error You lose. | |
| 52 | +#endif | |
| 53 | + | |
| 54 | +#define MN10300_JCCLK (MN10300_SRC_IOCLK / IOCLK_PRESCALE) | |
| 55 | +#define MN10300_TSCCLK (MN10300_SRC_IOCLK / IOCLK_PRESCALE) | |
| 56 | + | |
| 57 | +#define MN10300_JC_PER_HZ ((MN10300_JCCLK + HZ / 2) / HZ) | |
| 58 | +#define MN10300_TSC_PER_HZ ((MN10300_TSCCLK + HZ / 2) / HZ) | |
| 59 | + | |
| 60 | +static inline void stop_jiffies_counter(void) | |
| 37 | 61 | { |
| 38 | − unsigned rate; | |
| 39 | − u16 md, t16; | |
| 40 | − | |
| 41 | − /* use as little prescaling as possible to avoid losing accuracy */ | |
| 42 | − md = TM0MD_SRC_IOCLK; | |
| 43 | − rate = MN10300_JCCLK / HZ; | |
| 44 | − | |
| 45 | − if (rate > TMJCBR_MAX) { | |
| 46 | − md = TM0MD_SRC_IOCLK_8; | |
| 47 | − rate = MN10300_JCCLK / 8 / HZ; | |
| 48 | − | |
| 49 | − if (rate > TMJCBR_MAX) { | |
| 50 | − md = TM0MD_SRC_IOCLK_32; | |
| 51 | − rate = MN10300_JCCLK / 32 / HZ; | |
| 52 | − | |
| 53 | − if (rate > TMJCBR_MAX) | |
| 54 | − BUG(); | |
| 55 | − } | |
| 56 | − } | |
| 62 | + u16 tmp; | |
| 63 | + TM01MD = JC_TIMER_CLKSRC | TM1MD_SRC_TM0CASCADE << 8; | |
| 64 | + tmp = TM01MD; | |
| 65 | +} | |
| 57 | 66 | |
| 58 | − TMJCBR = rate - 1; | |
| 59 | − t16 = TMJCBR; | |
| 67 | +static inline void reload_jiffies_counter(u32 cnt) | |
| 68 | +{ | |
| 69 | + u32 tmp; | |
| 60 | 70 | |
| 61 | − TMJCMD = | |
| 62 | − md | | |
| 63 | − TM1MD_SRC_TM0CASCADE << 8 | | |
| 64 | − TM0MD_INIT_COUNTER | | |
| 65 | − TM1MD_INIT_COUNTER << 8; | |
| 71 | + TM01BR = cnt; | |
| 72 | + tmp = TM01BR; | |
| 66 | 73 | |
| 67 | − TMJCMD = | |
| 68 | − md | | |
| 69 | − TM1MD_SRC_TM0CASCADE << 8 | | |
| 70 | − TM0MD_COUNT_ENABLE | | |
| 71 | − TM1MD_COUNT_ENABLE << 8; | |
| 74 | + TM01MD = JC_TIMER_CLKSRC | \ | |
| 75 | + TM1MD_SRC_TM0CASCADE << 8 | \ | |
| 76 | + TM0MD_INIT_COUNTER | \ | |
| 77 | + TM1MD_INIT_COUNTER << 8; | |
| 72 | 78 | |
| 73 | − t16 = TMJCMD; | |
| 74 | 79 | |
| 75 | − TMJCICR |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST; | |
| 76 | − t16 = TMJCICR; | |
| 77 | −} | |
| 80 | + TM01MD = JC_TIMER_CLKSRC | \ | |
| 81 | + TM1MD_SRC_TM0CASCADE << 8 | \ | |
| 82 | + TM0MD_COUNT_ENABLE | \ | |
| 83 | + TM1MD_COUNT_ENABLE << 8; | |
| 78 | 84 | |
| 79 | −static inline void shutdown_jiffies_counter(void) | |
| 80 | −{ | |
| 85 | + tmp = TM01MD; | |
| 81 | 86 | } |
| 82 | 87 | |
| 83 | 88 | #endif /* !__ASSEMBLY__ */ |
| @@ -94,29 +99,39 @@ static inline void shutdown_jiffies_counter(void) · 10 unmodified lines | ||
| 94 | 99 | |
| 95 | 100 | static inline void startup_timestamp_counter(void) |
| 96 | 101 | { |
| 102 | + u32 t32; | |
| 103 | + | |
| 97 | 104 | /* set up timer 4 & 5 cascaded as a 32-bit counter to count real time |
| 98 | 105 | * - count down from 4Gig-1 to 0 and wrap at IOCLK rate |
| 99 | 106 | */ |
| 100 | 107 | TM45BR = TMTSCBR_MAX; |
| 108 | + t32 = TM45BR; | |
| 101 | 109 | |
| 102 | − TM4MD = TM4MD_SRC_IOCLK; | |
| 110 | + TM4MD = TSC_TIMER_CLKSRC; | |
| 103 | 111 | TM4MD |= TM4MD_INIT_COUNTER; |
| 104 | 112 | TM4MD &= ~TM4MD_INIT_COUNTER; |
| 105 | 113 | TM4ICR = 0; |
| 114 | + t32 = TM4ICR; | |
| 106 | 115 | |
| 107 | 116 | TM5MD = TM5MD_SRC_TM4CASCADE; |
| 108 | 117 | TM5MD |= TM5MD_INIT_COUNTER; |
| 109 | 118 | TM5MD &= ~TM5MD_INIT_COUNTER; |
| 110 | 119 | TM5ICR = 0; |
| 120 | + t32 = TM5ICR; | |
| 111 | 121 | |
| 112 | 122 | TM5MD |= TM5MD_COUNT_ENABLE; |
| 113 | 123 | TM4MD |= TM4MD_COUNT_ENABLE; |
| 124 | + t32 = TM5MD; | |
| 125 | + t32 = TM4MD; | |
| 114 | 126 | } |
| 115 | 127 | |
| 116 | 128 | static inline void shutdown_timestamp_counter(void) |
| 117 | 129 | { |
| 130 | + u8 t8; | |
| 118 | 131 | TM4MD = 0; |
| 119 | 132 | TM5MD = 0; |
| 133 | + t8 = TM4MD; | |
| 134 | + t8 = TM5MD; | |
| 120 | 135 | } |
| 121 | 136 | |
| 122 | 137 | /* |
| @@ -127,7 +142,7 @@ typedef unsigned long cycles_t; · 4 unmodified lines | ||
| 127 | 142 | |
| 128 | 143 | static inline cycles_t read_timestamp_counter(void) |
| 129 | 144 | { |
| 130 | − return (cycles_t) TMTSCBC; | |
| 145 | + return (cycles_t)~TMTSCBC; | |
| 131 | 146 | } |
| 132 | 147 | |
| 133 | 148 | #endif /* !__ASSEMBLY__ */ |
| @@ -93,7 +93,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) · 92 unmodified lines | ||
| 93 | 93 | struct pci_bus *bus; |
| 94 | 94 | struct pci_dev *dev; |
| 95 | 95 | int idx; |
| 96 | − struct resource *r, *pr; | |
| 96 | + struct resource *r; | |
| 97 | 97 | |
| 98 | 98 | /* Depth-First Search on bus tree */ |
| 99 | 99 | list_for_each_entry(bus, bus_list, node) { |
| @@ -105,10 +105,8 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) · 5 unmodified lines | ||
| 105 | 105 | r = &dev->resource[idx]; |
| 106 | 106 | if (!r->flags) |
| 107 | 107 | continue; |
| 108 | − pr = pci_find_parent_resource(dev, r); | |
| 109 | 108 | if (!r->start || |
| 110 | − !pr || | |
| 111 | − request_resource(pr, r) < 0) { | |
| 109 | + pci_claim_resource(dev, idx) < 0) { | |
| 112 | 110 | printk(KERN_ERR "PCI:" |
| 113 | 111 | " Cannot allocate resource" |
| 114 | 112 | " region %d of bridge %s\n", |
| @@ -131,7 +129,7 @@ static void __init pcibios_allocate_resources(int pass) · 16 unmodified lines | ||
| 131 | 129 | struct pci_dev *dev = NULL; |
| 132 | 130 | int idx, disabled; |
| 133 | 131 | u16 command; |
| 134 | − struct resource *r, *pr; | |
| 132 | + struct resource *r; | |
| 135 | 133 | |
| 136 | 134 | for_each_pci_dev(dev) { |
| 137 | 135 | pci_read_config_word(dev, PCI_COMMAND, &command); |
| @@ -150,8 +148,7 @@ static void __init pcibios_allocate_resources(int pass) · 12 unmodified lines | ||
| 150 | 148 | " (f=%lx, d=%d, p=%d)\n", |
| 151 | 149 | pci_name(dev), r->start, r->end, r->flags, |
| 152 | 150 | disabled, pass); |
| 153 | − pr = pci_find_parent_resource(dev, r); | |
| 154 | − if (!pr || request_resource(pr, r) < 0) { | |
| 151 | + if (pci_claim_resource(dev, idx) < 0) { | |
| 155 | 152 | printk(KERN_ERR "PCI:" |
| 156 | 153 | " Cannot allocate resource" |
| 157 | 154 | " region %d of device %s\n", |
| @@ -184,7 +181,7 @@ static void __init pcibios_allocate_resources(int pass) · 26 unmodified lines | ||
| 184 | 181 | static int __init pcibios_assign_resources(void) |
| 185 | 182 | { |
| 186 | 183 | struct pci_dev *dev = NULL; |
| 187 | − struct resource *r, *pr; | |
| 184 | + struct resource *r; | |
| 188 | 185 | |
| 189 | 186 | if (!(pci_probe & PCI_ASSIGN_ROMS)) { |
| 190 | 187 | /* Try to use BIOS settings for ROMs, otherwise let |
| @@ -194,8 +191,7 @@ static int __init pcibios_assign_resources(void) · 3 unmodified lines | ||
| 194 | 191 | r = &dev->resource[PCI_ROM_RESOURCE]; |
| 195 | 192 | if (!r->flags || !r->start) |
| 196 | 193 | continue; |
| 197 | − pr = pci_find_parent_resource(dev, r); | |
| 198 | − if (!pr || request_resource(pr, r) < 0) { | |
| 194 | + if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) { | |
| 199 | 195 | r->end -= r->start; |
| 200 | 196 | r->start = 0; |
| 201 | 197 | } |
| @@ -503,7 +503,7 @@ asmlinkage void __init unit_pci_init(void) · 502 unmodified lines | ||
| 503 | 503 | struct pci_ops *o = &pci_direct_ampci; |
| 504 | 504 | u32 x; |
| 505 | 505 | |
| 506 | − set_intr_level(XIRQ1, GxICR_LEVEL_3); | |
| 506 | + set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_PCI_IRQ_LEVEL)); | |
| 507 | 507 | |
| 508 | 508 | memset(&bus, 0, sizeof(bus)); |
| 509 | 509 | |
| @@ -26,8 +26,10 @@ asmlinkage void __init unit_init(void) · 25 unmodified lines | ||
| 26 | 26 | { |
| 27 | 27 | #ifndef CONFIG_GDBSTUB_ON_TTYSx |
| 28 | 28 | /* set the 16550 interrupt line to level 3 if not being used for GDB */ |
| 29 | − set_intr_level(XIRQ0, GxICR_LEVEL_3); | |
| 29 | +#ifdef CONFIG_EXT_SERIAL_IRQ_LEVEL | |
| 30 | + set_intr_level(XIRQ0, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL)); | |
| 30 | 31 | #endif |
| 32 | +#endif /* CONFIG_GDBSTUB_ON_TTYSx */ | |
| 31 | 33 | } |
| 32 | 34 | |
| 33 | 35 | /* |
| @@ -51,7 +53,7 @@ void __init unit_init_IRQ(void) · 17 unmodified lines | ||
| 51 | 53 | switch (GET_XIRQ_TRIGGER(extnum)) { |
| 52 | 54 | case XIRQ_TRIGGER_HILEVEL: |
| 53 | 55 | case XIRQ_TRIGGER_LOWLEVEL: |
| 54 | − set_intr_postackable(XIRQ2IRQ(extnum)); | |
| 56 | + mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum)); | |
| 55 | 57 | break; |
| 56 | 58 | default: |
| 57 | 59 | break; |
| @@ -0,0 +1,12 @@ | ||
| 1 | +# | |
| 2 | +# Makefile for the linux kernel. | |
| 3 | +# | |
| 4 | +# Note! Dependencies are done automagically by 'make dep', which also | |
| 5 | +# removes any old dependencies. DON'T put your own dependencies here | |
| 6 | +# unless it's something special (ie not a .c file). | |
| 7 | +# | |
| 8 | +# Note 2! The CFLAGS definitions are now in the main makefile... | |
| 9 | + | |
| 10 | +obj-y := unit-init.o leds.o irq-fpga.o | |
| 11 | + | |
| 12 | +obj-$(CONFIG_SMSC911X) += smsc911x.o | |
| @@ -0,0 +1,29 @@ | ||
| 1 | +/* clock.h: unit-specific clocks | |
| 2 | + * | |
| 3 | + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * Modified by Matsushita Electric Industrial Co., Ltd. | |
| 7 | + * Modifications: | |
| 8 | + * 23-Feb-2007 MEI Add define for watchdog timer. | |
| 9 | + * | |
| 10 | + * This program is free software; you can redistribute it and/or | |
| 11 | + * modify it under the terms of the GNU General Public License | |
| 12 | + * as published by the Free Software Foundation; either version | |
| 13 | + * 2 of the License, or (at your option) any later version. | |
| 14 | + */ | |
| 15 | + | |
| 16 | +#ifndef _ASM_UNIT_CLOCK_H | |
| 17 | +#define _ASM_UNIT_CLOCK_H | |
| 18 | + | |
| 19 | +#ifndef __ASSEMBLY__ | |
| 20 | + | |
| 21 | +#define MN10300_IOCLK 100000000UL /* for DDR800 */ | |
| 22 | +/*#define MN10300_IOCLK 83333333UL */ /* for DDR667 */ | |
| 23 | +#define MN10300_IOBCLK MN10300_IOCLK /* IOBCLK is equal to IOCLK */ | |
| 24 | + | |
| 25 | +#endif /* !__ASSEMBLY__ */ | |
| 26 | + | |
| 27 | +#define MN10300_WDCLK 27000000UL | |
| 28 | + | |
| 29 | +#endif /* _ASM_UNIT_CLOCK_H */ | |
| @@ -0,0 +1,52 @@ | ||
| 1 | +/* ASB2364 FPGA registers | |
| 2 | + */ | |
| 3 | + | |
| 4 | +#ifndef _ASM_UNIT_FPGA_REGS_H | |
| 5 | +#define _ASM_UNIT_FPGA_REGS_H | |
| 6 | + | |
| 7 | +#include <asm/cpu-regs.h> | |
| 8 | + | |
| 9 | +#ifdef __KERNEL__ | |
| 10 | + | |
| 11 | +#define ASB2364_FPGA_REG_RESET_LAN __SYSREG(0xa9001300, u16) | |
| 12 | +#define ASB2364_FPGA_REG_RESET_UART __SYSREG(0xa9001304, u16) | |
| 13 | +#define ASB2364_FPGA_REG_RESET_I2C __SYSREG(0xa9001308, u16) | |
| 14 | +#define ASB2364_FPGA_REG_RESET_USB __SYSREG(0xa900130c, u16) | |
| 15 | +#define ASB2364_FPGA_REG_RESET_AV __SYSREG(0xa9001310, u16) | |
| 16 | + | |
| 17 | +#define ASB2364_FPGA_REG_IRQ(X) __SYSREG(0xa9001590+((X)*4), u16) | |
| 18 | +#define ASB2364_FPGA_REG_IRQ_LAN ASB2364_FPGA_REG_IRQ(0) | |
| 19 | +#define ASB2364_FPGA_REG_IRQ_UART ASB2364_FPGA_REG_IRQ(1) | |
| 20 | +#define ASB2364_FPGA_REG_IRQ_I2C ASB2364_FPGA_REG_IRQ(2) | |
| 21 | +#define ASB2364_FPGA_REG_IRQ_USB ASB2364_FPGA_REG_IRQ(3) | |
| 22 | +#define ASB2364_FPGA_REG_IRQ_FPGA ASB2364_FPGA_REG_IRQ(5) | |
| 23 | + | |
| 24 | +#define ASB2364_FPGA_REG_MASK(X) __SYSREG(0xa9001590+((X)*4), u16) | |
| 25 | +#define ASB2364_FPGA_REG_MASK_LAN ASB2364_FPGA_REG_MASK(0) | |
| 26 | +#define ASB2364_FPGA_REG_MASK_UART ASB2364_FPGA_REG_MASK(1) | |
| 27 | +#define ASB2364_FPGA_REG_MASK_I2C ASB2364_FPGA_REG_MASK(2) | |
| 28 | +#define ASB2364_FPGA_REG_MASK_USB ASB2364_FPGA_REG_MASK(3) | |
| 29 | +#define ASB2364_FPGA_REG_MASK_FPGA ASB2364_FPGA_REG_MASK(5) | |
| 30 | + | |
| 31 | +#define ASB2364_FPGA_REG_CPLD5_SET1 __SYSREG(0xa9002500, u16) | |
| 32 | +#define ASB2364_FPGA_REG_CPLD5_SET2 __SYSREG(0xa9002504, u16) | |
| 33 | +#define ASB2364_FPGA_REG_CPLD6_SET1 __SYSREG(0xa9002600, u16) | |
| 34 | +#define ASB2364_FPGA_REG_CPLD6_SET2 __SYSREG(0xa9002604, u16) | |
| 35 | +#define ASB2364_FPGA_REG_CPLD7_SET1 __SYSREG(0xa9002700, u16) | |
| 36 | +#define ASB2364_FPGA_REG_CPLD7_SET2 __SYSREG(0xa9002704, u16) | |
| 37 | +#define ASB2364_FPGA_REG_CPLD8_SET1 __SYSREG(0xa9002800, u16) | |
| 38 | +#define ASB2364_FPGA_REG_CPLD8_SET2 __SYSREG(0xa9002804, u16) | |
| 39 | +#define ASB2364_FPGA_REG_CPLD9_SET1 __SYSREG(0xa9002900, u16) | |
| 40 | +#define ASB2364_FPGA_REG_CPLD9_SET2 __SYSREG(0xa9002904, u16) | |
| 41 | +#define ASB2364_FPGA_REG_CPLD10_SET1 __SYSREG(0xa9002a00, u16) | |
| 42 | +#define ASB2364_FPGA_REG_CPLD10_SET2 __SYSREG(0xa9002a04, u16) | |
| 43 | + | |
| 44 | +#define SyncExBus() \ | |
| 45 | + do { \ | |
| 46 | + unsigned short w; \ | |
| 47 | + w = *(volatile short *)0xa9000000; \ | |
| 48 | + } while (0) | |
| 49 | + | |
| 50 | +#endif /* __KERNEL__ */ | |
| 51 | + | |
| 52 | +#endif /* _ASM_UNIT_FPGA_REGS_H */ | |
| @@ -0,0 +1,35 @@ | ||
| 1 | +/* ASB2364 FPGA irq numbers | |
| 2 | + * | |
| 3 | + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#ifndef _UNIT_IRQ_H | |
| 12 | +#define _UNIT_IRQ_H | |
| 13 | + | |
| 14 | +#ifndef __ASSEMBLY__ | |
| 15 | + | |
| 16 | +#ifdef CONFIG_SMP | |
| 17 | +#define NR_CPU_IRQS GxICR_NUM_EXT_IRQS | |
| 18 | +#else | |
| 19 | +#define NR_CPU_IRQS GxICR_NUM_IRQS | |
| 20 | +#endif | |
| 21 | + | |
| 22 | +enum { | |
| 23 | + FPGA_LAN_IRQ = NR_CPU_IRQS, | |
| 24 | + FPGA_UART_IRQ, | |
| 25 | + FPGA_I2C_IRQ, | |
| 26 | + FPGA_USB_IRQ, | |
| 27 | + FPGA_RESERVED_IRQ, | |
| 28 | + FPGA_FPGA_IRQ, | |
| 29 | + NR_IRQS | |
| 30 | +}; | |
| 31 | + | |
| 32 | +extern void __init irq_fpga_init(void); | |
| 33 | + | |
| 34 | +#endif /* !__ASSEMBLY__ */ | |
| 35 | +#endif /* _UNIT_IRQ_H */ | |
| @@ -0,0 +1,54 @@ | ||
| 1 | +/* Unit-specific leds | |
| 2 | + * | |
| 3 | + * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the License, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#ifndef _ASM_UNIT_LEDS_H | |
| 13 | +#define _ASM_UNIT_LEDS_H | |
| 14 | + | |
| 15 | +#include <asm/pio-regs.h> | |
| 16 | +#include <asm/cpu-regs.h> | |
| 17 | +#include <asm/exceptions.h> | |
| 18 | + | |
| 19 | +#define MN10300_USE_7SEGLEDS 0 | |
| 20 | + | |
| 21 | +#define ASB2364_7SEGLEDS __SYSREG(0xA9001630, u32) | |
| 22 | + | |
| 23 | +/* | |
| 24 | + * use the 7-segment LEDs to indicate states | |
| 25 | + */ | |
| 26 | + | |
| 27 | +#if MN10300_USE_7SEGLEDS | |
| 28 | +/* flip the 7-segment LEDs between "Gdb-" and "----" */ | |
| 29 | +#define mn10300_set_gdbleds(ONOFF) \ | |
| 30 | + do { \ | |
| 31 | + ASB2364_7SEGLEDS = (ONOFF) ? 0x8543077f : 0x7f7f7f7f; \ | |
| 32 | + } while (0) | |
| 33 | +#else | |
| 34 | +#define mn10300_set_gdbleds(ONOFF) do {} while (0) | |
| 35 | +#endif | |
| 36 | + | |
| 37 | +#if MN10300_USE_7SEGLEDS | |
| 38 | +/* indicate double-fault by displaying "db-f" on the LEDs */ | |
| 39 | +#define mn10300_set_dbfleds \ | |
| 40 | + mov 0x43077f1d,d0 ; \ | |
| 41 | + mov d0,(ASB2364_7SEGLEDS) | |
| 42 | +#else | |
| 43 | +#define mn10300_set_dbfleds | |
| 44 | +#endif | |
| 45 | + | |
| 46 | +#ifndef __ASSEMBLY__ | |
| 47 | +extern void peripheral_leds_display_exception(enum exception_code); | |
| 48 | +extern void peripheral_leds_led_chase(void); | |
| 49 | +extern void peripheral_leds7x4_display_dec(unsigned int, unsigned int); | |
| 50 | +extern void peripheral_leds7x4_display_hex(unsigned int, unsigned int); | |
| 51 | +extern void debug_to_serial(const char *, int); | |
| 52 | +#endif /* __ASSEMBLY__ */ | |
| 53 | + | |
| 54 | +#endif /* _ASM_UNIT_LEDS_H */ | |
| @@ -0,0 +1,151 @@ | ||
| 1 | +/* Unit-specific 8250 serial ports | |
| 2 | + * | |
| 3 | + * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the License, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#ifndef _ASM_UNIT_SERIAL_H | |
| 13 | +#define _ASM_UNIT_SERIAL_H | |
| 14 | + | |
| 15 | +#include <asm/cpu-regs.h> | |
| 16 | +#include <proc/irq.h> | |
| 17 | +#include <unit/fpga-regs.h> | |
| 18 | +#include <linux/serial_reg.h> | |
| 19 | + | |
| 20 | +#define SERIAL_PORT0_BASE_ADDRESS 0xA8200000 | |
| 21 | + | |
| 22 | +#define SERIAL_IRQ XIRQ1 /* single serial (TL16C550C) (Lo) */ | |
| 23 | + | |
| 24 | +/* | |
| 25 | + * The ASB2364 has an 12.288 MHz clock | |
| 26 | + * for your UART. | |
| 27 | + * | |
| 28 | + * It'd be nice if someone built a serial card with a 24.576 MHz | |
| 29 | + * clock, since the 16550A is capable of handling a top speed of 1.5 | |
| 30 | + * megabits/second; but this requires the faster clock. | |
| 31 | + */ | |
| 32 | +#define BASE_BAUD (12288000 / 16) | |
| 33 | + | |
| 34 | +/* | |
| 35 | + * dispose of the /dev/ttyS0 and /dev/ttyS1 serial ports | |
| 36 | + */ | |
| 37 | +#ifndef CONFIG_GDBSTUB_ON_TTYSx | |
| 38 | + | |
| 39 | +#define SERIAL_PORT_DFNS \ | |
| 40 | + { \ | |
| 41 | + .baud_base = BASE_BAUD, \ | |
| 42 | + .irq = SERIAL_IRQ, \ | |
| 43 | + .flags = STD_COM_FLAGS, \ | |
| 44 | + .iomem_base = (u8 *) SERIAL_PORT0_BASE_ADDRESS, \ | |
| 45 | + .iomem_reg_shift = 1, \ | |
| 46 | + .io_type = SERIAL_IO_MEM, \ | |
| 47 | + }, | |
| 48 | + | |
| 49 | +#ifndef __ASSEMBLY__ | |
| 50 | + | |
| 51 | +static inline void __debug_to_serial(const char *p, int n) | |
| 52 | +{ | |
| 53 | +} | |
| 54 | + | |
| 55 | +#endif /* !__ASSEMBLY__ */ | |
| 56 | + | |
| 57 | +#else /* CONFIG_GDBSTUB_ON_TTYSx */ | |
| 58 | + | |
| 59 | +#define SERIAL_PORT_DFNS /* stolen by gdb-stub */ | |
| 60 | + | |
| 61 | +#if defined(CONFIG_GDBSTUB_ON_TTYS0) | |
| 62 | +#define GDBPORT_SERIAL_RX __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_RX * 4, u8) | |
| 63 | +#define GDBPORT_SERIAL_TX __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_TX * 4, u8) | |
| 64 | +#define GDBPORT_SERIAL_DLL __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLL * 4, u8) | |
| 65 | +#define GDBPORT_SERIAL_DLM __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLM * 4, u8) | |
| 66 | +#define GDBPORT_SERIAL_IER __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IER * 4, u8) | |
| 67 | +#define GDBPORT_SERIAL_IIR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IIR * 4, u8) | |
| 68 | +#define GDBPORT_SERIAL_FCR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_FCR * 4, u8) | |
| 69 | +#define GDBPORT_SERIAL_LCR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LCR * 4, u8) | |
| 70 | +#define GDBPORT_SERIAL_MCR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MCR * 4, u8) | |
| 71 | +#define GDBPORT_SERIAL_LSR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LSR * 4, u8) | |
| 72 | +#define GDBPORT_SERIAL_MSR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MSR * 4, u8) | |
| 73 | +#define GDBPORT_SERIAL_SCR __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_SCR * 4, u8) | |
| 74 | +#define GDBPORT_SERIAL_IRQ SERIAL_IRQ | |
| 75 | + | |
| 76 | +#elif defined(CONFIG_GDBSTUB_ON_TTYS1) | |
| 77 | +#error The ASB2364 does not have a /dev/ttyS1 | |
| 78 | +#endif | |
| 79 | + | |
| 80 | +#ifndef __ASSEMBLY__ | |
| 81 | + | |
| 82 | +static inline void __debug_to_serial(const char *p, int n) | |
| 83 | +{ | |
| 84 | + char ch; | |
| 85 | + | |
| 86 | +#define LSR_WAIT_FOR(STATE) \ | |
| 87 | + do {} while (!(GDBPORT_SERIAL_LSR & UART_LSR_##STATE)) | |
| 88 | +#define FLOWCTL_QUERY(LINE) \ | |
| 89 | + ({ GDBPORT_SERIAL_MSR & UART_MSR_##LINE; }) | |
| 90 | +#define FLOWCTL_WAIT_FOR(LINE) \ | |
| 91 | + do {} while (!(GDBPORT_SERIAL_MSR & UART_MSR_##LINE)) | |
| 92 | +#define FLOWCTL_CLEAR(LINE) \ | |
| 93 | + do { GDBPORT_SERIAL_MCR &= ~UART_MCR_##LINE; } while (0) | |
| 94 | +#define FLOWCTL_SET(LINE) \ | |
| 95 | + do { GDBPORT_SERIAL_MCR |= UART_MCR_##LINE; } while (0) | |
| 96 | + | |
| 97 | + FLOWCTL_SET(DTR); | |
| 98 | + | |
| 99 | + for (; n > 0; n--) { | |
| 100 | + LSR_WAIT_FOR(THRE); | |
| 101 | + FLOWCTL_WAIT_FOR(CTS); | |
| 102 | + | |
| 103 | + ch = *p++; | |
| 104 | + if (ch == 0x0a) { | |
| 105 | + GDBPORT_SERIAL_TX = 0x0d; | |
| 106 | + LSR_WAIT_FOR(THRE); | |
| 107 | + FLOWCTL_WAIT_FOR(CTS); | |
| 108 | + } | |
| 109 | + GDBPORT_SERIAL_TX = ch; | |
| 110 | + } | |
| 111 | + | |
| 112 | + FLOWCTL_CLEAR(DTR); | |
| 113 | +} | |
| 114 | + | |
| 115 | +#endif /* !__ASSEMBLY__ */ | |
| 116 | + | |
| 117 | +#endif /* CONFIG_GDBSTUB_ON_TTYSx */ | |
| 118 | + | |
| 119 | +#define SERIAL_INITIALIZE \ | |
| 120 | +do { \ | |
| 121 | + /* release reset */ \ | |
| 122 | + ASB2364_FPGA_REG_RESET_UART = 0x0001; \ | |
| 123 | + SyncExBus(); \ | |
| 124 | +} while (0) | |
| 125 | + | |
| 126 | +#define SERIAL_CHECK_INTERRUPT \ | |
| 127 | +do { \ | |
| 128 | + if ((ASB2364_FPGA_REG_IRQ_UART & 0x0001) == 0x0001) { \ | |
| 129 | + return IRQ_NONE; \ | |
| 130 | + } \ | |
| 131 | +} while (0) | |
| 132 | + | |
| 133 | +#define SERIAL_CLEAR_INTERRUPT \ | |
| 134 | +do { \ | |
| 135 | + ASB2364_FPGA_REG_IRQ_UART = 0x0001; \ | |
| 136 | + SyncExBus(); \ | |
| 137 | +} while (0) | |
| 138 | + | |
| 139 | +#define SERIAL_SET_INT_MASK \ | |
| 140 | +do { \ | |
| 141 | + ASB2364_FPGA_REG_MASK_UART = 0x0001; \ | |
| 142 | + SyncExBus(); \ | |
| 143 | +} while (0) | |
| 144 | + | |
| 145 | +#define SERIAL_CLEAR_INT_MASK \ | |
| 146 | +do { \ | |
| 147 | + ASB2364_FPGA_REG_MASK_UART = 0x0000; \ | |
| 148 | + SyncExBus(); \ | |
| 149 | +} while (0) | |
| 150 | + | |
| 151 | +#endif /* _ASM_UNIT_SERIAL_H */ | |
| @@ -0,0 +1,171 @@ | ||
| 1 | +/* Support for the SMSC911x NIC | |
| 2 | + * | |
| 3 | + * Copyright (C) 2006 Matsushita Electric Industrial Co., Ltd. | |
| 4 | + * All Rights Reserved. | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the License, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#ifndef _ASM_UNIT_SMSC911X_H | |
| 12 | +#define _ASM_UNIT_SMSC911X_H | |
| 13 | + | |
| 14 | +#include <linux/netdevice.h> | |
| 15 | +#include <proc/irq.h> | |
| 16 | +#include <unit/fpga-regs.h> | |
| 17 | + | |
| 18 | +#define MN10300_USE_EXT_EEPROM | |
| 19 | + | |
| 20 | + | |
| 21 | +#define SMSC911X_BASE 0xA8000000UL | |
| 22 | +#define SMSC911X_BASE_END 0xA8000100UL | |
| 23 | +#define SMSC911X_IRQ FPGA_LAN_IRQ | |
| 24 | + | |
| 25 | +/* | |
| 26 | + * Allow the FPGA to be initialised by the SMSC911x driver | |
| 27 | + */ | |
| 28 | +#undef SMSC_INITIALIZE | |
| 29 | +#define SMSC_INITIALIZE() \ | |
| 30 | +do { \ | |
| 31 | + /* release reset */ \ | |
| 32 | + ASB2364_FPGA_REG_RESET_LAN = 0x0001; \ | |
| 33 | + SyncExBus(); \ | |
| 34 | +} while (0) | |
| 35 | + | |
| 36 | +#ifdef MN10300_USE_EXT_EEPROM | |
| 37 | +#include <linux/delay.h> | |
| 38 | +#include <unit/clock.h> | |
| 39 | + | |
| 40 | +#define EEPROM_ADDRESS 0xA0 | |
| 41 | +#define MAC_OFFSET 0x0008 | |
| 42 | +#define USE_IIC_CH 0 /* 0 or 1 */ | |
| 43 | +#define IIC_OFFSET (0x80000 * USE_IIC_CH) | |
| 44 | +#define IIC_DTRM __SYSREG(0xd8400000 + IIC_OFFSET, u32) | |
| 45 | +#define IIC_DREC __SYSREG(0xd8400004 + IIC_OFFSET, u32) | |
| 46 | +#define IIC_MYADD __SYSREG(0xd8400008 + IIC_OFFSET, u32) | |
| 47 | +#define IIC_CLK __SYSREG(0xd840000c + IIC_OFFSET, u32) | |
| 48 | +#define IIC_BRST __SYSREG(0xd8400010 + IIC_OFFSET, u32) | |
| 49 | +#define IIC_HOLD __SYSREG(0xd8400014 + IIC_OFFSET, u32) | |
| 50 | +#define IIC_BSTS __SYSREG(0xd8400018 + IIC_OFFSET, u32) | |
| 51 | +#define IIC_ICR __SYSREG(0xd4000080 + 4 * USE_IIC_CH, u16) | |
| 52 | + | |
| 53 | +#define IIC_CLK_PLS ((unsigned short)(MN10300_IOCLK / 100000 - 1)) | |
| 54 | +#define IIC_CLK_LOW ((unsigned short)(IIC_CLK_PLS / 2)) | |
| 55 | + | |
| 56 | +#define SYS_IIC_DTRM_Bit_STA ((unsigned short)0x0400) | |
| 57 | +#define SYS_IIC_DTRM_Bit_STO ((unsigned short)0x0200) | |
| 58 | +#define SYS_IIC_DTRM_Bit_ACK ((unsigned short)0x0100) | |
| 59 | +#define SYS_IIC_DTRM_Bit_DATA ((unsigned short)0x00FF) | |
| 60 | + | |
| 61 | +static inline void POLL_INT_REQ(volatile u16 *icr) | |
| 62 | +{ | |
| 63 | + unsigned long flags; | |
| 64 | + u16 tmp; | |
| 65 | + | |
| 66 | + while (!(*icr & GxICR_REQUEST)) | |
| 67 | + ; | |
| 68 | + flags = arch_local_cli_save(); | |
| 69 | + tmp = *icr; | |
| 70 | + *icr = (tmp & GxICR_LEVEL) | GxICR_DETECT; | |
| 71 | + tmp = *icr; | |
| 72 | + arch_local_irq_restore(flags); | |
| 73 | +} | |
| 74 | + | |
| 75 | +/* | |
| 76 | + * Implement the SMSC911x hook for MAC address retrieval | |
| 77 | + */ | |
| 78 | +#undef smsc_get_mac | |
| 79 | +static inline int smsc_get_mac(struct net_device *dev) | |
| 80 | +{ | |
| 81 | + unsigned char *mac_buf = dev->dev_addr; | |
| 82 | + int i; | |
| 83 | + unsigned short value; | |
| 84 | + unsigned int data; | |
| 85 | + int mac_length = 6; | |
| 86 | + int check; | |
| 87 | + u16 orig_gicr, tmp; | |
| 88 | + unsigned long flags; | |
| 89 | + | |
| 90 | + /* save original GnICR and clear GnICR.IE */ | |
| 91 | + flags = arch_local_cli_save(); | |
| 92 | + orig_gicr = IIC_ICR; | |
| 93 | + IIC_ICR = orig_gicr & GxICR_LEVEL; | |
| 94 | + tmp = IIC_ICR; | |
| 95 | + arch_local_irq_restore(flags); | |
| 96 | + | |
| 97 | + IIC_MYADD = 0x00000008; | |
| 98 | + IIC_CLK = (IIC_CLK_LOW << 16) + (IIC_CLK_PLS); | |
| 99 | + /* bus hung recovery */ | |
| 100 | + | |
| 101 | + while (1) { | |
| 102 | + check = 0; | |
| 103 | + for (i = 0; i < 3; i++) { | |
| 104 | + if ((IIC_BSTS & 0x00000003) == 0x00000003) | |
| 105 | + check++; | |
| 106 | + udelay(3); | |
| 107 | + } | |
| 108 | + | |
| 109 | + if (check == 3) { | |
| 110 | + IIC_BRST = 0x00000003; | |
| 111 | + break; | |
| 112 | + } else { | |
| 113 | + for (i = 0; i < 3; i++) { | |
| 114 | + IIC_BRST = 0x00000002; | |
| 115 | + udelay(8); | |
| 116 | + IIC_BRST = 0x00000003; | |
| 117 | + udelay(8); | |
| 118 | + } | |
| 119 | + } | |
| 120 | + } | |
| 121 | + | |
| 122 | + IIC_BRST = 0x00000002; | |
| 123 | + IIC_BRST = 0x00000003; | |
| 124 | + | |
| 125 | + value = SYS_IIC_DTRM_Bit_STA | SYS_IIC_DTRM_Bit_ACK; | |
| 126 | + value |= (((unsigned short)EEPROM_ADDRESS & SYS_IIC_DTRM_Bit_DATA) | | |
| 127 | + (unsigned short)0x0000); | |
| 128 | + IIC_DTRM = value; | |
| 129 | + POLL_INT_REQ(&IIC_ICR); | |
| 130 | + | |
| 131 | + /** send offset of MAC address in EEPROM **/ | |
| 132 | + IIC_DTRM = (unsigned char)((MAC_OFFSET & 0xFF00) >> 8); | |
| 133 | + POLL_INT_REQ(&IIC_ICR); | |
| 134 | + | |
| 135 | + IIC_DTRM = (unsigned char)(MAC_OFFSET & 0x00FF); | |
| 136 | + POLL_INT_REQ(&IIC_ICR); | |
| 137 | + | |
| 138 | + udelay(1000); | |
| 139 | + | |
| 140 | + value = SYS_IIC_DTRM_Bit_STA; | |
| 141 | + value |= (((unsigned short)EEPROM_ADDRESS & SYS_IIC_DTRM_Bit_DATA) | | |
| 142 | + (unsigned short)0x0001); | |
| 143 | + IIC_DTRM = value; | |
| 144 | + POLL_INT_REQ(&IIC_ICR); | |
| 145 | + | |
| 146 | + IIC_DTRM = 0x00000000; | |
| 147 | + while (mac_length > 0) { | |
| 148 | + POLL_INT_REQ(&IIC_ICR); | |
| 149 | + | |
| 150 | + data = IIC_DREC; | |
| 151 | + mac_length--; | |
| 152 | + if (mac_length == 0) | |
| 153 | + value = 0x00000300; /* stop IIC bus */ | |
| 154 | + else if (mac_length == 1) | |
| 155 | + value = 0x00000100; /* no ack */ | |
| 156 | + else | |
| 157 | + value = 0x00000000; /* ack */ | |
| 158 | + IIC_DTRM = value; | |
| 159 | + *mac_buf++ = (unsigned char)(data & 0xff); | |
| 160 | + } | |
| 161 | + | |
| 162 | + /* restore GnICR.LV and GnICR.IE */ | |
| 163 | + flags = arch_local_cli_save(); | |
| 164 | + IIC_ICR = (orig_gicr & (GxICR_LEVEL | GxICR_ENABLE)); | |
| 165 | + tmp = IIC_ICR; | |
| 166 | + arch_local_irq_restore(flags); | |
| 167 | + | |
| 168 | + return 0; | |
| 169 | +} | |
| 170 | +#endif /* MN10300_USE_EXT_EEPROM */ | |
| 171 | +#endif /* _ASM_UNIT_SMSC911X_H */ | |
| @@ -0,0 +1,159 @@ | ||
| 1 | +/* timex.h: MN2WS0038 architecture timer specifications | |
| 2 | + * | |
| 3 | + * Copyright (C) 2002, 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the License, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | +#ifndef _ASM_UNIT_TIMEX_H | |
| 12 | +#define _ASM_UNIT_TIMEX_H | |
| 13 | + | |
| 14 | +#ifndef __ASSEMBLY__ | |
| 15 | +#include <linux/irq.h> | |
| 16 | +#endif /* __ASSEMBLY__ */ | |
| 17 | + | |
| 18 | +#include <asm/timer-regs.h> | |
| 19 | +#include <unit/clock.h> | |
| 20 | +#include <asm/param.h> | |
| 21 | + | |
| 22 | +/* | |
| 23 | + * jiffies counter specifications | |
| 24 | + */ | |
| 25 | + | |
| 26 | +#define TMJCBR_MAX 0xffffff /* 24bit */ | |
| 27 | +#define TMJCIRQ TMTIRQ | |
| 28 | + | |
| 29 | +#ifndef __ASSEMBLY__ | |
| 30 | + | |
| 31 | +#define MN10300_SRC_IOBCLK MN10300_IOBCLK | |
| 32 | + | |
| 33 | +#ifndef HZ | |
| 34 | +# error HZ undeclared. | |
| 35 | +#endif /* !HZ */ | |
| 36 | + | |
| 37 | +#define MN10300_JCCLK (MN10300_SRC_IOBCLK) | |
| 38 | +#define MN10300_TSCCLK (MN10300_SRC_IOBCLK) | |
| 39 | + | |
| 40 | +#define MN10300_JC_PER_HZ ((MN10300_JCCLK + HZ / 2) / HZ) | |
| 41 | +#define MN10300_TSC_PER_HZ ((MN10300_TSCCLK + HZ / 2) / HZ) | |
| 42 | + | |
| 43 | +/* Check bit width of MTM interval value that sets base register */ | |
| 44 | +#if (MN10300_JC_PER_HZ - 1) > TMJCBR_MAX | |
| 45 | +# error MTM tick timer interval value is overflow. | |
| 46 | +#endif | |
| 47 | + | |
| 48 | +static inline void stop_jiffies_counter(void) | |
| 49 | +{ | |
| 50 | + u16 tmp; | |
| 51 | + TMTMD = 0; | |
| 52 | + tmp = TMTMD; | |
| 53 | +} | |
| 54 | + | |
| 55 | +static inline void reload_jiffies_counter(u32 cnt) | |
| 56 | +{ | |
| 57 | + u32 tmp; | |
| 58 | + | |
| 59 | + TMTBR = cnt; | |
| 60 | + tmp = TMTBR; | |
| 61 | + | |
| 62 | + TMTMD = TMTMD_TMTLDE; | |
| 63 | + TMTMD = TMTMD_TMTCNE; | |
| 64 | + tmp = TMTMD; | |
| 65 | +} | |
| 66 | + | |
| 67 | +#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_CLOCKEVENTS) && \ | |
| 68 | + !defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) | |
| 69 | +/* | |
| 70 | + * If we aren't using broadcasting, each core needs its own event timer. | |
| 71 | + * Since CPU0 uses the tick timer which is 24-bits, we use timer 4 & 5 | |
| 72 | + * cascaded to 32-bits for CPU1 (but only really use 24-bits to match | |
| 73 | + * CPU0). | |
| 74 | + */ | |
| 75 | + | |
| 76 | +#define TMJC1IRQ TM5IRQ | |
| 77 | + | |
| 78 | +static inline void stop_jiffies_counter1(void) | |
| 79 | +{ | |
| 80 | + u8 tmp; | |
| 81 | + TM4MD = 0; | |
| 82 | + TM5MD = 0; | |
| 83 | + tmp = TM4MD; | |
| 84 | + tmp = TM5MD; | |
| 85 | +} | |
| 86 | + | |
| 87 | +static inline void reload_jiffies_counter1(u32 cnt) | |
| 88 | +{ | |
| 89 | + u32 tmp; | |
| 90 | + | |
| 91 | + TM45BR = cnt; | |
| 92 | + tmp = TM45BR; | |
| 93 | + | |
| 94 | + TM4MD = TM4MD_INIT_COUNTER; | |
| 95 | + tmp = TM4MD; | |
| 96 | + | |
| 97 | + TM5MD = TM5MD_SRC_TM4CASCADE | TM5MD_INIT_COUNTER; | |
| 98 | + TM5MD = TM5MD_SRC_TM4CASCADE | TM5MD_COUNT_ENABLE; | |
| 99 | + tmp = TM5MD; | |
| 100 | + | |
| 101 | + TM4MD = TM4MD_COUNT_ENABLE; | |
| 102 | + tmp = TM4MD; | |
| 103 | +} | |
| 104 | +#endif /* CONFIG_SMP&GENERIC_CLOCKEVENTS&!GENERIC_CLOCKEVENTS_BROADCAST */ | |
| 105 | + | |
| 106 | +#endif /* !__ASSEMBLY__ */ | |
| 107 | + | |
| 108 | + | |
| 109 | +/* | |
| 110 | + * timestamp counter specifications | |
| 111 | + */ | |
| 112 | +#define TMTSCBR_MAX 0xffffffff | |
| 113 | + | |
| 114 | +#ifndef __ASSEMBLY__ | |
| 115 | + | |
| 116 | +/* Use 32-bit timestamp counter */ | |
| 117 | +#define TMTSCMD TMSMD | |
| 118 | +#define TMTSCBR TMSBR | |
| 119 | +#define TMTSCBC TMSBC | |
| 120 | +#define TMTSCICR TMSICR | |
| 121 | + | |
| 122 | +static inline void startup_timestamp_counter(void) | |
| 123 | +{ | |
| 124 | + u32 sync; | |
| 125 | + | |
| 126 | + /* set up TMS(Timestamp) 32bit timer register to count real time | |
| 127 | + * - count down from 4Gig-1 to 0 and wrap at IOBCLK rate | |
| 128 | + */ | |
| 129 | + | |
| 130 | + TMTSCBR = TMTSCBR_MAX; | |
| 131 | + sync = TMTSCBR; | |
| 132 | + | |
| 133 | + TMTSCICR = 0; | |
| 134 | + sync = TMTSCICR; | |
| 135 | + | |
| 136 | + TMTSCMD = TMTMD_TMTLDE; | |
| 137 | + TMTSCMD = TMTMD_TMTCNE; | |
| 138 | + sync = TMTSCMD; | |
| 139 | +} | |
| 140 | + | |
| 141 | +static inline void shutdown_timestamp_counter(void) | |
| 142 | +{ | |
| 143 | + TMTSCMD = 0; | |
| 144 | +} | |
| 145 | + | |
| 146 | +/* | |
| 147 | + * we use a cascaded pair of 16-bit down-counting timers to count I/O | |
| 148 | + * clock cycles for the purposes of time keeping | |
| 149 | + */ | |
| 150 | +typedef unsigned long cycles_t; | |
| 151 | + | |
| 152 | +static inline cycles_t read_timestamp_counter(void) | |
| 153 | +{ | |
| 154 | + return (cycles_t)~TMTSCBC; | |
| 155 | +} | |
| 156 | + | |
| 157 | +#endif /* !__ASSEMBLY__ */ | |
| 158 | + | |
| 159 | +#endif /* _ASM_UNIT_TIMEX_H */ | |
| @@ -0,0 +1,96 @@ | ||
| 1 | +/* ASB2364 FPGA interrupt multiplexing | |
| 2 | + * | |
| 3 | + * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public Licence | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the Licence, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <linux/interrupt.h> | |
| 13 | +#include <linux/init.h> | |
| 14 | +#include <linux/irq.h> | |
| 15 | +#include <unit/fpga-regs.h> | |
| 16 | + | |
| 17 | +/* | |
| 18 | + * FPGA PIC operations | |
| 19 | + */ | |
| 20 | +static void asb2364_fpga_mask(unsigned int irq) | |
| 21 | +{ | |
| 22 | + ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0001; | |
| 23 | + SyncExBus(); | |
| 24 | +} | |
| 25 | + | |
| 26 | +static void asb2364_fpga_ack(unsigned int irq) | |
| 27 | +{ | |
| 28 | + ASB2364_FPGA_REG_IRQ(irq - NR_CPU_IRQS) = 0x0001; | |
| 29 | + SyncExBus(); | |
| 30 | +} | |
| 31 | + | |
| 32 | +static void asb2364_fpga_mask_ack(unsigned int irq) | |
| 33 | +{ | |
| 34 | + ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0001; | |
| 35 | + SyncExBus(); | |
| 36 | + ASB2364_FPGA_REG_IRQ(irq - NR_CPU_IRQS) = 0x0001; | |
| 37 | + SyncExBus(); | |
| 38 | +} | |
| 39 | + | |
| 40 | +static void asb2364_fpga_unmask(unsigned int irq) | |
| 41 | +{ | |
| 42 | + ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0000; | |
| 43 | + SyncExBus(); | |
| 44 | +} | |
| 45 | + | |
| 46 | +static struct irq_chip asb2364_fpga_pic = { | |
| 47 | + .name = "fpga", | |
| 48 | + .ack = asb2364_fpga_ack, | |
| 49 | + .mask = asb2364_fpga_mask, | |
| 50 | + .mask_ack = asb2364_fpga_mask_ack, | |
| 51 | + .unmask = asb2364_fpga_unmask, | |
| 52 | +}; | |
| 53 | + | |
| 54 | +/* | |
| 55 | + * FPGA PIC interrupt handler | |
| 56 | + */ | |
| 57 | +static irqreturn_t fpga_interrupt(int irq, void *_mask) | |
| 58 | +{ | |
| 59 | + if ((ASB2364_FPGA_REG_IRQ_LAN & 0x0001) != 0x0001) | |
| 60 | + generic_handle_irq(FPGA_LAN_IRQ); | |
| 61 | + if ((ASB2364_FPGA_REG_IRQ_UART & 0x0001) != 0x0001) | |
| 62 | + generic_handle_irq(FPGA_UART_IRQ); | |
| 63 | + if ((ASB2364_FPGA_REG_IRQ_I2C & 0x0001) != 0x0001) | |
| 64 | + generic_handle_irq(FPGA_I2C_IRQ); | |
| 65 | + if ((ASB2364_FPGA_REG_IRQ_USB & 0x0001) != 0x0001) | |
| 66 | + generic_handle_irq(FPGA_USB_IRQ); | |
| 67 | + if ((ASB2364_FPGA_REG_IRQ_FPGA & 0x0001) != 0x0001) | |
| 68 | + generic_handle_irq(FPGA_FPGA_IRQ); | |
| 69 | + | |
| 70 | + return IRQ_HANDLED; | |
| 71 | +} | |
| 72 | + | |
| 73 | +/* | |
| 74 | + * Define an interrupt action for each FPGA PIC output | |
| 75 | + */ | |
| 76 | +static struct irqaction fpga_irq[] = { | |
| 77 | + [0] = { | |
| 78 | + .handler = fpga_interrupt, | |
| 79 | + .flags = IRQF_DISABLED | IRQF_SHARED, | |
| 80 | + .name = "fpga", | |
| 81 | + }, | |
| 82 | +}; | |
| 83 | + | |
| 84 | +/* | |
| 85 | + * Initialise the FPGA's PIC | |
| 86 | + */ | |
| 87 | +void __init irq_fpga_init(void) | |
| 88 | +{ | |
| 89 | + int irq; | |
| 90 | + | |
| 91 | + for (irq = NR_CPU_IRQS; irq < NR_IRQS; irq++) | |
| 92 | + set_irq_chip_and_handler(irq, &asb2364_fpga_pic, handle_level_irq); | |
| 93 | + | |
| 94 | + /* the FPGA drives the XIRQ1 input on the CPU PIC */ | |
| 95 | + setup_irq(XIRQ1, &fpga_irq[0]); | |
| 96 | +} | |
| @@ -0,0 +1,98 @@ | ||
| 1 | +/* leds.c: ASB2364 peripheral 7seg LEDs x4 support | |
| 2 | + * | |
| 3 | + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the License, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <linux/kernel.h> | |
| 13 | +#include <linux/param.h> | |
| 14 | +#include <linux/init.h> | |
| 15 | + | |
| 16 | +#include <asm/io.h> | |
| 17 | +#include <asm/processor.h> | |
| 18 | +#include <asm/intctl-regs.h> | |
| 19 | +#include <asm/rtc-regs.h> | |
| 20 | +#include <unit/leds.h> | |
| 21 | + | |
| 22 | +#if MN10300_USE_7SEGLEDS | |
| 23 | +static const u8 asb2364_led_hex_tbl[16] = { | |
| 24 | + 0x80, 0xf2, 0x48, 0x60, 0x32, 0x24, 0x04, 0xf0, | |
| 25 | + 0x00, 0x20, 0x10, 0x06, 0x8c, 0x42, 0x0c, 0x1c | |
| 26 | +}; | |
| 27 | + | |
| 28 | +static const u32 asb2364_led_chase_tbl[6] = { | |
| 29 | + ~0x02020202, /* top - segA */ | |
| 30 | + ~0x04040404, /* right top - segB */ | |
| 31 | + ~0x08080808, /* right bottom - segC */ | |
| 32 | + ~0x10101010, /* bottom - segD */ | |
| 33 | + ~0x20202020, /* left bottom - segE */ | |
| 34 | + ~0x40404040, /* left top - segF */ | |
| 35 | +}; | |
| 36 | + | |
| 37 | +static unsigned asb2364_led_chase; | |
| 38 | + | |
| 39 | +void peripheral_leds7x4_display_dec(unsigned int val, unsigned int points) | |
| 40 | +{ | |
| 41 | + u32 leds; | |
| 42 | + | |
| 43 | + leds = asb2364_led_hex_tbl[(val/1000) % 10]; | |
| 44 | + leds <<= 8; | |
| 45 | + leds |= asb2364_led_hex_tbl[(val/100) % 10]; | |
| 46 | + leds <<= 8; | |
| 47 | + leds |= asb2364_led_hex_tbl[(val/10) % 10]; | |
| 48 | + leds <<= 8; | |
| 49 | + leds |= asb2364_led_hex_tbl[val % 10]; | |
| 50 | + leds |= points^0x01010101; | |
| 51 | + | |
| 52 | + ASB2364_7SEGLEDS = leds; | |
| 53 | +} | |
| 54 | + | |
| 55 | +void peripheral_leds7x4_display_hex(unsigned int val, unsigned int points) | |
| 56 | +{ | |
| 57 | + u32 leds; | |
| 58 | + | |
| 59 | + leds = asb2364_led_hex_tbl[(val/1000) % 10]; | |
| 60 | + leds <<= 8; | |
| 61 | + leds |= asb2364_led_hex_tbl[(val/100) % 10]; | |
| 62 | + leds <<= 8; | |
| 63 | + leds |= asb2364_led_hex_tbl[(val/10) % 10]; | |
| 64 | + leds <<= 8; | |
| 65 | + leds |= asb2364_led_hex_tbl[val % 10]; | |
| 66 | + leds |= points^0x01010101; | |
| 67 | + | |
| 68 | + ASB2364_7SEGLEDS = leds; | |
| 69 | +} | |
| 70 | + | |
| 71 | +/* display triple horizontal bar and exception code */ | |
| 72 | +void peripheral_leds_display_exception(enum exception_code code) | |
| 73 | +{ | |
| 74 | + u32 leds; | |
| 75 | + | |
| 76 | + leds = asb2364_led_hex_tbl[(code/0x100) % 0x10]; | |
| 77 | + leds <<= 8; | |
| 78 | + leds |= asb2364_led_hex_tbl[(code/0x10) % 0x10]; | |
| 79 | + leds <<= 8; | |
| 80 | + leds |= asb2364_led_hex_tbl[code % 0x10]; | |
| 81 | + leds |= 0x6d010101; | |
| 82 | + | |
| 83 | + ASB2364_7SEGLEDS = leds; | |
| 84 | +} | |
| 85 | + | |
| 86 | +void peripheral_leds_led_chase(void) | |
| 87 | +{ | |
| 88 | + ASB2364_7SEGLEDS = asb2364_led_chase_tbl[asb2364_led_chase]; | |
| 89 | + asb2364_led_chase++; | |
| 90 | + if (asb2364_led_chase >= 6) | |
| 91 | + asb2364_led_chase = 0; | |
| 92 | +} | |
| 93 | +#else /* MN10300_USE_7SEGLEDS */ | |
| 94 | +void peripheral_leds7x4_display_dec(unsigned int val, unsigned int points) { } | |
| 95 | +void peripheral_leds7x4_display_hex(unsigned int val, unsigned int points) { } | |
| 96 | +void peripheral_leds_display_exception(enum exception_code code) { } | |
| 97 | +void peripheral_leds_led_chase(void) { } | |
| 98 | +#endif /* MN10300_USE_7SEGLEDS */ | |
| @@ -0,0 +1,58 @@ | ||
| 1 | +/* Specification for the SMSC911x NIC | |
| 2 | + * | |
| 3 | + * Copyright (C) 2006 Matsushita Electric Industrial Co., Ltd. | |
| 4 | + * All Rights Reserved. | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the License, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <linux/kernel.h> | |
| 13 | +#include <linux/init.h> | |
| 14 | +#include <linux/platform_device.h> | |
| 15 | +#include <linux/io.h> | |
| 16 | +#include <linux/ioport.h> | |
| 17 | +#include <linux/smsc911x.h> | |
| 18 | +#include <unit/smsc911x.h> | |
| 19 | + | |
| 20 | +static struct smsc911x_platform_config smsc911x_config = { | |
| 21 | + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, | |
| 22 | + .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN, | |
| 23 | + .flags = SMSC911X_USE_32BIT, | |
| 24 | +}; | |
| 25 | + | |
| 26 | +static struct resource smsc911x_resources[] = { | |
| 27 | + [0] = { | |
| 28 | + .start = SMSC911X_BASE, | |
| 29 | + .end = SMSC911X_BASE_END, | |
| 30 | + .flags = IORESOURCE_MEM, | |
| 31 | + }, | |
| 32 | + [1] = { | |
| 33 | + .start = SMSC911X_IRQ, | |
| 34 | + .end = SMSC911X_IRQ, | |
| 35 | + .flags = IORESOURCE_IRQ, | |
| 36 | + }, | |
| 37 | +}; | |
| 38 | + | |
| 39 | +static struct platform_device smsc911x_device = { | |
| 40 | + .name = "smsc911x", | |
| 41 | + .id = 0, | |
| 42 | + .num_resources = ARRAY_SIZE(smsc911x_resources), | |
| 43 | + .resource = smsc911x_resources, | |
| 44 | + .dev = { | |
| 45 | + .platform_data = &smsc911x_config, | |
| 46 | + } | |
| 47 | +}; | |
| 48 | + | |
| 49 | +/* | |
| 50 | + * add platform devices | |
| 51 | + */ | |
| 52 | +static int __init unit_device_init(void) | |
| 53 | +{ | |
| 54 | + platform_device_register(&smsc911x_device); | |
| 55 | + return 0; | |
| 56 | +} | |
| 57 | + | |
| 58 | +device_initcall(unit_device_init); | |
| @@ -0,0 +1,88 @@ | ||
| 1 | +/* ASB2364 initialisation | |
| 2 | + * | |
| 3 | + * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | |
| 4 | + * Written by David Howells (dhowells@redhat.com) | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or | |
| 7 | + * modify it under the terms of the GNU General Public License | |
| 8 | + * as published by the Free Software Foundation; either version | |
| 9 | + * 2 of the License, or (at your option) any later version. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <linux/kernel.h> | |
| 13 | +#include <linux/param.h> | |
| 14 | +#include <linux/init.h> | |
| 15 | +#include <linux/device.h> | |
| 16 | +#include <linux/delay.h> | |
| 17 | + | |
| 18 | +#include <asm/io.h> | |
| 19 | +#include <asm/setup.h> | |
| 20 | +#include <asm/processor.h> | |
| 21 | +#include <asm/irq.h> | |
| 22 | +#include <asm/intctl-regs.h> | |
| 23 | +#include <unit/fpga-regs.h> | |
| 24 | + | |
| 25 | +/* | |
| 26 | + * initialise some of the unit hardware before gdbstub is set up | |
| 27 | + */ | |
| 28 | +asmlinkage void __init unit_init(void) | |
| 29 | +{ | |
| 30 | + /* set up the external interrupts */ | |
| 31 | + | |
| 32 | + /* XIRQ[0]: NAND RXBY */ | |
| 33 | + /* SET_XIRQ_TRIGGER(0, XIRQ_TRIGGER_LOWLEVEL); */ | |
| 34 | + | |
| 35 | + /* XIRQ[1]: LAN, UART, I2C, USB, PCI, FPGA */ | |
| 36 | + SET_XIRQ_TRIGGER(1, XIRQ_TRIGGER_LOWLEVEL); | |
| 37 | + | |
| 38 | + /* XIRQ[2]: Extend Slot 1-9 */ | |
| 39 | + /* SET_XIRQ_TRIGGER(2, XIRQ_TRIGGER_LOWLEVEL); */ | |
| 40 | + | |
| 41 | +#if defined(CONFIG_EXT_SERIAL_IRQ_LEVEL) && \ | |
| 42 | + defined(CONFIG_ETHERNET_IRQ_LEVEL) && \ | |
| 43 | + (CONFIG_EXT_SERIAL_IRQ_LEVEL != CONFIG_ETHERNET_IRQ_LEVEL) | |
| 44 | +# error CONFIG_EXT_SERIAL_IRQ_LEVEL != CONFIG_ETHERNET_IRQ_LEVEL | |
| 45 | +#endif | |
| 46 | + | |
| 47 | +#if defined(CONFIG_EXT_SERIAL_IRQ_LEVEL) | |
| 48 | + set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL)); | |
| 49 | +#elif defined(CONFIG_ETHERNET_IRQ_LEVEL) | |
| 50 | + set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_ETHERNET_IRQ_LEVEL)); | |
| 51 | +#endif | |
| 52 | +} | |
| 53 | + | |
| 54 | +/* | |
| 55 | + * initialise the rest of the unit hardware after gdbstub is ready | |
| 56 | + */ | |
| 57 | +asmlinkage void __init unit_setup(void) | |
| 58 | +{ | |
| 59 | + | |
| 60 | +} | |
| 61 | + | |
| 62 | +/* | |
| 63 | + * initialise the external interrupts used by a unit of this type | |
| 64 | + */ | |
| 65 | +void __init unit_init_IRQ(void) | |
| 66 | +{ | |
| 67 | + unsigned int extnum; | |
| 68 | + | |
| 69 | + for (extnum = 0 ; extnum < NR_XIRQS ; extnum++) { | |
| 70 | + switch (GET_XIRQ_TRIGGER(extnum)) { | |
| 71 | + /* LEVEL triggered interrupts should be made | |
| 72 | + * post-ACK'able as they hold their lines until | |
| 73 | + * serviced | |
| 74 | + */ | |
| 75 | + case XIRQ_TRIGGER_HILEVEL: | |
| 76 | + case XIRQ_TRIGGER_LOWLEVEL: | |
| 77 | + mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum)); | |
| 78 | + break; | |
| 79 | + default: | |
| 80 | + break; | |
| 81 | + } | |
| 82 | + } | |
| 83 | + | |
| 84 | +#define IRQCTL __SYSREG(0xd5000090, u32) | |
| 85 | + IRQCTL |= 0x02; | |
| 86 | + | |
| 87 | + irq_fpga_init(); | |
| 88 | +} | |
| @@ -1041,7 +1041,7 @@ config SMC911X · 1040 unmodified lines | ||
| 1041 | 1041 | tristate "SMSC LAN911[5678] support" |
| 1042 | 1042 | select CRC32 |
| 1043 | 1043 | select MII |
| 1044 | − depends on ARM || SUPERH | |
| 1044 | + depends on ARM || SUPERH || MN10300 | |
| 1045 | 1045 | help |
| 1046 | 1046 | This is a driver for SMSC's LAN911x series of Ethernet chipsets |
| 1047 | 1047 | including the new LAN9115, LAN9116, LAN9117, and LAN9118. |
| @@ -1055,7 +1055,7 @@ config SMC911X · 7 unmodified lines | ||
| 1055 | 1055 | |
| 1056 | 1056 | config SMSC911X |
| 1057 | 1057 | tristate "SMSC LAN911x/LAN921x families embedded ethernet support" |
| 1058 | − depends on ARM || SUPERH || BLACKFIN || MIPS | |
| 1058 | + depends on ARM || SUPERH || BLACKFIN || MIPS || MN10300 | |
| 1059 | 1059 | select CRC32 |
| 1060 | 1060 | select MII |
| 1061 | 1061 | select PHYLIB |
| @@ -1067,6 +1067,14 @@ config SMSC911X · 5 unmodified lines | ||
| 1067 | 1067 | <file:Documentation/networking/net-modules.txt>. The module |
| 1068 | 1068 | will be called smsc911x. |
| 1069 | 1069 | |
| 1070 | +config SMSC911X_ARCH_HOOKS | |
| 1071 | + def_bool n | |
| 1072 | + depends on SMSC911X | |
| 1073 | + help | |
| 1074 | + If the arch enables this, it allows the arch to implement various | |
| 1075 | + hooks for more comprehensive interrupt control and also to override | |
| 1076 | + the source of the MAC address. | |
| 1077 | + | |
| 1070 | 1078 | config NET_VENDOR_RACAL |
| 1071 | 1079 | bool "Racal-Interlan (Micom) NI cards" |
| 1072 | 1080 | depends on ISA |
| @@ -2075,7 +2075,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) · 2074 unmodified lines | ||
| 2075 | 2075 | } else { |
| 2076 | 2076 | /* Try reading mac address from device. if EEPROM is present |
| 2077 | 2077 | * it will already have been set */ |
| 2078 | − smsc911x_read_mac_address(dev); | |
| 2078 | + smsc_get_mac(dev); | |
| 2079 | 2079 | |
| 2080 | 2080 | if (is_valid_ether_addr(dev->dev_addr)) { |
| 2081 | 2081 | /* eeprom values are valid so use them */ |
| @@ -2176,6 +2176,7 @@ static struct platform_driver smsc911x_driver = { · 94 unmodified lines | ||
| 2176 | 2176 | /* Entry point for loading the module */ |
| 2177 | 2177 | static int __init smsc911x_init_module(void) |
| 2178 | 2178 | { |
| 2179 | + SMSC_INITIALIZE(); | |
| 2179 | 2180 | return platform_driver_register(&smsc911x_driver); |
| 2180 | 2181 | } |
| 2181 | 2182 | |
| @@ -394,4 +394,15 @@ · 393 unmodified lines | ||
| 394 | 394 | #define LPA_PAUSE_ALL (LPA_PAUSE_CAP | \ |
| 395 | 395 | LPA_PAUSE_ASYM) |
| 396 | 396 | |
| 397 | +/* | |
| 398 | + * Provide hooks to let the arch add to the initialisation procedure | |
| 399 | + * and to override the source of the MAC address. | |
| 400 | + */ | |
| 401 | +#define SMSC_INITIALIZE() do {} while (0) | |
| 402 | +#define smsc_get_mac(dev) smsc911x_read_mac_address((dev)) | |
| 403 | + | |
| 404 | +#ifdef CONFIG_SMSC911X_ARCH_HOOKS | |
| 405 | +#include <asm/smsc911x.h> | |
| 406 | +#endif | |
| 407 | + | |
| 397 | 408 | #endif /* __SMSC911X_H__ */ |
| @@ -13,9 +13,10 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | extern void cpu_idle(void); |
| 15 | 15 | |
| 16 | +typedef void (*smp_call_func_t)(void *info); | |
| 16 | 17 | struct call_single_data { |
| 17 | 18 | struct list_head list; |
| 18 | − void (*func) (void *info); | |
| 19 | + smp_call_func_t func; | |
| 19 | 20 | void *info; |
| 20 | 21 | u16 flags; |
| 21 | 22 | u16 priv; |
| @@ -24,8 +25,8 @@ struct call_single_data { · 2 unmodified lines | ||
| 24 | 25 | /* total number of cpus in this system (may exceed NR_CPUS) */ |
| 25 | 26 | extern unsigned int total_cpus; |
| 26 | 27 | |
| 27 | −int smp_call_function_single(int cpuid, void (*func) (void *info), void *info, | |
| 28 | − int wait); | |
| 28 | +int smp_call_function_single(int cpuid, smp_call_func_t func, void *info, | |
| 29 | + int wait); | |
| 29 | 30 | |
| 30 | 31 | #ifdef CONFIG_SMP |
| 31 | 32 | |
| @@ -69,15 +70,15 @@ extern void smp_cpus_done(unsigned int max_cpus); · 37 unmodified lines | ||
| 69 | 70 | /* |
| 70 | 71 | * Call a function on all other processors |
| 71 | 72 | */ |
| 72 | −int smp_call_function(void(*func)(void *info), void *info, int wait); | |
| 73 | +int smp_call_function(smp_call_func_t func, void *info, int wait); | |
| 73 | 74 | void smp_call_function_many(const struct cpumask *mask, |
| 74 | − void (*func)(void *info), void *info, bool wait); | |
| 75 | + smp_call_func_t func, void *info, bool wait); | |
| 75 | 76 | |
| 76 | 77 | void __smp_call_function_single(int cpuid, struct call_single_data *data, |
| 77 | 78 | int wait); |
| 78 | 79 | |
| 79 | 80 | int smp_call_function_any(const struct cpumask *mask, |
| 80 | − void (*func)(void *info), void *info, int wait); | |
| 81 | + smp_call_func_t func, void *info, int wait); | |
| 81 | 82 | |
| 82 | 83 | /* |
| 83 | 84 | * Generic and arch helpers |
| @@ -94,7 +95,7 @@ void ipi_call_unlock_irq(void); · 10 unmodified lines | ||
| 94 | 95 | /* |
| 95 | 96 | * Call a function on all processors |
| 96 | 97 | */ |
| 97 | −int on_each_cpu(void (*func) (void *info), void *info, int wait); | |
| 98 | +int on_each_cpu(smp_call_func_t func, void *info, int wait); | |
| 98 | 99 | |
| 99 | 100 | #define MSG_ALL_BUT_SELF 0x8000 /* Assume <32768 CPU's */ |
| 100 | 101 | #define MSG_ALL 0x8001 |
| @@ -122,7 +123,7 @@ static inline void smp_send_stop(void) { } · 21 unmodified lines | ||
| 122 | 123 | * These macros fold the SMP functionality into a single CPU system |
| 123 | 124 | */ |
| 124 | 125 | #define raw_smp_processor_id() 0 |
| 125 | −static inline int up_smp_call_function(void (*func)(void *), void *info) | |
| 126 | +static inline int up_smp_call_function(smp_call_func_t func, void *info) | |
| 126 | 127 | { |
| 127 | 128 | return 0; |
| 128 | 129 | } |
| @@ -143,7 +144,7 @@ static inline void smp_send_reschedule(int cpu) { } · 14 unmodified lines | ||
| 143 | 144 | static inline void init_call_single_data(void) { } |
| 144 | 145 | |
| 145 | 146 | static inline int |
| 146 | −smp_call_function_any(const struct cpumask *mask, void (*func)(void *info), | |
| 147 | +smp_call_function_any(const struct cpumask *mask, smp_call_func_t func, | |
| 147 | 148 | void *info, int wait) |
| 148 | 149 | { |
| 149 | 150 | return smp_call_function_single(0, func, info, wait); |
| @@ -267,7 +267,7 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data); · 266 unmodified lines | ||
| 267 | 267 | * |
| 268 | 268 | * Returns 0 on success, else a negative status code. |
| 269 | 269 | */ |
| 270 | −int smp_call_function_single(int cpu, void (*func) (void *info), void *info, | |
| 270 | +int smp_call_function_single(int cpu, smp_call_func_t func, void *info, | |
| 271 | 271 | int wait) |
| 272 | 272 | { |
| 273 | 273 | struct call_single_data d = { |
| @@ -336,7 +336,7 @@ EXPORT_SYMBOL(smp_call_function_single); · 62 unmodified lines | ||
| 336 | 336 | * 3) any other online cpu in @mask |
| 337 | 337 | */ |
| 338 | 338 | int smp_call_function_any(const struct cpumask *mask, |
| 339 | − void (*func)(void *info), void *info, int wait) | |
| 339 | + smp_call_func_t func, void *info, int wait) | |
| 340 | 340 | { |
| 341 | 341 | unsigned int cpu; |
| 342 | 342 | const struct cpumask *nodemask; |
| @@ -416,7 +416,7 @@ void __smp_call_function_single(int cpu, struct call_single_data *data, · 73 unmodified lines | ||
| 416 | 416 | * must be disabled when calling this function. |
| 417 | 417 | */ |
| 418 | 418 | void smp_call_function_many(const struct cpumask *mask, |
| 419 | − void (*func)(void *), void *info, bool wait) | |
| 419 | + smp_call_func_t func, void *info, bool wait) | |
| 420 | 420 | { |
| 421 | 421 | struct call_function_data *data; |
| 422 | 422 | unsigned long flags; |
| @@ -500,7 +500,7 @@ EXPORT_SYMBOL(smp_call_function_many); · 77 unmodified lines | ||
| 500 | 500 | * You must not call this function with disabled interrupts or from a |
| 501 | 501 | * hardware interrupt handler or from a bottom half handler. |
| 502 | 502 | */ |
| 503 | −int smp_call_function(void (*func)(void *), void *info, int wait) | |
| 503 | +int smp_call_function(smp_call_func_t func, void *info, int wait) | |
| 504 | 504 | { |
| 505 | 505 | preempt_disable(); |
| 506 | 506 | smp_call_function_many(cpu_online_mask, func, info, wait); |
| @@ -1,9 +1,9 @@ | ||
| 1 | 1 | /* |
| 2 | 2 | * Access kernel memory without faulting. |
| 3 | 3 | */ |
| 4 | −#include <linux/uaccess.h> | |
| 5 | 4 | #include <linux/module.h> |
| 6 | 5 | #include <linux/mm.h> |
| 6 | +#include <linux/uaccess.h> | |
| 7 | 7 | |
| 8 | 8 | /** |
| 9 | 9 | * probe_kernel_read(): safely attempt to read from a location |