Commit bc0b0607 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/net-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents bdeccb51 9facb9b8
...@@ -54,13 +54,16 @@ NET_Y := $(patsubst %/, %/built-in.o, $(net-y)) ...@@ -54,13 +54,16 @@ NET_Y := $(patsubst %/, %/built-in.o, $(net-y))
LIBS_Y := $(patsubst %/, %/lib.a, $(libs-y)) LIBS_Y := $(patsubst %/, %/lib.a, $(libs-y))
export INIT_Y CORE_Y DRIVERS_Y NET_Y LIBS_Y HEAD_Y export INIT_Y CORE_Y DRIVERS_Y NET_Y LIBS_Y HEAD_Y
makeboot =$(Q)$(MAKE) -f scripts/Makefile.build obj=arch/$(ARCH)/boot $(1) # Default target
all: image
boot := arch/sparc/boot
image tftpboot.img: vmlinux image tftpboot.img: vmlinux
$(call makeboot,arch/sparc/boot/$@) $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
archclean: archclean:
$(Q)$(MAKE) -f scripts/Makefile.clean obj=arch/$(ARCH)/boot $(Q)$(MAKE) $(clean)=$(boot)
prepare: include/asm-$(ARCH)/asm_offsets.h prepare: include/asm-$(ARCH)/asm_offsets.h
...@@ -72,3 +75,9 @@ include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s ...@@ -72,3 +75,9 @@ include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s
CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h \ CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h \
arch/$(ARCH)/kernel/asm-offsets.s arch/$(ARCH)/kernel/asm-offsets.s
# Don't use tabs in echo arguments.
define archhelp
echo '* image - kernel image ($(boot)/image)'
echo ' tftpboot.img - image prepared for tftp'
endef
...@@ -32,7 +32,3 @@ $(obj)/tftpboot.img: $(obj)/piggyback $(obj)/System.map $(obj)/image FORCE ...@@ -32,7 +32,3 @@ $(obj)/tftpboot.img: $(obj)/piggyback $(obj)/System.map $(obj)/image FORCE
$(obj)/btfix.s: $(obj)/btfixupprep vmlinux FORCE $(obj)/btfix.s: $(obj)/btfixupprep vmlinux FORCE
$(call if_changed,btfix) $(call if_changed,btfix)
archhelp:
@echo '* image - kernel image ($(obj)/image)'
@echo ' tftpboot.img - image prepared for tftp'
...@@ -139,8 +139,8 @@ config CPU_FREQ ...@@ -139,8 +139,8 @@ config CPU_FREQ
bool "CPU Frequency scaling" bool "CPU Frequency scaling"
help help
Clock scaling allows you to change the clock speed of CPUs on the Clock scaling allows you to change the clock speed of CPUs on the
fly. Currently there is only a sparc64 driver for UltraSPARC-III fly. Currently there are only sparc64 drivers for UltraSPARC-III
processors. and UltraSPARC-IIe processors.
For details, take a look at linux/Documentation/cpufreq. For details, take a look at linux/Documentation/cpufreq.
...@@ -166,6 +166,16 @@ config US3_FREQ ...@@ -166,6 +166,16 @@ config US3_FREQ
If in doubt, say N. If in doubt, say N.
config US2E_FREQ
tristate "UltraSPARC-IIe CPU Frequency driver"
depends on CPU_FREQ_TABLE
help
This adds the CPUFreq driver for UltraSPARC-IIe processors.
For details, take a look at linux/Documentation/cpufreq.
If in doubt, say N.
source "drivers/cpufreq/Kconfig" source "drivers/cpufreq/Kconfig"
# Identify this as a Sparc64 build # Identify this as a Sparc64 build
......
...@@ -71,10 +71,13 @@ libs-y += arch/sparc64/prom/ arch/sparc64/lib/ ...@@ -71,10 +71,13 @@ libs-y += arch/sparc64/prom/ arch/sparc64/lib/
# FIXME: is drivers- right? # FIXME: is drivers- right?
drivers-$(CONFIG_OPROFILE) += arch/sparc64/oprofile/ drivers-$(CONFIG_OPROFILE) += arch/sparc64/oprofile/
makeboot = $(Q)$(MAKE) -f scripts/Makefile.build obj=arch/$(ARCH)/boot $(1) boot := arch/sparc64/boot
image tftpboot.img vmlinux.aout: vmlinux image tftpboot.img vmlinux.aout: vmlinux
$(call makeboot,arch/sparc64/boot/$@) $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
define archhelp define archhelp
echo '* vmlinux - Standard sparc64 kernel' echo '* vmlinux - Standard sparc64 kernel'
......
...@@ -8,7 +8,7 @@ ROOT_IMG := /usr/src/root.img ...@@ -8,7 +8,7 @@ ROOT_IMG := /usr/src/root.img
ELFTOAOUT := elftoaout ELFTOAOUT := elftoaout
host-progs := piggyback host-progs := piggyback
targets := tftpboot.img vmlinux.aout targets := image tftpboot.img vmlinux.aout
quiet_cmd_elftoaout = ELT2AOUT $@ quiet_cmd_elftoaout = ELT2AOUT $@
cmd_elftoaout = $(ELFTOAOUT) vmlinux -o $@ cmd_elftoaout = $(ELFTOAOUT) vmlinux -o $@
......
...@@ -21,6 +21,7 @@ obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o ...@@ -21,6 +21,7 @@ obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o
obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
ifdef CONFIG_SUNOS_EMUL ifdef CONFIG_SUNOS_EMUL
obj-y += sys_sunos32.o sunos_ioctl32.o obj-y += sys_sunos32.o sunos_ioctl32.o
......
...@@ -152,7 +152,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) ...@@ -152,7 +152,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
#ifdef CONFIG_BINFMT_ELF32_MODULE #ifdef CONFIG_BINFMT_ELF32_MODULE
#define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE #define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
#endif #endif
#define ELF_FLAGS_INIT set_thread_flag(TIF_32BIT)
MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra"); MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra");
MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek"); MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek");
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/spitfire.h> #include <asm/spitfire.h>
#include <asm/timer.h>
/* Used to synchronize acceses to NatSemi SUPER I/O chip configure /* Used to synchronize acceses to NatSemi SUPER I/O chip configure
* operations in asm/ns87303.h * operations in asm/ns87303.h
...@@ -88,7 +89,6 @@ void __init device_scan(void) ...@@ -88,7 +89,6 @@ void __init device_scan(void)
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
{ {
extern unsigned long up_clock_tick;
up_clock_tick = prom_getintdefault(prom_node_cpu, up_clock_tick = prom_getintdefault(prom_node_cpu,
"clock-frequency", "clock-frequency",
0); 0);
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <asm/starfire.h> #include <asm/starfire.h>
#include <asm/hardirq.h> #include <asm/hardirq.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/timer.h>
#ifdef CONFIG_IP_PNP #ifdef CONFIG_IP_PNP
#include <net/ipconfig.h> #include <net/ipconfig.h>
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#endif #endif
#include <asm/a.out.h> #include <asm/a.out.h>
#include <asm/ns87303.h> #include <asm/ns87303.h>
#include <asm/timer.h>
struct poll { struct poll {
int fd; int fd;
...@@ -159,11 +160,7 @@ EXPORT_SYMBOL(_do_write_unlock); ...@@ -159,11 +160,7 @@ EXPORT_SYMBOL(_do_write_unlock);
EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_call_function);
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
/* Uniprocessor clock frequency */ EXPORT_SYMBOL(sparc64_get_clock_tick);
#ifndef CONFIG_SMP
extern unsigned long up_clock_tick;
EXPORT_SYMBOL(up_clock_tick);
#endif
/* semaphores */ /* semaphores */
EXPORT_SYMBOL(down); EXPORT_SYMBOL(down);
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include <linux/profile.h> #include <linux/profile.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/cpufreq.h>
#include <linux/percpu.h>
#include <asm/oplib.h> #include <asm/oplib.h>
#include <asm/mostek.h> #include <asm/mostek.h>
...@@ -988,6 +990,73 @@ static unsigned long sparc64_init_timers(void (*cfunc)(int, void *, struct pt_re ...@@ -988,6 +990,73 @@ static unsigned long sparc64_init_timers(void (*cfunc)(int, void *, struct pt_re
return clock; return clock;
} }
struct freq_table {
unsigned long udelay_val_ref;
unsigned long clock_tick_ref;
unsigned int ref_freq;
};
static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0, 0 };
unsigned long sparc64_get_clock_tick(unsigned int cpu)
{
struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu);
if (ft->clock_tick_ref)
return ft->clock_tick_ref;
#ifdef CONFIG_SMP
return cpu_data[cpu].clock_tick;
#else
return up_clock_tick;
#endif
}
#ifdef CONFIG_CPU_FREQ
static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct cpufreq_freqs *freq = data;
unsigned int cpu = freq->cpu;
struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu);
#ifdef CONFIG_SMP
if (!ft->ref_freq) {
ft->ref_freq = freq->old;
ft->udelay_val_ref = cpu_data[cpu].udelay_val;
ft->clock_tick_ref = cpu_data[cpu].clock_tick;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
cpu_data[cpu].udelay_val =
cpufreq_scale(ft->udelay_val_ref,
ft->ref_freq,
freq->new);
cpu_data[cpu].clock_tick =
cpufreq_scale(ft->clock_tick_ref,
ft->ref_freq,
freq->new);
}
#else
/* In the non-SMP case, kernel/cpufreq.c takes care of adjusting
* loops_per_jiffy.
*/
if (!ft->ref_freq) {
ft->ref_freq = freq->old;
ft->clock_tick_ref = up_clock_tick;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new))
up_clock_tick = cpufreq_scale(ft->clock_tick_ref, ft->ref_freq, freq->new);
#endif
return 0;
}
static struct notifier_block sparc64_cpufreq_notifier_block = {
.notifier_call = sparc64_cpufreq_notifier
};
#endif
/* The quotient formula is taken from the IA64 port. */ /* The quotient formula is taken from the IA64 port. */
void __init time_init(void) void __init time_init(void)
{ {
...@@ -996,6 +1065,11 @@ void __init time_init(void) ...@@ -996,6 +1065,11 @@ void __init time_init(void)
timer_ticks_per_usec_quotient = timer_ticks_per_usec_quotient =
(((1000000UL << 30) + (((1000000UL << 30) +
(clock / 2)) / clock); (clock / 2)) / clock);
#ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&sparc64_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
#endif
} }
static __inline__ unsigned long do_gettimeoffset(void) static __inline__ unsigned long do_gettimeoffset(void)
......
/* us2e_cpufreq.c: UltraSPARC-IIe cpu frequency support
*
* Copyright (C) 2003 David S. Miller (davem@redhat.com)
*
* Many thanks to Dominik Brodowski for fixing up the cpufreq
* infrastructure in order to make this driver easier to implement.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/cpufreq.h>
#include <linux/threads.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <asm/asi.h>
#include <asm/timer.h>
static struct cpufreq_driver *cpufreq_us2e_driver;
struct us2e_freq_percpu_info {
struct cpufreq_frequency_table table[6];
};
/* Indexed by cpu number. */
static struct us2e_freq_percpu_info *us2e_freq_table;
#define HBIRD_MEM_CNTL0_ADDR 0x1fe0000f010UL
#define HBIRD_ESTAR_MODE_ADDR 0x1fe0000f080UL
/* UltraSPARC-IIe has five dividers: 1, 2, 4, 6, and 8. These are controlled
* in the ESTAR mode control register.
*/
#define ESTAR_MODE_DIV_1 0x0000000000000000UL
#define ESTAR_MODE_DIV_2 0x0000000000000001UL
#define ESTAR_MODE_DIV_4 0x0000000000000003UL
#define ESTAR_MODE_DIV_6 0x0000000000000002UL
#define ESTAR_MODE_DIV_8 0x0000000000000004UL
#define ESTAR_MODE_DIV_MASK 0x0000000000000007UL
#define MCTRL0_SREFRESH_ENAB 0x0000000000010000UL
#define MCTRL0_REFR_COUNT_MASK 0x0000000000007f00UL
#define MCTRL0_REFR_COUNT_SHIFT 8
#define MCTRL0_REFR_INTERVAL 7800
#define MCTRL0_REFR_CLKS_P_CNT 64
static unsigned long read_hbreg(unsigned long addr)
{
unsigned long ret;
__asm__ __volatile__("ldxa [%1] %2, %0"
: "=&r" (ret)
: "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
return ret;
}
static void write_hbreg(unsigned long addr, unsigned long val)
{
__asm__ __volatile__("stxa %0, [%1] %2\n\t"
"membar #Sync"
: /* no outputs */
: "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E)
: "memory");
if (addr == HBIRD_ESTAR_MODE_ADDR) {
/* Need to wait 16 clock cycles for the PLL to lock. */
udelay(1);
}
}
static void self_refresh_ctl(int enable)
{
unsigned long mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
if (enable)
mctrl |= MCTRL0_SREFRESH_ENAB;
else
mctrl &= ~MCTRL0_SREFRESH_ENAB;
write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl);
(void) read_hbreg(HBIRD_MEM_CNTL0_ADDR);
}
static void frob_mem_refresh(int cpu_slowing_down,
unsigned long clock_tick,
unsigned long old_divisor, unsigned long divisor)
{
unsigned long old_refr_count, refr_count, mctrl;
refr_count = (clock_tick * MCTRL0_REFR_INTERVAL);
refr_count /= (MCTRL0_REFR_CLKS_P_CNT * divisor * 1000000000UL);
mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
old_refr_count = (mctrl & MCTRL0_REFR_COUNT_MASK)
>> MCTRL0_REFR_COUNT_SHIFT;
mctrl &= ~MCTRL0_REFR_COUNT_MASK;
mctrl |= refr_count << MCTRL0_REFR_COUNT_SHIFT;
write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl);
mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR);
if (cpu_slowing_down && !(mctrl & MCTRL0_SREFRESH_ENAB)) {
unsigned long usecs;
/* We have to wait for both refresh counts (old
* and new) to go to zero.
*/
usecs = (MCTRL0_REFR_CLKS_P_CNT *
(refr_count + old_refr_count) *
1000000UL *
old_divisor) / clock_tick;
udelay(usecs + 1UL);
}
}
static void us2e_transition(unsigned long estar, unsigned long new_bits,
unsigned long clock_tick,
unsigned long old_divisor, unsigned long divisor)
{
unsigned long flags;
local_irq_save(flags);
estar &= ~ESTAR_MODE_DIV_MASK;
/* This is based upon the state transition diagram in the IIe manual. */
if (old_divisor == 2 && divisor == 1) {
self_refresh_ctl(0);
write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
frob_mem_refresh(0, clock_tick, old_divisor, divisor);
} else if (old_divisor == 1 && divisor == 2) {
frob_mem_refresh(1, clock_tick, old_divisor, divisor);
write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
self_refresh_ctl(1);
} else if (old_divisor == 1 && divisor > 2) {
us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick,
1, 2);
us2e_transition(estar, new_bits, clock_tick,
2, divisor);
} else if (old_divisor > 2 && divisor == 1) {
us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick,
old_divisor, 2);
us2e_transition(estar, new_bits, clock_tick,
2, divisor);
} else if (old_divisor < divisor) {
frob_mem_refresh(0, clock_tick, old_divisor, divisor);
write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
} else if (old_divisor > divisor) {
write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits);
frob_mem_refresh(1, clock_tick, old_divisor, divisor);
} else {
BUG();
}
local_irq_restore(flags);
}
static unsigned long index_to_estar_mode(unsigned int index)
{
switch (index) {
case 0:
return ESTAR_MODE_DIV_1;
case 1:
return ESTAR_MODE_DIV_2;
case 2:
return ESTAR_MODE_DIV_4;
case 3:
return ESTAR_MODE_DIV_6;
case 4:
return ESTAR_MODE_DIV_8;
default:
BUG();
};
}
static unsigned long index_to_divisor(unsigned int index)
{
switch (index) {
case 0:
return 1;
case 1:
return 2;
case 2:
return 4;
case 3:
return 6;
case 4:
return 8;
default:
BUG();
};
}
static unsigned long estar_to_divisor(unsigned long estar)
{
unsigned long ret;
switch (estar & ESTAR_MODE_DIV_MASK) {
case ESTAR_MODE_DIV_1:
ret = 1;
break;
case ESTAR_MODE_DIV_2:
ret = 2;
break;
case ESTAR_MODE_DIV_4:
ret = 4;
break;
case ESTAR_MODE_DIV_6:
ret = 6;
break;
case ESTAR_MODE_DIV_8:
ret = 8;
break;
default:
BUG();
};
return ret;
}
static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index)
{
unsigned long new_bits, new_freq, cpus_allowed;
unsigned long clock_tick, divisor, old_divisor, estar;
struct cpufreq_freqs freqs;
if (!cpu_online(cpu))
return;
cpus_allowed = current->cpus_allowed;
set_cpus_allowed(current, (1UL << cpu));
new_freq = clock_tick = sparc64_get_clock_tick(cpu);
new_bits = index_to_estar_mode(index);
divisor = index_to_divisor(index);
new_freq /= divisor;
estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR);
old_divisor = estar_to_divisor(estar);
freqs.old = clock_tick / old_divisor;
freqs.new = new_freq;
freqs.cpu = cpu;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
us2e_transition(estar, new_bits, clock_tick, old_divisor, divisor);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
set_cpus_allowed(current, cpus_allowed);
}
static int us2e_freq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int new_index = 0;
if (cpufreq_frequency_table_target(policy,
&us2e_freq_table[policy->cpu].table[0],
target_freq,
relation,
&new_index))
return -EINVAL;
us2e_set_cpu_divider_index(policy->cpu, new_index);
return 0;
}
static int us2e_freq_verify(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy,
&us2e_freq_table[policy->cpu].table[0]);
}
static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
{
unsigned int cpu = policy->cpu;
unsigned long clock_tick = sparc64_get_clock_tick(cpu);
struct cpufreq_frequency_table *table =
&us2e_freq_table[cpu].table[0];
table[0].index = 0;
table[0].frequency = clock_tick / 1;
table[1].index = 1;
table[1].frequency = clock_tick / 2;
table[2].index = 2;
table[2].frequency = clock_tick / 4;
table[2].index = 3;
table[2].frequency = clock_tick / 6;
table[2].index = 4;
table[2].frequency = clock_tick / 8;
table[2].index = 5;
table[3].frequency = CPUFREQ_TABLE_END;
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
policy->cpuinfo.transition_latency = 0;
policy->cur = clock_tick;
return cpufreq_frequency_table_cpuinfo(policy, table);
}
static int __exit us2e_freq_cpu_exit(struct cpufreq_policy *policy)
{
if (cpufreq_us2e_driver)
us2e_set_cpu_divider_index(policy->cpu, 0);
return 0;
}
static int __init us2e_freq_init(void)
{
unsigned long manuf, impl, ver;
int ret;
__asm__("rdpr %%ver, %0" : "=r" (ver));
manuf = ((ver >> 48) & 0xffff);
impl = ((ver >> 32) & 0xffff);
if (manuf == 0x17 && impl == 0x13) {
struct cpufreq_driver *driver;
ret = -ENOMEM;
driver = kmalloc(sizeof(struct cpufreq_driver), GFP_KERNEL);
if (!driver)
goto err_out;
memset(driver, 0, sizeof(*driver));
us2e_freq_table = kmalloc(
(NR_CPUS * sizeof(struct us2e_freq_percpu_info)),
GFP_KERNEL);
if (!us2e_freq_table)
goto err_out;
memset(us2e_freq_table, 0,
(NR_CPUS * sizeof(struct us2e_freq_percpu_info)));
driver->verify = us2e_freq_verify;
driver->target = us2e_freq_target;
driver->init = us2e_freq_cpu_init;
driver->exit = us2e_freq_cpu_exit;
driver->owner = THIS_MODULE,
strcpy(driver->name, "UltraSPARC-IIe");
cpufreq_us2e_driver = driver;
ret = cpufreq_register_driver(driver);
if (ret)
goto err_out;
return 0;
err_out:
if (driver) {
kfree(driver);
cpufreq_us2e_driver = NULL;
}
if (us2e_freq_table) {
kfree(us2e_freq_table);
us2e_freq_table = NULL;
}
return ret;
}
return -ENODEV;
}
static void __exit us2e_freq_exit(void)
{
if (cpufreq_us2e_driver) {
cpufreq_unregister_driver(cpufreq_us2e_driver);
kfree(cpufreq_us2e_driver);
cpufreq_us2e_driver = NULL;
kfree(us2e_freq_table);
us2e_freq_table = NULL;
}
}
MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-IIe");
MODULE_LICENSE("GPL");
module_init(us2e_freq_init);
module_exit(us2e_freq_exit);
...@@ -16,14 +16,12 @@ ...@@ -16,14 +16,12 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/head.h> #include <asm/head.h>
#include <asm/timer.h>
static struct cpufreq_driver *cpufreq_us3_driver; static struct cpufreq_driver *cpufreq_us3_driver;
struct us3_freq_percpu_info { struct us3_freq_percpu_info {
struct cpufreq_frequency_table table[4]; struct cpufreq_frequency_table table[4];
unsigned long udelay_val_ref;
unsigned long clock_tick_ref;
unsigned int ref_freq;
}; };
/* Indexed by cpu number. */ /* Indexed by cpu number. */
...@@ -56,71 +54,9 @@ static void write_safari_cfg(unsigned long val) ...@@ -56,71 +54,9 @@ static void write_safari_cfg(unsigned long val)
: "memory"); : "memory");
} }
#ifndef CONFIG_SMP
extern unsigned long up_clock_tick;
unsigned long clock_tick_ref;
unsigned int ref_freq;
#endif
static __inline__ unsigned long get_clock_tick(unsigned int cpu)
{
#ifdef CONFIG_SMP
if (us3_freq_table[cpu].clock_tick_ref)
return us3_freq_table[cpu].clock_tick_ref;
return cpu_data[cpu].clock_tick;
#else
if (clock_tick_ref)
return clock_tick_ref;
return up_clock_tick;
#endif
}
static int us3_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct cpufreq_freqs *freq = data;
#ifdef CONFIG_SMP
unsigned int cpu = freq->cpu;
if (!us3_freq_table[cpu].ref_freq) {
us3_freq_table[cpu].ref_freq = freq->old;
us3_freq_table[cpu].udelay_val_ref = cpu_data[cpu].udelay_val;
us3_freq_table[cpu].clock_tick_ref = cpu_data[cpu].clock_tick;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
cpu_data[cpu].udelay_val =
cpufreq_scale(us3_freq_table[cpu].udelay_val_ref,
us3_freq_table[cpu].ref_freq,
freq->new);
cpu_data[cpu].clock_tick =
cpufreq_scale(us3_freq_table[cpu].clock_tick_ref,
us3_freq_table[cpu].ref_freq,
freq->new);
}
#else
/* In the non-SMP case, kernel/cpufreq.c takes care of adjusting
* loops_per_jiffy.
*/
if (!ref_freq) {
ref_freq = freq->old;
clock_tick_ref = up_clock_tick;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new))
up_clock_tick = cpufreq_scale(clock_tick_ref, ref_freq, freq->new);
#endif
return 0;
}
static struct notifier_block us3_cpufreq_notifier_block = {
.notifier_call = us3_cpufreq_notifier
};
static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg) static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg)
{ {
unsigned long clock_tick = get_clock_tick(cpu); unsigned long clock_tick = sparc64_get_clock_tick(cpu);
unsigned long ret; unsigned long ret;
switch (safari_cfg & SAFARI_CFG_DIV_MASK) { switch (safari_cfg & SAFARI_CFG_DIV_MASK) {
...@@ -151,7 +87,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) ...@@ -151,7 +87,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index)
cpus_allowed = current->cpus_allowed; cpus_allowed = current->cpus_allowed;
set_cpus_allowed(current, (1UL << cpu)); set_cpus_allowed(current, (1UL << cpu));
new_freq = get_clock_tick(cpu); new_freq = sparc64_get_clock_tick(cpu);
switch (index) { switch (index) {
case 0: case 0:
new_bits = SAFARI_CFG_DIV_1; new_bits = SAFARI_CFG_DIV_1;
...@@ -186,17 +122,17 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) ...@@ -186,17 +122,17 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index)
set_cpus_allowed(current, cpus_allowed); set_cpus_allowed(current, cpus_allowed);
} }
static int us3freq_target(struct cpufreq_policy *policy, static int us3_freq_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int target_freq,
unsigned int relation) unsigned int relation)
{ {
unsigned int new_index = 0; unsigned int new_index = 0;
if (cpufreq_frequency_table_target(policy, if (cpufreq_frequency_table_target(policy,
&us3_freq_table[policy->cpu].table[0], &us3_freq_table[policy->cpu].table[0],
target_freq, target_freq,
relation, relation,
&new_index)) &new_index))
return -EINVAL; return -EINVAL;
us3_set_cpu_divider_index(policy->cpu, new_index); us3_set_cpu_divider_index(policy->cpu, new_index);
...@@ -204,16 +140,16 @@ static int us3freq_target(struct cpufreq_policy *policy, ...@@ -204,16 +140,16 @@ static int us3freq_target(struct cpufreq_policy *policy,
return 0; return 0;
} }
static int us3freq_verify(struct cpufreq_policy *policy) static int us3_freq_verify(struct cpufreq_policy *policy)
{ {
return cpufreq_frequency_table_verify(policy, return cpufreq_frequency_table_verify(policy,
&us3_freq_table[policy->cpu].table[0]); &us3_freq_table[policy->cpu].table[0]);
} }
static int __init us3freq_cpu_init(struct cpufreq_policy *policy) static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
{ {
unsigned int cpu = policy->cpu; unsigned int cpu = policy->cpu;
unsigned long clock_tick = get_clock_tick(cpu); unsigned long clock_tick = sparc64_get_clock_tick(cpu);
struct cpufreq_frequency_table *table = struct cpufreq_frequency_table *table =
&us3_freq_table[cpu].table[0]; &us3_freq_table[cpu].table[0];
...@@ -233,7 +169,7 @@ static int __init us3freq_cpu_init(struct cpufreq_policy *policy) ...@@ -233,7 +169,7 @@ static int __init us3freq_cpu_init(struct cpufreq_policy *policy)
return cpufreq_frequency_table_cpuinfo(policy, table); return cpufreq_frequency_table_cpuinfo(policy, table);
} }
static int __exit us3freq_cpu_exit(struct cpufreq_policy *policy) static int __exit us3_freq_cpu_exit(struct cpufreq_policy *policy)
{ {
if (cpufreq_us3_driver) if (cpufreq_us3_driver)
us3_set_cpu_divider_index(policy->cpu, 0); us3_set_cpu_divider_index(policy->cpu, 0);
...@@ -241,7 +177,7 @@ static int __exit us3freq_cpu_exit(struct cpufreq_policy *policy) ...@@ -241,7 +177,7 @@ static int __exit us3freq_cpu_exit(struct cpufreq_policy *policy)
return 0; return 0;
} }
static int __init us3freq_init(void) static int __init us3_freq_init(void)
{ {
unsigned long manuf, impl, ver; unsigned long manuf, impl, ver;
int ret; int ret;
...@@ -254,9 +190,6 @@ static int __init us3freq_init(void) ...@@ -254,9 +190,6 @@ static int __init us3freq_init(void)
(impl == CHEETAH_IMPL || impl == CHEETAH_PLUS_IMPL)) { (impl == CHEETAH_IMPL || impl == CHEETAH_PLUS_IMPL)) {
struct cpufreq_driver *driver; struct cpufreq_driver *driver;
cpufreq_register_notifier(&us3_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
ret = -ENOMEM; ret = -ENOMEM;
driver = kmalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); driver = kmalloc(sizeof(struct cpufreq_driver), GFP_KERNEL);
if (!driver) if (!driver)
...@@ -272,10 +205,10 @@ static int __init us3freq_init(void) ...@@ -272,10 +205,10 @@ static int __init us3freq_init(void)
memset(us3_freq_table, 0, memset(us3_freq_table, 0,
(NR_CPUS * sizeof(struct us3_freq_percpu_info))); (NR_CPUS * sizeof(struct us3_freq_percpu_info)));
driver->verify = us3freq_verify; driver->verify = us3_freq_verify;
driver->target = us3freq_target; driver->target = us3_freq_target;
driver->init = us3freq_cpu_init; driver->init = us3_freq_cpu_init;
driver->exit = us3freq_cpu_exit; driver->exit = us3_freq_cpu_exit;
driver->owner = THIS_MODULE, driver->owner = THIS_MODULE,
strcpy(driver->name, "UltraSPARC-III"); strcpy(driver->name, "UltraSPARC-III");
...@@ -295,20 +228,16 @@ static int __init us3freq_init(void) ...@@ -295,20 +228,16 @@ static int __init us3freq_init(void)
kfree(us3_freq_table); kfree(us3_freq_table);
us3_freq_table = NULL; us3_freq_table = NULL;
} }
cpufreq_unregister_notifier(&us3_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
return ret; return ret;
} }
return -ENODEV; return -ENODEV;
} }
static void __exit us3freq_exit(void) static void __exit us3_freq_exit(void)
{ {
if (cpufreq_us3_driver) { if (cpufreq_us3_driver) {
cpufreq_unregister_driver(cpufreq_us3_driver); cpufreq_unregister_driver(cpufreq_us3_driver);
cpufreq_unregister_notifier(&us3_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
kfree(cpufreq_us3_driver); kfree(cpufreq_us3_driver);
cpufreq_us3_driver = NULL; cpufreq_us3_driver = NULL;
...@@ -321,5 +250,5 @@ MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); ...@@ -321,5 +250,5 @@ MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-III"); MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-III");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(us3freq_init); module_init(us3_freq_init);
module_exit(us3freq_exit); module_exit(us3_freq_exit);
...@@ -11,4 +11,4 @@ obj-y := PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \ ...@@ -11,4 +11,4 @@ obj-y := PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \
VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \
VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \ VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \
dec_and_lock.o U3memcpy.o U3copy_from_user.o U3copy_to_user.o \ dec_and_lock.o U3memcpy.o U3copy_from_user.o U3copy_to_user.o \
U3copy_in_user.o mcount.o ipcsum.o U3copy_in_user.o mcount.o ipcsum.o rwsem.o
/* rwsem.c: Don't inline expand these suckers all over the place.
*
* Written by David S. Miller (davem@redhat.com), 2001.
* Derived from asm-i386/rwsem.h
*/
#include <linux/kernel.h>
#include <linux/rwsem.h>
#include <linux/module.h>
extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem));
extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem));
extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *));
extern struct rw_semaphore *FASTCALL(rwsem_downgrade_wake(struct rw_semaphore *));
void __down_read(struct rw_semaphore *sem)
{
__asm__ __volatile__(
"! beginning __down_read\n"
"1:\tlduw [%0], %%g5\n\t"
"add %%g5, 1, %%g7\n\t"
"cas [%0], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" add %%g7, 1, %%g7\n\t"
"cmp %%g7, 0\n\t"
"bl,pn %%icc, 3f\n\t"
" membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tmov %0, %%g5\n\t"
"save %%sp, -160, %%sp\n\t"
"mov %%g1, %%l1\n\t"
"mov %%g2, %%l2\n\t"
"mov %%g3, %%l3\n\t"
"call %1\n\t"
" mov %%g5, %%o0\n\t"
"mov %%l1, %%g1\n\t"
"mov %%l2, %%g2\n\t"
"ba,pt %%xcc, 2b\n\t"
" restore %%l3, %%g0, %%g3\n\t"
".previous\n\t"
"! ending __down_read"
: : "r" (sem), "i" (rwsem_down_read_failed)
: "g5", "g7", "memory", "cc");
}
EXPORT_SYMBOL(__down_read);
int __down_read_trylock(struct rw_semaphore *sem)
{
int result;
__asm__ __volatile__(
"! beginning __down_read_trylock\n"
"1:\tlduw [%1], %%g5\n\t"
"add %%g5, 1, %%g7\n\t"
"cmp %%g7, 0\n\t"
"bl,pn %%icc, 2f\n\t"
" mov 0, %0\n\t"
"cas [%1], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" mov 1, %0\n\t"
"membar #StoreLoad | #StoreStore\n"
"2:\n\t"
"! ending __down_read_trylock"
: "=&r" (result)
: "r" (sem)
: "g5", "g7", "memory", "cc");
return result;
}
EXPORT_SYMBOL(__down_read_trylock);
void __down_write(struct rw_semaphore *sem)
{
__asm__ __volatile__(
"! beginning __down_write\n\t"
"sethi %%hi(%2), %%g1\n\t"
"or %%g1, %%lo(%2), %%g1\n"
"1:\tlduw [%0], %%g5\n\t"
"add %%g5, %%g1, %%g7\n\t"
"cas [%0], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" cmp %%g7, 0\n\t"
"bne,pn %%icc, 3f\n\t"
" membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tmov %0, %%g5\n\t"
"save %%sp, -160, %%sp\n\t"
"mov %%g2, %%l2\n\t"
"mov %%g3, %%l3\n\t"
"call %1\n\t"
" mov %%g5, %%o0\n\t"
"mov %%l2, %%g2\n\t"
"ba,pt %%xcc, 2b\n\t"
" restore %%l3, %%g0, %%g3\n\t"
".previous\n\t"
"! ending __down_write"
: : "r" (sem), "i" (rwsem_down_write_failed),
"i" (RWSEM_ACTIVE_WRITE_BIAS)
: "g1", "g5", "g7", "memory", "cc");
}
EXPORT_SYMBOL(__down_write);
int __down_write_trylock(struct rw_semaphore *sem)
{
int result;
__asm__ __volatile__(
"! beginning __down_write_trylock\n\t"
"sethi %%hi(%2), %%g1\n\t"
"or %%g1, %%lo(%2), %%g1\n"
"1:\tlduw [%1], %%g5\n\t"
"cmp %%g5, 0\n\t"
"bne,pn %%icc, 2f\n\t"
" mov 0, %0\n\t"
"add %%g5, %%g1, %%g7\n\t"
"cas [%1], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" mov 1, %0\n\t"
"membar #StoreLoad | #StoreStore\n"
"2:\n\t"
"! ending __down_write_trylock"
: "=&r" (result)
: "r" (sem), "i" (RWSEM_ACTIVE_WRITE_BIAS)
: "g1", "g5", "g7", "memory", "cc");
return result;
}
EXPORT_SYMBOL(__down_write_trylock);
void __up_read(struct rw_semaphore *sem)
{
__asm__ __volatile__(
"! beginning __up_read\n\t"
"1:\tlduw [%0], %%g5\n\t"
"sub %%g5, 1, %%g7\n\t"
"cas [%0], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" cmp %%g7, 0\n\t"
"bl,pn %%icc, 3f\n\t"
" membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tsethi %%hi(%2), %%g1\n\t"
"sub %%g7, 1, %%g7\n\t"
"or %%g1, %%lo(%2), %%g1\n\t"
"andcc %%g7, %%g1, %%g0\n\t"
"bne,pn %%icc, 2b\n\t"
" mov %0, %%g5\n\t"
"save %%sp, -160, %%sp\n\t"
"mov %%g2, %%l2\n\t"
"mov %%g3, %%l3\n\t"
"call %1\n\t"
" mov %%g5, %%o0\n\t"
"mov %%l2, %%g2\n\t"
"ba,pt %%xcc, 2b\n\t"
" restore %%l3, %%g0, %%g3\n\t"
".previous\n\t"
"! ending __up_read"
: : "r" (sem), "i" (rwsem_wake),
"i" (RWSEM_ACTIVE_MASK)
: "g1", "g5", "g7", "memory", "cc");
}
EXPORT_SYMBOL(__up_read);
void __up_write(struct rw_semaphore *sem)
{
__asm__ __volatile__(
"! beginning __up_write\n\t"
"sethi %%hi(%2), %%g1\n\t"
"or %%g1, %%lo(%2), %%g1\n"
"1:\tlduw [%0], %%g5\n\t"
"sub %%g5, %%g1, %%g7\n\t"
"cas [%0], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" sub %%g7, %%g1, %%g7\n\t"
"cmp %%g7, 0\n\t"
"bl,pn %%icc, 3f\n\t"
" membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tmov %0, %%g5\n\t"
"save %%sp, -160, %%sp\n\t"
"mov %%g2, %%l2\n\t"
"mov %%g3, %%l3\n\t"
"call %1\n\t"
" mov %%g5, %%o0\n\t"
"mov %%l2, %%g2\n\t"
"ba,pt %%xcc, 2b\n\t"
" restore %%l3, %%g0, %%g3\n\t"
".previous\n\t"
"! ending __up_write"
: : "r" (sem), "i" (rwsem_wake),
"i" (RWSEM_ACTIVE_WRITE_BIAS)
: "g1", "g5", "g7", "memory", "cc");
}
EXPORT_SYMBOL(__up_write);
void __downgrade_write(struct rw_semaphore *sem)
{
__asm__ __volatile__(
"! beginning __downgrade_write\n\t"
"sethi %%hi(%2), %%g1\n\t"
"or %%g1, %%lo(%2), %%g1\n"
"1:\tlduw [%0], %%g5\n\t"
"sub %%g5, %%g1, %%g7\n\t"
"cas [%0], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" sub %%g7, %%g1, %%g7\n\t"
"cmp %%g7, 0\n\t"
"bl,pn %%icc, 3f\n\t"
" membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tmov %0, %%g5\n\t"
"save %%sp, -160, %%sp\n\t"
"mov %%g2, %%l2\n\t"
"mov %%g3, %%l3\n\t"
"call %1\n\t"
" mov %%g5, %%o0\n\t"
"mov %%l2, %%g2\n\t"
"ba,pt %%xcc, 2b\n\t"
" restore %%l3, %%g0, %%g3\n\t"
".previous\n\t"
"! ending __up_write"
: : "r" (sem), "i" (rwsem_downgrade_wake),
"i" (RWSEM_WAITING_BIAS)
: "g1", "g5", "g7", "memory", "cc");
}
EXPORT_SYMBOL(__downgrade_write);
...@@ -18,11 +18,6 @@ ...@@ -18,11 +18,6 @@
struct rwsem_waiter; struct rwsem_waiter;
extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem));
extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem));
extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *));
extern struct rw_semaphore *FASTCALL(rwsem_downgrade_wake(struct rw_semaphore *));
struct rw_semaphore { struct rw_semaphore {
signed int count; signed int count;
#define RWSEM_UNLOCKED_VALUE 0x00000000 #define RWSEM_UNLOCKED_VALUE 0x00000000
...@@ -48,222 +43,13 @@ static __inline__ void init_rwsem(struct rw_semaphore *sem) ...@@ -48,222 +43,13 @@ static __inline__ void init_rwsem(struct rw_semaphore *sem)
INIT_LIST_HEAD(&sem->wait_list); INIT_LIST_HEAD(&sem->wait_list);
} }
static __inline__ void __down_read(struct rw_semaphore *sem) extern void __down_read(struct rw_semaphore *sem);
{ extern int __down_read_trylock(struct rw_semaphore *sem);
__asm__ __volatile__( extern void __down_write(struct rw_semaphore *sem);
"! beginning __down_read\n" extern int __down_write_trylock(struct rw_semaphore *sem);
"1:\tlduw [%0], %%g5\n\t" extern void __up_read(struct rw_semaphore *sem);
"add %%g5, 1, %%g7\n\t" extern void __up_write(struct rw_semaphore *sem);
"cas [%0], %%g5, %%g7\n\t" extern void __downgrade_write(struct rw_semaphore *sem);
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" add %%g7, 1, %%g7\n\t"
"cmp %%g7, 0\n\t"
"bl,pn %%icc, 3f\n\t"
" membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tmov %0, %%g5\n\t"
"save %%sp, -160, %%sp\n\t"
"mov %%g1, %%l1\n\t"
"mov %%g2, %%l2\n\t"
"mov %%g3, %%l3\n\t"
"call %1\n\t"
" mov %%g5, %%o0\n\t"
"mov %%l1, %%g1\n\t"
"mov %%l2, %%g2\n\t"
"ba,pt %%xcc, 2b\n\t"
" restore %%l3, %%g0, %%g3\n\t"
".previous\n\t"
"! ending __down_read"
: : "r" (sem), "i" (rwsem_down_read_failed)
: "g5", "g7", "memory", "cc");
}
static __inline__ int __down_read_trylock(struct rw_semaphore *sem)
{
int result;
__asm__ __volatile__(
"! beginning __down_read_trylock\n"
"1:\tlduw [%1], %%g5\n\t"
"add %%g5, 1, %%g7\n\t"
"cmp %%g7, 0\n\t"
"bl,pn %%icc, 2f\n\t"
" mov 0, %0\n\t"
"cas [%1], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" mov 1, %0\n\t"
"membar #StoreLoad | #StoreStore\n"
"2:\n\t"
"! ending __down_read_trylock"
: "=&r" (result)
: "r" (sem)
: "g5", "g7", "memory", "cc");
return result;
}
static __inline__ void __down_write(struct rw_semaphore *sem)
{
__asm__ __volatile__(
"! beginning __down_write\n\t"
"sethi %%hi(%2), %%g1\n\t"
"or %%g1, %%lo(%2), %%g1\n"
"1:\tlduw [%0], %%g5\n\t"
"add %%g5, %%g1, %%g7\n\t"
"cas [%0], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" cmp %%g7, 0\n\t"
"bne,pn %%icc, 3f\n\t"
" membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tmov %0, %%g5\n\t"
"save %%sp, -160, %%sp\n\t"
"mov %%g2, %%l2\n\t"
"mov %%g3, %%l3\n\t"
"call %1\n\t"
" mov %%g5, %%o0\n\t"
"mov %%l2, %%g2\n\t"
"ba,pt %%xcc, 2b\n\t"
" restore %%l3, %%g0, %%g3\n\t"
".previous\n\t"
"! ending __down_write"
: : "r" (sem), "i" (rwsem_down_write_failed),
"i" (RWSEM_ACTIVE_WRITE_BIAS)
: "g1", "g5", "g7", "memory", "cc");
}
static __inline__ int __down_write_trylock(struct rw_semaphore *sem)
{
int result;
__asm__ __volatile__(
"! beginning __down_write_trylock\n\t"
"sethi %%hi(%2), %%g1\n\t"
"or %%g1, %%lo(%2), %%g1\n"
"1:\tlduw [%1], %%g5\n\t"
"cmp %%g5, 0\n\t"
"bne,pn %%icc, 2f\n\t"
" mov 0, %0\n\t"
"add %%g5, %%g1, %%g7\n\t"
"cas [%1], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" mov 1, %0\n\t"
"membar #StoreLoad | #StoreStore\n"
"2:\n\t"
"! ending __down_write_trylock"
: "=&r" (result)
: "r" (sem), "i" (RWSEM_ACTIVE_WRITE_BIAS)
: "g1", "g5", "g7", "memory", "cc");
return result;
}
static __inline__ void __up_read(struct rw_semaphore *sem)
{
__asm__ __volatile__(
"! beginning __up_read\n\t"
"1:\tlduw [%0], %%g5\n\t"
"sub %%g5, 1, %%g7\n\t"
"cas [%0], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" cmp %%g7, 0\n\t"
"bl,pn %%icc, 3f\n\t"
" membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tsethi %%hi(%2), %%g1\n\t"
"sub %%g7, 1, %%g7\n\t"
"or %%g1, %%lo(%2), %%g1\n\t"
"andcc %%g7, %%g1, %%g0\n\t"
"bne,pn %%icc, 2b\n\t"
" mov %0, %%g5\n\t"
"save %%sp, -160, %%sp\n\t"
"mov %%g2, %%l2\n\t"
"mov %%g3, %%l3\n\t"
"call %1\n\t"
" mov %%g5, %%o0\n\t"
"mov %%l2, %%g2\n\t"
"ba,pt %%xcc, 2b\n\t"
" restore %%l3, %%g0, %%g3\n\t"
".previous\n\t"
"! ending __up_read"
: : "r" (sem), "i" (rwsem_wake),
"i" (RWSEM_ACTIVE_MASK)
: "g1", "g5", "g7", "memory", "cc");
}
static __inline__ void __up_write(struct rw_semaphore *sem)
{
__asm__ __volatile__(
"! beginning __up_write\n\t"
"sethi %%hi(%2), %%g1\n\t"
"or %%g1, %%lo(%2), %%g1\n"
"1:\tlduw [%0], %%g5\n\t"
"sub %%g5, %%g1, %%g7\n\t"
"cas [%0], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" sub %%g7, %%g1, %%g7\n\t"
"cmp %%g7, 0\n\t"
"bl,pn %%icc, 3f\n\t"
" membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tmov %0, %%g5\n\t"
"save %%sp, -160, %%sp\n\t"
"mov %%g2, %%l2\n\t"
"mov %%g3, %%l3\n\t"
"call %1\n\t"
" mov %%g5, %%o0\n\t"
"mov %%l2, %%g2\n\t"
"ba,pt %%xcc, 2b\n\t"
" restore %%l3, %%g0, %%g3\n\t"
".previous\n\t"
"! ending __up_write"
: : "r" (sem), "i" (rwsem_wake),
"i" (RWSEM_ACTIVE_WRITE_BIAS)
: "g1", "g5", "g7", "memory", "cc");
}
static __inline__ void __downgrade_write(struct rw_semaphore *sem)
{
__asm__ __volatile__(
"! beginning __up_write\n\t"
"sethi %%hi(%2), %%g1\n\t"
"or %%g1, %%lo(%2), %%g1\n"
"1:\tlduw [%0], %%g5\n\t"
"sub %%g5, %%g1, %%g7\n\t"
"cas [%0], %%g5, %%g7\n\t"
"cmp %%g5, %%g7\n\t"
"bne,pn %%icc, 1b\n\t"
" sub %%g7, %%g1, %%g7\n\t"
"cmp %%g7, 0\n\t"
"bl,pn %%icc, 3f\n\t"
" membar #StoreLoad | #StoreStore\n"
"2:\n\t"
".subsection 2\n"
"3:\tmov %0, %%g5\n\t"
"save %%sp, -160, %%sp\n\t"
"mov %%g2, %%l2\n\t"
"mov %%g3, %%l3\n\t"
"call %1\n\t"
" mov %%g5, %%o0\n\t"
"mov %%l2, %%g2\n\t"
"ba,pt %%xcc, 2b\n\t"
" restore %%l3, %%g0, %%g3\n\t"
".previous\n\t"
"! ending __up_write"
: : "r" (sem), "i" (rwsem_downgrade_wake),
"i" (RWSEM_WAITING_BIAS)
: "g1", "g5", "g7", "memory", "cc");
}
static __inline__ int rwsem_atomic_update(int delta, struct rw_semaphore *sem) static __inline__ int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
{ {
......
...@@ -66,4 +66,10 @@ extern unsigned long timer_tick_offset; ...@@ -66,4 +66,10 @@ extern unsigned long timer_tick_offset;
extern void timer_tick_interrupt(struct pt_regs *); extern void timer_tick_interrupt(struct pt_regs *);
#endif #endif
#ifndef CONFIG_SMP
extern unsigned long up_clock_tick;
#endif
extern unsigned long sparc64_get_clock_tick(unsigned int cpu);
#endif /* _SPARC64_TIMER_H */ #endif /* _SPARC64_TIMER_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment