diff options
Diffstat (limited to 'arch/ia64/sn')
-rw-r--r-- | arch/ia64/sn/kernel/sn2/sn_hwperf.c | 133 |
1 files changed, 124 insertions, 9 deletions
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index 197356460ee..3bff99130d5 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c @@ -28,6 +28,7 @@ #include <linux/vmalloc.h> #include <linux/seq_file.h> #include <linux/miscdevice.h> +#include <linux/utsname.h> #include <linux/cpumask.h> #include <linux/smp_lock.h> #include <linux/nodemask.h> @@ -43,6 +44,7 @@ #include <asm/sn/module.h> #include <asm/sn/geo.h> #include <asm/sn/sn2/sn_hwperf.h> +#include <asm/sn/addrs.h> static void *sn_hwperf_salheap = NULL; static int sn_hwperf_obj_cnt = 0; @@ -81,26 +83,45 @@ out: return e; } +static int sn_hwperf_location_to_bpos(char *location, + int *rack, int *bay, int *slot, int *slab) +{ + char type; + + /* first scan for an old style geoid string */ + if (sscanf(location, "%03d%c%02d#%d", + rack, &type, bay, slab) == 4) + *slot = 0; + else /* scan for a new bladed geoid string */ + if (sscanf(location, "%03d%c%02d^%02d#%d", + rack, &type, bay, slot, slab) != 5) + return -1; + /* success */ + return 0; +} + static int sn_hwperf_geoid_to_cnode(char *location) { int cnode; geoid_t geoid; moduleid_t module_id; - char type; - int rack, slot, slab; - int this_rack, this_slot, this_slab; + int rack, bay, slot, slab; + int this_rack, this_bay, this_slot, this_slab; - if (sscanf(location, "%03d%c%02d#%d", &rack, &type, &slot, &slab) != 4) + if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab)) return -1; for (cnode = 0; cnode < numionodes; cnode++) { geoid = cnodeid_get_geoid(cnode); module_id = geo_module(geoid); this_rack = MODULE_GET_RACK(module_id); - this_slot = MODULE_GET_BPOS(module_id); + this_bay = MODULE_GET_BPOS(module_id); + this_slot = 0; /* XXX */ this_slab = geo_slab(geoid); - if (rack == this_rack && slot == this_slot && slab == this_slab) + if (rack == this_rack && bay == this_bay && + slot == this_slot && slab == this_slab) { break; + } } return cnode < numionodes ? cnode : -1; @@ -153,11 +174,29 @@ static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj, return slabname; } +static void print_pci_topology(struct seq_file *s, + struct sn_hwperf_object_info *obj, int *ordinal, + char *pci_topo_buf, int len) +{ + char *p1; + char *p2; + + for (p1=pci_topo_buf; *p1 && p1 < pci_topo_buf + len;) { + if (!(p2 = strchr(p1, '\n'))) + break; + *p2 = '\0'; + seq_printf(s, "pcibus %d %s-%s\n", + *ordinal, obj->location, p1); + (*ordinal)++; + p1 = p2 + 1; + } +} + static int sn_topology_show(struct seq_file *s, void *d) { int sz; int pt; - int e; + int e = 0; int i; int j; const char *slabname; @@ -169,11 +208,46 @@ static int sn_topology_show(struct seq_file *s, void *d) struct sn_hwperf_object_info *p; struct sn_hwperf_object_info *obj = d; /* this object */ struct sn_hwperf_object_info *objs = s->private; /* all objects */ + int rack, bay, slot, slab; + u8 shubtype; + u8 system_size; + u8 sharing_size; + u8 partid; + u8 coher; + u8 nasid_shift; + u8 region_size; + u16 nasid_mask; + int nasid_msb; + char *pci_topo_buf; + int pci_bus_ordinal = 0; + static int pci_topo_buf_len = 256; if (obj == objs) { - seq_printf(s, "# sn_topology version 1\n"); + seq_printf(s, "# sn_topology version 2\n"); seq_printf(s, "# objtype ordinal location partition" " [attribute value [, ...]]\n"); + + if (ia64_sn_get_sn_info(0, + &shubtype, &nasid_mask, &nasid_shift, &system_size, + &sharing_size, &partid, &coher, ®ion_size)) + BUG(); + for (nasid_msb=63; nasid_msb > 0; nasid_msb--) { + if (((u64)nasid_mask << nasid_shift) & (1ULL << nasid_msb)) + break; + } + seq_printf(s, "partition %u %s local " + "shubtype %s, " + "nasid_mask 0x%016lx, " + "nasid_bits %d:%d, " + "system_size %d, " + "sharing_size %d, " + "coherency_domain %d, " + "region_size %d\n", + + partid, system_utsname.nodename, + shubtype ? "shub2" : "shub1", + (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift, + system_size, sharing_size, coher, region_size); } if (SN_HWPERF_FOREIGN(obj)) { @@ -181,7 +255,7 @@ static int sn_topology_show(struct seq_file *s, void *d) return 0; } - for (i = 0; obj->name[i]; i++) { + for (i = 0; i < SN_HWPERF_MAXSTRING && obj->name[i]; i++) { if (obj->name[i] == ' ') obj->name[i] = '_'; } @@ -221,6 +295,43 @@ static int sn_topology_show(struct seq_file *s, void *d) seq_putc(s, '\n'); } } + + /* + * PCI busses attached to this node, if any + */ + do { + if (!(pci_topo_buf = vmalloc(pci_topo_buf_len))) { + printk("sn_topology_show: kmalloc failed\n"); + break; + } + + if (sn_hwperf_location_to_bpos(obj->location, + &rack, &bay, &slot, &slab) != 0) + continue; + + e = ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab, + pci_topo_buf, pci_topo_buf_len); + + switch (e) { + case SALRET_NOT_IMPLEMENTED: + case SALRET_INVALID_ARG: + /* ignore, don't print anything */ + e = SN_HWPERF_OP_OK; + break; + + case SALRET_ERROR: + /* retry with a bigger buffer */ + pci_topo_buf_len += 256; + break; + + case SN_HWPERF_OP_OK: + /* export pci bus info */ + print_pci_topology(s, obj, &pci_bus_ordinal, + pci_topo_buf, pci_topo_buf_len); + break; + } + vfree(pci_topo_buf); + } while (e != SN_HWPERF_OP_OK && pci_topo_buf_len < 0x200000); } if (obj->ports) { @@ -397,6 +508,9 @@ static int sn_hwperf_map_err(int hwperf_err) break; case SN_HWPERF_OP_BUSY: + e = -EBUSY; + break; + case SN_HWPERF_OP_RECONFIGURE: e = -EAGAIN; break; @@ -549,6 +663,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) r = sn_hwperf_op_cpu(&op_info); if (r) { r = sn_hwperf_map_err(r); + a.v0 = v0; goto error; } break; |