* Copyright (c) 1982 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)autoconf.c 6.14 (Berkeley) %G%
* 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.
* use pcpu info about whether a ubasr exists
#include "../vaxmba/mbareg.h"
#include "../vaxmba/mbavar.h"
#include "../vaxuba/ubareg.h"
#include "../vaxuba/ubavar.h"
* 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 nsbi
; /* current sbi 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
};
Need to expand the table
for more than
4 massbus adaptors
#if defined(VAX780) || defined(VAX8600)
Xua0int
, Xua1int
, Xua2int
, Xua3int
,
Xua4int
, Xua5int
, Xua6int
, Xua7int
,
Need to expand the table
for more than
8 unibus adaptors
* This allocates the space for the per-uba information,
* such as buffered data path usage.
struct uba_hd uba_hd
[NUBA
];
* 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
->pc_cputype
; ocp
++)
if (ocp
->pc_cputype
== cpusid
.cpuany
.cp_type
) {
* Write protect the scb and UNIBUS interrupt vectors.
* 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
+ 1; *ip
&= ~PG_PROT
; *ip
|= PG_KR
;
ip
++; *ip
&= ~PG_PROT
; *ip
|= PG_KR
;
ip
++; *ip
&= ~PG_PROT
; *ip
|= PG_KR
;
* Configure swap area and related system
* parameter based on device(s) used.
printf("cpu type %d not configured\n", cpusid
.cpuany
.cp_type
);
register struct percpu
*pcpu
;
register struct ioa
*ioap
;
struct sbia_regs
*sbiaregs
;
for (;ioanum
< pcpu
->pc_nioa
; ioanum
++,
ioap
= (struct ioa
*)((caddr_t
)ioap
+ pcpu
->pc_ioasize
)) {
ioa_paddr
= pcpu
->pc_ioaaddr
[ioanum
];
nxaccess(ioa_paddr
, Ioamap
[ioanum
], pcpu
->pc_ioasize
);
type
= (int)pcpu
->pc_ioatype
[ioanum
];
ioacsr
.ioa_csr
= ioap
->ioacsr
.ioa_csr
;
type
= ioacsr
.ioa_type
& IOA_TYPMSK
;
type
= (int)pcpu
->pc_ioatype
[ioanum
];
printf("SBIA%d at IO adaptor %d address 0x%x\n",
nsbi
, ioanum
, ioa_paddr
);
probesbi(&sbi8600
[nsbi
]);
sbiaregs
= (struct sbia_regs
*)ioap
;
sbiaregs
->sbi_errsum
= -1;
sbiaregs
->sbi_error
= 0x1000;
sbiaregs
->sbi_fltsts
= 0xc0000;
"IOA%d at address 0x%x is unsupported (type = 0x%x)\n",
ioanum
, ioa_paddr
, ioacsr
.ioa_type
);
printf("IOA%d type 0x%x unknown\n", ioanum
,
* Probe nexus space, finding the interconnects
* and setting up and probing mba's and uba's for devices.
register struct persbi
*psbi
;
register struct nexus
*nxv
;
struct nexus
*nxp
= psbi
->psb_nexbase
;
for (; nexnum
< psbi
->psb_nnexus
; nexnum
++, nxp
++, nxv
++) {
* the 16 below shouldn't be there, but the constant
* is used at other points (vax/Locore.c)
nxaccess(nxp
, Nexmap
[nsbi
* 16 + nexnum
], sizeof(struct nexus
));
if (badaddr((caddr_t
)nxv
, 4))
if (psbi
->psb_nextype
&& psbi
->psb_nextype
[nexnum
] != NEX_ANY
)
nexcsr
.nex_csr
= psbi
->psb_nextype
[nexnum
];
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
);
if (numuba
>= 2 && cpu
== VAX_750
) {
printf("More than 2 UBA's");
printf("%d uba's", ++numuba
);
#if defined(VAX780) || defined(VAX8600)
if ((cpu
== VAX_780
) || (cpu
== VAX_8600
))
setscbnex(ubaintv
[numuba
]);
i
= nexcsr
.nex_type
- NEX_UBA0
;
unifind((struct uba_regs
*)nxv
, (struct uba_regs
*)nxp
,
umem
[numuba
], psbi
->psb_umaddr
[i
], UMEMmap
[numuba
],
#if defined(VAX780) || defined(VAX8600)
if ((cpu
== VAX_780
) || (cpu
== VAX_8600
))
((struct uba_regs
*)nxv
)->uba_cr
=
UBACR_USEFIE
|UBACR_SUEFIE
|
(((struct uba_regs
*)nxv
)->uba_cr
&0x7c000000);
/* 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("mcr%d (el) at tr%d\n", nmcr
, nexnum
);
mcraddr
[nmcr
++] = (struct mcr
*)nxv
;
if (nexcsr
.nex_type
!= NEX_MEM64I
&&
nexcsr
.nex_type
!= NEX_MEM256I
)
printf("mcr%d (eu) 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");
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
++) {
if ((mbd
->mbd_ds
&MBDS_DPR
) == 0)
mdp
->mba_sr
|= MBSR_NED
; /* si kludge */
dt
= mbd
->mbd_dt
& 0xffff;
if (mdp
->mba_sr
&MBSR_NED
)
continue; /* si kludge */
#define qeq(a, b) ( a == b || a == '?' )
if ((mi
= mbaconfig(&fnd
, dt
)) && (dt
& MBDT_TAP
))
for (sn
= 0; sn
< 8; sn
++) {
for (ms
= mbsinit
; ms
->ms_driver
; ms
++)
if (ms
->ms_driver
== mi
->mi_driver
&&
qeq(ms
->ms_ctlr
, mi
->mi_unit
) &&
(*ms
->ms_driver
->md_slave
)(mi
, ms
, sn
)) {
printf("%s%d at %s%d slave %d\n"
, ms
->ms_driver
->md_sname
, mi
->mi_driver
->md_dname
ms
->ms_ctlr
= mi
->mi_unit
;
* 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\n",
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_mbanum
= ni
->mi_mbanum
;
mi
->mi_drive
= ni
->mi_drive
;
* If drive has never been seen before,
* give it a dkn for statistics.
if (mi
->mi_driver
->md_info
[mi
->mi_unit
] == 0) {
mi
->mi_driver
->md_info
[mi
->mi_unit
] = mi
;
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
, memmap
, haveubasr
)
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
;
caddr_t ualloc
, zmemall();
* Initialize the UNIBUS, by freeing the map
* registers and the buffered data path registers
uhp
->uh_map
= (struct map
*)calloc(UAMSIZ
* sizeof (struct map
));
* Save virtual and physical addresses
* of adaptor, and allocate and initialize
* the UNIBUS interrupt vector.
uhp
->uh_vec
= (int(**)())calloc(512);
uhp
->uh_vec
= (int(**)())calloc(512);
for (i
= 0; i
< 128; i
++)
scbentry(&catcher
[i
*2], SCB_ISTACK
);
* Set last free interrupt vector for devices with
* programmable interrupt vectors. Use is to decrement
* this number and use result as interrupt vector.
ubaaccess(pumem
, memmap
, UBAPAGES
* NBPG
);
#if defined(VAX780) || defined(VAX8600)
vubp
->uba_sr
= vubp
->uba_sr
;
vubp
->uba_cr
= UBACR_IFS
|UBACR_BRIE
;
* First configure devices that have unibus memory,
* allowing them to allocate the correct map registers.
* Grab some memory to record the umem address space we allocate,
* so we can be sure not to place two devices at the same address.
* We could use just 1/8 of this (we only want a 1 bit flag) but
* we are going to give it back anyway, and that would make the
* code here bigger (which we can't give back), so ...
* One day, someone will make a unibus with something other than
* an 8K i/o address space, & screw this totally.
ualloc
= zmemall(memall
, 8*1024);
if (ualloc
== (caddr_t
)0)
panic("no mem for unifind");
* 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 ubaoff(off) ((off)&0x1fff)
#define ubaddr(off) (u_short *)((int)vumem + (ubaoff(off)|0x3e000))
* 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
;
* use the particular address specified first,
* or if it is given as "0", of there is no device
* at that address, try all the standard addresses
* in the driver til we find it
for (ap
= udp
->ud_addr
; addr
|| (addr
= *ap
++); addr
= 0) {
if (ualloc
[ubaoff(addr
)])
if (badaddr((caddr_t
)reg
, 2))
#if defined(VAX780) || defined(VAX8600)
if (haveubasr
&& vubp
->uba_sr
) {
vubp
->uba_sr
= vubp
->uba_sr
;
i
= (*udp
->ud_probe
)(reg
, um
->um_ctlr
, um
);
#if defined(VAX780) || defined(VAX8600)
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
+ ubdevreg(addr
);
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
;
for (ap
= udp
->ud_addr
; addr
|| (addr
= *ap
++); addr
= 0) {
if (ualloc
[ubaoff(addr
)])
if (badaddr((caddr_t
)reg
, 2))
#if defined(VAX780) || defined(VAX8600)
if (haveubasr
&& vubp
->uba_sr
) {
vubp
->uba_sr
= vubp
->uba_sr
;
i
= (*udp
->ud_probe
)(reg
, ui
);
#if defined(VAX780) || defined(VAX8600)
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
);
ualloc
[ubaoff(addr
+i
)] = 1;
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
+ ubdevreg(addr
);
/* ui_type comes from driver */
udp
->ud_dinfo
[ui
->ui_unit
] = ui
;
printf("Unibus allocation map");
for (i
= 0; i
< 8*1024; ) {
for (n
= 0; n
< 128; n
++)
for (n
= m
= 0; n
< 16; n
++) {
wmemfree(ualloc
, 8*1024);
register struct scb
*scbp
= &scb
;
scbp
= (struct scb
*)((caddr_t
)scbp
+ nsbi
* IOAMAPSIZ
);
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.
nxaccess(physa
, pte
, size
)
register struct pte
*pte
;
register int i
= btop(size
);
register unsigned v
= btop(physa
);
*(int *)pte
++ = PG_V
|PG_KW
|v
++;
ubaaccess(pumem
, pte
, size
)
register struct pte
*pte
;
register int i
= btop(size
);
register unsigned v
= btop(pumem
);
*(int *)pte
++ = PG_V
|PG_KW
|v
++;
* Configure swap space and related parameters.
register struct swdevt
*swp
;
for (swp
= swdevt
; swp
->sw_dev
; swp
++) {
if (bdevsw
[major(swp
->sw_dev
)].d_psize
) {
(*bdevsw
[major(swp
->sw_dev
)].d_psize
)(swp
->sw_dev
);
if (swp
->sw_nblks
== 0 || swp
->sw_nblks
> nblks
)
if (!cold
) /* in case called for mba device */
if (dumplo
== 0 && bdevsw
[major(dumpdev
)].d_psize
)
dumplo
= (*bdevsw
[major(dumpdev
)].d_psize
)(dumpdev
) - physmem
;