iSeries_setup.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:23k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * 
  3.  *
  4.  *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
  5.  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  6.  *
  7.  *    Module name: iSeries_setup.c
  8.  *
  9.  *    Description:
  10.  *      Architecture- / platform-specific boot-time initialization code for
  11.  *      the IBM iSeries LPAR.  Adapted from original code by Grant Erickson and
  12.  *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
  13.  *      <dan@net4x.com>.
  14.  *
  15.  *      This program is free software; you can redistribute it and/or
  16.  *      modify it under the terms of the GNU General Public License
  17.  *      as published by the Free Software Foundation; either version
  18.  *      2 of the License, or (at your option) any later version.
  19.  */
  20.  
  21. #include <linux/config.h>
  22. #include <linux/init.h>
  23. #include <linux/threads.h>
  24. #include <linux/smp.h>
  25. #include <linux/param.h>
  26. #include <linux/string.h>
  27. #include <linux/bootmem.h>
  28. #include <linux/blk.h>
  29. #include <linux/seq_file.h>
  30. #include <asm/processor.h>
  31. #include <asm/machdep.h>
  32. #include <asm/page.h>
  33. #include <asm/mmu.h>
  34. #include <asm/pgtable.h>
  35. #include <asm/mmu_context.h>
  36. #include <asm/time.h>
  37. #include "iSeries_setup.h"
  38. #include <asm/naca.h>
  39. #include <asm/paca.h>
  40. #include <asm/iSeries/LparData.h>
  41. #include <asm/iSeries/HvCallHpt.h>
  42. #include <asm/iSeries/HvLpConfig.h>
  43. #include <asm/iSeries/HvCallEvent.h>
  44. #include <asm/iSeries/HvCallSm.h>
  45. #include <asm/iSeries/HvCallXm.h>
  46. #include <asm/iSeries/ItLpQueue.h>
  47. #include <asm/iSeries/IoHriMainStore.h>
  48. #include <asm/iSeries/iSeries_proc.h>
  49. #include <asm/proc_pmc.h>
  50. #include <asm/perfmon.h>
  51. #include <asm/iSeries/mf.h>
  52. /* Function Prototypes */
  53. extern void abort(void);
  54. #ifdef CONFIG_PPC_ISERIES
  55. static void build_iSeries_Memory_Map( void );
  56. static void setup_iSeries_cache_sizes( void );
  57. static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr);
  58. #endif
  59. extern void ppcdbg_initialize(void);
  60. extern void iSeries_pcibios_init(void);
  61. extern void iSeries_pcibios_fixup(void);
  62. extern void iSeries_pcibios_fixup_bus(int);
  63. /* Global Variables */
  64. static unsigned long procFreqHz = 0;
  65. static unsigned long procFreqMhz = 0;
  66. static unsigned long procFreqMhzHundreths = 0;
  67. static unsigned long tbFreqHz = 0;
  68. static unsigned long tbFreqMhz = 0;
  69. static unsigned long tbFreqMhzHundreths = 0;
  70. int piranha_simulator = 0;
  71. extern char _end[];
  72. extern int rd_size; /* Defined in drivers/block/rd.c */
  73. extern unsigned long klimit;
  74. extern unsigned long embedded_sysmap_start;
  75. extern unsigned long embedded_sysmap_end;
  76. extern unsigned long iSeries_recal_tb;
  77. extern unsigned long iSeries_recal_titan;
  78. extern char _stext;
  79. extern char _etext;
  80. static int mf_initialized = 0;
  81. struct MemoryBlock {
  82. unsigned long absStart;
  83. unsigned long absEnd;
  84. unsigned long logicalStart;
  85. unsigned long logicalEnd;
  86. };
  87. /*
  88.  * Process the main store vpd to determine where the holes in memory are
  89.  * and return the number of physical blocks and fill in the array of
  90.  * block data.
  91.  */
  92. unsigned long iSeries_process_Condor_mainstore_vpd( struct MemoryBlock *mb_array, unsigned long max_entries )
  93. {
  94. /* Determine if absolute memory has any
  95.  * holes so that we can interpret the
  96.  * access map we get back from the hypervisor
  97.  * correctly.
  98.  */
  99. unsigned long holeFirstChunk, holeSizeChunks;
  100. unsigned long numMemoryBlocks = 1;
  101. struct IoHriMainStoreSegment4 * msVpd = (struct IoHriMainStoreSegment4 *)xMsVpd;
  102. unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr;
  103. unsigned long holeEnd   = msVpd->nonInterleavedBlocksEndAdr;
  104. unsigned long holeSize = holeEnd - holeStart;
  105. printk("Mainstore_VPD: Condorn");
  106. mb_array[0].logicalStart = 0;
  107. mb_array[0].logicalEnd   = 0x100000000;
  108. mb_array[0].absStart     = 0;
  109. mb_array[0].absEnd       = 0x100000000;
  110. if ( holeSize ) {
  111. numMemoryBlocks = 2;
  112. holeStart = holeStart & 0x000fffffffffffff;
  113. holeStart = addr_to_chunk(holeStart);
  114. holeFirstChunk = holeStart;
  115. holeSize = addr_to_chunk(holeSize);
  116. holeSizeChunks = holeSize;
  117. printk( "Main store hole: start chunk = %0lx, size = %0lx chunksn",
  118. holeFirstChunk, holeSizeChunks );
  119. mb_array[0].logicalEnd   = holeFirstChunk;
  120. mb_array[0].absEnd       = holeFirstChunk;
  121. mb_array[1].logicalStart = holeFirstChunk;
  122. mb_array[1].logicalEnd   = 0x100000000 - holeSizeChunks;
  123. mb_array[1].absStart     = holeFirstChunk + holeSizeChunks;
  124. mb_array[1].absEnd       = 0x100000000;
  125. }
  126. return numMemoryBlocks;
  127. }
  128. #define MaxSegmentAreas 32
  129. #define MaxSegmentAdrRangeBlocks 128
  130. #define MaxAreaRangeBlocks 4
  131. unsigned long iSeries_process_Regatta_mainstore_vpd( struct MemoryBlock *mb_array, unsigned long max_entries )
  132. {
  133. struct IoHriMainStoreSegment5 * msVpdP = (struct IoHriMainStoreSegment5 *)xMsVpd;
  134. unsigned long numSegmentBlocks = 0;
  135. u32 existsBits = msVpdP->msAreaExists;
  136. unsigned long area_num;
  137. printk("Mainstore_VPD: Regattan");
  138. for ( area_num = 0; area_num < MaxSegmentAreas; ++area_num ) {
  139. unsigned long numAreaBlocks;
  140. struct IoHriMainStoreArea4 * currentArea;
  141. if ( existsBits & 0x80000000 ) {
  142. unsigned long block_num;
  143. currentArea = &msVpdP->msAreaArray[area_num];
  144. numAreaBlocks = currentArea->numAdrRangeBlocks;
  145. printk("ms_vpd: processing area %2ld  blocks=%ld", area_num, numAreaBlocks);
  146. for ( block_num = 0; block_num < numAreaBlocks; ++block_num ) {
  147. /* Process an address range block */
  148. struct MemoryBlock tempBlock;
  149. unsigned long i;
  150. tempBlock.absStart = (unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart;
  151. tempBlock.absEnd   = (unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd;
  152. tempBlock.logicalStart = 0;
  153. tempBlock.logicalEnd   = 0;
  154. printk("n          block %ld absStart=%016lx absEnd=%016lx", block_num,
  155. tempBlock.absStart, tempBlock.absEnd);
  156. for ( i=0; i<numSegmentBlocks; ++i ) {
  157. if ( mb_array[i].absStart == tempBlock.absStart )
  158. break;
  159. }
  160. if ( i == numSegmentBlocks ) {
  161. if ( numSegmentBlocks == max_entries ) {
  162. panic("iSeries_process_mainstore_vpd: too many memory blocks");
  163. }
  164. mb_array[numSegmentBlocks] = tempBlock;
  165. ++numSegmentBlocks;
  166. }
  167. else {
  168. printk(" (duplicate)");
  169. }
  170. }
  171. printk("n");
  172. }
  173. existsBits <<= 1;
  174. }
  175. /* Now sort the blocks found into ascending sequence */
  176. if ( numSegmentBlocks > 1 ) {
  177. unsigned long m, n;
  178. for ( m=0; m<numSegmentBlocks-1; ++m ) {
  179. for ( n=numSegmentBlocks-1; m<n; --n ) {
  180. if ( mb_array[n].absStart < mb_array[n-1].absStart ) {
  181. struct MemoryBlock tempBlock;
  182. tempBlock = mb_array[n];
  183. mb_array[n] = mb_array[n-1];
  184. mb_array[n-1] = tempBlock;
  185. }
  186. }
  187. }
  188. }
  189. /* Assign "logical" addresses to each block.  These
  190.  * addresses correspond to the hypervisor "bitmap" space.
  191.  * Convert all addresses into units of 256K chunks.
  192.  */
  193. {
  194. unsigned long i, nextBitmapAddress;
  195. printk("ms_vpd: %ld sorted memory blocksn", numSegmentBlocks);
  196. nextBitmapAddress = 0;
  197. for ( i=0; i<numSegmentBlocks; ++i ) {
  198. unsigned long length = mb_array[i].absEnd - mb_array[i].absStart;
  199. mb_array[i].logicalStart = nextBitmapAddress;
  200. mb_array[i].logicalEnd = nextBitmapAddress + length;
  201. nextBitmapAddress += length;
  202. printk("          Bitmap range: %016lx - %016lxn"
  203.        "        Absolute range: %016lx - %016lxn",
  204. mb_array[i].logicalStart, mb_array[i].logicalEnd, 
  205. mb_array[i].absStart, mb_array[i].absEnd);
  206. mb_array[i].absStart     = addr_to_chunk( mb_array[i].absStart & 0x000fffffffffffff );
  207. mb_array[i].absEnd       = addr_to_chunk( mb_array[i].absEnd & 0x000fffffffffffff );
  208. mb_array[i].logicalStart = addr_to_chunk( mb_array[i].logicalStart );
  209. mb_array[i].logicalEnd   = addr_to_chunk( mb_array[i].logicalEnd );
  210. }
  211. }
  212. return numSegmentBlocks;
  213. }
  214. unsigned long iSeries_process_mainstore_vpd( struct MemoryBlock *mb_array, unsigned long max_entries )
  215. {
  216. unsigned long i;
  217. unsigned long mem_blocks = 0;
  218. if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
  219. mem_blocks = iSeries_process_Regatta_mainstore_vpd( mb_array, max_entries );
  220. else
  221. mem_blocks = iSeries_process_Condor_mainstore_vpd( mb_array, max_entries );
  222. printk("Mainstore_VPD: numMemoryBlocks = %ld n", mem_blocks);
  223. for ( i=0; i<mem_blocks; ++i ) {
  224. printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lxn"
  225.        "                             abs chunks %016lx - %016lxn",
  226. i, mb_array[i].logicalStart, mb_array[i].logicalEnd,
  227. mb_array[i].absStart, mb_array[i].absEnd);
  228. }
  229. return mem_blocks;
  230. }
  231. /*
  232.  * void __init iSeries_init_early()
  233.  */
  234. void __init
  235. iSeries_init_early(void)
  236. {
  237. #ifdef CONFIG_PPC_ISERIES
  238. #if defined(CONFIG_BLK_DEV_INITRD)
  239. /*
  240.  * If the init RAM disk has been configured and there is
  241.  * a non-zero starting address for it, set it up
  242.  */
  243. if ( naca->xRamDisk ) {
  244. initrd_start = (unsigned long)__va(naca->xRamDisk);
  245. initrd_end   = initrd_start + naca->xRamDiskSize * PAGE_SIZE;
  246. initrd_below_start_ok = 1; // ramdisk in kernel space
  247. ROOT_DEV = MKDEV( RAMDISK_MAJOR, 0 );
  248. if ( ((rd_size*1024)/PAGE_SIZE) < naca->xRamDiskSize )
  249. rd_size = (naca->xRamDiskSize*PAGE_SIZE)/1024;
  250. } else
  251. #endif /* CONFIG_BLK_DEV_INITRD */
  252.   {
  253.                 
  254.     /* ROOT_DEV = MKDEV( VIODASD_MAJOR, 1 ); */
  255.   }
  256. iSeries_recal_tb = get_tb();
  257. iSeries_recal_titan = HvCallXm_loadTod();
  258. ppc_md.setup_arch   = iSeries_setup_arch;
  259. ppc_md.setup_residual   = iSeries_setup_residual;
  260. ppc_md.get_cpuinfo   = iSeries_get_cpuinfo;
  261. ppc_md.irq_cannonicalize  = NULL;
  262. ppc_md.init_IRQ   = iSeries_init_IRQ;
  263. ppc_md.init_ras_IRQ = NULL;
  264. ppc_md.get_irq   = iSeries_get_irq;
  265. ppc_md.init   = NULL;
  266.   ppc_md.pcibios_fixup        = iSeries_pcibios_fixup;
  267. ppc_md.pcibios_fixup_bus    = iSeries_pcibios_fixup_bus;
  268. ppc_md.restart   = iSeries_restart;
  269. ppc_md.power_off   = iSeries_power_off;
  270. ppc_md.halt   = iSeries_halt;
  271. ppc_md.time_init   = NULL;
  272. ppc_md.get_boot_time    = iSeries_get_boot_time;
  273. ppc_md.set_rtc_time   = iSeries_set_rtc_time;
  274. ppc_md.get_rtc_time   = iSeries_get_rtc_time;
  275. ppc_md.calibrate_decr   = iSeries_calibrate_decr;
  276. ppc_md.progress = iSeries_progress;
  277. ppc_md.kbd_setkeycode     = NULL;
  278. ppc_md.kbd_getkeycode     = NULL;
  279. ppc_md.kbd_translate      = NULL;
  280. ppc_md.kbd_unexpected_up  = NULL;
  281. ppc_md.kbd_leds           = NULL;
  282. ppc_md.kbd_init_hw        = NULL;
  283. #if defined(CONFIG_MAGIC_SYSRQ)
  284. ppc_md.ppc_kbd_sysrq_xlate = NULL;
  285. #endif
  286. hpte_init_iSeries();
  287. tce_init_iSeries();
  288. /* Initialize the table which translate Linux physical addresses to
  289.  * AS/400 absolute addresses
  290.  */
  291. build_iSeries_Memory_Map();
  292. setup_iSeries_cache_sizes();
  293. /* Initialize machine-dependency vectors */
  294. #ifdef CONFIG_SMP
  295. smp_init_iSeries();
  296. #endif
  297. if ( itLpNaca.xPirEnvironMode == 0 ) 
  298. piranha_simulator = 1;
  299. #endif
  300. }
  301. /*
  302.  * void __init iSeries_init()
  303.  */
  304. void __init
  305. iSeries_init(unsigned long r3, unsigned long r4, unsigned long r5, 
  306.    unsigned long r6, unsigned long r7)
  307. {
  308. /* Associate Lp Event Queue 0 with processor 0 */
  309. HvCallEvent_setLpEventQueueInterruptProc( 0, 0 );
  310. {
  311. /* copy the command line parameter from the primary VSP  */
  312. char *p, *q;
  313. HvCallEvent_dmaToSp( cmd_line,
  314.      2*64*1024,
  315.      256,
  316.      HvLpDma_Direction_RemoteToLocal );
  317. p = q = cmd_line + 255;
  318. while( p > cmd_line ) {
  319. if ((*p == 0) || (*p == ' ') || (*p == 'n'))
  320. --p;
  321. else
  322. break;
  323. }
  324. if ( p < q )
  325. *(p+1) = 0;
  326. }
  327. iSeries_proc_early_init();
  328. mf_init();
  329. mf_initialized = 1;
  330. mb();
  331. iSeries_proc_callback( &pmc_proc_init );
  332. }
  333. #ifdef CONFIG_PPC_ISERIES
  334. /*
  335.  * The iSeries may have very large memories ( > 128 GB ) and a partition
  336.  * may get memory in "chunks" that may be anywhere in the 2**52 real
  337.  * address space.  The chunks are 256K in size.  To map this to the 
  338.  * memory model Linux expects, the AS/400 specific code builds a 
  339.  * translation table to translate what Linux thinks are "physical"
  340.  * addresses to the actual real addresses.  This allows us to make 
  341.  * it appear to Linux that we have contiguous memory starting at
  342.  * physical address zero while in fact this could be far from the truth.
  343.  * To avoid confusion, I'll let the words physical and/or real address 
  344.  * apply to the Linux addresses while I'll use "absolute address" to 
  345.  * refer to the actual hardware real address.
  346.  *
  347.  * build_iSeries_Memory_Map gets information from the Hypervisor and 
  348.  * looks at the Main Store VPD to determine the absolute addresses
  349.  * of the memory that has been assigned to our partition and builds
  350.  * a table used to translate Linux's physical addresses to these
  351.  * absolute addresses.  Absolute addresses are needed when 
  352.  * communicating with the hypervisor (e.g. to build HPT entries)
  353.  */
  354. static void __init build_iSeries_Memory_Map(void)
  355. {
  356. u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize;
  357. u32 nextPhysChunk;
  358. u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages;
  359. u32 num_ptegs;
  360. u32 totalChunks,moreChunks;
  361. u32 currChunk, thisChunk, absChunk;
  362. u32 currDword;
  363. u32 chunkBit;
  364. u64 map;
  365. struct MemoryBlock mb[32];
  366. unsigned long numMemoryBlocks, curBlock;
  367. /* Chunk size on iSeries is 256K bytes */
  368. totalChunks = (u32)HvLpConfig_getMsChunks();
  369. klimit = msChunks_alloc(klimit, totalChunks, 1UL<<18);
  370. /* Get absolute address of our load area
  371.  * and map it to physical address 0
  372.  * This guarantees that the loadarea ends up at physical 0
  373.  * otherwise, it might not be returned by PLIC as the first
  374.  * chunks
  375.  */
  376. loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr);
  377. loadAreaSize =  itLpNaca.xLoadAreaChunks;
  378. /* Only add the pages already mapped here.  
  379.  * Otherwise we might add the hpt pages 
  380.  * The rest of the pages of the load area
  381.  * aren't in the HPT yet and can still
  382.  * be assigned an arbitrary physical address
  383.  */
  384. if ( (loadAreaSize * 64) > HvPagesToMap )
  385. loadAreaSize = HvPagesToMap / 64;
  386. loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1;
  387. /* TODO Do we need to do something if the HPT is in the 64MB load area?
  388.  * This would be required if the itLpNaca.xLoadAreaChunks includes 
  389.  * the HPT size
  390.  */
  391. printk( "Mapping load area - physical addr = 0000000000000000n"
  392.                 "                    absolute addr = %016lxn", 
  393. chunk_to_addr(loadAreaFirstChunk) );
  394. printk( "Load area size %dKn", loadAreaSize*256 );
  395. for ( nextPhysChunk = 0; 
  396. nextPhysChunk < loadAreaSize; 
  397. ++nextPhysChunk ) {
  398. msChunks.abs[nextPhysChunk] = loadAreaFirstChunk+nextPhysChunk;
  399. }
  400. /* Get absolute address of our HPT and remember it so
  401.  * we won't map it to any physical address
  402.  */
  403. hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());
  404. hptSizePages =  (u32)(HvCallHpt_getHptPages());
  405. hptSizeChunks = hptSizePages >> (msChunks.chunk_shift-PAGE_SHIFT);
  406. hptLastChunk = hptFirstChunk + hptSizeChunks - 1;
  407. printk( "HPT absolute addr = %016lx, size = %dKn",
  408. chunk_to_addr(hptFirstChunk), hptSizeChunks*256 );
  409. /* Fill in the htab_data structure */
  410. /* Fill in size of hashed page table */
  411. num_ptegs = hptSizePages * (PAGE_SIZE/(sizeof(HPTE)*HPTES_PER_GROUP));
  412. htab_data.htab_num_ptegs = num_ptegs;
  413. htab_data.htab_hash_mask = num_ptegs - 1;
  414. /* The actual hashed page table is in the hypervisor, we have no direct access */
  415. htab_data.htab = NULL;
  416. /* Determine if absolute memory has any
  417.  * holes so that we can interpret the
  418.  * access map we get back from the hypervisor
  419.  * correctly.
  420.  */
  421. numMemoryBlocks = iSeries_process_mainstore_vpd( mb, 32 );
  422. /* Process the main store access map from the hypervisor
  423.  * to build up our physical -> absolute translation table
  424.  */
  425. curBlock = 0;
  426. currChunk = 0;
  427. currDword = 0;
  428. moreChunks = totalChunks;
  429. while ( moreChunks ) {
  430. map = HvCallSm_get64BitsOfAccessMap( itLpNaca.xLpIndex,
  431.      currDword );
  432. thisChunk = currChunk;
  433. while ( map ) {
  434. chunkBit = map >> 63;
  435. map <<= 1;
  436. if ( chunkBit ) {
  437. --moreChunks;
  438. while ( thisChunk >= mb[curBlock].logicalEnd ) {
  439. ++curBlock;
  440. if ( curBlock >= numMemoryBlocks )
  441. panic("out of memory blocks");
  442. }
  443. if ( thisChunk < mb[curBlock].logicalStart )
  444. panic("memory block error");
  445. absChunk = mb[curBlock].absStart + ( thisChunk - mb[curBlock].logicalStart );
  446. if ( ( ( absChunk < hptFirstChunk ) ||
  447.        ( absChunk > hptLastChunk ) ) &&
  448.      ( ( absChunk < loadAreaFirstChunk ) ||
  449.        ( absChunk > loadAreaLastChunk ) ) ) {
  450. msChunks.abs[nextPhysChunk] = absChunk;
  451. ++nextPhysChunk;
  452. }
  453. }
  454. ++thisChunk;
  455. }
  456. ++currDword;
  457. currChunk += 64;
  458. }
  459. /* main store size (in chunks) is 
  460.  *   totalChunks - hptSizeChunks
  461.  * which should be equal to 
  462.  *   nextPhysChunk
  463.  */
  464. naca->physicalMemorySize = chunk_to_addr(nextPhysChunk);
  465. /* Bolt kernel mappings for all of memory */
  466. iSeries_bolt_kernel( 0, naca->physicalMemorySize );
  467. lmb_init();
  468. lmb_add( 0, naca->physicalMemorySize );
  469. lmb_analyze(); /* ?? */
  470. lmb_reserve( 0, __pa(klimit));
  471. /* 
  472.  * Hardcode to GP size.  I am not sure where to get this info. DRENG
  473.  */
  474. naca->slb_size = 64;
  475. }
  476. /*
  477.  * Set up the variables that describe the cache line sizes
  478.  * for this machine.
  479.  */
  480. static void __init setup_iSeries_cache_sizes(void)
  481. {
  482. unsigned i,n;
  483. unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
  484. naca->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
  485. naca->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
  486. naca->iCacheL1LinesPerPage = PAGE_SIZE / naca->iCacheL1LineSize;
  487. naca->dCacheL1LinesPerPage = PAGE_SIZE / naca->dCacheL1LineSize;
  488. i = naca->iCacheL1LineSize;
  489. n = 0;
  490. while ((i=(i/2))) ++n;
  491. naca->iCacheL1LogLineSize = n;
  492. i = naca->dCacheL1LineSize;
  493. n = 0;
  494. while ((i=(i/2))) ++n;
  495. naca->dCacheL1LogLineSize = n;
  496. printk( "D-cache line size = %d  (log = %d)n",
  497. (unsigned)naca->dCacheL1LineSize,
  498. (unsigned)naca->dCacheL1LogLineSize );
  499. printk( "I-cache line size = %d  (log = %d)n",
  500. (unsigned)naca->iCacheL1LineSize,
  501. (unsigned)naca->iCacheL1LogLineSize );
  502. }
  503. /*
  504.  * Bolt the kernel addr space into the HPT
  505.  */
  506. static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr)
  507. {
  508. unsigned long pa;
  509. unsigned long mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
  510. HPTE hpte;
  511. for (pa=saddr; pa < eaddr ;pa+=PAGE_SIZE) {
  512. unsigned long ea = (unsigned long)__va(pa);
  513. unsigned long vsid = get_kernel_vsid( ea );
  514. unsigned long va = ( vsid << 28 ) | ( pa & 0xfffffff );
  515. unsigned long vpn = va >> PAGE_SHIFT;
  516. unsigned long slot = HvCallHpt_findValid( &hpte, vpn );
  517. if (hpte.dw0.dw0.v) {
  518. /* HPTE exists, so just bolt it */
  519. HvCallHpt_setSwBits(slot, 0x10, 0);
  520. } else {
  521. /* No HPTE exists, so create a new bolted one */
  522. make_pte(NULL, va, (unsigned long)__v2a(ea), 
  523.  mode_rw, 0, 0);
  524. }
  525. }
  526. }
  527. #endif /* CONFIG_PPC_ISERIES */
  528. extern unsigned long ppc_proc_freq;
  529. extern unsigned long ppc_tb_freq;
  530. /*
  531.  * Document me.
  532.  */
  533. void __init
  534. iSeries_setup_arch(void)
  535. {
  536. void * eventStack;
  537. unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
  538. /* Setup the Lp Event Queue */
  539. /* Allocate a page for the Event Stack
  540.  * The hypervisor wants the absolute real address, so
  541.  * we subtract out the KERNELBASE and add in the
  542.  * absolute real address of the kernel load area
  543.  */
  544. eventStack = alloc_bootmem_pages( LpEventStackSize );
  545. memset( eventStack, 0, LpEventStackSize );
  546. /* Invoke the hypervisor to initialize the event stack */
  547. HvCallEvent_setLpEventStack( 0, eventStack, LpEventStackSize );
  548. /* Initialize fields in our Lp Event Queue */
  549. xItLpQueue.xSlicEventStackPtr = (char *)eventStack;
  550. xItLpQueue.xSlicCurEventPtr = (char *)eventStack;
  551. xItLpQueue.xSlicLastValidEventPtr = (char *)eventStack + 
  552. (LpEventStackSize - LpEventMaxSize);
  553. xItLpQueue.xIndex = 0;
  554. /* Compute processor frequency */
  555. procFreqHz = (((1UL<<34) * 1000000) / xIoHriProcessorVpd[procIx].xProcFreq );
  556. procFreqMhz = procFreqHz / 1000000;
  557. procFreqMhzHundreths = (procFreqHz/10000) - (procFreqMhz*100);
  558. ppc_proc_freq = procFreqHz;
  559. /* Compute time base frequency */
  560. tbFreqHz = (((1UL<<32) * 1000000) / xIoHriProcessorVpd[procIx].xTimeBaseFreq );
  561. tbFreqMhz = tbFreqHz / 1000000;
  562. tbFreqMhzHundreths = (tbFreqHz/10000) - (tbFreqMhz*100);
  563. ppc_tb_freq = tbFreqHz;
  564. printk("Max  logical processors = %dn", 
  565. itVpdAreas.xSlicMaxLogicalProcs );
  566. printk("Max physical processors = %dn",
  567. itVpdAreas.xSlicMaxPhysicalProcs );
  568. printk("Processor frequency = %lu.%02lun",
  569. procFreqMhz, 
  570. procFreqMhzHundreths );
  571. printk("Time base frequency = %lu.%02lun",
  572. tbFreqMhz,
  573. tbFreqMhzHundreths );
  574. printk("Processor version = %xn",
  575. xIoHriProcessorVpd[procIx].xPVR );
  576. }
  577. /*
  578.  * int as400_setup_residual()
  579.  *
  580.  * Description:
  581.  *   This routine pretty-prints CPU information gathered from the VPD    
  582.  *   for use in /proc/cpuinfo                               
  583.  *
  584.  * Input(s):
  585.  *  *buffer - Buffer into which CPU data is to be printed.             
  586.  *
  587.  * Output(s):
  588.  *  *buffer - Buffer with CPU data.
  589.  *
  590.  * Returns:
  591.  *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
  592.  *   on error.
  593.  */
  594. void iSeries_setup_residual(struct seq_file *m)
  595. {
  596. seq_printf(m,"clocktt: %lu.%02luMhzn",
  597. procFreqMhz, procFreqMhzHundreths );
  598. seq_printf(m,"time baset: %lu.%02luMHzn",
  599. tbFreqMhz, tbFreqMhzHundreths );
  600. seq_printf(m,"i-cachett: %dn",
  601. naca->iCacheL1LineSize);
  602. seq_printf(m,"d-cachett: %dn",
  603. naca->dCacheL1LineSize);
  604. }
  605. void iSeries_get_cpuinfo(struct seq_file *m)
  606. {
  607. seq_printf(m,"machinett: 64-bit iSeries Logical Partitionn");
  608. }
  609. /*
  610.  * Document me.
  611.  * and Implement me.
  612.  */
  613. int
  614. iSeries_get_irq(struct pt_regs *regs)
  615. {
  616. /* -2 means ignore this interrupt */
  617. return -2;
  618. }
  619. /*
  620.  * Document me.
  621.  */
  622. void
  623. iSeries_restart(char *cmd)
  624. {
  625. mf_reboot();
  626. }
  627. /*
  628.  * Document me.
  629.  */
  630. void
  631. iSeries_power_off(void)
  632. {
  633. mf_powerOff();
  634. }
  635. /*
  636.  * Document me.
  637.  */
  638. void
  639. iSeries_halt(void)
  640. {
  641. mf_powerOff();
  642. }
  643. /*
  644.  * Nothing to do here.
  645.  */
  646. void __init
  647. iSeries_time_init(void)
  648. {
  649. /* Nothing to do */
  650. }
  651. /* JDH Hack */
  652. unsigned long jdh_time = 0;
  653. extern void setup_default_decr(void);
  654. /*
  655.  * void __init iSeries_calibrate_decr()
  656.  *
  657.  * Description:
  658.  *   This routine retrieves the internal processor frequency from the VPD,
  659.  *   and sets up the kernel timer decrementer based on that value.
  660.  *
  661.  */
  662. void __init
  663. iSeries_calibrate_decr(void)
  664. {
  665. unsigned long cyclesPerUsec;
  666. struct div_result divres;
  667. /* Compute decrementer (and TB) frequency 
  668.  * in cycles/sec 
  669.  */
  670. cyclesPerUsec = ppc_tb_freq / 1000000; /* cycles / usec */
  671. /* Set the amount to refresh the decrementer by.  This
  672.  * is the number of decrementer ticks it takes for 
  673.  * 1/HZ seconds.
  674.  */
  675. tb_ticks_per_jiffy = ppc_tb_freq / HZ;
  676. #if 0
  677. /* TEST CODE FOR ADJTIME */
  678. tb_ticks_per_jiffy += tb_ticks_per_jiffy / 5000;
  679. /* END OF TEST CODE */
  680. #endif
  681. /*
  682.  * tb_ticks_per_sec = freq; would give better accuracy
  683.  * but tb_ticks_per_sec = tb_ticks_per_jiffy*HZ; assures
  684.  * that jiffies (and xtime) will match the time returned
  685.  * by do_gettimeofday.
  686.  */
  687. tb_ticks_per_sec   = tb_ticks_per_jiffy * HZ;
  688. tb_ticks_per_usec = cyclesPerUsec;
  689. div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
  690. tb_to_xs = divres.result_low;
  691. setup_default_decr();
  692. }
  693. void __init
  694. iSeries_progress( char * st, unsigned short code )
  695. {
  696. printk( "Progress: [%04x] - %sn", (unsigned)code, st );
  697. if ( !piranha_simulator && mf_initialized ) {
  698.     if (code != 0xffff)
  699. mf_displayProgress( code );
  700.     else
  701. mf_clearSrc();
  702. }
  703. }
  704. void iSeries_fixup_klimit(void)
  705. {
  706. /* Change klimit to take into account any ram disk that may be included */
  707. if (naca->xRamDisk)
  708. klimit = KERNELBASE + (u64)naca->xRamDisk + (naca->xRamDiskSize * PAGE_SIZE);
  709. else {
  710. /* No ram disk was included - check and see if there was an embedded system map */
  711. /* Change klimit to take into account any embedded system map */
  712. if (embedded_sysmap_end)
  713. klimit = KERNELBASE + ((embedded_sysmap_end+4095) & 0xfffffffffffff000);
  714. }
  715. }