Annotation of sys/arch/aviion/dev/nvram.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: nvram.c,v 1.4 2006/07/17 04:21:30 miod Exp $ */
2:
3: /*
4: * Copyright (c) 1995 Theo de Raadt
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: */
27:
28: #include <sys/param.h>
29: #include <sys/kernel.h>
30: #include <sys/device.h>
31: #include <sys/malloc.h>
32: #include <sys/systm.h>
33: #include <sys/proc.h>
34: #include <sys/ioctl.h>
35: #include <sys/uio.h>
36:
37: #include <machine/autoconf.h>
38: #include <machine/conf.h>
39: #include <machine/cpu.h>
40: #include <machine/mioctl.h>
41: #include <machine/psl.h>
42: #include <machine/vmparam.h>
43:
44: #include <uvm/uvm_param.h>
45:
46: #include <aviion/dev/nvramreg.h>
47:
48: struct nvramsoftc {
49: struct device sc_dev;
50: paddr_t sc_base;
51: bus_space_tag_t sc_iot;
52: bus_space_handle_t sc_ioh;
53: bus_addr_t sc_regs;
54: size_t sc_len;
55: u_int8_t *sc_nvram;
56: };
57:
58: void nvramattach(struct device *, struct device *, void *);
59: int nvrammatch(struct device *, void *, void *);
60:
61: struct cfattach nvram_ca = {
62: sizeof(struct nvramsoftc), nvrammatch, nvramattach
63: };
64:
65: struct cfdriver nvram_cd = {
66: NULL, "nvram", DV_DULL
67: };
68:
69: u_long chiptotime(int, int, int, int, int, int);
70: int nvramrw(caddr_t, int, struct uio *, int);
71:
72: int
73: nvrammatch(parent, vcf, args)
74: struct device *parent;
75: void *vcf, *args;
76: {
77: struct confargs *ca = args;
78: bus_space_handle_t ioh;
79: int rc;
80:
81: if (bus_space_map(ca->ca_iot, ca->ca_paddr, PAGE_SIZE, 0, &ioh) != 0)
82: return (0);
83: rc = badaddr((vaddr_t)bus_space_vaddr(ca->ca_iot, ioh), 1) == 0;
84: bus_space_unmap(ca->ca_iot, ioh, PAGE_SIZE);
85: return (rc);
86: }
87:
88: void
89: nvramattach(parent, self, args)
90: struct device *parent, *self;
91: void *args;
92: {
93: struct confargs *ca = args;
94: struct nvramsoftc *sc = (struct nvramsoftc *)self;
95: bus_space_handle_t ioh;
96: vsize_t maplen;
97:
98: sc->sc_len = MK48T02_SIZE;
99: sc->sc_regs = AV_NVRAM_TOD_OFF;
100:
101: sc->sc_iot = ca->ca_iot;
102: sc->sc_base = ca->ca_paddr;
103:
104: /*
105: * The NK48T02 is mapped as one byte per longword,
106: * thus spans four times as much address space.
107: */
108: maplen = sc->sc_len * 4;
109:
110: if (bus_space_map(sc->sc_iot, sc->sc_base, round_page(maplen),
111: BUS_SPACE_MAP_LINEAR, &ioh) != 0) {
112: printf(": can't map memory!\n");
113: return;
114: }
115:
116: sc->sc_ioh = ioh;
117:
118: printf(": MK48T0%d\n", sc->sc_len / 1024);
119: }
120:
121: /*
122: * Return the best possible estimate of the time in the timeval
123: * to which tvp points. We do this by returning the current time
124: * plus the amount of time since the last clock interrupt (clock.c:clkread).
125: *
126: * Check that this time is no less than any previously-reported time,
127: * which could happen around the time of a clock adjustment. Just for fun,
128: * we guarantee that the time will be greater than the value obtained by a
129: * previous call.
130: */
131: void
132: microtime(tvp)
133: struct timeval *tvp;
134: {
135: int s = splhigh();
136: static struct timeval lasttime;
137:
138: *tvp = time;
139: while (tvp->tv_usec >= 1000000) {
140: tvp->tv_sec++;
141: tvp->tv_usec -= 1000000;
142: }
143: if (tvp->tv_sec == lasttime.tv_sec &&
144: tvp->tv_usec <= lasttime.tv_usec &&
145: (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
146: tvp->tv_sec++;
147: tvp->tv_usec -= 1000000;
148: }
149: lasttime = *tvp;
150: splx(s);
151: }
152:
153: #define LEAPYEAR(y) (((y) & 3) == 0)
154:
155: /*
156: * This code is defunct after 2068.
157: * Will Unix still be here then??
158: */
159: const int dayyr[12] =
160: { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
161:
162: u_long
163: chiptotime(sec, min, hour, day, mon, year)
164: int sec, min, hour, day, mon, year;
165: {
166: int days, yr;
167:
168: sec = FROMBCD(sec);
169: min = FROMBCD(min);
170: hour = FROMBCD(hour);
171: day = FROMBCD(day);
172: mon = FROMBCD(mon);
173: year = FROMBCD(year) + YEAR0;
174:
175: /* simple sanity checks */
176: if (year>164 || mon<1 || mon>12 || day<1 || day>31)
177: return (0);
178: yr = 70;
179: days = 0;
180:
181: if (year < 70) { /* 2000 <= year */
182: for (; yr < 100; yr++) /* deal with first 30 years */
183: days += LEAPYEAR(yr) ? 366 : 365;
184: yr = 0;
185: }
186:
187: for (; yr < year; yr++) /* deal with years left */
188: days += LEAPYEAR(yr) ? 366 : 365;
189:
190: days += dayyr[mon - 1] + day - 1;
191:
192: if (LEAPYEAR(yr) && mon > 2)
193: days++;
194:
195: /* now have days since Jan 1, 1970; the rest is easy... */
196: return (days * SECDAY + hour * 3600 + min * 60 + sec);
197: }
198:
199: struct chiptime {
200: int sec;
201: int min;
202: int hour;
203: int wday;
204: int day;
205: int mon;
206: int year;
207: };
208:
209: void timetochip(struct chiptime *c);
210:
211: void
212: timetochip(c)
213: struct chiptime *c;
214: {
215: int t, t2, t3, now = time.tv_sec;
216:
217: /* January 1 1970 was a Thursday (4 in unix wdays) */
218: /* compute the days since the epoch */
219: t2 = now / SECDAY;
220:
221: t3 = (t2 + 4) % 7; /* day of week */
222: c->wday = TOBCD(t3 + 1);
223:
224: /* compute the year */
225: t = 69;
226: while (t2 >= 0) { /* whittle off years */
227: t3 = t2;
228: t++;
229: t2 -= LEAPYEAR(t) ? 366 : 365;
230: }
231: c->year = t;
232:
233: /* t3 = month + day; separate */
234: t = LEAPYEAR(t);
235: for (t2 = 1; t2 < 12; t2++)
236: if (t3 < (dayyr[t2] + ((t && (t2 > 1)) ? 1:0)))
237: break;
238:
239: /* t2 is month */
240: c->mon = t2;
241: c->day = t3 - dayyr[t2 - 1] + 1;
242: if (t && t2 > 2)
243: c->day--;
244:
245: /* the rest is easy */
246: t = now % SECDAY;
247: c->hour = t / 3600;
248: t %= 3600;
249: c->min = t / 60;
250: c->sec = t % 60;
251:
252: c->sec = TOBCD(c->sec);
253: c->min = TOBCD(c->min);
254: c->hour = TOBCD(c->hour);
255: c->day = TOBCD(c->day);
256: c->mon = TOBCD(c->mon);
257: c->year = TOBCD((c->year - YEAR0) % 100);
258: }
259:
260: /*
261: * Set up the system's time, given a `reasonable' time value.
262: */
263:
264: void
265: inittodr(base)
266: time_t base;
267: {
268: struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[0];
269: int sec, min, hour, day, mon, year;
270: int badbase = 0, waszero = base == 0;
271:
272: if (base < 36 * SECYR) { /* this code did not exist until 2006 */
273: /*
274: * If base is 0, assume filesystem time is just unknown
275: * in stead of preposterous. Don't bark.
276: */
277: if (base != 0)
278: printf("WARNING: preposterous time in file system\n");
279: /* not going to use it anyway, if the chip is readable */
280: base = 36 * SECYR + 109 * SECDAY + 22 * 3600;
281: badbase = 1;
282: }
283:
284: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
285: sc->sc_regs + (CLK_CSR << 2), CLK_READ |
286: bus_space_read_4(sc->sc_iot, sc->sc_ioh,
287: sc->sc_regs + (CLK_CSR << 2)));
288: sec = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
289: sc->sc_regs + (CLK_SEC << 2)) & 0xff;
290: min = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
291: sc->sc_regs + (CLK_MIN << 2)) & 0xff;
292: hour = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
293: sc->sc_regs + (CLK_HOUR << 2)) & 0xff;
294: day = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
295: sc->sc_regs + (CLK_DAY << 2)) & 0xff;
296: mon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
297: sc->sc_regs + (CLK_MONTH << 2)) & 0xff;
298: year = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
299: sc->sc_regs + (CLK_YEAR << 2)) & 0xff;
300: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
301: sc->sc_regs + (CLK_CSR << 2),
302: bus_space_read_4(sc->sc_iot, sc->sc_ioh,
303: sc->sc_regs + (CLK_CSR << 2)) & ~CLK_READ);
304:
305: if ((time.tv_sec = chiptotime(sec, min, hour, day, mon, year)) == 0) {
306: printf("WARNING: bad date in nvram");
307: #ifdef DEBUG
308: printf("\nday = %d, mon = %d, year = %d, hour = %d, min = %d, sec = %d",
309: FROMBCD(day), FROMBCD(mon), FROMBCD(year) + YEAR0,
310: FROMBCD(hour), FROMBCD(min), FROMBCD(sec));
311: #endif
312: /*
313: * Believe the time in the file system for lack of
314: * anything better, resetting the clock.
315: */
316: time.tv_sec = base;
317: if (!badbase)
318: resettodr();
319: } else {
320: int deltat = time.tv_sec - base;
321:
322: if (deltat < 0)
323: deltat = -deltat;
324: if (waszero || deltat < 2 * SECDAY)
325: return;
326: printf("WARNING: clock %s %d days",
327: time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
328: }
329: printf(" -- CHECK AND RESET THE DATE!\n");
330: }
331:
332: /*
333: * Reset the clock based on the current time.
334: * Used when the current clock is preposterous, when the time is changed,
335: * and when rebooting. Do nothing if the time is not yet known, e.g.,
336: * when crashing during autoconfig.
337: */
338: void
339: resettodr()
340: {
341: struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[0];
342: struct chiptime c;
343:
344: if (!time.tv_sec || sc == NULL)
345: return;
346: timetochip(&c);
347:
348: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
349: sc->sc_regs + (CLK_CSR << 2), CLK_WRITE |
350: bus_space_read_4(sc->sc_iot, sc->sc_ioh,
351: sc->sc_regs + (CLK_CSR << 2)));
352: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
353: sc->sc_regs + (CLK_SEC << 2), c.sec);
354: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
355: sc->sc_regs + (CLK_MIN << 2), c.min);
356: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
357: sc->sc_regs + (CLK_HOUR << 2), c.hour);
358: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
359: sc->sc_regs + (CLK_WDAY << 2), c.wday);
360: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
361: sc->sc_regs + (CLK_DAY << 2), c.day);
362: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
363: sc->sc_regs + (CLK_MONTH << 2), c.mon);
364: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
365: sc->sc_regs + (CLK_YEAR << 2), c.year);
366: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
367: sc->sc_regs + (CLK_CSR << 2),
368: bus_space_read_4(sc->sc_iot, sc->sc_ioh,
369: sc->sc_regs + (CLK_CSR << 2)) & ~CLK_WRITE);
370: }
371:
372: /*ARGSUSED*/
373: int
374: nvramopen(dev, flag, mode, p)
375: dev_t dev;
376: int flag, mode;
377: struct proc *p;
378: {
379: if (minor(dev) >= nvram_cd.cd_ndevs ||
380: nvram_cd.cd_devs[minor(dev)] == NULL)
381: return (ENODEV);
382:
383: return (0);
384: }
385:
386: /*ARGSUSED*/
387: int
388: nvramclose(dev, flag, mode, p)
389: dev_t dev;
390: int flag, mode;
391: struct proc *p;
392: {
393: /*
394: * It might be worth free()ing the NVRAM copy here.
395: */
396: return (0);
397: }
398:
399: /*ARGSUSED*/
400: int
401: nvramioctl(dev, cmd, data, flag, p)
402: dev_t dev;
403: u_long cmd;
404: caddr_t data;
405: int flag;
406: struct proc *p;
407: {
408: int unit = minor(dev);
409: struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[unit];
410: int error = 0;
411:
412: switch (cmd) {
413: case MIOCGSIZ:
414: *(int *)data = sc->sc_len;
415: break;
416: default:
417: error = ENOTTY;
418: break;
419: }
420: return (error);
421: }
422:
423: paddr_t
424: nvrammmap(dev, off, prot)
425: dev_t dev;
426: off_t off;
427: int prot;
428: {
429: #if 0
430: int unit = minor(dev);
431: struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[unit];
432:
433: if (minor(dev) != 0)
434: return (-1);
435:
436: /* allow access only in RAM */
437: if (off < 0 || off > sc->sc_len)
438: return (-1);
439: return (atop(sc->sc_base + off));
440: #else
441: /* disallow mmap due to non-linear layout */
442: return (-1);
443: #endif
444: }
445:
446: int read_nvram(struct nvramsoftc *);
447:
448: /*
449: * Build a local copy of the NVRAM contents.
450: */
451: int
452: read_nvram(struct nvramsoftc *sc)
453: {
454: u_int cnt;
455: u_int8_t *dest;
456: u_int32_t *src;
457:
458: if (sc->sc_nvram == NULL) {
459: sc->sc_nvram = (u_int8_t *)malloc(sc->sc_len, M_DEVBUF,
460: M_WAITOK | M_CANFAIL);
461: if (sc->sc_nvram == NULL)
462: return (EAGAIN);
463: }
464:
465: dest = sc->sc_nvram;
466: src = (u_int32_t *)bus_space_vaddr(sc->sc_iot, sc->sc_ioh);
467: cnt = sc->sc_len;
468: while (cnt-- != 0)
469: *dest++ = (u_int8_t)*src++;
470:
471: return (0);
472: }
473:
474: /*ARGSUSED*/
475: int
476: nvramrw(caddr_t base, int len, struct uio *uio, int flags)
477: {
478: vaddr_t v;
479: int c;
480: struct iovec *iov;
481: int error = 0;
482:
483: while (uio->uio_resid > 0 && error == 0) {
484: iov = uio->uio_iov;
485: if (iov->iov_len == 0) {
486: uio->uio_iov++;
487: uio->uio_iovcnt--;
488: #ifdef DIAGNOSTIC
489: if (uio->uio_iovcnt < 0)
490: panic("nvramrw");
491: #endif
492: continue;
493: }
494:
495: v = uio->uio_offset;
496: c = min(iov->iov_len, MAXPHYS);
497: if (v + c > len)
498: c = len - v; /* till end of dev */
499: if (c == 0)
500: return (0);
501: error = uiomove(base + v, c, uio);
502: }
503: return (error);
504: }
505:
506: int
507: nvramread(dev_t dev, struct uio *uio, int flags)
508: {
509: int unit = minor(dev);
510: struct nvramsoftc *sc = (struct nvramsoftc *)nvram_cd.cd_devs[unit];
511: int rc;
512:
513: /*
514: * Get a copy of the NVRAM contents.
515: */
516: rc = read_nvram(sc);
517: if (rc != 0)
518: return (rc);
519:
520: /*
521: * Move data from our NVRAM copy to the user.
522: */
523: return (nvramrw(sc->sc_nvram, sc->sc_len, uio, flags));
524: }
525:
526: int
527: nvramwrite(dev_t dev, struct uio *uio, int flags)
528: {
529: int unit = minor(dev);
530: struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[unit];
531: u_int cnt;
532: u_int8_t *src;
533: u_int32_t *dest;
534: int rc;
535:
536: /*
537: * Get a copy of the NVRAM contents.
538: */
539: rc = read_nvram(sc);
540: if (rc != 0)
541: return (rc);
542:
543: /*
544: * Move data from the user to our NVRAM copy.
545: */
546: rc = nvramrw(sc->sc_nvram, sc->sc_len, uio, flags);
547: if (rc != 0) {
548: /* reset NVRAM copy contents */
549: read_nvram(sc);
550: return (rc);
551: }
552:
553: /*
554: * Update the NVRAM. This could be optimized by only working on
555: * the areas which have been modified by the user.
556: */
557: src = sc->sc_nvram;
558: dest = (u_int32_t *)bus_space_vaddr(sc->sc_iot, sc->sc_ioh);
559: cnt = sc->sc_len;
560: while (cnt-- != 0) {
561: if ((*dest & 0xff) != *src) {
562: *dest = (u_int32_t)*src;
563: /*
564: * A jumper on the motherboard may write-protect
565: * the 0x80 bytes at offset 0x80 (i.e. addresses
566: * 0x200-0x3ff), so check our write had successed.
567: * If it failed, discard the remainder of the changes
568: * and return EROFS.
569: */
570: if ((*dest & 0xff) != *src)
571: rc = EROFS;
572: }
573: dest++;
574: src++;
575: }
576:
577: if (rc != 0) {
578: /* reset NVRAM copy contents */
579: read_nvram(sc);
580: }
581:
582: return (rc);
583: }
CVSweb