iseries_setup.c
来自「底层驱动开发」· C语言 代码 · 共 978 行 · 第 1/2 页
C
978 行
*/ 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 - PAGE_SHIFT); hptLastChunk = hptFirstChunk + hptSizeChunks - 1; printk("HPT absolute addr = %016lx, size = %dK\n", chunk_to_addr(hptFirstChunk), hptSizeChunks * 256); /* Fill in the hashed page table hash mask */ num_ptegs = hptSizePages * (PAGE_SIZE / (sizeof(hpte_t) * HPTES_PER_GROUP)); htab_hash_mask = num_ptegs - 1; /* * The actual hashed page table is in the hypervisor, * we have no direct access */ htab_address = NULL; /* * 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 */ systemcfg->physicalMemorySize = chunk_to_addr(nextPhysChunk);}/* * Set up the variables that describe the cache line sizes * for this machine. */static void __init setup_iSeries_cache_sizes(void){ unsigned int i, n; unsigned int procIx = get_paca()->lppaca.dyn_hv_phys_proc_index; systemcfg->icache_size = ppc64_caches.isize = xIoHriProcessorVpd[procIx].xInstCacheSize * 1024; systemcfg->icache_line_size = ppc64_caches.iline_size = xIoHriProcessorVpd[procIx].xInstCacheOperandSize; systemcfg->dcache_size = ppc64_caches.dsize = xIoHriProcessorVpd[procIx].xDataL1CacheSizeKB * 1024; systemcfg->dcache_line_size = ppc64_caches.dline_size = xIoHriProcessorVpd[procIx].xDataCacheOperandSize; ppc64_caches.ilines_per_page = PAGE_SIZE / ppc64_caches.iline_size; ppc64_caches.dlines_per_page = PAGE_SIZE / ppc64_caches.dline_size; i = ppc64_caches.iline_size; n = 0; while ((i = (i / 2))) ++n; ppc64_caches.log_iline_size = n; i = ppc64_caches.dline_size; n = 0; while ((i = (i / 2))) ++n; ppc64_caches.log_dline_size = n; printk("D-cache line size = %d\n", (unsigned int)ppc64_caches.dline_size); printk("I-cache line size = %d\n", (unsigned int)ppc64_caches.iline_size);}/* * Create a pte. Used during initialization only. */static void iSeries_make_pte(unsigned long va, unsigned long pa, int mode){ hpte_t local_hpte, rhpte; unsigned long hash, vpn; long slot; vpn = va >> PAGE_SHIFT; hash = hpt_hash(vpn, 0); local_hpte.r = pa | mode; local_hpte.v = ((va >> 23) << HPTE_V_AVPN_SHIFT) | HPTE_V_BOLTED | HPTE_V_VALID; slot = HvCallHpt_findValid(&rhpte, vpn); if (slot < 0) { /* Must find space in primary group */ panic("hash_page: hpte already exists\n"); } HvCallHpt_addValidate(slot, 0, &local_hpte);}/* * Bolt the kernel addr space into the HPT */static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr){ unsigned long pa; unsigned long mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; hpte_t hpte; for (pa = saddr; pa < eaddr ;pa += PAGE_SIZE) { unsigned long ea = (unsigned long)__va(pa); unsigned long vsid = get_kernel_vsid(ea); unsigned long va = (vsid << 28) | (pa & 0xfffffff); unsigned long vpn = va >> PAGE_SHIFT; unsigned long slot = HvCallHpt_findValid(&hpte, vpn); /* Make non-kernel text non-executable */ if (!in_kernel_text(ea)) mode_rw |= HW_NO_EXEC; if (hpte.v & HPTE_V_VALID) { /* HPTE exists, so just bolt it */ HvCallHpt_setSwBits(slot, 0x10, 0); /* And make sure the pp bits are correct */ HvCallHpt_setPp(slot, PP_RWXX); } else /* No HPTE exists, so create a new bolted one */ iSeries_make_pte(va, phys_to_abs(pa), mode_rw); }}/* * Document me. */static void __init iSeries_setup_arch(void){ unsigned procIx = get_paca()->lppaca.dyn_hv_phys_proc_index; /* Add an eye catcher and the systemcfg layout version number */ strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); systemcfg->version.major = SYSTEMCFG_MAJOR; systemcfg->version.minor = SYSTEMCFG_MINOR; /* Setup the Lp Event Queue */ setup_hvlpevent_queue(); /* Compute processor frequency */ procFreqHz = ((1UL << 34) * 1000000) / xIoHriProcessorVpd[procIx].xProcFreq; procFreqMhz = procFreqHz / 1000000; procFreqMhzHundreths = (procFreqHz / 10000) - (procFreqMhz * 100); ppc_proc_freq = procFreqHz; /* Compute time base frequency */ tbFreqHz = ((1UL << 32) * 1000000) / xIoHriProcessorVpd[procIx].xTimeBaseFreq; tbFreqMhz = tbFreqHz / 1000000; tbFreqMhzHundreths = (tbFreqHz / 10000) - (tbFreqMhz * 100); ppc_tb_freq = tbFreqHz; printk("Max logical processors = %d\n", itVpdAreas.xSlicMaxLogicalProcs); printk("Max physical processors = %d\n", itVpdAreas.xSlicMaxPhysicalProcs); printk("Processor frequency = %lu.%02lu\n", procFreqMhz, procFreqMhzHundreths); printk("Time base frequency = %lu.%02lu\n", tbFreqMhz, tbFreqMhzHundreths); systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR; printk("Processor version = %x\n", systemcfg->processor);}static void iSeries_get_cpuinfo(struct seq_file *m){ seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n");}/* * Document me. * and Implement me. */static int iSeries_get_irq(struct pt_regs *regs){ /* -2 means ignore this interrupt */ return -2;}/* * Document me. */static void iSeries_restart(char *cmd){ mf_reboot();}/* * Document me. */static void iSeries_power_off(void){ mf_power_off();}/* * Document me. */static void iSeries_halt(void){ mf_power_off();}/* * void __init iSeries_calibrate_decr() * * Description: * This routine retrieves the internal processor frequency from the VPD, * and sets up the kernel timer decrementer based on that value. * */static void __init iSeries_calibrate_decr(void){ unsigned long cyclesPerUsec; struct div_result divres; /* Compute decrementer (and TB) frequency in cycles/sec */ cyclesPerUsec = ppc_tb_freq / 1000000; /* * Set the amount to refresh the decrementer by. This * is the number of decrementer ticks it takes for * 1/HZ seconds. */ tb_ticks_per_jiffy = ppc_tb_freq / HZ;#if 0 /* TEST CODE FOR ADJTIME */ tb_ticks_per_jiffy += tb_ticks_per_jiffy / 5000; /* END OF TEST CODE */#endif /* * tb_ticks_per_sec = freq; would give better accuracy * but tb_ticks_per_sec = tb_ticks_per_jiffy*HZ; assures * that jiffies (and xtime) will match the time returned * by do_gettimeofday. */ tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; tb_ticks_per_usec = cyclesPerUsec; tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); div128_by_32(1024 * 1024, 0, tb_ticks_per_sec, &divres); tb_to_xs = divres.result_low; setup_default_decr();}static void __init iSeries_progress(char * st, unsigned short code){ printk("Progress: [%04x] - %s\n", (unsigned)code, st); if (!piranha_simulator && mf_initialized) { if (code != 0xffff) mf_display_progress(code); else mf_clear_src(); }}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 * PAGE_SIZE); else { /* * No ram disk was included - check and see if there * was an embedded system map. Change klimit to take * into account any embedded system map */ if (embedded_sysmap_end) klimit = KERNELBASE + ((embedded_sysmap_end + 4095) & 0xfffffffffffff000); }}static int __init iSeries_src_init(void){ /* clear the progress line */ 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_paca()->lppaca.int_dword.fields.decr_int = 1; process_iSeries_events();}static int iseries_shared_idle(void){ while (1) { 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(); if (hvlpevent_is_pending()) process_iSeries_events(); schedule(); } return 0;}static int iseries_dedicated_idle(void){ long oldval; while (1) { oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); if (!oldval) { set_thread_flag(TIF_POLLING_NRFLAG); while (!need_resched()) { ppc64_runlatch_off(); HMT_low(); if (hvlpevent_is_pending()) { HMT_medium(); ppc64_runlatch_on(); process_iSeries_events(); } } HMT_medium(); clear_thread_flag(TIF_POLLING_NRFLAG); } else { set_need_resched(); } ppc64_runlatch_on(); schedule(); } return 0;}#ifndef CONFIG_PCIvoid __init iSeries_init_IRQ(void) { }#endifvoid __init iSeries_early_setup(void){ iSeries_fixup_klimit(); ppc_md.setup_arch = iSeries_setup_arch; ppc_md.get_cpuinfo = iSeries_get_cpuinfo; ppc_md.init_IRQ = iSeries_init_IRQ; ppc_md.get_irq = iSeries_get_irq; ppc_md.init_early = iSeries_init_early, ppc_md.pcibios_fixup = iSeries_pci_final_fixup; ppc_md.restart = iSeries_restart; ppc_md.power_off = iSeries_power_off; ppc_md.halt = iSeries_halt; ppc_md.get_boot_time = iSeries_get_boot_time; 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; /* XXX Implement enable_pmcs for iSeries */ if (get_paca()->lppaca.shared_proc) { ppc_md.idle_loop = iseries_shared_idle; printk(KERN_INFO "Using shared processor idle loop\n"); } else { ppc_md.idle_loop = iseries_dedicated_idle; printk(KERN_INFO "Using dedicated idle loop\n"); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?