vsmp_64.c 3.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*
 * vSMPowered(tm) systems specific initialization
 * Copyright (C) 2005 ScaleMP Inc.
 *
 * Use of this code is subject to the terms and conditions of the
 * GNU general public license version 2. See "COPYING" or
 * http://www.gnu.org/licenses/gpl.html
 *
 * Ravikiran Thirumalai <kiran@scalemp.com>,
 * Shai Fultheim <shai@scalemp.com>
11 12
 * Paravirt ops integration: Glauber de Oliveira Costa <gcosta@redhat.com>,
 *			     Ravikiran Thirumalai <kiran@scalemp.com>
13 14 15 16 17
 */

#include <linux/init.h>
#include <linux/pci_ids.h>
#include <linux/pci_regs.h>
18 19

#include <asm/apic.h>
20
#include <asm/pci-direct.h>
21
#include <asm/io.h>
22
#include <asm/paravirt.h>
23
#include <asm/setup.h>
24

25
#if defined CONFIG_PCI && defined CONFIG_PARAVIRT
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
/*
 * Interrupt control on vSMPowered systems:
 * ~AC is a shadow of IF.  If IF is 'on' AC should be 'off'
 * and vice versa.
 */

static unsigned long vsmp_save_fl(void)
{
	unsigned long flags = native_save_fl();

	if (!(flags & X86_EFLAGS_IF) || (flags & X86_EFLAGS_AC))
		flags &= ~X86_EFLAGS_IF;
	return flags;
}

static void vsmp_restore_fl(unsigned long flags)
{
	if (flags & X86_EFLAGS_IF)
		flags &= ~X86_EFLAGS_AC;
	else
		flags |= X86_EFLAGS_AC;
	native_restore_fl(flags);
}

static void vsmp_irq_disable(void)
{
	unsigned long flags = native_save_fl();

	native_restore_fl((flags & ~X86_EFLAGS_IF) | X86_EFLAGS_AC);
}

static void vsmp_irq_enable(void)
{
	unsigned long flags = native_save_fl();

	native_restore_fl((flags | X86_EFLAGS_IF) & (~X86_EFLAGS_AC));
}

64
static unsigned __init_or_module vsmp_patch(u8 type, u16 clobbers, void *ibuf,
65 66 67 68 69 70 71 72 73 74 75 76 77
				  unsigned long addr, unsigned len)
{
	switch (type) {
	case PARAVIRT_PATCH(pv_irq_ops.irq_enable):
	case PARAVIRT_PATCH(pv_irq_ops.irq_disable):
	case PARAVIRT_PATCH(pv_irq_ops.save_fl):
	case PARAVIRT_PATCH(pv_irq_ops.restore_fl):
		return paravirt_patch_default(type, clobbers, ibuf, addr, len);
	default:
		return native_patch(type, clobbers, ibuf, addr, len);
	}

}
78

79
static void __init set_vsmp_pv_ops(void)
80
{
81
	void __iomem *address;
G
Glauber Costa 已提交
82
	unsigned int cap, ctl, cfg;
83 84

	/* set vSMP magic bits to indicate vSMP capable kernel */
G
Glauber Costa 已提交
85 86
	cfg = read_pci_config(0, 0x1f, 0, PCI_BASE_ADDRESS_0);
	address = early_ioremap(cfg, 8);
87 88
	cap = readl(address);
	ctl = readl(address + 4);
89 90
	printk(KERN_INFO "vSMP CTL: capabilities:0x%08x  control:0x%08x\n",
	       cap, ctl);
91
	if (cap & ctl & (1 << 4)) {
92 93 94 95 96 97 98
		/* Setup irq ops and turn on vSMP  IRQ fastpath handling */
		pv_irq_ops.irq_disable = vsmp_irq_disable;
		pv_irq_ops.irq_enable  = vsmp_irq_enable;
		pv_irq_ops.save_fl  = vsmp_save_fl;
		pv_irq_ops.restore_fl  = vsmp_restore_fl;
		pv_init_ops.patch = vsmp_patch;

99 100 101
		ctl &= ~(1 << 4);
		writel(ctl, address + 4);
		ctl = readl(address + 4);
102
		printk(KERN_INFO "vSMP CTL: control set to:0x%08x\n", ctl);
103 104
	}

G
Glauber Costa 已提交
105
	early_iounmap(address, 8);
106 107 108 109 110 111 112 113
}
#else
static void __init set_vsmp_pv_ops(void)
{
}
#endif

#ifdef CONFIG_PCI
114
static int is_vsmp = -1;
115

116
static void __init detect_vsmp_box(void)
117
{
118
	is_vsmp = 0;
119 120

	if (!early_pci_allowed())
121
		return;
122

123
	/* Check if we are running on a ScaleMP vSMPowered box */
124 125
	if (read_pci_config(0, 0x1f, 0, PCI_VENDOR_ID) ==
	     (PCI_VENDOR_ID_SCALEMP | (PCI_DEVICE_ID_SCALEMP_VSMP_CTL << 16)))
126 127
		is_vsmp = 1;
}
128

129 130 131 132 133 134 135 136
int is_vsmp_box(void)
{
	if (is_vsmp != -1)
		return is_vsmp;
	else {
		WARN_ON_ONCE(1);
		return 0;
	}
137 138
}
#else
139
static void __init detect_vsmp_box(void)
140 141
{
}
142 143 144 145 146 147 148 149
int is_vsmp_box(void)
{
	return 0;
}
#endif

void __init vsmp_init(void)
{
150
	detect_vsmp_box();
151 152 153 154
	if (!is_vsmp_box())
		return;

	set_vsmp_pv_ops();
155
	return;
156
}