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