|
|
Power 6/32 Unix version 1.2b
#include "vioc.h"
#include "conf.h"
#include "const.h"
#include "pte.h"
#define ON 0x80
#define OFF 0
#define LOOPBK 0
#define ECHO 1
#define MAXPORT 16
#define MAXRLEN 50
#define MAXSLEN 256
#define HEAD "\n\r\t** VIOC test **\n"
#define PORT "\rlogical port no "
#define NL writec('\n')
/* Pointers to VIOC structures in I/O space */
struct vblok *VP; /* Pointer to commom buffer */
struct cmd_inp cblok; /* VIOC command block (from HOST) */
struct cmd_res *rblok; /* PTR to CMD respond blk (from VIOC) */
short *s_entry;
short cmdrsp[MAXRLEN];
long msg_on = 1; /* Global flag to enable messages */
long cmd_id = 0;
long IObase; /* Virtual Address of VIOC base */
long vioc_ack, vioc_rsp;
long log_p0 = 1; /* Logical port no. of 1st terminal */
long log_pn = 0; /* Logical port no. of last terminal */
char port_on[MAXPORT];
extern long savvec3, unused, clk_cnt, proc_no;
vioc()
{ register long ix;
long v_reset(), v_init();
m_vioc(); /* Set up map for IO space */
init_vec(); /* Set up int. handlers */
if (!v_reset()) return(0); /* Reset VIOC */
writes("\nVIOC controller is at "); writeh(VBASE);
if (!v_init()) return(0); /* Initialize VIOC */
return(1);
}
/* Routine to map VIOC :
VIOC space is map from 1st unused virtual page on
*/
m_vioc()
{ long phys_pg, pte, old_pte, which1;
phys_pg = ((VBASE+IOBASE) >> PGSHIFT) & 0x3fffff;
/* 1st physical page of VIOC in IO space */
pte = phys_pg | PG_KW | PG_V | PG_NC;
for (which1=unused; which1<(unused+VIOC_LEN); which1++) {
fix_pte(SBR,which1,&old_pte,pte);
pte++; }
VP = (struct vblok *)(unused << PGSHIFT);
IObase = (long)VP; /* Base addr of common buffer */
asm("mfpr $SLR,_savvec3");
savvec3 += VIOC_LEN;
asm("mtpr _savvec3,$SLR");
unused = which1; /* Next unused PTE in system map */
}
/* Initialize Tahoe SCB vectors to handle VIOC interrupts
*/
init_vec()
{ long old_vec1, old_vec2, old_vec3;
asm("movab ack_hdlr,_savvec3");
set_handler(ACK_VIOC,&old_vec1,savvec3); /* Set handler for VIOC ACK */
asm("movab rsp_hdlr,_savvec3");
set_handler(CMD_RESP,&old_vec2,savvec3); /* Set handler for VIOC RSP */
asm("movab unsol_hdlr,_savvec3");
set_handler(UNS_VEC,&old_vec3,savvec3); /* Set hdler for VIOC UNSOL */
}
/* Routine to Reset VIOC
Poll for 10 sec. then check
if (VIOC busy flag is clear) and (VIOC is ready)
*/
v_reset()
{ register long cnt, stat, r10;
VP->v_vioc = V_BSY; /* Set VIOC busy flag */
VP->v_ident = (short)0;
VP->v_hdwre = V_RESET; /* Reset VIOC */
cnt = 200; /* Might need to be tuned ! */
while (VP->v_ident==(short)0) /* WATCH OUT WHEN DATA CACHE IS ON */
{ DELAY(0x50000);
if (--cnt == 0) { writes("\nVIOC error, Time out on Reset !");
return(0); }
}
cnt = 0x1ffffff; /* Need to be TUNED */
for (;cnt != 0;--cnt); /* VIOC is executing its diagnostic */
if ((VP->v_ident != (short)V_ALLOK) &&
(VP->v_ident != (unsigned short)0x5555) ) {
writes("\nVIOC error after Reset !");
stat = ((long)VP->v_ident) & 0xffff;
writes("\nFault code : ");
writeh(stat); writec('\n');
return(0);
}
VP->v_ustat = VP->v_uqual = 0; /* Clear UNSOL. BUFF */
return(1);
}
/* VIOC initialization routines : Sent LIDENT cmd
(1) Define interrupt vectors
(2) Set 1st, Last logical port no.
*/
v_init()
{ short *flycmd(), *rsp_blk, stat_wd;
cblok.opcode = LIDENT; /* Set opcode */
cblok.byte[0] = ACK_VIOC; /* Set interrupt vectors */
cblok.byte[1] = CMD_RESP;
cblok.byte[3] = UNS_VEC;
cblok.byte[4] = 16; /* Max no port to turn on */
cblok.byte[5] = log_p0 = 1; /* 1st port is logical no. 1 */
/* Sent command to VIOC */
log_pn = 0;
rsp_blk = flycmd(&stat_wd);
if ((stat_wd & 0x7f00) != 0x300) {
writes("LIDENT error ");
stat_wd = (stat_wd >> 8) & 0xff;
writeh((long)stat_wd); NL;
return(0);
asm("halt");
}
log_pn = (long)(rsp_blk[6] & 0xff); /* Last log. port no */
rsp2v(rsp_blk); /* Sent a cmd respond int. to VIOC */
if (log_pn < log_p0) writes("0 port available.\n");
else {
set_port();
writes("\nLast port no. ");
writed(log_pn); writec('\n');
}
return(1);
}
/* check out how many ports are on line
*/
set_port()
{ long ix;
/* Initialze ports */
for(ix=1; ix<=log_pn; ix++) {
msg_on = 0;
port_on[ix-1] = (char)1; /* This port is on */
if ( !v_initp(ix,NDBT,NSBT,BAUD,PARY)) {
port_on[ix-1] = (char)0; /* This port is off */
writes("Port "); writeh(ix);
writes(" is not on line\n");
}
else {
init_buf(ix); /* Init. input buffer */
}
msg_on = 1;
}
}
/* routine to inittialize input buffer for port X
input : pno - logical port no. on VIOC
*/
init_buf(pno)
long pno;
{ struct vbuf *vb;
register long ix;
vb = &vi_buf[pno-1];
vb->cnt = vb->nxt_c = vb->nxt_fill = 0;
for(ix=0; ix<BUFLEN; ix++) vb->buf[ix] = 0;
}
/* Routine to sent LPRARAX command to VIOC
Also used to probe if a port is on line
return 1 if port is on line else return 0
*/
v_initp(pno, ndbits, nsbits, baud, parity)
long pno, ndbits, nsbits, baud, parity;
{
short *flycmd(), stat_wd, *rsp_blk;
cblok.opcode = LPARAX; /* Set opcode */
cblok.byte[0] = 0; /* not used */
cblok.byte[1] = (char)pno; /* Port no. */
cblok.byte[2] = 0; /* Enable port's transmitter */
cblok.byte[3] = 0;
cblok.byte[4] = (char)ndbits; /* no. data bit */
cblok.byte[5] = (char)nsbits; /* no. stop bit */
cblok.byte[6] = (char)baud; /* Baud rate */
cblok.byte[7] = (char)parity; /* Parity */
/* Sent command to VIOC */
rsp_blk = flycmd(&stat_wd);
rsp2v(rsp_blk); /* Sent a cmd respond int. to VIOC */
if (stat_wd) { /* CMD Respond error */
if (msg_on) {
writes("LPARAX error ");
stat_wd = (stat_wd >> 8) & 0xff;
writeh((long)stat_wd); NL; }
return(0);
}
return(1);
}
/* Routine to sent AUTO loop back/local echo
command to VIOC;
return 1 if port is on line else return 0
*/
v_autol(pno,on,op)
long pno,on, op;
{
short *flycmd(), stat_wd, *rsp_blk;
cblok.opcode = AUTOLP; /* Set opcode */
cblok.byte[0] = on | op; /* enable/disable auto loopback/echo */
cblok.byte[1] = pno; /* port no */
/* Sent command to VIOC */
rsp_blk = flycmd(&stat_wd);
rsp2v(rsp_blk); /* Sent a cmd respond int. to VIOC */
if (stat_wd) { /* CMD Respond error */
if (msg_on) {
writes("AUTOLP error ");
stat_wd = (stat_wd >> 8) & 0xff;
writeh((long)stat_wd); NL; }
return(0);
}
return(1);
}
/* Sent a command to VIOC. wait for respond and
(1) return pointer to respond buffer
(2) output paramter :
stat = 1st word of respond buffer if error;
0 if command sucessfully executed by VIOC
*/
short *flycmd(stat)
short *stat;
{ register long *r12;
short *sent_cmd(), *rsp_blk, stat_wd;
rsp_blk = sent_cmd(&cblok); /* issue command to VIOC */
if ( !rsp_blk ) { /* HOST issued invalid interrupt */
stop();
}
stat_wd = (*rsp_blk) & 0xffff;
if ( stat_wd & (V_ERR << 8) ) *stat = stat_wd;
else *stat = 0;
return(rsp_blk);
}
/* Routine to sent a command to VIOC, Command buffer should be
filled by HOST before calling this routine :
Issue CMD INP INT to VIOC, Wait for VIOC to sent ACK INT
If VIOC ACK with INT ERR bit set print INT ERR code and return 0
else wait for CMD RESP INT from VIOC
Return pointer to Command Respond block.
*/
short *sent_cmd(cmdblk)
struct cmd_inp *cmdblk;
{
register long cnt, *r11;
register short *rsp_stat;
short *sptr, *gt_rspadr(), ix;
cnt = 0x100;
while (v_busy()) /* Test VIOC Busy flag */
{ DELAY(0x50000);
if (--cnt == 0) panic("\nSent_cmd time out\n");
}
if (!v_rdy4cmd()) /* VIOC not ready for new command */
{ DELAY(0x50000);
if (--cnt == 0) panic("\nSent_cmd not ready\n");
}
set_cadr((long)cmdblk); /* Set cmd address in commom buffer */
VP->v_vcbsy = V_BSY; /* Set CMD BUSY FLAG */
v_int((char)V_CMDI); /* Sent CMD INPUT INTERRUPT */
for(vioc_ack=1;vioc_ack != 0;); /* Wait for ACK */
if (VP->v_vcid & V_ERR)
{ /* Interrupt error */
writes("\nCmd input Int. error ");
writeh((long)(VP->v_vcid & 0x3)); NL;
return(0);
}
cmd_id = (long)VP->v_vcid & 0xf; /* Get command ID from VIOC */
for(vioc_rsp=1;vioc_rsp != 0;); /* Wait for CMD respond int. */
rsp_stat = gt_rspadr(); /* Get addr of Respond buffer */
/* For debugging only : Read command respond buffer from VIOC */
sptr = rsp_stat;
for (ix=0; ix <MAXRLEN; ix++) cmdrsp[ix] = *sptr++;
return(rsp_stat);
}
/* This routine sent a command respond interrupt to VIOC
*/
rsp2v(rsp_blk)
short *rsp_blk;
{ register long cnt;
cnt = 0x100;
while (v_busy()) /* Test VIOC Busy flag */
{ DELAY(0x50000);
if (--cnt == 0) panic("\nRsp2v time out\n");
}
*rsp_blk = 0; /* Clear RESP. BUSY Flag */
v_int((char)V_CMDRI); /* Sent a cmd respond int. to VIOC */
}
/* Routine to sent a string to port #pno
Return a 1 if command executed else return 0
*/
pstr(pno,c)
long pno;
char *c;
{ register long *lptr, slen, phys_adr;
char *cptr;
short *rsp_blk, stat_wd , *flycnd();
/* Count length of string */
slen = 0;
for (cptr=c; *cptr++ != NULL; slen++);
/* Fill command buffer */
cblok.opcode = (short)XMITDTA; /* XMIT opcode */
cblok.byte[0] = (char)pno; /* Port no. */
cblok.byte[1] = (char)slen; /* Byte count */
lptr = (long *)&cblok.byte[2];
phys_adr = va2pa((long)c); /* Convert VA of string to phys. addr */
*lptr = (long)phys_adr; /* Set address of buffer */
rsp_blk = flycmd(&stat_wd); /* Sent command to VIOC */
rsp2v(rsp_blk); /* sent respond int. to VIOC */
if (stat_wd) {
writes("XMITDTA error ");
stat_wd = (stat_wd >> 8) & 0xff;
writeh((long)stat_wd); NL;
return(0);
}
return(1);
}
/* Routine to put a char to port #pno
*/
pchar(pno,c)
long pno;
char c;
{
char str[3];
str[0] = c;
if (c=='\n') {
str[1] = '\r';
str[2] = NULL; }
else str[1] = NULL;
return(pstr(pno,str));
}
/* Routine return the address of CMD RESP. Buffer in
shared area
*/
short *gt_rspadr()
{
return((short *)((long)VP + VP->v_rsp));
}
/* Routine to sent an interrupt to VIOC
Input : Bit 0,1 of 'qual' indicate type of interrupt
*/
v_int(qual)
char qual;
{
char vint;
vint = (char)((V_BSY | qual) & 0xff);
VP->v_vioc = vint; /* Set busy flag, int. qualifier */
VP->v_hdwre = V_INTR; /* Interrupt VIOC */
}
/* Routine to test if VIOC is ready to accept new command
Return 1 if ready Else return 0
*/
v_rdy4cmd()
{ register long *r12;
if (VP->v_vcbsy & V_BSY) {
return(0);
}
else return(1);
}
/* Routine to test if VIOC busy, Return 1
if not busy Else return 0
*/
v_busy()
{ register long *r12;
if (VP->v_vioc & V_BSY) return(1);
else {
return(0);
}
}
/* Routine to set cmd address in commom buffer.
Command address has to be translated to physical
address.
input : blkadr (virtual address)
*/
set_cadr(blkadr)
long blkadr;
{ register long word1, cmdadr;
cmdadr = va2pa(blkadr); /* VA to physical address */
VP->v_vcp1 = (short)(cmdadr & 0xffff);
word1 = (cmdadr >> 16) & 0xffff;
VP->v_vcp0 = (short)word1;
}
/* Routine translate virtual address to physical address
*/
va2pa(va)
long va;
{ register long *base, pte, pte_no, page_no, cmdadr;
/* Translate virtual to physical address */
asm("mfpr $SBR,r12");
pte_no = (va >> PGSHIFT) & 0x3fffff; /* Virtual pgno of cmd addr */
pte = base[pte_no]; /* PTE for this page no */
page_no = pte & 0x3fffff;
cmdadr = (page_no << PGSHIFT) | (va & 0x3ff);
return(cmdadr);
}
panic(msg)
char *msg;
{
writes(msg);
stop();
}
stop()
{
asm("halt");
}
/* Handler of VIOC CMD RESP. INT */
rsp_handlr()
{
asm(".align 2");
asm(".globl rsp_hdlr");
asm("rsp_hdlr:");
vioc_rsp = 0; /* Clear Vioc_rsp flag */
asm("rei");
}
/* Handler of VIOC ACK INT */
ack_handlr()
{
asm(".align 2");
asm(".globl ack_hdlr");
asm("ack_hdlr:");
vioc_ack = 0; /* Clear Vioc ack flag */
asm("rei");
}
/* Global variables used in Unsolicited int. handler */
long silo_no, no_char, cin, count;
char ascii;
/* Handler of VIOC UNSOLICITED interrupt : service on ISP
(1) Dump silo contents
*/
unsol_handlr()
{
asm(".align 2");
asm(".globl unsol_hdlr");
asm("unsol_hdlr:");
asm("svpctx"); /* Save context, also switch to ISP */
dmp_silo();
asm("ldpctx"); /* Restore context, switch to KSP */
asm("rei");
}
dmp_silo()
{ register long rsp_qual, pno, error, rec_err;
rec_err = 0;
rsp_qual = VP->v_uqual & 0x7;
switch (rsp_qual) {
case 1 : {
writes("received data error\n");
rec_err = 1;
goto nomore; }
case 2 : {
writes("VIOC process error\n");
goto nomore; }
case 3 : {
writes("data set change ");
writeh(VP->v_uqual & 0x3f); NL;
goto nomore; }
case 4 : {
writes("secondary receive change");
goto nomore; }
case 5 : {
writes("undefined respond error code ");
writeh(rsp_qual); NL;
goto nomore; }
}
/* Data available */
silo_no = (long)VP->v_usdata[0];
for(;;) {
s_entry = (short *)(IObase+SILO_BASE + (silo_no * SILO_DEPTH));
cin = (long)((*s_entry) & 0xff); /* Get char. count */
if (cin==0) goto nomore;
/* Print contents of 1 SILO */
for(no_char=1; no_char<=cin; no_char++)
{
ascii = (char)((s_entry[no_char] & 0xff00) >> 8);
if ( !(s_entry[no_char] & 0x00c0) ) {
pno = s_entry[no_char] & 0x3f;
/* Check for port no out of bound */
if (!((pno>log_pn) || (pno<log_p0))) {
fillc(pno,ascii); }
}
else {
/* Data receive error : parity,frame,overrun */
/*
writes("data receive error ");
error = (long)(s_entry[no_char] & 0xc0) >> 6;
writeh(error & 0x3); NL;
*/
}
}
*s_entry = 0; /* Clear char. count */
silo_no++; /* Proceed to next silo */
}
nomore:
count = 200;
while (v_busy()) /* Test VIOC Busy flag */
{ DELAY(0x50000);
if (--count == 0)
panic("\nUNSOL hdlr : Time out on VIOC busy flag..\n");
}
VP->v_uqual = 0; /* Reset UNSOL BUSY FLAG */
v_int((char)V_URESP); /* Sent ACK UNSOL interrupt to VIOC */
return(0);
}
fillc(pno,c)
long pno;
char c;
{ struct vbuf *vb;
vb = &vi_buf[pno-1];
if (vb->cnt >= BUFLEN) {
writes("\ninput overflow port ");
writed(pno); NL;
return(0); }
vb->buf[vb->nxt_fill++] = c;
vb->cnt++;
if (vb->nxt_fill > BUFLEN) vb->nxt_fill = 0;
}
char get1c(pno)
long pno;
{ struct vbuf *vb;
char c;
vb = &vi_buf[pno-1];
if (vb->cnt == 0) return((char)0xff);
c = vb->buf[vb->nxt_c++];
vb->cnt--;
if (vb->nxt_c > BUFLEN) vb->nxt_c = 0;
return(c);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.