Annotation of sys/arch/aviion/dev/nvram.c, Revision 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