📄 setup.c
字号:
*/static unsigned long __init build_iSeries_Memory_Map(void){ u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize; u32 nextPhysChunk; u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages; u32 totalChunks,moreChunks; u32 currChunk, thisChunk, absChunk; u32 currDword; u32 chunkBit; u64 map; struct MemoryBlock mb[32]; unsigned long numMemoryBlocks, curBlock; /* Chunk size on iSeries is 256K bytes */ totalChunks = (u32)HvLpConfig_getMsChunks(); mschunks_alloc(totalChunks); /* * 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)addr_to_chunk(itLpNaca.xLoadAreaAddr); loadAreaSize = itLpNaca.xLoadAreaChunks; /* * Only add the pages already mapped here. * Otherwise we might add the hpt pages * The rest of the pages of the load area * aren't in the HPT yet and can still * be assigned an arbitrary physical address */ if ((loadAreaSize * 64) > HvPagesToMap) loadAreaSize = HvPagesToMap / 64; loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1; /* * TODO Do we need to do something if the HPT is in the 64MB load area? * This would be required if the itLpNaca.xLoadAreaChunks includes * the HPT size */ printk("Mapping load area - physical addr = 0000000000000000\n" " absolute addr = %016lx\n", chunk_to_addr(loadAreaFirstChunk)); printk("Load area size %dK\n", loadAreaSize * 256); for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk) mschunks_map.mapping[nextPhysChunk] = loadAreaFirstChunk + nextPhysChunk; /* * Get absolute address of our HPT and remember it so * we won't map it to any physical address */ hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress()); hptSizePages = (u32)HvCallHpt_getHptPages(); hptSizeChunks = hptSizePages >> (MSCHUNKS_CHUNK_SHIFT - HW_PAGE_SHIFT); hptLastChunk = hptFirstChunk + hptSizeChunks - 1; printk("HPT absolute addr = %016lx, size = %dK\n", chunk_to_addr(hptFirstChunk), hptSizeChunks * 256); /* * Determine if absolute memory has any * holes so that we can interpret the * access map we get back from the hypervisor * correctly. */ numMemoryBlocks = iSeries_process_mainstore_vpd(mb, 32); /* * Process the main store access map from the hypervisor * to build up our physical -> absolute translation table */ curBlock = 0; 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; while (thisChunk >= mb[curBlock].logicalEnd) { ++curBlock; if (curBlock >= numMemoryBlocks) panic("out of memory blocks"); } if (thisChunk < mb[curBlock].logicalStart) panic("memory block error"); absChunk = mb[curBlock].absStart + (thisChunk - mb[curBlock].logicalStart); if (((absChunk < hptFirstChunk) || (absChunk > hptLastChunk)) && ((absChunk < loadAreaFirstChunk) || (absChunk > loadAreaLastChunk))) { mschunks_map.mapping[nextPhysChunk] = absChunk; ++nextPhysChunk; } } ++thisChunk; } ++currDword; currChunk += 64; } /* * main store size (in chunks) is * totalChunks - hptSizeChunks * which should be equal to * nextPhysChunk */ return chunk_to_addr(nextPhysChunk);}/* * Document me. */static void __init iSeries_setup_arch(void){ if (get_lppaca()->shared_proc) { ppc_md.idle_loop = iseries_shared_idle; printk(KERN_DEBUG "Using shared processor idle loop\n"); } else { ppc_md.idle_loop = iseries_dedicated_idle; printk(KERN_DEBUG "Using dedicated idle loop\n"); } /* Setup the Lp Event Queue */ setup_hvlpevent_queue(); printk("Max logical processors = %d\n", itVpdAreas.xSlicMaxLogicalProcs); printk("Max physical processors = %d\n", itVpdAreas.xSlicMaxPhysicalProcs);}static void iSeries_show_cpuinfo(struct seq_file *m){ seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n");}static void __init iSeries_progress(char * st, unsigned short code){ printk("Progress: [%04x] - %s\n", (unsigned)code, st); mf_display_progress(code);}static void __init iSeries_fixup_klimit(void){ /* * Change klimit to take into account any ram disk * that may be included */ if (naca.xRamDisk) klimit = KERNELBASE + (u64)naca.xRamDisk + (naca.xRamDiskSize * HW_PAGE_SIZE);}static int __init iSeries_src_init(void){ /* clear the progress line */ if (firmware_has_feature(FW_FEATURE_ISERIES)) ppc_md.progress(" ", 0xffff); return 0;}late_initcall(iSeries_src_init);static inline void process_iSeries_events(void){ asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");}static void yield_shared_processor(void){ unsigned long tb; HvCall_setEnabledInterrupts(HvCall_MaskIPI | HvCall_MaskLpEvent | HvCall_MaskLpProd | HvCall_MaskTimeout); tb = get_tb(); /* Compute future tb value when yield should expire */ HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy); /* * The decrementer stops during the yield. Force a fake decrementer * here and let the timer_interrupt code sort out the actual time. */ get_lppaca()->int_dword.fields.decr_int = 1; ppc64_runlatch_on(); process_iSeries_events();}static void iseries_shared_idle(void){ while (1) { tick_nohz_stop_sched_tick(); while (!need_resched() && !hvlpevent_is_pending()) { local_irq_disable(); ppc64_runlatch_off(); /* Recheck with irqs off */ if (!need_resched() && !hvlpevent_is_pending()) yield_shared_processor(); HMT_medium(); local_irq_enable(); } ppc64_runlatch_on(); tick_nohz_restart_sched_tick(); if (hvlpevent_is_pending()) process_iSeries_events(); preempt_enable_no_resched(); schedule(); preempt_disable(); }}static void iseries_dedicated_idle(void){ set_thread_flag(TIF_POLLING_NRFLAG); while (1) { tick_nohz_stop_sched_tick(); if (!need_resched()) { while (!need_resched()) { ppc64_runlatch_off(); HMT_low(); if (hvlpevent_is_pending()) { HMT_medium(); ppc64_runlatch_on(); process_iSeries_events(); } } HMT_medium(); } ppc64_runlatch_on(); tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); preempt_disable(); }}static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size, unsigned long flags){ return (void __iomem *)address;}static void iseries_iounmap(volatile void __iomem *token){}static int __init iseries_probe(void){ unsigned long root = of_get_flat_dt_root(); if (!of_flat_dt_is_compatible(root, "IBM,iSeries")) return 0; hpte_init_iSeries(); /* iSeries does not support 16M pages */ cur_cpu_spec->cpu_features &= ~CPU_FTR_16M_PAGE; return 1;}define_machine(iseries) { .name = "iSeries", .setup_arch = iSeries_setup_arch, .show_cpuinfo = iSeries_show_cpuinfo, .init_IRQ = iSeries_init_IRQ, .get_irq = iSeries_get_irq, .init_early = iSeries_init_early, .pcibios_fixup = iSeries_pci_final_fixup, .restart = mf_reboot, .power_off = mf_power_off, .halt = mf_power_off, .get_boot_time = iSeries_get_boot_time, .set_rtc_time = iSeries_set_rtc_time, .get_rtc_time = iSeries_get_rtc_time, .calibrate_decr = generic_calibrate_decr, .progress = iSeries_progress, .probe = iseries_probe, .ioremap = iseries_ioremap, .iounmap = iseries_iounmap, /* XXX Implement enable_pmcs for iSeries */};void * __init iSeries_early_setup(void){ unsigned long phys_mem_size; /* Identify CPU type. This is done again by the common code later * on but calling this function multiple times is fine. */ identify_cpu(0, mfspr(SPRN_PVR)); powerpc_firmware_features |= FW_FEATURE_ISERIES; powerpc_firmware_features |= FW_FEATURE_LPAR; iSeries_fixup_klimit(); /* * Initialize the table which translate Linux physical addresses to * AS/400 absolute addresses */ phys_mem_size = build_iSeries_Memory_Map(); iSeries_get_cmdline(); return (void *) __pa(build_flat_dt(phys_mem_size));}static void hvputc(char c){ if (c == '\n') hvputc('\r'); HvCall_writeLogBuffer(&c, 1);}void __init udbg_init_iseries(void){ udbg_putc = hvputc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -