* Copyright (c) 1982,1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)autoconf.c 6.21 (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.
#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 */
int cpuspeed
= 1; /* relative cpu speed */
* 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
) {
cpuspeed
= ocp
->pc_cpuspeed
;
* 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
);
* Probe the main IO bus(es).
* The percpu structure gives us a handle on the addresses and/or types.
register struct percpu
*pcpu
;
register struct iobus
*iob
;
for (iob
= pcpu
->pc_io
; ioanum
< pcpu
->pc_nioa
; ioanum
++, iob
++) {
#if VAX780 || VAX750 || VAX730
probenexi((struct nexusconnect
*)iob
->io_details
);
"IO adaptor %d, type %d, at address 0x%x is unsupported\n",
ioanum
, iob
->io_type
, iob
->io_addr
);
printf("IO adaptor %d, type %d, is unsupported\n",
register struct iobus
*iob
;
register struct ioa
*ioap
;
struct sbia_regs
*sbiaregs
;
nxaccess(iob
->io_addr
, Ioamap
[ioanum
], iob
->io_size
);
if (badaddr((caddr_t
)ioap
, 4))
ioacsr
.ioa_csr
= ioap
->ioacsr
.ioa_csr
;
type
= ioacsr
.ioa_type
& IOA_TYPMSK
;
printf("SBIA%d at IO adaptor %d address 0x%x\n",
nsbi
, ioanum
, iob
->io_addr
);
probenexi((struct nexusconnect
*)iob
->io_details
);
sbiaregs
= (struct sbia_regs
*)ioap
;
sbiaregs
->sbi_errsum
= -1;
sbiaregs
->sbi_error
= 0x1000;
sbiaregs
->sbi_fltsts
= 0xc0000;
printf("IOA%d at address 0x%x is unsupported (type = 0x%x)\n",
ioanum
, iob
->io_addr
, ioacsr
.ioa_type
);
* Probe nexus space, finding the interconnects
* and setting up and probing mba's and uba's for devices.
register struct nexusconnect
*pnc
;
register struct nexus
*nxv
;
struct nexus
*nxp
= pnc
->psb_nexbase
;
nexnum
= 0, nxv
= &nexus
[nsbi
* 16];
for (; nexnum
< pnc
->psb_nnexus
; nexnum
++, nxp
++, nxv
++) {
* the 16 below shouldn't be there, but the constant
* is used at other points (vax/locore.s)
nxaccess((caddr_t
)nxp
, Nexmap
[nsbi
* 16 + nexnum
],
if (badaddr((caddr_t
)nxv
, 4))
if (pnc
->psb_nextype
&& pnc
->psb_nextype
[nexnum
] != NEX_ANY
)
nexcsr
.nex_csr
= pnc
->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
], pnc
->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 an IO register area accessible at physical address physa
* 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
;
#define DOSWAP /* Change swdevt, argdev, and dumpdev too */
u_long bootdev
; /* should be dev_t, but not until 32 bits */
static char devname
[][2] = {
#define PARTITIONMASK 0x7
* Attempt to find the device from which we were booted.
* If we can do so, and not instructed not to do so,
* change rootdev to correspond to the load device.
int majdev
, mindev
, unit
, part
, adaptor
;
if (boothowto
& RB_DFLTROOT
|| (bootdev
& B_MAGICMASK
) != B_DEVMAGIC
)
majdev
= (bootdev
>> B_TYPESHIFT
) & B_TYPEMASK
;
if (majdev
> sizeof(devname
) / sizeof(devname
[0]))
adaptor
= (bootdev
>> B_ADAPTORSHIFT
) & B_ADAPTORMASK
;
part
= (bootdev
>> B_PARTITIONSHIFT
) & B_PARTITIONMASK
;
unit
= (bootdev
>> B_UNITSHIFT
) & B_UNITMASK
;
if (majdev
== 0) { /* MBA device */
register struct mba_device
*mbap
;
for (mbap
= mbdinit
; mbap
->mi_driver
; mbap
++)
if (mbap
->mi_alive
&& mbap
->mi_drive
== unit
&&
mbap
->mi_mbanum
== adaptor
&&
if (mbap
->mi_driver
== 0)
register struct uba_device
*ubap
;
for (ubap
= ubdinit
; ubap
->ui_driver
; ubap
++)
if (ubap
->ui_alive
&& ubap
->ui_slave
== unit
&&
ubap
->ui_ubanum
== adaptor
&&
ubap
->ui_driver
->ud_dname
[0] == devname
[majdev
][0] &&
ubap
->ui_driver
->ud_dname
[1] == devname
[majdev
][1])
if (ubap
->ui_driver
== 0)
mindev
= (mindev
<< PARTITIONSHIFT
) + part
;
rootdev
= makedev(majdev
, mindev
);
* If the original rootdev is the same as the one
* just calculated, don't need to adjust the swap configuration.
printf("Changing root device to %c%c%d%c\n",
devname
[majdev
][0], devname
[majdev
][1],
mindev
>> PARTITIONSHIFT
, part
+ 'a');
mindev
&= ~PARTITIONMASK
;
for (swp
= swdevt
; swp
->sw_dev
; swp
++) {
if (majdev
== major(swp
->sw_dev
) &&
mindev
== (minor(swp
->sw_dev
) & ~PARTITIONMASK
)) {
swdevt
[0].sw_dev
= swp
->sw_dev
;
* If argdev and dumpdev were the same as the old primary swap
* device, move them to the new primary swap device.
dumpdev
= swdevt
[0].sw_dev
;
argdev
= swdevt
[0].sw_dev
;