From 2f7dd07ecadac6bdc3d55c217d65efa2834ba1cb Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sat, 13 Jan 2018 17:37:13 -0500 Subject: nubus: Rework /proc/bus/nubus/s/ implementation The /proc/bus/nubus/s/ directory tree for any slot s is missing a lot of information. The struct file_operations methods have long been left unimplemented (hence the familiar compile-time warning, "Need to set some I/O handlers here"). Slot resources have a complex structure which varies depending on board function. The logic for interpreting these ROM data structures is found in nubus.c. Let's not duplicate that logic in proc.c. Create the /proc/bus/nubus/s/ inodes while scanning slot s. During descent through slot resource subdirectories, call the new nubus_proc_add_foo() functions to create the procfs inodes. Also add a new function, nubus_seq_write_rsrc_mem(), to write the contents of a particular slot resource to a given seq_file. This is used by the procfs file_operations methods, to finally give userspace access to slot ROM information, such as the available video modes. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Geert Uytterhoeven --- drivers/nubus/nubus.c | 114 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 23 deletions(-) (limited to 'drivers/nubus/nubus.c') diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c index c56ac36d91f2..f05541914c21 100644 --- a/drivers/nubus/nubus.c +++ b/drivers/nubus/nubus.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -146,7 +147,7 @@ static inline void *nubus_rom_addr(int slot) return (void *)(0xF1000000 + (slot << 24)); } -static unsigned char *nubus_dirptr(const struct nubus_dirent *nd) +unsigned char *nubus_dirptr(const struct nubus_dirent *nd) { unsigned char *p = nd->base; @@ -173,8 +174,8 @@ void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent, } EXPORT_SYMBOL(nubus_get_rsrc_mem); -void nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent, - unsigned int len) +unsigned int nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent, + unsigned int len) { char *t = dest; unsigned char *p = nubus_dirptr(dirent); @@ -189,9 +190,33 @@ void nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent, } if (len > 0) *t = '\0'; + return t - dest; } EXPORT_SYMBOL(nubus_get_rsrc_str); +void nubus_seq_write_rsrc_mem(struct seq_file *m, + const struct nubus_dirent *dirent, + unsigned int len) +{ + unsigned long buf[32]; + unsigned int buf_size = sizeof(buf); + unsigned char *p = nubus_dirptr(dirent); + + /* If possible, write out full buffers */ + while (len >= buf_size) { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(buf); i++) + buf[i] = nubus_get_rom(&p, sizeof(buf[0]), + dirent->mask); + seq_write(m, buf, buf_size); + len -= buf_size; + } + /* If not, write out individual bytes */ + while (len--) + seq_putc(m, nubus_get_rom(&p, 1, dirent->mask)); +} + int nubus_get_root_dir(const struct nubus_board *board, struct nubus_dir *dir) { @@ -326,35 +351,35 @@ EXPORT_SYMBOL(nubus_find_rsrc); looking at, and print out lots and lots of information from the resource blocks. */ -/* FIXME: A lot of this stuff will eventually be useful after - initialization, for intelligently probing Ethernet and video chips, - among other things. The rest of it should go in the /proc code. - For now, we just use it to give verbose boot logs. */ - static int __init nubus_get_block_rsrc_dir(struct nubus_board *board, + struct proc_dir_entry *procdir, const struct nubus_dirent *parent) { struct nubus_dir dir; struct nubus_dirent ent; nubus_get_subdir(parent, &dir); + dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board); while (nubus_readdir(&dir, &ent) != -1) { u32 size; nubus_get_rsrc_mem(&size, &ent, 4); pr_debug(" block (0x%x), size %d\n", ent.type, size); + nubus_proc_add_rsrc_mem(dir.procdir, &ent, size); } return 0; } static int __init nubus_get_display_vidmode(struct nubus_board *board, + struct proc_dir_entry *procdir, const struct nubus_dirent *parent) { struct nubus_dir dir; struct nubus_dirent ent; nubus_get_subdir(parent, &dir); + dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board); while (nubus_readdir(&dir, &ent) != -1) { switch (ent.type) { @@ -366,37 +391,42 @@ static int __init nubus_get_display_vidmode(struct nubus_board *board, nubus_get_rsrc_mem(&size, &ent, 4); pr_debug(" block (0x%x), size %d\n", ent.type, size); + nubus_proc_add_rsrc_mem(dir.procdir, &ent, size); break; } default: pr_debug(" unknown resource 0x%02x, data 0x%06x\n", ent.type, ent.data); + nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0); } } return 0; } static int __init nubus_get_display_resource(struct nubus_dev *dev, + struct proc_dir_entry *procdir, const struct nubus_dirent *ent) { switch (ent->type) { case NUBUS_RESID_GAMMADIR: pr_debug(" gamma directory offset: 0x%06x\n", ent->data); - nubus_get_block_rsrc_dir(dev->board, ent); + nubus_get_block_rsrc_dir(dev->board, procdir, ent); break; case 0x0080 ... 0x0085: pr_debug(" mode 0x%02x info offset: 0x%06x\n", ent->type, ent->data); - nubus_get_display_vidmode(dev->board, ent); + nubus_get_display_vidmode(dev->board, procdir, ent); break; default: pr_debug(" unknown resource 0x%02x, data 0x%06x\n", ent->type, ent->data); + nubus_proc_add_rsrc_mem(procdir, ent, 0); } return 0; } static int __init nubus_get_network_resource(struct nubus_dev *dev, + struct proc_dir_entry *procdir, const struct nubus_dirent *ent) { switch (ent->type) { @@ -406,16 +436,19 @@ static int __init nubus_get_network_resource(struct nubus_dev *dev, nubus_get_rsrc_mem(addr, ent, 6); pr_debug(" MAC address: %pM\n", addr); + nubus_proc_add_rsrc_mem(procdir, ent, 6); break; } default: pr_debug(" unknown resource 0x%02x, data 0x%06x\n", ent->type, ent->data); + nubus_proc_add_rsrc_mem(procdir, ent, 0); } return 0; } static int __init nubus_get_cpu_resource(struct nubus_dev *dev, + struct proc_dir_entry *procdir, const struct nubus_dirent *ent) { switch (ent->type) { @@ -426,6 +459,7 @@ static int __init nubus_get_cpu_resource(struct nubus_dev *dev, nubus_get_rsrc_mem(&meminfo, ent, 8); pr_debug(" memory: [ 0x%08lx 0x%08lx ]\n", meminfo[0], meminfo[1]); + nubus_proc_add_rsrc_mem(procdir, ent, 8); break; } case NUBUS_RESID_ROMINFO: @@ -435,31 +469,35 @@ static int __init nubus_get_cpu_resource(struct nubus_dev *dev, nubus_get_rsrc_mem(&rominfo, ent, 8); pr_debug(" ROM: [ 0x%08lx 0x%08lx ]\n", rominfo[0], rominfo[1]); + nubus_proc_add_rsrc_mem(procdir, ent, 8); break; } default: pr_debug(" unknown resource 0x%02x, data 0x%06x\n", ent->type, ent->data); + nubus_proc_add_rsrc_mem(procdir, ent, 0); } return 0; } static int __init nubus_get_private_resource(struct nubus_dev *dev, + struct proc_dir_entry *procdir, const struct nubus_dirent *ent) { switch (dev->category) { case NUBUS_CAT_DISPLAY: - nubus_get_display_resource(dev, ent); + nubus_get_display_resource(dev, procdir, ent); break; case NUBUS_CAT_NETWORK: - nubus_get_network_resource(dev, ent); + nubus_get_network_resource(dev, procdir, ent); break; case NUBUS_CAT_CPU: - nubus_get_cpu_resource(dev, ent); + nubus_get_cpu_resource(dev, procdir, ent); break; default: pr_debug(" unknown resource 0x%02x, data 0x%06x\n", ent->type, ent->data); + nubus_proc_add_rsrc_mem(procdir, ent, 0); } return 0; } @@ -474,6 +512,7 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, pr_debug(" Functional resource 0x%02x:\n", parent->type); nubus_get_subdir(parent, &dir); + dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board); /* Actually we should probably panic if this fails */ if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL) @@ -495,14 +534,17 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, dev->dr_hw = nbtdata[3]; pr_debug(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n", nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]); + nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8); break; } case NUBUS_RESID_NAME: { char name[64]; + unsigned int len; - nubus_get_rsrc_str(name, &ent, sizeof(name)); + len = nubus_get_rsrc_str(name, &ent, sizeof(name)); pr_debug(" name: %s\n", name); + nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1); break; } case NUBUS_RESID_DRVRDIR: @@ -511,7 +553,7 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, use this :-) */ pr_debug(" driver directory offset: 0x%06x\n", ent.data); - nubus_get_block_rsrc_dir(board, &ent); + nubus_get_block_rsrc_dir(board, dir.procdir, &ent); break; } case NUBUS_RESID_MINOR_BASEOS: @@ -523,6 +565,7 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, nubus_get_rsrc_mem(&base_offset, &ent, 4); pr_debug(" memory offset: 0x%08x\n", base_offset); + nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4); break; } case NUBUS_RESID_MINOR_LENGTH: @@ -532,18 +575,21 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, nubus_get_rsrc_mem(&length, &ent, 4); pr_debug(" memory length: 0x%08x\n", length); + nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4); break; } case NUBUS_RESID_FLAGS: pr_debug(" flags: 0x%06x\n", ent.data); + nubus_proc_add_rsrc(dir.procdir, &ent); break; case NUBUS_RESID_HWDEVID: pr_debug(" hwdevid: 0x%06x\n", ent.data); + nubus_proc_add_rsrc(dir.procdir, &ent); break; default: /* Local/Private resources have their own function */ - nubus_get_private_resource(dev, &ent); + nubus_get_private_resource(dev, dir.procdir, &ent); } } @@ -552,6 +598,7 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, /* This is *really* cool. */ static int __init nubus_get_icon(struct nubus_board *board, + struct proc_dir_entry *procdir, const struct nubus_dirent *ent) { /* Should be 32x32 if my memory serves me correctly */ @@ -564,11 +611,13 @@ static int __init nubus_get_icon(struct nubus_board *board, pr_debug(" %08x %08x %08x %08x\n", icon[i * 4 + 0], icon[i * 4 + 1], icon[i * 4 + 2], icon[i * 4 + 3]); + nubus_proc_add_rsrc_mem(procdir, ent, 128); return 0; } static int __init nubus_get_vendorinfo(struct nubus_board *board, + struct proc_dir_entry *procdir, const struct nubus_dirent *parent) { struct nubus_dir dir; @@ -578,15 +627,18 @@ static int __init nubus_get_vendorinfo(struct nubus_board *board, pr_debug(" vendor info:\n"); nubus_get_subdir(parent, &dir); + dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board); while (nubus_readdir(&dir, &ent) != -1) { char name[64]; + unsigned int len; /* These are all strings, we think */ - nubus_get_rsrc_str(name, &ent, sizeof(name)); + len = nubus_get_rsrc_str(name, &ent, sizeof(name)); if (ent.type < 1 || ent.type > 5) ent.type = 5; pr_debug(" %s: %s\n", vendor_fields[ent.type - 1], name); + nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1); } return 0; } @@ -599,6 +651,7 @@ static int __init nubus_get_board_resource(struct nubus_board *board, int slot, pr_debug(" Board resource 0x%02x:\n", parent->type); nubus_get_subdir(parent, &dir); + dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board); while (nubus_readdir(&dir, &ent) != -1) { switch (ent.type) { @@ -615,49 +668,62 @@ static int __init nubus_get_board_resource(struct nubus_board *board, int slot, nbtdata[2] != 0 || nbtdata[3] != 0) pr_err("Slot %X: sResource is not a board resource!\n", slot); + nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8); break; } case NUBUS_RESID_NAME: - nubus_get_rsrc_str(board->name, &ent, - sizeof(board->name)); + { + unsigned int len; + + len = nubus_get_rsrc_str(board->name, &ent, + sizeof(board->name)); pr_debug(" name: %s\n", board->name); + nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1); break; + } case NUBUS_RESID_ICON: - nubus_get_icon(board, &ent); + nubus_get_icon(board, dir.procdir, &ent); break; case NUBUS_RESID_BOARDID: pr_debug(" board id: 0x%x\n", ent.data); + nubus_proc_add_rsrc(dir.procdir, &ent); break; case NUBUS_RESID_PRIMARYINIT: pr_debug(" primary init offset: 0x%06x\n", ent.data); + nubus_proc_add_rsrc(dir.procdir, &ent); break; case NUBUS_RESID_VENDORINFO: - nubus_get_vendorinfo(board, &ent); + nubus_get_vendorinfo(board, dir.procdir, &ent); break; case NUBUS_RESID_FLAGS: pr_debug(" flags: 0x%06x\n", ent.data); + nubus_proc_add_rsrc(dir.procdir, &ent); break; case NUBUS_RESID_HWDEVID: pr_debug(" hwdevid: 0x%06x\n", ent.data); + nubus_proc_add_rsrc(dir.procdir, &ent); break; case NUBUS_RESID_SECONDINIT: pr_debug(" secondary init offset: 0x%06x\n", ent.data); + nubus_proc_add_rsrc(dir.procdir, &ent); break; /* WTF isn't this in the functional resources? */ case NUBUS_RESID_VIDNAMES: pr_debug(" vidnames directory offset: 0x%06x\n", ent.data); - nubus_get_block_rsrc_dir(board, &ent); + nubus_get_block_rsrc_dir(board, dir.procdir, &ent); break; /* Same goes for this */ case NUBUS_RESID_VIDMODES: pr_debug(" video mode parameter directory offset: 0x%06x\n", ent.data); + nubus_proc_add_rsrc(dir.procdir, &ent); break; default: pr_debug(" unknown resource 0x%02x, data 0x%06x\n", ent.type, ent.data); + nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0); } } return 0; @@ -748,6 +814,8 @@ static struct nubus_board * __init nubus_add_board(int slot, int bytelanes) if (ent.type < 1 || ent.type > 127) pr_warn("Slot %X: Board resource ID is invalid!\n", slot); + board->procdir = nubus_proc_add_board(board); + nubus_get_board_resource(board, slot, &ent); while (nubus_readdir(&dir, &ent) != -1) { @@ -835,8 +903,8 @@ static int __init nubus_init(void) if (!MACH_IS_MAC) return 0; - nubus_scan_bus(); nubus_proc_init(); + nubus_scan_bus(); return 0; } -- cgit v1.2.3-59-g8ed1b