Update ia64 patch to 2.5.72-030619
[linux-flexiantxendom0-3.2.10.git] / arch / ia64 / sn / io / sn2 / l1.c
1 /* $Id$
2  *
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.  See the file "COPYING" in the main directory of this archive
5  * for more details.
6  *
7  * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc.  All rights reserved.
8  */
9
10 /* In general, this file is organized in a hierarchy from lower-level
11  * to higher-level layers, as follows:
12  *
13  *      UART routines
14  *      Bedrock/L1 "PPP-like" protocol implementation
15  *      System controller "message" interface (allows multiplexing
16  *              of various kinds of requests and responses with
17  *              console I/O)
18  *      Console interface:
19  *        "l1_cons", the glue that allows the L1 to act
20  *              as the system console for the stdio libraries
21  *
22  * Routines making use of the system controller "message"-style interface
23  * can be found in l1_command.c.
24  */
25
26
27 #include <linux/types.h>
28 #include <linux/config.h>
29 #include <linux/slab.h>
30 #include <linux/spinlock.h>
31 #include <linux/delay.h>
32 #include <linux/interrupt.h>
33 #include <asm/io.h>
34 #include <asm/sn/sgi.h>
35 #include <asm/sn/io.h>
36 #include <asm/sn/iograph.h>
37 #include <asm/sn/invent.h>
38 #include <asm/sn/hcl.h>
39 #include <asm/sn/hcl_util.h>
40 #include <asm/sn/labelcl.h>
41 #include <asm/sn/router.h>
42 #include <asm/sn/module.h>
43 #include <asm/sn/ksys/l1.h>
44 #include <asm/sn/nodepda.h>
45 #include <asm/sn/clksupport.h>
46 #include <asm/sn/sn_sal.h>
47 #include <asm/sn/sn_cpuid.h>
48 #include <asm/sn/uart16550.h>
49 #include <asm/sn/simulator.h>
50
51
52 #define UART_BAUD_RATE          57600
53
54 static int L1_connected;        /* non-zero when interrupts are enabled */
55
56
57 int 
58 get_L1_baud(void)
59 {
60     return UART_BAUD_RATE;
61 }
62
63
64
65 /* Return the current interrupt level */
66 int
67 l1_get_intr_value( void )
68 {
69         cpuid_t intr_cpuid;
70         nasid_t console_nasid;
71         int major, minor;
72         extern nasid_t get_console_nasid(void);
73
74         /* if it is an old prom, run in poll mode */
75
76         major = sn_sal_rev_major();
77         minor = sn_sal_rev_minor();
78         if ( (major < 1) || ((major == 1) && (minor < 10)) ) {
79                 /* before version 1.10 doesn't work */
80                 return (0);
81         }
82
83         console_nasid = get_console_nasid();
84         intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid))->node_first_cpu;
85         return CPU_VECTOR_TO_IRQ(intr_cpuid, SGI_UART_VECTOR);
86 }
87
88 /* Disconnect the callup functions - throw away interrupts */
89
90 void
91 l1_unconnect_intr(void)
92 {
93 }
94
95 /* Set up uart interrupt handling for this node's uart */
96
97 int
98 l1_connect_intr(void *intr_func, void *arg, struct pt_regs *ep)
99 {
100         cpuid_t intr_cpuid;
101         nasid_t console_nasid;
102         unsigned int console_irq;
103         int result;
104         extern int intr_connect_level(cpuid_t, int, ilvl_t, intr_func_t);
105         extern nasid_t get_console_nasid(void);
106
107
108         /* don't call to connect multiple times - we DON'T support changing the handler */
109
110         if ( !L1_connected ) {
111                 L1_connected++;
112                 console_nasid = get_console_nasid();
113                 intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid))->node_first_cpu;
114                 console_irq = CPU_VECTOR_TO_IRQ(intr_cpuid, SGI_UART_VECTOR);
115                 result = intr_connect_level(intr_cpuid, SGI_UART_VECTOR,
116                                         0 /*not used*/, 0 /*not used*/);
117                 if (result != SGI_UART_VECTOR) {
118                         if (result < 0)
119                                 printk(KERN_WARNING "L1 console driver : intr_connect_level failed %d\n", result);
120                         else
121                                 printk(KERN_WARNING "L1 console driver : intr_connect_level returns wrong bit %d\n", result);
122                         return (-1);
123                 }
124
125                 result = request_irq(console_irq, intr_func, SA_INTERRUPT,
126                                         "SGI L1 console driver", (void *)arg);
127                 if (result < 0) {
128                         printk(KERN_WARNING "L1 console driver : request_irq failed %d\n", result);
129                         return (-1);
130                 }
131
132                 /* ask SAL to turn on interrupts in the UART itself */
133                 ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
134         }
135         return (0);
136 }
137
138
139 /* These are functions to use from serial_in/out when in protocol
140  * mode to send and receive uart control regs. These are external
141  * interfaces into the protocol driver.
142  */
143
144 void
145 l1_control_out(int offset, int value)
146 {
147         /* quietly ignore unless simulator */
148         if ( IS_RUNNING_ON_SIMULATOR() ) {
149                 extern u64 master_node_bedrock_address;
150                 if ( master_node_bedrock_address != (u64)0 ) {
151                         writeb(value, (unsigned long)master_node_bedrock_address +
152                                 (offset<< 3));
153                 }
154                 return;
155         }
156 }
157
158 /* Console input exported interface. Return a register value.  */
159
160 int
161 l1_control_in_polled(int offset)
162 {
163         static int l1_control_in_local(int);
164
165         return(l1_control_in_local(offset));
166 }
167
168 int
169 l1_control_in(int offset)
170 {
171         static int l1_control_in_local(int);
172
173         return(l1_control_in_local(offset));
174 }
175
176 static int
177 l1_control_in_local(int offset)
178 {
179         int sal_call_status = 0, input;
180         int ret = 0;
181
182         if ( IS_RUNNING_ON_SIMULATOR() ) {
183                 extern u64 master_node_bedrock_address;
184                 ret = readb((unsigned long)master_node_bedrock_address +
185                                 (offset<< 3));
186                 return(ret);
187         }               
188         if ( offset == REG_LSR ) {
189                 ret = (LSR_XHRE | LSR_XSRE);    /* can send anytime */
190                 sal_call_status = ia64_sn_console_check(&input);
191                 if ( !sal_call_status && input ) {
192                         /* input pending */
193                         ret |= LSR_RCA;
194                 }
195         }
196         return(ret);
197 }
198
199 /*
200  * Console input exported interface. Return a character (if one is available)
201  */
202
203 int
204 l1_serial_in_polled(void)
205 {
206         static int l1_serial_in_local(void);
207
208         return(l1_serial_in_local());
209 }
210
211 int
212 l1_serial_in(void)
213 {
214         static int l1_serial_in_local(void);
215
216         if ( IS_RUNNING_ON_SIMULATOR() ) {
217                 extern u64 master_node_bedrock_address;
218                 return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3)));
219         }       
220         return(l1_serial_in_local());
221 }
222
223 static int
224 l1_serial_in_local(void)
225 {
226         int ch;
227
228         if ( IS_RUNNING_ON_SIMULATOR() ) {
229                 extern u64 master_node_bedrock_address;
230                 return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3)));
231         }               
232
233         if ( !(ia64_sn_console_getc(&ch)) )
234                 return(ch);
235         else
236                 return(0);
237 }
238
239 /* Console output exported interface. Write message to the console.  */
240
241 int
242 l1_serial_out( char *str, int len )
243 {
244         int tmp;
245
246         /* Ignore empty messages */
247         if ( len == 0 )
248                 return(len);
249
250 #if defined(CONFIG_IA64_EARLY_PRINTK)
251         /* Need to setup SAL calls so the PROM calls will work */
252         {
253                 static int inited;
254                 void early_sn_setup(void);
255                 if(!inited) {
256                         inited=1;
257                         early_sn_setup();
258                 }
259         }
260 #endif
261
262         if ( IS_RUNNING_ON_SIMULATOR() ) {
263                 extern u64 master_node_bedrock_address;
264                 void early_sn_setup(void);
265                 int counter = len;
266
267                 if (!master_node_bedrock_address)
268                         early_sn_setup();
269                 if ( master_node_bedrock_address != (u64)0 ) {
270 #ifdef FLAG_DIRECT_CONSOLE_WRITES
271                         /* This is an easy way to pre-pend the output to know whether the output
272                          * was done via sal or directly */
273                         writeb('[', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
274                         writeb('+', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
275                         writeb(']', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
276                         writeb(' ', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
277 #endif  /* FLAG_DIRECT_CONSOLE_WRITES */
278                         while ( counter > 0 ) {
279                                 writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
280                                 counter--;
281                                 str++;
282                         }
283                 }
284                 return(len);
285         }
286
287         /* Attempt to write things out thru the sal */
288         if ( L1_connected )
289                 tmp = ia64_sn_console_xmit_chars(str, len);
290         else
291                 tmp = ia64_sn_console_putb(str, len);
292         return ((tmp < 0) ? 0 : tmp);
293 }