Loading Documentation/cpu-freq/user-guide.txt +4 −1 Original line number Diff line number Diff line Loading @@ -157,6 +157,9 @@ scaling_min_freq and scaling_max_freq show the current "policy limits" (in kHz). By echoing new values into these files, you can change these limits. NOTE: when setting a policy you need to first set scaling_max_freq, then scaling_min_freq. If you have selected the "userspace" governor which allows you to Loading arch/i386/kernel/cpu/cpufreq/Kconfig +2 −1 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ config X86_POWERNOW_K8_ACPI config X86_GX_SUSPMOD tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation" depends on PCI help This add the CPUFreq driver for NatSemi Geode processors which support suspend modulation. Loading Loading @@ -202,7 +203,7 @@ config X86_LONGRUN config X86_LONGHAUL tristate "VIA Cyrix III Longhaul" select CPU_FREQ_TABLE depends on BROKEN depends on ACPI_PROCESSOR help This adds the CPUFreq driver for VIA Samuel/CyrixIII, VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T Loading arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +1 −2 Original line number Diff line number Diff line Loading @@ -384,8 +384,7 @@ static int acpi_cpufreq_early_init_acpi(void) } /* Do initialization in ACPI core */ acpi_processor_preregister_performance(acpi_perf_data); return 0; return acpi_processor_preregister_performance(acpi_perf_data); } static int Loading arch/i386/kernel/cpu/cpufreq/longhaul.c +129 −92 Original line number Diff line number Diff line Loading @@ -29,11 +29,13 @@ #include <linux/cpufreq.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/pci.h> #include <asm/msr.h> #include <asm/timex.h> #include <asm/io.h> #include <asm/acpi.h> #include <linux/acpi.h> #include <acpi/processor.h> #include "longhaul.h" Loading @@ -56,6 +58,8 @@ static int minvid, maxvid; static unsigned int minmult, maxmult; static int can_scale_voltage; static int vrmrev; static struct acpi_processor *pr = NULL; static struct acpi_processor_cx *cx = NULL; /* Module parameters */ static int dont_scale_voltage; Loading Loading @@ -118,84 +122,65 @@ static int longhaul_get_cpu_mult(void) return eblcr_table[invalue]; } /* For processor with BCR2 MSR */ static void do_powersaver(union msr_longhaul *longhaul, unsigned int clock_ratio_index) static void do_longhaul1(int cx_address, unsigned int clock_ratio_index) { struct pci_dev *dev; unsigned long flags; unsigned int tmp_mask; int version; int i; u16 pci_cmd; u16 cmd_state[64]; union msr_bcr2 bcr2; u32 t; switch (cpu_model) { case CPU_EZRA_T: version = 3; break; case CPU_NEHEMIAH: version = 0xf; break; default: return; rdmsrl(MSR_VIA_BCR2, bcr2.val); /* Enable software clock multiplier */ bcr2.bits.ESOFTBF = 1; bcr2.bits.CLOCKMUL = clock_ratio_index; /* Sync to timer tick */ safe_halt(); ACPI_FLUSH_CPU_CACHE(); /* Change frequency on next halt or sleep */ wrmsrl(MSR_VIA_BCR2, bcr2.val); /* Invoke C3 */ inb(cx_address); /* Dummy op - must do something useless after P_LVL3 read */ t = inl(acpi_fadt.xpm_tmr_blk.address); /* Disable software clock multiplier */ local_irq_disable(); rdmsrl(MSR_VIA_BCR2, bcr2.val); bcr2.bits.ESOFTBF = 0; wrmsrl(MSR_VIA_BCR2, bcr2.val); } rdmsrl(MSR_VIA_LONGHAUL, longhaul->val); longhaul->bits.SoftBusRatio = clock_ratio_index & 0xf; longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; longhaul->bits.EnableSoftBusRatio = 1; longhaul->bits.RevisionKey = 0; /* For processor with Longhaul MSR */ preempt_disable(); local_irq_save(flags); static void do_powersaver(int cx_address, unsigned int clock_ratio_index) { union msr_longhaul longhaul; u32 t; /* * get current pci bus master state for all devices * and clear bus master bit */ dev = NULL; i = 0; do { dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); if (dev != NULL) { pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); cmd_state[i++] = pci_cmd; pci_cmd &= ~PCI_COMMAND_MASTER; pci_write_config_word(dev, PCI_COMMAND, pci_cmd); } } while (dev != NULL); tmp_mask=inb(0x21); /* works on C3. save mask. */ outb(0xFE,0x21); /* TMR0 only */ outb(0xFF,0x80); /* delay */ rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); longhaul.bits.RevisionKey = longhaul.bits.RevisionID; longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; longhaul.bits.EnableSoftBusRatio = 1; /* Sync to timer tick */ safe_halt(); wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); halt(); ACPI_FLUSH_CPU_CACHE(); /* Change frequency on next halt or sleep */ wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); /* Invoke C3 */ inb(cx_address); /* Dummy op - must do something useless after P_LVL3 read */ t = inl(acpi_fadt.xpm_tmr_blk.address); /* Disable bus ratio bit */ local_irq_disable(); outb(tmp_mask,0x21); /* restore mask */ /* restore pci bus master state for all devices */ dev = NULL; i = 0; do { dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); if (dev != NULL) { pci_cmd = cmd_state[i++]; pci_write_config_byte(dev, PCI_COMMAND, pci_cmd); } } while (dev != NULL); local_irq_restore(flags); preempt_enable(); /* disable bus ratio bit */ rdmsrl(MSR_VIA_LONGHAUL, longhaul->val); longhaul->bits.EnableSoftBusRatio = 0; longhaul->bits.RevisionKey = version; wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); longhaul.bits.RevisionKey = longhaul.bits.RevisionID; longhaul.bits.EnableSoftBusRatio = 0; longhaul.bits.EnableSoftBSEL = 0; longhaul.bits.EnableSoftVID = 0; wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); } /** Loading @@ -209,9 +194,9 @@ static void longhaul_setstate(unsigned int clock_ratio_index) { int speed, mult; struct cpufreq_freqs freqs; union msr_longhaul longhaul; union msr_bcr2 bcr2; static unsigned int old_ratio=-1; unsigned long flags; unsigned int pic1_mask, pic2_mask; if (old_ratio == clock_ratio_index) return; Loading @@ -234,6 +219,20 @@ static void longhaul_setstate(unsigned int clock_ratio_index) dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", fsb, mult/10, mult%10, print_speed(speed/1000)); preempt_disable(); local_irq_save(flags); pic2_mask = inb(0xA1); pic1_mask = inb(0x21); /* works on C3. save mask. */ outb(0xFF,0xA1); /* Overkill */ outb(0xFE,0x21); /* TMR0 only */ /* Disable bus master arbitration */ if (pr->flags.bm_check) { acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK); } switch (longhaul_version) { /* Loading @@ -245,20 +244,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index) */ case TYPE_LONGHAUL_V1: case TYPE_LONGHAUL_V2: rdmsrl (MSR_VIA_BCR2, bcr2.val); /* Enable software clock multiplier */ bcr2.bits.ESOFTBF = 1; bcr2.bits.CLOCKMUL = clock_ratio_index; local_irq_disable(); wrmsrl (MSR_VIA_BCR2, bcr2.val); safe_halt(); /* Disable software clock multiplier */ rdmsrl (MSR_VIA_BCR2, bcr2.val); bcr2.bits.ESOFTBF = 0; local_irq_disable(); wrmsrl (MSR_VIA_BCR2, bcr2.val); local_irq_enable(); do_longhaul1(cx->address, clock_ratio_index); break; /* Loading @@ -273,10 +259,22 @@ static void longhaul_setstate(unsigned int clock_ratio_index) * to work in practice. */ case TYPE_POWERSAVER: do_powersaver(&longhaul, clock_ratio_index); do_powersaver(cx->address, clock_ratio_index); break; } /* Enable bus master arbitration */ if (pr->flags.bm_check) { acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK); } outb(pic2_mask,0xA1); /* restore mask */ outb(pic1_mask,0x21); local_irq_restore(flags); preempt_enable(); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } Loading Loading @@ -324,9 +322,11 @@ static int guess_fsb(void) static int __init longhaul_get_ranges(void) { unsigned long invalue; unsigned int multipliers[32]= { 50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65, -1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 }; unsigned int ezra_t_multipliers[32]= { 90, 30, 40, 100, 55, 35, 45, 95, 50, 70, 80, 60, 120, 75, 85, 65, -1, 110, 120, -1, 135, 115, 125, 105, 130, 150, 160, 140, -1, 155, -1, 145 }; unsigned int j, k = 0; union msr_longhaul longhaul; unsigned long lo, hi; Loading Loading @@ -355,13 +355,13 @@ static int __init longhaul_get_ranges(void) invalue = longhaul.bits.MaxMHzBR; if (longhaul.bits.MaxMHzBR4) invalue += 16; maxmult=multipliers[invalue]; maxmult=ezra_t_multipliers[invalue]; invalue = longhaul.bits.MinMHzBR; if (longhaul.bits.MinMHzBR4 == 1) minmult = 30; else minmult = multipliers[invalue]; minmult = ezra_t_multipliers[invalue]; fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; break; } Loading Loading @@ -527,6 +527,18 @@ static unsigned int longhaul_get(unsigned int cpu) return calc_speed(longhaul_get_cpu_mult()); } static acpi_status longhaul_walk_callback(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { struct acpi_device *d; if ( acpi_bus_get_device(obj_handle, &d) ) { return 0; } *return_value = (void *)acpi_driver_data(d); return 1; } static int __init longhaul_cpu_init(struct cpufreq_policy *policy) { Loading @@ -534,6 +546,15 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) char *cpuname=NULL; int ret; /* Check ACPI support for C3 state */ acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, &longhaul_walk_callback, NULL, (void *)&pr); if (pr == NULL) goto err_acpi; cx = &pr->power.states[ACPI_STATE_C3]; if (cx->address == 0 || cx->latency > 1000) goto err_acpi; /* Now check what we have on this motherboard */ switch (c->x86_model) { case 6: cpu_model = CPU_SAMUEL; Loading Loading @@ -634,6 +655,10 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu); return 0; err_acpi: printk(KERN_ERR PFX "No ACPI support for CPU frequency changes.\n"); return -ENODEV; } static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) Loading Loading @@ -666,6 +691,18 @@ static int __init longhaul_init(void) if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6) return -ENODEV; #ifdef CONFIG_SMP if (num_online_cpus() > 1) { return -ENODEV; printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n"); } #endif #ifdef CONFIG_X86_IO_APIC if (cpu_has_apic) { printk(KERN_ERR PFX "APIC detected. Longhaul is currently broken in this configuration.\n"); return -ENODEV; } #endif switch (c->x86_model) { case 6 ... 9: return cpufreq_register_driver(&longhaul_driver); Loading Loading @@ -699,6 +736,6 @@ MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>"); MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); MODULE_LICENSE ("GPL"); module_init(longhaul_init); late_initcall(longhaul_init); module_exit(longhaul_exit); arch/ia64/kernel/uncached.c +57 −29 Original line number Diff line number Diff line Loading @@ -32,32 +32,38 @@ extern void __init efi_memmap_walk_uc(efi_freemem_callback_t, void *); #define MAX_UNCACHED_GRANULES 5 static int allocated_granules; struct uncached_pool { struct gen_pool *pool; struct mutex add_chunk_mutex; /* serialize adding a converted chunk */ int nchunks_added; /* #of converted chunks added to pool */ atomic_t status; /* smp called function's return status*/ }; #define MAX_CONVERTED_CHUNKS_PER_NODE 2 struct gen_pool *uncached_pool[MAX_NUMNODES]; struct uncached_pool uncached_pools[MAX_NUMNODES]; static void uncached_ipi_visibility(void *data) { int status; struct uncached_pool *uc_pool = (struct uncached_pool *)data; status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL); if ((status != PAL_VISIBILITY_OK) && (status != PAL_VISIBILITY_OK_REMOTE_NEEDED)) printk(KERN_DEBUG "pal_prefetch_visibility() returns %i on " "CPU %i\n", status, raw_smp_processor_id()); atomic_inc(&uc_pool->status); } static void uncached_ipi_mc_drain(void *data) { int status; struct uncached_pool *uc_pool = (struct uncached_pool *)data; status = ia64_pal_mc_drain(); if (status) printk(KERN_WARNING "ia64_pal_mc_drain() failed with %i on " "CPU %i\n", status, raw_smp_processor_id()); if (status != PAL_STATUS_SUCCESS) atomic_inc(&uc_pool->status); } Loading @@ -70,21 +76,34 @@ static void uncached_ipi_mc_drain(void *data) * This is accomplished by first allocating a granule of cached memory pages * and then converting them to uncached memory pages. */ static int uncached_add_chunk(struct gen_pool *pool, int nid) static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid) { struct page *page; int status, i; int status, i, nchunks_added = uc_pool->nchunks_added; unsigned long c_addr, uc_addr; if (allocated_granules >= MAX_UNCACHED_GRANULES) if (mutex_lock_interruptible(&uc_pool->add_chunk_mutex) != 0) return -1; /* interrupted by a signal */ if (uc_pool->nchunks_added > nchunks_added) { /* someone added a new chunk while we were waiting */ mutex_unlock(&uc_pool->add_chunk_mutex); return 0; } if (uc_pool->nchunks_added >= MAX_CONVERTED_CHUNKS_PER_NODE) { mutex_unlock(&uc_pool->add_chunk_mutex); return -1; } /* attempt to allocate a granule's worth of cached memory pages */ page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO, IA64_GRANULE_SHIFT-PAGE_SHIFT); if (!page) if (!page) { mutex_unlock(&uc_pool->add_chunk_mutex); return -1; } /* convert the memory pages from cached to uncached */ Loading @@ -102,11 +121,14 @@ static int uncached_add_chunk(struct gen_pool *pool, int nid) flush_tlb_kernel_range(uc_addr, uc_adddr + IA64_GRANULE_SIZE); status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL); if (!status) { status = smp_call_function(uncached_ipi_visibility, NULL, 0, 1); if (status) if (status == PAL_VISIBILITY_OK_REMOTE_NEEDED) { atomic_set(&uc_pool->status, 0); status = smp_call_function(uncached_ipi_visibility, uc_pool, 0, 1); if (status || atomic_read(&uc_pool->status)) goto failed; } else if (status != PAL_VISIBILITY_OK) goto failed; } preempt_disable(); Loading @@ -120,20 +142,24 @@ static int uncached_add_chunk(struct gen_pool *pool, int nid) preempt_enable(); ia64_pal_mc_drain(); status = smp_call_function(uncached_ipi_mc_drain, NULL, 0, 1); if (status) status = ia64_pal_mc_drain(); if (status != PAL_STATUS_SUCCESS) goto failed; atomic_set(&uc_pool->status, 0); status = smp_call_function(uncached_ipi_mc_drain, uc_pool, 0, 1); if (status || atomic_read(&uc_pool->status)) goto failed; /* * The chunk of memory pages has been converted to uncached so now we * can add it to the pool. */ status = gen_pool_add(pool, uc_addr, IA64_GRANULE_SIZE, nid); status = gen_pool_add(uc_pool->pool, uc_addr, IA64_GRANULE_SIZE, nid); if (status) goto failed; allocated_granules++; uc_pool->nchunks_added++; mutex_unlock(&uc_pool->add_chunk_mutex); return 0; /* failed to convert or add the chunk so give it back to the kernel */ Loading @@ -142,6 +168,7 @@ static int uncached_add_chunk(struct gen_pool *pool, int nid) ClearPageUncached(&page[i]); free_pages(c_addr, IA64_GRANULE_SHIFT-PAGE_SHIFT); mutex_unlock(&uc_pool->add_chunk_mutex); return -1; } Loading @@ -158,7 +185,7 @@ static int uncached_add_chunk(struct gen_pool *pool, int nid) unsigned long uncached_alloc_page(int starting_nid) { unsigned long uc_addr; struct gen_pool *pool; struct uncached_pool *uc_pool; int nid; if (unlikely(starting_nid >= MAX_NUMNODES)) Loading @@ -171,14 +198,14 @@ unsigned long uncached_alloc_page(int starting_nid) do { if (!node_online(nid)) continue; pool = uncached_pool[nid]; if (pool == NULL) uc_pool = &uncached_pools[nid]; if (uc_pool->pool == NULL) continue; do { uc_addr = gen_pool_alloc(pool, PAGE_SIZE); uc_addr = gen_pool_alloc(uc_pool->pool, PAGE_SIZE); if (uc_addr != 0) return uc_addr; } while (uncached_add_chunk(pool, nid) == 0); } while (uncached_add_chunk(uc_pool, nid) == 0); } while ((nid = (nid + 1) % MAX_NUMNODES) != starting_nid); Loading @@ -197,7 +224,7 @@ EXPORT_SYMBOL(uncached_alloc_page); void uncached_free_page(unsigned long uc_addr) { int nid = paddr_to_nid(uc_addr - __IA64_UNCACHED_OFFSET); struct gen_pool *pool = uncached_pool[nid]; struct gen_pool *pool = uncached_pools[nid].pool; if (unlikely(pool == NULL)) return; Loading @@ -224,7 +251,7 @@ static int __init uncached_build_memmap(unsigned long uc_start, unsigned long uc_end, void *arg) { int nid = paddr_to_nid(uc_start - __IA64_UNCACHED_OFFSET); struct gen_pool *pool = uncached_pool[nid]; struct gen_pool *pool = uncached_pools[nid].pool; size_t size = uc_end - uc_start; touch_softlockup_watchdog(); Loading @@ -242,7 +269,8 @@ static int __init uncached_init(void) int nid; for_each_online_node(nid) { uncached_pool[nid] = gen_pool_create(PAGE_SHIFT, nid); uncached_pools[nid].pool = gen_pool_create(PAGE_SHIFT, nid); mutex_init(&uncached_pools[nid].add_chunk_mutex); } efi_memmap_walk_uc(uncached_build_memmap, NULL); Loading Loading
Documentation/cpu-freq/user-guide.txt +4 −1 Original line number Diff line number Diff line Loading @@ -157,6 +157,9 @@ scaling_min_freq and scaling_max_freq show the current "policy limits" (in kHz). By echoing new values into these files, you can change these limits. NOTE: when setting a policy you need to first set scaling_max_freq, then scaling_min_freq. If you have selected the "userspace" governor which allows you to Loading
arch/i386/kernel/cpu/cpufreq/Kconfig +2 −1 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ config X86_POWERNOW_K8_ACPI config X86_GX_SUSPMOD tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation" depends on PCI help This add the CPUFreq driver for NatSemi Geode processors which support suspend modulation. Loading Loading @@ -202,7 +203,7 @@ config X86_LONGRUN config X86_LONGHAUL tristate "VIA Cyrix III Longhaul" select CPU_FREQ_TABLE depends on BROKEN depends on ACPI_PROCESSOR help This adds the CPUFreq driver for VIA Samuel/CyrixIII, VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T Loading
arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +1 −2 Original line number Diff line number Diff line Loading @@ -384,8 +384,7 @@ static int acpi_cpufreq_early_init_acpi(void) } /* Do initialization in ACPI core */ acpi_processor_preregister_performance(acpi_perf_data); return 0; return acpi_processor_preregister_performance(acpi_perf_data); } static int Loading
arch/i386/kernel/cpu/cpufreq/longhaul.c +129 −92 Original line number Diff line number Diff line Loading @@ -29,11 +29,13 @@ #include <linux/cpufreq.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/pci.h> #include <asm/msr.h> #include <asm/timex.h> #include <asm/io.h> #include <asm/acpi.h> #include <linux/acpi.h> #include <acpi/processor.h> #include "longhaul.h" Loading @@ -56,6 +58,8 @@ static int minvid, maxvid; static unsigned int minmult, maxmult; static int can_scale_voltage; static int vrmrev; static struct acpi_processor *pr = NULL; static struct acpi_processor_cx *cx = NULL; /* Module parameters */ static int dont_scale_voltage; Loading Loading @@ -118,84 +122,65 @@ static int longhaul_get_cpu_mult(void) return eblcr_table[invalue]; } /* For processor with BCR2 MSR */ static void do_powersaver(union msr_longhaul *longhaul, unsigned int clock_ratio_index) static void do_longhaul1(int cx_address, unsigned int clock_ratio_index) { struct pci_dev *dev; unsigned long flags; unsigned int tmp_mask; int version; int i; u16 pci_cmd; u16 cmd_state[64]; union msr_bcr2 bcr2; u32 t; switch (cpu_model) { case CPU_EZRA_T: version = 3; break; case CPU_NEHEMIAH: version = 0xf; break; default: return; rdmsrl(MSR_VIA_BCR2, bcr2.val); /* Enable software clock multiplier */ bcr2.bits.ESOFTBF = 1; bcr2.bits.CLOCKMUL = clock_ratio_index; /* Sync to timer tick */ safe_halt(); ACPI_FLUSH_CPU_CACHE(); /* Change frequency on next halt or sleep */ wrmsrl(MSR_VIA_BCR2, bcr2.val); /* Invoke C3 */ inb(cx_address); /* Dummy op - must do something useless after P_LVL3 read */ t = inl(acpi_fadt.xpm_tmr_blk.address); /* Disable software clock multiplier */ local_irq_disable(); rdmsrl(MSR_VIA_BCR2, bcr2.val); bcr2.bits.ESOFTBF = 0; wrmsrl(MSR_VIA_BCR2, bcr2.val); } rdmsrl(MSR_VIA_LONGHAUL, longhaul->val); longhaul->bits.SoftBusRatio = clock_ratio_index & 0xf; longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; longhaul->bits.EnableSoftBusRatio = 1; longhaul->bits.RevisionKey = 0; /* For processor with Longhaul MSR */ preempt_disable(); local_irq_save(flags); static void do_powersaver(int cx_address, unsigned int clock_ratio_index) { union msr_longhaul longhaul; u32 t; /* * get current pci bus master state for all devices * and clear bus master bit */ dev = NULL; i = 0; do { dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); if (dev != NULL) { pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); cmd_state[i++] = pci_cmd; pci_cmd &= ~PCI_COMMAND_MASTER; pci_write_config_word(dev, PCI_COMMAND, pci_cmd); } } while (dev != NULL); tmp_mask=inb(0x21); /* works on C3. save mask. */ outb(0xFE,0x21); /* TMR0 only */ outb(0xFF,0x80); /* delay */ rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); longhaul.bits.RevisionKey = longhaul.bits.RevisionID; longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; longhaul.bits.EnableSoftBusRatio = 1; /* Sync to timer tick */ safe_halt(); wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); halt(); ACPI_FLUSH_CPU_CACHE(); /* Change frequency on next halt or sleep */ wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); /* Invoke C3 */ inb(cx_address); /* Dummy op - must do something useless after P_LVL3 read */ t = inl(acpi_fadt.xpm_tmr_blk.address); /* Disable bus ratio bit */ local_irq_disable(); outb(tmp_mask,0x21); /* restore mask */ /* restore pci bus master state for all devices */ dev = NULL; i = 0; do { dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); if (dev != NULL) { pci_cmd = cmd_state[i++]; pci_write_config_byte(dev, PCI_COMMAND, pci_cmd); } } while (dev != NULL); local_irq_restore(flags); preempt_enable(); /* disable bus ratio bit */ rdmsrl(MSR_VIA_LONGHAUL, longhaul->val); longhaul->bits.EnableSoftBusRatio = 0; longhaul->bits.RevisionKey = version; wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); longhaul.bits.RevisionKey = longhaul.bits.RevisionID; longhaul.bits.EnableSoftBusRatio = 0; longhaul.bits.EnableSoftBSEL = 0; longhaul.bits.EnableSoftVID = 0; wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); } /** Loading @@ -209,9 +194,9 @@ static void longhaul_setstate(unsigned int clock_ratio_index) { int speed, mult; struct cpufreq_freqs freqs; union msr_longhaul longhaul; union msr_bcr2 bcr2; static unsigned int old_ratio=-1; unsigned long flags; unsigned int pic1_mask, pic2_mask; if (old_ratio == clock_ratio_index) return; Loading @@ -234,6 +219,20 @@ static void longhaul_setstate(unsigned int clock_ratio_index) dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", fsb, mult/10, mult%10, print_speed(speed/1000)); preempt_disable(); local_irq_save(flags); pic2_mask = inb(0xA1); pic1_mask = inb(0x21); /* works on C3. save mask. */ outb(0xFF,0xA1); /* Overkill */ outb(0xFE,0x21); /* TMR0 only */ /* Disable bus master arbitration */ if (pr->flags.bm_check) { acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK); } switch (longhaul_version) { /* Loading @@ -245,20 +244,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index) */ case TYPE_LONGHAUL_V1: case TYPE_LONGHAUL_V2: rdmsrl (MSR_VIA_BCR2, bcr2.val); /* Enable software clock multiplier */ bcr2.bits.ESOFTBF = 1; bcr2.bits.CLOCKMUL = clock_ratio_index; local_irq_disable(); wrmsrl (MSR_VIA_BCR2, bcr2.val); safe_halt(); /* Disable software clock multiplier */ rdmsrl (MSR_VIA_BCR2, bcr2.val); bcr2.bits.ESOFTBF = 0; local_irq_disable(); wrmsrl (MSR_VIA_BCR2, bcr2.val); local_irq_enable(); do_longhaul1(cx->address, clock_ratio_index); break; /* Loading @@ -273,10 +259,22 @@ static void longhaul_setstate(unsigned int clock_ratio_index) * to work in practice. */ case TYPE_POWERSAVER: do_powersaver(&longhaul, clock_ratio_index); do_powersaver(cx->address, clock_ratio_index); break; } /* Enable bus master arbitration */ if (pr->flags.bm_check) { acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK); } outb(pic2_mask,0xA1); /* restore mask */ outb(pic1_mask,0x21); local_irq_restore(flags); preempt_enable(); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } Loading Loading @@ -324,9 +322,11 @@ static int guess_fsb(void) static int __init longhaul_get_ranges(void) { unsigned long invalue; unsigned int multipliers[32]= { 50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65, -1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 }; unsigned int ezra_t_multipliers[32]= { 90, 30, 40, 100, 55, 35, 45, 95, 50, 70, 80, 60, 120, 75, 85, 65, -1, 110, 120, -1, 135, 115, 125, 105, 130, 150, 160, 140, -1, 155, -1, 145 }; unsigned int j, k = 0; union msr_longhaul longhaul; unsigned long lo, hi; Loading Loading @@ -355,13 +355,13 @@ static int __init longhaul_get_ranges(void) invalue = longhaul.bits.MaxMHzBR; if (longhaul.bits.MaxMHzBR4) invalue += 16; maxmult=multipliers[invalue]; maxmult=ezra_t_multipliers[invalue]; invalue = longhaul.bits.MinMHzBR; if (longhaul.bits.MinMHzBR4 == 1) minmult = 30; else minmult = multipliers[invalue]; minmult = ezra_t_multipliers[invalue]; fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; break; } Loading Loading @@ -527,6 +527,18 @@ static unsigned int longhaul_get(unsigned int cpu) return calc_speed(longhaul_get_cpu_mult()); } static acpi_status longhaul_walk_callback(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { struct acpi_device *d; if ( acpi_bus_get_device(obj_handle, &d) ) { return 0; } *return_value = (void *)acpi_driver_data(d); return 1; } static int __init longhaul_cpu_init(struct cpufreq_policy *policy) { Loading @@ -534,6 +546,15 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) char *cpuname=NULL; int ret; /* Check ACPI support for C3 state */ acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, &longhaul_walk_callback, NULL, (void *)&pr); if (pr == NULL) goto err_acpi; cx = &pr->power.states[ACPI_STATE_C3]; if (cx->address == 0 || cx->latency > 1000) goto err_acpi; /* Now check what we have on this motherboard */ switch (c->x86_model) { case 6: cpu_model = CPU_SAMUEL; Loading Loading @@ -634,6 +655,10 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu); return 0; err_acpi: printk(KERN_ERR PFX "No ACPI support for CPU frequency changes.\n"); return -ENODEV; } static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) Loading Loading @@ -666,6 +691,18 @@ static int __init longhaul_init(void) if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6) return -ENODEV; #ifdef CONFIG_SMP if (num_online_cpus() > 1) { return -ENODEV; printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n"); } #endif #ifdef CONFIG_X86_IO_APIC if (cpu_has_apic) { printk(KERN_ERR PFX "APIC detected. Longhaul is currently broken in this configuration.\n"); return -ENODEV; } #endif switch (c->x86_model) { case 6 ... 9: return cpufreq_register_driver(&longhaul_driver); Loading Loading @@ -699,6 +736,6 @@ MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>"); MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); MODULE_LICENSE ("GPL"); module_init(longhaul_init); late_initcall(longhaul_init); module_exit(longhaul_exit);
arch/ia64/kernel/uncached.c +57 −29 Original line number Diff line number Diff line Loading @@ -32,32 +32,38 @@ extern void __init efi_memmap_walk_uc(efi_freemem_callback_t, void *); #define MAX_UNCACHED_GRANULES 5 static int allocated_granules; struct uncached_pool { struct gen_pool *pool; struct mutex add_chunk_mutex; /* serialize adding a converted chunk */ int nchunks_added; /* #of converted chunks added to pool */ atomic_t status; /* smp called function's return status*/ }; #define MAX_CONVERTED_CHUNKS_PER_NODE 2 struct gen_pool *uncached_pool[MAX_NUMNODES]; struct uncached_pool uncached_pools[MAX_NUMNODES]; static void uncached_ipi_visibility(void *data) { int status; struct uncached_pool *uc_pool = (struct uncached_pool *)data; status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL); if ((status != PAL_VISIBILITY_OK) && (status != PAL_VISIBILITY_OK_REMOTE_NEEDED)) printk(KERN_DEBUG "pal_prefetch_visibility() returns %i on " "CPU %i\n", status, raw_smp_processor_id()); atomic_inc(&uc_pool->status); } static void uncached_ipi_mc_drain(void *data) { int status; struct uncached_pool *uc_pool = (struct uncached_pool *)data; status = ia64_pal_mc_drain(); if (status) printk(KERN_WARNING "ia64_pal_mc_drain() failed with %i on " "CPU %i\n", status, raw_smp_processor_id()); if (status != PAL_STATUS_SUCCESS) atomic_inc(&uc_pool->status); } Loading @@ -70,21 +76,34 @@ static void uncached_ipi_mc_drain(void *data) * This is accomplished by first allocating a granule of cached memory pages * and then converting them to uncached memory pages. */ static int uncached_add_chunk(struct gen_pool *pool, int nid) static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid) { struct page *page; int status, i; int status, i, nchunks_added = uc_pool->nchunks_added; unsigned long c_addr, uc_addr; if (allocated_granules >= MAX_UNCACHED_GRANULES) if (mutex_lock_interruptible(&uc_pool->add_chunk_mutex) != 0) return -1; /* interrupted by a signal */ if (uc_pool->nchunks_added > nchunks_added) { /* someone added a new chunk while we were waiting */ mutex_unlock(&uc_pool->add_chunk_mutex); return 0; } if (uc_pool->nchunks_added >= MAX_CONVERTED_CHUNKS_PER_NODE) { mutex_unlock(&uc_pool->add_chunk_mutex); return -1; } /* attempt to allocate a granule's worth of cached memory pages */ page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO, IA64_GRANULE_SHIFT-PAGE_SHIFT); if (!page) if (!page) { mutex_unlock(&uc_pool->add_chunk_mutex); return -1; } /* convert the memory pages from cached to uncached */ Loading @@ -102,11 +121,14 @@ static int uncached_add_chunk(struct gen_pool *pool, int nid) flush_tlb_kernel_range(uc_addr, uc_adddr + IA64_GRANULE_SIZE); status = ia64_pal_prefetch_visibility(PAL_VISIBILITY_PHYSICAL); if (!status) { status = smp_call_function(uncached_ipi_visibility, NULL, 0, 1); if (status) if (status == PAL_VISIBILITY_OK_REMOTE_NEEDED) { atomic_set(&uc_pool->status, 0); status = smp_call_function(uncached_ipi_visibility, uc_pool, 0, 1); if (status || atomic_read(&uc_pool->status)) goto failed; } else if (status != PAL_VISIBILITY_OK) goto failed; } preempt_disable(); Loading @@ -120,20 +142,24 @@ static int uncached_add_chunk(struct gen_pool *pool, int nid) preempt_enable(); ia64_pal_mc_drain(); status = smp_call_function(uncached_ipi_mc_drain, NULL, 0, 1); if (status) status = ia64_pal_mc_drain(); if (status != PAL_STATUS_SUCCESS) goto failed; atomic_set(&uc_pool->status, 0); status = smp_call_function(uncached_ipi_mc_drain, uc_pool, 0, 1); if (status || atomic_read(&uc_pool->status)) goto failed; /* * The chunk of memory pages has been converted to uncached so now we * can add it to the pool. */ status = gen_pool_add(pool, uc_addr, IA64_GRANULE_SIZE, nid); status = gen_pool_add(uc_pool->pool, uc_addr, IA64_GRANULE_SIZE, nid); if (status) goto failed; allocated_granules++; uc_pool->nchunks_added++; mutex_unlock(&uc_pool->add_chunk_mutex); return 0; /* failed to convert or add the chunk so give it back to the kernel */ Loading @@ -142,6 +168,7 @@ static int uncached_add_chunk(struct gen_pool *pool, int nid) ClearPageUncached(&page[i]); free_pages(c_addr, IA64_GRANULE_SHIFT-PAGE_SHIFT); mutex_unlock(&uc_pool->add_chunk_mutex); return -1; } Loading @@ -158,7 +185,7 @@ static int uncached_add_chunk(struct gen_pool *pool, int nid) unsigned long uncached_alloc_page(int starting_nid) { unsigned long uc_addr; struct gen_pool *pool; struct uncached_pool *uc_pool; int nid; if (unlikely(starting_nid >= MAX_NUMNODES)) Loading @@ -171,14 +198,14 @@ unsigned long uncached_alloc_page(int starting_nid) do { if (!node_online(nid)) continue; pool = uncached_pool[nid]; if (pool == NULL) uc_pool = &uncached_pools[nid]; if (uc_pool->pool == NULL) continue; do { uc_addr = gen_pool_alloc(pool, PAGE_SIZE); uc_addr = gen_pool_alloc(uc_pool->pool, PAGE_SIZE); if (uc_addr != 0) return uc_addr; } while (uncached_add_chunk(pool, nid) == 0); } while (uncached_add_chunk(uc_pool, nid) == 0); } while ((nid = (nid + 1) % MAX_NUMNODES) != starting_nid); Loading @@ -197,7 +224,7 @@ EXPORT_SYMBOL(uncached_alloc_page); void uncached_free_page(unsigned long uc_addr) { int nid = paddr_to_nid(uc_addr - __IA64_UNCACHED_OFFSET); struct gen_pool *pool = uncached_pool[nid]; struct gen_pool *pool = uncached_pools[nid].pool; if (unlikely(pool == NULL)) return; Loading @@ -224,7 +251,7 @@ static int __init uncached_build_memmap(unsigned long uc_start, unsigned long uc_end, void *arg) { int nid = paddr_to_nid(uc_start - __IA64_UNCACHED_OFFSET); struct gen_pool *pool = uncached_pool[nid]; struct gen_pool *pool = uncached_pools[nid].pool; size_t size = uc_end - uc_start; touch_softlockup_watchdog(); Loading @@ -242,7 +269,8 @@ static int __init uncached_init(void) int nid; for_each_online_node(nid) { uncached_pool[nid] = gen_pool_create(PAGE_SHIFT, nid); uncached_pools[nid].pool = gen_pool_create(PAGE_SHIFT, nid); mutex_init(&uncached_pools[nid].add_chunk_mutex); } efi_memmap_walk_uc(uncached_build_memmap, NULL); Loading