iseries_setup.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 823 行 · 第 1/2 页
C
823 行
/* * * * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> * * Module name: iSeries_setup.c * * Description: * Architecture- / platform-specific boot-time initialization code for * the IBM iSeries LPAR. Adapted from original code by Grant Erickson and * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek * <dan@net4x.com>. * */#include <linux/pci.h>#include <linux/config.h>#include <linux/init.h>#include <linux/threads.h>#include <linux/smp.h>#include <linux/param.h>#include <linux/string.h>#include <linux/bootmem.h>#include <linux/blk.h>#include <linux/ide.h>#include <linux/seq_file.h>#include <asm/processor.h>#include <asm/machdep.h>#include <asm/page.h>#include <asm/bootinfo.h>#include <asm/time.h>#include "iSeries_setup.h"#include <asm/iSeries/LparData.h>#include <asm/iSeries/HvCallHpt.h>#include <asm/iSeries/HvLpConfig.h>#include <asm/iSeries/HvCallEvent.h>#include <asm/iSeries/HvCallSm.h>#include <asm/iSeries/ItLpQueue.h>#include <asm/iSeries/IoHriMainStore.h>#include <asm/iSeries/iSeries_proc.h>#include <asm/iSeries/pmc_proc.h>#include <asm/iSeries/mf.h>#include <asm/pci-bridge.h>#include <asm/iSeries/HvCallXm.h>#include <asm/iSeries/iSeries_fixup.h>#include <asm/iSeries/HvReleaseData.h>/* Function Prototypes */extern void abort(void);static void build_iSeries_Memory_Map( void );static void setup_iSeries_cache_sizes( void );extern void iSeries_pci_Initialize(void);static int iSeries_show_cpuinfo(struct seq_file *m);static int iSeries_show_percpuinfo(struct seq_file *m, int i);extern struct pci_ops iSeries_pci_ops;/* Global Variables */unsigned short iSeries_icache_line_size = 0;unsigned short iSeries_dcache_line_size = 0;unsigned short iSeries_icache_lines_per_page = 0;unsigned short iSeries_dcache_lines_per_page = 0;unsigned short iSeries_log_icache_line_size = 0;unsigned short iSeries_log_dcache_line_size = 0;unsigned long procFreqHz = 0;unsigned long procFreqMhz = 0;unsigned long procFreqMhzHundreths = 0;unsigned long tbFreqHz = 0;unsigned long tbFreqMhz = 0;unsigned long tbFreqMhzHundreths = 0;unsigned long decr_overclock = 8;unsigned long decr_overclock_proc0 = 8;unsigned long decr_overclock_set = 0;unsigned long decr_overclock_proc0_set = 0;extern unsigned long embedded_sysmap_start;extern unsigned long embedded_sysmap_end;extern unsigned long sysmap;extern unsigned long sysmap_size;extern unsigned long end_of_DRAM; // Defined in ppc/mm/init.c#ifdef CONFIG_SMPextern struct smp_ops_t iSeries_smp_ops;#endif /* CONFIG_SMP *//* XXX for now... */#ifndef CONFIG_PCIunsigned long isa_io_base;#endif/* * void __init platform_init() * * Description: * This routine... * * Input(s): * r3 - Optional pointer to a board information structure. * r4 - Optional pointer to the physical starting address of the init RAM * disk. * r5 - Optional pointer to the physical ending address of the init RAM * disk. * r6 - Optional pointer to the physical starting address of any kernel * command-line parameters. * r7 - Optional pointer to the physical ending address of any kernel * command-line parameters. * * Output(s): * N/A * * Returns: * N/A * */extern int rd_size; // Defined in drivers/block/rd.cextern u64 next_jiffy_update_tb[];extern u64 get_tb64(void);unsigned long __init iSeries_find_end_of_memory(void){ /* totalLpChunks contains the size of memory (in units of 256K) */ unsigned long memory_end = (totalLpChunks << 18); #ifndef CONFIG_HIGHMEM /* Max memory if highmem is not configured is 768 MB */ if (memory_end > (768 << 20)) memory_end = 768 << 20; #endif /* CONFIG_HIGHMEM */ return memory_end;}void __initplatform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7){ parse_bootinfo(find_bootinfo());#if defined(CONFIG_BLK_DEV_INITRD) /* * If the init RAM disk has been configured and there is * a non-zero starting address for it, set it up */ if ( xNaca.xRamDisk ) { initrd_start = xNaca.xRamDisk + KERNELBASE; initrd_end = initrd_start + xNaca.xRamDiskSize * PAGE_SIZE; initrd_below_start_ok = 1; // ramdisk in kernel space ROOT_DEV = MKDEV( RAMDISK_MAJOR, 0 ); if ( ((rd_size*1024)/PAGE_SIZE) < xNaca.xRamDiskSize ) rd_size = (xNaca.xRamDiskSize*PAGE_SIZE)/1024; } else#endif /* CONFIG_BLK_DEV_INITRD */#if CONFIG_VIODASD_IDE { ROOT_DEV = MKDEV( IDE0_MAJOR, 1 ); }#elif defined(CONFIG_VIODASD) { ROOT_DEV = MKDEV( VIODASD_MAJOR, 1 ); }#endif /* CONFIG_VIODASD_IDE */ /* If an embedded System.map has been added to the kernel, * set it up. */ if ( embedded_sysmap_start ) { sysmap = embedded_sysmap_start + KERNELBASE; sysmap_size = embedded_sysmap_end - embedded_sysmap_start; } /* Copy the kernel command line arguments to a safe place. */ if (r6) { *(char *)(r7 + KERNELBASE) = 0; strcpy(cmd_line, (char *)(r6 + KERNELBASE)); } /* Initialize the table which translate Linux physical addresses to * iSeries absolute addresses */ build_iSeries_Memory_Map(); setup_iSeries_cache_sizes(); /* Initialize machine-dependency vectors */ ppc_md.setup_arch = iSeries_setup_arch; ppc_md.show_cpuinfo = iSeries_show_cpuinfo; ppc_md.show_percpuinfo = iSeries_show_percpuinfo; ppc_md.irq_cannonicalize = NULL; ppc_md.init_IRQ = iSeries_init_IRQ; ppc_md.get_irq = iSeries_get_irq; ppc_md.init = NULL; ppc_md.restart = iSeries_restart; ppc_md.power_off = iSeries_power_off; ppc_md.halt = iSeries_halt; ppc_md.time_init = NULL; ppc_md.set_rtc_time = iSeries_set_rtc_time; ppc_md.get_rtc_time = iSeries_get_rtc_time; ppc_md.calibrate_decr = iSeries_calibrate_decr; ppc_md.progress = iSeries_progress; ppc_md.find_end_of_memory = iSeries_find_end_of_memory; ppc_md.kbd_setkeycode = NULL; ppc_md.kbd_getkeycode = NULL; ppc_md.kbd_translate = NULL; ppc_md.kbd_unexpected_up = NULL; ppc_md.kbd_leds = NULL; ppc_md.kbd_init_hw = NULL;#ifdef CONFIG_PCI ppc_md.pcibios_fixup_bus = iSeries_fixup_bus; ppc_md.pcibios_fixup = iSeries_fixup;#else ppc_md.pcibios_fixup_bus = NULL; ppc_md.pcibios_fixup = NULL;#endif /* CONFIG_PCI */#if defined(CONFIG_MAGIC_SYSRQ) ppc_md.ppc_kbd_sysrq_xlate = NULL;#endif#ifdef CONFIG_SMP ppc_md.smp_ops = &iSeries_smp_ops;#endif /* CONFIG_SMP */ // Associate Lp Event Queue 0 with processor 0 HvCallEvent_setLpEventQueueInterruptProc( 0, 0 ); { // copy the command line parameter from the primary VSP char *p, *q; HvCallEvent_dmaToSp( cmd_line, 2*64*1024, 256, HvLpDma_Direction_RemoteToLocal ); p = q = cmd_line + 255; while( p > cmd_line ) { if ((*p == 0) || (*p == ' ') || (*p == '\n')) --p; else break; } if ( p < q ) *(p+1) = 0; } next_jiffy_update_tb[0] = get_tb64(); iSeries_proc_early_init(); mf_init(); iSeries_proc_callback( &pmc_proc_init ); return;}/* * The iSeries may have very large memories ( > 128 GB ) and a partition * may get memory in "chunks" that may be anywhere in the 2**52 real * address space. The chunks are 256K in size. To map this to the * memory model Linux expects, the iSeries specific code builds a * translation table to translate what Linux thinks are "physical" * addresses to the actual real addresses. This allows us to make * it appear to Linux that we have contiguous memory starting at * physical address zero while in fact this could be far from the truth. * To avoid confusion, I'll let the words physical and/or real address * apply to the Linux addresses while I'll use "absolute address" to * refer to the actual hardware real address. * * build_iSeries_Memory_Map gets information from the Hypervisor and * looks at the Main Store VPD to determine the absolute addresses * of the memory that has been assigned to our partition and builds * a table used to translate Linux's physical addresses to these * absolute addresses. Absolute addresses are needed when * communicating with the hypervisor (e.g. to build HPT entries) */static void __init build_iSeries_Memory_Map(void){ u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize; u32 hptFirstChunk, hptLastChunk, hptSizeChunks; u32 absAddrHi, absAddrLo; u32 nextPhysChunk; u32 holeFirstChunk, holeSizeChunks; u32 totalChunks,moreChunks; u32 currChunk, thisChunk, absChunk; u32 currDword; u32 chunkBit; u64 holeStart, holeEnd, holeSize; u64 map; struct IoHriMainStoreSegment4 * msVpd; // Get absolute address of our load area // and map it to physical address 0 // This guarantees that the loadarea ends up at physical 0 // otherwise, it might not be returned by PLIC as the first // chunks loadAreaFirstChunk = (u32)(itLpNaca.xLoadAreaAddr >> 18); loadAreaSize = itLpNaca.xLoadAreaChunks; loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1; // Get absolute address of our HPT and remember it so // we won't map it to any physical address hptFirstChunk = (u32)(HvCallHpt_getHptAddress() >> 18 ); hptSizeChunks = (u32)(HvCallHpt_getHptPages() >> 6 ); hptLastChunk = hptFirstChunk + hptSizeChunks - 1; loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1; absAddrLo = loadAreaFirstChunk << 18; absAddrHi = loadAreaFirstChunk >> 14; printk( "Mapping load area - physical addr = 0, absolute addr = %08x%08x\n", absAddrHi, absAddrLo ); printk( "Load area size %dK\n", loadAreaSize*256 ); nextPhysChunk = 0; for ( absChunk = loadAreaFirstChunk; absChunk <= loadAreaLastChunk; ++absChunk ) { if ( ( absChunk < hptFirstChunk ) || ( absChunk > hptLastChunk ) ) { msChunks[nextPhysChunk] = absChunk; ++nextPhysChunk; } } // Get absolute address of our HPT and remember it so // we won't map it to any physical address hptFirstChunk = (u32)(HvCallHpt_getHptAddress() >> 18 ); hptSizeChunks = (u32)(HvCallHpt_getHptPages() >> 6 ); hptLastChunk = hptFirstChunk + hptSizeChunks - 1; absAddrLo = hptFirstChunk << 18; absAddrHi = hptFirstChunk >> 14; printk( "HPT absolute addr = %08x%08x, size = %dK\n", absAddrHi, absAddrLo, hptSizeChunks*256 ); // Determine if absolute memory has any // holes so that we can interpret the // access map we get back from the hypervisor // correctly. msVpd = (struct IoHriMainStoreSegment4 *)xMsVpd; holeStart = msVpd->nonInterleavedBlocksStartAdr; holeEnd = msVpd->nonInterleavedBlocksEndAdr; holeSize = holeEnd - holeStart; if ( holeSize ) { holeStart = holeStart & 0x000fffffffffffff; holeStart = holeStart >> 18; holeFirstChunk = (u32)holeStart; holeSize = holeSize >> 18; holeSizeChunks = (u32)holeSize; printk( "Main store hole: start chunk = %0x, size = %0x chunks\n", holeFirstChunk, holeSizeChunks ); } else { holeFirstChunk = 0xffffffff; holeSizeChunks = 0; } // Process the main store access map from the hypervisor // to build up our physical -> absolute translation table totalChunks = (u32)HvLpConfig_getMsChunks(); if ((totalChunks-hptSizeChunks) > 16384) { panic("More than 4GB of memory assigned to this partition"); } currChunk = 0; currDword = 0; moreChunks = totalChunks; while ( moreChunks ) { map = HvCallSm_get64BitsOfAccessMap( itLpNaca.xLpIndex, currDword ); thisChunk = currChunk; while ( map ) { chunkBit = map >> 63; map <<= 1; if ( chunkBit ) { --moreChunks; absChunk = thisChunk; if ( absChunk >= holeFirstChunk ) absChunk += holeSizeChunks; if ( ( ( absChunk < hptFirstChunk ) || ( absChunk > hptLastChunk ) ) && ( ( absChunk < loadAreaFirstChunk ) || ( absChunk > loadAreaLastChunk ) ) ) {// printk( "Mapping physical = %0x to absolute %0x for 256K\n", nextPhysChunk << 18, absChunk << 18 ); msChunks[nextPhysChunk] = absChunk; ++nextPhysChunk; } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?