📄 hypfs_diag.c
字号:
static void diag204_free_buffer(void){ if (!diag204_buf) return; if (diag204_buf_vmalloc) { vfree(diag204_buf_vmalloc); diag204_buf_vmalloc = NULL; } else { free_pages((unsigned long) diag204_buf, 0); } diag204_buf_pages = 0; diag204_buf = NULL;}static void *diag204_alloc_vbuf(int pages){ /* The buffer has to be page aligned! */ diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1)); if (!diag204_buf_vmalloc) return ERR_PTR(-ENOMEM); diag204_buf = (void*)((unsigned long)diag204_buf_vmalloc & ~0xfffUL) + 0x1000; diag204_buf_pages = pages; return diag204_buf;}static void *diag204_alloc_rbuf(void){ diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0); if (!diag204_buf) return ERR_PTR(-ENOMEM); diag204_buf_pages = 1; return diag204_buf;}static void *diag204_get_buffer(enum diag204_format fmt, int *pages){ if (diag204_buf) { *pages = diag204_buf_pages; return diag204_buf; } if (fmt == INFO_SIMPLE) { *pages = 1; return diag204_alloc_rbuf(); } else {/* INFO_EXT */ *pages = diag204((unsigned long)SUBC_RSI | (unsigned long)INFO_EXT, 0, NULL); if (*pages <= 0) return ERR_PTR(-ENOSYS); else return diag204_alloc_vbuf(*pages); }}/* * diag204_probe() has to find out, which type of diagnose 204 implementation * we have on our machine. Currently there are three possible scanarios: * - subcode 4 + simple data format (only one page) * - subcode 4-6 + extended data format * - subcode 4-7 + extended data format * * Subcode 5 is used to retrieve the size of the data, provided by subcodes * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition * to subcode 6 it provides also information about secondary cpus. * In order to get as much information as possible, we first try * subcode 7, then 6 and if both fail, we use subcode 4. */static int diag204_probe(void){ void *buf; int pages, rc; buf = diag204_get_buffer(INFO_EXT, &pages); if (!IS_ERR(buf)) { if (diag204((unsigned long)SUBC_STIB7 | (unsigned long)INFO_EXT, pages, buf) >= 0) { diag204_store_sc = SUBC_STIB7; diag204_info_type = INFO_EXT; goto out; } if (diag204((unsigned long)SUBC_STIB6 | (unsigned long)INFO_EXT, pages, buf) >= 0) { diag204_store_sc = SUBC_STIB7; diag204_info_type = INFO_EXT; goto out; } diag204_free_buffer(); } /* subcodes 6 and 7 failed, now try subcode 4 */ buf = diag204_get_buffer(INFO_SIMPLE, &pages); if (IS_ERR(buf)) { rc = PTR_ERR(buf); goto fail_alloc; } if (diag204((unsigned long)SUBC_STIB4 | (unsigned long)INFO_SIMPLE, pages, buf) >= 0) { diag204_store_sc = SUBC_STIB4; diag204_info_type = INFO_SIMPLE; goto out; } else { rc = -ENOSYS; goto fail_store; }out: rc = 0;fail_store: diag204_free_buffer();fail_alloc: return rc;}static void *diag204_store(void){ void *buf; int pages; buf = diag204_get_buffer(diag204_info_type, &pages); if (IS_ERR(buf)) goto out; if (diag204((unsigned long)diag204_store_sc | (unsigned long)diag204_info_type, pages, buf) < 0) return ERR_PTR(-ENOSYS);out: return buf;}/* Diagnose 224 functions */static int diag224(void *ptr){ int rc = -ENOTSUPP; asm volatile( " diag %1,%2,0x224\n" "0: lhi %0,0x0\n" "1:\n" EX_TABLE(0b,1b) : "+d" (rc) :"d" (0), "d" (ptr) : "memory"); return rc;}static int diag224_get_name_table(void){ /* memory must be below 2GB */ diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); if (!diag224_cpu_names) return -ENOMEM; if (diag224(diag224_cpu_names)) { kfree(diag224_cpu_names); return -ENOTSUPP; } EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16); return 0;}static void diag224_delete_name_table(void){ kfree(diag224_cpu_names);}static int diag224_idx2name(int index, char *name){ memcpy(name, diag224_cpu_names + ((index + 1) * CPU_NAME_LEN), CPU_NAME_LEN); name[CPU_NAME_LEN] = 0; strstrip(name); return 0;}__init int hypfs_diag_init(void){ int rc; if (diag204_probe()) { printk(KERN_ERR "hypfs: diag 204 not working."); return -ENODATA; } rc = diag224_get_name_table(); if (rc) { diag204_free_buffer(); printk(KERN_ERR "hypfs: could not get name table.\n"); } return rc;}void hypfs_diag_exit(void){ diag224_delete_name_table(); diag204_free_buffer();}/* * Functions to create the directory structure * ******************************************* */static int hypfs_create_cpu_files(struct super_block *sb, struct dentry *cpus_dir, void *cpu_info){ struct dentry *cpu_dir; char buffer[TMP_SIZE]; void *rc; snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type, cpu_info)); cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer); rc = hypfs_create_u64(sb, cpu_dir, "mgmtime", cpu_info__acc_time(diag204_info_type, cpu_info) - cpu_info__lp_time(diag204_info_type, cpu_info)); if (IS_ERR(rc)) return PTR_ERR(rc); rc = hypfs_create_u64(sb, cpu_dir, "cputime", cpu_info__lp_time(diag204_info_type, cpu_info)); if (IS_ERR(rc)) return PTR_ERR(rc); if (diag204_info_type == INFO_EXT) { rc = hypfs_create_u64(sb, cpu_dir, "onlinetime", cpu_info__online_time(diag204_info_type, cpu_info)); if (IS_ERR(rc)) return PTR_ERR(rc); } diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer); rc = hypfs_create_str(sb, cpu_dir, "type", buffer); if (IS_ERR(rc)) return PTR_ERR(rc); return 0;}static void *hypfs_create_lpar_files(struct super_block *sb, struct dentry *systems_dir, void *part_hdr){ struct dentry *cpus_dir; struct dentry *lpar_dir; char lpar_name[LPAR_NAME_LEN + 1]; void *cpu_info; int i; part_hdr__part_name(diag204_info_type, part_hdr, lpar_name); lpar_name[LPAR_NAME_LEN] = 0; lpar_dir = hypfs_mkdir(sb, systems_dir, lpar_name); if (IS_ERR(lpar_dir)) return lpar_dir; cpus_dir = hypfs_mkdir(sb, lpar_dir, "cpus"); if (IS_ERR(cpus_dir)) return cpus_dir; cpu_info = part_hdr + part_hdr__size(diag204_info_type); for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) { int rc; rc = hypfs_create_cpu_files(sb, cpus_dir, cpu_info); if (rc) return ERR_PTR(rc); cpu_info += cpu_info__size(diag204_info_type); } return cpu_info;}static int hypfs_create_phys_cpu_files(struct super_block *sb, struct dentry *cpus_dir, void *cpu_info){ struct dentry *cpu_dir; char buffer[TMP_SIZE]; void *rc; snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type, cpu_info)); cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer); if (IS_ERR(cpu_dir)) return PTR_ERR(cpu_dir); rc = hypfs_create_u64(sb, cpu_dir, "mgmtime", phys_cpu__mgm_time(diag204_info_type, cpu_info)); if (IS_ERR(rc)) return PTR_ERR(rc); diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer); rc = hypfs_create_str(sb, cpu_dir, "type", buffer); if (IS_ERR(rc)) return PTR_ERR(rc); return 0;}static void *hypfs_create_phys_files(struct super_block *sb, struct dentry *parent_dir, void *phys_hdr){ int i; void *cpu_info; struct dentry *cpus_dir; cpus_dir = hypfs_mkdir(sb, parent_dir, "cpus"); if (IS_ERR(cpus_dir)) return cpus_dir; cpu_info = phys_hdr + phys_hdr__size(diag204_info_type); for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) { int rc; rc = hypfs_create_phys_cpu_files(sb, cpus_dir, cpu_info); if (rc) return ERR_PTR(rc); cpu_info += phys_cpu__size(diag204_info_type); } return cpu_info;}int hypfs_diag_create_files(struct super_block *sb, struct dentry *root){ struct dentry *systems_dir, *hyp_dir; void *time_hdr, *part_hdr; int i, rc; void *buffer, *ptr; buffer = diag204_store(); if (IS_ERR(buffer)) return PTR_ERR(buffer); systems_dir = hypfs_mkdir(sb, root, "systems"); if (IS_ERR(systems_dir)) { rc = PTR_ERR(systems_dir); goto err_out; } time_hdr = (struct x_info_blk_hdr *)buffer; part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type); for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) { part_hdr = hypfs_create_lpar_files(sb, systems_dir, part_hdr); if (IS_ERR(part_hdr)) { rc = PTR_ERR(part_hdr); goto err_out; } } if (info_blk_hdr__flags(diag204_info_type, time_hdr) & LPAR_PHYS_FLG) { ptr = hypfs_create_phys_files(sb, root, part_hdr); if (IS_ERR(ptr)) { rc = PTR_ERR(ptr); goto err_out; } } hyp_dir = hypfs_mkdir(sb, root, "hyp"); if (IS_ERR(hyp_dir)) { rc = PTR_ERR(hyp_dir); goto err_out; } ptr = hypfs_create_str(sb, hyp_dir, "type", "LPAR Hypervisor"); if (IS_ERR(ptr)) { rc = PTR_ERR(ptr); goto err_out; } rc = 0;err_out: return rc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -