123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- MODULE SdControllers;
- (**
- AUTHOR Timothée Martiel, 12/2015
- PURPOSE SD Host Controller Initialization for Zynq SoC.
- *)
- IMPORT
- Platform, Modules, Objects, Commands,
- Sd, SdDisks, SdEnvironment, Log := SdEnvironment;
- CONST
- Ready = 0;
- Running = 1;
- Stopped = 2;
- Error = 3;
- TYPE
- HostController * = OBJECT
- VAR
- hc: Sd.HostController;
- handler: InterruptHandler;
- state, event: LONGINT;
- card: Sd.Card;
- halted: BOOLEAN;
- PROCEDURE & Init (base: ADDRESS; int: LONGINT; clock: HUGEINT);
- VAR
- result: LONGINT;
- BEGIN
- NEW(hc);
- Sd.InitHostController(hc, base);
- IF ~Sd.SetExternalClock(hc, clock, clock, result) THEN
- Log.String("[SD] Failed to initialize host controller: error code ");
- Log.Int(result, 0);
- Log.Ln;
- state := Error;
- RETURN
- END;
- state := Ready; (* Do not put this later, as events might be triggered in the constructor *)
- NEW(handler, SELF);
- SdEnvironment.InstallHandler(handler.Handle, int);
- END Init;
- PROCEDURE HandleEvent (card: Sd.Card; event: LONGINT; param: ANY);
- BEGIN {EXCLUSIVE}
- AWAIT(state # Running);
- SELF.event := event;
- SELF.card := card;
- IF state = Ready THEN state := Running END
- END HandleEvent;
- PROCEDURE Stop;
- BEGIN {EXCLUSIVE}
- IF state < Stopped THEN state := Stopped END;
- AWAIT(halted)
- END Stop;
- PROCEDURE WaitForEventCompletion;
- BEGIN {EXCLUSIVE}
- AWAIT(state # Running)
- END WaitForEventCompletion;
- BEGIN {ACTIVE}
- LOOP
- BEGIN {EXCLUSIVE}
- AWAIT(state # Ready);
- IF state >= Stopped THEN EXIT END;
- END;
- SdDisks.HandleSdEvent(card, event);
- BEGIN {EXCLUSIVE}
- state := Ready
- END
- END
- FINALLY
- BEGIN {EXCLUSIVE} halted := TRUE END
- END HostController;
- InterruptHandler * = OBJECT
- VAR
- hc: Sd.HostController;
- timer: Objects.Timer;
- mask: SET;
- blocked: BOOLEAN;
- PROCEDURE & Init (hc: HostController);
- BEGIN
- SELF.hc := hc.hc;
- NEW(timer);
- blocked := FALSE
- END Init;
- PROCEDURE Block (hc: Sd.HostController; mask: SET; timeout: LONGINT): BOOLEAN;
- VAR
- irqs: SET;
- BEGIN {EXCLUSIVE}
- ASSERT(hc = SELF.hc);
- blocked := TRUE;
- irqs := hc.regs.InterruptSignalEnable;
- hc.regs.InterruptSignalEnable := irqs + mask;
- SELF.mask := mask;
- Objects.SetTimeout(timer, Unblock, timeout);
- AWAIT(~blocked);
- hc.regs.InterruptSignalEnable := irqs;
- RETURN mask * hc.regs.InterruptStatus # {}
- END Block;
- PROCEDURE Unblock;
- BEGIN {EXCLUSIVE}
- blocked := FALSE
- END Unblock;
- PROCEDURE Handle;
- BEGIN
- IF hc.regs.InterruptStatus * mask # {} THEN
- Unblock;
- Objects.CancelTimeout(timer);
- END;
- Sd.HandleInterrupt(hc);
- END Handle;
- END InterruptHandler;
- VAR
- hc: ARRAY 2 OF HostController;
- PROCEDURE Init;
- VAR
- i: LONGINT;
- BEGIN
- Modules.InstallTermHandler(Cleanup);
- FOR i := 0 TO Platform.SdNb - 1 DO
- IF SdEnvironment.Enable(i) THEN
- IF Sd.EnableTrace THEN
- Log.String("[SD] Enabling controller "); Log.Int(i, 0); Log.Ln;
- Log.String("[SD] register base = "); Log.Address(Platform.SdBase[i]); Log.Ln;
- Log.String("[SD] base clock = "); Log.Int(SdEnvironment.HcClock(i), 0); Log.String(" Hz"); Log.Ln;
- Log.String("[SD] irq = "); Log.Int(Platform.SdIrq[i], 0); Log.Ln;
- END;
- NEW(hc[i], Platform.SdBase[i], Platform.SdIrq[i], SdEnvironment.HcClock(i));
- Sd.SetEventHandler(hc[i].hc, hc[i].HandleEvent, NIL);
- hc[i].WaitForEventCompletion;
- (* Sd.SetBlocker(hc[i].hc, hc[i].handler.Block)*)
- ELSE
- IF Sd.EnableTrace THEN
- Log.String("[SD] Not Enabling controller "); Log.Int(i, 0); Log.Ln
- END;
- END
- END
- END Init;
- PROCEDURE Cleanup;
- VAR
- i: LONGINT;
- BEGIN
- FOR i := 0 TO LEN(hc) - 1 DO
- IF hc[i] # NIL THEN hc[i].Stop END
- END
- END Cleanup;
- PROCEDURE Statistics * (c: Commands.Context);
- VAR
- accesses: LONGINT;
- byteRead, byteWritten, read, write: HUGEINT;
- tread, twrite: HUGEINT;
- speedR, speedW: LONGREAL;
- BEGIN
- byteRead := Sd.NbyteRead;
- byteWritten := Sd.NbyteWritten;
- read := Sd.Nread;
- write := Sd.Nwrite;
- tread := SdEnvironment.ToMicro(Sd.Tread);
- twrite := SdEnvironment.ToMicro(Sd.Twrite);
- IF read > 0 THEN
- speedR := LONGREAL(byteRead) / LONGREAL(tread);
- c.out.String("SD Statistics:"); c.out.Ln;
- c.out.String(" Bytes read: "); c.out.Int(byteRead, 0); c.out.Ln;
- c.out.String(" Number of reads: "); c.out.Int(read, 0); c.out.Ln;
- c.out.String(" Read time: "); c.out.Int(tread, 0); c.out.String(" us"); c.out.Ln;
- c.out.String(" Average read size: "); c.out.Int(byteRead DIV read, 0); c.out.String(" bytes"); c.out.Ln;
- c.out.String(" Read speed: "); c.out.FloatFix(speedR, 0, 3, 0); c.out.String(" Mb/s"); c.out.Ln;
- c.out.String(" Average read time: "); c.out.FloatFix(LONGREAL(tread) / LONGREAL(read), 0, 3, 0); c.out.String(" us"); c.out.Ln;
- ELSE
- c.out.String("No read statistics");
- c.out.Ln
- END;
- IF write > 0 THEN
- speedW := LONGREAL(byteWritten) / LONGREAL(twrite);
- c.out.String(" Bytes written: "); c.out.Int(byteWritten, 0); c.out.Ln;
- c.out.String(" Number of writes: "); c.out.Int(write, 0); c.out.Ln;
- c.out.String(" Write time: "); c.out.Int(twrite, 0); c.out.String(" us"); c.out.Ln;
- c.out.String(" Average write size: "); c.out.Int(byteWritten DIV write, 0); c.out.String(" bytes"); c.out.Ln;
- c.out.String(" Write speed: "); c.out.FloatFix(speedW, 0, 3, 0); c.out.String(" Mb/s"); c.out.Ln;
- c.out.String(" Average write time: "); c.out.FloatFix(LONGREAL(twrite) / LONGREAL(write), 0, 3, 0); c.out.String(" us"); c.out.Ln;
- ELSE
- c.out.String("No write statistics");
- c.out.Ln
- END;
- accesses := SdDisks.NcacheHits + SdDisks.NcacheMiss;
- c.out.String("SD Disks Cache Statistics"); c.out.Ln;
- c.out.String(" Number of accesses: "); c.out.Int(accesses, 0); c.out.Ln;
- c.out.String(" Number of hits: "); c.out.Int(SdDisks.NcacheHits, 0); c.out.String(" ("); c.out.FloatFix(SdDisks.NcacheHits / accesses * 100.0, 0, 2, 0); c.out.String(" %)"); c.out.Ln;
- c.out.String(" Number of misses: "); c.out.Int(SdDisks.NcacheMiss, 0); c.out.String(" ("); c.out.FloatFix(SdDisks.NcacheMiss / accesses * 100.0, 0, 2, 0); c.out.String(" %)"); c.out.Ln;
- c.out.String(" Number of evictions: "); c.out.Int(SdDisks.NcacheEvict, 0); c.out.String(" ("); c.out.FloatFix(SdDisks.NcacheEvict / SdDisks.NcacheMiss * 100.0, 0, 2, 0); c.out.String(" %)"); c.out.Ln;
- c.out.String("SD Disks Write Buffer Statistics"); c.out.Ln;
- c.out.String(" Average write size: "); c.out.FloatFix(SdDisks.NbufferSize / SdDisks.NbufferWrites, 0, 2, 0); c.out.String(" bytes"); c.out.Ln;
- c.out.String(" Average queue length: "); c.out.FloatFix(SdDisks.NbufferQueueSize / SdDisks.NbufferQueueSamples, 0, 2, 0); c.out.Ln;
- c.out.Update;
- END Statistics;
- BEGIN
- Init
- END SdControllers.
|