diff options
| author | Vineet Gupta <vgupta@synopsys.com> | 2013-02-17 05:51:42 -0500 |
|---|---|---|
| committer | Vineet Gupta <vgupta@synopsys.com> | 2014-06-26 02:29:01 -0400 |
| commit | 2328af0c9ce89d3ec121ba832c4e6faeff9e70ac (patch) | |
| tree | a76007060d64b0f37627e1094bbae30c32657e1c | |
| parent | 7e5122190b47c2574eda26aa0bbda693b2821449 (diff) | |
ARC: [SMP] Enable icache coherency
icaches are not snooped hence not cohrent in SMP setups which means
kernel has to do cross core calls to ensure the same.
The leaf routine __ic_line_inv_vaddr() now does cross core calls.
__sync_icache_dcache() is affected due to this:
* local dcache line flushed ahead of remote icache inv requests
* can't disable interrupts anymore, since
__ic_line_inv_vaddr()->on_each_cpu() can deadlock.
| WARNING: CPU: 0 PID: 1 at kernel/smp.c:374
| smp_call_function_many+0x25a/0x2c4()
|
| init_kprobes+0x90/0xc8
| register_kprobe+0x1d6/0x510
| __sync_icache_dcache+0x28/0x80
|
| DISABLE IRQ
|
| __ic_line_inv_vaddr
| on_each_cpu
| smp_call_function_many+0x25a/0x2c4 --> WARN
| __ic_line_inv_vaddr_local
| __dc_line_op
* TODO: Needs to use mask of relevant CPUs to avoid broadcasting
Signed-off-by: Noam Camus <noamc@ezchip.com>
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
| -rw-r--r-- | arch/arc/mm/cache_arc700.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c index 1f676c4794e0..353b202c37c9 100644 --- a/arch/arc/mm/cache_arc700.c +++ b/arch/arc/mm/cache_arc700.c | |||
| @@ -389,7 +389,7 @@ static inline void __dc_line_op(unsigned long paddr, unsigned long vaddr, | |||
| 389 | /*********************************************************** | 389 | /*********************************************************** |
| 390 | * Machine specific helper for per line I-Cache invalidate. | 390 | * Machine specific helper for per line I-Cache invalidate. |
| 391 | */ | 391 | */ |
| 392 | static void __ic_line_inv_vaddr(unsigned long paddr, unsigned long vaddr, | 392 | static void __ic_line_inv_vaddr_local(unsigned long paddr, unsigned long vaddr, |
| 393 | unsigned long sz) | 393 | unsigned long sz) |
| 394 | { | 394 | { |
| 395 | unsigned long flags; | 395 | unsigned long flags; |
| @@ -405,6 +405,23 @@ static inline void __ic_entire_inv(void) | |||
| 405 | read_aux_reg(ARC_REG_IC_CTRL); /* blocks */ | 405 | read_aux_reg(ARC_REG_IC_CTRL); /* blocks */ |
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | struct ic_line_inv_vaddr_ipi { | ||
| 409 | unsigned long paddr, vaddr; | ||
| 410 | int sz; | ||
| 411 | }; | ||
| 412 | |||
| 413 | static void __ic_line_inv_vaddr_helper(void *info) | ||
| 414 | { | ||
| 415 | struct ic_line_inv_vaddr_ipi *ic_inv = (struct ic_line_inv_vaddr_ipi*) info; | ||
| 416 | __ic_line_inv_vaddr_local(ic_inv->paddr, ic_inv->vaddr, ic_inv->sz); | ||
| 417 | } | ||
| 418 | |||
| 419 | static void __ic_line_inv_vaddr(unsigned long paddr, unsigned long vaddr, | ||
| 420 | unsigned long sz) | ||
| 421 | { | ||
| 422 | struct ic_line_inv_vaddr_ipi ic_inv = { paddr, vaddr , sz}; | ||
| 423 | on_each_cpu(__ic_line_inv_vaddr_helper, &ic_inv, 1); | ||
| 424 | } | ||
| 408 | #else | 425 | #else |
| 409 | 426 | ||
| 410 | #define __ic_entire_inv() | 427 | #define __ic_entire_inv() |
| @@ -553,12 +570,8 @@ void flush_icache_range(unsigned long kstart, unsigned long kend) | |||
| 553 | */ | 570 | */ |
| 554 | void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len) | 571 | void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len) |
| 555 | { | 572 | { |
| 556 | unsigned long flags; | ||
| 557 | |||
| 558 | local_irq_save(flags); | ||
| 559 | __ic_line_inv_vaddr(paddr, vaddr, len); | ||
| 560 | __dc_line_op(paddr, vaddr, len, OP_FLUSH_N_INV); | 573 | __dc_line_op(paddr, vaddr, len, OP_FLUSH_N_INV); |
| 561 | local_irq_restore(flags); | 574 | __ic_line_inv_vaddr(paddr, vaddr, len); |
| 562 | } | 575 | } |
| 563 | 576 | ||
| 564 | /* wrapper to compile time eliminate alignment checks in flush loop */ | 577 | /* wrapper to compile time eliminate alignment checks in flush loop */ |
