[Skiboot] [RFC PATCH 4/7] external/common: Add POWERPC code reenable building pflash for POWER
Cyril Bur
cyril.bur at au1.ibm.com
Mon Aug 3 15:02:08 AEST 2015
On Mon, 20 Jul 2015 14:28:13 +0930
Joel Stanley <joel at jms.id.au> wrote:
> On Fri, 2015-07-17 at 17:01 +1000, Cyril Bur wrote:
> > As per commit to create the external/common code, this commit introduces
> > the POWER arch compatibility flash reading code.
> >
> > This commit actually should cause no functional change to pflash (it won't
> > be able to access the BMC flash if it ever could), however rather than
> > accessing the flash via the debug xscom interface it will access it though
> > the MTD interface provided by linux and skiboot.
>
Thanks for the review! I'll go pflash some new firmware on a palmetto or two
just to be sure there isn't a massive regression but I can't see myself testing
all the corner cases...
> Did we ever use xscom? I think you mean LPC.
Maybe....
>
> Although it happens to be ARM/Power, when writing your commit messages
> it would make sense to talk about it in terms of the method you're using
> to access it:
>
> AHB is the bus that attaches PNOR to the BMC, which happens to be ARM
> (but could also be ColdFire - but lets not go there)
>
> LPC is how the Power8 is attached to the PNOR.
>
> When the PNOR is mapped on the LPC bus, Linux can talk to it using the:
>
> - mtd device, which uses opal_flash_{read,write,erase}
> - debugfs lpc, which use opal_lpc_{read,write}
>
So this may be the best explaination I have of what used to be done... (i'm
going to run with it!), I'll edit the commit message, probs get you to proof
read it once more...
> (cc+benh so he can correct me where I'm wrong)
> > --- /dev/null
> > +++ b/external/common/arch_flash_powerpc.c
>
> > +static int get_dev_attr(const char *dev, const char *attr_file, uint32_t *attr)
> > +{
> > + char dev_path[PATH_MAX] = SYSFS_MTD_PATH;
> > + /*
> > + * Needs to be large enough to hold at most uint32_t represented as a
> > + * string in hex with leading 0x
> > + */
> > + char attr_buf[10];
> > + int fd, rc;
> > +
> > + /*
> > + * sizeof(dev_path) - (strlen(dev_path) + 1) is the remaining space in
> > + * dev_path, + 1 to account for the '\0'. As strncat could write n+1 bytes
> > + * to dev_path the correct calulcation for n is:
> > + * (sizeof(dev_path) - (strlen(dev_path) + 1) - 1)
> > + */
> > + strncat(dev_path, dev, (sizeof(dev_path) - (strlen(dev_path) + 1) - 1));
> > + strncat(dev_path, "/", (sizeof(dev_path) - (strlen(dev_path) + 1) - 1));
> > + strncat(dev_path, attr_file, (sizeof(dev_path) - (strlen(dev_path) + 1) - 1));
>
> I think this is more readable:
>
> char *dev_path;
> rc = asprintf(&dev_path, "%s/%s/%s", FDT_FLASH_PATH, dev, attr_file);
> if (rc < 0)
> goto out;
Very nice yes.
>
> don't forget to free dev_path after reading it.
>
I bet I did...
> > + fd = open(dev_path, O_RDONLY);
> > + if (fd == -1)
> > + goto out;
> > +
> > + rc = read(fd, attr_buf, sizeof(attr_buf));
> > + close(fd);
> > + if (rc == -1)
> > + goto out;
> > +
> > + if (attr)
> > + *attr = strtol(attr_buf, NULL, 0);
> > +
> > + return 0;
> > +
> > +out:
> > + fprintf(stderr, "Couldn't get MTD device attribute '%s' from '%s'\n", dev, attr_file);
> > + return -1;
> > +}
> > +
> > +static int get_dev_mtd(const char *fdt_flash_path, char **r_path)
>
> r_path means something else to me. Perhaps a different name? fdt_path
> and mtd_path?
>
Sure
> This function is searching for /dev/mtdN devices, and then looking in
> the dt for a matching entry?
>
Yeah, I wasn't thrilled with this method of finding out which /dev/mtdN is the
flash but its the best I could come up with...
> > +{
> > + struct dirent **namelist;
> > + char fdt_node_path[PATH_MAX];
> > + int count, i, rc, fd, done;
> > +
> > + if (!fdt_flash_path)
> > + return -1;
> > +
> > + fd = open(fdt_flash_path, O_RDONLY);
> > + if (fd == -1) {
> > + fprintf(stderr, "Couldn't open '%s' FDT attribute to determine which flash device to use\n",
> > + fdt_flash_path);
> > + return -1;
> > + }
> > +
> > + rc = read(fd, fdt_node_path, sizeof(fdt_node_path));
> > + close(fd);
> > + if (rc == -1) {
> > + fprintf(stderr, "Couldn't read flash FDT node from '%s'\n", fdt_flash_path);
>
> We can give the user a hint that they might not have permissions
> (root?), or that their kernel/skiboot may not be new enough to have the
> flash node in the device tree.
>
Yeah, hints are always nice.
> Is there a --force mode so the user can say "just use the flash device
> I've pointed you to?"
It's not really up to this layer to worry too much about that but it can be
done.
If you look at arch_flash_init(), what you would want is a tool which
passes through something in with *file, the gard tool is written that way
(although it doesn't use this infrastructure yet. pflash would need to be
updated --force or --file or whatever is what it needs... this is something I'm
planning on doing, it's basically a must for running pflash on x86, which, is
going to be nice!
>
> > + return -1;
> > + }
> > +
> > + count = scandir(SYSFS_MTD_PATH, &namelist, NULL, alphasort);
> > + if (count == -1) {
> > + fprintf(stderr, "Couldn't scan '%s' for MTD devices\n", SYSFS_MTD_PATH);
>
> Again, give the user a hint to run as root?
>
> > + return -1;
> > + }
> > +
> > + rc = 0;
> > + done = 0;
> > + for (i = 0; i < count; i++) {
> > + struct dirent *dirent;
> > + char dev_path[PATH_MAX] = SYSFS_MTD_PATH;
> > + char fdt_node_path_tmp[PATH_MAX];
> > +
> > + dirent = namelist[i];
> > + if (dirent->d_name[0] == '.' || rc || done) {
> > + free(namelist[i]);
> > + continue;
> > + }
> > +
> > + strncat(dev_path, dirent->d_name, sizeof(dev_path) - strlen(dev_path) - 2);
> > + strncat(dev_path, "/device/of_node", sizeof(dev_path) - strlen(dev_path) - 2);
>
> asprintf
>
> > +
> > + rc = readlink(dev_path, fdt_node_path_tmp, sizeof(fdt_node_path_tmp) - 1);
> > + if (rc == -1) {
> > + /*
> > + * This might fail because it could not exist if the system has flash
> > + * devices that present as mtd but don't have corresponding FDT
> > + * nodes, just continue silently.
> > + */
> > + free(namelist[i]);
> > + /* Should still try the next dir so reset rc */
> > + rc = 0;
> > + continue;
> > + }
> > + fdt_node_path_tmp[rc] = '\0';
> > +
> > + if (strstr(fdt_node_path_tmp, fdt_node_path)) {
> > + uint32_t flags, size;
> > +
> > + /*
> > + * size and flags could perhaps have be gotten another way but this
> > + * method is super unlikely to fail so it will do.
> > + */
> > +
> > + /* Check to see if device is writeable */
> > + rc = get_dev_attr(dirent->d_name, "flags", &flags);
> > + if (rc) {
> > + free(namelist[i]);
> > + continue;
> > + }
> > +
> > + /* Get the size of the mtd device while we're at it */
> > + rc = get_dev_attr(dirent->d_name, "size", &size);
> > + if (rc) {
> > + free(namelist[i]);
> > + continue;
> > + }
> > +
> > + strcpy(dev_path, "/dev/");
> > + strncat(dev_path, dirent->d_name, sizeof(dev_path) - strlen(dev_path) - 2);
> > + *r_path = strdup(dev_path);
>
> asprintf
>
> > + done = 1;
>
> true?
true!
>
> > + }
> > + free(namelist[i]);
> > + }
> > + free(namelist);
> > +
> > + if (!done)
> > + fprintf(stderr, "Couldn't find '%s' corresponding MTD\n", fdt_flash_path);
> > +
> > + /* explicit negative value so as to not return a libflash code */
> > + return done ? rc : -1;
> > +}
>
>
More information about the Skiboot
mailing list