Skip to content

Commit

Permalink
Merge branch 'timers-for-linus-hpet' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/tip/linux-2.6-tip

* 'timers-for-linus-hpet' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86: hpet: Make WARN_ON understandable
  x86: arch specific support for remapping HPET MSIs
  intr-remap: generic support for remapping HPET MSIs
  x86, hpet: Simplify the HPET code
  x86, hpet: Disable per-cpu hpet timer if ARAT is supported
  • Loading branch information
Linus Torvalds committed Dec 9, 2009
2 parents e069efb + 18ed61d commit 849e8de
Showing 8 changed files with 199 additions and 43 deletions.
7 changes: 4 additions & 3 deletions arch/x86/include/asm/hpet.h
Original file line number Diff line number Diff line change
@@ -65,11 +65,12 @@
/* hpet memory map physical address */
extern unsigned long hpet_address;
extern unsigned long force_hpet_address;
extern u8 hpet_blockid;
extern int hpet_force_user;
extern int is_hpet_enabled(void);
extern int hpet_enable(void);
extern void hpet_disable(void);
extern unsigned long hpet_readl(unsigned long a);
extern unsigned int hpet_readl(unsigned int a);
extern void force_hpet_resume(void);

extern void hpet_msi_unmask(unsigned int irq);
@@ -78,9 +79,9 @@ extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg);
extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);

#ifdef CONFIG_PCI_MSI
extern int arch_setup_hpet_msi(unsigned int irq);
extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id);
#else
static inline int arch_setup_hpet_msi(unsigned int irq)
static inline int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
{
return -EINVAL;
}
1 change: 1 addition & 0 deletions arch/x86/kernel/acpi/boot.c
Original file line number Diff line number Diff line change
@@ -624,6 +624,7 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table)
}

hpet_address = hpet_tbl->address.address;
hpet_blockid = hpet_tbl->sequence;

/*
* Some broken BIOSes advertise HPET at 0x0. We really do not
49 changes: 41 additions & 8 deletions arch/x86/kernel/apic/io_apic.c
Original file line number Diff line number Diff line change
@@ -3267,7 +3267,8 @@ void destroy_irq(unsigned int irq)
* MSI message composition
*/
#ifdef CONFIG_PCI_MSI
static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
struct msi_msg *msg, u8 hpet_id)
{
struct irq_cfg *cfg;
int err;
@@ -3301,7 +3302,10 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
irte.dest_id = IRTE_DEST(dest);

/* Set source-id of interrupt request */
set_msi_sid(&irte, pdev);
if (pdev)
set_msi_sid(&irte, pdev);
else
set_hpet_sid(&irte, hpet_id);

modify_irte(irq, &irte);

@@ -3466,7 +3470,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
int ret;
struct msi_msg msg;

ret = msi_compose_msg(dev, irq, &msg);
ret = msi_compose_msg(dev, irq, &msg, -1);
if (ret < 0)
return ret;

@@ -3599,7 +3603,7 @@ int arch_setup_dmar_msi(unsigned int irq)
int ret;
struct msi_msg msg;

ret = msi_compose_msg(NULL, irq, &msg);
ret = msi_compose_msg(NULL, irq, &msg, -1);
if (ret < 0)
return ret;
dmar_msi_write(irq, &msg);
@@ -3639,6 +3643,19 @@ static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)

#endif /* CONFIG_SMP */

static struct irq_chip ir_hpet_msi_type = {
.name = "IR-HPET_MSI",
.unmask = hpet_msi_unmask,
.mask = hpet_msi_mask,
#ifdef CONFIG_INTR_REMAP
.ack = ir_ack_apic_edge,
#ifdef CONFIG_SMP
.set_affinity = ir_set_msi_irq_affinity,
#endif
#endif
.retrigger = ioapic_retrigger_irq,
};

static struct irq_chip hpet_msi_type = {
.name = "HPET_MSI",
.unmask = hpet_msi_unmask,
@@ -3650,20 +3667,36 @@ static struct irq_chip hpet_msi_type = {
.retrigger = ioapic_retrigger_irq,
};

int arch_setup_hpet_msi(unsigned int irq)
int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
{
int ret;
struct msi_msg msg;
struct irq_desc *desc = irq_to_desc(irq);

ret = msi_compose_msg(NULL, irq, &msg);
if (intr_remapping_enabled) {
struct intel_iommu *iommu = map_hpet_to_ir(id);
int index;

if (!iommu)
return -1;

index = alloc_irte(iommu, irq, 1);
if (index < 0)
return -1;
}

ret = msi_compose_msg(NULL, irq, &msg, id);
if (ret < 0)
return ret;

hpet_msi_write(irq, &msg);
desc->status |= IRQ_MOVE_PCNTXT;
set_irq_chip_and_handler_name(irq, &hpet_msi_type, handle_edge_irq,
"edge");
if (irq_remapped(irq))
set_irq_chip_and_handler_name(irq, &ir_hpet_msi_type,
handle_edge_irq, "edge");
else
set_irq_chip_and_handler_name(irq, &hpet_msi_type,
handle_edge_irq, "edge");

return 0;
}
77 changes: 49 additions & 28 deletions arch/x86/kernel/hpet.c
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@
* HPET address is set in acpi/boot.c, when an ACPI entry exists
*/
unsigned long hpet_address;
u8 hpet_blockid; /* OS timer block num */
#ifdef CONFIG_PCI_MSI
static unsigned long hpet_num_timers;
#endif
@@ -47,12 +48,12 @@ struct hpet_dev {
char name[10];
};

unsigned long hpet_readl(unsigned long a)
inline unsigned int hpet_readl(unsigned int a)
{
return readl(hpet_virt_address + a);
}

static inline void hpet_writel(unsigned long d, unsigned long a)
static inline void hpet_writel(unsigned int d, unsigned int a)
{
writel(d, hpet_virt_address + a);
}
@@ -167,7 +168,7 @@ do { \

static void hpet_reserve_msi_timers(struct hpet_data *hd);

static void hpet_reserve_platform_timers(unsigned long id)
static void hpet_reserve_platform_timers(unsigned int id)
{
struct hpet __iomem *hpet = hpet_virt_address;
struct hpet_timer __iomem *timer = &hpet->hpet_timers[2];
@@ -205,7 +206,7 @@ static void hpet_reserve_platform_timers(unsigned long id)

}
#else
static void hpet_reserve_platform_timers(unsigned long id) { }
static void hpet_reserve_platform_timers(unsigned int id) { }
#endif

/*
@@ -246,7 +247,7 @@ static void hpet_reset_counter(void)

static void hpet_start_counter(void)
{
unsigned long cfg = hpet_readl(HPET_CFG);
unsigned int cfg = hpet_readl(HPET_CFG);
cfg |= HPET_CFG_ENABLE;
hpet_writel(cfg, HPET_CFG);
}
@@ -271,7 +272,7 @@ static void hpet_resume_counter(void)

static void hpet_enable_legacy_int(void)
{
unsigned long cfg = hpet_readl(HPET_CFG);
unsigned int cfg = hpet_readl(HPET_CFG);

cfg |= HPET_CFG_LEGACY;
hpet_writel(cfg, HPET_CFG);
@@ -314,7 +315,7 @@ static int hpet_setup_msi_irq(unsigned int irq);
static void hpet_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt, int timer)
{
unsigned long cfg, cmp, now;
unsigned int cfg, cmp, now;
uint64_t delta;

switch (mode) {
@@ -323,7 +324,7 @@ static void hpet_set_mode(enum clock_event_mode mode,
delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult;
delta >>= evt->shift;
now = hpet_readl(HPET_COUNTER);
cmp = now + (unsigned long) delta;
cmp = now + (unsigned int) delta;
cfg = hpet_readl(HPET_Tn_CFG(timer));
/* Make sure we use edge triggered interrupts */
cfg &= ~HPET_TN_LEVEL;
@@ -339,7 +340,7 @@ static void hpet_set_mode(enum clock_event_mode mode,
* (See AMD-8111 HyperTransport I/O Hub Data Sheet,
* Publication # 24674)
*/
hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
hpet_writel((unsigned int) delta, HPET_Tn_CMP(timer));
hpet_start_counter();
hpet_print_config();
break;
@@ -383,13 +384,24 @@ static int hpet_next_event(unsigned long delta,
hpet_writel(cnt, HPET_Tn_CMP(timer));

/*
* We need to read back the CMP register to make sure that
* what we wrote hit the chip before we compare it to the
* counter.
* We need to read back the CMP register on certain HPET
* implementations (ATI chipsets) which seem to delay the
* transfer of the compare register into the internal compare
* logic. With small deltas this might actually be too late as
* the counter could already be higher than the compare value
* at that point and we would wait for the next hpet interrupt
* forever. We found out that reading the CMP register back
* forces the transfer so we can rely on the comparison with
* the counter register below. If the read back from the
* compare register does not match the value we programmed
* then we might have a real hardware problem. We can not do
* much about it here, but at least alert the user/admin with
* a prominent warning.
*/
WARN_ON_ONCE((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt);
WARN_ONCE(hpet_readl(HPET_Tn_CMP(timer)) != cnt,
KERN_WARNING "hpet: compare register read back failed.\n");

return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
}

static void hpet_legacy_set_mode(enum clock_event_mode mode,
@@ -415,7 +427,7 @@ static struct hpet_dev *hpet_devs;
void hpet_msi_unmask(unsigned int irq)
{
struct hpet_dev *hdev = get_irq_data(irq);
unsigned long cfg;
unsigned int cfg;

/* unmask it */
cfg = hpet_readl(HPET_Tn_CFG(hdev->num));
@@ -425,7 +437,7 @@ void hpet_msi_unmask(unsigned int irq)

void hpet_msi_mask(unsigned int irq)
{
unsigned long cfg;
unsigned int cfg;
struct hpet_dev *hdev = get_irq_data(irq);

/* mask it */
@@ -467,7 +479,7 @@ static int hpet_msi_next_event(unsigned long delta,

static int hpet_setup_msi_irq(unsigned int irq)
{
if (arch_setup_hpet_msi(irq)) {
if (arch_setup_hpet_msi(irq, hpet_blockid)) {
destroy_irq(irq);
return -EINVAL;
}
@@ -584,6 +596,8 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
unsigned int num_timers_used = 0;
int i;

if (boot_cpu_has(X86_FEATURE_ARAT))
return;
id = hpet_readl(HPET_ID);

num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT);
@@ -598,7 +612,7 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)

for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) {
struct hpet_dev *hdev = &hpet_devs[num_timers_used];
unsigned long cfg = hpet_readl(HPET_Tn_CFG(i));
unsigned int cfg = hpet_readl(HPET_Tn_CFG(i));

/* Only consider HPET timer with MSI support */
if (!(cfg & HPET_TN_FSB_CAP))
@@ -813,7 +827,7 @@ static int hpet_clocksource_register(void)
*/
int __init hpet_enable(void)
{
unsigned long id;
unsigned int id;
int i;

if (!is_hpet_capable())
@@ -872,10 +886,8 @@ int __init hpet_enable(void)

if (id & HPET_ID_LEGSUP) {
hpet_legacy_clockevent_register();
hpet_msi_capability_lookup(2);
return 1;
}
hpet_msi_capability_lookup(0);
return 0;

out_nohpet:
@@ -908,9 +920,17 @@ static __init int hpet_late_init(void)
if (!hpet_virt_address)
return -ENODEV;

if (hpet_readl(HPET_ID) & HPET_ID_LEGSUP)
hpet_msi_capability_lookup(2);
else
hpet_msi_capability_lookup(0);

hpet_reserve_platform_timers(hpet_readl(HPET_ID));
hpet_print_config();

if (boot_cpu_has(X86_FEATURE_ARAT))
return 0;

for_each_online_cpu(cpu) {
hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu);
}
@@ -925,7 +945,7 @@ fs_initcall(hpet_late_init);
void hpet_disable(void)
{
if (is_hpet_capable()) {
unsigned long cfg = hpet_readl(HPET_CFG);
unsigned int cfg = hpet_readl(HPET_CFG);

if (hpet_legacy_int_enabled) {
cfg &= ~HPET_CFG_LEGACY;
@@ -965,8 +985,8 @@ static int hpet_prev_update_sec;
static struct rtc_time hpet_alarm_time;
static unsigned long hpet_pie_count;
static u32 hpet_t1_cmp;
static unsigned long hpet_default_delta;
static unsigned long hpet_pie_delta;
static u32 hpet_default_delta;
static u32 hpet_pie_delta;
static unsigned long hpet_pie_limit;

static rtc_irq_handler irq_handler;
@@ -1017,7 +1037,8 @@ EXPORT_SYMBOL_GPL(hpet_unregister_irq_handler);
*/
int hpet_rtc_timer_init(void)
{
unsigned long cfg, cnt, delta, flags;
unsigned int cfg, cnt, delta;
unsigned long flags;

if (!is_hpet_enabled())
return 0;
@@ -1027,7 +1048,7 @@ int hpet_rtc_timer_init(void)

clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT;
hpet_default_delta = (unsigned long) clc;
hpet_default_delta = clc;
}

if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
@@ -1113,7 +1134,7 @@ int hpet_set_periodic_freq(unsigned long freq)
clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
do_div(clc, freq);
clc >>= hpet_clockevent.shift;
hpet_pie_delta = (unsigned long) clc;
hpet_pie_delta = clc;
}
return 1;
}
@@ -1127,7 +1148,7 @@ EXPORT_SYMBOL_GPL(hpet_rtc_dropped_irq);

static void hpet_rtc_timer_reinit(void)
{
unsigned long cfg, delta;
unsigned int cfg, delta;
int lost_ints = -1;

if (unlikely(!hpet_rtc_flags)) {
Loading

0 comments on commit 849e8de

Please sign in to comment.