1 /* $NetBSD: a12dc.c,v 1.23 2009/03/18 10:22:22 cegger Exp $ */
3 /* [Notice revision 2.2]
4 * Copyright (c) 1997, 1998 Avalon Computer Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright and
13 * author notice, this list of conditions, and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of Avalon Computer Systems, Inc. nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 * 4. This copyright will be assigned to The NetBSD Foundation on
21 * 1/1/2000 unless these terms (including possibly the assignment
22 * date) are updated in writing by Avalon prior to the latest specified
25 * THIS SOFTWARE IS PROVIDED BY AVALON COMPUTER SYSTEMS, INC. AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AVALON OR THE CONTRIBUTORS
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
39 * The A12 uses what DEC calls a "detached console", i.e., some of the console
40 * implementation is on a dedicated processor with its own RAM.
42 * The A12 Detached Console interface uses two 16 bit registers (per CPU), one
43 * going from the CPU to the a12ctrl processor and one going back the other
44 * way. The first is polled, the second produces a GInt.
46 * In the very early days we loaded program images through this interface.
48 * Consequently, it developed an overly complicated (but sort of fast)
49 * inverting sync/ack that isn't needed at all for its present application as
50 * a text console device.
52 * One possible solution: most of the channels are undefined, so a console
53 * channel using a stateless ack could be defined, with corresponding changes
54 * to the backplane 68360 code.
56 * This file is complicated somewhat by its use in three different kernels:
57 * NetBSD, the A12 CPU-resident console, and the a12ctrl backplane processor.
58 * (The protocol is symmetrical.)
61 #include "opt_avalon_a12.h" /* Config options headers */
65 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
67 __KERNEL_RCSID(0, "$NetBSD: a12dc.c,v 1.23 2009/03/18 10:22:22 cegger Exp $");
69 #include <sys/types.h>
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/malloc.h>
77 #include <sys/device.h>
79 #include <sys/kauth.h>
83 #include <machine/cpuconf.h>
84 #include <machine/autoconf.h>
85 #include <machine/rpb.h>
87 #include <alpha/pci/a12creg.h>
88 #include <alpha/pci/a12cvar.h>
89 #include <alpha/pci/pci_a12.h>
93 #define A12DC() /* Generate ctags(1) key */
97 int a12dcmatch(struct device
*, struct cfdata
*, void *);
98 void a12dcattach(struct device
*, struct device
*, void *);
101 struct device sc_dev
;
104 CFATTACH_DECL(a12dc
, sizeof(struct a12dc_softc
),
105 a12dcmatch
, a12dcattach
, NULL
, NULL
);
107 extern struct cfdriver a12dc_cd
;
109 dev_type_open(a12dcopen
);
110 dev_type_close(a12dcclose
);
111 dev_type_read(a12dcread
);
112 dev_type_write(a12dcwrite
);
113 dev_type_ioctl(a12dcioctl
);
114 dev_type_stop(a12dcstop
);
115 dev_type_tty(a12dctty
);
116 dev_type_poll(a12dcpoll
);
118 const struct cdevsw a12dc_cdevsw
= {
119 a12dcopen
, a12dcclose
, a12dcread
, a12dcwrite
, a12dcioctl
,
120 a12dcstop
, a12dctty
, a12dcpoll
, nommap
, ttykqfilter
, D_TTY
123 int a12dcfound
; /* There Can Be Only One. */
125 struct a12dc_config
{ int im_not_used
; } a12dc_configuration
;
127 static struct tty
*a12dc_tty
[1];
129 void a12dcstart(struct tty
*);
130 void a12dctimeout(void *);
131 int a12dcparam(struct tty
*, struct termios
*);
132 void a12dc_init(struct a12dc_config
*, int);
133 static void a12cdrputc(int);
134 int a12dccngetc(dev_t
);
135 void a12dccnputc(dev_t
, int);
136 void a12dccnpollc(dev_t
, int);
137 /* static int get_bc_char(int mn, int chan); */
138 /* static int get_bc_any(int,int *,int *); */
139 int a12dcintr(void *);
140 static void a12_worry(int worry_number
);
141 static void A12InitBackDriver(int);
144 a12dcmatch(struct device
*parent
, struct cfdata
*match
, void *aux
)
146 struct pcibus_attach_args
*pba
= aux
;
148 return cputype
== ST_AVALON_A12
153 a12dcattach(struct device
*parent
, struct device
*self
, void *aux
)
156 struct a12dc_config
*ccp
;
158 /* note that we've attached the chipset; can't have 2 A12Cs. */
161 printf(": driver %s\n", "$Revision: 1.24 $");
163 tp
= a12dc_tty
[0] = ttymalloc();
164 tp
->t_oproc
= a12dcstart
;
165 tp
->t_param
= a12dcparam
;
168 ccp
= &a12dc_configuration
;
173 a12dc_init(struct a12dc_config
*ccp
, int mallocsafe
)
178 * XXX definitions specific to only one of the kernels will be moved into
179 * kernel-local include files. (One of these days.)
181 #define spla12dc() spltty()
183 #define CDRADDR(m) ((mmreg_t *)(REGADDR(A12_CDR))) /* ignore m */
185 #define mb() alpha_mb()
186 #define wmb() alpha_wmb()
190 #include "product.def"
196 #define swpipl(a) (a)
199 #define hrhpanic(s,v) panic((s))
200 #define CDRADDR(m) ((mmreg_t *)(A12_BACKPLANE+(m)))
204 static int msgetput(register mstate_type
*, int, int);
205 static void checkinit(void);
208 A12InitBackDriver(int m
)
211 * XXX memset() would be good here, but there is a (temporary) reason
212 * for all this right now
214 a12_mstate
[m
].xcdr
= CDRADDR(m
);
215 a12_mstate
[m
].txrdy_out
= A12C_TXRDY
;
216 a12_mstate
[m
].txrdy_in
= A12C_TXRDY
;
217 a12_mstate
[m
].txack_out
= A12C_TXACK
;
218 a12_mstate
[m
].txack_in
= A12C_TXACK
;
219 a12_mstate
[m
].txsv
= tx_idle
;
220 a12_mstate
[m
].rxsv
= rx_idle
;
221 a12_mstate
[m
].reset_scanner
= 1;
222 a12_mstate
[m
].reset_loader
= 1;
223 a12_mstate
[m
].up
= 1;
224 a12_mstate
[m
].lastr
= 0; /* last char. received */
225 a12_mstate
[m
].lastrc
= 0; /* last received channel */
226 a12_mstate
[m
].rx_busy_wait
= 0; /* last received busy ticks */
227 a12_mstate
[m
].rx_busy_cnt
= 0; /* last received start clock */
228 a12_mstate
[m
].lastt
= 0; /* last char. trasmitted */
229 a12_mstate
[m
].lasttc
= 0; /* last transmit channel */
230 a12_mstate
[m
].tx_busy_wait
= 0; /* last transmitted busy ticks */
231 a12_mstate
[m
].tx_busy_cnt
= 0; /* last transmitted start clock */
232 a12_mstate
[m
].tbytes
= 0;
233 a12_mstate
[m
].tblkbytes
= 0;
234 a12_mstate
[m
].tblks
= 0;
235 a12_mstate
[m
].blwobe
= 0;
236 a12_mstate
[m
].blwbe
= 0;
237 a12_mstate
[m
].max_blkretry
= 0;
238 a12_mstate
[m
].max_blktime
= 0;
239 a12_mstate
[m
].max_blktimesz
= 0;
240 a12_mstate
[m
].avg_blksz
= 0;
241 a12_mstate
[m
].avg_blktime
= 0;
242 a12_mstate
[m
].retry_time
= 0;
251 A12InitBackDriver(0);
257 a12dcopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
259 int unit
= minor(dev
);
267 if (flags
& COM_HW_KGDB
)
271 if (!a12dc_tty
[unit
]) {
272 tp
= a12dc_tty
[unit
] = ttymalloc();
275 tp
= a12dc_tty
[unit
];
277 if (kauth_authorize_device_tty(l
->l_cred
, KAUTH_DEVICE_TTY_OPEN
, tp
))
282 tp
->t_oproc
= a12dcstart
;
283 tp
->t_param
= a12dcparam
;
285 if ((tp
->t_state
& TS_ISOPEN
) == 0) {
286 tp
->t_state
|= TS_CARR_ON
;
288 tp
->t_iflag
= TTYDEF_IFLAG
;
289 tp
->t_oflag
= TTYDEF_OFLAG
;
290 tp
->t_cflag
= TTYDEF_CFLAG
|CLOCAL
;
291 tp
->t_lflag
= TTYDEF_LFLAG
;
292 tp
->t_ispeed
= tp
->t_ospeed
= 9600;
295 a12_intr_register_icw(a12dcintr);
301 return (*tp
->t_linesw
->l_open
)(dev
, tp
);
305 a12dcclose(dev_t dev
, int flag
, int mode
, struct proc
*p
)
307 int unit
= minor(dev
);
308 struct tty
*tp
= a12dc_tty
[unit
];
310 (*tp
->t_linesw
->l_close
)(tp
, flag
);
316 a12dcread(dev_t dev
, struct uio
*uio
, int flag
)
318 struct tty
*tp
= a12dc_tty
[minor(dev
)];
320 return ((*tp
->t_linesw
->l_read
)(tp
, uio
, flag
));
324 a12dcwrite(dev_t dev
, struct uio
*uio
, int flag
)
326 struct tty
*tp
= a12dc_tty
[minor(dev
)];
328 return ((*tp
->t_linesw
->l_write
)(tp
, uio
, flag
));
332 a12dcpoll(dev_t dev
, int events
, struct proc
*p
)
334 struct tty
*tp
= a12dc_tty
[minor(dev
)];
336 return ((*tp
->t_linesw
->l_poll
)(tp
, events
, p
));
340 a12dcioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct proc
*p
)
342 int unit
= minor(dev
);
343 struct tty
*tp
= a12dc_tty
[unit
];
346 error
= (*tp
->t_linesw
->l_ioctl
)(tp
, cmd
, data
, flag
, p
);
347 if (error
!= EPASSTHROUGH
)
349 return ttioctl(tp
, cmd
, data
, flag
, p
);
353 a12dcparam(struct tty
*tp
, struct termios
*t
)
359 a12dcstart(struct tty
*tp
)
364 if (tp
->t_state
& (TS_TTSTOP
| TS_BUSY
))
367 tp
->t_state
|= TS_BUSY
;
368 while (tp
->t_outq
.c_cc
!= 0)
369 a12dccnputc(tp
->t_dev
, getc(&tp
->t_outq
));
370 tp
->t_state
&= ~TS_BUSY
;
376 * Stop output on a line.
379 a12dcstop(struct tty
*tp
, flag
)
384 if (tp
->t_state
& TS_BUSY
)
385 if ((tp
->t_state
& TS_TTSTOP
) == 0)
386 tp
->t_state
|= TS_FLUSH
;
399 while (a12dccnlookc(tp
->t_dev
, &c
)) {
400 if (tp
->t_state
& TS_ISOPEN
)
401 (*tp
->t_linesw
->l_rint
)(c
, tp
);
411 panic("a12dctty: bogus");
419 static struct consdev a12dccons
= {
420 NULL
, NULL
, a12dccngetc
, a12dccnputc
, a12dccnpollc
, NULL
,
424 a12dccons
.cn_dev
= makedev(cdevsw_lookup_major(&a12dc_cdevsw
), 0);
431 a12dccngetc(dev_t dev
)
438 a12dccnputc(dev_t dev
, int c
)
444 a12dccnpollc(dev_t dev
, int on
)
454 while(msgetput(MSP(0),CHANNEL_MONITOR
,c
)) {
467 static int srom_word_address
,
472 if(!get_bc_any(0,&bpchar
,&cnumber
))
476 printf("Unknown cdr channel %d",cnumber
);
480 printf("Ignoring new kernel\n");
486 #ifndef _KERNEL /* NetBSD kernel, that is. "if defined: rtmon kernel" */
488 srom_word_address
= bpchar
;
491 push_check_ok
= check_cdr_ok
;
494 write_ethernet_srom(srom_word_address
,bpchar
);
497 check_cdr_ok
= push_check_ok
;
501 logmchar(bpchar
,"<");
502 SerialByteReceived(bpchar
);
504 case CHANNEL_MONITOR
:
505 if (bpchar
== CPX_PANIC
)
506 /* TJF - Could kill all processes and then panic? */
507 hrhpanic("Panic in cooperating CPU.",0);
508 else cpxchar(bpchar
);
511 case CHANNEL_CONSOLE
:
512 #ifdef A12CON /* XXX this can be done much better */
513 virtual_keyboard_byte(bpchar
);
524 get_bc_any(int mn
, int *c
, int *chan
) {
525 mstate_type
*ms
= &a12_mstate
[mn
];
527 (void)mcgetput(mn
, 0, -1);
528 if(ms
->rxsv
==rx_busy
) {
529 *c
= ms
->c2b_char
& 0xff;
530 *chan
= ms
->c2b_channel
;
538 get_bc_char(int mn
, int chan
) {
541 if(get_bc_any(mn
,&newc
,&newchan
)) {
543 printf("receiver busy on dumb channel %d", newchan
);
551 msgetput(register mstate_type
*ms
, int channel
, int c
)
556 if(c
==-2 || ms
->up
==0) {
564 if(!(0<=channel
&& channel
<64)) {
569 for(i
=0; i
<20; ++i
) {
574 ms
->lasttc
= channel
;
575 ms
->cdr
= (ms
->cdr
& (A12C_TXACK
| A12C_TXRDY
))
580 ms
->cdr
= ((ms
->cdr
& A12C_TXACK
) &~ A12C_TXRDY
)
593 if((*ms
->xcdr
& A12C_TXACK
)==ms
->txack_in
) {
594 ms
->txrdy_out
^= A12C_TXRDY
;
595 ms
->txack_in
^= A12C_TXACK
;
610 if((t
& A12C_TXRDY
)==ms
->txrdy_in
) {
611 ms
->cdr
= (ms
->cdr
& ~A12C_TXACK
)
615 ms
->c2b_char
= t
& 0xff;
616 ms
->lastr
= ms
->c2b_char
;
617 ms
->c2b_channel
= (t
& CHMASK
) >> 8;
618 ms
->lastrc
= ms
->c2b_channel
;
619 ms
->txrdy_in
^= A12C_TXRDY
;
620 ms
->txack_out
^= A12C_TXACK
;
640 a12_worry(int worry_number
)
642 a12console_last_unexpected_error
= worry_number
;