@@ 52,8 52,10 @@ enum
static struct
{
- Lock lock;
+ Lock;
+ int mode;
vlong when; /* next fastticks a clock interrupt should occur */
+ vlong cycwhen; /* next fastticks a cycintr happens; 0 == infinity */
long fastperiod; /* fastticks/hz */
long fast2freq; /* fastticks*FreqMul/Freq */
}i8253;
@@ 74,6 76,7 @@ i8253init(int aalcycles, int havecycleclock)
* set clock for 1/HZ seconds
*/
outb(Tmode, Load0|Square);
+ i8253.mode = Square;
outb(T0cntr, (Freq/HZ)); /* low byte */
outb(T0cntr, (Freq/HZ)>>8); /* high byte */
@@ 158,31 161,70 @@ i8253init(int aalcycles, int havecycleclock)
}
}
-#ifdef SETNEXT
-set up clock so it is reloaded every interrupt
- outb(Tmode, Load0|Trigger);
- outb(T0cntr, (Freq/HZ)); /* low byte */
- outb(T0cntr, (Freq/HZ)>>8); /* high byte */
-#endif
-
+/*
+ * schedule the next interrupt
+ * cycwhen is the next time for the cycle counter routines
+ */
static void
-clockintr0(Ureg* ureg, void *v)
+clockintrsched0(vlong next)
{
-#ifdef SETNEXT
vlong now;
long set;
+ i8253.cycwhen = next;
+ if(i8253.mode == Square && next == 0)
+ return;
+
now = fastticks(nil);
- while(i8253.when < now)
- i8253.when += i8253.fastperiod;
- set = (long)(i8253.when - now) * FreqMul / i8253.fast2freq;
- set -= 3; /* three cycles for the count to take effect: outb, outb, wait */
- outb(T0cntr, set); /* low byte */
- outb(T0cntr, set>>8); /* high byte */
-#endif
-
- checkcycintr(ureg, v);
- clockintr(ureg, v);
+ if(next || now < i8253.when - i8253.fastperiod || now > i8253.when - ((3*i8253.fastperiod)>>2)){
+ if(next > i8253.when)
+ next = i8253.when;
+ set = (long)(next - now) * FreqMul / i8253.fast2freq;
+ set -= 3; /* three cycles for the count to take effect: outb, outb, wait */
+ if(i8253.mode != Trigger){
+ outb(Tmode, Load0|Trigger);
+ i8253.mode = Trigger;
+ set--;
+ }
+ if(set < 3)
+ set = 5;
+ outb(T0cntr, set); /* low byte */
+ outb(T0cntr, set>>8); /* high byte */
+ }else if(i8253.mode != Square){
+ i8253.mode = Square;
+ outb(Tmode, Load0|Square);
+ outb(T0cntr, (Freq/HZ)); /* low byte */
+ outb(T0cntr, (Freq/HZ)>>8); /* high byte */
+ }
+}
+
+void
+clockintrsched(void)
+{
+ vlong next;
+
+ ilock(&i8253);
+ next = cycintrnext();
+ if(next != i8253.cycwhen)
+ clockintrsched0(next);
+ iunlock(&i8253);
+}
+
+static void
+clockintr0(Ureg* ureg, void *v)
+{
+ vlong now, when;
+
+ now = fastticks(nil);
+ when = i8253.when;
+ if(now >= i8253.when){
+ clockintr(ureg, v);
+ do
+ i8253.when += i8253.fastperiod;
+ while(i8253.when < now);
+ }
+ if(i8253.cycwhen || i8253.mode != Square)
+ clockintrsched0(checkcycintr(ureg, v));
}
void
@@ 315,6 315,10 @@ static unsigned char cf2[] = { 6, 2, 3, 4, 6, 8, 12, 16 };
typedef struct Controller {
Lock;
+ struct {
+ uchar scntl3;
+ uchar stest2;
+ } bios;
uchar synctab[NULTRA2SCF - 1][8];/* table of legal tpfs */
NegoState s[MAXTARGET];
uchar scntl3[MAXTARGET];
@@ 359,6 363,7 @@ enum { DataOut, DataIn, Cmd, Status, ReservedOut, ReservedIn, MessageOut, Messag
static void setmovedata(Movedata*, ulong, ulong);
static void advancedata(Movedata*, long);
+static int bios_set_differential(Controller *c);
static char *phase[] = {
"data out", "data in", "command", "status",
@@ 838,8 843,8 @@ softreset(Controller *c)
n->dmode |= (1 << 1); /* burst opcode fetch */
if (c->v->feature & Differential) {
/* chip capable */
- if ((c->feature & Differential) || (n->gpreg & 0x8) == 0) {
- /* user enabled, or bit 3 of GPREG clear (Symbios cards) */
+ if ((c->feature & Differential) || bios_set_differential(c)) {
+ /* user enabled, or some evidence bios set differential */
if (n->sstat2 & (1 << 2))
print("sd53c8xx: can't go differential; wrong cable\n");
else {
@@ 1797,6 1802,25 @@ docheck:
return r->status = status;
}
+static void
+cribbios(Controller *c)
+{
+ c->bios.scntl3 = c->n->scntl3;
+ c->bios.stest2 = c->n->stest2;
+ print("sd53c8xx: bios scntl3(%.2x) stest2(%.2x)\n", c->bios.scntl3, c->bios.stest2);
+}
+
+static int
+bios_set_differential(Controller *c)
+{
+ /* Concept lifted from FreeBSD - thanks Gerard */
+ /* basically, if clock conversion factors are set, then there is
+ * evidence the bios had a go at the chip, and if so, it would
+ * have set the differential enable bit in stest2
+ */
+ return (c->bios.scntl3 & 7) != 0 && (c->bios.stest2 & 0x20) != 0;
+}
+
#define NCR_VID 0x1000
#define NCR_810_DID 0x0001
#define NCR_820_DID 0x0002 /* don't know enough about this one to support it */
@@ 1808,6 1832,7 @@ docheck:
#define SYM_895_DID 0x000c
#define SYM_885_DID 0x000d /* ditto */
#define SYM_875_DID 0x000f /* ditto */
+#define SYM_1010_DID 0x0020
#define SYM_875J_DID 0x008f
static Variant variant[] = {
@@ 1826,6 1851,7 @@ static Variant variant[] = {
{ SYM_885_DID, 0xff, "SYM53C885", Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Wide|Ultra|ClockDouble },
{ SYM_895_DID, 0xff, "SYM53C895", Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Wide|Ultra|Ultra2 },
{ SYM_896_DID, 0xff, "SYM53C896", Burst128, 16, 64, Prefetch|LocalRAM|BigFifo|Wide|Ultra|Ultra2 },
+{ SYM_896_DID, 0xff, "SYM53C1010", Burst128, 16, 64, Prefetch|LocalRAM|BigFifo|Wide|Ultra|Ultra2 },
};
#define offsetof(s, t) ((ulong)&((s *)0)->t)
@@ 2046,6 2072,7 @@ symenable(SDev* sdev)
ilock(ctlr);
synctabinit(ctlr);
+ cribbios(ctlr);
reset(ctlr);
iunlock(ctlr);
@@ 2070,3 2097,4 @@ SDifc sd53c8xxifc = {
scsibio, /* bio */
};
+