diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2005-06-13 16:24:00 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2005-10-29 14:31:22 -0400 |
commit | fded2e508a1d3c26ab477ab3b98f13274d4359ba (patch) | |
tree | a720d2799e7ea32cb96d664bc55b2aa149b77550 | |
parent | d925c262dd8bee2202b0d1b85ce0b332f48dd34b (diff) |
Optimize R3k TLB Load/Store/Modified handlers, by scheduling
delay slots properly and avoiding an unnecessary jump to a jump.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | arch/mips/mm/tlbex.c | 70 |
1 files changed, 30 insertions, 40 deletions
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 68d24b80053b..48546d18a5a3 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * Synthesize TLB refill handlers at runtime. | 6 | * Synthesize TLB refill handlers at runtime. |
7 | * | 7 | * |
8 | * Copyright (C) 2004,2005 by Thiemo Seufer | 8 | * Copyright (C) 2004,2005 by Thiemo Seufer |
9 | * Copyright (C) 2005 Maciej W. Rozycki | ||
9 | */ | 10 | */ |
10 | 11 | ||
11 | #include <stdarg.h> | 12 | #include <stdarg.h> |
@@ -410,7 +411,6 @@ enum label_id { | |||
410 | label_nopage_tlbm, | 411 | label_nopage_tlbm, |
411 | label_smp_pgtable_change, | 412 | label_smp_pgtable_change, |
412 | label_r3000_write_probe_fail, | 413 | label_r3000_write_probe_fail, |
413 | label_r3000_write_probe_ok | ||
414 | }; | 414 | }; |
415 | 415 | ||
416 | struct label { | 416 | struct label { |
@@ -443,7 +443,6 @@ L_LA(_nopage_tlbs) | |||
443 | L_LA(_nopage_tlbm) | 443 | L_LA(_nopage_tlbm) |
444 | L_LA(_smp_pgtable_change) | 444 | L_LA(_smp_pgtable_change) |
445 | L_LA(_r3000_write_probe_fail) | 445 | L_LA(_r3000_write_probe_fail) |
446 | L_LA(_r3000_write_probe_ok) | ||
447 | 446 | ||
448 | /* convenience macros for instructions */ | 447 | /* convenience macros for instructions */ |
449 | #ifdef CONFIG_64BIT | 448 | #ifdef CONFIG_64BIT |
@@ -1414,34 +1413,41 @@ build_pte_modifiable(u32 **p, struct label **l, struct reloc **r, | |||
1414 | * R3000 style TLB load/store/modify handlers. | 1413 | * R3000 style TLB load/store/modify handlers. |
1415 | */ | 1414 | */ |
1416 | 1415 | ||
1417 | /* This places the pte in the page table at PTR into ENTRYLO0. */ | 1416 | /* |
1417 | * This places the pte into ENTRYLO0 and writes it with tlbwi. | ||
1418 | * Then it returns. | ||
1419 | */ | ||
1418 | static void __init | 1420 | static void __init |
1419 | build_r3000_pte_reload(u32 **p, unsigned int ptr) | 1421 | build_r3000_pte_reload_tlbwi(u32 **p, unsigned int pte, unsigned int tmp) |
1420 | { | 1422 | { |
1421 | i_lw(p, ptr, 0, ptr); | 1423 | i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */ |
1422 | i_nop(p); /* load delay */ | 1424 | i_mfc0(p, tmp, C0_EPC); /* cp0 delay */ |
1423 | i_mtc0(p, ptr, C0_ENTRYLO0); | 1425 | i_tlbwi(p); |
1424 | i_nop(p); /* cp0 delay */ | 1426 | i_jr(p, tmp); |
1427 | i_rfe(p); /* branch delay */ | ||
1425 | } | 1428 | } |
1426 | 1429 | ||
1427 | /* | 1430 | /* |
1428 | * The index register may have the probe fail bit set, | 1431 | * This places the pte into ENTRYLO0 and writes it with tlbwi |
1429 | * because we would trap on access kseg2, i.e. without refill. | 1432 | * or tlbwr as appropriate. This is because the index register |
1433 | * may have the probe fail bit set as a result of a trap on a | ||
1434 | * kseg2 access, i.e. without refill. Then it returns. | ||
1430 | */ | 1435 | */ |
1431 | static void __init | 1436 | static void __init |
1432 | build_r3000_tlb_write(u32 **p, struct label **l, struct reloc **r, | 1437 | build_r3000_tlb_reload_write(u32 **p, struct label **l, struct reloc **r, |
1433 | unsigned int tmp) | 1438 | unsigned int pte, unsigned int tmp) |
1434 | { | 1439 | { |
1435 | i_mfc0(p, tmp, C0_INDEX); | 1440 | i_mfc0(p, tmp, C0_INDEX); |
1436 | i_nop(p); /* cp0 delay */ | 1441 | i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */ |
1437 | il_bltz(p, r, tmp, label_r3000_write_probe_fail); | 1442 | il_bltz(p, r, tmp, label_r3000_write_probe_fail); /* cp0 delay */ |
1438 | i_nop(p); /* branch delay */ | 1443 | i_mfc0(p, tmp, C0_EPC); /* branch delay */ |
1439 | i_tlbwi(p); | 1444 | i_tlbwi(p); /* cp0 delay */ |
1440 | il_b(p, r, label_r3000_write_probe_ok); | 1445 | i_jr(p, tmp); |
1441 | i_nop(p); /* branch delay */ | 1446 | i_rfe(p); /* branch delay */ |
1442 | l_r3000_write_probe_fail(l, *p); | 1447 | l_r3000_write_probe_fail(l, *p); |
1443 | i_tlbwr(p); | 1448 | i_tlbwr(p); /* cp0 delay */ |
1444 | l_r3000_write_probe_ok(l, *p); | 1449 | i_jr(p, tmp); |
1450 | i_rfe(p); /* branch delay */ | ||
1445 | } | 1451 | } |
1446 | 1452 | ||
1447 | static void __init | 1453 | static void __init |
@@ -1461,17 +1467,7 @@ build_r3000_tlbchange_handler_head(u32 **p, unsigned int pte, | |||
1461 | i_andi(p, pte, pte, 0xffc); /* load delay */ | 1467 | i_andi(p, pte, pte, 0xffc); /* load delay */ |
1462 | i_addu(p, ptr, ptr, pte); | 1468 | i_addu(p, ptr, ptr, pte); |
1463 | i_lw(p, pte, 0, ptr); | 1469 | i_lw(p, pte, 0, ptr); |
1464 | i_nop(p); /* load delay */ | 1470 | i_tlbp(p); /* load delay */ |
1465 | i_tlbp(p); | ||
1466 | } | ||
1467 | |||
1468 | static void __init | ||
1469 | build_r3000_tlbchange_handler_tail(u32 **p, unsigned int tmp) | ||
1470 | { | ||
1471 | i_mfc0(p, tmp, C0_EPC); | ||
1472 | i_nop(p); /* cp0 delay */ | ||
1473 | i_jr(p, tmp); | ||
1474 | i_rfe(p); /* branch delay */ | ||
1475 | } | 1471 | } |
1476 | 1472 | ||
1477 | static void __init build_r3000_tlb_load_handler(void) | 1473 | static void __init build_r3000_tlb_load_handler(void) |
@@ -1488,9 +1484,7 @@ static void __init build_r3000_tlb_load_handler(void) | |||
1488 | build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl); | 1484 | build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl); |
1489 | i_nop(&p); /* load delay */ | 1485 | i_nop(&p); /* load delay */ |
1490 | build_make_valid(&p, &r, K0, K1); | 1486 | build_make_valid(&p, &r, K0, K1); |
1491 | build_r3000_pte_reload(&p, K1); | 1487 | build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); |
1492 | build_r3000_tlb_write(&p, &l, &r, K0); | ||
1493 | build_r3000_tlbchange_handler_tail(&p, K0); | ||
1494 | 1488 | ||
1495 | l_nopage_tlbl(&l, p); | 1489 | l_nopage_tlbl(&l, p); |
1496 | i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff); | 1490 | i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff); |
@@ -1530,9 +1524,7 @@ static void __init build_r3000_tlb_store_handler(void) | |||
1530 | build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs); | 1524 | build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs); |
1531 | i_nop(&p); /* load delay */ | 1525 | i_nop(&p); /* load delay */ |
1532 | build_make_write(&p, &r, K0, K1); | 1526 | build_make_write(&p, &r, K0, K1); |
1533 | build_r3000_pte_reload(&p, K1); | 1527 | build_r3000_tlb_reload_write(&p, &l, &r, K0, K1); |
1534 | build_r3000_tlb_write(&p, &l, &r, K0); | ||
1535 | build_r3000_tlbchange_handler_tail(&p, K0); | ||
1536 | 1528 | ||
1537 | l_nopage_tlbs(&l, p); | 1529 | l_nopage_tlbs(&l, p); |
1538 | i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); | 1530 | i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); |
@@ -1572,9 +1564,7 @@ static void __init build_r3000_tlb_modify_handler(void) | |||
1572 | build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm); | 1564 | build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm); |
1573 | i_nop(&p); /* load delay */ | 1565 | i_nop(&p); /* load delay */ |
1574 | build_make_write(&p, &r, K0, K1); | 1566 | build_make_write(&p, &r, K0, K1); |
1575 | build_r3000_pte_reload(&p, K1); | 1567 | build_r3000_pte_reload_tlbwi(&p, K0, K1); |
1576 | i_tlbwi(&p); | ||
1577 | build_r3000_tlbchange_handler_tail(&p, K0); | ||
1578 | 1568 | ||
1579 | l_nopage_tlbm(&l, p); | 1569 | l_nopage_tlbm(&l, p); |
1580 | i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); | 1570 | i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff); |