]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/mips/mm/pg-sb1.c
Fix initialization. Unbreak the wait-for-completion loops. Code cleanup.
[linux-2.6-omap-h63xx.git] / arch / mips / mm / pg-sb1.c
1 /*
2  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
3  * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org)
4  * Copyright (C) 2000 SiByte, Inc.
5  * Copyright (C) 2005 Thiemo Seufer
6  *
7  * Written by Justin Carlson of SiByte, Inc.
8  *         and Kip Walker of Broadcom Corp.
9  *
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 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25 #include <linux/config.h>
26 #include <linux/module.h>
27 #include <linux/sched.h>
28 #include <linux/smp.h>
29
30 #include <asm/io.h>
31 #include <asm/sibyte/sb1250.h>
32 #include <asm/sibyte/sb1250_regs.h>
33 #include <asm/sibyte/sb1250_dma.h>
34
35 #ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
36 #define SB1_PREF_LOAD_STREAMED_HINT "0"
37 #define SB1_PREF_STORE_STREAMED_HINT "1"
38 #else
39 #define SB1_PREF_LOAD_STREAMED_HINT "4"
40 #define SB1_PREF_STORE_STREAMED_HINT "5"
41 #endif
42
43 static inline void clear_page_cpu(void *page)
44 {
45         unsigned char *addr = (unsigned char *) page;
46         unsigned char *end = addr + PAGE_SIZE;
47
48         /*
49          * JDCXXX - This should be bottlenecked by the write buffer, but these
50          * things tend to be mildly unpredictable...should check this on the
51          * performance model
52          *
53          * We prefetch 4 lines ahead.  We're also "cheating" slightly here...
54          * since we know we're on an SB1, we force the assembler to take
55          * 64-bit operands to speed things up
56          */
57         __asm__ __volatile__(
58         "       .set    push            \n"
59         "       .set    mips4           \n"
60         "       .set    noreorder       \n"
61 #ifdef CONFIG_CPU_HAS_PREFETCH
62         "       daddiu  %0, %0, 128     \n"
63         "       pref    " SB1_PREF_STORE_STREAMED_HINT ", -128(%0)  \n"  /* Prefetch the first 4 lines */
64         "       pref    " SB1_PREF_STORE_STREAMED_HINT ",  -96(%0)  \n"
65         "       pref    " SB1_PREF_STORE_STREAMED_HINT ",  -64(%0)  \n"
66         "       pref    " SB1_PREF_STORE_STREAMED_HINT ",  -32(%0)  \n"
67         "1:     sd      $0, -128(%0)    \n"  /* Throw out a cacheline of 0's */
68         "       sd      $0, -120(%0)    \n"
69         "       sd      $0, -112(%0)    \n"
70         "       sd      $0, -104(%0)    \n"
71         "       daddiu  %0, %0, 32      \n"
72         "       bnel    %0, %1, 1b      \n"
73         "        pref   " SB1_PREF_STORE_STREAMED_HINT ",  -32(%0)  \n"
74         "       daddiu  %0, %0, -128    \n"
75 #endif
76         "       sd      $0, 0(%0)       \n"  /* Throw out a cacheline of 0's */
77         "1:     sd      $0, 8(%0)       \n"
78         "       sd      $0, 16(%0)      \n"
79         "       sd      $0, 24(%0)      \n"
80         "       daddiu  %0, %0, 32      \n"
81         "       bnel    %0, %1, 1b      \n"
82         "        sd     $0, 0(%0)       \n"
83         "       .set    pop             \n"
84         : "+r" (addr)
85         : "r" (end)
86         : "memory");
87 }
88
89 static inline void copy_page_cpu(void *to, void *from)
90 {
91         unsigned char *src = (unsigned char *)from;
92         unsigned char *dst = (unsigned char *)to;
93         unsigned char *end = src + PAGE_SIZE;
94
95         /*
96          * The pref's used here are using "streaming" hints, which cause the
97          * copied data to be kicked out of the cache sooner.  A page copy often
98          * ends up copying a lot more data than is commonly used, so this seems
99          * to make sense in terms of reducing cache pollution, but I've no real
100          * performance data to back this up
101          */
102         __asm__ __volatile__(
103         "       .set    push            \n"
104         "       .set    mips4           \n"
105         "       .set    noreorder       \n"
106 #ifdef CONFIG_CPU_HAS_PREFETCH
107         "       daddiu  %0, %0, 128     \n"
108         "       daddiu  %1, %1, 128     \n"
109         "       pref    " SB1_PREF_LOAD_STREAMED_HINT  ", -128(%0)\n"  /* Prefetch the first 4 lines */
110         "       pref    " SB1_PREF_STORE_STREAMED_HINT ", -128(%1)\n"
111         "       pref    " SB1_PREF_LOAD_STREAMED_HINT  ",  -96(%0)\n"
112         "       pref    " SB1_PREF_STORE_STREAMED_HINT ",  -96(%1)\n"
113         "       pref    " SB1_PREF_LOAD_STREAMED_HINT  ",  -64(%0)\n"
114         "       pref    " SB1_PREF_STORE_STREAMED_HINT ",  -64(%1)\n"
115         "       pref    " SB1_PREF_LOAD_STREAMED_HINT  ",  -32(%0)\n"
116         "1:     pref    " SB1_PREF_STORE_STREAMED_HINT ",  -32(%1)\n"
117 # ifdef CONFIG_64BIT
118         "       ld      $8, -128(%0)    \n"  /* Block copy a cacheline */
119         "       ld      $9, -120(%0)    \n"
120         "       ld      $10, -112(%0)   \n"
121         "       ld      $11, -104(%0)   \n"
122         "       sd      $8, -128(%1)    \n"
123         "       sd      $9, -120(%1)    \n"
124         "       sd      $10, -112(%1)   \n"
125         "       sd      $11, -104(%1)   \n"
126 # else
127         "       lw      $2, -128(%0)    \n"  /* Block copy a cacheline */
128         "       lw      $3, -124(%0)    \n"
129         "       lw      $6, -120(%0)    \n"
130         "       lw      $7, -116(%0)    \n"
131         "       lw      $8, -112(%0)    \n"
132         "       lw      $9, -108(%0)    \n"
133         "       lw      $10, -104(%0)   \n"
134         "       lw      $11, -100(%0)   \n"
135         "       sw      $2, -128(%1)    \n"
136         "       sw      $3, -124(%1)    \n"
137         "       sw      $6, -120(%1)    \n"
138         "       sw      $7, -116(%1)    \n"
139         "       sw      $8, -112(%1)    \n"
140         "       sw      $9, -108(%1)    \n"
141         "       sw      $10, -104(%1)   \n"
142         "       sw      $11, -100(%1)   \n"
143 # endif
144         "       daddiu  %0, %0, 32      \n"
145         "       daddiu  %1, %1, 32      \n"
146         "       bnel    %0, %2, 1b      \n"
147         "        pref   " SB1_PREF_LOAD_STREAMED_HINT  ",  -32(%0)\n"
148         "       daddiu  %0, %0, -128    \n"
149         "       daddiu  %1, %1, -128    \n"
150 #endif
151 #ifdef CONFIG_64BIT
152         "       ld      $8, 0(%0)       \n"  /* Block copy a cacheline */
153         "1:     ld      $9, 8(%0)       \n"
154         "       ld      $10, 16(%0)     \n"
155         "       ld      $11, 24(%0)     \n"
156         "       sd      $8, 0(%1)       \n"
157         "       sd      $9, 8(%1)       \n"
158         "       sd      $10, 16(%1)     \n"
159         "       sd      $11, 24(%1)     \n"
160 #else
161         "       lw      $2, 0(%0)       \n"  /* Block copy a cacheline */
162         "1:     lw      $3, 4(%0)       \n"
163         "       lw      $6, 8(%0)       \n"
164         "       lw      $7, 12(%0)      \n"
165         "       lw      $8, 16(%0)      \n"
166         "       lw      $9, 20(%0)      \n"
167         "       lw      $10, 24(%0)     \n"
168         "       lw      $11, 28(%0)     \n"
169         "       sw      $2, 0(%1)       \n"
170         "       sw      $3, 4(%1)       \n"
171         "       sw      $6, 8(%1)       \n"
172         "       sw      $7, 12(%1)      \n"
173         "       sw      $8, 16(%1)      \n"
174         "       sw      $9, 20(%1)      \n"
175         "       sw      $10, 24(%1)     \n"
176         "       sw      $11, 28(%1)     \n"
177 #endif
178         "       daddiu  %0, %0, 32      \n"
179         "       daddiu  %1, %1, 32      \n"
180         "       bnel    %0, %2, 1b      \n"
181 #ifdef CONFIG_64BIT
182         "        ld     $8, 0(%0)       \n"
183 #else
184         "        lw     $2, 0(%0)       \n"
185 #endif
186         "       .set    pop             \n"
187         : "+r" (src), "+r" (dst)
188         : "r" (end)
189 #ifdef CONFIG_64BIT
190         : "$8","$9","$10","$11","memory");
191 #else
192         : "$2","$3","$6","$7","$8","$9","$10","$11","memory");
193 #endif
194 }
195
196
197 #ifdef CONFIG_SIBYTE_DMA_PAGEOPS
198
199 /*
200  * Pad descriptors to cacheline, since each is exclusively owned by a
201  * particular CPU.
202  */
203 typedef struct dmadscr_s {
204         u64 dscr_a;
205         u64 dscr_b;
206         u64 pad_a;
207         u64 pad_b;
208 } dmadscr_t;
209
210 static dmadscr_t page_descr[DM_NUM_CHANNELS] __attribute__((aligned(SMP_CACHE_BYTES)));
211
212 void sb1_dma_init(void)
213 {
214         int i;
215
216         for (i = 0; i < DM_NUM_CHANNELS; i++) {
217                 u64 base_val = (u64)CPHYSADDR(&page_descr[i]) | V_DM_DSCR_BASE_RINGSZ(1);
218                 void *base_reg = (void *)IOADDR(A_DM_REGISTER(i, R_DM_DSCR_BASE));
219
220                 __raw_writeq(base_val, base_reg);
221                 __raw_writeq(base_val | M_DM_DSCR_BASE_RESET, base_reg);
222                 __raw_writeq(base_val | M_DM_DSCR_BASE_ENABL, base_reg);
223         }
224 }
225
226 void clear_page(void *page)
227 {
228         u64 to_phys = (u64)CPHYSADDR(page);
229         unsigned int cpu = smp_processor_id();
230
231         /* if the page is not in KSEG0, use old way */
232         if ((long)KSEGX(page) != (long)CKSEG0)
233                 return clear_page_cpu(page);
234
235         page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_ZERO_MEM | M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT;
236         page_descr[cpu].dscr_b = V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE);
237         __raw_writeq(1, IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
238
239         /*
240          * Don't really want to do it this way, but there's no
241          * reliable way to delay completion detection.
242          */
243         while (!(__raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)))
244                  & M_DM_DSCR_BASE_INTERRUPT))
245                 ;
246         __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
247 }
248
249 void copy_page(void *to, void *from)
250 {
251         u64 from_phys = (u64)CPHYSADDR(from);
252         u64 to_phys = (u64)CPHYSADDR(to);
253         unsigned int cpu = smp_processor_id();
254
255         /* if any page is not in KSEG0, use old way */
256         if ((long)KSEGX(to) != (long)CKSEG0
257             || (long)KSEGX(from) != (long)CKSEG0)
258                 return copy_page_cpu(to, from);
259
260         page_descr[cpu].dscr_a = to_phys | M_DM_DSCRA_L2C_DEST | M_DM_DSCRA_INTERRUPT;
261         page_descr[cpu].dscr_b = from_phys | V_DM_DSCRB_SRC_LENGTH(PAGE_SIZE);
262         __raw_writeq(1, (void *)IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_COUNT)));
263
264         /*
265          * Don't really want to do it this way, but there's no
266          * reliable way to delay completion detection.
267          */
268         while (!(__raw_readq((void *)IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE_DEBUG)))
269                  & M_DM_DSCR_BASE_INTERRUPT))
270                 ;
271         __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
272 }
273
274 #else /* !CONFIG_SIBYTE_DMA_PAGEOPS */
275
276 void clear_page(void *page)
277 {
278         return clear_page_cpu(page);
279 }
280
281 void copy_page(void *to, void *from)
282 {
283         return copy_page_cpu(to, from);
284 }
285
286 #endif /* !CONFIG_SIBYTE_DMA_PAGEOPS */
287
288 EXPORT_SYMBOL(clear_page);
289 EXPORT_SYMBOL(copy_page);