📄 dt.c
字号:
/* * Copyright (C) 2005-2006 Michael Ellerman, IBM Corporation * Copyright (C) 2000-2004, IBM Corporation * * Description: * This file contains all the routines to build a flattened device * tree for a legacy iSeries machine. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#undef DEBUG#include <linux/types.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/pci_regs.h>#include <linux/pci_ids.h>#include <linux/threads.h>#include <linux/bitops.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/if_ether.h> /* ETH_ALEN */#include <asm/machdep.h>#include <asm/prom.h>#include <asm/lppaca.h>#include <asm/cputable.h>#include <asm/abs_addr.h>#include <asm/system.h>#include <asm/iseries/hv_types.h>#include <asm/iseries/hv_lp_config.h>#include <asm/iseries/hv_call_xm.h>#include <asm/udbg.h>#include "processor_vpd.h"#include "call_hpt.h"#include "call_pci.h"#include "pci.h"#include "it_exp_vpd_panel.h"#include "naca.h"#ifdef DEBUG#define DBG(fmt...) udbg_printf(fmt)#else#define DBG(fmt...)#endif/* * These are created by the linker script at the start and end * of the section containing all the strings from this file. */extern char __dt_strings_start[];extern char __dt_strings_end[];struct iseries_flat_dt { struct boot_param_header header; u64 reserve_map[2];};static void * __initdata dt_data;/* * Putting these strings here keeps them out of the section * that we rename to .dt_strings using objcopy and capture * for the strings blob of the flattened device tree. */static char __initdata device_type_cpu[] = "cpu";static char __initdata device_type_memory[] = "memory";static char __initdata device_type_serial[] = "serial";static char __initdata device_type_network[] = "network";static char __initdata device_type_pci[] = "pci";static char __initdata device_type_vdevice[] = "vdevice";static char __initdata device_type_vscsi[] = "vscsi";/* EBCDIC to ASCII conversion routines */static unsigned char __init e2a(unsigned char x){ switch (x) { case 0x81 ... 0x89: return x - 0x81 + 'a'; case 0x91 ... 0x99: return x - 0x91 + 'j'; case 0xA2 ... 0xA9: return x - 0xA2 + 's'; case 0xC1 ... 0xC9: return x - 0xC1 + 'A'; case 0xD1 ... 0xD9: return x - 0xD1 + 'J'; case 0xE2 ... 0xE9: return x - 0xE2 + 'S'; case 0xF0 ... 0xF9: return x - 0xF0 + '0'; } return ' ';}static unsigned char * __init strne2a(unsigned char *dest, const unsigned char *src, size_t n){ int i; n = strnlen(src, n); for (i = 0; i < n; i++) dest[i] = e2a(src[i]); return dest;}static struct iseries_flat_dt * __init dt_init(void){ struct iseries_flat_dt *dt; unsigned long str_len; str_len = __dt_strings_end - __dt_strings_start; dt = (struct iseries_flat_dt *)ALIGN(klimit, 8); dt->header.off_mem_rsvmap = offsetof(struct iseries_flat_dt, reserve_map); dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8); dt->header.off_dt_struct = dt->header.off_dt_strings + ALIGN(str_len, 8); dt_data = (void *)((unsigned long)dt + dt->header.off_dt_struct); dt->header.dt_strings_size = str_len; /* There is no notion of hardware cpu id on iSeries */ dt->header.boot_cpuid_phys = smp_processor_id(); memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start, str_len); dt->header.magic = OF_DT_HEADER; dt->header.version = 0x10; dt->header.last_comp_version = 0x10; dt->reserve_map[0] = 0; dt->reserve_map[1] = 0; return dt;}static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value){ *((u32 *)dt_data) = value; dt_data += sizeof(u32);}#ifdef notyetstatic void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value){ *((u64 *)dt_data) = value; dt_data += sizeof(u64);}#endifstatic void __init dt_push_bytes(struct iseries_flat_dt *dt, const char *data, int len){ memcpy(dt_data, data, len); dt_data += ALIGN(len, 4);}static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name){ dt_push_u32(dt, OF_DT_BEGIN_NODE); dt_push_bytes(dt, name, strlen(name) + 1);}#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)static void __init dt_prop(struct iseries_flat_dt *dt, const char *name, const void *data, int len){ unsigned long offset; dt_push_u32(dt, OF_DT_PROP); /* Length of the data */ dt_push_u32(dt, len); offset = name - __dt_strings_start; /* The offset of the properties name in the string blob. */ dt_push_u32(dt, (u32)offset); /* The actual data. */ dt_push_bytes(dt, data, len);}static void __init dt_prop_str(struct iseries_flat_dt *dt, const char *name, const char *data){ dt_prop(dt, name, data, strlen(data) + 1); /* + 1 for NULL */}static void __init dt_prop_u32(struct iseries_flat_dt *dt, const char *name, u32 data){ dt_prop(dt, name, &data, sizeof(u32));}static void __init dt_prop_u64(struct iseries_flat_dt *dt, const char *name, u64 data){ dt_prop(dt, name, &data, sizeof(u64));}static void __init dt_prop_u64_list(struct iseries_flat_dt *dt, const char *name, u64 *data, int n){ dt_prop(dt, name, data, sizeof(u64) * n);}static void __init dt_prop_u32_list(struct iseries_flat_dt *dt, const char *name, u32 *data, int n){ dt_prop(dt, name, data, sizeof(u32) * n);}#ifdef notyetstatic void __init dt_prop_empty(struct iseries_flat_dt *dt, const char *name){ dt_prop(dt, name, NULL, 0);}#endifstatic void __init dt_cpus(struct iseries_flat_dt *dt){ unsigned char buf[32]; unsigned char *p; unsigned int i, index; struct IoHriProcessorVpd *d; u32 pft_size[2]; /* yuck */ snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name); p = strchr(buf, ' '); if (!p) p = buf + strlen(buf); dt_start_node(dt, "cpus"); dt_prop_u32(dt, "#address-cells", 1); dt_prop_u32(dt, "#size-cells", 0); pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA */ pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE); for (i = 0; i < NR_CPUS; i++) { if (lppaca[i].dyn_proc_status >= 2) continue; snprintf(p, 32 - (p - buf), "@%d", i); dt_start_node(dt, buf); dt_prop_str(dt, "device_type", device_type_cpu); index = lppaca[i].dyn_hv_phys_proc_index; d = &xIoHriProcessorVpd[index]; dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024); dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize); dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024); dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize); /* magic conversions to Hz copied from old code */ dt_prop_u32(dt, "clock-frequency", ((1UL << 34) * 1000000) / d->xProcFreq); dt_prop_u32(dt, "timebase-frequency", ((1UL << 32) * 1000000) / d->xTimeBaseFreq); dt_prop_u32(dt, "reg", i); dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2); dt_end_node(dt); } dt_end_node(dt);}static void __init dt_model(struct iseries_flat_dt *dt){ char buf[16] = "IBM,"; /* N.B. lparcfg.c knows about the "IBM," prefixes ... */ /* "IBM," + mfgId[2:3] + systemSerial[1:5] */ strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2); strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5); buf[11] = '\0'; dt_prop_str(dt, "system-id", buf); /* "IBM," + machineType[0:4] */ strne2a(buf + 4, xItExtVpdPanel.machineType, 4); buf[8] = '\0'; dt_prop_str(dt, "model", buf); dt_prop_str(dt, "compatible", "IBM,iSeries"); dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex());}static void __init dt_initrd(struct iseries_flat_dt *dt){#ifdef CONFIG_BLK_DEV_INITRD if (naca.xRamDisk) { dt_prop_u64(dt, "linux,initrd-start", (u64)naca.xRamDisk); dt_prop_u64(dt, "linux,initrd-end", (u64)naca.xRamDisk + naca.xRamDiskSize * HW_PAGE_SIZE); }#endif}static void __init dt_do_vdevice(struct iseries_flat_dt *dt, const char *name, u32 reg, int unit, const char *type, const char *compat, int end){ char buf[32]; snprintf(buf, 32, "%s@%08x", name, reg + ((unit >= 0) ? unit : 0)); dt_start_node(dt, buf); dt_prop_str(dt, "device_type", type); if (compat)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -