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 + -
显示快捷键?