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

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>

+19 -6
+19 -6
arch/arc/mm/cache_arc700.c
··· 389 389 /*********************************************************** 390 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 393 unsigned long sz) 394 394 { 395 395 unsigned long flags; ··· 405 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 425 #else 409 426 410 427 #define __ic_entire_inv() ··· 570 553 */ 571 554 void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len) 572 555 { 573 - unsigned long flags; 574 - 575 - local_irq_save(flags); 576 - __ic_line_inv_vaddr(paddr, vaddr, len); 577 556 __dc_line_op(paddr, vaddr, len, OP_FLUSH_N_INV); 578 - local_irq_restore(flags); 557 + __ic_line_inv_vaddr(paddr, vaddr, len); 579 558 } 580 559 581 560 /* wrapper to compile time eliminate alignment checks in flush loop */