android_kernel_samsung_msm8976/drivers/cpufreq/speedstep-smi.c
Ian Maund 068b0551a9 This is the 3.10.73 stable release
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJVFBE+AAoJEDjbvchgkmk+oTkP/j2ipSvgXghFEipZbOJUQkqC
 fa8elfoF7riTKpKOuDtDU2WI1ttCGYs5gmTNpd4KaEt23eJOQgVqIpV8GhAkW5Af
 NVyGhjF3dXNqpBkxnyuIkk5OLrNKGRNS2xpz1U254iGObYrK+tr62IzGPxEcPAhX
 Y+58xPVSjLtNdTJW3YLT3DohUbnbHG6Br9geI1IHtlxg1oDiTxtnX2FmOFzzDpP5
 qu8gnPIekg/+1EE46nEiq0C59AwC3aCzNxwlYe1Kd41SY3LUFF1eZMzmOnnwyI5K
 3FslAzT6x/sOmGJFTYrKjFA4GKsW67xHVkB/hp/Mu768RqxiQCxV4kgmPsAFLbXb
 D5qbNwr3i0iQ/9AaD7h8HJkxC/KHmszMux00L/mgZ3SGdGMEIBxHg+oP8+nP8V6C
 WfXKSWA94dpdRyULEfWdnKnUnp2860C7kt7ASTkOl8rIgU8HgaRqeu+U/KPM2ovD
 ZJtXPVB5UXCRuVAhZwbvvrLOY8UMZTnv2auAaeLYG8YptcvGeN5Z398/8qdV/z7c
 A9kOsgebs74X+lR3rbVgSDPQaq2AEiuIvtX77SfmrWXBXGmc99i9+PikuFggRprz
 cJm5bCM9DaHu/3b77X9Fwl7vnpReB0zPHiwTdH/p7OPMf5m1uQt7SqegC6btLPHs
 iYgjLd4oW+6uiV/2X1Vx
 =L+mC
 -----END PGP SIGNATURE-----

Merge commit 'v3.10.73' into msm-3.10

This merge brings us up to date with upstream kernel.org tag v3.10.73.
As part of the conflict resolution, changes introduced by commit 72684eae7
("arm64: Fix up /proc/cpuinfo") have been intentionally dropped, as they
conflict with Android changes msm-3.10 kernel to solve the problems
in a different way. Since userspace readers of this file may depend on
the existing msm-3.10 implementation, it's left as-is for now. The
commit may later be introduced if it is found to not impact userspaces
paired with this kernel.

* commit 'v3.10.73' (264 commits):
  Linux 3.10.73
  target: Allow Write Exclusive non-reservation holders to READ
  target: Allow AllRegistrants to re-RESERVE existing reservation
  target: Fix R_HOLDER bit usage for AllRegistrants
  target/pscsi: Fix NULL pointer dereference in get_device_type
  iscsi-target: Avoid early conn_logout_comp for iser connections
  target: Fix reference leak in target_get_sess_cmd() error path
  ARM: at91: pm: fix at91rm9200 standby
  ipvs: rerouting to local clients is not needed anymore
  ipvs: add missing ip_vs_pe_put in sync code
  powerpc/smp: Wait until secondaries are active & online
  x86/vdso: Fix the build on GCC5
  x86/fpu: Drop_fpu() should not assume that tsk equals current
  x86/fpu: Avoid math_state_restore() without used_math() in __restore_xstate_sig()
  crypto: aesni - fix memory usage in GCM decryption
  libsas: Fix Kernel Crash in smp_execute_task
  xen-pciback: limit guest control of command register
  nilfs2: fix deadlock of segment constructor during recovery
  regulator: core: Fix enable GPIO reference counting
  regulator: Only enable disabled regulators on resume
  ALSA: hda - Treat stereo-to-mono mix properly
  ALSA: hda - Add workaround for MacBook Air 5,2 built-in mic
  ALSA: hda - Set single_adc_amp flag for CS420x codecs
  ALSA: hda - Don't access stereo amps for mono channel widgets
  ALSA: hda - Fix built-in mic on Compaq Presario CQ60
  ALSA: control: Add sanity checks for user ctl id name string
  spi: pl022: Fix race in giveback() leading to driver lock-up
  tpm/ibmvtpm: Additional LE support for tpm_ibmvtpm_send
  workqueue: fix hang involving racing cancel[_delayed]_work_sync()'s for PREEMPT_NONE
  can: add missing initialisations in CAN related skbuffs
  Change email address for 8250_pci
  virtio_console: init work unconditionally
  fuse: notify: don't move pages
  fuse: set stolen page uptodate
  drm/radeon: drop setting UPLL to sleep mode
  drm/radeon: do a posting read in rs600_set_irq
  drm/radeon: do a posting read in si_set_irq
  drm/radeon: do a posting read in r600_set_irq
  drm/radeon: do a posting read in r100_set_irq
  drm/radeon: do a posting read in evergreen_set_irq
  drm/radeon: fix DRM_IOCTL_RADEON_CS oops
  tcp: make connect() mem charging friendly
  net: compat: Update get_compat_msghdr() to match copy_msghdr_from_user() behaviour
  tcp: fix tcp fin memory accounting
  Revert "net: cx82310_eth: use common match macro"
  rxrpc: bogus MSG_PEEK test in rxrpc_recvmsg()
  caif: fix MSG_OOB test in caif_seqpkt_recvmsg()
  inet_diag: fix possible overflow in inet_diag_dump_one_icsk()
  rds: avoid potential stack overflow
  net: sysctl_net_core: check SNDBUF and RCVBUF for min length
  sparc64: Fix several bugs in memmove().
  sparc: Touch NMI watchdog when walking cpus and calling printk
  sparc: perf: Make counting mode actually work
  sparc: perf: Remove redundant perf_pmu_{en|dis}able calls
  sparc: semtimedop() unreachable due to comparison error
  sparc32: destroy_context() and switch_mm() needs to disable interrupts.
  Linux 3.10.72
  ath5k: fix spontaneus AR5312 freezes
  ACPI / video: Load the module even if ACPI is disabled
  drm/radeon: fix 1 RB harvest config setup for TN/RL
  Drivers: hv: vmbus: incorrect device name is printed when child device is unregistered
  HID: fixup the conflicting keyboard mappings quirk
  HID: input: fix confusion on conflicting mappings
  staging: comedi: cb_pcidas64: fix incorrect AI range code handling
  dm snapshot: fix a possible invalid memory access on unload
  dm: fix a race condition in dm_get_md
  dm io: reject unsupported DISCARD requests with EOPNOTSUPP
  dm mirror: do not degrade the mirror on discard error
  staging: comedi: comedi_compat32.c: fix COMEDI_CMD copy back
  clk: sunxi: Support factor clocks with N factor starting not from 0
  fixed invalid assignment of 64bit mask to host dma_boundary for scatter gather segment boundary limit.
  nilfs2: fix potential memory overrun on inode
  IB/qib: Do not write EEPROM
  sg: fix read() error reporting
  ALSA: hda - Add pin configs for ASUS mobo with IDT 92HD73XX codec
  ALSA: pcm: Don't leave PREPARED state after draining
  tty: fix up atime/mtime mess, take four
  sunrpc: fix braino in ->poll()
  procfs: fix race between symlink removals and traversals
  debugfs: leave freeing a symlink body until inode eviction
  autofs4 copy_dev_ioctl(): keep the value of ->size we'd used for allocation
  USB: serial: fix potential use-after-free after failed probe
  TTY: fix tty_wait_until_sent on 64-bit machines
  USB: serial: fix infinite wait_until_sent timeout
  net: irda: fix wait_until_sent poll timeout
  xhci: fix reporting of 0-sized URBs in control endpoint
  xhci: Allocate correct amount of scratchpad buffers
  usb: ftdi_sio: Add jtag quirk support for Cyber Cortex AV boards
  USB: usbfs: don't leak kernel data in siginfo
  USB: serial: cp210x: Adding Seletek device id's
  KVM: MIPS: Fix trace event to save PC directly
  KVM: emulate: fix CMPXCHG8B on 32-bit hosts
  Btrfs:__add_inode_ref: out of bounds memory read when looking for extended ref.
  Btrfs: fix data loss in the fast fsync path
  btrfs: fix lost return value due to variable shadowing
  iio: imu: adis16400: Fix sign extension
  x86/asm/entry/64: Remove a bogus 'ret_from_fork' optimization
  PM / QoS: remove duplicate call to pm_qos_update_target
  target: Check for LBA + sectors wrap-around in sbc_parse_cdb
  mm/memory.c: actually remap enough memory
  mm/compaction: fix wrong order check in compact_finished()
  mm/nommu.c: fix arithmetic overflow in __vm_enough_memory()
  mm/mmap.c: fix arithmetic overflow in __vm_enough_memory()
  mm/hugetlb: add migration entry check in __unmap_hugepage_range
  team: don't traverse port list using rcu in team_set_mac_address
  udp: only allow UFO for packets from SOCK_DGRAM sockets
  usb: plusb: Add support for National Instruments host-to-host cable
  macvtap: make sure neighbour code can push ethernet header
  net: compat: Ignore MSG_CMSG_COMPAT in compat_sys_{send, recv}msg
  team: fix possible null pointer dereference in team_handle_frame
  net: reject creation of netdev names with colons
  ematch: Fix auto-loading of ematch modules.
  net: phy: Fix verification of EEE support in phy_init_eee
  ipv4: ip_check_defrag should not assume that skb_network_offset is zero
  ipv4: ip_check_defrag should correctly check return value of skb_copy_bits
  gen_stats.c: Duplicate xstats buffer for later use
  rtnetlink: call ->dellink on failure when ->newlink exists
  ipv6: fix ipv6_cow_metrics for non DST_HOST case
  rtnetlink: ifla_vf_policy: fix misuses of NLA_BINARY
  Linux 3.10.71
  libceph: fix double __remove_osd() problem
  libceph: change from BUG to WARN for __remove_osd() asserts
  libceph: assert both regular and lingering lists in __remove_osd()
  MIPS: Export FP functions used by lose_fpu(1) for KVM
  x86, mm/ASLR: Fix stack randomization on 64-bit systems
  blk-throttle: check stats_cpu before reading it from sysfs
  jffs2: fix handling of corrupted summary length
  md/raid1: fix read balance when a drive is write-mostly.
  md/raid5: Fix livelock when array is both resyncing and degraded.
  metag: Fix KSTK_EIP() and KSTK_ESP() macros
  gpio: tps65912: fix wrong container_of arguments
  arm64: compat Fix siginfo_t -> compat_siginfo_t conversion on big endian
  hx4700: regulator: declare full constraints
  KVM: x86: update masterclock values on TSC writes
  KVM: MIPS: Don't leak FPU/DSP to guest
  ARC: fix page address calculation if PAGE_OFFSET != LINUX_LINK_BASE
  ntp: Fixup adjtimex freq validation on 32-bit systems
  kdb: fix incorrect counts in KDB summary command output
  ARM: pxa: add regulator_has_full_constraints to poodle board file
  ARM: pxa: add regulator_has_full_constraints to corgi board file
  vt: provide notifications on selection changes
  usb: core: buffer: smallest buffer should start at ARCH_DMA_MINALIGN
  USB: fix use-after-free bug in usb_hcd_unlink_urb()
  USB: cp210x: add ID for RUGGEDCOM USB Serial Console
  tty: Prevent untrappable signals from malicious program
  axonram: Fix bug in direct_access
  cfq-iosched: fix incorrect filing of rt async cfqq
  cfq-iosched: handle failure of cfq group allocation
  iscsi-target: Drop problematic active_ts_list usage
  NFSv4.1: Fix a kfree() of uninitialised pointers in decode_cb_sequence_args
  Added Little Endian support to vtpm module
  tpm/tpm_i2c_stm_st33: Fix potential bug in tpm_stm_i2c_send
  tpm: Fix NULL return in tpm_ibmvtpm_get_desired_dma
  tpm_tis: verify interrupt during init
  ARM: 8284/1: sa1100: clear RCSR_SMR on resume
  tracing: Fix unmapping loop in tracing_mark_write
  MIPS: KVM: Deliver guest interrupts after local_irq_disable()
  nfs: don't call blocking operations while !TASK_RUNNING
  mmc: sdhci-pxav3: fix setting of pdata->clk_delay_cycles
  power_supply: 88pm860x: Fix leaked power supply on probe fail
  ALSA: hdspm - Constrain periods to 2 on older cards
  ALSA: off by one bug in snd_riptide_joystick_probe()
  lmedm04: Fix usb_submit_urb BOGUS urb xfer, pipe 1 != type 3 in interrupt urb
  cpufreq: speedstep-smi: enable interrupts when waiting
  PCI: Fix infinite loop with ROM image of size 0
  PCI: Generate uppercase hex for modalias var in uevent
  HID: i2c-hid: Limit reads to wMaxInputLength bytes for input events
  iwlwifi: mvm: always use mac color zero
  iwlwifi: mvm: fix failure path when power_update fails in add_interface
  iwlwifi: mvm: validate tid and sta_id in ba_notif
  iwlwifi: pcie: disable the SCD_BASE_ADDR when we resume from WoWLAN
  fsnotify: fix handling of renames in audit
  xfs: set superblock buffer type correctly
  xfs: inode unlink does not set AGI buffer type
  xfs: ensure buffer types are set correctly
  Bluetooth: ath3k: workaround the compatibility issue with xHCI controller
  Linux 3.10.70
  rbd: drop an unsafe assertion
  media/rc: Send sync space information on the lirc device
  net: sctp: fix passing wrong parameter header to param_type2af in sctp_process_param
  ppp: deflate: never return len larger than output buffer
  ipv4: tcp: get rid of ugly unicast_sock
  tcp: ipv4: initialize unicast_sock sk_pacing_rate
  bridge: dont send notification when skb->len == 0 in rtnl_bridge_notify
  ipv6: replacing a rt6_info needs to purge possible propagated rt6_infos too
  ping: Fix race in free in receive path
  udp_diag: Fix socket skipping within chain
  ipv4: try to cache dst_entries which would cause a redirect
  net: sctp: fix slab corruption from use after free on INIT collisions
  netxen: fix netxen_nic_poll() logic
  ipv6: stop sending PTB packets for MTU < 1280
  net: rps: fix cpu unplug
  ip: zero sockaddr returned on error queue
  Linux 3.10.69
  crypto: crc32c - add missing crypto module alias
  x86,kvm,vmx: Preserve CR4 across VM entry
  kvm: vmx: handle invvpid vm exit gracefully
  smpboot: Add missing get_online_cpus() in smpboot_register_percpu_thread()
  ALSA: ak411x: Fix stall in work callback
  ASoC: sgtl5000: add delay before first I2C access
  ASoC: atmel_ssc_dai: fix start event for I2S mode
  lib/checksum.c: fix build for generic csum_tcpudp_nofold
  ext4: prevent bugon on race between write/fcntl
  arm64: Fix up /proc/cpuinfo
  nilfs2: fix deadlock of segment constructor over I_SYNC flag
  lib/checksum.c: fix carry in csum_tcpudp_nofold
  mm: pagewalk: call pte_hole() for VM_PFNMAP during walk_page_range
  MIPS: Fix kernel lockup or crash after CPU offline/online
  MIPS: IRQ: Fix disable_irq on CPU IRQs
  PCI: Add NEC variants to Stratus ftServer PCIe DMI check
  gpio: sysfs: fix memory leak in gpiod_sysfs_set_active_low
  gpio: sysfs: fix memory leak in gpiod_export_link
  Linux 3.10.68
  target: Drop arbitrary maximum I/O size limit
  iser-target: Fix implicit termination of connections
  iser-target: Handle ADDR_CHANGE event for listener cm_id
  iser-target: Fix connected_handler + teardown flow race
  iser-target: Parallelize CM connection establishment
  iser-target: Fix flush + disconnect completion handling
  iscsi,iser-target: Initiate termination only once
  vhost-scsi: Add missing virtio-scsi -> TCM attribute conversion
  tcm_loop: Fix wrong I_T nexus association
  vhost-scsi: Take configfs group dependency during VHOST_SCSI_SET_ENDPOINT
  ib_isert: Add max_send_sge=2 minimum for control PDU responses
  IB/isert: Adjust CQ size to HW limits
  workqueue: fix subtle pool management issue which can stall whole worker_pool
  gpio: squelch a compiler warning
  efi-pstore: Make efi-pstore return a unique id
  pstore/ram: avoid atomic accesses for ioremapped regions
  pstore: Fix NULL pointer fault if get NULL prz in ramoops_get_next_prz
  pstore: skip zero size persistent ram buffer in traverse
  pstore: clarify clearing of _read_cnt in ramoops_context
  pstore: d_alloc_name() doesn't return an ERR_PTR
  pstore: Fail to unlink if a driver has not defined pstore_erase
  ARM: 8109/1: mm: Modify pte_write and pmd_write logic for LPAE
  ARM: 8108/1: mm: Introduce {pte,pmd}_isset and {pte,pmd}_isclear
  ARM: DMA: ensure that old section mappings are flushed from the TLB
  ARM: 7931/1: Correct virt_addr_valid
  ARM: fix asm/memory.h build error
  ARM: 7867/1: include: asm: use 'int' instead of 'unsigned long' for 'oldval' in atomic_cmpxchg().
  ARM: 7866/1: include: asm: use 'long long' instead of 'u64' within atomic.h
  ARM: lpae: fix definition of PTE_HWTABLE_PTRS
  ARM: fix type of PHYS_PFN_OFFSET to unsigned long
  ARM: LPAE: use phys_addr_t in alloc_init_pud()
  ARM: LPAE: use signed arithmetic for mask definitions
  ARM: mm: correct pte_same behaviour for LPAE.
  ARM: 7829/1: Add ".text.unlikely" and ".text.hot" to arm unwind tables
  drivers: net: cpsw: discard dual emac default vlan configuration
  regulator: core: fix race condition in regulator_put()
  spi/pxa2xx: Clear cur_chip pointer before starting next message
  dm cache: fix missing ERR_PTR returns and handling
  dm thin: don't allow messages to be sent to a pool target in READ_ONLY or FAIL mode
  nl80211: fix per-station group key get/del and memory leak
  NFSv4.1: Fix an Oops in nfs41_walk_client_list
  nfs: fix dio deadlock when O_DIRECT flag is flipped
  Input: i8042 - add noloop quirk for Medion Akoya E7225 (MD98857)
  ALSA: seq-dummy: remove deadlock-causing events on close
  powerpc/xmon: Fix another endiannes issue in RTAS call from xmon
  can: kvaser_usb: Fix state handling upon BUS_ERROR events
  can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT
  can: kvaser_usb: Send correct context to URB completion
  can: kvaser_usb: Do not sleep in atomic context
  ASoC: wm8960: Fix capture sample rate from 11250 to 11025
  spi: dw-mid: fix FIFO size

Signed-off-by: Ian Maund <imaund@codeaurora.org>
2015-04-24 18:14:57 -07:00

490 lines
12 KiB
C

/*
* Intel SpeedStep SMI driver.
*
* (C) 2003 Hiroshi Miura <miura@da-cha.org>
*
* Licensed under the terms of the GNU GPL License version 2.
*
*/
/*********************************************************************
* SPEEDSTEP - DEFINITIONS *
*********************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <asm/ist.h>
#include <asm/cpu_device_id.h>
#include "speedstep-lib.h"
/* speedstep system management interface port/command.
*
* These parameters are got from IST-SMI BIOS call.
* If user gives it, these are used.
*
*/
static int smi_port;
static int smi_cmd;
static unsigned int smi_sig;
/* info about the processor */
static enum speedstep_processor speedstep_processor;
/*
* There are only two frequency states for each processor. Values
* are in kHz for the time being.
*/
static struct cpufreq_frequency_table speedstep_freqs[] = {
{SPEEDSTEP_HIGH, 0},
{SPEEDSTEP_LOW, 0},
{0, CPUFREQ_TABLE_END},
};
#define GET_SPEEDSTEP_OWNER 0
#define GET_SPEEDSTEP_STATE 1
#define SET_SPEEDSTEP_STATE 2
#define GET_SPEEDSTEP_FREQS 4
/* how often shall the SMI call be tried if it failed, e.g. because
* of DMA activity going on? */
#define SMI_TRIES 5
/**
* speedstep_smi_ownership
*/
static int speedstep_smi_ownership(void)
{
u32 command, result, magic, dummy;
u32 function = GET_SPEEDSTEP_OWNER;
unsigned char magic_data[] = "Copyright (c) 1999 Intel Corporation";
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
magic = virt_to_phys(magic_data);
pr_debug("trying to obtain ownership with command %x at port %x\n",
command, smi_port);
__asm__ __volatile__(
"push %%ebp\n"
"out %%al, (%%dx)\n"
"pop %%ebp\n"
: "=D" (result),
"=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy),
"=S" (dummy)
: "a" (command), "b" (function), "c" (0), "d" (smi_port),
"D" (0), "S" (magic)
: "memory"
);
pr_debug("result is %x\n", result);
return result;
}
/**
* speedstep_smi_get_freqs - get SpeedStep preferred & current freq.
* @low: the low frequency value is placed here
* @high: the high frequency value is placed here
*
* Only available on later SpeedStep-enabled systems, returns false results or
* even hangs [cf. bugme.osdl.org # 1422] on earlier systems. Empirical testing
* shows that the latter occurs if !(ist_info.event & 0xFFFF).
*/
static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high)
{
u32 command, result = 0, edi, high_mhz, low_mhz, dummy;
u32 state = 0;
u32 function = GET_SPEEDSTEP_FREQS;
if (!(ist_info.event & 0xFFFF)) {
pr_debug("bug #1422 -- can't read freqs from BIOS\n");
return -ENODEV;
}
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
pr_debug("trying to determine frequencies with command %x at port %x\n",
command, smi_port);
__asm__ __volatile__(
"push %%ebp\n"
"out %%al, (%%dx)\n"
"pop %%ebp"
: "=a" (result),
"=b" (high_mhz),
"=c" (low_mhz),
"=d" (state), "=D" (edi), "=S" (dummy)
: "a" (command),
"b" (function),
"c" (state),
"d" (smi_port), "S" (0), "D" (0)
);
pr_debug("result %x, low_freq %u, high_freq %u\n",
result, low_mhz, high_mhz);
/* abort if results are obviously incorrect... */
if ((high_mhz + low_mhz) < 600)
return -EINVAL;
*high = high_mhz * 1000;
*low = low_mhz * 1000;
return result;
}
/**
* speedstep_get_state - set the SpeedStep state
* @state: processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
*
*/
static int speedstep_get_state(void)
{
u32 function = GET_SPEEDSTEP_STATE;
u32 result, state, edi, command, dummy;
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
pr_debug("trying to determine current setting with command %x "
"at port %x\n", command, smi_port);
__asm__ __volatile__(
"push %%ebp\n"
"out %%al, (%%dx)\n"
"pop %%ebp\n"
: "=a" (result),
"=b" (state), "=D" (edi),
"=c" (dummy), "=d" (dummy), "=S" (dummy)
: "a" (command), "b" (function), "c" (0),
"d" (smi_port), "S" (0), "D" (0)
);
pr_debug("state is %x, result is %x\n", state, result);
return state & 1;
}
/**
* speedstep_set_state - set the SpeedStep state
* @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
*
*/
static void speedstep_set_state(unsigned int state)
{
unsigned int result = 0, command, new_state, dummy;
unsigned long flags;
unsigned int function = SET_SPEEDSTEP_STATE;
unsigned int retry = 0;
if (state > 0x1)
return;
/* Disable IRQs */
preempt_disable();
local_irq_save(flags);
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
pr_debug("trying to set frequency to state %u "
"with command %x at port %x\n",
state, command, smi_port);
do {
if (retry) {
/*
* We need to enable interrupts, otherwise the blockage
* won't resolve.
*
* We disable preemption so that other processes don't
* run. If other processes were running, they could
* submit more DMA requests, making the blockage worse.
*/
pr_debug("retry %u, previous result %u, waiting...\n",
retry, result);
local_irq_enable();
mdelay(retry * 50);
local_irq_disable();
}
retry++;
__asm__ __volatile__(
"push %%ebp\n"
"out %%al, (%%dx)\n"
"pop %%ebp"
: "=b" (new_state), "=D" (result),
"=c" (dummy), "=a" (dummy),
"=d" (dummy), "=S" (dummy)
: "a" (command), "b" (function), "c" (state),
"d" (smi_port), "S" (0), "D" (0)
);
} while ((new_state != state) && (retry <= SMI_TRIES));
/* enable IRQs */
local_irq_restore(flags);
preempt_enable();
if (new_state == state)
pr_debug("change to %u MHz succeeded after %u tries "
"with result %u\n",
(speedstep_freqs[new_state].frequency / 1000),
retry, result);
else
printk(KERN_ERR "cpufreq: change to state %u "
"failed with new_state %u and result %u\n",
state, new_state, result);
return;
}
/**
* speedstep_target - set a new CPUFreq policy
* @policy: new policy
* @target_freq: new freq
* @relation:
*
* Sets a new CPUFreq policy/freq.
*/
static int speedstep_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int relation)
{
unsigned int newstate = 0;
struct cpufreq_freqs freqs;
if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0],
target_freq, relation, &newstate))
return -EINVAL;
freqs.old = speedstep_freqs[speedstep_get_state()].frequency;
freqs.new = speedstep_freqs[newstate].frequency;
if (freqs.old == freqs.new)
return 0;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
speedstep_set_state(newstate);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
/**
* speedstep_verify - verifies a new CPUFreq policy
* @policy: new policy
*
* Limit must be within speedstep_low_freq and speedstep_high_freq, with
* at least one border included.
*/
static int speedstep_verify(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);
}
static int speedstep_cpu_init(struct cpufreq_policy *policy)
{
int result;
unsigned int speed, state;
unsigned int *low, *high;
/* capability check */
if (policy->cpu != 0)
return -ENODEV;
result = speedstep_smi_ownership();
if (result) {
pr_debug("fails in acquiring ownership of a SMI interface.\n");
return -EINVAL;
}
/* detect low and high frequency */
low = &speedstep_freqs[SPEEDSTEP_LOW].frequency;
high = &speedstep_freqs[SPEEDSTEP_HIGH].frequency;
result = speedstep_smi_get_freqs(low, high);
if (result) {
/* fall back to speedstep_lib.c dection mechanism:
* try both states out */
pr_debug("could not detect low and high frequencies "
"by SMI call.\n");
result = speedstep_get_freqs(speedstep_processor,
low, high,
NULL,
&speedstep_set_state);
if (result) {
pr_debug("could not detect two different speeds"
" -- aborting.\n");
return result;
} else
pr_debug("workaround worked.\n");
}
/* get current speed setting */
state = speedstep_get_state();
speed = speedstep_freqs[state].frequency;
pr_debug("currently at %s speed setting - %i MHz\n",
(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency)
? "low" : "high",
(speed / 1000));
/* cpuinfo and default policy values */
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = speed;
result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
if (result)
return result;
cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu);
return 0;
}
static int speedstep_cpu_exit(struct cpufreq_policy *policy)
{
cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
}
static unsigned int speedstep_get(unsigned int cpu)
{
if (cpu)
return -ENODEV;
return speedstep_get_frequency(speedstep_processor);
}
static int speedstep_resume(struct cpufreq_policy *policy)
{
int result = speedstep_smi_ownership();
if (result)
pr_debug("fails in re-acquiring ownership of a SMI interface.\n");
return result;
}
static struct freq_attr *speedstep_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
static struct cpufreq_driver speedstep_driver = {
.name = "speedstep-smi",
.verify = speedstep_verify,
.target = speedstep_target,
.init = speedstep_cpu_init,
.exit = speedstep_cpu_exit,
.get = speedstep_get,
.resume = speedstep_resume,
.attr = speedstep_attr,
};
static const struct x86_cpu_id ss_smi_ids[] = {
{ X86_VENDOR_INTEL, 6, 0xb, },
{ X86_VENDOR_INTEL, 6, 0x8, },
{ X86_VENDOR_INTEL, 15, 2 },
{}
};
#if 0
/* Not auto loaded currently */
MODULE_DEVICE_TABLE(x86cpu, ss_smi_ids);
#endif
/**
* speedstep_init - initializes the SpeedStep CPUFreq driver
*
* Initializes the SpeedStep support. Returns -ENODEV on unsupported
* BIOS, -EINVAL on problems during initiatization, and zero on
* success.
*/
static int __init speedstep_init(void)
{
if (!x86_match_cpu(ss_smi_ids))
return -ENODEV;
speedstep_processor = speedstep_detect_processor();
switch (speedstep_processor) {
case SPEEDSTEP_CPU_PIII_T:
case SPEEDSTEP_CPU_PIII_C:
case SPEEDSTEP_CPU_PIII_C_EARLY:
break;
default:
speedstep_processor = 0;
}
if (!speedstep_processor) {
pr_debug("No supported Intel CPU detected.\n");
return -ENODEV;
}
pr_debug("signature:0x%.8ulx, command:0x%.8ulx, "
"event:0x%.8ulx, perf_level:0x%.8ulx.\n",
ist_info.signature, ist_info.command,
ist_info.event, ist_info.perf_level);
/* Error if no IST-SMI BIOS or no PARM
sig= 'ISGE' aka 'Intel Speedstep Gate E' */
if ((ist_info.signature != 0x47534943) && (
(smi_port == 0) || (smi_cmd == 0)))
return -ENODEV;
if (smi_sig == 1)
smi_sig = 0x47534943;
else
smi_sig = ist_info.signature;
/* setup smi_port from MODLULE_PARM or BIOS */
if ((smi_port > 0xff) || (smi_port < 0))
return -EINVAL;
else if (smi_port == 0)
smi_port = ist_info.command & 0xff;
if ((smi_cmd > 0xff) || (smi_cmd < 0))
return -EINVAL;
else if (smi_cmd == 0)
smi_cmd = (ist_info.command >> 16) & 0xff;
return cpufreq_register_driver(&speedstep_driver);
}
/**
* speedstep_exit - unregisters SpeedStep support
*
* Unregisters SpeedStep support.
*/
static void __exit speedstep_exit(void)
{
cpufreq_unregister_driver(&speedstep_driver);
}
module_param(smi_port, int, 0444);
module_param(smi_cmd, int, 0444);
module_param(smi_sig, uint, 0444);
MODULE_PARM_DESC(smi_port, "Override the BIOS-given IST port with this value "
"-- Intel's default setting is 0xb2");
MODULE_PARM_DESC(smi_cmd, "Override the BIOS-given IST command with this value "
"-- Intel's default setting is 0x82");
MODULE_PARM_DESC(smi_sig, "Set to 1 to fake the IST signature when using the "
"SMI interface.");
MODULE_AUTHOR("Hiroshi Miura");
MODULE_DESCRIPTION("Speedstep driver for IST applet SMI interface.");
MODULE_LICENSE("GPL");
module_init(speedstep_init);
module_exit(speedstep_exit);