* Copyright (c) 1982, 1986 The Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)uba.c 7.7 (Berkeley) 2/15/89
#include "../vax/nexus.h"
char ubasr_bits
[] = UBASR_BITS
;
#define spluba spl7 /* IPL 17 */
* Do transfer on device argument. The controller
* and uba involved are implied by the device.
* We queue for resource wait in the uba code if necessary.
* We return 1 if the transfer was started, 0 if it was not.
* The onq argument must be zero iff the device is not on the
* queue for this UBA. If onq is set, the device must be at the
* head of the queue. In any case, if the transfer is started,
* the device will be off the queue, and if not, it will be on.
* Drivers that allocate one BDP and hold it for some time should
* set ud_keepbdp. In this case um_bdp tells which BDP is allocated
* to the controller, unless it is zero, indicating that the controller
* does not now have a BDP.
register struct uba_device
*ui
;
register struct uba_ctlr
*um
= ui
->ui_mi
;
register struct uba_hd
*uh
;
register struct uba_driver
*ud
;
uh
= &uba_hd
[um
->um_ubanum
];
* Honor exclusive BDP use requests.
if (ud
->ud_xclu
&& uh
->uh_users
> 0 || uh
->uh_xclu
)
* First get just a BDP (though in fact it comes with
um
->um_bdp
= uballoc(um
->um_ubanum
,
(caddr_t
)0, 0, UBA_NEEDBDP
|UBA_CANTWAIT
);
/* now share it with this transfer */
um
->um_ubinfo
= ubasetup(um
->um_ubanum
,
um
->um_tab
.b_actf
->b_actf
,
um
->um_bdp
|UBA_HAVEBDP
|UBA_CANTWAIT
);
um
->um_ubinfo
= ubasetup(um
->um_ubanum
,
um
->um_tab
.b_actf
->b_actf
, UBA_NEEDBDP
|UBA_CANTWAIT
);
dk_wds
[unit
] += um
->um_tab
.b_actf
->b_actf
->b_bcount
>>6;
uh
->uh_actf
= ui
->ui_forw
;
uh
->uh_actl
->ui_forw
= ui
;
register struct uba_ctlr
*um
;
register struct uba_hd
*uh
= &uba_hd
[um
->um_ubanum
];
if (um
->um_driver
->ud_xclu
)
if (um
->um_driver
->ud_keepbdp
)
um
->um_ubinfo
&= ~BDPMASK
; /* keep BDP for misers */
ubarelse(um
->um_ubanum
, &um
->um_ubinfo
);
* Allocate and setup UBA map registers, and bdp's
* Flags says whether bdp is needed, whether the caller can't
* wait (e.g. if the caller is at interrupt level).
* Return value encodes map register plus page offset,
* bdp number and number of map registers.
ubasetup(uban
, bp
, flags
)
register struct uba_hd
*uh
= &uba_hd
[uban
];
register struct pte
*pte
, *io
;
if (uh
->uh_type
== DW730
)
o
= (int)bp
->b_un
.b_addr
& PGOFSET
;
npf
= btoc(bp
->b_bcount
+ o
) + 1;
panic("uba xfer too big");
while ((reg
= rmalloc(uh
->uh_map
, (long)npf
)) == 0) {
if (flags
& UBA_CANTWAIT
) {
sleep((caddr_t
)&uh
->uh_mrwant
, PSWP
);
if ((flags
& UBA_NEED16
) && reg
+ npf
> 128) {
* Could hang around and try again (if we can ever succeed).
* Won't help any current device...
rmfree(uh
->uh_map
, (long)npf
, (long)reg
);
if (flags
& UBA_NEEDBDP
) {
while ((bdp
= ffs((long)uh
->uh_bdpfree
)) == 0) {
if (flags
& UBA_CANTWAIT
) {
rmfree(uh
->uh_map
, (long)npf
, (long)reg
);
sleep((caddr_t
)&uh
->uh_bdpwant
, PSWP
);
uh
->uh_bdpfree
&= ~(1 << (bdp
-1));
} else if (flags
& UBA_HAVEBDP
)
bdp
= (flags
>> 28) & 0xf;
ubinfo
= UBAI_INFO(o
, reg
, npf
, bdp
);
temp
= (bdp
<< 21) | UBAMR_MRV
;
if ((bp
->b_flags
& B_PHYS
) == 0)
pte
= kvtopte(bp
->b_un
.b_addr
);
else if (bp
->b_flags
& B_PAGET
)
pte
= &Usrptmap
[btokmx((struct pte
*)bp
->b_un
.b_addr
)];
rp
= bp
->b_flags
&B_DIRTY
? &proc
[2] : bp
->b_proc
;
v
= btop(bp
->b_un
.b_addr
);
if (bp
->b_flags
& B_UAREA
)
panic("uba zero uentry");
*(int *)io
++ = pfnum
| temp
;
* Non buffer setup interface... set up a buffer and call ubasetup.
uballoc(uban
, addr
, bcnt
, flags
)
ubabuf
.b_un
.b_addr
= addr
;
/* that's all the fields ubasetup() needs */
return (ubasetup(uban
, &ubabuf
, flags
));
* Release resources on uba uban, and then unblock resource waiters.
* The map register parameter is by value since we need to block
* against uba resets on 11/780's.
register struct uba_hd
*uh
= &uba_hd
[uban
];
register int bdp
, reg
, npf
, s
;
* Carefully see if we should release the space, since
* it may be released asynchronously at uba reset time.
* A ubareset() occurred before we got around
* to releasing the space... no need to bother.
BUA(uh
->uh_uba
)->bua_dpr
[bdp
] |= BUADPR_PURGE
;
uh
->uh_uba
->uba_dpr
[bdp
] |= UBADPR_BNE
;
uh
->uh_uba
->uba_dpr
[bdp
] |=
UBADPR_PURGE
|UBADPR_NXM
|UBADPR_UCE
;
uh
->uh_bdpfree
|= 1 << (bdp
-1); /* atomic */
wakeup((caddr_t
)&uh
->uh_bdpwant
);
* Put back the registers in the resource map.
* The map code must not be reentered,
* nor can the registers be freed twice.
* Unblock interrupts once this is done.
rmfree(uh
->uh_map
, (long)npf
, (long)reg
);
* Wakeup sleepers for map registers,
* and also, if there are processes blocked in dgo(),
* give them a chance at the UNIBUS.
wakeup((caddr_t
)&uh
->uh_mrwant
);
while (uh
->uh_actf
&& ubaqueue(uh
->uh_actf
, 1))
register struct uba_ctlr
*um
;
register struct uba_hd
*uh
= um
->um_hd
;
register int bdp
= UBAI_BDP(um
->um_ubinfo
);
BUA(uh
->uh_uba
)->bua_dpr
[bdp
] |= BUADPR_PURGE
;
uh
->uh_uba
->uba_dpr
[bdp
] |= UBADPR_BNE
;
uh
->uh_uba
->uba_dpr
[bdp
] |= UBADPR_PURGE
|UBADPR_NXM
|UBADPR_UCE
;
register struct uba_hd
*uhp
;
if (uhp
->uh_memsize
> UBA_MAXMR
)
uhp
->uh_memsize
= UBA_MAXMR
;
rminit(uhp
->uh_map
, (long)uhp
->uh_memsize
, (long)1, "uba", UAMSIZ
);
uhp
->uh_bdpfree
= (1<<NBDPBUA
) - 1;
uhp
->uh_bdpfree
= (1<<NBDP780
) - 1;
uhp
->uh_bdpfree
= (1<<NBDP750
) - 1;
* Generate a reset on uba number uban. Then
* call each device in the character device table,
* giving it a chance to clean up so as to be able to continue.
register struct cdevsw
*cdp
;
register struct uba_hd
*uh
= &uba_hd
[uban
];
uh
->uh_actf
= uh
->uh_actl
= 0;
wakeup((caddr_t
)&uh
->uh_bdpwant
);
wakeup((caddr_t
)&uh
->uh_mrwant
);
printf("uba%d: reset", uban
);
for (cdp
= cdevsw
; cdp
< cdevsw
+ nchrdev
; cdp
++)
* Init a uba. This is called with a pointer
* rather than a virtual address since it is called
* by code which runs with memory mapping disabled.
* In these cases we really don't need the interrupts
* enabled, but since we run with ipl high, we don't care
* if they are, they will never happen anyways.
* SHOULD GET POINTER TO UBA_HD INSTEAD OF UBA.
register struct uba_regs
*uba
;
register struct uba_hd
*uhp
;
for (uhp
= uba_hd
; uhp
< uba_hd
+ numuba
; uhp
++) {
if (uhp
->uh_physuba
== uba
) {
if (uhp
>= uba_hd
+ numuba
) {
printf("init unknown uba\n");
BUA(uba
)->bua_csr
|= BUACSR_UPI
;
/* give devices time to recover from power fail */
uba
->uba_cr
= UBACR_ADINIT
;
uba
->uba_cr
= UBACR_IFS
|UBACR_BRIE
|UBACR_USEFIE
|UBACR_SUEFIE
;
while ((uba
->uba_cnfgr
& UBACNFGR_UBIC
) == 0)
#if DW750 || DW730 || QBA
/* give devices time to recover from power fail */
/* THIS IS PROBABLY UNNECESSARY */
/* END PROBABLY UNNECESSARY */
* Re-enable local memory access
if (uhp
->uh_type
== QBA
) {
*((char *)QIOPAGE630
+ QIPCR
) = Q_LMEAE
;
*(uhp
->uh_iopage
+ QIPCR
) = Q_LMEAE
;
#endif DW750 || DW730 || QBA
* Determine the interrupt priority of a Q-bus
* peripheral. The device probe routine must spl6(),
* attempt to make the device request an interrupt,
* delaying as necessary, then call this routine
* before resetting the device.
for (pri
= 0x17; pri
> 0x14; ) {
if (cvec
&& cvec
!= 0x200) /* interrupted at pri */
int zvcnt_max
= 5000; /* in 8 sec */
* This routine is called by the locore code to process a UBA
* error on an 11/780 or 8600. The arguments are passed
* on the stack, and value-result (through some trickery).
* In particular, the uvec argument is used for further
* uba processing so the result aspect of it is very important.
* It must not be declared register.
ubaerror(uban
, uh
, ipl
, uvec
, uba
)
register struct uba_hd
*uh
;
register struct uba_regs
*uba
;
* Declare dt as unsigned so that negative values
* are handled as >8 below, in case time was set back.
u_long dt
= time
.tv_sec
- uh
->uh_zvtime
;
uh
->uh_zvtime
= time
.tv_sec
;
if (++uh
->uh_zvcnt
> zvcnt_max
) {
printf("uba%d: too many zero vectors (%d in <%d sec)\n",
uban
, uh
->uh_zvcnt
, dt
+ 1);
printf("\tIPL 0x%x\n\tcnfgr: %b Adapter Code: 0x%x\n",
ipl
, uba
->uba_cnfgr
&(~0xff), UBACNFGR_BITS
,
printf("\tsr: %b\n\tdcr: %x (MIC %sOK)\n",
uba
->uba_sr
, ubasr_bits
, uba
->uba_dcr
,
(uba
->uba_dcr
&0x8000000)?"":"NOT ");
if (uba
->uba_cnfgr
& NEX_CFGFLT
) {
printf("uba%d: sbi fault sr=%b cnfgr=%b\n",
uban
, uba
->uba_sr
, ubasr_bits
,
uba
->uba_cnfgr
, NEXFLT_BITS
);
printf("uba%d: uba error sr=%b fmer=%x fubar=%o\n",
uban
, uba
->uba_sr
, ubasr_bits
, uba
->uba_fmer
, 4*uba
->uba_fubar
);
if (++uh
->uh_errcnt
% ubawedgecnt
== 0) {
if (uh
->uh_errcnt
> ubacrazy
)
* Look for devices with unibus memory, allow them to configure, then disable
* map registers as necessary. Called during autoconfiguration and ubareset.
* The device ubamem routine returns 0 on success, 1 on success if it is fully
* configured (has no csr or interrupt, so doesn't need to be probed),
register struct uba_device
*ui
;
register struct uba_hd
*uh
= &uba_hd
[uban
];
caddr_t umembase
= umem
[uban
] + 0x3e000, addr
;
#define ubaoff(off) ((int)(off) & 0x1fff)
for (ui
= ubdinit
; ui
->ui_driver
; ui
++) {
if (ui
->ui_ubanum
!= uban
&& ui
->ui_ubanum
!= '?')
if (ui
->ui_driver
->ud_ubamem
) {
* During autoconfiguration, need to fudge ui_addr.
ui
->ui_addr
= umembase
+ ubaoff(addr
);
switch ((*ui
->ui_driver
->ud_ubamem
)(ui
, uban
)) {
* On a DW780, throw away any map registers disabled by rounding
* the map disable in the configuration register
* up to the next 8K boundary, or below the last unibus memory.
if (uh
->uh_type
== DW780
) {
i
= btop(((uh
->uh_lastmem
+ 8191) / 8192) * 8192);
(void) rmget(uh
->uh_map
, 1, i
--);
* Allocate UNIBUS memory. Allocates and initializes
* sufficient mapping registers for access. On a 780,
* the configuration register is setup to disable UBA
* response on DMA transfers to addresses controlled
* by the disabled mapping registers.
* On a DW780, should only be called from ubameminit, or in ascending order
* from 0 with 8K-sized and -aligned addresses; freeing memory that isn't
* the last unibus memory would free unusable map registers.
* Doalloc is 1 to allocate, 0 to deallocate.
ubamem(uban
, addr
, npg
, doalloc
)
int uban
, addr
, npg
, doalloc
;
register struct uba_hd
*uh
= &uba_hd
[uban
];
a
= rmget(uh
->uh_map
, npg
, a
);
rmfree(uh
->uh_map
, (long)npg
, (long)a
);
m
= (int *)&uh
->uh_mr
[a
- 1];
for (i
= 0; i
< npg
; i
++)
*m
++ = 0; /* All off, especially 'valid' */
if (doalloc
&& i
> uh
->uh_lastmem
)
else if (doalloc
== 0 && i
== uh
->uh_lastmem
)
* On a 780, set up the map register disable
* field in the configuration register. Beware
* of callers that request memory ``out of order''
* or in sections other than 8K multiples.
* Ubameminit handles such requests properly, however.
if (uh
->uh_type
== DW780
) {
i
= uh
->uh_uba
->uba_cr
&~ 0x7c000000;
i
|= ((uh
->uh_lastmem
+ 8191) / 8192) << 26;
* Map a virtual address into users address space. Actually all we
* do is turn on the user mode write protection bits for the particular
* page of memory involved.
kvtopte(vaddress
)->pg_prot
= (PG_UW
>> 27);
kvtopte(vaddress
)->pg_prot
= (PG_KW
>> 27);