Commit 92dd7ca0 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/home/rmk/linux-2.6-arm

parents 164cad9b da41119a
...@@ -30,9 +30,6 @@ extern void __lshrdi3(void); ...@@ -30,9 +30,6 @@ extern void __lshrdi3(void);
extern void __modsi3(void); extern void __modsi3(void);
extern void __muldi3(void); extern void __muldi3(void);
extern void __ucmpdi2(void); extern void __ucmpdi2(void);
extern void __udivdi3(void);
extern void __umoddi3(void);
extern void __udivmoddi4(void);
extern void __udivsi3(void); extern void __udivsi3(void);
extern void __umodsi3(void); extern void __umodsi3(void);
extern void __do_div64(void); extern void __do_div64(void);
...@@ -134,9 +131,6 @@ EXPORT_SYMBOL(__lshrdi3); ...@@ -134,9 +131,6 @@ EXPORT_SYMBOL(__lshrdi3);
EXPORT_SYMBOL(__modsi3); EXPORT_SYMBOL(__modsi3);
EXPORT_SYMBOL(__muldi3); EXPORT_SYMBOL(__muldi3);
EXPORT_SYMBOL(__ucmpdi2); EXPORT_SYMBOL(__ucmpdi2);
EXPORT_SYMBOL(__udivdi3);
EXPORT_SYMBOL(__umoddi3);
EXPORT_SYMBOL(__udivmoddi4);
EXPORT_SYMBOL(__udivsi3); EXPORT_SYMBOL(__udivsi3);
EXPORT_SYMBOL(__umodsi3); EXPORT_SYMBOL(__umodsi3);
EXPORT_SYMBOL(__do_div64); EXPORT_SYMBOL(__do_div64);
......
...@@ -359,7 +359,8 @@ void cpu_init(void) ...@@ -359,7 +359,8 @@ void cpu_init(void)
"I" (offsetof(struct stack, abt[0])), "I" (offsetof(struct stack, abt[0])),
"I" (PSR_F_BIT | PSR_I_BIT | UND_MODE), "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
"I" (offsetof(struct stack, und[0])), "I" (offsetof(struct stack, und[0])),
"I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)); "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
: "r14");
} }
static struct machine_desc * __init setup_machine(unsigned int nr) static struct machine_desc * __init setup_machine(unsigned int nr)
......
...@@ -502,3 +502,126 @@ int __init setup_profiling_timer(unsigned int multiplier) ...@@ -502,3 +502,126 @@ int __init setup_profiling_timer(unsigned int multiplier)
{ {
return -EINVAL; return -EINVAL;
} }
static int
on_each_cpu_mask(void (*func)(void *), void *info, int retry, int wait,
cpumask_t mask)
{
int ret = 0;
preempt_disable();
ret = smp_call_function_on_cpu(func, info, retry, wait, mask);
if (cpu_isset(smp_processor_id(), mask))
func(info);
preempt_enable();
return ret;
}
/**********************************************************************/
/*
* TLB operations
*/
struct tlb_args {
struct vm_area_struct *ta_vma;
unsigned long ta_start;
unsigned long ta_end;
};
static inline void ipi_flush_tlb_all(void *ignored)
{
local_flush_tlb_all();
}
static inline void ipi_flush_tlb_mm(void *arg)
{
struct mm_struct *mm = (struct mm_struct *)arg;
local_flush_tlb_mm(mm);
}
static inline void ipi_flush_tlb_page(void *arg)
{
struct tlb_args *ta = (struct tlb_args *)arg;
local_flush_tlb_page(ta->ta_vma, ta->ta_start);
}
static inline void ipi_flush_tlb_kernel_page(void *arg)
{
struct tlb_args *ta = (struct tlb_args *)arg;
local_flush_tlb_kernel_page(ta->ta_start);
}
static inline void ipi_flush_tlb_range(void *arg)
{
struct tlb_args *ta = (struct tlb_args *)arg;
local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end);
}
static inline void ipi_flush_tlb_kernel_range(void *arg)
{
struct tlb_args *ta = (struct tlb_args *)arg;
local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end);
}
void flush_tlb_all(void)
{
on_each_cpu(ipi_flush_tlb_all, NULL, 1, 1);
}
void flush_tlb_mm(struct mm_struct *mm)
{
cpumask_t mask = mm->cpu_vm_mask;
on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, 1, mask);
}
void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
{
cpumask_t mask = vma->vm_mm->cpu_vm_mask;
struct tlb_args ta;
ta.ta_vma = vma;
ta.ta_start = uaddr;
on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, 1, mask);
}
void flush_tlb_kernel_page(unsigned long kaddr)
{
struct tlb_args ta;
ta.ta_start = kaddr;
on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1, 1);
}
void flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
cpumask_t mask = vma->vm_mm->cpu_vm_mask;
struct tlb_args ta;
ta.ta_vma = vma;
ta.ta_start = start;
ta.ta_end = end;
on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, 1, mask);
}
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
struct tlb_args ta;
ta.ta_start = start;
ta.ta_end = end;
on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1, 1);
}
...@@ -11,7 +11,7 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ ...@@ -11,7 +11,7 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
strnlen_user.o strchr.o strrchr.o testchangebit.o \ strnlen_user.o strchr.o strrchr.o testchangebit.o \
testclearbit.o testsetbit.o uaccess.o getuser.o \ testclearbit.o testsetbit.o uaccess.o getuser.o \
putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
ucmpdi2.o udivdi3.o lib1funcs.o div64.o \ ucmpdi2.o lib1funcs.o div64.o \
io-readsb.o io-writesb.o io-readsl.o io-writesl.o io-readsb.o io-writesb.o io-readsl.o io-writesl.o
ifeq ($(CONFIG_CPU_32v3),y) ifeq ($(CONFIG_CPU_32v3),y)
......
/* longlong.h -- based on code from gcc-2.95.3
definitions for mixed size 32/64 bit arithmetic.
Copyright (C) 1991, 92, 94, 95, 96, 1997, 1998 Free Software Foundation, Inc.
This definition file is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2, or (at your option) any later version.
This definition file is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Borrowed from GCC 2.95.3, I Molton 29/07/01 */
#ifndef SI_TYPE_SIZE
#define SI_TYPE_SIZE 32
#endif
#define __BITS4 (SI_TYPE_SIZE / 4)
#define __ll_B (1L << (SI_TYPE_SIZE / 2))
#define __ll_lowpart(t) ((u32) (t) % __ll_B)
#define __ll_highpart(t) ((u32) (t) / __ll_B)
/* Define auxiliary asm macros.
1) umul_ppmm(high_prod, low_prod, multipler, multiplicand)
multiplies two u32 integers MULTIPLER and MULTIPLICAND,
and generates a two-part u32 product in HIGH_PROD and
LOW_PROD.
2) __umulsidi3(a,b) multiplies two u32 integers A and B,
and returns a u64 product. This is just a variant of umul_ppmm.
3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
denominator) divides a two-word unsigned integer, composed by the
integers HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and
places the quotient in QUOTIENT and the remainder in REMAINDER.
HIGH_NUMERATOR must be less than DENOMINATOR for correct operation.
If, in addition, the most significant bit of DENOMINATOR must be 1,
then the pre-processor symbol UDIV_NEEDS_NORMALIZATION is defined to 1.
4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
denominator). Like udiv_qrnnd but the numbers are signed. The
quotient is rounded towards 0.
5) count_leading_zeros(count, x) counts the number of zero-bits from
the msb to the first non-zero bit. This is the number of steps X
needs to be shifted left to set the msb. Undefined for X == 0.
6) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
high_addend_2, low_addend_2) adds two two-word unsigned integers,
composed by HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and
LOW_ADDEND_2 respectively. The result is placed in HIGH_SUM and
LOW_SUM. Overflow (i.e. carry out) is not stored anywhere, and is
lost.
7) sub_ddmmss(high_difference, low_difference, high_minuend,
low_minuend, high_subtrahend, low_subtrahend) subtracts two
two-word unsigned integers, composed by HIGH_MINUEND_1 and
LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and LOW_SUBTRAHEND_2
respectively. The result is placed in HIGH_DIFFERENCE and
LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere,
and is lost.
If any of these macros are left undefined for a particular CPU,
C macros are used. */
#if defined (__arm__)
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("adds %1, %4, %5 \n\
adc %0, %2, %3" \
: "=r" ((u32) (sh)), \
"=&r" ((u32) (sl)) \
: "%r" ((u32) (ah)), \
"rI" ((u32) (bh)), \
"%r" ((u32) (al)), \
"rI" ((u32) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subs %1, %4, %5 \n\
sbc %0, %2, %3" \
: "=r" ((u32) (sh)), \
"=&r" ((u32) (sl)) \
: "r" ((u32) (ah)), \
"rI" ((u32) (bh)), \
"r" ((u32) (al)), \
"rI" ((u32) (bl)))
#define umul_ppmm(xh, xl, a, b) \
{register u32 __t0, __t1, __t2; \
__asm__ ("%@ Inlined umul_ppmm \n\
mov %2, %5, lsr #16 \n\
mov %0, %6, lsr #16 \n\
bic %3, %5, %2, lsl #16 \n\
bic %4, %6, %0, lsl #16 \n\
mul %1, %3, %4 \n\
mul %4, %2, %4 \n\
mul %3, %0, %3 \n\
mul %0, %2, %0 \n\
adds %3, %4, %3 \n\
addcs %0, %0, #65536 \n\
adds %1, %1, %3, lsl #16 \n\
adc %0, %0, %3, lsr #16" \
: "=&r" ((u32) (xh)), \
"=r" ((u32) (xl)), \
"=&r" (__t0), "=&r" (__t1), "=r" (__t2) \
: "r" ((u32) (a)), \
"r" ((u32) (b)));}
#define UMUL_TIME 20
#define UDIV_TIME 100
#endif /* __arm__ */
#define __umulsidi3(u, v) \
({DIunion __w; \
umul_ppmm (__w.s.high, __w.s.low, u, v); \
__w.ll; })
#define __udiv_qrnnd_c(q, r, n1, n0, d) \
do { \
u32 __d1, __d0, __q1, __q0; \
u32 __r1, __r0, __m; \
__d1 = __ll_highpart (d); \
__d0 = __ll_lowpart (d); \
\
__r1 = (n1) % __d1; \
__q1 = (n1) / __d1; \
__m = (u32) __q1 * __d0; \
__r1 = __r1 * __ll_B | __ll_highpart (n0); \
if (__r1 < __m) \
{ \
__q1--, __r1 += (d); \
if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
if (__r1 < __m) \
__q1--, __r1 += (d); \
} \
__r1 -= __m; \
\
__r0 = __r1 % __d1; \
__q0 = __r1 / __d1; \
__m = (u32) __q0 * __d0; \
__r0 = __r0 * __ll_B | __ll_lowpart (n0); \
if (__r0 < __m) \
{ \
__q0--, __r0 += (d); \
if (__r0 >= (d)) \
if (__r0 < __m) \
__q0--, __r0 += (d); \
} \
__r0 -= __m; \
\
(q) = (u32) __q1 * __ll_B | __q0; \
(r) = __r0; \
} while (0)
#define UDIV_NEEDS_NORMALIZATION 1
#define udiv_qrnnd __udiv_qrnnd_c
#define count_leading_zeros(count, x) \
do { \
u32 __xr = (x); \
u32 __a; \
\
if (SI_TYPE_SIZE <= 32) \
{ \
__a = __xr < ((u32)1<<2*__BITS4) \
? (__xr < ((u32)1<<__BITS4) ? 0 : __BITS4) \
: (__xr < ((u32)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \
} \
else \
{ \
for (__a = SI_TYPE_SIZE - 8; __a > 0; __a -= 8) \
if (((__xr >> __a) & 0xff) != 0) \
break; \
} \
\
(count) = SI_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \
} while (0)
/* More subroutines needed by GCC output code on some machines. */
/* Compile this one with gcc. */
/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, if you link this library with other files,
some of which are compiled with GCC, to produce an executable,
this library does not by itself cause the resulting executable
to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License.
*/
/* support functions required by the kernel. based on code from gcc-2.95.3 */
/* I Molton 29/07/01 */
#include "gcclib.h"
#include "longlong.h"
static const u8 __clz_tab[] = {
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
};
u64 __udivmoddi4(u64 n, u64 d, u64 * rp)
{
DIunion ww;
DIunion nn, dd;
DIunion rr;
u32 d0, d1, n0, n1, n2;
u32 q0, q1;
u32 b, bm;
nn.ll = n;
dd.ll = d;
d0 = dd.s.low;
d1 = dd.s.high;
n0 = nn.s.low;
n1 = nn.s.high;
if (d1 == 0) {
if (d0 > n1) {
/* 0q = nn / 0D */
count_leading_zeros(bm, d0);
if (bm != 0) {
/* Normalize, i.e. make the most significant bit of the
denominator set. */
d0 = d0 << bm;
n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm));
n0 = n0 << bm;
}
udiv_qrnnd(q0, n0, n1, n0, d0);
q1 = 0;
/* Remainder in n0 >> bm. */
} else {
/* qq = NN / 0d */
if (d0 == 0)
d0 = 1 / d0; /* Divide intentionally by zero. */
count_leading_zeros(bm, d0);
if (bm == 0) {
/* From (n1 >= d0) /\ (the most significant bit of d0 is set),
conclude (the most significant bit of n1 is set) /\ (the
leading quotient digit q1 = 1).
This special case is necessary, not an optimization.
(Shifts counts of SI_TYPE_SIZE are undefined.) */
n1 -= d0;
q1 = 1;
} else {
/* Normalize. */
b = SI_TYPE_SIZE - bm;
d0 = d0 << bm;
n2 = n1 >> b;
n1 = (n1 << bm) | (n0 >> b);
n0 = n0 << bm;
udiv_qrnnd(q1, n1, n2, n1, d0);
}
/* n1 != d0... */
udiv_qrnnd(q0, n0, n1, n0, d0);
/* Remainder in n0 >> bm. */
}
if (rp != 0) {
rr.s.low = n0 >> bm;
rr.s.high = 0;
*rp = rr.ll;
}
} else {
if (d1 > n1) {
/* 00 = nn / DD */
q0 = 0;
q1 = 0;
/* Remainder in n1n0. */
if (rp != 0) {
rr.s.low = n0;
rr.s.high = n1;
*rp = rr.ll;
}
} else {
/* 0q = NN / dd */
count_leading_zeros(bm, d1);
if (bm == 0) {
/* From (n1 >= d1) /\ (the most significant bit of d1 is set),
conclude (the most significant bit of n1 is set) /\ (the
quotient digit q0 = 0 or 1).
This special case is necessary, not an optimization. */
/* The condition on the next line takes advantage of that
n1 >= d1 (true due to program flow). */
if (n1 > d1 || n0 >= d0) {
q0 = 1;
sub_ddmmss(n1, n0, n1, n0, d1, d0);
} else
q0 = 0;
q1 = 0;
if (rp != 0) {
rr.s.low = n0;
rr.s.high = n1;
*rp = rr.ll;
}
} else {
u32 m1, m0;
/* Normalize. */
b = SI_TYPE_SIZE - bm;
d1 = (d1 << bm) | (d0 >> b);
d0 = d0 << bm;
n2 = n1 >> b;
n1 = (n1 << bm) | (n0 >> b);
n0 = n0 << bm;
udiv_qrnnd(q0, n1, n2, n1, d1);
umul_ppmm(m1, m0, q0, d0);
if (m1 > n1 || (m1 == n1 && m0 > n0)) {
q0--;
sub_ddmmss(m1, m0, m1, m0, d1, d0);
}
q1 = 0;
/* Remainder in (n1n0 - m1m0) >> bm. */
if (rp != 0) {
sub_ddmmss(n1, n0, n1, n0, m1, m0);
rr.s.low = (n1 << b) | (n0 >> bm);
rr.s.high = n1 >> bm;
*rp = rr.ll;
}
}
}
}
ww.s.low = q0;
ww.s.high = q1;
return ww.ll;
}
u64 __udivdi3(u64 n, u64 d)
{
return __udivmoddi4(n, d, (u64 *) 0);
}
u64 __umoddi3(u64 u, u64 v)
{
u64 w;
(void)__udivmoddi4(u, v, &w);
return w;
}
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/hardware/amba.h> #include <asm/hardware/amba.h>
#include <asm/hardware/arm_timer.h>
#include <asm/arch/cm.h> #include <asm/arch/cm.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/leds.h> #include <asm/leds.h>
...@@ -156,16 +157,6 @@ EXPORT_SYMBOL(cm_control); ...@@ -156,16 +157,6 @@ EXPORT_SYMBOL(cm_control);
#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
#endif #endif
/*
* What does it look like?
*/
typedef struct TimerStruct {
unsigned long TimerLoad;
unsigned long TimerValue;
unsigned long TimerControl;
unsigned long TimerClear;
} TimerStruct_t;
static unsigned long timer_reload; static unsigned long timer_reload;
/* /*
...@@ -174,7 +165,6 @@ static unsigned long timer_reload; ...@@ -174,7 +165,6 @@ static unsigned long timer_reload;
*/ */
unsigned long integrator_gettimeoffset(void) unsigned long integrator_gettimeoffset(void)
{ {
volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE;
unsigned long ticks1, ticks2, status; unsigned long ticks1, ticks2, status;
/* /*
...@@ -183,11 +173,11 @@ unsigned long integrator_gettimeoffset(void) ...@@ -183,11 +173,11 @@ unsigned long integrator_gettimeoffset(void)
* an interrupt. We get around this by ensuring that the * an interrupt. We get around this by ensuring that the
* counter has not reloaded between our two reads. * counter has not reloaded between our two reads.
*/ */
ticks2 = timer1->TimerValue & 0xffff; ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
do { do {
ticks1 = ticks2; ticks1 = ticks2;
status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS); status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
ticks2 = timer1->TimerValue & 0xffff; ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
} while (ticks2 > ticks1); } while (ticks2 > ticks1);
/* /*
...@@ -213,14 +203,12 @@ unsigned long integrator_gettimeoffset(void) ...@@ -213,14 +203,12 @@ unsigned long integrator_gettimeoffset(void)
static irqreturn_t static irqreturn_t
integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
write_seqlock(&xtime_lock); write_seqlock(&xtime_lock);
/* /*
* clear the interrupt * clear the interrupt
*/ */
timer1->TimerClear = 1; writel(1, TIMER1_VA_BASE + TIMER_INTCLR);
/* /*
* the clock tick routines are only processed on the * the clock tick routines are only processed on the
...@@ -256,32 +244,29 @@ static struct irqaction integrator_timer_irq = { ...@@ -256,32 +244,29 @@ static struct irqaction integrator_timer_irq = {
*/ */
void __init integrator_time_init(unsigned long reload, unsigned int ctrl) void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
{ {
volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; unsigned int timer_ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
unsigned int timer_ctrl = 0x80 | 0x40; /* periodic */
timer_reload = reload; timer_reload = reload;
timer_ctrl |= ctrl; timer_ctrl |= ctrl;
if (timer_reload > 0x100000) { if (timer_reload > 0x100000) {
timer_reload >>= 8; timer_reload >>= 8;
timer_ctrl |= 0x08; /* /256 */ timer_ctrl |= TIMER_CTRL_DIV256;
} else if (timer_reload > 0x010000) { } else if (timer_reload > 0x010000) {
timer_reload >>= 4; timer_reload >>= 4;
timer_ctrl |= 0x04; /* /16 */ timer_ctrl |= TIMER_CTRL_DIV16;
} }
/* /*
* Initialise to a known state (all timers off) * Initialise to a known state (all timers off)
*/ */
timer0->TimerControl = 0; writel(0, TIMER0_VA_BASE + TIMER_CTRL);
timer1->TimerControl = 0; writel(0, TIMER1_VA_BASE + TIMER_CTRL);
timer2->TimerControl = 0; writel(0, TIMER2_VA_BASE + TIMER_CTRL);
timer1->TimerLoad = timer_reload; writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD);
timer1->TimerValue = timer_reload; writel(timer_reload, TIMER1_VA_BASE + TIMER_VALUE);
timer1->TimerControl = timer_ctrl; writel(timer_ctrl, TIMER1_VA_BASE + TIMER_CTRL);
/* /*
* Make irqs happen for the system timer * Make irqs happen for the system timer
......
...@@ -41,7 +41,9 @@ ...@@ -41,7 +41,9 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/mach/time.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/arch/omap16xx.h> #include <asm/arch/omap16xx.h>
#include <asm/arch/pm.h> #include <asm/arch/pm.h>
#include <asm/arch/mux.h> #include <asm/arch/mux.h>
...@@ -80,13 +82,13 @@ void omap_pm_idle(void) ...@@ -80,13 +82,13 @@ void omap_pm_idle(void)
return; return;
} }
mask32 = omap_readl(ARM_SYSST); mask32 = omap_readl(ARM_SYSST);
local_fiq_enable();
local_irq_enable();
#if defined(CONFIG_OMAP_32K_TIMER) && defined(CONFIG_NO_IDLE_HZ) /*
/* Override timer to use VST for the next cycle */ * Since an interrupt may set up a timer, we don't want to
omap_32k_timer_next_vst_interrupt(); * reprogram the hardware timer with interrupts enabled.
#endif * Re-enable interrupts only after returning from idle.
*/
timer_dyn_reprogram();
if ((mask32 & DSP_IDLE) == 0) { if ((mask32 & DSP_IDLE) == 0) {
__asm__ volatile ("mcr p15, 0, r0, c7, c0, 4"); __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4");
...@@ -102,6 +104,8 @@ void omap_pm_idle(void) ...@@ -102,6 +104,8 @@ void omap_pm_idle(void)
func_ptr(); func_ptr();
} }
local_fiq_enable();
local_irq_enable();
} }
/* /*
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* OMAP Timers * OMAP Timers
* *
* Copyright (C) 2004 Nokia Corporation * Copyright (C) 2004 Nokia Corporation
* Partial timer rewrite and additional VST timer support by * Partial timer rewrite and additional dynamic tick timer support by
* Tony Lindgen <tony@atomide.com> and * Tony Lindgen <tony@atomide.com> and
* Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
* *
...@@ -261,7 +261,6 @@ unsigned long long sched_clock(void) ...@@ -261,7 +261,6 @@ unsigned long long sched_clock(void)
* so with HZ = 100, TVR = 327.68. * so with HZ = 100, TVR = 327.68.
*/ */
#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1) #define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1)
#define MAX_SKIP_JIFFIES 25
#define TIMER_32K_SYNCHRONIZED 0xfffbc410 #define TIMER_32K_SYNCHRONIZED 0xfffbc410
#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ #define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
...@@ -347,6 +346,42 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, ...@@ -347,6 +346,42 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#ifdef CONFIG_NO_IDLE_HZ
/*
* Programs the next timer interrupt needed. Called when dynamic tick is
* enabled, and to reprogram the ticks to skip from pm_idle. Note that
* we can keep the timer continuous, and don't need to set it to run in
* one-shot mode. This is because the timer will get reprogrammed again
* after next interrupt.
*/
void omap_32k_timer_reprogram(unsigned long next_tick)
{
omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1);
}
static struct irqaction omap_32k_timer_irq;
extern struct timer_update_handler timer_update;
static int omap_32k_timer_enable_dyn_tick(void)
{
/* No need to reprogram timer, just use the next interrupt */
return 0;
}
static int omap_32k_timer_disable_dyn_tick(void)
{
omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
return 0;
}
static struct dyn_tick_timer omap_dyn_tick_timer = {
.enable = omap_32k_timer_enable_dyn_tick,
.disable = omap_32k_timer_disable_dyn_tick,
.reprogram = omap_32k_timer_reprogram,
.handler = omap_32k_timer_interrupt,
};
#endif /* CONFIG_NO_IDLE_HZ */
static struct irqaction omap_32k_timer_irq = { static struct irqaction omap_32k_timer_irq = {
.name = "32KHz timer", .name = "32KHz timer",
.flags = SA_INTERRUPT | SA_TIMER, .flags = SA_INTERRUPT | SA_TIMER,
...@@ -355,6 +390,11 @@ static struct irqaction omap_32k_timer_irq = { ...@@ -355,6 +390,11 @@ static struct irqaction omap_32k_timer_irq = {
static __init void omap_init_32k_timer(void) static __init void omap_init_32k_timer(void)
{ {
#ifdef CONFIG_NO_IDLE_HZ
omap_timer.dyn_tick = &omap_dyn_tick_timer;
#endif
setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
omap_timer.offset = omap_32k_timer_gettimeoffset; omap_timer.offset = omap_32k_timer_gettimeoffset;
omap_32k_last_tick = omap_32k_sync_timer_read(); omap_32k_last_tick = omap_32k_sync_timer_read();
......
...@@ -154,6 +154,11 @@ config S3C2410_PM_CHECK_CHUNKSIZE ...@@ -154,6 +154,11 @@ config S3C2410_PM_CHECK_CHUNKSIZE
the CRC data block will take more memory, but wil identify any the CRC data block will take more memory, but wil identify any
faults with better precision. faults with better precision.
config PM_SIMTEC
bool
depends on PM && (ARCH_BAST || MACH_VR1000)
default y
config S3C2410_LOWLEVEL_UART_PORT config S3C2410_LOWLEVEL_UART_PORT
int "S3C2410 UART to use for low-level messages" int "S3C2410 UART to use for low-level messages"
default 0 default 0
......
...@@ -18,6 +18,7 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o ...@@ -18,6 +18,7 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o
# Power Management support # Power Management support
obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
# S3C2440 support # S3C2440 support
......
...@@ -96,8 +96,8 @@ struct platform_device s3c_device_lcd = { ...@@ -96,8 +96,8 @@ struct platform_device s3c_device_lcd = {
.num_resources = ARRAY_SIZE(s3c_lcd_resource), .num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource, .resource = s3c_lcd_resource,
.dev = { .dev = {
.dma_mask = &s3c_device_lcd_dmamask, .dma_mask = &s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL .coherent_dma_mask = 0xffffffffUL
} }
}; };
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
* 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
* 14-Mar-2006 BJD Updated for __iomem changes * 14-Mar-2006 BJD Updated for __iomem changes
* 22-Jun-2006 BJD Added DM9000 platform information * 22-Jun-2006 BJD Added DM9000 platform information
* 28-Jun-2006 BJD Moved pm functionality out to common code
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -67,7 +68,6 @@ ...@@ -67,7 +68,6 @@
#include "devs.h" #include "devs.h"
#include "cpu.h" #include "cpu.h"
#include "usb-simtec.h" #include "usb-simtec.h"
#include "pm.h"
#define COPYRIGHT ", (c) 2004-2005 Simtec Electronics" #define COPYRIGHT ", (c) 2004-2005 Simtec Electronics"
...@@ -405,44 +405,13 @@ void __init bast_map_io(void) ...@@ -405,44 +405,13 @@ void __init bast_map_io(void)
usb_simtec_init(); usb_simtec_init();
} }
void __init bast_init_irq(void)
{
s3c24xx_init_irq();
}
#ifdef CONFIG_PM
/* bast_init_machine
*
* enable the power management functions for the EB2410ITX
*/
static __init void bast_init_machine(void)
{
unsigned long gstatus4;
printk(KERN_INFO "BAST Power Manangement" COPYRIGHT "\n");
gstatus4 = (__raw_readl(S3C2410_BANKCON7) & 0x3) << 30;
gstatus4 |= (__raw_readl(S3C2410_BANKCON6) & 0x3) << 28;
gstatus4 |= (__raw_readl(S3C2410_BANKSIZE) & S3C2410_BANKSIZE_MASK);
__raw_writel(gstatus4, S3C2410_GSTATUS4);
s3c2410_pm_init();
}
#else
#define bast_init_machine NULL
#endif
MACHINE_START(BAST, "Simtec-BAST") MACHINE_START(BAST, "Simtec-BAST")
MAINTAINER("Ben Dooks <ben@simtec.co.uk>") MAINTAINER("Ben Dooks <ben@simtec.co.uk>")
BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART) BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
MAPIO(bast_map_io)
INITIRQ(bast_init_irq) .map_io = bast_map_io,
.init_machine = bast_init_machine, .init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer, .timer = &s3c24xx_timer,
MACHINE_END MACHINE_END
...@@ -371,16 +371,12 @@ void __init vr1000_map_io(void) ...@@ -371,16 +371,12 @@ void __init vr1000_map_io(void)
usb_simtec_init(); usb_simtec_init();
} }
void __init vr1000_init_irq(void)
{
s3c24xx_init_irq();
}
MACHINE_START(VR1000, "Thorcom-VR1000") MACHINE_START(VR1000, "Thorcom-VR1000")
MAINTAINER("Ben Dooks <ben@simtec.co.uk>") MAINTAINER("Ben Dooks <ben@simtec.co.uk>")
BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART) BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
MAPIO(vr1000_map_io) .map_io = vr1000_map_io,
INITIRQ(vr1000_init_irq) .init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer, .timer = &s3c24xx_timer,
MACHINE_END MACHINE_END
/* linux/arch/arm/mach-s3c2410/pm-simtec.c
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* http://armlinux.simtec.co.uk/
*
* Power Management helpers for Simtec S3C24XX implementations
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/device.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/arch/map.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-mem.h>
#include <asm/mach-types.h>
#include "pm.h"
#define COPYRIGHT ", (c) 2005 Simtec Electronics"
/* pm_simtec_init
*
* enable the power management functions
*/
static __init int pm_simtec_init(void)
{
unsigned long gstatus4;
/* check which machine we are running on */
if (!machine_is_bast() && !machine_is_vr1000())
return 0;
printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n");
gstatus4 = (__raw_readl(S3C2410_BANKCON7) & 0x3) << 30;
gstatus4 |= (__raw_readl(S3C2410_BANKCON6) & 0x3) << 28;
gstatus4 |= (__raw_readl(S3C2410_BANKSIZE) & S3C2410_BANKSIZE_MASK);
__raw_writel(gstatus4, S3C2410_GSTATUS4);
return s3c2410_pm_init();
}
arch_initcall(pm_simtec_init);
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/hardware/amba.h> #include <asm/hardware/amba.h>
#include <asm/hardware/amba_clcd.h> #include <asm/hardware/amba_clcd.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst307.h> #include <asm/hardware/icst307.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
...@@ -788,38 +789,25 @@ void __init versatile_init(void) ...@@ -788,38 +789,25 @@ void __init versatile_init(void)
*/ */
#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) #define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
#if TIMER_INTERVAL >= 0x100000 #if TIMER_INTERVAL >= 0x100000
#define TIMER_RELOAD (TIMER_INTERVAL >> 8) /* Divide by 256 */ #define TIMER_RELOAD (TIMER_INTERVAL >> 8)
#define TIMER_CTRL 0x88 /* Enable, Clock / 256 */ #define TIMER_DIVISOR (TIMER_CTRL_DIV256)
#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) #define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
#elif TIMER_INTERVAL >= 0x10000 #elif TIMER_INTERVAL >= 0x10000
#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ #define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */
#define TIMER_CTRL 0x84 /* Enable, Clock / 16 */ #define TIMER_DIVISOR (TIMER_CTRL_DIV16)
#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) #define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
#else #else
#define TIMER_RELOAD (TIMER_INTERVAL) #define TIMER_RELOAD (TIMER_INTERVAL)
#define TIMER_CTRL 0x80 /* Enable */ #define TIMER_DIVISOR (TIMER_CTRL_DIV1)
#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
#endif #endif
#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */
/*
* What does it look like?
*/
typedef struct TimerStruct {
unsigned long TimerLoad;
unsigned long TimerValue;
unsigned long TimerControl;
unsigned long TimerClear;
} TimerStruct_t;
/* /*
* Returns number of ms since last clock interrupt. Note that interrupts * Returns number of ms since last clock interrupt. Note that interrupts
* will have been disabled by do_gettimeoffset() * will have been disabled by do_gettimeoffset()
*/ */
static unsigned long versatile_gettimeoffset(void) static unsigned long versatile_gettimeoffset(void)
{ {
volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE;
unsigned long ticks1, ticks2, status; unsigned long ticks1, ticks2, status;
/* /*
...@@ -828,11 +816,11 @@ static unsigned long versatile_gettimeoffset(void) ...@@ -828,11 +816,11 @@ static unsigned long versatile_gettimeoffset(void)
* an interrupt. We get around this by ensuring that the * an interrupt. We get around this by ensuring that the
* counter has not reloaded between our two reads. * counter has not reloaded between our two reads.
*/ */
ticks2 = timer0->TimerValue & 0xffff; ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
do { do {
ticks1 = ticks2; ticks1 = ticks2;
status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS); status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS);
ticks2 = timer0->TimerValue & 0xffff; ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
} while (ticks2 > ticks1); } while (ticks2 > ticks1);
/* /*
...@@ -859,12 +847,10 @@ static unsigned long versatile_gettimeoffset(void) ...@@ -859,12 +847,10 @@ static unsigned long versatile_gettimeoffset(void)
*/ */
static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
write_seqlock(&xtime_lock); write_seqlock(&xtime_lock);
// ...clear the interrupt // ...clear the interrupt
timer0->TimerClear = 1; writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
timer_tick(regs); timer_tick(regs);
...@@ -884,31 +870,32 @@ static struct irqaction versatile_timer_irq = { ...@@ -884,31 +870,32 @@ static struct irqaction versatile_timer_irq = {
*/ */
static void __init versatile_timer_init(void) static void __init versatile_timer_init(void)
{ {
volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; u32 val;
volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
volatile TimerStruct_t *timer3 = (volatile TimerStruct_t *)TIMER3_VA_BASE;
/* /*
* set clock frequency: * set clock frequency:
* VERSATILE_REFCLK is 32KHz * VERSATILE_REFCLK is 32KHz
* VERSATILE_TIMCLK is 1MHz * VERSATILE_TIMCLK is 1MHz
*/ */
*(volatile unsigned int *)IO_ADDRESS(VERSATILE_SCTL_BASE) |= val = readl(IO_ADDRESS(VERSATILE_SCTL_BASE));
((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
(VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel)); (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
(VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
(VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
IO_ADDRESS(VERSATILE_SCTL_BASE));
/* /*
* Initialise to a known state (all timers off) * Initialise to a known state (all timers off)
*/ */
timer0->TimerControl = 0; writel(0, TIMER0_VA_BASE + TIMER_CTRL);
timer1->TimerControl = 0; writel(0, TIMER1_VA_BASE + TIMER_CTRL);
timer2->TimerControl = 0; writel(0, TIMER2_VA_BASE + TIMER_CTRL);
timer3->TimerControl = 0; writel(0, TIMER3_VA_BASE + TIMER_CTRL);
timer0->TimerLoad = TIMER_RELOAD; writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
timer0->TimerValue = TIMER_RELOAD; writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE);
timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE; /* periodic + IE */ writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC |
TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL);
/* /*
* Make irqs happen for the system timer * Make irqs happen for the system timer
......
...@@ -437,7 +437,7 @@ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc) ...@@ -437,7 +437,7 @@ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
memtable_init(mi); memtable_init(mi);
if (mdesc->map_io) if (mdesc->map_io)
mdesc->map_io(); mdesc->map_io();
flush_tlb_all(); local_flush_tlb_all();
/* /*
* initialise the zones within each node * initialise the zones within each node
......
...@@ -682,7 +682,7 @@ void __init memtable_init(struct meminfo *mi) ...@@ -682,7 +682,7 @@ void __init memtable_init(struct meminfo *mi)
} }
flush_cache_all(); flush_cache_all();
flush_tlb_all(); local_flush_tlb_all();
top_pmd = pmd_off_k(0xffff0000); top_pmd = pmd_off_k(0xffff0000);
} }
......
...@@ -117,7 +117,13 @@ static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) ...@@ -117,7 +117,13 @@ static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m)
if (nh >= m) if (nh >= m)
return ~0ULL; return ~0ULL;
mh = m >> 32; mh = m >> 32;
z = (mh << 32 <= nh) ? 0xffffffff00000000ULL : (nh / mh) << 32; if (mh << 32 <= nh) {
z = 0xffffffff00000000ULL;
} else {
z = nh;
do_div(z, mh);
z <<= 32;
}
mul64to128(&termh, &terml, m, z); mul64to128(&termh, &terml, m, z);
sub128(&remh, &reml, nh, nl, termh, terml); sub128(&remh, &reml, nh, nl, termh, terml);
ml = m << 32; ml = m << 32;
...@@ -126,7 +132,12 @@ static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) ...@@ -126,7 +132,12 @@ static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m)
add128(&remh, &reml, remh, reml, mh, ml); add128(&remh, &reml, remh, reml, mh, ml);
} }
remh = (remh << 32) | (reml >> 32); remh = (remh << 32) | (reml >> 32);
z |= (mh << 32 <= remh) ? 0xffffffff : remh / mh; if (mh << 32 <= remh) {
z |= 0xffffffff;
} else {
do_div(remh, mh);
z |= remh;
}
return z; return z;
} }
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <asm/div64.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/vfp.h> #include <asm/vfp.h>
......
...@@ -89,7 +89,7 @@ void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs) ...@@ -89,7 +89,7 @@ void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
current->thread.error_code = 0; current->thread.error_code = 0;
current->thread.trap_no = 6; current->thread.trap_no = 6;
force_sig_info(SIGFPE, &info, current); send_sig_info(SIGFPE, &info, current);
} }
static void vfp_panic(char *reason) static void vfp_panic(char *reason)
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <asm/div64.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/vfp.h> #include <asm/vfp.h>
...@@ -303,7 +305,11 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand) ...@@ -303,7 +305,11 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
if (z <= a) if (z <= a)
return (s32)a >> 1; return (s32)a >> 1;
} }
return (u32)(((u64)a << 31) / z) + (z >> 1); {
u64 v = (u64)a << 31;
do_div(v, z);
return v + (z >> 1);
}
} }
static u32 vfp_single_fsqrt(int sd, int unused, s32 m, u32 fpscr) static u32 vfp_single_fsqrt(int sd, int unused, s32 m, u32 fpscr)
...@@ -1107,7 +1113,11 @@ static u32 vfp_single_fdiv(int sd, int sn, s32 m, u32 fpscr) ...@@ -1107,7 +1113,11 @@ static u32 vfp_single_fdiv(int sd, int sn, s32 m, u32 fpscr)
vsn.significand >>= 1; vsn.significand >>= 1;
vsd.exponent++; vsd.exponent++;
} }
vsd.significand = ((u64)vsn.significand << 32) / vsm.significand; {
u64 significand = (u64)vsn.significand << 32;
do_div(significand, vsm.significand);
vsd.significand = significand;
}
if ((vsd.significand & 0x3f) == 0) if ((vsd.significand & 0x3f) == 0)
vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32); vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
......
...@@ -68,7 +68,6 @@ struct etherh_priv { ...@@ -68,7 +68,6 @@ struct etherh_priv {
void __iomem *dma_base; void __iomem *dma_base;
unsigned int id; unsigned int id;
void __iomem *ctrl_port; void __iomem *ctrl_port;
void __iomem *base;
unsigned char ctrl; unsigned char ctrl;
u32 supported; u32 supported;
}; };
...@@ -178,7 +177,7 @@ etherh_setif(struct net_device *dev) ...@@ -178,7 +177,7 @@ etherh_setif(struct net_device *dev)
switch (etherh_priv(dev)->id) { switch (etherh_priv(dev)->id) {
case PROD_I3_ETHERLAN600: case PROD_I3_ETHERLAN600:
case PROD_I3_ETHERLAN600A: case PROD_I3_ETHERLAN600A:
addr = etherh_priv(dev)->base + EN0_RCNTHI; addr = (void *)dev->base_addr + EN0_RCNTHI;
switch (dev->if_port) { switch (dev->if_port) {
case IF_PORT_10BASE2: case IF_PORT_10BASE2:
...@@ -219,7 +218,7 @@ etherh_getifstat(struct net_device *dev) ...@@ -219,7 +218,7 @@ etherh_getifstat(struct net_device *dev)
switch (etherh_priv(dev)->id) { switch (etherh_priv(dev)->id) {
case PROD_I3_ETHERLAN600: case PROD_I3_ETHERLAN600:
case PROD_I3_ETHERLAN600A: case PROD_I3_ETHERLAN600A:
addr = etherh_priv(dev)->base + EN0_RCNTHI; addr = (void *)dev->base_addr + EN0_RCNTHI;
switch (dev->if_port) { switch (dev->if_port) {
case IF_PORT_10BASE2: case IF_PORT_10BASE2:
stat = 1; stat = 1;
...@@ -282,7 +281,7 @@ static void ...@@ -282,7 +281,7 @@ static void
etherh_reset(struct net_device *dev) etherh_reset(struct net_device *dev)
{ {
struct ei_device *ei_local = netdev_priv(dev); struct ei_device *ei_local = netdev_priv(dev);
void __iomem *addr = etherh_priv(dev)->base; void __iomem *addr = (void *)dev->base_addr;
writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr); writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr);
...@@ -328,7 +327,7 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf ...@@ -328,7 +327,7 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf
ei_local->dmaing = 1; ei_local->dmaing = 1;
addr = etherh_priv(dev)->base; addr = (void *)dev->base_addr;
dma_base = etherh_priv(dev)->dma_base; dma_base = etherh_priv(dev)->dma_base;
count = (count + 1) & ~1; count = (count + 1) & ~1;
...@@ -388,7 +387,7 @@ etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ...@@ -388,7 +387,7 @@ etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int
ei_local->dmaing = 1; ei_local->dmaing = 1;
addr = etherh_priv(dev)->base; addr = (void *)dev->base_addr;
dma_base = etherh_priv(dev)->dma_base; dma_base = etherh_priv(dev)->dma_base;
buf = skb->data; buf = skb->data;
...@@ -428,7 +427,7 @@ etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_p ...@@ -428,7 +427,7 @@ etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_p
ei_local->dmaing = 1; ei_local->dmaing = 1;
addr = etherh_priv(dev)->base; addr = (void *)dev->base_addr;
dma_base = etherh_priv(dev)->dma_base; dma_base = etherh_priv(dev)->dma_base;
writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
...@@ -697,8 +696,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) ...@@ -697,8 +696,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
eh->ctrl_port = eh->ioc_fast; eh->ctrl_port = eh->ioc_fast;
} }
eh->base = eh->memc + data->ns8390_offset; dev->base_addr = (unsigned long)eh->memc + data->ns8390_offset;
dev->base_addr = (unsigned long)eh->base;
eh->dma_base = eh->memc + data->dataport_offset; eh->dma_base = eh->memc + data->dataport_offset;
eh->ctrl_port += data->ctrlport_offset; eh->ctrl_port += data->ctrlport_offset;
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
* *
*/ */
#include "hardware.h"
.macro addruart,rx .macro addruart,rx
mrc p15, 0, \rx, c1, c0 mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled? tst \rx, #1 @ MMU enabled?
......
#ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H
#define __ASM_ARM_HARDWARE_ARM_TIMER_H
#define TIMER_LOAD 0x00
#define TIMER_VALUE 0x04
#define TIMER_CTRL 0x08
#define TIMER_CTRL_ONESHOT (1 << 0)
#define TIMER_CTRL_32BIT (1 << 1)
#define TIMER_CTRL_DIV1 (0 << 2)
#define TIMER_CTRL_DIV16 (1 << 2)
#define TIMER_CTRL_DIV256 (2 << 2)
#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable (versatile only) */
#define TIMER_CTRL_PERIODIC (1 << 6)
#define TIMER_CTRL_ENABLE (1 << 7)
#define TIMER_INTCLR 0x0c
#define TIMER_RIS 0x10
#define TIMER_MIS 0x14
#define TIMER_BGLOAD 0x18
#endif
...@@ -290,7 +290,6 @@ do { \ ...@@ -290,7 +290,6 @@ do { \
}) })
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
#error SMP not supported
#define smp_mb() mb() #define smp_mb() mb()
#define smp_rmb() rmb() #define smp_rmb() rmb()
...@@ -304,6 +303,8 @@ do { \ ...@@ -304,6 +303,8 @@ do { \
#define smp_wmb() barrier() #define smp_wmb() barrier()
#define smp_read_barrier_depends() do { } while(0) #define smp_read_barrier_depends() do { } while(0)
#endif /* CONFIG_SMP */
#if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110) #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
/* /*
* On the StrongARM, "swp" is terminally broken since it bypasses the * On the StrongARM, "swp" is terminally broken since it bypasses the
...@@ -316,9 +317,16 @@ do { \ ...@@ -316,9 +317,16 @@ do { \
* *
* We choose (1) since its the "easiest" to achieve here and is not * We choose (1) since its the "easiest" to achieve here and is not
* dependent on the processor type. * dependent on the processor type.
*
* NOTE that this solution won't work on an SMP system, so explcitly
* forbid it here.
*/ */
#ifdef CONFIG_SMP
#error SMP is not supported on SA1100/SA110
#else
#define swp_is_buggy #define swp_is_buggy
#endif #endif
#endif
static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
{ {
...@@ -361,8 +369,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size ...@@ -361,8 +369,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
return ret; return ret;
} }
#endif /* CONFIG_SMP */
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#define arch_align_stack(x) (x) #define arch_align_stack(x) (x)
......
...@@ -235,7 +235,7 @@ extern struct cpu_tlb_fns cpu_tlb; ...@@ -235,7 +235,7 @@ extern struct cpu_tlb_fns cpu_tlb;
#define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f))) #define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f)))
static inline void flush_tlb_all(void) static inline void local_flush_tlb_all(void)
{ {
const int zero = 0; const int zero = 0;
const unsigned int __tlb_flag = __cpu_tlb_flags; const unsigned int __tlb_flag = __cpu_tlb_flags;
...@@ -253,7 +253,7 @@ static inline void flush_tlb_all(void) ...@@ -253,7 +253,7 @@ static inline void flush_tlb_all(void)
asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero)); asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
} }
static inline void flush_tlb_mm(struct mm_struct *mm) static inline void local_flush_tlb_mm(struct mm_struct *mm)
{ {
const int zero = 0; const int zero = 0;
const int asid = ASID(mm); const int asid = ASID(mm);
...@@ -282,7 +282,7 @@ static inline void flush_tlb_mm(struct mm_struct *mm) ...@@ -282,7 +282,7 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
} }
static inline void static inline void
flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
{ {
const int zero = 0; const int zero = 0;
const unsigned int __tlb_flag = __cpu_tlb_flags; const unsigned int __tlb_flag = __cpu_tlb_flags;
...@@ -313,7 +313,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) ...@@ -313,7 +313,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (uaddr)); asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (uaddr));
} }
static inline void flush_tlb_kernel_page(unsigned long kaddr) static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
{ {
const int zero = 0; const int zero = 0;
const unsigned int __tlb_flag = __cpu_tlb_flags; const unsigned int __tlb_flag = __cpu_tlb_flags;
...@@ -384,8 +384,24 @@ static inline void clean_pmd_entry(pmd_t *pmd) ...@@ -384,8 +384,24 @@ static inline void clean_pmd_entry(pmd_t *pmd)
/* /*
* Convert calls to our calling convention. * Convert calls to our calling convention.
*/ */
#define flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma) #define local_flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma)
#define flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e) #define local_flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e)
#ifndef CONFIG_SMP
#define flush_tlb_all local_flush_tlb_all
#define flush_tlb_mm local_flush_tlb_mm
#define flush_tlb_page local_flush_tlb_page
#define flush_tlb_kernel_page local_flush_tlb_kernel_page
#define flush_tlb_range local_flush_tlb_range
#define flush_tlb_kernel_range local_flush_tlb_kernel_range
#else
extern void flush_tlb_all(void);
extern void flush_tlb_mm(struct mm_struct *mm);
extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
extern void flush_tlb_kernel_page(unsigned long kaddr);
extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
#endif
/* /*
* if PG_dcache_dirty is set for the page, we need to ensure that any * if PG_dcache_dirty is set for the page, we need to ensure that any
......
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