aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/lib-64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/lib-64')
-rw-r--r--arch/mips/lib-64/Makefile25
-rw-r--r--arch/mips/lib-64/csum_partial.S242
-rw-r--r--arch/mips/lib-64/dump_tlb.c211
-rw-r--r--arch/mips/lib-64/memset.S142
-rw-r--r--arch/mips/lib-64/watch.S57
5 files changed, 677 insertions, 0 deletions
diff --git a/arch/mips/lib-64/Makefile b/arch/mips/lib-64/Makefile
new file mode 100644
index 000000000000..fd6a2bafdfcf
--- /dev/null
+++ b/arch/mips/lib-64/Makefile
@@ -0,0 +1,25 @@
1#
2# Makefile for MIPS-specific library files..
3#
4
5lib-y += csum_partial.o memset.o watch.o
6
7obj-$(CONFIG_CPU_MIPS32) += dump_tlb.o
8obj-$(CONFIG_CPU_MIPS64) += dump_tlb.o
9obj-$(CONFIG_CPU_NEVADA) += dump_tlb.o
10obj-$(CONFIG_CPU_R10000) += dump_tlb.o
11obj-$(CONFIG_CPU_R3000) += r3k_dump_tlb.o
12obj-$(CONFIG_CPU_R4300) += dump_tlb.o
13obj-$(CONFIG_CPU_R4X00) += dump_tlb.o
14obj-$(CONFIG_CPU_R5000) += dump_tlb.o
15obj-$(CONFIG_CPU_R5432) += dump_tlb.o
16obj-$(CONFIG_CPU_R6000) +=
17obj-$(CONFIG_CPU_R8000) +=
18obj-$(CONFIG_CPU_RM7000) += dump_tlb.o
19obj-$(CONFIG_CPU_RM9000) += dump_tlb.o
20obj-$(CONFIG_CPU_SB1) += dump_tlb.o
21obj-$(CONFIG_CPU_TX39XX) += r3k_dump_tlb.o
22obj-$(CONFIG_CPU_TX49XX) += dump_tlb.o
23obj-$(CONFIG_CPU_VR41XX) += dump_tlb.o
24
25EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/lib-64/csum_partial.S b/arch/mips/lib-64/csum_partial.S
new file mode 100644
index 000000000000..25aba660cc9c
--- /dev/null
+++ b/arch/mips/lib-64/csum_partial.S
@@ -0,0 +1,242 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Quick'n'dirty IP checksum ...
7 *
8 * Copyright (C) 1998, 1999 Ralf Baechle
9 * Copyright (C) 1999 Silicon Graphics, Inc.
10 */
11#include <asm/asm.h>
12#include <asm/regdef.h>
13
14#define ADDC(sum,reg) \
15 addu sum, reg; \
16 sltu v1, sum, reg; \
17 addu sum, v1
18
19#define CSUM_BIGCHUNK(src, offset, sum, t0, t1, t2, t3) \
20 lw t0, (offset + 0x00)(src); \
21 lw t1, (offset + 0x04)(src); \
22 lw t2, (offset + 0x08)(src); \
23 lw t3, (offset + 0x0c)(src); \
24 ADDC(sum, t0); \
25 ADDC(sum, t1); \
26 ADDC(sum, t2); \
27 ADDC(sum, t3); \
28 lw t0, (offset + 0x10)(src); \
29 lw t1, (offset + 0x14)(src); \
30 lw t2, (offset + 0x18)(src); \
31 lw t3, (offset + 0x1c)(src); \
32 ADDC(sum, t0); \
33 ADDC(sum, t1); \
34 ADDC(sum, t2); \
35 ADDC(sum, t3); \
36
37/*
38 * a0: source address
39 * a1: length of the area to checksum
40 * a2: partial checksum
41 */
42
43#define src a0
44#define sum v0
45
46 .text
47 .set noreorder
48
49/* unknown src alignment and < 8 bytes to go */
50small_csumcpy:
51 move a1, ta2
52
53 andi ta0, a1, 4
54 beqz ta0, 1f
55 andi ta0, a1, 2
56
57 /* Still a full word to go */
58 ulw ta1, (src)
59 daddiu src, 4
60 ADDC(sum, ta1)
61
621: move ta1, zero
63 beqz ta0, 1f
64 andi ta0, a1, 1
65
66 /* Still a halfword to go */
67 ulhu ta1, (src)
68 daddiu src, 2
69
701: beqz ta0, 1f
71 sll ta1, ta1, 16
72
73 lbu ta2, (src)
74 nop
75
76#ifdef __MIPSEB__
77 sll ta2, ta2, 8
78#endif
79 or ta1, ta2
80
811: ADDC(sum, ta1)
82
83 /* fold checksum */
84 sll v1, sum, 16
85 addu sum, v1
86 sltu v1, sum, v1
87 srl sum, sum, 16
88 addu sum, v1
89
90 /* odd buffer alignment? */
91 beqz t3, 1f
92 nop
93 sll v1, sum, 8
94 srl sum, sum, 8
95 or sum, v1
96 andi sum, 0xffff
971:
98 .set reorder
99 /* Add the passed partial csum. */
100 ADDC(sum, a2)
101 jr ra
102 .set noreorder
103
104/* ------------------------------------------------------------------------- */
105
106 .align 5
107LEAF(csum_partial)
108 move sum, zero
109 move t3, zero
110
111 sltiu t8, a1, 0x8
112 bnez t8, small_csumcpy /* < 8 bytes to copy */
113 move ta2, a1
114
115 beqz a1, out
116 andi t3, src, 0x1 /* odd buffer? */
117
118hword_align:
119 beqz t3, word_align
120 andi t8, src, 0x2
121
122 lbu ta0, (src)
123 dsubu a1, a1, 0x1
124#ifdef __MIPSEL__
125 sll ta0, ta0, 8
126#endif
127 ADDC(sum, ta0)
128 daddu src, src, 0x1
129 andi t8, src, 0x2
130
131word_align:
132 beqz t8, dword_align
133 sltiu t8, a1, 56
134
135 lhu ta0, (src)
136 dsubu a1, a1, 0x2
137 ADDC(sum, ta0)
138 sltiu t8, a1, 56
139 daddu src, src, 0x2
140
141dword_align:
142 bnez t8, do_end_words
143 move t8, a1
144
145 andi t8, src, 0x4
146 beqz t8, qword_align
147 andi t8, src, 0x8
148
149 lw ta0, 0x00(src)
150 dsubu a1, a1, 0x4
151 ADDC(sum, ta0)
152 daddu src, src, 0x4
153 andi t8, src, 0x8
154
155qword_align:
156 beqz t8, oword_align
157 andi t8, src, 0x10
158
159 lw ta0, 0x00(src)
160 lw ta1, 0x04(src)
161 dsubu a1, a1, 0x8
162 ADDC(sum, ta0)
163 ADDC(sum, ta1)
164 daddu src, src, 0x8
165 andi t8, src, 0x10
166
167oword_align:
168 beqz t8, begin_movement
169 dsrl t8, a1, 0x7
170
171 lw ta3, 0x08(src)
172 lw t0, 0x0c(src)
173 lw ta0, 0x00(src)
174 lw ta1, 0x04(src)
175 ADDC(sum, ta3)
176 ADDC(sum, t0)
177 ADDC(sum, ta0)
178 ADDC(sum, ta1)
179 dsubu a1, a1, 0x10
180 daddu src, src, 0x10
181 dsrl t8, a1, 0x7
182
183begin_movement:
184 beqz t8, 1f
185 andi ta2, a1, 0x40
186
187move_128bytes:
188 CSUM_BIGCHUNK(src, 0x00, sum, ta0, ta1, ta3, t0)
189 CSUM_BIGCHUNK(src, 0x20, sum, ta0, ta1, ta3, t0)
190 CSUM_BIGCHUNK(src, 0x40, sum, ta0, ta1, ta3, t0)
191 CSUM_BIGCHUNK(src, 0x60, sum, ta0, ta1, ta3, t0)
192 dsubu t8, t8, 0x01
193 bnez t8, move_128bytes
194 daddu src, src, 0x80
195
1961:
197 beqz ta2, 1f
198 andi ta2, a1, 0x20
199
200move_64bytes:
201 CSUM_BIGCHUNK(src, 0x00, sum, ta0, ta1, ta3, t0)
202 CSUM_BIGCHUNK(src, 0x20, sum, ta0, ta1, ta3, t0)
203 daddu src, src, 0x40
204
2051:
206 beqz ta2, do_end_words
207 andi t8, a1, 0x1c
208
209move_32bytes:
210 CSUM_BIGCHUNK(src, 0x00, sum, ta0, ta1, ta3, t0)
211 andi t8, a1, 0x1c
212 daddu src, src, 0x20
213
214do_end_words:
215 beqz t8, maybe_end_cruft
216 dsrl t8, t8, 0x2
217
218end_words:
219 lw ta0, (src)
220 dsubu t8, t8, 0x1
221 ADDC(sum, ta0)
222 bnez t8, end_words
223 daddu src, src, 0x4
224
225maybe_end_cruft:
226 andi ta2, a1, 0x3
227
228small_memcpy:
229 j small_csumcpy; move a1, ta2 /* XXX ??? */
230 beqz t2, out
231 move a1, ta2
232
233end_bytes:
234 lb ta0, (src)
235 dsubu a1, a1, 0x1
236 bnez a2, end_bytes
237 daddu src, src, 0x1
238
239out:
240 jr ra
241 move v0, sum
242 END(csum_partial)
diff --git a/arch/mips/lib-64/dump_tlb.c b/arch/mips/lib-64/dump_tlb.c
new file mode 100644
index 000000000000..42f88e055b4c
--- /dev/null
+++ b/arch/mips/lib-64/dump_tlb.c
@@ -0,0 +1,211 @@
1/*
2 * Dump R4x00 TLB for debugging purposes.
3 *
4 * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle.
5 * Copyright (C) 1999 by Silicon Graphics, Inc.
6 */
7#include <linux/config.h>
8#include <linux/kernel.h>
9#include <linux/mm.h>
10#include <linux/sched.h>
11#include <linux/string.h>
12
13#include <asm/bootinfo.h>
14#include <asm/cachectl.h>
15#include <asm/cpu.h>
16#include <asm/mipsregs.h>
17#include <asm/page.h>
18#include <asm/pgtable.h>
19
20static inline const char *msk2str(unsigned int mask)
21{
22 switch (mask) {
23 case PM_4K: return "4kb";
24 case PM_16K: return "16kb";
25 case PM_64K: return "64kb";
26 case PM_256K: return "256kb";
27#ifndef CONFIG_CPU_VR41XX
28 case PM_1M: return "1Mb";
29 case PM_4M: return "4Mb";
30 case PM_16M: return "16Mb";
31 case PM_64M: return "64Mb";
32 case PM_256M: return "256Mb";
33#endif
34 }
35
36 return "unknown";
37}
38
39#define BARRIER() \
40 __asm__ __volatile__( \
41 ".set\tnoreorder\n\t" \
42 "nop;nop;nop;nop;nop;nop;nop\n\t" \
43 ".set\treorder");
44
45void dump_tlb(int first, int last)
46{
47 unsigned long s_entryhi, entryhi, entrylo0, entrylo1, asid;
48 unsigned int s_index, pagemask, c0, c1, i;
49
50 s_entryhi = read_c0_entryhi();
51 s_index = read_c0_index();
52 asid = s_entryhi & 0xff;
53
54 for (i = first; i <= last; i++) {
55 write_c0_index(i);
56 BARRIER();
57 tlb_read();
58 BARRIER();
59 pagemask = read_c0_pagemask();
60 entryhi = read_c0_entryhi();
61 entrylo0 = read_c0_entrylo0();
62 entrylo1 = read_c0_entrylo1();
63
64 /* Unused entries have a virtual address of CKSEG0. */
65 if ((entryhi & ~0x1ffffUL) != CKSEG0
66 && (entryhi & 0xff) == asid) {
67 /*
68 * Only print entries in use
69 */
70 printk("Index: %2d pgmask=%s ", i, msk2str(pagemask));
71
72 c0 = (entrylo0 >> 3) & 7;
73 c1 = (entrylo1 >> 3) & 7;
74
75 printk("va=%011lx asid=%02lx\n",
76 (entryhi & ~0x1fffUL),
77 entryhi & 0xff);
78 printk("\t[pa=%011lx c=%d d=%d v=%d g=%ld] ",
79 (entrylo0 << 6) & PAGE_MASK, c0,
80 (entrylo0 & 4) ? 1 : 0,
81 (entrylo0 & 2) ? 1 : 0,
82 (entrylo0 & 1));
83 printk("[pa=%011lx c=%d d=%d v=%d g=%ld]\n",
84 (entrylo1 << 6) & PAGE_MASK, c1,
85 (entrylo1 & 4) ? 1 : 0,
86 (entrylo1 & 2) ? 1 : 0,
87 (entrylo1 & 1));
88 }
89 }
90 printk("\n");
91
92 write_c0_entryhi(s_entryhi);
93 write_c0_index(s_index);
94}
95
96void dump_tlb_all(void)
97{
98 dump_tlb(0, current_cpu_data.tlbsize - 1);
99}
100
101void dump_tlb_wired(void)
102{
103 int wired;
104
105 wired = read_c0_wired();
106 printk("Wired: %d", wired);
107 dump_tlb(0, read_c0_wired());
108}
109
110void dump_tlb_addr(unsigned long addr)
111{
112 unsigned int flags, oldpid;
113 int index;
114
115 local_irq_save(flags);
116 oldpid = read_c0_entryhi() & 0xff;
117 BARRIER();
118 write_c0_entryhi((addr & PAGE_MASK) | oldpid);
119 BARRIER();
120 tlb_probe();
121 BARRIER();
122 index = read_c0_index();
123 write_c0_entryhi(oldpid);
124 local_irq_restore(flags);
125
126 if (index < 0) {
127 printk("No entry for address 0x%08lx in TLB\n", addr);
128 return;
129 }
130
131 printk("Entry %d maps address 0x%08lx\n", index, addr);
132 dump_tlb(index, index);
133}
134
135void dump_tlb_nonwired(void)
136{
137 dump_tlb(read_c0_wired(), current_cpu_data.tlbsize - 1);
138}
139
140void dump_list_process(struct task_struct *t, void *address)
141{
142 pgd_t *page_dir, *pgd;
143 pmd_t *pmd;
144 pte_t *pte, page;
145 unsigned long addr, val;
146
147 addr = (unsigned long) address;
148
149 printk("Addr == %08lx\n", addr);
150 printk("tasks->mm.pgd == %08lx\n", (unsigned long) t->mm->pgd);
151
152 page_dir = pgd_offset(t->mm, 0);
153 printk("page_dir == %016lx\n", (unsigned long) page_dir);
154
155 pgd = pgd_offset(t->mm, addr);
156 printk("pgd == %016lx\n", (unsigned long) pgd);
157
158 pmd = pmd_offset(pgd, addr);
159 printk("pmd == %016lx\n", (unsigned long) pmd);
160
161 pte = pte_offset(pmd, addr);
162 printk("pte == %016lx\n", (unsigned long) pte);
163
164 page = *pte;
165 printk("page == %08lx\n", pte_val(page));
166
167 val = pte_val(page);
168 if (val & _PAGE_PRESENT) printk("present ");
169 if (val & _PAGE_READ) printk("read ");
170 if (val & _PAGE_WRITE) printk("write ");
171 if (val & _PAGE_ACCESSED) printk("accessed ");
172 if (val & _PAGE_MODIFIED) printk("modified ");
173 if (val & _PAGE_R4KBUG) printk("r4kbug ");
174 if (val & _PAGE_GLOBAL) printk("global ");
175 if (val & _PAGE_VALID) printk("valid ");
176 printk("\n");
177}
178
179void dump_list_current(void *address)
180{
181 dump_list_process(current, address);
182}
183
184unsigned int vtop(void *address)
185{
186 pgd_t *pgd;
187 pmd_t *pmd;
188 pte_t *pte;
189 unsigned int addr, paddr;
190
191 addr = (unsigned long) address;
192 pgd = pgd_offset(current->mm, addr);
193 pmd = pmd_offset(pgd, addr);
194 pte = pte_offset(pmd, addr);
195 paddr = (CKSEG1 | (unsigned int) pte_val(*pte)) & PAGE_MASK;
196 paddr |= (addr & ~PAGE_MASK);
197
198 return paddr;
199}
200
201void dump16(unsigned long *p)
202{
203 int i;
204
205 for (i = 0; i < 8; i++) {
206 printk("*%08lx == %08lx, ", (unsigned long)p, *p);
207 p++;
208 printk("*%08lx == %08lx\n", (unsigned long)p, *p);
209 p++;
210 }
211}
diff --git a/arch/mips/lib-64/memset.S b/arch/mips/lib-64/memset.S
new file mode 100644
index 000000000000..242f1976cfaf
--- /dev/null
+++ b/arch/mips/lib-64/memset.S
@@ -0,0 +1,142 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1998, 1999, 2000 by Ralf Baechle
7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8 */
9#include <asm/asm.h>
10#include <asm/offset.h>
11#include <asm/regdef.h>
12
13#define EX(insn,reg,addr,handler) \
149: insn reg, addr; \
15 .section __ex_table,"a"; \
16 PTR 9b, handler; \
17 .previous
18
19 .macro f_fill64 dst, offset, val, fixup
20 EX(LONG_S, \val, (\offset + 0 * LONGSIZE)(\dst), \fixup)
21 EX(LONG_S, \val, (\offset + 1 * LONGSIZE)(\dst), \fixup)
22 EX(LONG_S, \val, (\offset + 2 * LONGSIZE)(\dst), \fixup)
23 EX(LONG_S, \val, (\offset + 3 * LONGSIZE)(\dst), \fixup)
24 EX(LONG_S, \val, (\offset + 4 * LONGSIZE)(\dst), \fixup)
25 EX(LONG_S, \val, (\offset + 5 * LONGSIZE)(\dst), \fixup)
26 EX(LONG_S, \val, (\offset + 6 * LONGSIZE)(\dst), \fixup)
27 EX(LONG_S, \val, (\offset + 7 * LONGSIZE)(\dst), \fixup)
28 .endm
29
30/*
31 * memset(void *s, int c, size_t n)
32 *
33 * a0: start of area to clear
34 * a1: char to fill with
35 * a2: size of area to clear
36 */
37 .set noreorder
38 .align 5
39LEAF(memset)
40 beqz a1, 1f
41 move v0, a0 /* result */
42
43 andi a1, 0xff /* spread fillword */
44 dsll t1, a1, 8
45 or a1, t1
46 dsll t1, a1, 16
47 or a1, t1
48 dsll t1, a1, 32
49 or a1, t1
501:
51
52FEXPORT(__bzero)
53 sltiu t0, a2, LONGSIZE /* very small region? */
54 bnez t0, small_memset
55 andi t0, a0, LONGMASK /* aligned? */
56
57 beqz t0, 1f
58 PTR_SUBU t0, LONGSIZE /* alignment in bytes */
59
60#ifdef __MIPSEB__
61 EX(sdl, a1, (a0), first_fixup) /* make dword aligned */
62#endif
63#ifdef __MIPSEL__
64 EX(sdr, a1, (a0), first_fixup) /* make dword aligned */
65#endif
66 PTR_SUBU a0, t0 /* long align ptr */
67 PTR_ADDU a2, t0 /* correct size */
68
691: ori t1, a2, 0x3f /* # of full blocks */
70 xori t1, 0x3f
71 beqz t1, memset_partial /* no block to fill */
72 andi t0, a2, 0x38
73
74 PTR_ADDU t1, a0 /* end address */
75 .set reorder
761: PTR_ADDIU a0, 64
77 f_fill64 a0, -64, a1, fwd_fixup
78 bne t1, a0, 1b
79 .set noreorder
80
81memset_partial:
82 PTR_LA t1, 2f /* where to start */
83 .set noat
84 dsrl AT, t0, 1
85 PTR_SUBU t1, AT
86 .set noat
87 jr t1
88 PTR_ADDU a0, t0 /* dest ptr */
89
90 .set push
91 .set noreorder
92 .set nomacro
93 f_fill64 a0, -64, a1, partial_fixup /* ... but first do longs ... */
942: .set pop
95 andi a2, LONGMASK /* At most one long to go */
96
97 beqz a2, 1f
98 PTR_ADDU a0, a2 /* What's left */
99#ifdef __MIPSEB__
100 EX(sdr, a1, -1(a0), last_fixup)
101#endif
102#ifdef __MIPSEL__
103 EX(sdl, a1, -1(a0), last_fixup)
104#endif
1051: jr ra
106 move a2, zero
107
108small_memset:
109 beqz a2, 2f
110 PTR_ADDU t1, a0, a2
111
1121: PTR_ADDIU a0, 1 /* fill bytewise */
113 bne t1, a0, 1b
114 sb a1, -1(a0)
115
1162: jr ra /* done */
117 move a2, zero
118 END(memset)
119
120first_fixup:
121 jr ra
122 nop
123
124fwd_fixup:
125 PTR_L t0, TI_TASK($28)
126 LONG_L t0, THREAD_BUADDR(t0)
127 andi a2, 0x3f
128 LONG_ADDU a2, t1
129 jr ra
130 LONG_SUBU a2, t0
131
132partial_fixup:
133 PTR_L t0, TI_TASK($28)
134 LONG_L t0, THREAD_BUADDR(t0)
135 andi a2, LONGMASK
136 LONG_ADDU a2, t1
137 jr ra
138 LONG_SUBU a2, t0
139
140last_fixup:
141 jr ra
142 andi v1, a2, LONGMASK
diff --git a/arch/mips/lib-64/watch.S b/arch/mips/lib-64/watch.S
new file mode 100644
index 000000000000..f91434013695
--- /dev/null
+++ b/arch/mips/lib-64/watch.S
@@ -0,0 +1,57 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Kernel debug stuff to use the Watch registers.
7 * Useful to find stack overflows, dangling pointers etc.
8 *
9 * Copyright (C) 1995, 1996, 1999, 2001 by Ralf Baechle
10 */
11#include <asm/asm.h>
12#include <asm/mipsregs.h>
13#include <asm/regdef.h>
14
15 .set noreorder
16/*
17 * Parameter: a0 - physical address to watch
18 * a1 - set bit #1 to trap on load references
19 * bit #0 to trap on store references
20 * Results : none
21 */
22 LEAF(__watch_set)
23 ori a0, 7
24 xori a0, 7
25 or a0, a1
26 mtc0 a0, CP0_WATCHLO
27 sd a0, watch_savelo
28 dsrl32 a0, a0, 0
29
30 jr ra
31 mtc0 zero, CP0_WATCHHI
32 END(__watch_set)
33
34/*
35 * Parameter: none
36 * Results : none
37 */
38 LEAF(__watch_clear)
39 jr ra
40 mtc0 zero, CP0_WATCHLO
41 END(__watch_clear)
42
43/*
44 * Parameter: none
45 * Results : none
46 */
47 LEAF(__watch_reenable)
48 ld t0, watch_savelo
49 jr ra
50 mtc0 t0, CP0_WATCHLO
51 END(__watch_reenable)
52
53/*
54 * Saved value of the c0_watchlo register for watch_reenable()
55 */
56 .local watch_savelo
57 .comm watch_savelo, 8, 8