128ea44a89
a portable SG_NOEXEC segment attribute was added to allow non-executable (physical) segments. which will set the PTENOEXEC bits for putmmu(). in the future, this can be used to make non-executable stack / bss segments. the SG_DEVICE attribute was added to distinguish between mmio regions and uncached memory. only matterns on arm64. on arm, theres the issue that PTEUNCACHED would have no bits set when using the hardware bit definitions. this is the reason bcm, kw, teg2 and omap kernels use arteficial PTE constants. on zynq, the XN bit was used as a hack to give PTEUNCACHED a non-zero value and when the bit is clear then cache attributes where added to the pte. to fix this, PTECACHED constant was added. the portable mmu code in fault.c will now explicitely set PTECACHED bits for cached memory and PTEUNCACHED for uncached memory. that way the hardware bit definitions can be used everywhere.
662 lines
14 KiB
C
662 lines
14 KiB
C
/*
|
|
* 8260 specific stuff:
|
|
* Interrupt handling
|
|
*/
|
|
#include "u.h"
|
|
#include "../port/lib.h"
|
|
#include "mem.h"
|
|
#include "dat.h"
|
|
#include "io.h"
|
|
#include "fns.h"
|
|
#include "m8260.h"
|
|
|
|
enum {
|
|
Pin4 = BIT(4),
|
|
};
|
|
|
|
static union {
|
|
struct {
|
|
ulong hi;
|
|
ulong lo;
|
|
};
|
|
uvlong val;
|
|
} ticks;
|
|
|
|
struct {
|
|
ulong hi;
|
|
ulong lo;
|
|
} vec2mask[64] = {
|
|
[0] = {0, 0 }, /* Error, No interrupt */
|
|
[1] = {0, BIT(16) }, /* I2C */
|
|
[2] = {0, BIT(17) }, /* SPI */
|
|
[3] = {0, BIT(18) }, /* Risc Timers */
|
|
[4] = {0, BIT(19) }, /* SMC1 */
|
|
[5] = {0, BIT(20) }, /* SMC2 */
|
|
[6] = {0, BIT(21) }, /* IDMA1 */
|
|
[7] = {0, BIT(22) }, /* IDMA2 */
|
|
[8] = {0, BIT(23) }, /* IDMA3 */
|
|
[9] = {0, BIT(24) }, /* IDMA4 */
|
|
[10] = {0, BIT(25) }, /* SDMA */
|
|
[11] = {0, 0 }, /* Reserved */
|
|
[12] = {0, BIT(27) }, /* Timer1 */
|
|
[13] = {0, BIT(28) }, /* Timer2 */
|
|
[14] = {0, BIT(29) }, /* Timer3 */
|
|
[15] = {0, BIT(30) }, /* Timer4 */
|
|
|
|
[16] = {BIT(29), 0 }, /* TMCNT */
|
|
[17] = {BIT(30), 0 }, /* PIT */
|
|
[18] = {0, 0 }, /* Reserved */
|
|
[19] = {BIT(17), 0 }, /* IRQ1 */
|
|
[20] = {BIT(18), 0 }, /* IRQ2 */
|
|
[21] = {BIT(19), 0 }, /* IRQ3 */
|
|
[22] = {BIT(20), 0 }, /* IRQ4 */
|
|
[23] = {BIT(21), 0 }, /* IRQ5 */
|
|
[24] = {BIT(22), 0 }, /* IRQ6 */
|
|
[25] = {BIT(23), 0 }, /* IRQ7 */
|
|
[26] = {0, 0 }, /* Reserved */
|
|
[27] = {0, 0 }, /* Reserved */
|
|
[28] = {0, 0 }, /* Reserved */
|
|
[29] = {0, 0 }, /* Reserved */
|
|
[30] = {0, 0 }, /* Reserved */
|
|
[31] = {0, 0 }, /* Reserved */
|
|
|
|
[32] = {0, BIT(0) }, /* FCC1 */
|
|
[33] = {0, BIT(1) }, /* FCC2 */
|
|
[34] = {0, BIT(2) }, /* FCC3 */
|
|
[35] = {0, 0 }, /* Reserved */
|
|
[36] = {0, BIT(4) }, /* MCC1 */
|
|
[37] = {0, BIT(5) }, /* MCC2 */
|
|
[38] = {0, 0 }, /* Reserved */
|
|
[39] = {0, 0 }, /* Reserved */
|
|
[40] = {0, BIT(8) }, /* SCC1 */
|
|
[41] = {0, BIT(9) }, /* SCC2 */
|
|
[42] = {0, BIT(10) }, /* SCC3 */
|
|
[43] = {0, BIT(11) }, /* SCC4 */
|
|
[44] = {0, 0 }, /* Reserved */
|
|
[45] = {0, 0 }, /* Reserved */
|
|
[46] = {0, 0 }, /* Reserved */
|
|
[47] = {0, 0 }, /* Reserved */
|
|
|
|
[48] = {BIT(15), 0 }, /* PC15 */
|
|
[49] = {BIT(14), 0 }, /* PC14 */
|
|
[50] = {BIT(13), 0 }, /* PC13 */
|
|
[51] = {BIT(12), 0 }, /* PC12 */
|
|
[52] = {BIT(11), 0 }, /* PC11 */
|
|
[53] = {BIT(10), 0 }, /* PC10 */
|
|
[54] = {BIT(9), 0 }, /* PC9 */
|
|
[55] = {BIT(8), 0 }, /* PC8 */
|
|
[56] = {BIT(7), 0 }, /* PC7 */
|
|
[57] = {BIT(6), 0 }, /* PC6 */
|
|
[58] = {BIT(5), 0 }, /* PC5 */
|
|
[59] = {BIT(4), 0 }, /* PC4 */
|
|
[60] = {BIT(3), 0 }, /* PC3 */
|
|
[61] = {BIT(2), 0 }, /* PC2 */
|
|
[62] = {BIT(1), 0 }, /* PC1 */
|
|
[63] = {BIT(0), 0 }, /* PC0 */
|
|
};
|
|
|
|
/* Blast memory layout:
|
|
* CS0: FE000000 -> FFFFFFFF (Flash)
|
|
* CS1: FC000000 -> FCFFFFFF (DSP hpi)
|
|
* CS2: 00000000 -> 03FFFFFF (60x sdram)
|
|
* CS3: 04000000 -> 04FFFFFF (FPGA)
|
|
* CS4: 05000000 -> 06FFFFFF (local bus sdram)
|
|
* CS5: 07000000 -> 0700FFFF (eeprom - not populated)
|
|
* CS6: E0000000 -> E0FFFFFF (FPGA - 64bits)
|
|
*
|
|
* Main Board memory layout:
|
|
* CS0: FE000000 -> FEFFFFFF (16 M FLASH)
|
|
* CS1: FC000000 -> FCFFFFFF (16 M DSP1)
|
|
* CS2: 00000000 -> 03FFFFFF (64 M SDRAM)
|
|
* CS3: 04000000 -> 04FFFFFF (16M DSP2)
|
|
* CS4: 05000000 -> 06FFFFFF (32 M Local SDRAM)
|
|
* CS5: 07000000 -> 0700FFFF (eeprom - not populated)
|
|
* CS6: unused
|
|
* CS7: E0000000 -> E0FFFFFF (16 M FPGA)
|
|
*/
|
|
|
|
IMM* iomem = (IMM*)IOMEM;
|
|
|
|
static Lock cpmlock;
|
|
|
|
void
|
|
machinit(void)
|
|
{
|
|
ulong scmr;
|
|
int pllmf;
|
|
extern char* plan9inistr;
|
|
|
|
memset(m, 0, sizeof(*m));
|
|
m->cputype = getpvr()>>16; /* pvr = 0x00810101 for the 8260 */
|
|
m->imap = (Imap*)INTMEM;
|
|
|
|
m->loopconst = 1096;
|
|
|
|
/* Make sure Ethernet is disabled (boot code may have buffers allocated anywhere in memory) */
|
|
iomem->fcc[0].gfmr &= ~(BIT(27)|BIT(26));
|
|
iomem->fcc[1].gfmr &= ~(BIT(27)|BIT(26));
|
|
iomem->fcc[2].gfmr &= ~(BIT(27)|BIT(26));
|
|
|
|
/* Flashed CS configuration is wrong for DSP2. It's set to 64 bits, should be 16 */
|
|
iomem->bank[3].br = 0x04001001; /* Set 16-bit port */
|
|
|
|
/*
|
|
* FPGA is capable of doing 64-bit transfers. To use these, set br to 0xe0000001.
|
|
* Currently we use 32-bit transfers, because the 8260 does not easily do 64-bit operations.
|
|
*/
|
|
iomem->bank[6].br = 0xe0001801;
|
|
iomem->bank[6].or = 0xff000830; /* Was 0xff000816 */
|
|
|
|
/*
|
|
* All systems with rev. A.1 (0K26N) silicon had serious problems when doing
|
|
* DMA transfers with data cache enabled (usually this shows when using
|
|
* one of the FCC's with some traffic on the ethernet). Allocating FCC buffer
|
|
* descriptors in main memory instead of DP ram solves this problem.
|
|
*/
|
|
|
|
/* Guess at clocks based upon the PLL configuration from the
|
|
* power-on reset.
|
|
*/
|
|
scmr = iomem->scmr;
|
|
|
|
/* The EST8260 is typically run using either 33 or 66 MHz
|
|
* external clock. The configuration byte in the Flash will
|
|
* tell us which is configured. The blast appears to be slightly
|
|
* overclocked at 72 MHz (if set to 66 MHz, the uart runs too fast)
|
|
*/
|
|
|
|
m->clkin = CLKIN;
|
|
|
|
pllmf = scmr & 0xfff;
|
|
|
|
/* This is arithmetic from the 8260 manual, section 9.4.1. */
|
|
|
|
/* Collect the bits from the scmr.
|
|
*/
|
|
m->vco_out = m->clkin * (pllmf + 1);
|
|
if (scmr & BIT(19)) /* plldf (division factor is 1 or 2) */
|
|
m->vco_out >>= 1;
|
|
|
|
m->cpmhz = m->vco_out >> 1; /* cpm hz is half of vco_out */
|
|
m->brghz = m->vco_out >> (2 * ((iomem->sccr & 0x3) + 1));
|
|
m->bushz = m->vco_out / (((scmr & 0x00f00000) >> 20) + 1);
|
|
|
|
/* Serial init sets BRG clock....I don't know how to compute
|
|
* core clock from core configuration, but I think I know the
|
|
* mapping....
|
|
*/
|
|
switch(scmr >> (31-7)){
|
|
case 0x0a:
|
|
m->cpuhz = m->clkin * 2;
|
|
break;
|
|
case 0x0b:
|
|
m->cpuhz = (m->clkin >> 1) * 5;
|
|
break;
|
|
default:
|
|
case 0x0d:
|
|
m->cpuhz = m->clkin * 3;
|
|
break;
|
|
case 0x14:
|
|
m->cpuhz = (m->clkin >> 1) * 7;
|
|
break;
|
|
case 0x1c:
|
|
m->cpuhz = m->clkin * 4;
|
|
break;
|
|
}
|
|
|
|
m->cyclefreq = m->bushz / 4;
|
|
|
|
/* Expect:
|
|
intfreq 133 m->cpuhz
|
|
busfreq 33 m->bushz
|
|
cpmfreq 99 m->cpmhz
|
|
brgfreq 49.5 m->brghz
|
|
vco 198
|
|
*/
|
|
|
|
active.machs[0] = 1;
|
|
active.exiting = 0;
|
|
|
|
putmsr(getmsr() | MSR_ME);
|
|
|
|
/*
|
|
* turn on data cache before instruction cache;
|
|
* for some reason which I don't understand,
|
|
* you can't turn on both caches at once
|
|
*/
|
|
icacheenb();
|
|
dcacheenb();
|
|
|
|
kfpinit();
|
|
|
|
/* Plan9.ini location in flash is FLASHMEM+PLAN9INI
|
|
* if PLAN9INI == ~0, it's not stored in flash or there is no flash
|
|
* if *cp == 0xff, flash memory is not initialized
|
|
*/
|
|
if (PLAN9INI == ~0 || *(plan9inistr = (char*)(FLASHMEM+PLAN9INI)) == 0xff){
|
|
/* No plan9.ini in flash */
|
|
plan9inistr =
|
|
"console=0\n"
|
|
"ether0=type=fcc port=0 ea=00601d051dd8\n"
|
|
"flash0=mem=0xfe000000\n"
|
|
"fs=135.104.9.42\n"
|
|
"auth=135.104.9.7\n"
|
|
"authdom=cs.bell-labs.com\n"
|
|
"sys=blast\n"
|
|
"ntp=135.104.9.52\n";
|
|
}
|
|
}
|
|
|
|
void
|
|
fpgareset(void)
|
|
{
|
|
print("fpga reset\n");
|
|
|
|
ioplock();
|
|
|
|
iomem->port[1].pdat &= ~Pin4; /* force reset signal to 0 */
|
|
delay(100);
|
|
iomem->port[1].pdat |= Pin4; /* force reset signal back to one */
|
|
|
|
iopunlock();
|
|
}
|
|
|
|
void
|
|
hwintrinit(void)
|
|
{
|
|
iomem->sicr = 2 << 8;
|
|
/* Write ones into most bits of the interrupt pending registers to clear interrupts */
|
|
iomem->sipnr_h = ~7;
|
|
iomem->sipnr_h = ~1;
|
|
/* Clear the interrupt masks, thereby disabling all interrupts */
|
|
iomem->simr_h = 0;
|
|
iomem->simr_l = 0;
|
|
|
|
iomem->sypcr &= ~2; /* cause a machine check interrupt on memory timeout */
|
|
|
|
/* Initialize fpga reset pin */
|
|
iomem->port[1].pdir |= Pin4; /* 1 is an output */
|
|
iomem->port[1].ppar &= ~Pin4;
|
|
iomem->port[1].pdat |= Pin4; /* force reset signal back to one */
|
|
}
|
|
|
|
int
|
|
vectorenable(Vctl *v)
|
|
{
|
|
ulong hi, lo;
|
|
|
|
if (v->irq & ~0x3f){
|
|
print("m8260enable: interrupt vector %d out of range\n", v->irq);
|
|
return -1;
|
|
}
|
|
hi = vec2mask[v->irq].hi;
|
|
lo = vec2mask[v->irq].lo;
|
|
if (hi == 0 && lo == 0){
|
|
print("m8260enable: nonexistent vector %d\n", v->irq);
|
|
return -1;
|
|
}
|
|
ioplock();
|
|
/* Clear the interrupt before enabling */
|
|
iomem->sipnr_h |= hi;
|
|
iomem->sipnr_l |= lo;
|
|
/* Enable */
|
|
iomem->simr_h |= hi;
|
|
iomem->simr_l |= lo;
|
|
iopunlock();
|
|
return v->irq;
|
|
}
|
|
|
|
void
|
|
vectordisable(Vctl *v)
|
|
{
|
|
ulong hi, lo;
|
|
|
|
if (v->irq & ~0x3f){
|
|
print("m8260disable: interrupt vector %d out of range\n", v->irq);
|
|
return;
|
|
}
|
|
hi = vec2mask[v->irq].hi;
|
|
lo = vec2mask[v->irq].lo;
|
|
if (hi == 0 && lo == 0){
|
|
print("m8260disable: nonexistent vector %d\n", v->irq);
|
|
return;
|
|
}
|
|
ioplock();
|
|
iomem->simr_h &= ~hi;
|
|
iomem->simr_l &= ~lo;
|
|
iopunlock();
|
|
}
|
|
|
|
int
|
|
intvec(void)
|
|
{
|
|
return iomem->sivec >> 26;
|
|
}
|
|
|
|
void
|
|
intend(int vno)
|
|
{
|
|
/* Clear interrupt */
|
|
ioplock();
|
|
iomem->sipnr_h |= vec2mask[vno].hi;
|
|
iomem->sipnr_l |= vec2mask[vno].lo;
|
|
iopunlock();
|
|
}
|
|
|
|
int
|
|
m8260eoi(int)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
m8260isr(int)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
flashprogpower(int)
|
|
{
|
|
}
|
|
|
|
enum {
|
|
TgcrCas = 0x80,
|
|
TgcrGm = 0x08,
|
|
TgcrStp = 0x2, /* There are two of these, timer-2 bits are bits << 4 */
|
|
TgcrRst = 0x1,
|
|
|
|
TmrIclkCasc = 0x00<<1,
|
|
TmrIclkIntclock = 0x01<<1,
|
|
TmrIclkIntclock16 = 0x02<<1,
|
|
TmrIclkTin = 0x03<<1,
|
|
TmrCERising = 0x1 << 6,
|
|
TmrCEFalling = 0x2 << 6,
|
|
TmrCEAny = 0x3 << 6,
|
|
TmrFrr = SBIT(12),
|
|
TmrOri = SBIT(11),
|
|
|
|
TerRef = SBIT(14),
|
|
TerCap = SBIT(15),
|
|
};
|
|
|
|
uvlong
|
|
fastticks(uvlong *hz)
|
|
{
|
|
ulong count;
|
|
static Lock fasttickslock;
|
|
|
|
if (hz)
|
|
*hz = m->clkin>>1;
|
|
ilock(&fasttickslock);
|
|
count = iomem->tcnl1;
|
|
if (count < ticks.lo)
|
|
ticks.hi += 1;
|
|
ticks.lo = count;
|
|
iunlock(&fasttickslock);
|
|
return ticks.val;
|
|
}
|
|
|
|
void
|
|
timerset(uvlong next)
|
|
{
|
|
long offset;
|
|
uvlong now;
|
|
static int cnt;
|
|
|
|
now = fastticks(nil);
|
|
offset = next - now;
|
|
if (offset < 2500)
|
|
next = now + 2500; /* 10000 instructions */
|
|
else if (offset > m->clkin / HZ){
|
|
print("too far in the future: offset %llux, now %llux\n", next, now);
|
|
next = now + m->clkin / HZ;
|
|
}
|
|
iomem->trrl1 = next;
|
|
}
|
|
|
|
void
|
|
m8260timerintr(Ureg *u, void*)
|
|
{
|
|
iomem->ter2 |= TerRef | TerCap; /* Clear interrupt */
|
|
timerintr(u, 0);
|
|
}
|
|
|
|
void
|
|
timerinit(void)
|
|
{
|
|
|
|
iomem->tgcr1 = TgcrCas | TgcrGm; /* cascade timers 1 & 2, normal gate mode */
|
|
iomem->tcnl1 = 0;
|
|
iomem->trrl1 = m->clkin / HZ; /* first capture in 1/HZ seconds */
|
|
iomem->tmr1 = TmrIclkCasc;
|
|
iomem->tmr2 = TmrIclkIntclock | TmrOri;
|
|
intrenable(13, m8260timerintr, nil, "timer"); /* Timer 2 interrupt is on 13 */
|
|
iomem->tgcr1 |= TgcrRst << 4;
|
|
}
|
|
|
|
static void
|
|
addseg(char *name, ulong start, ulong length)
|
|
{
|
|
Physseg segbuf;
|
|
|
|
memset(&segbuf, 0, sizeof(segbuf));
|
|
segbuf.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
|
|
kstrdup(&segbuf.name, name);
|
|
segbuf.pa = start;
|
|
segbuf.size = length;
|
|
if (addphysseg(&segbuf) == nil) {
|
|
print("addphysseg: %s\n", name);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void
|
|
sharedseginit(void)
|
|
{
|
|
int i, j;
|
|
ulong base, size;
|
|
char name[16], *a, *b, *s;
|
|
static char *segnames[] = {
|
|
"fpga",
|
|
"dsp",
|
|
};
|
|
|
|
for (j = 0; j < nelem(segnames); j++){
|
|
for (i = 0; i < 8; i++){
|
|
snprint(name, sizeof name, "%s%d", segnames[j], i);
|
|
if ((a = getconf(name)) == nil)
|
|
continue;
|
|
if ((b = strstr(a, "mem=")) == nil){
|
|
print("blastseginit: %s: no base\n", name);
|
|
continue;
|
|
}
|
|
b += 4;
|
|
base = strtoul(b, nil, 0);
|
|
if (base == 0){
|
|
print("blastseginit: %s: bad base: %s\n", name, b);
|
|
continue;
|
|
}
|
|
if ((s = strstr(a, "size=")) == nil){
|
|
print("blastseginit: %s: no size\n", name);
|
|
continue;
|
|
}
|
|
s += 5;
|
|
size = strtoul(s, nil, 0);
|
|
if (size == 0){
|
|
print("blastseginit: %s: bad size: %s\n", name, s);
|
|
continue;
|
|
}
|
|
addseg(name, base, size);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
cpmop(int op, int dev, int mcn)
|
|
{
|
|
ioplock();
|
|
eieio();
|
|
while(iomem->cpcr & 0x10000)
|
|
eieio();
|
|
iomem->cpcr = dev<<(31-10) | mcn<<(31-25) | op | 0x10000;
|
|
eieio();
|
|
while(iomem->cpcr & 0x10000)
|
|
eieio();
|
|
iopunlock();
|
|
}
|
|
|
|
/*
|
|
* connect SCCx clocks in NSMI mode (x=1 for USB)
|
|
*/
|
|
void
|
|
sccnmsi(int x, int rcs, int tcs)
|
|
{
|
|
ulong v;
|
|
int sh;
|
|
|
|
sh = (x-1)*8; /* each SCCx field in sicr is 8 bits */
|
|
v = (((rcs&7)<<3) | (tcs&7)) << sh;
|
|
iomem->sicr = (iomem->sicr & ~(0xFF<<sh)) | v;
|
|
}
|
|
|
|
/*
|
|
* lock the shared IO memory and return a reference to it
|
|
*/
|
|
void
|
|
ioplock(void)
|
|
{
|
|
ilock(&cpmlock);
|
|
}
|
|
|
|
/*
|
|
* release the lock on the shared IO memory
|
|
*/
|
|
void
|
|
iopunlock(void)
|
|
{
|
|
eieio();
|
|
iunlock(&cpmlock);
|
|
}
|
|
|
|
BD*
|
|
bdalloc(int n)
|
|
{
|
|
static BD *palloc = ((Imap*)INTMEM)->bd;
|
|
BD *p;
|
|
|
|
p = palloc;
|
|
if (palloc > ((Imap*)INTMEM)->bd + nelem(((Imap*)INTMEM)->bd)){
|
|
print("bdalloc: out of BDs\n");
|
|
return nil;
|
|
}
|
|
palloc += n;
|
|
return p;
|
|
}
|
|
|
|
/*
|
|
* Initialise receive and transmit buffer rings. Only used for FCC
|
|
* Ethernet now.
|
|
*
|
|
* Ioringinit will allocate the buffer descriptors in normal memory
|
|
* and NOT in Dual-Ported Ram, as prescribed by the MPC8260
|
|
* PowerQUICC II manual (Section 28.6). When they are allocated
|
|
* in DPram and the Dcache is enabled, the processor will hang.
|
|
* This has been observed for the FCCs, it may or may not be true
|
|
* for SCCs or DMA.
|
|
* The SMC Uart buffer descriptors are not allocated here; (1) they
|
|
* can ONLY be in DPram and (2) they are not configured as a ring.
|
|
*/
|
|
int
|
|
ioringinit(Ring* r, int nrdre, int ntdre, int bufsize)
|
|
{
|
|
int i, x;
|
|
static uchar *dpmallocaddr;
|
|
static uchar *dpmallocend;
|
|
|
|
if (dpmallocaddr == nil){
|
|
dpmallocaddr = m->imap->dpram1;
|
|
dpmallocend = dpmallocaddr + sizeof(m->imap->dpram1);
|
|
}
|
|
/* the ring entries must be aligned on sizeof(BD) boundaries */
|
|
r->nrdre = nrdre;
|
|
if(r->rdr == nil)
|
|
r->rdr = xspanalloc(nrdre*sizeof(BD), 0, 8);
|
|
if(r->rdr == nil)
|
|
return -1;
|
|
if(r->rrb == nil && bufsize){
|
|
r->rrb = xspanalloc(nrdre*bufsize, 0, CACHELINESZ);
|
|
if(r->rrb == nil)
|
|
return -1;
|
|
}
|
|
x = bufsize ? PADDR(r->rrb) : 0;
|
|
for(i = 0; i < nrdre; i++){
|
|
r->rdr[i].length = 0;
|
|
r->rdr[i].addr = x;
|
|
r->rdr[i].status = BDEmpty|BDInt;
|
|
x += bufsize;
|
|
}
|
|
r->rdr[i-1].status |= BDWrap;
|
|
r->rdrx = 0;
|
|
|
|
r->ntdre = ntdre;
|
|
if(r->tdr == nil)
|
|
r->tdr = xspanalloc(ntdre*sizeof(BD), 0, 8);
|
|
if(r->txb == nil)
|
|
r->txb = xspanalloc(ntdre*sizeof(Block*), 0, CACHELINESZ);
|
|
if(r->tdr == nil || r->txb == nil)
|
|
return -1;
|
|
for(i = 0; i < ntdre; i++){
|
|
r->txb[i] = nil;
|
|
r->tdr[i].addr = 0;
|
|
r->tdr[i].length = 0;
|
|
r->tdr[i].status = 0;
|
|
}
|
|
r->tdr[i-1].status |= BDWrap;
|
|
r->tdrh = 0;
|
|
r->tdri = 0;
|
|
r->ntq = 0;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
trapinit(void)
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
* set all exceptions to trap
|
|
*/
|
|
for(i = 0x0; i < 0x2000; i += 0x100)
|
|
sethvec(i, trapvec);
|
|
|
|
setmvec(0x1000, imiss, tlbvec);
|
|
setmvec(0x1100, dmiss, tlbvec);
|
|
setmvec(0x1200, dmiss, tlbvec);
|
|
|
|
/* Useful for avoiding assembler miss handling:
|
|
sethvec(0x1000, tlbvec);
|
|
sethvec(0x1100, tlbvec);
|
|
sethvec(0x1200, tlbvec);
|
|
/* */
|
|
dcflush(KADDR(0), 0x2000);
|
|
icflush(KADDR(0), 0x2000);
|
|
|
|
putmsr(getmsr() & ~MSR_IP);
|
|
}
|
|
|
|
void
|
|
reboot(void*, void*, ulong)
|
|
{
|
|
ulong *p;
|
|
int x;
|
|
|
|
p = (ulong*)0x90000000;
|
|
x = splhi();
|
|
iomem->sypcr |= 0xc0;
|
|
print("iomem->sypcr = 0x%lux\n", iomem->sypcr);
|
|
*p = 0;
|
|
print("still alive\n");
|
|
splx(x);
|
|
}
|