Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
31bbed52
Commit
31bbed52
authored
Mar 05, 2009
by
Ingo Molnar
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'x86/uv' into x86/core
parents
0fbba487
b2b35259
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
452 additions
and
1 deletion
+452
-1
arch/x86/include/asm/apic.h
arch/x86/include/asm/apic.h
+2
-0
arch/x86/include/asm/entry_arch.h
arch/x86/include/asm/entry_arch.h
+2
-0
arch/x86/include/asm/hardirq.h
arch/x86/include/asm/hardirq.h
+1
-0
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/hw_irq.h
+1
-0
arch/x86/include/asm/irq.h
arch/x86/include/asm/irq.h
+1
-0
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/irq_vectors.h
+5
-0
arch/x86/include/asm/uv/uv_hub.h
arch/x86/include/asm/uv/uv_hub.h
+4
-0
arch/x86/kernel/Makefile
arch/x86/kernel/Makefile
+1
-1
arch/x86/kernel/entry_64.S
arch/x86/kernel/entry_64.S
+2
-0
arch/x86/kernel/irq.c
arch/x86/kernel/irq.c
+34
-0
arch/x86/kernel/irqinit_32.c
arch/x86/kernel/irqinit_32.c
+3
-0
arch/x86/kernel/irqinit_64.c
arch/x86/kernel/irqinit_64.c
+3
-0
arch/x86/kernel/uv_time.c
arch/x86/kernel/uv_time.c
+393
-0
No files found.
arch/x86/include/asm/apic.h
View file @
31bbed52
...
...
@@ -379,6 +379,7 @@ static inline u32 safe_apic_wait_icr_idle(void)
static
inline
void
ack_APIC_irq
(
void
)
{
#ifdef CONFIG_X86_LOCAL_APIC
/*
* ack_APIC_irq() actually gets compiled as a single instruction
* ... yummie.
...
...
@@ -386,6 +387,7 @@ static inline void ack_APIC_irq(void)
/* Docs say use 0 for future compatibility */
apic_write
(
APIC_EOI
,
0
);
#endif
}
static
inline
unsigned
default_get_apic_id
(
unsigned
long
x
)
...
...
arch/x86/include/asm/entry_arch.h
View file @
31bbed52
...
...
@@ -33,6 +33,8 @@ BUILD_INTERRUPT3(invalidate_interrupt7,INVALIDATE_TLB_VECTOR_START+7,
smp_invalidate_interrupt
)
#endif
BUILD_INTERRUPT
(
generic_interrupt
,
GENERIC_INTERRUPT_VECTOR
)
/*
* every pentium local APIC has two 'local interrupts', with a
* soft-definable vector attached to both interrupts, one of
...
...
arch/x86/include/asm/hardirq.h
View file @
31bbed52
...
...
@@ -12,6 +12,7 @@ typedef struct {
unsigned
int
apic_timer_irqs
;
/* arch dependent */
unsigned
int
irq_spurious_count
;
#endif
unsigned
int
generic_irqs
;
/* arch dependent */
#ifdef CONFIG_SMP
unsigned
int
irq_resched_count
;
unsigned
int
irq_call_count
;
...
...
arch/x86/include/asm/hw_irq.h
View file @
31bbed52
...
...
@@ -27,6 +27,7 @@
/* Interrupt handlers registered during init_IRQ */
extern
void
apic_timer_interrupt
(
void
);
extern
void
generic_interrupt
(
void
);
extern
void
error_interrupt
(
void
);
extern
void
spurious_interrupt
(
void
);
extern
void
thermal_interrupt
(
void
);
...
...
arch/x86/include/asm/irq.h
View file @
31bbed52
...
...
@@ -36,6 +36,7 @@ static inline int irq_canonicalize(int irq)
extern
void
fixup_irqs
(
void
);
#endif
extern
void
(
*
generic_interrupt_extension
)(
void
);
extern
void
init_IRQ
(
void
);
extern
void
native_init_IRQ
(
void
);
extern
bool
handle_irq
(
unsigned
irq
,
struct
pt_regs
*
regs
);
...
...
arch/x86/include/asm/irq_vectors.h
View file @
31bbed52
...
...
@@ -111,6 +111,11 @@
*/
#define LOCAL_PERF_VECTOR 0xee
/*
* Generic system vector for platform specific use
*/
#define GENERIC_INTERRUPT_VECTOR 0xed
/*
* First APIC vector available to drivers: (vectors 0x30-0xee) we
* start at 0x31(0x41) to spread out vectors evenly between priority
...
...
arch/x86/include/asm/uv/uv_hub.h
View file @
31bbed52
...
...
@@ -199,6 +199,10 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
#define SCIR_CPU_ACTIVITY 0x02
/* not idle */
#define SCIR_CPU_HB_INTERVAL (HZ)
/* once per second */
/* Loop through all installed blades */
#define for_each_possible_blade(bid) \
for ((bid) = 0; (bid) < uv_num_possible_blades(); (bid)++)
/*
* Macros for converting between kernel virtual addresses, socket local physical
* addresses, and UV global physical addresses.
...
...
arch/x86/kernel/Makefile
View file @
31bbed52
...
...
@@ -111,7 +111,7 @@ obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o # NB rename without _64
###
# 64 bit specific files
ifeq
($(CONFIG_X86_64),y)
obj-$(CONFIG_X86_UV)
+=
tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o
obj-$(CONFIG_X86_UV)
+=
tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o
uv_time.o
obj-$(CONFIG_X86_PM_TIMER)
+=
pmtimer_64.o
obj-$(CONFIG_AUDIT)
+=
audit_64.o
...
...
arch/x86/kernel/entry_64.S
View file @
31bbed52
...
...
@@ -984,6 +984,8 @@ apicinterrupt UV_BAU_MESSAGE \
#endif
apicinterrupt
LOCAL_TIMER_VECTOR
\
apic_timer_interrupt
smp_apic_timer_interrupt
apicinterrupt
GENERIC_INTERRUPT_VECTOR
\
generic_interrupt
smp_generic_interrupt
#ifdef CONFIG_SMP
apicinterrupt
INVALIDATE_TLB_VECTOR_START
+0
\
...
...
arch/x86/kernel/irq.c
View file @
31bbed52
...
...
@@ -15,6 +15,9 @@
atomic_t
irq_err_count
;
/* Function pointer for generic interrupt vector handling */
void
(
*
generic_interrupt_extension
)(
void
)
=
NULL
;
/*
* 'what should we do if we get a hw irq event on an illegal vector'.
* each architecture has to answer this themselves.
...
...
@@ -56,6 +59,12 @@ static int show_other_interrupts(struct seq_file *p)
seq_printf
(
p
,
"%10u "
,
irq_stats
(
j
)
->
apic_timer_irqs
);
seq_printf
(
p
,
" Local timer interrupts
\n
"
);
#endif
if
(
generic_interrupt_extension
)
{
seq_printf
(
p
,
"PLT: "
);
for_each_online_cpu
(
j
)
seq_printf
(
p
,
"%10u "
,
irq_stats
(
j
)
->
generic_irqs
);
seq_printf
(
p
,
" Platform interrupts
\n
"
);
}
#ifdef CONFIG_SMP
seq_printf
(
p
,
"RES: "
);
for_each_online_cpu
(
j
)
...
...
@@ -163,6 +172,8 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
#ifdef CONFIG_X86_LOCAL_APIC
sum
+=
irq_stats
(
cpu
)
->
apic_timer_irqs
;
#endif
if
(
generic_interrupt_extension
)
sum
+=
irq_stats
(
cpu
)
->
generic_irqs
;
#ifdef CONFIG_SMP
sum
+=
irq_stats
(
cpu
)
->
irq_resched_count
;
sum
+=
irq_stats
(
cpu
)
->
irq_call_count
;
...
...
@@ -226,4 +237,27 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
return
1
;
}
/*
* Handler for GENERIC_INTERRUPT_VECTOR.
*/
void
smp_generic_interrupt
(
struct
pt_regs
*
regs
)
{
struct
pt_regs
*
old_regs
=
set_irq_regs
(
regs
);
ack_APIC_irq
();
exit_idle
();
irq_enter
();
inc_irq_stat
(
generic_irqs
);
if
(
generic_interrupt_extension
)
generic_interrupt_extension
();
irq_exit
();
set_irq_regs
(
old_regs
);
}
EXPORT_SYMBOL_GPL
(
vector_used_by_percpu_irq
);
arch/x86/kernel/irqinit_32.c
View file @
31bbed52
...
...
@@ -175,6 +175,9 @@ void __init native_init_IRQ(void)
/* self generated IPI for local APIC timer */
alloc_intr_gate
(
LOCAL_TIMER_VECTOR
,
apic_timer_interrupt
);
/* generic IPI for platform specific use */
alloc_intr_gate
(
GENERIC_INTERRUPT_VECTOR
,
generic_interrupt
);
/* IPI vectors for APIC spurious and error interrupts */
alloc_intr_gate
(
SPURIOUS_APIC_VECTOR
,
spurious_interrupt
);
alloc_intr_gate
(
ERROR_APIC_VECTOR
,
error_interrupt
);
...
...
arch/x86/kernel/irqinit_64.c
View file @
31bbed52
...
...
@@ -147,6 +147,9 @@ static void __init apic_intr_init(void)
/* self generated IPI for local APIC timer */
alloc_intr_gate
(
LOCAL_TIMER_VECTOR
,
apic_timer_interrupt
);
/* generic IPI for platform specific use */
alloc_intr_gate
(
GENERIC_INTERRUPT_VECTOR
,
generic_interrupt
);
/* IPI vectors for APIC spurious and error interrupts */
alloc_intr_gate
(
SPURIOUS_APIC_VECTOR
,
spurious_interrupt
);
alloc_intr_gate
(
ERROR_APIC_VECTOR
,
error_interrupt
);
...
...
arch/x86/kernel/uv_time.c
0 → 100644
View file @
31bbed52
/*
* SGI RTC clock/timer routines.
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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
*
* Copyright (c) 2009 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) Dimitri Sivanich
*/
#include <linux/clockchips.h>
#include <asm/uv/uv_mmrs.h>
#include <asm/uv/uv_hub.h>
#include <asm/uv/bios.h>
#include <asm/uv/uv.h>
#include <asm/apic.h>
#include <asm/cpu.h>
#define RTC_NAME "sgi_rtc"
static
cycle_t
uv_read_rtc
(
void
);
static
int
uv_rtc_next_event
(
unsigned
long
,
struct
clock_event_device
*
);
static
void
uv_rtc_timer_setup
(
enum
clock_event_mode
,
struct
clock_event_device
*
);
static
struct
clocksource
clocksource_uv
=
{
.
name
=
RTC_NAME
,
.
rating
=
400
,
.
read
=
uv_read_rtc
,
.
mask
=
(
cycle_t
)
UVH_RTC_REAL_TIME_CLOCK_MASK
,
.
shift
=
10
,
.
flags
=
CLOCK_SOURCE_IS_CONTINUOUS
,
};
static
struct
clock_event_device
clock_event_device_uv
=
{
.
name
=
RTC_NAME
,
.
features
=
CLOCK_EVT_FEAT_ONESHOT
,
.
shift
=
20
,
.
rating
=
400
,
.
irq
=
-
1
,
.
set_next_event
=
uv_rtc_next_event
,
.
set_mode
=
uv_rtc_timer_setup
,
.
event_handler
=
NULL
,
};
static
DEFINE_PER_CPU
(
struct
clock_event_device
,
cpu_ced
);
/* There is one of these allocated per node */
struct
uv_rtc_timer_head
{
spinlock_t
lock
;
/* next cpu waiting for timer, local node relative: */
int
next_cpu
;
/* number of cpus on this node: */
int
ncpus
;
struct
{
int
lcpu
;
/* systemwide logical cpu number */
u64
expires
;
/* next timer expiration for this cpu */
}
cpu
[
1
];
};
/*
* Access to uv_rtc_timer_head via blade id.
*/
static
struct
uv_rtc_timer_head
**
blade_info
__read_mostly
;
static
int
uv_rtc_enable
;
/*
* Hardware interface routines
*/
/* Send IPIs to another node */
static
void
uv_rtc_send_IPI
(
int
cpu
)
{
unsigned
long
apicid
,
val
;
int
pnode
;
apicid
=
cpu_physical_id
(
cpu
);
pnode
=
uv_apicid_to_pnode
(
apicid
);
val
=
(
1UL
<<
UVH_IPI_INT_SEND_SHFT
)
|
(
apicid
<<
UVH_IPI_INT_APIC_ID_SHFT
)
|
(
GENERIC_INTERRUPT_VECTOR
<<
UVH_IPI_INT_VECTOR_SHFT
);
uv_write_global_mmr64
(
pnode
,
UVH_IPI_INT
,
val
);
}
/* Check for an RTC interrupt pending */
static
int
uv_intr_pending
(
int
pnode
)
{
return
uv_read_global_mmr64
(
pnode
,
UVH_EVENT_OCCURRED0
)
&
UVH_EVENT_OCCURRED0_RTC1_MASK
;
}
/* Setup interrupt and return non-zero if early expiration occurred. */
static
int
uv_setup_intr
(
int
cpu
,
u64
expires
)
{
u64
val
;
int
pnode
=
uv_cpu_to_pnode
(
cpu
);
uv_write_global_mmr64
(
pnode
,
UVH_RTC1_INT_CONFIG
,
UVH_RTC1_INT_CONFIG_M_MASK
);
uv_write_global_mmr64
(
pnode
,
UVH_INT_CMPB
,
-
1L
);
uv_write_global_mmr64
(
pnode
,
UVH_EVENT_OCCURRED0_ALIAS
,
UVH_EVENT_OCCURRED0_RTC1_MASK
);
val
=
(
GENERIC_INTERRUPT_VECTOR
<<
UVH_RTC1_INT_CONFIG_VECTOR_SHFT
)
|
((
u64
)
cpu_physical_id
(
cpu
)
<<
UVH_RTC1_INT_CONFIG_APIC_ID_SHFT
);
/* Set configuration */
uv_write_global_mmr64
(
pnode
,
UVH_RTC1_INT_CONFIG
,
val
);
/* Initialize comparator value */
uv_write_global_mmr64
(
pnode
,
UVH_INT_CMPB
,
expires
);
return
(
expires
<
uv_read_rtc
()
&&
!
uv_intr_pending
(
pnode
));
}
/*
* Per-cpu timer tracking routines
*/
static
__init
void
uv_rtc_deallocate_timers
(
void
)
{
int
bid
;
for_each_possible_blade
(
bid
)
{
kfree
(
blade_info
[
bid
]);
}
kfree
(
blade_info
);
}
/* Allocate per-node list of cpu timer expiration times. */
static
__init
int
uv_rtc_allocate_timers
(
void
)
{
int
cpu
;
blade_info
=
kmalloc
(
uv_possible_blades
*
sizeof
(
void
*
),
GFP_KERNEL
);
if
(
!
blade_info
)
return
-
ENOMEM
;
memset
(
blade_info
,
0
,
uv_possible_blades
*
sizeof
(
void
*
));
for_each_present_cpu
(
cpu
)
{
int
nid
=
cpu_to_node
(
cpu
);
int
bid
=
uv_cpu_to_blade_id
(
cpu
);
int
bcpu
=
uv_cpu_hub_info
(
cpu
)
->
blade_processor_id
;
struct
uv_rtc_timer_head
*
head
=
blade_info
[
bid
];
if
(
!
head
)
{
head
=
kmalloc_node
(
sizeof
(
struct
uv_rtc_timer_head
)
+
(
uv_blade_nr_possible_cpus
(
bid
)
*
2
*
sizeof
(
u64
)),
GFP_KERNEL
,
nid
);
if
(
!
head
)
{
uv_rtc_deallocate_timers
();
return
-
ENOMEM
;
}
spin_lock_init
(
&
head
->
lock
);
head
->
ncpus
=
uv_blade_nr_possible_cpus
(
bid
);
head
->
next_cpu
=
-
1
;
blade_info
[
bid
]
=
head
;
}
head
->
cpu
[
bcpu
].
lcpu
=
cpu
;
head
->
cpu
[
bcpu
].
expires
=
ULLONG_MAX
;
}
return
0
;
}
/* Find and set the next expiring timer. */
static
void
uv_rtc_find_next_timer
(
struct
uv_rtc_timer_head
*
head
,
int
pnode
)
{
u64
lowest
=
ULLONG_MAX
;
int
c
,
bcpu
=
-
1
;
head
->
next_cpu
=
-
1
;
for
(
c
=
0
;
c
<
head
->
ncpus
;
c
++
)
{
u64
exp
=
head
->
cpu
[
c
].
expires
;
if
(
exp
<
lowest
)
{
bcpu
=
c
;
lowest
=
exp
;
}
}
if
(
bcpu
>=
0
)
{
head
->
next_cpu
=
bcpu
;
c
=
head
->
cpu
[
bcpu
].
lcpu
;
if
(
uv_setup_intr
(
c
,
lowest
))
/* If we didn't set it up in time, trigger */
uv_rtc_send_IPI
(
c
);
}
else
{
uv_write_global_mmr64
(
pnode
,
UVH_RTC1_INT_CONFIG
,
UVH_RTC1_INT_CONFIG_M_MASK
);
}
}
/*
* Set expiration time for current cpu.
*
* Returns 1 if we missed the expiration time.
*/
static
int
uv_rtc_set_timer
(
int
cpu
,
u64
expires
)
{
int
pnode
=
uv_cpu_to_pnode
(
cpu
);
int
bid
=
uv_cpu_to_blade_id
(
cpu
);
struct
uv_rtc_timer_head
*
head
=
blade_info
[
bid
];
int
bcpu
=
uv_cpu_hub_info
(
cpu
)
->
blade_processor_id
;
u64
*
t
=
&
head
->
cpu
[
bcpu
].
expires
;
unsigned
long
flags
;
int
next_cpu
;
spin_lock_irqsave
(
&
head
->
lock
,
flags
);
next_cpu
=
head
->
next_cpu
;
*
t
=
expires
;
/* Will this one be next to go off? */
if
(
next_cpu
<
0
||
bcpu
==
next_cpu
||
expires
<
head
->
cpu
[
next_cpu
].
expires
)
{
head
->
next_cpu
=
bcpu
;
if
(
uv_setup_intr
(
cpu
,
expires
))
{
*
t
=
ULLONG_MAX
;
uv_rtc_find_next_timer
(
head
,
pnode
);
spin_unlock_irqrestore
(
&
head
->
lock
,
flags
);
return
1
;
}
}
spin_unlock_irqrestore
(
&
head
->
lock
,
flags
);
return
0
;
}
/*
* Unset expiration time for current cpu.
*
* Returns 1 if this timer was pending.
*/
static
int
uv_rtc_unset_timer
(
int
cpu
)
{
int
pnode
=
uv_cpu_to_pnode
(
cpu
);
int
bid
=
uv_cpu_to_blade_id
(
cpu
);
struct
uv_rtc_timer_head
*
head
=
blade_info
[
bid
];
int
bcpu
=
uv_cpu_hub_info
(
cpu
)
->
blade_processor_id
;
u64
*
t
=
&
head
->
cpu
[
bcpu
].
expires
;
unsigned
long
flags
;
int
rc
=
0
;
spin_lock_irqsave
(
&
head
->
lock
,
flags
);
if
(
head
->
next_cpu
==
bcpu
&&
uv_read_rtc
()
>=
*
t
)
rc
=
1
;
*
t
=
ULLONG_MAX
;
/* Was the hardware setup for this timer? */
if
(
head
->
next_cpu
==
bcpu
)
uv_rtc_find_next_timer
(
head
,
pnode
);
spin_unlock_irqrestore
(
&
head
->
lock
,
flags
);
return
rc
;
}
/*
* Kernel interface routines.
*/
/*
* Read the RTC.
*/
static
cycle_t
uv_read_rtc
(
void
)
{
return
(
cycle_t
)
uv_read_local_mmr
(
UVH_RTC
);
}
/*
* Program the next event, relative to now
*/
static
int
uv_rtc_next_event
(
unsigned
long
delta
,
struct
clock_event_device
*
ced
)
{
int
ced_cpu
=
cpumask_first
(
ced
->
cpumask
);
return
uv_rtc_set_timer
(
ced_cpu
,
delta
+
uv_read_rtc
());
}
/*
* Setup the RTC timer in oneshot mode
*/
static
void
uv_rtc_timer_setup
(
enum
clock_event_mode
mode
,
struct
clock_event_device
*
evt
)
{
int
ced_cpu
=
cpumask_first
(
evt
->
cpumask
);
switch
(
mode
)
{
case
CLOCK_EVT_MODE_PERIODIC
:
case
CLOCK_EVT_MODE_ONESHOT
:
case
CLOCK_EVT_MODE_RESUME
:
/* Nothing to do here yet */
break
;
case
CLOCK_EVT_MODE_UNUSED
:
case
CLOCK_EVT_MODE_SHUTDOWN
:
uv_rtc_unset_timer
(
ced_cpu
);
break
;
}
}
static
void
uv_rtc_interrupt
(
void
)
{
struct
clock_event_device
*
ced
=
&
__get_cpu_var
(
cpu_ced
);
int
cpu
=
smp_processor_id
();
if
(
!
ced
||
!
ced
->
event_handler
)
return
;
if
(
uv_rtc_unset_timer
(
cpu
)
!=
1
)
return
;
ced
->
event_handler
(
ced
);
}
static
int
__init
uv_enable_rtc
(
char
*
str
)
{
uv_rtc_enable
=
1
;
return
1
;
}
__setup
(
"uvrtc"
,
uv_enable_rtc
);
static
__init
void
uv_rtc_register_clockevents
(
struct
work_struct
*
dummy
)
{
struct
clock_event_device
*
ced
=
&
__get_cpu_var
(
cpu_ced
);
*
ced
=
clock_event_device_uv
;
ced
->
cpumask
=
cpumask_of
(
smp_processor_id
());
clockevents_register_device
(
ced
);
}
static
__init
int
uv_rtc_setup_clock
(
void
)
{
int
rc
;
if
(
!
uv_rtc_enable
||
!
is_uv_system
()
||
generic_interrupt_extension
)
return
-
ENODEV
;
generic_interrupt_extension
=
uv_rtc_interrupt
;
clocksource_uv
.
mult
=
clocksource_hz2mult
(
sn_rtc_cycles_per_second
,
clocksource_uv
.
shift
);
rc
=
clocksource_register
(
&
clocksource_uv
);
if
(
rc
)
{
generic_interrupt_extension
=
NULL
;
return
rc
;
}
/* Setup and register clockevents */
rc
=
uv_rtc_allocate_timers
();
if
(
rc
)
{
clocksource_unregister
(
&
clocksource_uv
);
generic_interrupt_extension
=
NULL
;
return
rc
;
}
clock_event_device_uv
.
mult
=
div_sc
(
sn_rtc_cycles_per_second
,
NSEC_PER_SEC
,
clock_event_device_uv
.
shift
);
clock_event_device_uv
.
min_delta_ns
=
NSEC_PER_SEC
/
sn_rtc_cycles_per_second
;
clock_event_device_uv
.
max_delta_ns
=
clocksource_uv
.
mask
*
(
NSEC_PER_SEC
/
sn_rtc_cycles_per_second
);
rc
=
schedule_on_each_cpu
(
uv_rtc_register_clockevents
);
if
(
rc
)
{
clocksource_unregister
(
&
clocksource_uv
);
generic_interrupt_extension
=
NULL
;
uv_rtc_deallocate_timers
();
}
return
rc
;
}
arch_initcall
(
uv_rtc_setup_clock
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment