The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bitsy/devflash.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "io.h"
    7 #include        "../port/error.h"
    8 
    9 /*
   10  *  on the bitsy, all 32 bit accesses to flash are mapped to two 16 bit
   11  *  accesses, one to the low half of the chip and the other to the high
   12  *  half.  Therefore for all command accesses, ushort indices in the
   13  *  manuals turn into ulong indices in our code.  Also, by copying all
   14  *  16 bit commands to both halves of a 32 bit command, we erase 2
   15  *  sectors for each request erase request.
   16  */
   17 
   18 #define mirror(x) (((x)<<16)|(x))
   19 
   20 /* this defines a contiguous set of erase blocks of one size */
   21 typedef struct FlashRegion FlashRegion;
   22 struct FlashRegion
   23 {
   24         ulong   addr;           /* start of region */
   25         ulong   end;            /* end of region + 1 */
   26         ulong   n;              /* number of blocks */
   27         ulong   size;           /* size of each block */
   28 };
   29 
   30 /* this defines a particular access algorithm */
   31 typedef struct FlashAlg FlashAlg;
   32 struct FlashAlg
   33 {
   34         int     id;
   35         char    *name;
   36         void    (*identify)(void);      /* identify device */
   37         void    (*erase)(ulong);        /* erase a region */
   38         void    (*write)(void*, long, ulong);   /* write a region */
   39 };
   40 
   41 static void     ise_id(void);
   42 static void     ise_erase(ulong);
   43 static void     ise_write(void*, long, ulong);
   44 
   45 static void     afs_id(void);
   46 static void     afs_erase(ulong);
   47 static void     afs_write(void*, long, ulong);
   48 
   49 static ulong    blockstart(ulong);
   50 static ulong    blockend(ulong);
   51 
   52 FlashAlg falg[] =
   53 {
   54         { 1,    "Intel/Sharp Extended", ise_id, ise_erase, ise_write    },
   55         { 2,    "AMD/Fujitsu Standard", afs_id, afs_erase, afs_write    },
   56 };
   57 
   58 struct
   59 {
   60         RWlock;
   61         ulong           *p;
   62         ushort          algid;          /* access algorithm */
   63         FlashAlg        *alg;
   64         ushort          manid;          /* manufacturer id */
   65         ushort          devid;          /* device id */
   66         ulong           size;           /* size in bytes */
   67         int             wbsize;         /* size of write buffer */ 
   68         ulong           nr;             /* number of regions */
   69         uchar           bootprotect;
   70         FlashRegion     r[32];
   71 } flash;
   72 
   73 enum
   74 {
   75         Maxwchunk=      1024,   /* maximum chunk written by one call to falg->write */
   76 };
   77 
   78 /*
   79  *  common flash interface
   80  */
   81 static uchar
   82 cfigetc(int off)
   83 {
   84         uchar rv;
   85 
   86         flash.p[0x55] = mirror(0x98);
   87         rv = flash.p[off];
   88         flash.p[0x55] = mirror(0xFF);
   89         return rv;
   90 }
   91 
   92 static ushort
   93 cfigets(int off)
   94 {
   95         return (cfigetc(off+1)<<8)|cfigetc(off);
   96 }
   97 
   98 static ulong
   99 cfigetl(int off)
  100 {
  101         return (cfigetc(off+3)<<24)|(cfigetc(off+2)<<16)|
  102                 (cfigetc(off+1)<<8)|cfigetc(off);
  103 }
  104 
  105 static void
  106 cfiquery(void)
  107 {
  108         uchar q, r, y;
  109         ulong x, addr;
  110 
  111         q = cfigetc(0x10);
  112         r = cfigetc(0x11);
  113         y = cfigetc(0x12);
  114         if(q != 'Q' || r != 'R' || y != 'Y'){
  115                 print("cfi query failed: %ux %ux %ux\n", q, r, y);
  116                 return;
  117         }
  118         flash.algid = cfigetc(0x13);
  119         flash.size = 1<<(cfigetc(0x27)+1);
  120         flash.wbsize = 1<<(cfigetc(0x2a)+1);
  121         flash.nr = cfigetc(0x2c);
  122         if(flash.nr > nelem(flash.r)){
  123                 print("cfi reports > %d regions\n", nelem(flash.r));
  124                 flash.nr = nelem(flash.r);
  125         }
  126         addr = 0;
  127         for(q = 0; q < flash.nr; q++){
  128                 x = cfigetl(q+0x2d);
  129                 flash.r[q].size = 2*256*(x>>16);
  130                 flash.r[q].n = (x&0xffff)+1;
  131                 flash.r[q].addr = addr;
  132                 addr += flash.r[q].size*flash.r[q].n;
  133                 flash.r[q].end = addr;
  134         }
  135 }
  136 
  137 /*
  138  *  flash device interface
  139  */
  140 
  141 enum
  142 {
  143         Qtopdir,
  144         Q2nddir,
  145         Qfctl,
  146         Qfdata,
  147 
  148         Maxpart= 8,
  149 };
  150 
  151 
  152 typedef struct FPart FPart;
  153 struct FPart
  154 {
  155         char    *name;
  156         char    *ctlname;
  157         ulong   start;
  158         ulong   end;
  159 };
  160 static FPart    part[Maxpart];
  161 
  162 #define FQID(p,q)       ((p)<<8|(q))
  163 #define FTYPE(q)        ((q) & 0xff)
  164 #define FPART(q)        (&part[(q) >>8])
  165 
  166 static int
  167 gen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
  168 {
  169         Qid q;
  170         FPart *fp;
  171 
  172         q.vers = 0;
  173 
  174         /* top level directory contains the name of the network */
  175         if(c->qid.path == Qtopdir){
  176                 switch(i){
  177                 case DEVDOTDOT:
  178                         q.path = Qtopdir;
  179                         q.type = QTDIR;
  180                         devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
  181                         break;
  182                 case 0:
  183                         q.path = Q2nddir;
  184                         q.type = QTDIR;
  185                         devdir(c, q, "flash", 0, eve, DMDIR|0555, dp);
  186                         break;
  187                 default:
  188                         return -1;
  189                 }
  190                 return 1;
  191         }
  192 
  193         /* second level contains all partitions and their control files */
  194         switch(i) {
  195         case DEVDOTDOT:
  196                 q.path = Qtopdir;
  197                 q.type = QTDIR;
  198                 devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
  199                 break;
  200         default:
  201                 if(i >= 2*Maxpart)
  202                         return -1;
  203                 fp = &part[i>>1];
  204                 if(fp->name == nil)
  205                         return 0;
  206                 if(i & 1){
  207                         q.path = FQID(i>>1, Qfdata);
  208                         q.type = QTFILE;
  209                         devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp);
  210                 } else {
  211                         q.path = FQID(i>>1, Qfctl);
  212                         q.type = QTFILE;
  213                         devdir(c, q, fp->ctlname, 0, eve, 0660, dp);
  214                 }
  215                 break;
  216         }
  217         return 1;
  218 }
  219 
  220 static FPart*
  221 findpart(char *name)
  222 {
  223         int i;
  224 
  225         for(i = 0; i < Maxpart; i++)
  226                 if(part[i].name != nil && strcmp(name, part[i].name) == 0)
  227                         break;
  228         if(i >= Maxpart)
  229                 return nil;
  230         return &part[i];
  231 }
  232 
  233 static void
  234 addpart(FPart *fp, char *name, ulong start, ulong end)
  235 {
  236         int i;
  237         char ctlname[64];
  238 
  239         if(fp == nil){
  240                 if(start >= flash.size || end > flash.size)
  241                         error(Ebadarg);
  242         } else {
  243                 start += fp->start;
  244                 end += fp->start;
  245                 if(start >= fp->end || end > fp->end)
  246                         error(Ebadarg);
  247         }
  248         if(blockstart(start) != start)
  249                 error("must start on erase boundary");
  250         if(blockstart(end) != end && end != flash.size)
  251                 error("must end on erase boundary");
  252 
  253         fp = findpart(name);
  254         if(fp != nil)
  255                 error(Eexist);
  256         for(i = 0; i < Maxpart; i++)
  257                 if(part[i].name == nil)
  258                         break;
  259         if(i == Maxpart)
  260                 error("no more partitions");
  261         fp = &part[i];
  262         kstrdup(&fp->name, name);
  263         snprint(ctlname, sizeof ctlname, "%sctl", name);
  264         kstrdup(&fp->ctlname, ctlname);
  265         fp->start = start;
  266         fp->end = end;
  267 }
  268 
  269 static void
  270 rempart(FPart *fp)
  271 {
  272         char *p, *cp;
  273 
  274         p = fp->name;
  275         fp->name = nil;
  276         cp = fp->ctlname;
  277         fp->ctlname = nil;
  278         free(p);
  279         free(cp);
  280 }
  281 
  282 void
  283 flashinit(void)
  284 {
  285         int i;
  286 
  287         flash.p = (ulong*)FLASHZERO;
  288         cfiquery();
  289         for(i = 0; i < nelem(falg); i++)
  290                 if(flash.algid == falg[i].id){
  291                         flash.alg = &falg[i];
  292                         (*flash.alg->identify)();
  293                         break;
  294                 }
  295         flash.bootprotect = 1;
  296 
  297         addpart(nil, "flash", 0, flash.size);
  298 }
  299 
  300 static Chan*
  301 flashattach(char* spec)
  302 {
  303         return devattach('F', spec);
  304 }
  305 
  306 static Walkqid*
  307 flashwalk(Chan *c, Chan *nc, char **name, int nname)
  308 {
  309         return devwalk(c, nc, name, nname, nil, 0, gen);
  310 }
  311 
  312 static int       
  313 flashstat(Chan *c, uchar *db, int n)
  314 {
  315         return devstat(c, db, n, nil, 0, gen);
  316 }
  317 
  318 static Chan*
  319 flashopen(Chan* c, int omode)
  320 {
  321         omode = openmode(omode);
  322         if(strcmp(up->user, eve)!=0)
  323                 error(Eperm);
  324         return devopen(c, omode, nil, 0, gen);
  325 }
  326 
  327 static void      
  328 flashclose(Chan*)
  329 {
  330 }
  331 
  332 static long
  333 flashctlread(FPart *fp, void* a, long n, vlong off)
  334 {
  335         char *buf, *p, *e;
  336         int i;
  337         ulong addr, end;
  338 
  339         buf = smalloc(1024);
  340         e = buf + 1024;
  341         p = seprint(buf, e, "0x%-9lux 0x%-9x 0x%-9ux 0x%-9ux\n", fp->end-fp->start,
  342                 flash.wbsize, flash.manid, flash.devid);
  343         addr = fp->start;
  344         for(i = 0; i < flash.nr && addr < fp->end; i++)
  345                 if(flash.r[i].addr <= addr && flash.r[i].end > addr){
  346                         if(fp->end <= flash.r[i].end)
  347                                 end = fp->end;
  348                         else
  349                                 end = flash.r[i].end;
  350                         p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", addr,
  351                                 (end-addr)/flash.r[i].size, flash.r[i].size);
  352                         addr = end;
  353                 }
  354         n = readstr(off, a, n, buf);
  355         free(buf);
  356         return n;
  357 }
  358 
  359 static long
  360 flashdataread(FPart *fp, void* a, long n, vlong off)
  361 {
  362         rlock(&flash);
  363         if(waserror()){
  364                 runlock(&flash);
  365                 nexterror();
  366         }
  367         if(fp->name == nil)
  368                 error("partition vanished");
  369         if(!iseve())
  370                 error(Eperm);
  371         off += fp->start;
  372         if(off >= fp->end)
  373                 n = 0;
  374         if(off+n >= fp->end)
  375                 n = fp->end - off;
  376         if(n > 0)
  377                 memmove(a, ((uchar*)FLASHZERO)+off, n);
  378         runlock(&flash);
  379         poperror();
  380 
  381         return n;
  382 }
  383 
  384 static long      
  385 flashread(Chan* c, void* a, long n, vlong off)
  386 {
  387         int t;
  388 
  389         if(c->qid.type == QTDIR)
  390                 return devdirread(c, a, n, nil, 0, gen);
  391         t = FTYPE(c->qid.path);
  392         switch(t){
  393         default:
  394                 error(Eperm);
  395         case Qfctl:
  396                 n = flashctlread(FPART(c->qid.path), a, n, off);
  397                 break;
  398         case Qfdata:
  399                 n = flashdataread(FPART(c->qid.path), a, n, off);
  400                 break;
  401         }
  402         return n;
  403 }
  404 
  405 static void
  406 bootprotect(ulong addr)
  407 {
  408         FlashRegion *r;
  409 
  410         if(flash.bootprotect == 0)
  411                 return;
  412         if(flash.nr == 0)
  413                 error("writing over boot loader disallowed");
  414         r = flash.r;
  415         if(addr >= r->addr && addr < r->addr + r->size)
  416                 error("writing over boot loader disallowed");
  417 }
  418 
  419 static ulong
  420 blockstart(ulong addr)
  421 {
  422         FlashRegion *r, *e;
  423         ulong x;
  424 
  425         r = flash.r;
  426         for(e = &flash.r[flash.nr]; r < e; r++)
  427                 if(addr >= r->addr && addr < r->end){
  428                         x = addr - r->addr;
  429                         x /= r->size;
  430                         return r->addr + x*r->size;
  431                 }
  432                         
  433         return (ulong)-1;
  434 }
  435 
  436 static ulong
  437 blockend(ulong addr)
  438 {
  439         FlashRegion *r, *e;
  440         ulong x;
  441 
  442         r = flash.r;
  443         for(e = &flash.r[flash.nr]; r < e; r++)
  444                 if(addr >= r->addr && addr < r->end){
  445                         x = addr - r->addr;
  446                         x /= r->size;
  447                         return r->addr + (x+1)*r->size;
  448                 }
  449                         
  450         return (ulong)-1;
  451 }
  452 
  453 static long
  454 flashctlwrite(FPart *fp, char *p, long n)
  455 {
  456         Cmdbuf *cmd;
  457         ulong off;
  458 
  459         if(fp == nil)
  460                 panic("flashctlwrite");
  461 
  462         cmd = parsecmd(p, n);
  463         wlock(&flash);
  464         if(waserror()){
  465                 wunlock(&flash);
  466                 nexterror();
  467         }
  468         if(strcmp(cmd->f[0], "erase") == 0){
  469                 switch(cmd->nf){
  470                 case 2:
  471                         /* erase a single block in the partition */
  472                         off = atoi(cmd->f[1]);
  473                         off += fp->start;
  474                         if(off >= fp->end)
  475                                 error("region not in partition");
  476                         if(off != blockstart(off))
  477                                 error("erase must be a block boundary");
  478                         bootprotect(off);
  479                         (*flash.alg->erase)(off);
  480                         break;
  481                 case 1:
  482                         /* erase the whole partition */
  483                         bootprotect(fp->start);
  484                         for(off = fp->start; off < fp->end; off = blockend(off))
  485                                 (*flash.alg->erase)(off);
  486                         break;
  487                 default:
  488                         error(Ebadarg);
  489                 }
  490         } else if(strcmp(cmd->f[0], "add") == 0){
  491                 if(cmd->nf != 4)
  492                         error(Ebadarg);
  493                 addpart(fp, cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0));
  494         } else if(strcmp(cmd->f[0], "remove") == 0){
  495                 rempart(fp);
  496         } else if(strcmp(cmd->f[0], "protectboot") == 0){
  497                 if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0)
  498                         flash.bootprotect = 1;
  499                 else
  500                         flash.bootprotect = 0;
  501         } else
  502                 error(Ebadarg);
  503         poperror();
  504         wunlock(&flash);
  505         free(cmd);
  506 
  507         return n;
  508 }
  509 
  510 static long
  511 flashdatawrite(FPart *fp, uchar *p, long n, long off)
  512 {
  513         uchar *end;
  514         int m;
  515         int on;
  516         long ooff;
  517         uchar *buf;
  518 
  519         if(fp == nil)
  520                 panic("flashctlwrite");
  521 
  522         buf = nil;
  523         wlock(&flash);
  524         if(waserror()){
  525                 wunlock(&flash);
  526                 if(buf != nil)
  527                         free(buf);
  528                 nexterror();
  529         }
  530 
  531         if(fp->name == nil)
  532                 error("partition vanished");
  533         if(!iseve())
  534                 error(Eperm);
  535 
  536         /* can't cross partition boundaries */
  537         off += fp->start;
  538         if(off >= fp->end || off+n > fp->end || n <= 0)
  539                 error(Ebadarg);
  540 
  541         /* make sure we're not writing the boot sector */
  542         bootprotect(off);
  543 
  544         on = n;
  545 
  546         /*
  547          *  get the data into kernel memory to avoid faults during writing.
  548          *  if write is not on a quad boundary or not a multiple of 4 bytes,
  549          *  extend with data already in flash.
  550          */
  551         buf = smalloc(n+8);
  552         m = off & 3;
  553         if(m){
  554                 *(ulong*)buf = flash.p[(off)>>2];
  555                 n += m;
  556                 off -= m;
  557         }
  558         if(n & 3){
  559                 n -= n & 3;
  560                 *(ulong*)(&buf[n]) = flash.p[(off+n)>>2];
  561                 n += 4;
  562         }
  563         memmove(&buf[m], p, on);
  564 
  565         /* (*flash.alg->write) can't cross blocks */
  566         ooff = off;
  567         p = buf;
  568         for(end = p + n; p < end; p += m){
  569                 m = blockend(off) - off;
  570                 if(m > end - p)
  571                         m = end - p;
  572                 if(m > Maxwchunk)
  573                         m = Maxwchunk;
  574                 (*flash.alg->write)(p, m, off);
  575                 off += m;
  576         }
  577 
  578         /* make sure write succeeded */
  579         if(memcmp(buf, &flash.p[ooff>>2], n) != 0)
  580                 error("written bytes don't match");
  581 
  582         wunlock(&flash);
  583         free(buf);
  584         poperror();
  585 
  586         return on;
  587 }
  588 
  589 static long      
  590 flashwrite(Chan* c, void* a, long n, vlong off)
  591 {
  592         int t;
  593 
  594         if(c->qid.type == QTDIR)
  595                 error(Eperm);
  596 
  597         if(!iseve())
  598                 error(Eperm);
  599 
  600         t = FTYPE(c->qid.path);
  601         switch(t){
  602         default:
  603                 panic("flashwrite");
  604         case Qfctl:
  605                 n = flashctlwrite(FPART(c->qid.path), a, n);
  606                 break;
  607         case Qfdata:
  608                 n = flashdatawrite(FPART(c->qid.path), a, n, off);
  609                 break;
  610         }
  611         return n;
  612 }
  613 
  614 Dev flashdevtab = {
  615         'F',
  616         "flash",
  617 
  618         devreset,
  619         flashinit,
  620         devshutdown,
  621         flashattach,
  622         flashwalk,
  623         flashstat,
  624         flashopen,
  625         devcreate,
  626         flashclose,
  627         flashread,
  628         devbread,
  629         flashwrite,
  630         devbwrite,
  631         devremove,
  632         devwstat,
  633 };
  634 
  635 enum
  636 {
  637         /* status register */
  638         ISEs_lockerr=           1<<1,
  639         ISEs_powererr=          1<<3,
  640         ISEs_progerr=           1<<4,
  641         ISEs_eraseerr=          1<<5,
  642         ISEs_ready=             1<<7,
  643         ISEs_err= (ISEs_lockerr|ISEs_powererr|ISEs_progerr|ISEs_eraseerr),
  644 
  645         /* extended status register */
  646         ISExs_bufavail=         1<<7,
  647 };
  648 
  649 
  650 
  651 /* intel/sharp extended command set */
  652 static void
  653 ise_reset(void)
  654 {
  655         flash.p[0x55] = mirror(0xff);   /* reset */
  656 }
  657 static void
  658 ise_id(void)
  659 {
  660         ise_reset();
  661         flash.p[0x555] = mirror(0x90);  /* uncover vendor info */
  662         flash.manid = flash.p[00];
  663         flash.devid = flash.p[01];
  664         ise_reset();
  665 }
  666 static void
  667 ise_clearerror(void)
  668 {
  669         flash.p[0x100] = mirror(0x50);
  670 
  671 }
  672 static void
  673 ise_error(int bank, ulong status)
  674 {
  675         char err[64];
  676 
  677         if(status & (ISEs_lockerr)){
  678                 sprint(err, "flash%d: block locked %lux", bank, status);
  679                 error(err);
  680         }
  681         if(status & (ISEs_powererr)){
  682                 sprint(err, "flash%d: low prog voltage %lux", bank, status);
  683                 error(err);
  684         }
  685         if(status & (ISEs_progerr|ISEs_eraseerr)){
  686                 sprint(err, "flash%d: i/o error %lux", bank, status);
  687                 error(err);
  688         }
  689 }
  690 static void
  691 ise_erase(ulong addr)
  692 {
  693         ulong start;
  694         ulong x;
  695 
  696         addr >>= 2;     /* convert to ulong offset */
  697 
  698         flashprogpower(1);
  699         flash.p[addr] = mirror(0x20);
  700         flash.p[addr] = mirror(0xd0);
  701         start = m->ticks;
  702         do {
  703                 x = flash.p[addr];
  704                 if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
  705                         break;
  706         } while(TK2MS(m->ticks-start) < 1500);
  707         flashprogpower(0);
  708 
  709         ise_clearerror();
  710         ise_error(0, x);
  711         ise_error(1, x>>16);
  712 
  713         ise_reset();
  714 }
  715 /*
  716  *  the flash spec claimes writing goes faster if we use
  717  *  the write buffer.  We fill the write buffer and then
  718  *  issue the write request.  After the write request,
  719  *  subsequent reads will yield the status register.
  720  *
  721  *  returns the status, even on timeouts.
  722  *
  723  *  NOTE: I tried starting back to back buffered writes
  724  *      without reading the status in between, as the
  725  *      flowchart in the intel data sheet suggests.
  726  *      However, it always responded with an illegal
  727  *      command sequence, so I must be missing something.
  728  *      If someone learns better, please email me, though
  729  *      I doubt it will be much faster. -  presotto@bell-labs.com
  730  */
  731 static int
  732 ise_wbwrite(ulong *p, int n, ulong off, ulong baddr, ulong *status)
  733 {
  734         ulong x, start;
  735         int i;
  736         int s;
  737 
  738         /* put flash into write buffer mode */
  739         start = m->ticks;
  740         for(;;) {
  741                 s = splhi();
  742                 /* request write buffer mode */
  743                 flash.p[baddr] = mirror(0xe8);
  744 
  745                 /* look at extended status reg for status */
  746                 if((flash.p[baddr] & mirror(1<<7)) == mirror(1<<7))
  747                         break;
  748                 splx(s);
  749 
  750                 /* didn't work, keep trying for 2 secs */
  751                 if(TK2MS(m->ticks-start) > 2000){
  752                         /* set up to read status */
  753                         flash.p[baddr] = mirror(0x70);
  754                         *status = flash.p[baddr];
  755                         pprint("write buffered cmd timed out\n");
  756                         return -1;
  757                 }
  758         }
  759 
  760         /* fill write buffer */
  761         flash.p[baddr] = mirror(n-1);
  762         for(i = 0; i < n; i++)
  763                 flash.p[off+i] = *p++;
  764 
  765         /* program from buffer */
  766         flash.p[baddr] = mirror(0xd0);
  767         splx(s);
  768 
  769         /* wait till the programming is done */
  770         start = m->ticks;
  771         for(;;) {
  772                 x = *status = flash.p[baddr];   /* read status register */
  773                 if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
  774                         break;
  775                 if(TK2MS(m->ticks-start) > 2000){
  776                         pprint("read status timed out\n");
  777                         return -1;
  778                 }
  779         }
  780         if(x & mirror(ISEs_err))
  781                 return -1;
  782 
  783         return n;
  784 }
  785 static void
  786 ise_write(void *a, long n, ulong off)
  787 {
  788         ulong *p, *end;
  789         int i, wbsize;
  790         ulong x, baddr;
  791 
  792         /* everything in terms of ulongs */
  793         wbsize = flash.wbsize>>2;
  794         baddr = blockstart(off);
  795         off >>= 2;
  796         n >>= 2;
  797         p = a;
  798         baddr >>= 2;
  799 
  800         /* first see if write will succeed */
  801         for(i = 0; i < n; i++)
  802                 if((p[i] & flash.p[off+i]) != p[i])
  803                         error("flash needs erase");
  804 
  805         if(waserror()){
  806                 ise_reset();
  807                 flashprogpower(0);
  808                 nexterror();
  809         }
  810         flashprogpower(1);
  811 
  812         /*
  813          *  use the first write to reach
  814          *  a write buffer boundary.  the intel maunal
  815          *  says writes startng at wb boundaries
  816          *  maximize speed.
  817          */
  818         i = wbsize - (off & (wbsize-1));
  819         for(end = p + n; p < end;){
  820                 if(i > end - p)
  821                         i = end - p;
  822 
  823                 if(ise_wbwrite(p, i, off, baddr, &x) < 0)
  824                         break;
  825 
  826                 off += i;
  827                 p += i;
  828                 i = wbsize;
  829         }
  830 
  831         ise_clearerror();
  832         ise_error(0, x);
  833         ise_error(1, x>>16);
  834 
  835         ise_reset();
  836         flashprogpower(0);
  837         poperror();
  838 }
  839 
  840 /* amd/fujitsu standard command set
  841  *      I don't have an amd chipset to work with
  842  *      so I'm loathe to write this yet.  If someone
  843  *      else does, please send it to me and I'll
  844  *      incorporate it -- presotto@bell-labs.com
  845  */
  846 static void
  847 afs_reset(void)
  848 {
  849         flash.p[0x55] = mirror(0xf0);   /* reset */
  850 }
  851 static void
  852 afs_id(void)
  853 {
  854         afs_reset();
  855         flash.p[0x55] = mirror(0xf0);   /* reset */
  856         flash.p[0x555] = mirror(0xaa);  /* query vendor block */
  857         flash.p[0x2aa] = mirror(0x55);
  858         flash.p[0x555] = mirror(0x90);
  859         flash.manid = flash.p[00];
  860         afs_reset();
  861         flash.p[0x555] = mirror(0xaa);  /* query vendor block */
  862         flash.p[0x2aa] = mirror(0x55);
  863         flash.p[0x555] = mirror(0x90);
  864         flash.devid = flash.p[01];
  865         afs_reset();
  866 }
  867 static void
  868 afs_erase(ulong)
  869 {
  870         error("amd/fujistsu erase not implemented");
  871 }
  872 static void
  873 afs_write(void*, long, ulong)
  874 {
  875         error("amd/fujistsu write not implemented");
  876 }

Cache object: 97872da95d1490a2eafeddde0fd7a118


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.