Date: Sun, 25 Oct 2009 19:13:39 +0000 (UTC) From: Andrew Thompson <thompsa@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r198474 - projects/mips/sys/geom Message-ID: <200910251913.n9PJDdAO066690@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: thompsa Date: Sun Oct 25 19:13:39 2009 New Revision: 198474 URL: http://svn.freebsd.org/changeset/base/198474 Log: If the FIS entry is smaller than the sector size then set it as hot so g_slice calls us to fix it, we then issue a read for a full sector and then copy in/out the payload. This will happen if Redboot is compiled with CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG. Modified: projects/mips/sys/geom/geom_redboot.c Modified: projects/mips/sys/geom/geom_redboot.c ============================================================================== --- projects/mips/sys/geom/geom_redboot.c Sun Oct 25 17:47:52 2009 (r198473) +++ projects/mips/sys/geom/geom_redboot.c Sun Oct 25 19:13:39 2009 (r198474) @@ -71,6 +71,7 @@ struct fis_image_desc { struct g_redboot_softc { uint32_t entry[REDBOOT_MAXSLICE]; uint32_t dsize[REDBOOT_MAXSLICE]; + uint32_t sectoff[REDBOOT_MAXSLICE]; uint8_t readonly[REDBOOT_MAXSLICE]; g_access_t *parent_access; }; @@ -104,29 +105,125 @@ g_redboot_access(struct g_provider *pp, return (sc->parent_access(pp, dread, dwrite, dexcl)); } +static void +g_redboot_done(struct bio *bp) +{ + struct bio *bp2; + struct g_provider *pp; + struct g_consumer *cp; + struct g_geom *gp; + struct g_redboot_softc *sc; + struct g_slicer *gsp; + int idx; + + bp2 = bp->bio_parent; + pp = bp2->bio_to; + idx = pp->index; + gp = pp->geom; + gsp = gp->softc; + sc = gsp->softc; + + bp2->bio_error = bp->bio_error; + if (bp2->bio_error != 0) + goto done; + + KASSERT(sc->sectoff[idx] + bp2->bio_length <= bp->bio_length, + ("overflowed bio data")); + if (bp2->bio_cmd == BIO_READ) { + /* Copy out read data */ + memcpy(bp2->bio_data, bp->bio_data + sc->sectoff[idx], + bp2->bio_length); + bp2->bio_completed = bp2->bio_length; + } else { + if (bp->bio_cmd == BIO_READ) { + /* Copy in and reissue as write */ + cp = LIST_FIRST(&gp->consumer); + memcpy(bp->bio_data + sc->sectoff[idx], bp2->bio_data, + bp2->bio_length); + bp->bio_cmd = BIO_WRITE; + g_io_request(bp, cp); + return; + } else { + /* Write done */ + bp2->bio_completed = bp2->bio_length; + } + } +done: + /* + * Finish processing the request. + */ + free(bp->bio_data, M_GEOM); + g_destroy_bio(bp); + g_io_deliver(bp2, bp2->bio_error); +} + static int g_redboot_start(struct bio *bp) { - struct g_provider *pp; + struct g_provider *pp, *pp2; struct g_geom *gp; struct g_redboot_softc *sc; struct g_slicer *gsp; + struct g_slice *gsl; + struct g_consumer *cp; + struct bio *bp2; + size_t bsize; int idx; pp = bp->bio_to; idx = pp->index; gp = pp->geom; gsp = gp->softc; + gsl = &gsp->slices[idx]; sc = gsp->softc; - if (bp->bio_cmd == BIO_GETATTR) { - if (g_handleattr_int(bp, REDBOOT_CLASS_NAME "::entry", - sc->entry[idx])) - return (1); - if (g_handleattr_int(bp, REDBOOT_CLASS_NAME "::dsize", - sc->dsize[idx])) - return (1); + switch (bp->bio_cmd) { + /* + * Read/Write are handled in g_redboot_done() after reading + * the sector + */ + case BIO_READ: + case BIO_WRITE: + break; + case BIO_GETATTR: + if (g_handleattr_int(bp, REDBOOT_CLASS_NAME "::entry", + sc->entry[idx])) + return (1); + if (g_handleattr_int(bp, REDBOOT_CLASS_NAME "::dsize", + sc->dsize[idx])) + return (1); + if (g_handleattr_int(bp, REDBOOT_CLASS_NAME "::sectoff", + sc->sectoff[idx])) + return (1); + return (0); + default: + return (EINVAL); } + cp = LIST_FIRST(&gp->consumer); + pp2 = cp->provider; + bsize = pp2->sectorsize; + + /* + * At this point we have a request which is less than the flash sector + * size, to do this we read the entire sector and then copy the data + * in/out. + */ + KASSERT(bp->bio_length < bsize, ("length greater than one sector")); + KASSERT(bp->bio_offset == 0, ("not at start of sector")); + + bp2 = g_clone_bio(bp); + if (bp2 == NULL) + return (ENOMEM); + bp2->bio_cmd = BIO_READ; + bp2->bio_done = g_redboot_done; + bp2->bio_offset = gsl->offset - sc->sectoff[idx]; + bp2->bio_length = bsize; + bp2->bio_data = malloc(bsize, M_GEOM, M_NOWAIT); + if (bp2->bio_data == NULL) { + g_destroy_bio(bp2); + return (ENOMEM); + } + g_io_request(bp2, cp); return (0); } @@ -144,11 +241,14 @@ g_redboot_dumpconf(struct sbuf *sb, cons if (indent == NULL) { sbuf_printf(sb, " entry %d", sc->entry[pp->index]); sbuf_printf(sb, " dsize %d", sc->dsize[pp->index]); + sbuf_printf(sb, " sectoff %d", sc->sectoff[pp->index]); } else { sbuf_printf(sb, "%s<entry>%d</entry>\n", indent, sc->entry[pp->index]); sbuf_printf(sb, "%s<dsize>%d</dsize>\n", indent, sc->dsize[pp->index]); + sbuf_printf(sb, "%s<sectoff>%d</sectoff>\n", indent, + sc->sectoff[pp->index]); } } } @@ -172,7 +272,7 @@ parse_fis_directory(u_char *buf, size_t { #define match(a,b) (bcmp(a, b, sizeof(b)-1) == 0) struct fis_image_desc *fd, *efd; - struct fis_image_desc *fisdir, *redbcfg; + struct fis_image_desc *fisdir; struct fis_image_desc *head, **tail; int i; @@ -193,15 +293,13 @@ parse_fis_directory(u_char *buf, size_t /* * Scan forward collecting entries in a list. */ - fisdir = redbcfg = NULL; + fisdir = NULL; *(tail = &head) = NULL; for (i = 0; fd < efd; i++, fd++) { if (fd->name[0] == 0xff) continue; if (match(fd->name, FISDIR_NAME)) fisdir = fd; - else if (match(fd->name, REDBCFG_NAME)) - redbcfg = fd; if (nameok(fd->name)) { /* * NB: flash address includes platform mapping; @@ -220,16 +318,6 @@ parse_fis_directory(u_char *buf, size_t (long) offset); return (NULL); } - if (redbcfg != NULL && - fisdir->offset + fisdir->size == redbcfg->offset) { - /* - * Merged FIS/RedBoot config directory. - */ - if (bootverbose) - printf("FIS/RedBoot merged at 0x%jx (not yet)\n", - offset + fisdir->offset); - /* XXX */ - } return head; #undef match } @@ -252,7 +340,8 @@ g_redboot_taste(struct g_class *mp, stru if (!strcmp(pp->geom->class->name, REDBOOT_CLASS_NAME)) return (NULL); /* XXX only taste flash providers */ - if (strncmp(pp->name, "cfi", 3)) + if (strncmp(pp->name, "cfi", 3) && + strncmp(pp->name, "flash/spi", 9)) return (NULL); gp = g_slice_new(mp, REDBOOT_MAXSLICE, pp, &cp, &sc, sizeof(*sc), g_redboot_start); @@ -300,8 +389,25 @@ again: for (fd = head, i = 0; fd != NULL; fd = fd->next) { if (fd->name[0] == '\0') continue; - error = g_slice_config(gp, i, G_SLICE_CONFIG_SET, - fd->offset, fd->size, sectorsize, "redboot/%s", fd->name); + if (fd->size < sectorsize) { + /* + * If the FIS entry is smaller than the sector size + * then set it as hot so g_slice calls us to fix it. + * This will happen if Redboot is compiled with + * CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG. + */ + sc->sectoff[i] = fd->offset & (sectorsize - 1); + error = g_slice_config(gp, i, G_SLICE_CONFIG_SET, + fd->offset, fd->size, fd->size, + "redboot/%s", fd->name); + g_slice_conf_hot(gp, i, fd->offset, fd->size, + G_SLICE_HOT_START, G_SLICE_HOT_DENY, + G_SLICE_HOT_START); + } else { + error = g_slice_config(gp, i, G_SLICE_CONFIG_SET, + fd->offset, fd->size, sectorsize, "redboot/%s", + fd->name); + } if (error) printf("%s: g_slice_config returns %d for \"%s\"\n", __func__, error, fd->name);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200910251913.n9PJDdAO066690>