18cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/**
28cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @file op_fixmap.c
38cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Horrible hacks for compatibility's sake.
48cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Based in part on arch/i386/kernel/mpparse.c
58cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
68cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Copyright 2002 OProfile authors
78cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Read the file COPYING
88cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
98cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author John Levon
108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author Philippe Elie
118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/mm.h>
148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/init.h>
158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/config.h>
168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/pagemap.h>
178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <asm/io.h>
188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "oprofile.h"
208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "apic_compat.h"
218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifndef cpu_has_pge
238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#if V_BEFORE(2, 4, 0)
248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#define cpu_has_pge (test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability))
258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#else
268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#define cpu_has_pge (test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability))
278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddunsigned long virt_apic_base;
318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* some static commented out to avoid warning, trying to figure out
338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * in exactly which circumstances we need this function is too prone
348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * error to be made w/o a full rebuild of supported kernel version */
358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* how about __attribute__(__unused__) then ? */
368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* FIXME is this comment right ? */
388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* We don't take care about locking mm->page_table_lock because this is
398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * only needed on SMP and on SMP we have already a sensible setup */
408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/*static*/ void set_pte_phys(ulong vaddr, ulong phys)
428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pgprot_t prot;
448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pgd_t * pgd;
458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pmd_t * pmd;
468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pte_t * pte;
478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pgd = pgd_offset_k(vaddr);
498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pmd = pmd_offset(pgd, vaddr);
508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pte = pte_offset(pmd, vaddr);
518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	prot = PAGE_KERNEL;
528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* when !CONFIG_X86_LOCAL_APIC we can't rely on no cache flag set */
538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pgprot_val(prot) |= _PAGE_PCD;
548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (cpu_has_pge)
558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		pgprot_val(prot) |= _PAGE_GLOBAL;
568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	set_pte(pte, mk_pte_phys(phys, prot));
578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	__flush_tlb_one(vaddr);
588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/*static*/ void alloc_fixmap(void)
618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* dirty hack :/ */
638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	virt_apic_base = (ulong)vmalloc(4096);
648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	set_pte_phys(virt_apic_base, APIC_DEFAULT_PHYS_BASE);
658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/*static*/ void free_fixmap(void)
688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ulong vaddr;
708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pgd_t * pgd;
718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pmd_t * pmd;
728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pte_t * pte;
738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	vaddr = virt_apic_base;
758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!vaddr)
768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return;
778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pgd = pgd_offset_k(vaddr);
798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!pgd)
808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return;
818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pmd = pmd_offset(pgd, vaddr);
838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!pmd)
848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return;
858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pte = pte_offset(pmd, vaddr);
878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!pte)
888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return;
898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* FIXME: is this the right way */
918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	pte_clear(pte);
928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	__flush_tlb_one(vaddr);
938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	vfree((void*)virt_apic_base);
958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/*
988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Make sure we can access the APIC. Some kernel versions create
998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * a meaningless zero-page mapping for the local APIC: we must
1008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * detect this case and reset it.
1018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
1028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Some kernel versions/configs won't map the APIC at all, in
1038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * which case we need to hack it ourselves.
1048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
1058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid fixmap_setup(void)
1068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#if V_BEFORE(2, 4, 10)
1088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#if defined(CONFIG_X86_LOCAL_APIC)
1098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	static int find_intel_smp(void);
1108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!find_intel_smp()) {
1128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		set_pte_phys(__fix_to_virt(FIX_APIC_BASE),
1138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			APIC_DEFAULT_PHYS_BASE);
1148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		printk(KERN_INFO "oprofile: remapping local APIC.\n");
1158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#else
1178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	alloc_fixmap();
1188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	printk(KERN_INFO "oprofile: mapping APIC.\n");
1198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif /* CONFIG_X86_LOCAL_APIC */
1208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#else
1218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#if !defined(CONFIG_X86_LOCAL_APIC)
1228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	alloc_fixmap();
1238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	printk(KERN_INFO "oprofile: mapping APIC.\n");
1248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
1258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
1268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid fixmap_restore(void)
1298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#if V_BEFORE(2, 4, 10)
1318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#if defined(CONFIG_X86_LOCAL_APIC)
1328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	/* Nothing to do */
1338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#else
1348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	free_fixmap();
1358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	printk(KERN_INFO "oprofile: freeing APIC mapping.\n");
1368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif /* CONFIG_X86_LOCAL_APIC */
1378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#else
1388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#if !defined(CONFIG_X86_LOCAL_APIC)
1398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	free_fixmap();
1408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	printk(KERN_INFO "oprofile: freeing APIC mapping.\n");
1418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
1428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif
1438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* ---------------- MP table code ------------------ */
1468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#if V_BEFORE(2, 4, 10) && defined(CONFIG_X86_LOCAL_APIC)
1488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int __init mpf_checksum(unsigned char * mp, int len)
1508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int sum = 0;
1528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	while (len--)
1548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		sum += *mp++;
1558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return sum & 0xFF;
1578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int __init mpf_table_ok(struct intel_mp_floating * mpf, unsigned long * bp)
1608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (*bp != SMP_MAGIC_IDENT)
1628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return 0;
1638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (mpf->mpf_length != 1)
1648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return 0;
1658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (mpf_checksum((unsigned char *)bp, 16))
1668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return 0;
1678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return (mpf->mpf_specification == 1 || mpf->mpf_specification == 4);
1698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int __init smp_scan_config (unsigned long base, unsigned long length)
1728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	unsigned long * bp = phys_to_virt(base);
1748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	struct intel_mp_floating * mpf;
1758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	while (length > 0) {
1778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		mpf = (struct intel_mp_floating *)bp;
1788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (mpf_table_ok(mpf, bp))
1798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			return 1;
1808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		bp += 4;
1818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		length -= 16;
1828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return 0;
1848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int __init find_intel_smp(void)
1878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	unsigned int address;
1898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (smp_scan_config(0x0, 0x400) ||
1918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		smp_scan_config(639*0x400, 0x400) ||
1928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		smp_scan_config(0xF0000, 0x10000))
1938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return 1;
1948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	address = *(unsigned short *)phys_to_virt(0x40E);
1968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	address <<= 4;
1978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return smp_scan_config(address, 0x1000);
1988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif /* V_BEFORE(2,4,10) && defined(CONFIG_X86_LOCAL_APIC) */
201