/* autoconf.c 4.26 81/03/09 */
* Setup the system to run on the current machine.
* Configure() is called at boot time and initializes the uba and mba
* device tables and the memory controller monitoring. Available
* devices are determined (from possibilities mentioned in ioconf.c),
* and the drivers are initialized.
* N.B.: A lot of the conditionals based on processor type say
* which may be incorrect after more processors are introduced if they
* are like either of these machines. Thus the exact form of these
* lines may change. Will future machines have configuration registers
* in the adapters and probable nexus space (like the 780), or wired
* addresses (like the 750)? It remains to be seen.
* The following several variables are related to
* the configuration process, and are used in initializing
int cold
; /* if 1, still working on cold-start */
int nexnum
; /* current nexus number */
int dkn
; /* number of iostat dk numbers assigned so far */
* Addresses of the (locore) routines which bootstrap us from
* hardware traps to C code. Filled into the system control block
int (*mbaintv
[4])() = { Xmba0int
, Xmba1int
, Xmba2int
, Xmba3int
};
int (*ubaintv
[4])() = { Xua0int
, Xua1int
, Xua2int
, Xua3int
};
* These are the (fixed) addresses of the (last 8k bytes of) unibus memory for
* each of the 4 possible unibus adapters. Note that the unibus memory
* addresses are actually indexed by the unibus adapter type code,
* and are unrelated to tr (nexus) number.
(caddr_t
) 0x2013e000, (caddr_t
) 0x2017e000,
(caddr_t
) 0x201be000, (caddr_t
) 0x201fe000
* This allocates the space for the per-uba information,
* such as buffered data path usage.
struct uba_hd uba_hd
[MAXNUBA
];
* The bits which decode the fault bits in the configuration register
* of nexus's are reusable per nexus-type, so we declare them once here
char nexflt_bits
[] = NEXFLT_BITS
;
* Per-processor type initialization routines and data.
* It would be nice to parameterize initialization more,
* but the 780 and 750 are really quite different at this
* level. We await future machines before attempting
* any significant parameterization.
struct percpu percpu
[] = {
#define NCPU (sizeof(percpu)/sizeof(struct percpu))
* Determine mass storage and memory configuration for a machine.
* Get cpu type, and then switch out to machine specific procedures
* which will probe adaptors to see what is out there.
register struct percpu
*ocp
;
cpusid
.cpusid
= mfpr(SID
);
for (ocp
= percpu
; ocp
< &percpu
[NCPU
]; ocp
++)
if (ocp
->pc_cputype
== cpusid
.cpuany
.cp_type
) {
* Write protect the scb. It is strange
* that this code is here, but this is as soon
* as we are done mucking with it, and the
* write-enable was done in assembly language
* to which we will never return.
ip
= (int *)Sysmap
; *ip
&= ~PG_PROT
; *ip
|= PG_KR
;
printf("cpu type %d not configured\n", cpusid
.cpuany
.cp_type
);
* Build configuration table for a 780, by looking
* at the things (mbas and ubas) in the nexus slots
* and initialzing each appropriately.
register struct percpu
*pcpu
;
register struct nexus
*nxv
;
struct nexus
*nxp
= NEX780
;
for (nexnum
= 0,nxv
= nexus
; nexnum
< NNEX780
; nexnum
++,nxp
++,nxv
++) {
nxaccess(nxp
, Nexmap
[nexnum
]);
if (badaddr((caddr_t
)nxv
, 4))
if (nexcsr
.nex_csr
&NEX_APD
)
switch (nexcsr
.nex_type
) {
printf("mba%d at tr%d\n", nummba
, nexnum
);
printf("%d mba's", nummba
);
printf("uba%d at tr%d\n", numuba
, nexnum
);
setscbnex(ubaintv
[numuba
]);
i
= nexcsr
.nex_type
- NEX_UBA0
;
unifind((struct uba_regs
*)nxv
, (struct uba_regs
*)nxp
,
((struct uba_regs
*)nxv
)->uba_cr
=
UBACR_IFS
|UBACR_BRIE
|UBACR_USEFIE
|UBACR_SUEFIE
;
/* there can be more than one... are there other codes??? */
printf("mcr%d at tr%d\n", nmcr
, nexnum
);
mcraddr
[nmcr
++] = (struct mcr
*)nxv
;
printf("nexus type %x", nexcsr
.nex_type
);
printf(" unsupported (at tr %d)\n", nexnum
);
printf(" not configured\n");
timeout(ubawatch
, (caddr_t
)0, hz
);
* Configure a 750. There are four possible mba's,
* one standard UNIBUS, and a memory controller.
register struct nexus
*nxv
= nexus
;
struct nexus
*nxp
= NEX750
;
printf("mcr at %x\n", MCR_750
);
nxaccess((struct nexus
*)MCR_750
, Nexmap
[nexnum
]);
mcraddr
[nmcr
++] = (struct mcr
*)nxv
;
for (nexnum
= 0; nexnum
< NNEX750
; nexnum
++, nxp
++, nxv
++) {
nxaccess(nxp
, Nexmap
[nexnum
]);
if (badaddr((caddr_t
)nxv
, 4))
printf("mba%d at %x\n", nummba
, nxp
);
printf("%d mba(s) not configured\n", nummba
+1);
printf("uba at %x\n", nxp
);
nxaccess(nxp
, Nexmap
[nexnum
++]);
unifind((struct uba_regs
*)nxv
, (struct uba_regs
*)nxp
,
struct mba_device
*mbaconfig();
* Find devices attached to a particular mba
* and look for each device found in the massbus
register struct mba_regs
*mdp
;
register struct mba_drv
*mbd
;
register struct mba_device
*mi
;
register struct mba_slave
*ms
;
mdp
= (struct mba_regs
*)nxv
;
mba_hd
[nummba
].mh_mba
= mdp
;
mba_hd
[nummba
].mh_physmba
= (struct mba_regs
*)nxp
;
setscbnex(mbaintv
[nummba
]);
for (mbd
= mdp
->mba_drv
, dn
= 0; mbd
< &mdp
->mba_drv
[8]; mbd
++, dn
++) {
dt
= mbd
->mbd_dt
& 0xffff;
if ((dt
&MBDT_TYPE
) == MBDT_TU78
) {
printf("tm04/tu78 unsupported\n");
if ((mi
= mbaconfig(&fnd
, dt
)) && (dt
& MBDT_TAP
)) {
for (ms
= mbsinit
; ms
->ms_driver
; ms
++)
if (ms
->ms_driver
== mi
->mi_driver
&& ms
->ms_alive
== 0 &&
(ms
->ms_ctlr
== mi
->mi_unit
|| ms
->ms_ctlr
=='?')) {
mbd
->mbd_tc
= ms
->ms_slave
;
printf("%s%d at %s%d slave %d\n",
ms
->ms_ctlr
= mi
->mi_unit
;
(*ms
->ms_driver
->md_slave
)
* Have found a massbus device;
* see if it is in the configuration table.
* If so, fill in its data.
register struct mba_device
*ni
;
register struct mba_device
*mi
;
register struct mba_hd
*mh
;
for (mi
= mbdinit
; mi
->mi_driver
; mi
++) {
tp
= mi
->mi_driver
->md_type
;
for (mi
->mi_type
= 0; *tp
; tp
++, mi
->mi_type
++)
if (*tp
== (type
&MBDT_TYPE
))
#define match(fld) (ni->fld == mi->fld || mi->fld == '?')
if (!match(mi_drive
) || !match(mi_mbanum
))
printf("%s%d at mba%d drive %d",
mi
->mi_driver
->md_dname
, mi
->mi_unit
,
ni
->mi_mbanum
, ni
->mi_drive
);
mh
= &mba_hd
[ni
->mi_mbanum
];
mh
->mh_mbip
[ni
->mi_drive
] = mi
;
mi
->mi_drv
= &mi
->mi_mba
->mba_drv
[ni
->mi_drive
];
mi
->mi_driver
->md_info
[mi
->mi_unit
] = mi
;
mi
->mi_mbanum
= ni
->mi_mbanum
;
mi
->mi_drive
= ni
->mi_drive
;
if (mi
->mi_dk
&& dkn
< DK_NDRIVE
)
(*mi
->mi_driver
->md_attach
)(mi
);
* Fixctlrmask fixes the masks of the driver ctlr routines
* which otherwise save r10 and r11 where the interrupt and br
* level are passed through.
register struct uba_ctlr
*um
;
register struct uba_device
*ui
;
register struct uba_driver
*ud
;
#define phys(a,b) ((b)(((int)(a))&0x7fffffff))
for (um
= ubminit
; ud
= phys(um
->um_driver
, struct uba_driver
*); um
++)
*phys(ud
->ud_probe
, short *) &= ~0xc00;
for (ui
= ubdinit
; ud
= phys(ui
->ui_driver
, struct uba_driver
*); ui
++)
*phys(ud
->ud_probe
, short *) &= ~0xc00;
* Find devices on a UNIBUS.
* Uses per-driver routine to set <br,cvec> into <r11,r10>,
* and then fills in the tables, with help from a per-driver
* slave initialization routine.
unifind(vubp
, pubp
, vumem
, pumem
)
struct uba_regs
*vubp
, *pubp
;
register int br
, cvec
; /* MUST BE r11, r10 */
* Lint doesn't realize that these
* can be initialized asynchronously
* when devices interrupt.
register int br
= 0, cvec
= 0;
register struct uba_device
*ui
;
register struct uba_ctlr
*um
;
int i
, (**ivec
)(), haveubasr
= 0;
* Initialize the UNIBUS, by freeing the map
* registers and the buffered data path registers
uhp
->uh_map
= (struct map
*)calloc(UAMSIZ
* sizeof (struct map
));
rminit(uhp
->uh_map
, NUBMREG
, 1, "uba", UAMSIZ
);
uhp
->uh_bdpfree
= (1<<NBDP780
) - 1;
uhp
->uh_bdpfree
= (1<<NBDP750
) - 1;
* Save virtual and physical addresses
* of adaptor, and allocate and initialize
* the UNIBUS interrupt vector.
uhp
->uh_vec
= (int(**)())calloc(512);
for (i
= 0; i
< 128; i
++)
scbentry(&catcher
[i
*2], SCB_ISTACK
);
/* THIS IS A CHEAT: USING THE FACT THAT UMEM and NEXI ARE SAME SIZE */
nxaccess((struct nexus
*)pumem
, UMEMmap
[numuba
]);
vubp
->uba_sr
= vubp
->uba_sr
;
vubp
->uba_cr
= UBACR_IFS
|UBACR_BRIE
;
* Map the first page of UNIBUS i/o
* space to the first page of memory
* for devices which will need to dma
* output to produce an interrupt.
*(int *)(&vubp
->uba_map
[0]) = UBAMR_MRV
;
#define ubaddr(off) (u_short *)((int)vumem + ((off)&0x1fff))
* Check each unibus mass storage controller.
* For each one which is potentially on this uba,
* see if it is really there, and if it is record it and
* then go looking for slaves.
for (um
= ubminit
; udp
= um
->um_driver
; um
++) {
if (um
->um_ubanum
!= numuba
&& um
->um_ubanum
!= '?')
addr
= (u_short
)um
->um_addr
;
if (badaddr((caddr_t
)reg
, 2))
if (haveubasr
&& vubp
->uba_sr
) {
vubp
->uba_sr
= vubp
->uba_sr
;
i
= (*udp
->ud_probe
)(reg
);
if (haveubasr
&& vubp
->uba_sr
) {
vubp
->uba_sr
= vubp
->uba_sr
;
printf("%s%d at uba%d csr %o ",
udp
->ud_mname
, um
->um_ctlr
, numuba
, addr
);
printf("didn't interrupt\n");
printf("vec %o, ipl %x\n", cvec
, br
);
um
->um_hd
= &uba_hd
[numuba
];
um
->um_addr
= (caddr_t
)reg
;
udp
->ud_minfo
[um
->um_ctlr
] = um
;
for (ivec
= um
->um_intr
; *ivec
; ivec
++) {
um
->um_hd
->uh_vec
[cvec
/4] =
scbentry(*ivec
, SCB_ISTACK
);
for (ui
= ubdinit
; ui
->ui_driver
; ui
++) {
if (ui
->ui_driver
!= udp
|| ui
->ui_alive
||
ui
->ui_ctlr
!= um
->um_ctlr
&& ui
->ui_ctlr
!= '?' ||
ui
->ui_ubanum
!= numuba
&& ui
->ui_ubanum
!= '?')
if ((*udp
->ud_slave
)(ui
, reg
)) {
ui
->ui_ctlr
= um
->um_ctlr
;
ui
->ui_hd
= &uba_hd
[numuba
];
ui
->ui_addr
= (caddr_t
)reg
;
ui
->ui_physaddr
= pumem
+ (addr
&0x1fff);
if (ui
->ui_dk
&& dkn
< DK_NDRIVE
)
/* ui_type comes from driver */
udp
->ud_dinfo
[ui
->ui_unit
] = ui
;
printf("%s%d at %s%d slave %d\n",
udp
->ud_dname
, ui
->ui_unit
,
udp
->ud_mname
, um
->um_ctlr
, ui
->ui_slave
);
* Now look for non-mass storage peripherals.
for (ui
= ubdinit
; udp
= ui
->ui_driver
; ui
++) {
if (ui
->ui_ubanum
!= numuba
&& ui
->ui_ubanum
!= '?' ||
ui
->ui_alive
|| ui
->ui_slave
!= -1)
addr
= (u_short
)ui
->ui_addr
;
if (badaddr((caddr_t
)reg
, 2))
if (haveubasr
&& vubp
->uba_sr
) {
vubp
->uba_sr
= vubp
->uba_sr
;
i
= (*udp
->ud_probe
)(reg
);
if (haveubasr
&& vubp
->uba_sr
) {
vubp
->uba_sr
= vubp
->uba_sr
;
printf("%s%d at uba%d csr %o ",
ui
->ui_driver
->ud_dname
, ui
->ui_unit
, numuba
, addr
);
printf("didn't interrupt\n");
printf("vec %o, ipl %x\n", cvec
, br
);
ui
->ui_hd
= &uba_hd
[numuba
];
for (ivec
= ui
->ui_intr
; *ivec
; ivec
++) {
ui
->ui_hd
->uh_vec
[cvec
/4] =
scbentry(*ivec
, SCB_ISTACK
);
ui
->ui_addr
= (caddr_t
)reg
;
ui
->ui_physaddr
= pumem
+ (addr
&0x1fff);
/* ui_type comes from driver */
udp
->ud_dinfo
[ui
->ui_unit
] = ui
;
register struct scb
*scbp
= &scb
;
scbp
->scb_ipl14
[nexnum
] = scbp
->scb_ipl15
[nexnum
] =
scbp
->scb_ipl16
[nexnum
] = scbp
->scb_ipl17
[nexnum
] =
scbentry(fn
, SCB_ISTACK
);
* Make a nexus accessible at physical address phys
* by mapping kernel ptes starting at pte.
* WE LEAVE ALL NEXI MAPPED; THIS IS PERHAPS UNWISE
* SINCE MISSING NEXI DONT RESPOND. BUT THEN AGAIN
* PRESENT NEXI DONT RESPOND TO ALL OF THEIR ADDRESS SPACE.
register struct pte
*pte
;
register int i
= btop(sizeof (struct nexus
));
register unsigned v
= btop(physa
);
*(int *)pte
++ = PG_V
|PG_KW
|v
++;