Update ia64 patch to 2.5.72-030619
[linux-flexiantxendom0-3.2.10.git] / arch / ia64 / sn / kernel / bte.c
1 /*
2  *
3  *
4  * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
5  * 
6  * This program is free software; you can redistribute it and/or modify it 
7  * under the terms of version 2 of the GNU General Public License 
8  * as published by the Free Software Foundation.
9  * 
10  * This program is distributed in the hope that it would be useful, but 
11  * WITHOUT ANY WARRANTY; without even the implied warranty of 
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
13  * 
14  * Further, this software is distributed without any warranty that it is 
15  * free of the rightful claim of any third person regarding infringement 
16  * or the like.  Any license provided herein, whether implied or 
17  * otherwise, applies only to this software file.  Patent licenses, if 
18  * any, provided herein do not apply to combinations of this program with 
19  * other software, or any other product whatsoever.
20  * 
21  * You should have received a copy of the GNU General Public 
22  * License along with this program; if not, write the Free Software 
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
24  * 
25  * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
26  * Mountain View, CA  94043, or:
27  * 
28  * http://www.sgi.com 
29  * 
30  * For further information regarding this notice, see: 
31  * 
32  * http://oss.sgi.com/projects/GenInfo/NoticeExplan
33  */
34
35 #include <linux/config.h>
36 #include <asm/sn/nodepda.h>
37 #include <asm/sn/addrs.h>
38 #include <asm/sn/arch.h>
39 #include <asm/sn/sn_cpuid.h>
40 #include <asm/sn/pda.h>
41 #include <asm/sn/sn2/shubio.h>
42 #include <asm/nodedata.h>
43
44 #include <linux/bootmem.h>
45 #include <linux/string.h>
46 #include <linux/sched.h>
47
48 #include <asm/sn/bte.h>
49
50 #ifndef L1_CACHE_MASK
51 #define L1_CACHE_MASK (L1_CACHE_BYTES - 1)
52 #endif
53
54 /*
55  * The base address of for each set of bte registers.
56  */
57 static int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 };
58
59
60 /************************************************************************
61  * Block Transfer Engine copy related functions.
62  *
63  ***********************************************************************/
64
65
66 /*
67  * bte_copy(src, dest, len, mode, notification)
68  *
69  * Use the block transfer engine to move kernel memory from src to dest
70  * using the assigned mode.
71  *
72  * Paramaters:
73  *   src - physical address of the transfer source.
74  *   dest - physical address of the transfer destination.
75  *   len - number of bytes to transfer from source to dest.
76  *   mode - hardware defined.  See reference information
77  *          for IBCT0/1 in the SHUB Programmers Reference
78  *   notification - kernel virtual address of the notification cache
79  *                  line.  If NULL, the default is used and
80  *                  the bte_copy is synchronous.
81  *
82  * NOTE:  This function requires src, dest, and len to
83  * be cacheline aligned.
84  */
85 bte_result_t
86 bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification)
87 {
88         int bte_to_use;
89         u64 transfer_size;
90         struct bteinfo_s *bte;
91         bte_result_t bte_status;
92         unsigned long irq_flags;
93
94
95         BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n",
96                     src, dest, len, mode, notification));
97
98         if (len == 0) {
99                 return BTE_SUCCESS;
100         }
101
102         ASSERT(!((len & L1_CACHE_MASK) ||
103                  (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK)));
104         ASSERT(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT));
105
106         do {
107                 local_irq_save(irq_flags);
108
109                 bte_to_use = 0;
110                 /* Attempt to lock one of the BTE interfaces. */
111                 while ((bte_to_use < BTES_PER_NODE) &&
112                        BTE_LOCK_IF_AVAIL(bte_to_use)) {
113                         bte_to_use++;
114                 }
115
116                 if (bte_to_use < BTES_PER_NODE) {
117                         break;
118                 }
119
120                 local_irq_restore(irq_flags);
121
122                 if (!(mode & BTE_WACQUIRE)) {
123                         return BTEFAIL_NOTAVAIL;
124                 }
125
126                 /* Wait until a bte is available. */
127                 udelay(10);
128         } while (1);
129
130         bte = pda->cpu_bte_if[bte_to_use];
131         BTE_PRINTKV(("Got a lock on bte %d\n", bte_to_use));
132
133
134         if (notification == NULL) {
135                 /* User does not want to be notified. */
136                 bte->most_rcnt_na = &bte->notify;
137         } else {
138                 bte->most_rcnt_na = notification;
139         }
140
141         /* Calculate the number of cache lines to transfer. */
142         transfer_size = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK);
143
144         /* Initialize the notification to a known value. */
145         *bte->most_rcnt_na = -1L;
146
147         /* Set the status reg busy bit and transfer length */
148         BTE_PRINTKV(("IBLS - HUB_S(0x%p, 0x%lx)\n",
149                      BTEREG_LNSTAT_ADDR, IBLS_BUSY | transfer_size));
150         HUB_S(BTEREG_LNSTAT_ADDR, (IBLS_BUSY | transfer_size));
151
152         /* Set the source and destination registers */
153         BTE_PRINTKV(("IBSA - HUB_S(0x%p, 0x%lx)\n", BTEREG_SRC_ADDR,
154                      (TO_PHYS(src))));
155         HUB_S(BTEREG_SRC_ADDR, (TO_PHYS(src)));
156         BTE_PRINTKV(("IBDA - HUB_S(0x%p, 0x%lx)\n", BTEREG_DEST_ADDR,
157                      (TO_PHYS(dest))));
158         HUB_S(BTEREG_DEST_ADDR, (TO_PHYS(dest)));
159
160         /* Set the notification register */
161         BTE_PRINTKV(("IBNA - HUB_S(0x%p, 0x%lx)\n", BTEREG_NOTIF_ADDR,
162                      (TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na)))));
163         HUB_S(BTEREG_NOTIF_ADDR, (TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na))));
164
165
166         /* Initiate the transfer */
167         BTE_PRINTK(("IBCT - HUB_S(0x%p, 0x%lx)\n", BTEREG_CTRL_ADDR,
168                      BTE_VALID_MODE(mode)));
169         HUB_S(BTEREG_CTRL_ADDR, BTE_VALID_MODE(mode));
170
171         spin_unlock_irqrestore(&bte->spinlock, irq_flags);
172
173
174         if (notification != NULL) {
175                 return BTE_SUCCESS;
176         }
177
178         while (*bte->most_rcnt_na == -1UL) {
179         }
180
181
182         BTE_PRINTKV((" Delay Done.  IBLS = 0x%lx, most_rcnt_na = 0x%lx\n",
183                                 HUB_L(BTEREG_LNSTAT_ADDR), *bte->most_rcnt_na));
184
185         if (*bte->most_rcnt_na & IBLS_ERROR) {
186                 bte_status = *bte->most_rcnt_na & ~IBLS_ERROR;
187                 *bte->most_rcnt_na = 0L;
188         } else {
189                 bte_status = BTE_SUCCESS;
190         }
191         BTE_PRINTK(("Returning status is 0x%lx and most_rcnt_na is 0x%lx\n",
192                                 HUB_L(BTEREG_LNSTAT_ADDR), *bte->most_rcnt_na));
193
194         return bte_status;
195 }
196
197
198 /*
199  * bte_unaligned_copy(src, dest, len, mode)
200  *
201  * use the block transfer engine to move kernel
202  * memory from src to dest using the assigned mode.
203  *
204  * Paramaters:
205  *   src - physical address of the transfer source.
206  *   dest - physical address of the transfer destination.
207  *   len - number of bytes to transfer from source to dest.
208  *   mode - hardware defined.  See reference information
209  *          for IBCT0/1 in the SGI documentation.
210  *
211  * NOTE: If the source, dest, and len are all cache line aligned,
212  * then it would be _FAR_ preferrable to use bte_copy instead.
213  */
214 bte_result_t
215 bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode)
216 {
217         int destFirstCacheOffset;
218         u64 headBteSource;
219         u64 headBteLen;
220         u64 headBcopySrcOffset;
221         u64 headBcopyDest;
222         u64 headBcopyLen;
223         u64 footBteSource;
224         u64 footBteLen;
225         u64 footBcopyDest;
226         u64 footBcopyLen;
227         bte_result_t rv;
228         char *bteBlock;
229
230         if (len == 0) {
231                 return BTE_SUCCESS;
232         }
233
234         /* temporary buffer used during unaligned transfers */
235         bteBlock = pda->cpu_bte_if[0]->scratch_buf;
236
237         headBcopySrcOffset = src & L1_CACHE_MASK;
238         destFirstCacheOffset = dest & L1_CACHE_MASK;
239
240         /*
241          * At this point, the transfer is broken into
242          * (up to) three sections.  The first section is
243          * from the start address to the first physical
244          * cache line, the second is from the first physical
245          * cache line to the last complete cache line,
246          * and the third is from the last cache line to the
247          * end of the buffer.  The first and third sections
248          * are handled by bte copying into a temporary buffer
249          * and then bcopy'ing the necessary section into the
250          * final location.  The middle section is handled with
251          * a standard bte copy.
252          *
253          * One nasty exception to the above rule is when the
254          * source and destination are not symetrically
255          * mis-aligned.  If the source offset from the first
256          * cache line is different from the destination offset,
257          * we make the first section be the entire transfer
258          * and the bcopy the entire block into place.
259          */
260         if (headBcopySrcOffset == destFirstCacheOffset) {
261
262                 /*
263                  * Both the source and destination are the same
264                  * distance from a cache line boundary so we can
265                  * use the bte to transfer the bulk of the
266                  * data.
267                  */
268                 headBteSource = src & ~L1_CACHE_MASK;
269                 headBcopyDest = dest;
270                 if (headBcopySrcOffset) {
271                         headBcopyLen =
272                             (len >
273                              (L1_CACHE_BYTES -
274                               headBcopySrcOffset) ? L1_CACHE_BYTES
275                              - headBcopySrcOffset : len);
276                         headBteLen = L1_CACHE_BYTES;
277                 } else {
278                         headBcopyLen = 0;
279                         headBteLen = 0;
280                 }
281
282                 if (len > headBcopyLen) {
283                         footBcopyLen =
284                             (len - headBcopyLen) & L1_CACHE_MASK;
285                         footBteLen = L1_CACHE_BYTES;
286
287                         footBteSource = src + len - footBcopyLen;
288                         footBcopyDest = dest + len - footBcopyLen;
289
290                         if (footBcopyDest ==
291                             (headBcopyDest + headBcopyLen)) {
292                                 /*
293                                  * We have two contigous bcopy
294                                  * blocks.  Merge them.
295                                  */
296                                 headBcopyLen += footBcopyLen;
297                                 headBteLen += footBteLen;
298                         } else if (footBcopyLen > 0) {
299                                 rv = bte_copy(footBteSource,
300                                               ia64_tpa((unsigned long)bteBlock),
301                                               footBteLen, mode, NULL);
302                                 if (rv != BTE_SUCCESS) {
303                                         return rv;
304                                 }
305
306
307                                 memcpy(__va(footBcopyDest),
308                                        (char *) bteBlock, footBcopyLen);
309                         }
310                 } else {
311                         footBcopyLen = 0;
312                         footBteLen = 0;
313                 }
314
315                 if (len > (headBcopyLen + footBcopyLen)) {
316                         /* now transfer the middle. */
317                         rv = bte_copy((src + headBcopyLen),
318                                       (dest +
319                                        headBcopyLen),
320                                       (len - headBcopyLen -
321                                        footBcopyLen), mode, NULL);
322                         if (rv != BTE_SUCCESS) {
323                                 return rv;
324                         }
325
326                 }
327         } else {
328
329
330                 /*
331                  * The transfer is not symetric, we will
332                  * allocate a buffer large enough for all the
333                  * data, bte_copy into that buffer and then
334                  * bcopy to the destination.
335                  */
336
337                 /* Add the leader from source */
338                 headBteLen = len + (src & L1_CACHE_MASK);
339                 /* Add the trailing bytes from footer. */
340                 headBteLen +=
341                     L1_CACHE_BYTES - (headBteLen & L1_CACHE_MASK);
342                 headBteSource = src & ~L1_CACHE_MASK;
343                 headBcopySrcOffset = src & L1_CACHE_MASK;
344                 headBcopyDest = dest;
345                 headBcopyLen = len;
346         }
347
348         if (headBcopyLen > 0) {
349                 rv = bte_copy(headBteSource,
350                               ia64_tpa((unsigned long)bteBlock), headBteLen, mode, NULL);
351                 if (rv != BTE_SUCCESS) {
352                         return rv;
353                 }
354
355                 memcpy(__va(headBcopyDest), ((char *) bteBlock +
356                                              headBcopySrcOffset),
357                        headBcopyLen);
358         }
359         return BTE_SUCCESS;
360 }
361
362
363 /************************************************************************
364  * Block Transfer Engine initialization functions.
365  *
366  ***********************************************************************/
367
368
369 /*
370  * bte_init_node(nodepda, cnode)
371  *
372  * Initialize the nodepda structure with BTE base addresses and
373  * spinlocks.
374  */
375 void
376 bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode)
377 {
378         int i;
379
380
381         /*
382          * Indicate that all the block transfer engines on this node
383          * are available.
384          */
385
386         /*
387          * Allocate one bte_recover_t structure per node.  It holds
388          * the recovery lock for node.  All the bte interface structures
389          * will point at this one bte_recover structure to get the lock.
390          */
391         spin_lock_init(&mynodepda->bte_recovery_lock);
392         init_timer(&mynodepda->bte_recovery_timer);
393         mynodepda->bte_recovery_timer.function = bte_error_handler;
394         mynodepda->bte_recovery_timer.data = (unsigned long) mynodepda;
395
396         for (i = 0; i < BTES_PER_NODE; i++) {
397                 /* >>> Don't know why the 0x1800000L is here.  Robin */
398                 mynodepda->bte_if[i].bte_base_addr =
399                     (char *) LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L);
400
401                 /*
402                  * Initialize the notification and spinlock
403                  * so the first transfer can occur.
404                  */
405                 mynodepda->bte_if[i].most_rcnt_na =
406                     &(mynodepda->bte_if[i].notify);
407                 mynodepda->bte_if[i].notify = 0L;
408                 spin_lock_init(&mynodepda->bte_if[i].spinlock);
409
410                 mynodepda->bte_if[i].scratch_buf =
411                     alloc_bootmem_node(NODE_DATA(cnode), BTE_MAX_XFER);
412                 mynodepda->bte_if[i].bte_cnode = cnode;
413                 mynodepda->bte_if[i].bte_error_count = 0;
414                 mynodepda->bte_if[i].bte_num = i;
415                 mynodepda->bte_if[i].cleanup_active = 0;
416                 mynodepda->bte_if[i].bh_error = 0;
417         }
418
419 }
420
421 /*
422  * bte_init_cpu()
423  *
424  * Initialize the cpupda structure with pointers to the
425  * nodepda bte blocks.
426  *
427  */
428 void
429 bte_init_cpu(void)
430 {
431         /* Called by setup.c as each cpu is being added to the nodepda */
432         if (local_node_data->active_cpu_count & 0x1) {
433                 pda->cpu_bte_if[0] = &(nodepda->bte_if[0]);
434                 pda->cpu_bte_if[1] = &(nodepda->bte_if[1]);
435         } else {
436                 pda->cpu_bte_if[0] = &(nodepda->bte_if[1]);
437                 pda->cpu_bte_if[1] = &(nodepda->bte_if[0]);
438         }
439 }