Commit 49e9c1cc authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Linus Torvalds

[PATCH] PA-RISC updates for 2.6.6

 - Split PA7300LC from PA7100LC (Matthew Wilcox)
 - Handle 32-bit firmware and 64-bit kernel at runtime (Ryan Bradetich)
 - Fix building in a separate tree (Matthew Wilcox)
 - Update defconfigs (Randolph Chung)
 - Make WCHAN work (Randolph Chung)
 - Initial support for SMP in 2.6 (Grant Grundler)
 - Use 8-byte PTEs on 32-bit kernels (James Bottomley)
 - Implement L2/L3 hybrid page tables for 64 bit kernels (James Bottomley)
 - Support 8TB of physical and virtual address space (James Bottomley)
 - Macro'ise the tlb miss handlers (James Bottomley)
 - Check the ptrace flags correctly in the syscall return path (Randolph Chung)
 - Eliminate many magic numbers (James Bottomley)
 - Work around linker bug in vmlinux.lds.S (James Bottomley)
 - Many cache flushing fixes (James Bottomley)
 - first baby step for PA8800 support (Grant Grundler)
 - Self-aligning spinlocks (Randolph Chung)
parent 10190153
......@@ -51,25 +51,34 @@ choice
config PA7000
bool "PA7000/PA7100"
---help---
This is the processor type of your CPU. This information is used for
optimizing purposes. In order to compile a kernel that can run on
all PA CPUs (albeit not optimally fast), you can specify "PA7000"
here.
This is the processor type of your CPU. This information is
used for optimizing purposes. In order to compile a kernel
that can run on all 32-bit PA CPUs (albeit not optimally fast),
you can specify "PA7000" here.
Specifying "PA8000" here will allow you to select a 64-bit kernel
which is required on some machines.
config PA7100LC
bool "PA7100LC/PA7300LC"
bool "PA7100LC"
help
Select this option for a 7100LC or 7300LC processor, as used
in the 712, 715/Mirage, A180, B132, C160L and some other machines.
Select this option for the PCX-L processor, as used in the
712, 715/64, 715/80, 715/100, 715/100XC, 725/100, 743, 748,
D200, D210, D300, D310 and E-class
config PA7200
bool "PA7200"
help
Select this option for the PCX-T' processor, as used in C110, D100
and similar machines.
Select this option for the PCX-T' processor, as used in the
C100, C110, J100, J110, J210XC, D250, D260, D350, D360,
K100, K200, K210, K220, K400, K410 and K420
config PA7300LC
bool "PA7300LC"
help
Select this option for the PCX-L2 processor, as used in the
744, A180, B132L, B160L, B180L, C132L, C160L, C180L,
D220, D230, D320 and D330.
config PA8X00
bool "PA8000 and up"
......@@ -81,14 +90,16 @@ endchoice
# Define implied options from the CPU selection here
config PA20
bool
def_bool y
depends on PA8X00
default y
config PA11
bool
depends on PA7000 || PA7100LC || PA7200
default y
def_bool y
depends on PA7000 || PA7100LC || PA7200 || PA7300LC
config PREFETCH
def_bool y
depends on PA8X00
config PARISC64
bool "64-bit kernel"
......@@ -106,18 +117,6 @@ config PARISC64
config 64BIT
def_bool PARISC64
config PDC_NARROW
bool "32-bit firmware"
depends on PARISC64
help
This option will enable owners of C160, C180, C200, C240, C360, J280,
J282, J2240 and some D/K/R class to run a 64bit kernel with their
32bit PDC firmware.
Nobody should try this option unless they know what they are doing.
If unsure, say N.
config SMP
bool "Symmetric multi-processing support"
---help---
......
......@@ -16,7 +16,7 @@
# Modified for PA-RISC Linux by Paul Lahaie, Alex deVries,
# Mike Shaver, Helge Deller and Martin K. Petersen
#
NM = sh arch/parisc/nm
NM = sh $(srctree)/arch/parisc/nm
ifdef CONFIG_PARISC64
CROSS_COMPILE := hppa64-linux-
UTS_MACHINE := parisc64
......@@ -48,6 +48,7 @@ cflags-y += -ffunction-sections
cflags-$(CONFIG_PA7100) += -march=1.1 -mschedule=7100
cflags-$(CONFIG_PA7200) += -march=1.1 -mschedule=7200
cflags-$(CONFIG_PA7100LC) += -march=1.1 -mschedule=7100LC
cflags-$(CONFIG_PA7300LC) += -march=1.1 -mschedule=7300
cflags-$(CONFIG_PA8X00) += -march=2.0 -mschedule=8000
head-y := arch/parisc/kernel/head.o
......
......@@ -141,6 +141,12 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
#
# SCSI Transport Attributes
#
CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_FC_ATTRS=y
#
# SCSI low-level drivers
#
......@@ -179,10 +185,6 @@ CONFIG_MD_RAID5=y
# I2O device support
#
#
# Macintosh device drivers
#
#
# Networking support
#
......@@ -206,7 +208,6 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
CONFIG_INET_ECN=y
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
......@@ -290,6 +291,8 @@ CONFIG_NET_RADIO=y
# Bluetooth support
#
# CONFIG_BT is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
......@@ -335,6 +338,7 @@ CONFIG_SERIO_GSCPS2=y
CONFIG_INPUT_KEYBOARD=y
# CONFIG_KEYBOARD_ATKBD is not set
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_HIL_OLD is not set
......@@ -342,6 +346,7 @@ CONFIG_INPUT_KEYBOARD=y
CONFIG_INPUT_MOUSE=y
# CONFIG_MOUSE_PS2 is not set
# CONFIG_MOUSE_SERIAL is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_MOUSE_HIL is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
......@@ -385,11 +390,6 @@ CONFIG_PRINTER=y
# CONFIG_LP_CONSOLE is not set
# CONFIG_PPDEV is not set
# CONFIG_TIPAR is not set
#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
#
......@@ -401,7 +401,6 @@ CONFIG_PRINTER=y
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
CONFIG_GEN_RTC=y
# CONFIG_GEN_RTC_X is not set
# CONFIG_DTLK is not set
......@@ -635,6 +634,7 @@ CONFIG_CRYPTO=y
# CONFIG_CRYPTO_CAST6 is not set
# CONFIG_CRYPTO_ARC4 is not set
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_TEST is not set
#
......
......@@ -27,7 +27,7 @@ CONFIG_HOTPLUG=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
CONFIG_KALLSYMS=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_IOSCHED_NOOP=y
......@@ -78,6 +78,7 @@ CONFIG_CHASSIS_LCD_LED=y
# PCMCIA/CardBus support
#
CONFIG_PCMCIA=m
CONFIG_PCMCIA_DEBUG=y
CONFIG_YENTA=m
CONFIG_CARDBUS=y
# CONFIG_I82092 is not set
......@@ -129,6 +130,7 @@ CONFIG_BLK_DEV_UMEM=m
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_CARMEL is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=6144
CONFIG_BLK_DEV_INITRD=y
......@@ -162,6 +164,12 @@ CONFIG_SCSI_REPORT_LUNS=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
#
# SCSI Transport Attributes
#
CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_SCSI_FC_ATTRS is not set
#
# SCSI low-level drivers
#
......@@ -242,10 +250,6 @@ CONFIG_FUSION_CTL=m
# I2O device support
#
#
# Macintosh device drivers
#
#
# Networking support
#
......@@ -270,7 +274,6 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
......@@ -348,7 +351,6 @@ CONFIG_XFRM_USER=m
#
# SCTP Configuration (EXPERIMENTAL)
#
CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
# CONFIG_VLAN_8021Q is not set
......@@ -504,6 +506,11 @@ CONFIG_PCI_HERMES=m
CONFIG_PCMCIA_HERMES=m
CONFIG_AIRO_CS=m
# CONFIG_PCMCIA_WL3501 is not set
#
# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
#
# CONFIG_PRISM54 is not set
CONFIG_NET_WIRELESS=y
#
......@@ -512,6 +519,7 @@ CONFIG_NET_WIRELESS=y
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
#
# Wan interfaces
......@@ -545,6 +553,8 @@ CONFIG_PCMCIA_XIRC2PS=m
# Bluetooth support
#
# CONFIG_BT is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
......@@ -617,11 +627,6 @@ CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
#
......@@ -633,7 +638,6 @@ CONFIG_UNIX98_PTYS=y
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
CONFIG_GEN_RTC=y
CONFIG_GEN_RTC_X=y
# CONFIG_DTLK is not set
......@@ -682,7 +686,6 @@ CONFIG_MAX_RAW_DEVS=256
# Console display driver support
#
# CONFIG_MDA_CONSOLE is not set
# CONFIG_STI_CONSOLE is not set
CONFIG_DUMMY_CONSOLE_COLUMNS=160
CONFIG_DUMMY_CONSOLE_ROWS=64
CONFIG_DUMMY_CONSOLE=y
......@@ -788,7 +791,8 @@ CONFIG_LOCKD=m
CONFIG_LOCKD_V4=y
CONFIG_EXPORTFS=m
CONFIG_SUNRPC=m
# CONFIG_SUNRPC_GSS is not set
CONFIG_SUNRPC_GSS=m
CONFIG_RPCSEC_GSS_KRB5=m
CONFIG_SMB_FS=m
CONFIG_SMB_NLS_DEFAULT=y
CONFIG_SMB_NLS_REMOTE="cp437"
......@@ -887,6 +891,7 @@ CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
# CONFIG_CRYPTO_ARC4 is not set
CONFIG_CRYPTO_DEFLATE=m
# CONFIG_CRYPTO_MICHAEL_MIC is not set
CONFIG_CRYPTO_TEST=m
#
......
......@@ -121,6 +121,7 @@ CONFIG_PARPORT_GSC=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=y
# CONFIG_BLK_DEV_NBD is not set
CONFIG_BLK_DEV_CARMEL=y
# CONFIG_BLK_DEV_RAM is not set
#
......@@ -152,6 +153,12 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
#
# SCSI Transport Attributes
#
CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_SCSI_FC_ATTRS is not set
#
# SCSI low-level drivers
#
......@@ -244,10 +251,6 @@ CONFIG_MD_RAID5=y
#
# CONFIG_I2O is not set
#
# Macintosh device drivers
#
#
# Networking support
#
......@@ -271,7 +274,6 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
CONFIG_INET_ECN=y
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
......@@ -376,6 +378,10 @@ CONFIG_NET_RADIO=y
#
# CONFIG_AIRO is not set
# CONFIG_HERMES is not set
#
# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
#
CONFIG_NET_WIRELESS=y
#
......@@ -403,6 +409,8 @@ CONFIG_NET_WIRELESS=y
# Bluetooth support
#
# CONFIG_BT is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
......@@ -449,6 +457,7 @@ CONFIG_SERIO_GSCPS2=y
CONFIG_INPUT_KEYBOARD=y
# CONFIG_KEYBOARD_ATKBD is not set
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_HIL_OLD is not set
......@@ -459,6 +468,7 @@ CONFIG_INPUT_MOUSE=y
# CONFIG_MOUSE_INPORT is not set
# CONFIG_MOUSE_LOGIBM is not set
# CONFIG_MOUSE_PC110PAD is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_MOUSE_HIL is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
......@@ -502,11 +512,6 @@ CONFIG_PRINTER=y
# CONFIG_LP_CONSOLE is not set
# CONFIG_PPDEV is not set
# CONFIG_TIPAR is not set
#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
#
......@@ -518,7 +523,6 @@ CONFIG_PRINTER=y
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
CONFIG_GEN_RTC=y
# CONFIG_GEN_RTC_X is not set
# CONFIG_DTLK is not set
......@@ -768,6 +772,7 @@ CONFIG_CRYPTO=y
# CONFIG_CRYPTO_CAST6 is not set
# CONFIG_CRYPTO_ARC4 is not set
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_TEST is not set
#
......
......@@ -77,6 +77,7 @@ CONFIG_SUPERIO=y
# PCMCIA/CardBus support
#
CONFIG_PCMCIA=m
CONFIG_PCMCIA_DEBUG=y
CONFIG_YENTA=m
CONFIG_CARDBUS=y
# CONFIG_I82092 is not set
......@@ -128,6 +129,7 @@ CONFIG_BLK_DEV_UMEM=m
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_CARMEL is not set
# CONFIG_BLK_DEV_RAM is not set
#
......@@ -212,6 +214,12 @@ CONFIG_SCSI_REPORT_LUNS=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
#
# SCSI Transport Attributes
#
CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_SCSI_FC_ATTRS is not set
#
# SCSI low-level drivers
#
......@@ -230,6 +238,7 @@ CONFIG_SCSI_ATA_PIIX=m
CONFIG_SCSI_SATA_PROMISE=m
CONFIG_SCSI_SATA_SIL=m
CONFIG_SCSI_SATA_VIA=m
# CONFIG_SCSI_SATA_VITESSE is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_CPQFCTS is not set
# CONFIG_SCSI_DMX3191D is not set
......@@ -303,10 +312,6 @@ CONFIG_FUSION_CTL=m
#
# CONFIG_I2O is not set
#
# Macintosh device drivers
#
#
# Networking support
#
......@@ -331,7 +336,6 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
......@@ -409,7 +413,6 @@ CONFIG_XFRM_USER=m
#
# SCTP Configuration (EXPERIMENTAL)
#
CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
# CONFIG_VLAN_8021Q is not set
......@@ -543,6 +546,7 @@ CONFIG_PPPOE=m
# CONFIG_NET_FC is not set
# CONFIG_RCPCI is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
#
# Wan interfaces
......@@ -576,6 +580,8 @@ CONFIG_PCMCIA_AXNET=m
# Bluetooth support
#
# CONFIG_BT is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
......@@ -619,6 +625,7 @@ CONFIG_SERIO_SERPORT=m
CONFIG_INPUT_KEYBOARD=y
# CONFIG_KEYBOARD_ATKBD is not set
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_HIL_OLD is not set
......@@ -626,6 +633,7 @@ CONFIG_INPUT_KEYBOARD=y
CONFIG_INPUT_MOUSE=y
# CONFIG_MOUSE_PS2 is not set
# CONFIG_MOUSE_SERIAL is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_MOUSE_HIL is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
......@@ -663,11 +671,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
#
......@@ -679,7 +682,6 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
CONFIG_GEN_RTC=y
CONFIG_GEN_RTC_X=y
# CONFIG_DTLK is not set
......@@ -831,7 +833,9 @@ CONFIG_USB_AIPTEK=m
CONFIG_USB_WACOM=m
CONFIG_USB_KBTAB=m
# CONFIG_USB_POWERMATE is not set
# CONFIG_USB_MTOUCH is not set
# CONFIG_USB_XPAD is not set
# CONFIG_USB_ATI_REMOTE is not set
#
# USB Imaging devices
......@@ -968,7 +972,7 @@ CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_EXPORTFS=y
CONFIG_SUNRPC=y
# CONFIG_SUNRPC_GSS is not set
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
......@@ -1065,6 +1069,7 @@ CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
# CONFIG_CRYPTO_ARC4 is not set
CONFIG_CRYPTO_DEFLATE=m
# CONFIG_CRYPTO_MICHAEL_MIC is not set
CONFIG_CRYPTO_TEST=m
#
......
......@@ -14,7 +14,7 @@ obj-y := cache.o pacache.o setup.o traps.o time.o irq.o \
pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \
ptrace.o hardware.o inventory.o drivers.o semaphore.o \
signal.o hpmc.o real2.o parisc_ksyms.o unaligned.o \
process.o processor.o pdc_cons.o pdc_chassis.o
process.o processor.o pdc_cons.o pdc_chassis.o unwind.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PA11) += pci-dma.o
......
......@@ -32,6 +32,7 @@
#include <linux/thread_info.h>
#include <linux/version.h>
#include <linux/ptrace.h>
#include <asm/pgtable.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
......@@ -276,5 +277,19 @@ int main(void)
DEFINE(PA_BLOCKSTEP_BIT, 31-PT_BLOCKSTEP_BIT);
DEFINE(PA_SINGLESTEP_BIT, 31-PT_SINGLESTEP_BIT);
BLANK();
DEFINE(ASM_PMD_SHIFT, PMD_SHIFT);
DEFINE(ASM_PGDIR_SHIFT, PGDIR_SHIFT);
DEFINE(ASM_BITS_PER_PGD, BITS_PER_PGD);
DEFINE(ASM_BITS_PER_PMD, BITS_PER_PMD);
DEFINE(ASM_BITS_PER_PTE, BITS_PER_PTE);
DEFINE(ASM_PGD_PMD_OFFSET, -(PAGE_SIZE << PGD_ORDER));
DEFINE(ASM_PMD_ENTRY, ((PAGE_OFFSET & PMD_MASK) >> PMD_SHIFT));
DEFINE(ASM_PGD_ENTRY, PAGE_OFFSET >> PGDIR_SHIFT);
DEFINE(ASM_PGD_ENTRY_SIZE, PGD_ENTRY_SIZE);
DEFINE(ASM_PMD_ENTRY_SIZE, PMD_ENTRY_SIZE);
DEFINE(ASM_PTE_ENTRY_SIZE, PTE_ENTRY_SIZE);
DEFINE(ASM_PT_INITIAL, PT_INITIAL);
DEFINE(ASM_PAGE_SIZE, PAGE_SIZE);
BLANK();
return 0;
}
......@@ -230,27 +230,22 @@ void disable_sr_hashing(void)
void __flush_dcache_page(struct page *page)
{
struct address_space *mapping = page_mapping(page);
struct mm_struct *mm = current->active_mm;
struct list_head *l;
flush_kernel_dcache_page(page_address(page));
if (!mapping)
return;
/* check shared list first if it's not empty...it's usually
* the shortest */
/* We have ensured in arch_get_unmapped_area() that all shared
* mappings are mapped at equivalent addresses, so we only need
* to flush one for them all to become coherent */
list_for_each(l, &mapping->i_mmap_shared) {
struct vm_area_struct *mpnt;
unsigned long off;
unsigned long off, addr;
mpnt = list_entry(l, struct vm_area_struct, shared);
/*
* If this VMA is not in our MM, we can ignore it.
*/
if (mpnt->vm_mm != mm)
continue;
if (page->index < mpnt->vm_pgoff)
continue;
......@@ -258,26 +253,35 @@ void __flush_dcache_page(struct page *page)
if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)
continue;
flush_cache_page(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
addr = mpnt->vm_start + (off << PAGE_SHIFT);
/* All user shared mappings should be equivalently mapped,
* so once we've flushed one we should be ok
*/
/* flush instructions produce non access tlb misses.
* On PA, we nullify these instructions rather than
* taking a page fault if the pte doesn't exist, so we
* have to find a congruent address with an existing
* translation */
if (!translation_exists(mpnt, addr))
continue;
__flush_cache_page(mpnt, addr);
/* If we find an address to flush, that will also
* bring all the private mappings up to date (see
* comment below) */
return;
}
/* then check private mapping list for read only shared mappings
* which are flagged by VM_MAYSHARE */
/* we have carefully arranged in arch_get_unmapped_area() that
* *any* mappings of a file are always congruently mapped (whether
* declared as MAP_PRIVATE or MAP_SHARED), so we only need
* to flush one address here too */
list_for_each(l, &mapping->i_mmap) {
struct vm_area_struct *mpnt;
unsigned long off;
unsigned long off, addr;
mpnt = list_entry(l, struct vm_area_struct, shared);
if (mpnt->vm_mm != mm || !(mpnt->vm_flags & VM_MAYSHARE))
continue;
if (page->index < mpnt->vm_pgoff)
continue;
......@@ -285,12 +289,17 @@ void __flush_dcache_page(struct page *page)
if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)
continue;
flush_cache_page(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
addr = mpnt->vm_start + (off << PAGE_SHIFT);
/* All user shared mappings should be equivalently mapped,
* so once we've flushed one we should be ok
*/
break;
/* This is just for speed. If the page translation isn't
* there there's no point exciting the nadtlb handler into
* a nullification frenzy */
if(!translation_exists(mpnt, addr))
continue;
__flush_cache_page(mpnt, addr);
return;
}
}
EXPORT_SYMBOL(__flush_dcache_page);
......
......@@ -40,11 +40,13 @@
#ifdef __LP64__
#define CMPIB cmpib,*
#define CMPB cmpb,*
#define COND(x) *x
.level 2.0w
#else
#define CMPIB cmpib,
#define CMPB cmpb,
#define COND(x) x
.level 2.0
#endif
......@@ -389,6 +391,228 @@
.align 32
.endm
/* The following are simple 32 vs 64 bit instruction
* abstractions for the macros */
.macro EXTR reg1,start,length,reg2
#ifdef __LP64__
extrd,u \reg1,32+\start,\length,\reg2
#else
extrw,u \reg1,\start,\length,\reg2
#endif
.endm
.macro DEP reg1,start,length,reg2
#ifdef __LP64__
depd \reg1,32+\start,\length,\reg2
#else
depw \reg1,\start,\length,\reg2
#endif
.endm
.macro DEPI val,start,length,reg
#ifdef __LP64__
depdi \val,32+\start,\length,\reg
#else
depwi \val,\start,\length,\reg
#endif
.endm
/* In LP64, the space contains part of the upper 32 bits of the
* fault. We have to extract this and place it in the va,
* zeroing the corresponding bits in the space register */
.macro space_adjust spc,va,tmp
#ifdef __LP64__
extrd,u \spc,63,SPACEID_SHIFT,\tmp
depd %r0,63,SPACEID_SHIFT,\spc
depd \tmp,31,SPACEID_SHIFT,\va
#endif
.endm
.import swapper_pg_dir,code
/* Get the pgd. For faults on space zero (kernel space), this
* is simply swapper_pg_dir. For user space faults, the
* pgd is stored in %cr25 */
.macro get_pgd spc,reg
ldil L%PA(swapper_pg_dir),\reg
ldo R%PA(swapper_pg_dir)(\reg),\reg
or,COND(=) %r0,\spc,%r0
mfctl %cr25,\reg
.endm
/* Only allow faults on different spaces from the
* currently active one if we're the kernel */
.macro space_check spc,tmp,fault
mfsp %sr7,\tmp
or,COND(<>) %r0,\spc,%r0 /* user may execute gateway page
* as kernel, so defeat the space
* check if it is */
copy \spc,\tmp
or,COND(=) %r0,\tmp,%r0 /* nullify if executing as kernel */
cmpb,COND(<>),n \tmp,\spc,\fault
.endm
/* Look up a PTE in a 2-Level scheme (faulting at each
* level if the entry isn't present
*
* NOTE: we use ldw even for LP64 because our pte
* and pmd are allocated <4GB */
.macro L2_ptep pmd,pte,index,va,fault
#if PT_NLEVELS == 3
EXTR \va,31-ASM_PMD_SHIFT,ASM_BITS_PER_PMD,\index
#else
EXTR \va,31-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
#endif
DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */
copy %r0,\pte
ldw,s \index(\pmd),\pmd
EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
bb,>=,n \pmd,_PAGE_PRESENT_BIT,\fault
DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */
shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd
LDREG %r0(\pmd),\pte /* pmd is now pte */
bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault
.endm
/* Look up PTE in a 3-Level scheme.
*
* Here we implement a Hybrid L2/L3 scheme: we allocate the
* first pmd adjacent to the pgd. This means that we can
* subtract a constant offset to get to it. The pmd and pgd
* sizes are arranged so that a single pmd covers 4GB (giving
* a full LP64 process access to 8TB) so our lookups are
* effectively L2 for the first 4GB of the kernel (i.e. for
* all ILP32 processes and all the kernel for machines with
* under 4GB of memory) */
.macro L3_ptep pgd,pte,index,va,fault
extrd,u \va,63-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
copy %r0,\pte
extrd,u,*= \va,31,32,%r0
ldw,s \index(\pgd),\pgd
extrd,u,*<> \va,31,32,%r0
ldo ASM_PGD_PMD_OFFSET(\pgd),\pgd
extrd,u,*= \va,31,32,%r0
bb,>=,n \pgd,_PAGE_PRESENT_BIT,\fault
L2_ptep \pgd,\pte,\index,\va,\fault
.endm
/* Set the _PAGE_ACCESSED bit of the PTE. Be clever and
* don't needlessly dirty the cache line if it was already set */
.macro update_ptep ptep,pte,tmp,tmp1
ldi _PAGE_ACCESSED,\tmp1
or \tmp1,\pte,\tmp
and,COND(<>) \tmp1,\pte,%r0
STREG \tmp,0(\ptep)
.endm
/* Set the dirty bit (and accessed bit). No need to be
* clever, this is only used from the dirty fault */
.macro update_dirty ptep,pte,tmp,tmp1
ldi _PAGE_ACCESSED|_PAGE_DIRTY,\tmp
or \tmp,\pte,\pte
STREG \pte,0(\ptep)
.endm
/* Convert the pte and prot to tlb insertion values. How
* this happens is quite subtle, read below */
.macro make_insert_tlb spc,pte,prot
space_to_prot \spc \prot /* create prot id from space */
/* The following is the real subtlety. This is depositing
* T <-> _PAGE_REFTRAP
* D <-> _PAGE_DIRTY
* B <-> _PAGE_DMB (memory break)
*
* Then incredible subtlety: The access rights are
* _PAGE_GATEWAY _PAGE_EXEC _PAGE_READ
* See 3-14 of the parisc 2.0 manual
*
* Finally, _PAGE_READ goes in the top bit of PL1 (so we
* trigger an access rights trap in user space if the user
* tries to read an unreadable page */
depd \pte,8,7,\prot
/* PAGE_USER indicates the page can be read with user privileges,
* so deposit X1|11 to PL1|PL2 (remember the upper bit of PL1
* contains _PAGE_READ */
extrd,u,*= \pte,_PAGE_USER_BIT+32,1,%r0
depdi 7,11,3,\prot
/* If we're a gateway page, drop PL2 back to zero for promotion
* to kernel privilege (so we can execute the page as kernel).
* Any privilege promotion page always denys read and write */
extrd,u,*= \pte,_PAGE_GATEWAY_BIT+32,1,%r0
depd %r0,11,2,\prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for iitlbt */
depd %r0,63,PAGE_SHIFT,\pte
extrd,u \pte,56,32,\pte
.endm
/* Identical macro to make_insert_tlb above, except it
* makes the tlb entry for the differently formatted pa11
* insertion instructions */
.macro make_insert_tlb_11 spc,pte,prot
zdep \spc,30,15,\prot
dep \pte,8,7,\prot
extru,= \pte,_PAGE_NO_CACHE_BIT,1,%r0
depi 1,12,1,\prot
extru,= \pte,_PAGE_USER_BIT,1,%r0
depi 7,11,3,\prot /* Set for user space (1 rsvd for read) */
extru,= \pte,_PAGE_GATEWAY_BIT,1,%r0
depi 0,11,2,\prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for iitlba */
depi 0,31,12,\pte
extru \pte,24,25,\pte
.endm
/* This is for ILP32 PA2.0 only. The TLB insertion needs
* to extend into I/O space if the address is 0xfXXXXXXX
* so we extend the f's into the top word of the pte in
* this case */
.macro f_extend pte,tmp
extrd,s \pte,42,4,\tmp
addi,<> 1,\tmp,%r0
extrd,s \pte,63,25,\pte
.endm
/* The alias region is an 8MB aligned 16MB to do clear and
* copy user pages at addresses congruent with the user
* virtual address.
*
* To use the alias page, you set %r26 up with the to TLB
* entry (identifying the physical page) and %r23 up with
* the from tlb entry (or nothing if only a to entry---for
* clear_user_page_asm) */
.macro do_alias spc,tmp,tmp1,va,pte,prot,fault
cmpib,COND(<>),n 0,\spc,\fault
ldil L%(TMPALIAS_MAP_START),\tmp
#if defined(__LP64__) && (TMPALIAS_MAP_START >= 0x80000000)
/* on LP64, ldi will sign extend into the upper 32 bits,
* which is behaviour we don't want */
depdi 0,31,32,\tmp
#endif
copy \va,\tmp1
DEPI 0,31,23,\tmp1
cmpb,COND(<>),n \tmp,\tmp1,\fault
ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),\prot
depd,z \prot,8,7,\prot
/*
* OK, it is in the temp alias region, check whether "from" or "to".
* Check "subtle" note in pacache.S re: r23/r26.
*/
#ifdef __LP64__
extrd,u,*= \va,41,1,%r0
#else
extrw,u,= \va,9,1,%r0
#endif
or,COND(tr) %r23,%r0,\pte
or %r26,%r0,\pte
.endm
/*
* Align fault_vector_20 on 4K boundary so that both
* fault_vector_11 and fault_vector_20 are on the
......@@ -979,82 +1203,23 @@ skip_save_ior:
#ifdef __LP64__
dtlb_miss_20w:
extrd,u spc,63,7,t1 /* adjust va */
depd t1,31,7,va /* adjust va */
depdi 0,63,7,spc /* adjust space */
mfctl %cr25,ptp /* Assume user space miss */
or,*<> %r0,spc,%r0 /* If it is user space, nullify */
mfctl %cr24,ptp /* Load kernel pgd instead */
extrd,u va,33,9,t1 /* Get pgd index */
mfsp %sr7,t0 /* Get current space */
or,*= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,*<>,n t0,spc,dtlb_fault /* forward */
/* First level page table lookup */
ldd,s t1(ptp),ptp
extrd,u va,42,9,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
depdi 0,63,12,ptp /* clear prot bits */
/* Second level page table lookup */
ldd,s t0(ptp),ptp
extrd,u va,51,9,t0 /* get third-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
depdi 0,63,12,ptp /* clear prot bits */
/* Third level page table lookup */
space_adjust spc,va,t0
get_pgd spc,ptp
space_check spc,t0,dtlb_fault
shladd t0,3,ptp,ptp
ldi _PAGE_ACCESSED,t1
ldd 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
L3_ptep ptp,pte,t0,va,dtlb_check_alias_20w
/* Check whether the "accessed" bit was set, otherwise do so */
update_ptep ptp,pte,t0,t1
or t1,pte,t0 /* t0 has R bit set */
and,*<> t1,pte,%r0 /* test and nullify if already set */
std t0,0(ptp) /* write back pte */
make_insert_tlb spc,pte,prot
space_to_prot spc prot /* create prot id from space */
depd pte,8,7,prot /* add in prot bits from pte */
extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for idtlbt */
depdi 0,63,12,pte
extrd,u pte,56,52,pte
idtlbt pte,prot
rfir
nop
dtlb_check_alias_20w:
/* Check to see if fault is in the temporary alias region */
cmpib,*<>,n 0,spc,dtlb_fault /* forward */
ldil L%(TMPALIAS_MAP_START),t0
copy va,t1
depdi 0,63,23,t1
cmpb,*<>,n t0,t1,dtlb_fault /* forward */
ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
depd,z prot,8,7,prot
/*
* OK, it is in the temp alias region, check whether "from" or "to".
* Check "subtle" note in pacache.S re: r23/r26.
*/
extrd,u,*= va,41,1,r0
or,*tr %r23,%r0,pte /* If "from" use "from" page */
or,* %r26,%r0,pte /* else "to", use "to" page */
do_alias spc,t0,t1,va,pte,prot,dtlb_fault
idtlbt pte,prot
......@@ -1062,51 +1227,16 @@ dtlb_check_alias_20w:
nop
nadtlb_miss_20w:
extrd,u spc,63,7,t1 /* adjust va */
depd t1,31,7,va /* adjust va */
depdi 0,63,7,spc /* adjust space */
mfctl %cr25,ptp /* Assume user space miss */
or,*<> %r0,spc,%r0 /* If it is user space, nullify */
mfctl %cr24,ptp /* Load kernel pgd instead */
extrd,u va,33,9,t1 /* Get pgd index */
mfsp %sr7,t0 /* Get current space */
or,*= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,*<>,n t0,spc,nadtlb_fault /* forward */
/* First level page table lookup */
ldd,s t1(ptp),ptp
extrd,u va,42,9,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
depdi 0,63,12,ptp /* clear prot bits */
space_adjust spc,va,t0
get_pgd spc,ptp
space_check spc,t0,nadtlb_fault
/* Second level page table lookup */
L3_ptep ptp,pte,t0,va,nadtlb_check_flush_20w
ldd,s t0(ptp),ptp
extrd,u va,51,9,t0 /* get third-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
depdi 0,63,12,ptp /* clear prot bits */
update_ptep ptp,pte,t0,t1
/* Third level page table lookup */
make_insert_tlb spc,pte,prot
shladd t0,3,ptp,ptp
ldi _PAGE_ACCESSED,t1
ldd 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20w
space_to_prot spc prot /* create prot id from space */
depd pte,8,7,prot /* add in prot bits from pte */
extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for idtlbt */
depdi 0,63,12,pte
extrd,u pte,56,52,pte
idtlbt pte,prot
rfir
......@@ -1132,49 +1262,15 @@ nadtlb_check_flush_20w:
#else
dtlb_miss_11:
mfctl %cr25,ptp /* Assume user space miss */
or,<> %r0,spc,%r0 /* If it is user space, nullify */
mfctl %cr24,ptp /* Load kernel pgd instead */
extru va,9,10,t1 /* Get pgd index */
get_pgd spc,ptp
mfsp %sr7,t0 /* Get current space */
or,= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,<>,n t0,spc,dtlb_fault /* forward */
space_check spc,t0,dtlb_fault
/* First level page table lookup */
L2_ptep ptp,pte,t0,va,dtlb_check_alias_11
ldwx,s t1(ptp),ptp
extru va,19,10,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_11
depi 0,31,12,ptp /* clear prot bits */
update_ptep ptp,pte,t0,t1
/* Second level page table lookup */
sh2addl t0,ptp,ptp
ldi _PAGE_ACCESSED,t1
ldw 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_11
/* Check whether the "accessed" bit was set, otherwise do so */
or t1,pte,t0 /* t0 has R bit set */
and,<> t1,pte,%r0 /* test and nullify if already set */
stw t0,0(ptp) /* write back pte */
zdep spc,30,15,prot /* create prot id from space */
dep pte,8,7,prot /* add in prot bits from pte */
extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
depi 1,12,1,prot
extru,= pte,_PAGE_USER_BIT,1,r0
depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extru,= pte,_PAGE_GATEWAY_BIT,1,r0
depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for idtlba */
depi 0,31,12,pte
extru pte,24,25,pte
make_insert_tlb_11 spc,pte,prot
mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
mtsp spc,%sr1
......@@ -1215,43 +1311,16 @@ dtlb_check_alias_11:
nop
nadtlb_miss_11:
mfctl %cr25,ptp /* Assume user space miss */
or,<> %r0,spc,%r0 /* If it is user space, nullify */
mfctl %cr24,ptp /* Load kernel pgd instead */
extru va,9,10,t1 /* Get pgd index */
mfsp %sr7,t0 /* Get current space */
or,= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,<>,n t0,spc,nadtlb_fault /* forward */
/* First level page table lookup */
ldwx,s t1(ptp),ptp
extru va,19,10,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
depi 0,31,12,ptp /* clear prot bits */
get_pgd spc,ptp
/* Second level page table lookup */
space_check spc,t0,nadtlb_fault
sh2addl t0,ptp,ptp
ldi _PAGE_ACCESSED,t1
ldw 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_11
L2_ptep ptp,pte,t0,va,nadtlb_check_flush_11
zdep spc,30,15,prot /* create prot id from space */
dep pte,8,7,prot /* add in prot bits from pte */
update_ptep ptp,pte,t0,t1
extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
depi 1,12,1,prot
extru,= pte,_PAGE_USER_BIT,1,r0
depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extru,= pte,_PAGE_GATEWAY_BIT,1,r0
depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
make_insert_tlb_11 spc,pte,prot
/* Get rid of prot bits and convert to page addr for idtlba */
depi 0,31,12,pte
extru pte,24,25,pte
mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
mtsp spc,%sr1
......@@ -1289,75 +1358,25 @@ nadtlb_check_flush_11:
nop
dtlb_miss_20:
mfctl %cr25,ptp /* Assume user space miss */
or,<> %r0,spc,%r0 /* If it is user space, nullify */
mfctl %cr24,ptp /* Load kernel pgd instead */
extru va,9,10,t1 /* Get pgd index */
mfsp %sr7,t0 /* Get current space */
or,= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,<>,n t0,spc,dtlb_fault /* forward */
/* First level page table lookup */
ldwx,s t1(ptp),ptp
extru va,19,10,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20
depi 0,31,12,ptp /* clear prot bits */
space_adjust spc,va,t0
get_pgd spc,ptp
space_check spc,t0,dtlb_fault
/* Second level page table lookup */
L2_ptep ptp,pte,t0,va,dtlb_check_alias_20
sh2addl t0,ptp,ptp
ldi _PAGE_ACCESSED,t1
ldw 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20
update_ptep ptp,pte,t0,t1
/* Check whether the "accessed" bit was set, otherwise do so */
make_insert_tlb spc,pte,prot
or t1,pte,t0 /* t0 has R bit set */
and,<> t1,pte,%r0 /* test and nullify if already set */
stw t0,0(ptp) /* write back pte */
f_extend pte,t0
space_to_prot spc prot /* create prot id from space */
depd pte,8,7,prot /* add in prot bits from pte */
extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for idtlbt */
extrd,s pte,35,4,t0
depdi 0,63,12,pte /* clear lower 12 bits */
addi,= 1,t0,0
extrd,u,*tr pte,56,25,pte
extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
idtlbt pte,prot
rfir
nop
dtlb_check_alias_20:
/* Check to see if fault is in the temporary alias region */
cmpib,<>,n 0,spc,dtlb_fault /* forward */
ldil L%(TMPALIAS_MAP_START),t0
copy va,t1
depwi 0,31,23,t1
cmpb,<>,n t0,t1,dtlb_fault /* forward */
ldi (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
depd,z prot,8,7,prot
/*
* OK, it is in the temp alias region, check whether "from" or "to".
* Check "subtle" note in pacache.S re: r23/r26.
*/
extrw,u,= va,9,1,r0
or,tr %r23,%r0,pte /* If "from" use "from" page */
or %r26,%r0,pte /* else "to", use "to" page */
do_alias spc,t0,t1,va,pte,prot,dtlb_fault
idtlbt pte,prot
......@@ -1365,44 +1384,18 @@ dtlb_check_alias_20:
nop
nadtlb_miss_20:
mfctl %cr25,ptp /* Assume user space miss */
or,<> %r0,spc,%r0 /* If it is user space, nullify */
mfctl %cr24,ptp /* Load kernel pgd instead */
extru va,9,10,t1 /* Get pgd index */
mfsp %sr7,t0 /* Get current space */
or,= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,<>,n t0,spc,nadtlb_fault /* forward */
get_pgd spc,ptp
/* First level page table lookup */
space_check spc,t0,nadtlb_fault
ldwx,s t1(ptp),ptp
extru va,19,10,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
depi 0,31,12,ptp /* clear prot bits */
L2_ptep ptp,pte,t0,va,nadtlb_check_flush_20
/* Second level page table lookup */
update_ptep ptp,pte,t0,t1
sh2addl t0,ptp,ptp
ldi _PAGE_ACCESSED,t1
ldw 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20
make_insert_tlb spc,pte,prot
space_to_prot spc prot /* create prot id from space */
depd pte,8,7,prot /* add in prot bits from pte */
f_extend pte,t0
extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for idtlbt */
extrd,s pte,35,4,t0
depdi 0,63,12,pte /* clear lower 12 bits */
addi,= 1,t0,0
extrd,u,*tr pte,56,25,pte
extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
idtlbt pte,prot
rfir
......@@ -1475,119 +1468,33 @@ itlb_miss_20w:
* on the gateway page which is in the kernel address space.
*/
extrd,u spc,63,7,t1 /* adjust va */
depd t1,31,7,va /* adjust va */
depdi 0,63,7,spc /* adjust space */
cmpib,*= 0,spc,itlb_miss_kernel_20w
extrd,u va,33,9,t1 /* Get pgd index */
mfctl %cr25,ptp /* load user pgd */
mfsp %sr7,t0 /* Get current space */
or,*= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,*<>,n t0,spc,itlb_fault /* forward */
/* First level page table lookup */
itlb_miss_common_20w:
ldd,s t1(ptp),ptp
extrd,u va,42,9,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
depdi 0,63,12,ptp /* clear prot bits */
/* Second level page table lookup */
ldd,s t0(ptp),ptp
extrd,u va,51,9,t0 /* get third-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
depdi 0,63,12,ptp /* clear prot bits */
/* Third level page table lookup */
shladd t0,3,ptp,ptp
ldi _PAGE_ACCESSED,t1
ldd 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
/* Check whether the "accessed" bit was set, otherwise do so */
space_adjust spc,va,t0
get_pgd spc,ptp
space_check spc,t0,itlb_fault
or t1,pte,t0 /* t0 has R bit set */
and,*<> t1,pte,%r0 /* test and nullify if already set */
std t0,0(ptp) /* write back pte */
L3_ptep ptp,pte,t0,va,itlb_fault
space_to_prot spc prot /* create prot id from space */
depd pte,8,7,prot /* add in prot bits from pte */
update_ptep ptp,pte,t0,t1
extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
make_insert_tlb spc,pte,prot
/* Get rid of prot bits and convert to page addr for iitlbt */
depdi 0,63,12,pte
extrd,u pte,56,32,pte
iitlbt pte,prot
rfir
nop
itlb_miss_kernel_20w:
b itlb_miss_common_20w
mfctl %cr24,ptp /* Load kernel pgd */
#else
itlb_miss_11:
get_pgd spc,ptp
/*
* I miss is a little different, since we allow users to fault
* on the gateway page which is in the kernel address space.
*/
cmpib,= 0,spc,itlb_miss_kernel_11
extru va,9,10,t1 /* Get pgd index */
mfctl %cr25,ptp /* load user pgd */
mfsp %sr7,t0 /* Get current space */
or,= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,<>,n t0,spc,itlb_fault /* forward */
/* First level page table lookup */
itlb_miss_common_11:
ldwx,s t1(ptp),ptp
extru va,19,10,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
depi 0,31,12,ptp /* clear prot bits */
space_check spc,t0,itlb_fault
/* Second level page table lookup */
L2_ptep ptp,pte,t0,va,itlb_fault
sh2addl t0,ptp,ptp
ldi _PAGE_ACCESSED,t1
ldw 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
update_ptep ptp,pte,t0,t1
/* Check whether the "accessed" bit was set, otherwise do so */
or t1,pte,t0 /* t0 has R bit set */
and,<> t1,pte,%r0 /* test and nullify if already set */
stw t0,0(ptp) /* write back pte */
zdep spc,30,15,prot /* create prot id from space */
dep pte,8,7,prot /* add in prot bits from pte */
extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
depi 1,12,1,prot
extru,= pte,_PAGE_USER_BIT,1,r0
depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extru,= pte,_PAGE_GATEWAY_BIT,1,r0
depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for iitlba */
depi 0,31,12,pte
extru pte,24,25,pte
make_insert_tlb_11 spc,pte,prot
mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
mtsp spc,%sr1
......@@ -1600,106 +1507,35 @@ itlb_miss_common_11:
rfir
nop
itlb_miss_kernel_11:
b itlb_miss_common_11
mfctl %cr24,ptp /* Load kernel pgd */
itlb_miss_20:
get_pgd spc,ptp
/*
* I miss is a little different, since we allow users to fault
* on the gateway page which is in the kernel address space.
*/
cmpib,= 0,spc,itlb_miss_kernel_20
extru va,9,10,t1 /* Get pgd index */
space_check spc,t0,itlb_fault
mfctl %cr25,ptp /* load user pgd */
L2_ptep ptp,pte,t0,va,itlb_fault
mfsp %sr7,t0 /* Get current space */
or,= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,<>,n t0,spc,itlb_fault /* forward */
update_ptep ptp,pte,t0,t1
/* First level page table lookup */
make_insert_tlb spc,pte,prot
itlb_miss_common_20:
ldwx,s t1(ptp),ptp
extru va,19,10,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,itlb_fault
depi 0,31,12,ptp /* clear prot bits */
f_extend pte,t0
/* Second level page table lookup */
sh2addl t0,ptp,ptp
ldi _PAGE_ACCESSED,t1
ldw 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,itlb_fault
/* Check whether the "accessed" bit was set, otherwise do so */
or t1,pte,t0 /* t0 has R bit set */
and,<> t1,pte,%r0 /* test and nullify if already set */
stw t0,0(ptp) /* write back pte */
space_to_prot spc prot /* create prot id from space */
depd pte,8,7,prot /* add in prot bits from pte */
extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for iitlbt */
extrd,s pte,35,4,t0
depdi 0,63,12,pte /* clear lower 12 bits */
addi,= 1,t0,0
extrd,u,*tr pte,56,25,pte
extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
iitlbt pte,prot
rfir
nop
itlb_miss_kernel_20:
b itlb_miss_common_20
mfctl %cr24,ptp /* Load kernel pgd */
#endif
#ifdef __LP64__
dbit_trap_20w:
extrd,u spc,63,7,t1 /* adjust va */
depd t1,31,7,va /* adjust va */
depdi 0,1,2,va /* adjust va */
depdi 0,63,7,spc /* adjust space */
mfctl %cr25,ptp /* Assume user space miss */
or,*<> %r0,spc,%r0 /* If it is user space, nullify */
mfctl %cr24,ptp /* Load kernel pgd instead */
extrd,u va,33,9,t1 /* Get pgd index */
mfsp %sr7,t0 /* Get current space */
or,*= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,*<>,n t0,spc,dbit_fault /* forward */
/* First level page table lookup */
ldd,s t1(ptp),ptp
extrd,u va,42,9,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
depdi 0,63,12,ptp /* clear prot bits */
/* Second level page table lookup */
ldd,s t0(ptp),ptp
extrd,u va,51,9,t0 /* get third-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
depdi 0,63,12,ptp /* clear prot bits */
space_adjust spc,va,t0
get_pgd spc,ptp
space_check spc,t0,dbit_fault
/* Third level page table lookup */
L3_ptep ptp,pte,t0,va,dbit_fault
shladd t0,3,ptp,ptp
#ifdef CONFIG_SMP
CMPIB=,n 0,spc,dbit_nolock_20w
ldil L%PA(pa_dbit_lock),t0
......@@ -1712,27 +1548,10 @@ dbit_spin_20w:
dbit_nolock_20w:
#endif
ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
ldd 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
update_dirty ptp,pte,t0,t1
/* Set Accessed and Dirty bits in the pte */
make_insert_tlb spc,pte,prot
or t1,pte,pte
std pte,0(ptp) /* write back pte */
space_to_prot spc prot /* create prot id from space */
depd pte,8,7,prot /* add in prot bits from pte */
extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for idtlbt */
depdi 0,63,12,pte
extrd,u pte,56,52,pte
idtlbt pte,prot
#ifdef CONFIG_SMP
CMPIB=,n 0,spc,dbit_nounlock_20w
......@@ -1747,25 +1566,13 @@ dbit_nounlock_20w:
#else
dbit_trap_11:
mfctl %cr25,ptp /* Assume user space trap */
or,<> %r0,spc,%r0 /* If it is user space, nullify */
mfctl %cr24,ptp /* Load kernel pgd instead */
extru va,9,10,t1 /* Get pgd index */
mfsp %sr7,t0 /* Get current space */
or,= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,<>,n t0,spc,dbit_fault /* forward */
get_pgd spc,ptp
/* First level page table lookup */
space_check spc,t0,dbit_fault
ldwx,s t1(ptp),ptp
extru va,19,10,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
depi 0,31,12,ptp /* clear prot bits */
L2_ptep ptp,pte,t0,va,dbit_fault
/* Second level page table lookup */
sh2addl t0,ptp,ptp
#ifdef CONFIG_SMP
CMPIB=,n 0,spc,dbit_nolock_11
ldil L%PA(pa_dbit_lock),t0
......@@ -1778,29 +1585,9 @@ dbit_spin_11:
dbit_nolock_11:
#endif
ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
ldw 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
/* Set Accessed and Dirty bits in the pte */
or t1,pte,pte
stw pte,0(ptp) /* write back pte */
zdep spc,30,15,prot /* create prot id from space */
dep pte,8,7,prot /* add in prot bits from pte */
update_dirty ptp,pte,t0,t1
extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
depi 1,12,1,prot
extru,= pte,_PAGE_USER_BIT,1,r0
depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extru,= pte,_PAGE_GATEWAY_BIT,1,r0
depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for idtlba */
depi 0,31,12,pte
extru pte,24,25,pte
make_insert_tlb_11 spc,pte,prot
mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
mtsp spc,%sr1
......@@ -1821,25 +1608,12 @@ dbit_nounlock_11:
nop
dbit_trap_20:
mfctl %cr25,ptp /* Assume user space trap */
or,<> %r0,spc,%r0 /* If it is user space, nullify */
mfctl %cr24,ptp /* Load kernel pgd instead */
extru va,9,10,t1 /* Get pgd index */
mfsp %sr7,t0 /* Get current space */
or,= %r0,t0,%r0 /* If kernel, nullify following test */
cmpb,<>,n t0,spc,dbit_fault /* forward */
/* First level page table lookup */
get_pgd spc,ptp
ldwx,s t1(ptp),ptp
extru va,19,10,t0 /* get second-level index */
bb,>=,n ptp,_PAGE_PRESENT_BIT,dbit_fault
depi 0,31,12,ptp /* clear prot bits */
space_check spc,t0,dbit_fault
/* Second level page table lookup */
L2_ptep ptp,pte,t0,va,dbit_fault
sh2addl t0,ptp,ptp
#ifdef CONFIG_SMP
CMPIB=,n 0,spc,dbit_nolock_20
ldil L%PA(pa_dbit_lock),t0
......@@ -1852,28 +1626,12 @@ dbit_spin_20:
dbit_nolock_20:
#endif
ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
ldw 0(ptp),pte
bb,>=,n pte,_PAGE_PRESENT_BIT,dbit_fault
update_dirty ptp,pte,t0,t1
/* Set Accessed and Dirty bits in the pte */
make_insert_tlb spc,pte,prot
or t1,pte,pte
stw pte,0(ptp) /* write back pte */
f_extend pte,t0
space_to_prot spc prot /* create prot id from space */
depd pte,8,7,prot /* add in prot bits from pte */
extrd,u,*= pte,_PAGE_USER_BIT+32,1,r0
depdi 7,11,3,prot /* Set for user space (1 rsvd for read) */
extrd,u,*= pte,_PAGE_GATEWAY_BIT+32,1,r0
depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
extrd,s pte,35,4,t0
depdi 0,63,12,pte /* clear lower 12 bits */
addi,= 1,t0,0
extrd,u,*tr pte,56,25,pte
extrd,s pte,56,25,pte /* bit 31:8 >> 8 */
idtlbt pte,prot
#ifdef CONFIG_SMP
......@@ -2285,9 +2043,13 @@ syscall_check_sig:
bb,<,n %r19, 31-TIF_SIGPENDING, syscall_do_signal /* forward */
syscall_restore:
LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* get ti flags */
bb,< %r19, 31-TIF_SYSCALL_TRACE,syscall_restore_rfi
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* delay slot! */
/* Are we being ptraced? */
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
LDREG TASK_PTRACE(%r1), %r19
bb,< %r19,31,syscall_restore_rfi
nop
ldo TASK_PT_FR31(%r1),%r19 /* reload fpregs */
rest_fp %r19
......@@ -2337,7 +2099,6 @@ syscall_restore:
* the most efficient way of doing things, but it works.
*/
syscall_restore_rfi:
LDREG TASK_PTRACE(%r1), %r19
ldo -1(%r0),%r2 /* Set recovery cntr to -1 */
mtctl %r2,%cr0 /* for immediate trap */
LDREG TASK_PT_PSW(%r1),%r2 /* Get old PSW */
......
......@@ -10,6 +10,7 @@
* Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org)
* Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
* Copyright 2003 Grant Grundler <grundler parisc-linux org>
* Copyright 2003,2004 Ryan Bradetich <rbrad@parisc-linux.org>
*
* 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
......@@ -71,6 +72,15 @@ static spinlock_t pdc_lock = SPIN_LOCK_UNLOCKED;
static unsigned long pdc_result[32] __attribute__ ((aligned (8)));
static unsigned long pdc_result2[32] __attribute__ ((aligned (8)));
#ifdef __LP64__
#define WIDE_FIRMWARE 0x1
#define NARROW_FIRMWARE 0x2
/* Firmware needs to be initially set to narrow to determine the
* actual firmware width. */
int parisc_narrow_firmware = 1;
#endif
/* on all currently-supported platforms, IODC I/O calls are always
* 32-bit calls, and MEM_PDC calls are always the same width as the OS.
* This means Cxxx boxes can't run wide kernels right now. -PB
......@@ -87,11 +97,11 @@ long real64_call(unsigned long function, ...);
#endif
long real32_call(unsigned long function, ...);
#if defined(__LP64__) && ! defined(CONFIG_PDC_NARROW)
#define MEM_PDC (unsigned long)(PAGE0->mem_pdc_hi) << 32 | PAGE0->mem_pdc
# define mem_pdc_call(args...) real64_call(MEM_PDC, args)
#ifdef __LP64__
# define MEM_PDC (unsigned long)(PAGE0->mem_pdc_hi) << 32 | PAGE0->mem_pdc
# define mem_pdc_call(args...) unlikely(parisc_narrow_firmware) ? real32_call(MEM_PDC, args) : real64_call(MEM_PDC, args)
#else
#define MEM_PDC (unsigned long)PAGE0->mem_pdc
# define MEM_PDC (unsigned long)PAGE0->mem_pdc
# define mem_pdc_call(args...) real32_call(MEM_PDC, args)
#endif
......@@ -105,12 +115,14 @@ long real32_call(unsigned long function, ...);
*/
static unsigned long f_extend(unsigned long address)
{
#ifdef CONFIG_PDC_NARROW
#ifdef __LP64__
if(unlikely(parisc_narrow_firmware)) {
if((address & 0xff000000) == 0xf0000000)
return 0xf0f0f0f000000000 | (u32)address;
if((address & 0xf0000000) == 0xf0000000)
return 0xffffffff00000000 | (u32)address;
}
#endif
return address;
}
......@@ -125,11 +137,34 @@ static unsigned long f_extend(unsigned long address)
*/
static void convert_to_wide(unsigned long *addr)
{
#ifdef CONFIG_PDC_NARROW
#ifdef __LP64__
int i;
unsigned *p = (unsigned int *)addr;
unsigned int *p = (unsigned int *)addr;
if(unlikely(parisc_narrow_firmware)) {
for(i = 31; i >= 0; --i)
addr[i] = p[i];
}
#endif
}
/**
* set_firmware_width - Determine if the firmware is wide or narrow.
*
* This function must be called before any pdc_* function that uses the convert_to_wide
* function.
*/
void __init set_firmware_width(void)
{
#ifdef __LP64__
int retval;
spin_lock_irq(&pdc_lock);
retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0);
convert_to_wide(pdc_result);
if(pdc_result[0] != NARROW_FIRMWARE)
parisc_narrow_firmware = 0;
spin_unlock_irq(&pdc_lock);
#endif
}
......@@ -582,6 +617,7 @@ int pdc_get_initiator(struct hardware_path *hwpath, unsigned char *scsi_id,
case 10: *period = 1000; break;
case 20: *period = 500; break;
case 40: *period = 250; break;
case 80: *period = 125; break;
default: /* Do nothing */ break;
}
......
......@@ -1273,8 +1273,8 @@ static struct hp_cpu_type_mask {
{ 0x05e6, 0x0ffe, pcxw2 }, /* 0x05e6 - 0x05e7 */
{ 0x05e8, 0x0ff8, pcxw2 }, /* 0x05e8 - 0x05ef */
{ 0x05f0, 0x0ff0, pcxw2 }, /* 0x05f0 - 0x05ff */
{ 0x0600, 0x0ff0, pcxl }, /* 0x0600 - 0x060f */
{ 0x0610, 0x0ff0, pcxl }, /* 0x0610 - 0x061f */
{ 0x0600, 0x0fe0, pcxl }, /* 0x0600 - 0x061f */
{ 0x0880, 0x0ff0, mako }, /* 0x0880 - 0x088f */
{ 0x0000, 0x0000, pcx } /* terminate table */
};
......@@ -1289,7 +1289,8 @@ char *cpu_name_version[][2] = {
[pcxu_] { "PA8200 (PCX-U+)", "2.0" },
[pcxw] { "PA8500 (PCX-W)", "2.0" },
[pcxw_] { "PA8600 (PCX-W+)", "2.0" },
[pcxw2] { "PA8700 (PCX-W2)", "2.0" }
[pcxw2] { "PA8700 (PCX-W2)", "2.0" },
[mako] { "PA8800 (MAKO)", "2.0" }
};
const char * __init
......
......@@ -82,19 +82,21 @@ $bss_loop:
ldo R%PA(swapper_pg_dir)(%r4),%r4
mtctl %r4,%cr24 /* Initialize kernel root pointer */
mtctl %r4,%cr25 /* Initialize user root pointer */
ldi ASM_PT_INITIAL,%r1
ldo ASM_PGD_ENTRY*ASM_PGD_ENTRY_SIZE(%r4),%r4
1:
stw %r3,0(%r4)
ldo ASM_PAGE_SIZE(%r3),%r3
addib,> -1,%r1,1b
ldo ASM_PGD_ENTRY_SIZE(%r4),%r4
#if (__PAGE_OFFSET != 0x10000000UL)
Error! Code below (the next two stw's) needs to be changed
#endif
stw %r3,0x100(%r4) /* Hardwired 0x1... kernel Vaddr start*/
ldo 0x1000(%r3),%r3
stw %r3,0x104(%r4)
ldo _PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */
ldil L%PA(pg0),%r1
ldo R%PA(pg0)(%r1),%r1
$pgt_fill_loop:
stwm %r3,4(%r1)
ldo 0x1000(%r3),%r3
bb,>= %r3,8,$pgt_fill_loop
stwm %r3,ASM_PTE_ENTRY_SIZE(%r1)
ldo ASM_PAGE_SIZE(%r3),%r3
bb,>= %r3,31-KERNEL_INITIAL_ORDER,$pgt_fill_loop
nop
......
......@@ -88,26 +88,25 @@ $bss_loop:
mtctl %r4,%cr24 /* Initialize kernel root pointer */
mtctl %r4,%cr25 /* Initialize user root pointer */
#if (__PAGE_OFFSET != 0x10000000UL)
Error! Code below (the next five std's) needs to be changed
#endif
std %r3,0x00(%r4) /* Hardwired 0x1... kernel Vaddr start*/
stw %r3,ASM_PGD_ENTRY*ASM_PGD_ENTRY_SIZE(%r4)
ldo _PAGE_TABLE(%r1),%r3
std %r3,0x400(%r5) /* Hardwired 0x1... kernel Vaddr start*/
ldo 0x1000(%r3),%r3
std %r3,0x408(%r5)
ldo 0x1000(%r3),%r3
std %r3,0x410(%r5)
ldo 0x1000(%r3),%r3
std %r3,0x418(%r5)
ldo ASM_PMD_ENTRY*ASM_PMD_ENTRY_SIZE(%r5),%r5
ldi ASM_PT_INITIAL,%r1
1:
stw %r3,0(%r5)
ldo ASM_PAGE_SIZE(%r3),%r3
addib,> -1,%r1,1b
ldo ASM_PMD_ENTRY_SIZE(%r5),%r5
ldo _PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */
ldil L%PA(pg0),%r1
ldo R%PA(pg0)(%r1),%r1
$pgt_fill_loop:
std,ma %r3,8(%r1)
ldo 0x1000(%r3),%r3
bb,>= %r3,8,$pgt_fill_loop
std,ma %r3,ASM_PTE_ENTRY_SIZE(%r1)
ldo ASM_PAGE_SIZE(%r3),%r3
bb,>= %r3,31-KERNEL_INITIAL_ORDER,$pgt_fill_loop
nop
/* And the RFI Target address too */
......@@ -169,7 +168,6 @@ common_stext:
tophys_r1 %r10
std %r11, TASK_PT_GR11(%r10)
#ifndef CONFIG_PDC_NARROW
/* Switch to wide mode; Superdome doesn't support narrow PDC
** calls.
*/
......@@ -179,7 +177,6 @@ common_stext:
bv (%rp)
ssm PSW_SM_W,%r0
2:
#endif /* CONFIG_PDC_NARROW */
/* Set Wide mode as the "Default" (eg for traps)
** First trap occurs *right* after (or part of) rfi for slave CPUs.
......
......@@ -52,11 +52,13 @@ union thread_union init_thread_union
__attribute__((aligned(128))) __attribute__((__section__(".data.init_task"))) =
{ INIT_THREAD_INFO(init_task) };
pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(4096))) = { {0}, };
#ifdef __LP64__
unsigned long pmd0[PTRS_PER_PMD] __attribute__ ((aligned(4096))) = { 0, };
/* NOTE: This layout exactly conforms to the hybrid L2/L3 page table layout
* with the first pmd adjacent to the pgd and below it */
pmd_t pmd0[PTRS_PER_PMD] __attribute__ ((aligned(PAGE_SIZE))) = { {0}, };
#endif
unsigned long pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((aligned(4096))) = { 0, };
pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(PAGE_SIZE))) = { {0}, };
pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((aligned(PAGE_SIZE))) = { {0}, };
/*
* Initial task structure.
......
......@@ -350,10 +350,6 @@ copy_user_page_asm:
.procend
#if (TMPALIAS_MAP_START >= 0x80000000UL)
Warning TMPALIAS_MAP_START changed. If > 2 Gb, code in pacache.S is bogus
#endif
/*
* NOTE: Code in clear_user_page has a hard coded dependency on the
* maximum alias boundary being 4 Mb. We've been assured by the
......@@ -490,6 +486,9 @@ clear_user_page_asm:
ldil L%(TMPALIAS_MAP_START),%r28
#ifdef __LP64__
#if (TMPALIAS_MAP_START >= 0x80000000)
depdi 0,31,32,%r28 /* clear any sign extension */
#endif
extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
depd %r25,63,22,%r28 /* Form aliased virtual address 'to' */
depdi 0,63,12,%r28 /* Clear any offset bits */
......@@ -575,6 +574,95 @@ flush_kernel_dcache_page:
.procend
.export flush_user_dcache_page
flush_user_dcache_page:
.proc
.callinfo NO_CALLS
.entry
ldil L%dcache_stride,%r1
ldw R%dcache_stride(%r1),%r23
#ifdef __LP64__
depdi,z 1,63-PAGE_SHIFT,1,%r25
#else
depwi,z 1,31-PAGE_SHIFT,1,%r25
#endif
add %r26,%r25,%r25
sub %r25,%r23,%r25
1: fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
fdc,m %r23(%sr3,%r26)
CMPB<< %r26,%r25,1b
fdc,m %r23(%sr3,%r26)
sync
bv %r0(%r2)
nop
.exit
.procend
.export flush_user_icache_page
flush_user_icache_page:
.proc
.callinfo NO_CALLS
.entry
ldil L%dcache_stride,%r1
ldw R%dcache_stride(%r1),%r23
#ifdef __LP64__
depdi,z 1,63-PAGE_SHIFT,1,%r25
#else
depwi,z 1,31-PAGE_SHIFT,1,%r25
#endif
add %r26,%r25,%r25
sub %r25,%r23,%r25
1: fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
fic,m %r23(%sr3,%r26)
CMPB<< %r26,%r25,1b
fic,m %r23(%sr3,%r26)
sync
bv %r0(%r2)
nop
.exit
.procend
.export purge_kernel_dcache_page
purge_kernel_dcache_page:
......
......@@ -539,10 +539,10 @@ struct hppa_dma_ops pcx_dma_ops = {
.unmap_single = pa11_dma_unmap_single,
.map_sg = pa11_dma_map_sg,
.unmap_sg = pa11_dma_unmap_sg,
.dma_sync_single_cpu = pa11_dma_sync_single_cpu,
.dma_sync_single_device = pa11_dma_sync_single_device,
.dma_sync_sg_cpu = pa11_dma_sync_sg_cpu,
.dma_sync_sg_device = pa11_dma_sync_sg_device,
.dma_sync_single_for_cpu = pa11_dma_sync_single_for_cpu,
.dma_sync_single_for_device = pa11_dma_sync_single_for_device,
.dma_sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu,
.dma_sync_sg_for_device = pa11_dma_sync_sg_for_device,
};
......
......@@ -506,9 +506,11 @@ static int __init perf_init(void)
perf_processor_interface = ONYX_INTF;
} else if (boot_cpu_data.cpu_type == pcxw ||
boot_cpu_data.cpu_type == pcxw_ ||
boot_cpu_data.cpu_type == pcxw2) {
boot_cpu_data.cpu_type == pcxw2 ||
boot_cpu_data.cpu_type == mako) {
perf_processor_interface = CUDA_INTF;
if (boot_cpu_data.cpu_type == pcxw2)
if (boot_cpu_data.cpu_type == pcxw2 ||
boot_cpu_data.cpu_type == mako)
bitmask_array = perf_bitmasks_piranha;
} else {
perf_processor_interface = UNKNOWN_INTF;
......
......@@ -44,6 +44,7 @@
#include <linux/sched.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/kallsyms.h>
#include <asm/io.h>
#include <asm/offsets.h>
......@@ -51,6 +52,7 @@
#include <asm/pdc_chassis.h>
#include <asm/pgalloc.h>
#include <asm/uaccess.h>
#include <asm/unwind.h>
int hlt_counter;
......@@ -368,3 +370,28 @@ asmlinkage int sys_execve(struct pt_regs *regs)
return error;
}
unsigned long
get_wchan(struct task_struct *p)
{
struct unwind_frame_info info;
unsigned long ip;
int count = 0;
/*
* These bracket the sleeping functions..
*/
# define first_sched ((unsigned long) scheduling_functions_start_here)
# define last_sched ((unsigned long) scheduling_functions_end_here)
unwind_frame_init_from_blocked_task(&info, p);
do {
if (unwind_once(&info) < 0)
return 0;
ip = info.ip;
if (ip < first_sched || ip >= last_sched)
return ip;
} while (count++ < 16);
return 0;
# undef first_sched
# undef last_sched
}
......@@ -231,9 +231,7 @@ void __init collect_boot_cpu_data(void)
boot_cpu_data.hversion = boot_cpu_data.pdc.model.hversion;
boot_cpu_data.sversion = boot_cpu_data.pdc.model.sversion;
boot_cpu_data.cpu_type =
parisc_get_cpu_type(boot_cpu_data.hversion);
boot_cpu_data.cpu_type = parisc_get_cpu_type(boot_cpu_data.hversion);
boot_cpu_data.cpu_name = cpu_name_version[boot_cpu_data.cpu_type][0];
boot_cpu_data.family_name = cpu_name_version[boot_cpu_data.cpu_type][1];
}
......@@ -276,6 +274,7 @@ int __init init_per_cpu(int cpunum)
int ret;
struct pdc_coproc_cfg coproc_cfg;
set_firmware_width();
ret = pdc_coproc_cfg(&coproc_cfg);
if(ret >= 0 && coproc_cfg.ccr_functional) {
......
......@@ -26,6 +26,7 @@ real_stack:
save_cr_space:
.block REG_SZ * N_SAVED_REGS
save_cr_end:
/************************ 32-bit real-mode calls ***********************/
......@@ -123,7 +124,7 @@ save_control_regs:
nop
restore_control_regs:
load32 PA(save_cr_space+(N_SAVED_REGS*REG_SZ)), %r26
load32 PA(save_cr_end), %r26
POP_CR(%cr15, %r26)
POP_CR(%cr31, %r26)
POP_CR(%cr30, %r26)
......
......@@ -121,8 +121,11 @@ void __init setup_arch(char **cmdline_p)
pdc_console_init();
#ifdef CONFIG_PDC_NARROW
#ifdef __LP64__
extern int parisc_narrow_firmware;
if(parisc_narrow_firmware) {
printk(KERN_INFO "Kernel is using PDC in 32-bit mode.\n");
}
#endif
setup_pdc();
setup_cmdline(cmdline_p);
......@@ -204,6 +207,7 @@ static void __init parisc_proc_mkdir(void)
case pcxw:
case pcxw_:
case pcxw2:
case mako: /* XXX : this is really mckinley bus */
if (NULL == proc_runway_root)
{
proc_runway_root = proc_mkdir("bus/runway", 0);
......
......@@ -353,12 +353,17 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
goto give_sigsegv;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
already in userspace. The first words of tramp are used to
save the previous sigrestartblock trampoline that might be
on the stack. We start the sigreturn trampoline at
SIGRESTARTBLOCK_TRAMP+X. */
err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0,
&frame->tramp[SIGRETURN_TRAMP+0]);
err |= __put_user(INSN_LDI_R20, &frame->tramp[SIGRETURN_TRAMP+1]);
err |= __put_user(INSN_BLE_SR2_R0, &frame->tramp[SIGRETURN_TRAMP+2]);
err |= __put_user(INSN_NOP, &frame->tramp[SIGRETURN_TRAMP+3]);
&frame->tramp[SIGRESTARTBLOCK_TRAMP+0]);
err |= __put_user(INSN_LDI_R20,
&frame->tramp[SIGRESTARTBLOCK_TRAMP+1]);
err |= __put_user(INSN_BLE_SR2_R0,
&frame->tramp[SIGRESTARTBLOCK_TRAMP+2]);
err |= __put_user(INSN_NOP, &frame->tramp[SIGRESTARTBLOCK_TRAMP+3]);
#if DEBUG_SIG
/* Assert that we're flushing in the correct space... */
......@@ -370,12 +375,16 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
}
#endif
flush_user_dcache_range((unsigned long) &frame->tramp[SIGRETURN_TRAMP],
flush_user_dcache_range((unsigned long) &frame->tramp[0],
(unsigned long) &frame->tramp[TRAMP_SIZE]);
flush_user_icache_range((unsigned long) &frame->tramp[SIGRETURN_TRAMP],
flush_user_icache_range((unsigned long) &frame->tramp[0],
(unsigned long) &frame->tramp[TRAMP_SIZE]);
rp = (unsigned long) &frame->tramp[SIGRETURN_TRAMP];
/* TRAMP Words 0-4, Lenght 5 = SIGRESTARTBLOCK_TRAMP
* TRAMP Words 5-9, Length 4 = SIGRETURN_TRAMP
* So the SIGRETURN_TRAMP is at the end of SIGRESTARTBLOCK_TRAMP
*/
rp = (unsigned long) &frame->tramp[SIGRESTARTBLOCK_TRAMP];
if (err)
goto give_sigsegv;
......
......@@ -3,7 +3,7 @@
**
** Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
** Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
** Copyright (C) 2001 Grant Grundler <grundler@parisc-linux.org>
** Copyright (C) 2001,2004 Grant Grundler <grundler@parisc-linux.org>
**
** Lots of stuff stolen from arch/alpha/kernel/smp.c
** ...and then parisc stole from arch/ia64/kernel/smp.c. Thanks David! :^)
......@@ -60,20 +60,16 @@ spinlock_t smp_lock = SPIN_LOCK_UNLOCKED;
volatile struct task_struct *smp_init_current_idle_task;
static volatile int smp_commenced = 0; /* Set when the idlers are all forked */
static volatile int cpu_now_booting = 0; /* track which CPU is booting */
static int parisc_max_cpus = -1; /* Command line */
unsigned long cache_decay_ticks; /* declared by include/linux/sched.h */
cpumask_t cpu_online_map = CPU_MASK_NONE; /* Bitmap of online CPUs */
#define IS_LOGGED_IN(cpunum) (cpu_isset(cpunum, cpu_online_map))
cpumask_t cpu_possible_map = CPU_MASK_NONE; /* Bitmap of Present CPUs */
EXPORT_SYMBOL(cpu_online_map);
EXPORT_SYMBOL(cpu_possible_map);
int smp_num_cpus = 1;
int smp_threads_ready = 0;
unsigned long cache_decay_ticks;
static int max_cpus = -1; /* Command line */
cpumask_t cpu_present_mask;
EXPORT_SYMBOL(cpu_present_mask);
struct smp_call_struct {
void (*func) (void *info);
......@@ -114,7 +110,7 @@ ipi_init(int cpuid)
#error verify IRQ_OFFSET(IPI_IRQ) is ipi_interrupt() in new IRQ region
if(IS_LOGGED_IN(cpuid) )
if(cpu_online(cpuid) )
{
switch_to_idle_task(current);
}
......@@ -293,12 +289,13 @@ send_IPI_allbutself(enum ipi_message_type op)
{
int i;
for (i = 0; i < smp_num_cpus; i++) {
if (i != smp_processor_id())
for (i = 0; i < parisc_max_cpus; i++) {
if (cpu_online(i) && i != smp_processor_id())
send_IPI_single(i, op);
}
}
inline void
smp_send_stop(void) { send_IPI_allbutself(IPI_CPU_STOP); }
......@@ -334,8 +331,8 @@ smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
data.func = func;
data.info = info;
data.wait = wait;
atomic_set(&data.unstarted_count, smp_num_cpus - 1);
atomic_set(&data.unfinished_count, smp_num_cpus - 1);
atomic_set(&data.unstarted_count, num_online_cpus() - 1);
atomic_set(&data.unfinished_count, num_online_cpus() - 1);
if (retry) {
spin_lock (&lock);
......@@ -395,7 +392,7 @@ EXPORT_SYMBOL(smp_call_function);
static int __init nosmp(char *str)
{
max_cpus = 0;
parisc_max_cpus = 0;
return 1;
}
......@@ -403,7 +400,7 @@ __setup("nosmp", nosmp);
static int __init maxcpus(char *str)
{
get_option(&str, &max_cpus);
get_option(&str, &parisc_max_cpus);
return 1;
}
......@@ -499,17 +496,13 @@ void __init smp_callin(void)
local_irq_enable(); /* Interrupts have been off until now */
/* Slaves wait here until Big Poppa daddy say "jump" */
mb(); /* PARANOID */
while (!smp_commenced) ;
mb(); /* PARANOID */
cpu_idle(); /* Wait for timer to schedule some work */
/* NOTREACHED */
panic("smp_callin() AAAAaaaaahhhh....\n");
}
#if 0
/*
* Create the idle task for a new Slave CPU. DO NOT use kernel_thread()
* because that could end up calling schedule(). If it did, the new idle
......@@ -531,7 +524,7 @@ static struct task_struct *fork_by_hand(void)
/*
* Bring one cpu online.
*/
static int __init smp_boot_one_cpu(int cpuid, int cpunum)
int __init smp_boot_one_cpu(int cpuid, int cpunum)
{
struct task_struct *idle;
long timeout;
......@@ -576,12 +569,11 @@ static int __init smp_boot_one_cpu(int cpuid, int cpunum)
/*
* OK, wait a bit for that CPU to finish staggering about.
* Slave will set a bit when it reaches smp_cpu_init() and then
* wait for smp_commenced to be 1.
* Once we see the bit change, we can move on.
* Slave will set a bit when it reaches smp_cpu_init().
* Once the "monarch CPU" sees the bit change, it can move on.
*/
for (timeout = 0; timeout < 10000; timeout++) {
if(IS_LOGGED_IN(cpunum)) {
if(cpu_online(cpunum)) {
/* Which implies Slave has started up */
cpu_now_booting = 0;
smp_init_current_idle_task = NULL;
......@@ -608,120 +600,56 @@ static int __init smp_boot_one_cpu(int cpuid, int cpunum)
#endif
return 0;
}
#endif
/*
** inventory.c:do_inventory() has already 'discovered' the additional CPU's.
** We are ready to wrest them from PDC's control now.
** Called by smp_init bring all the secondaries online and hold them.
**
** o Setup of the IPI irq handler is done in irq.c.
** o MEM_RENDEZ is initialzed in head.S:stext()
**
*/
void __init smp_boot_cpus(void)
void __devinit smp_prepare_boot_cpu(void)
{
int i, cpu_count = 1;
unsigned long bogosum = cpu_data[0].loops_per_jiffy; /* Count Monarch */
/* REVISIT - assumes first CPU reported by PAT PDC is BSP */
int bootstrap_processor=cpu_data[0].cpuid; /* CPU ID of BSP */
/* Setup BSP mappings */
printk(KERN_DEBUG "SMP: bootstrap CPU ID is %d\n",bootstrap_processor);
init_task.thread_info->cpu = bootstrap_processor;
current->thread_info->cpu = bootstrap_processor;
/* Mark Boostrap processor as present */
cpu_online_map = cpumask_of_cpu(bootstrap_processor);
current->active_mm = &init_mm;
#ifdef ENTRY_SYS_CPUS
cpu_data[0].state = STATE_RUNNING;
#endif
cpu_present_mask = cpumask_of_cpu(bootstrap_processor);
/* Nothing to do when told not to. */
if (max_cpus == 0) {
printk(KERN_INFO "SMP mode deactivated.\n");
return;
}
if (max_cpus != -1)
printk(KERN_INFO "Limiting CPUs to %d\n", max_cpus);
/* Setup BSP mappings */
printk(KERN_DEBUG "SMP: bootstrap CPU ID is %d\n",bootstrap_processor);
init_task.thread_info->cpu = bootstrap_processor;
current->thread_info->cpu = bootstrap_processor;
/* We found more than one CPU.... */
if (boot_cpu_data.cpu_count > 1) {
cpu_set(bootstrap_processor, cpu_online_map);
cpu_set(bootstrap_processor, cpu_possible_map);
for (i = 0; i < NR_CPUS; i++) {
if (cpu_data[i].cpuid == NO_PROC_ID ||
cpu_data[i].cpuid == bootstrap_processor)
continue;
/* Mark Boostrap processor as present */
current->active_mm = &init_mm;
if (smp_boot_one_cpu(cpu_data[i].cpuid, cpu_count) < 0)
continue;
cache_decay_ticks = HZ/100; /* FIXME very rough. */
}
bogosum += cpu_data[i].loops_per_jiffy;
cpu_count++; /* Count good CPUs only... */
cpu_present_mask |= 1UL << i;
/* Bail when we've started as many CPUS as told to */
if (cpu_count == max_cpus)
break;
}
}
if (cpu_count == 1) {
printk(KERN_INFO "SMP: Bootstrap processor only.\n");
}
/*
** inventory.c:do_inventory() hasn't yet been run and thus we
** don't 'discover' the additional CPU's until later.
*/
void __init smp_prepare_cpus(unsigned int max_cpus)
{
/*
* FIXME very rough.
*/
cache_decay_ticks = HZ/100;
if (max_cpus != -1)
printk(KERN_INFO "SMP: Limited to %d CPUs\n", max_cpus);
printk(KERN_INFO "SMP: Total %d of %d processors activated "
"(%lu.%02lu BogoMIPS noticed) (Present Mask: %lu).\n",
cpu_count, boot_cpu_data.cpu_count, (bogosum + 25) / 5000,
((bogosum + 25) / 50) % 100, cpu_present_mask);
printk(KERN_INFO "SMP: Monarch CPU activated (%lu.%02lu BogoMIPS)\n",
(cpu_data[0].loops_per_jiffy + 25) / 5000,
((cpu_data[0].loops_per_jiffy + 25) / 50) % 100);
smp_num_cpus = cpu_count;
#ifdef PER_CPU_IRQ_REGION
ipi_init();
#endif
return;
}
/*
* Called from main.c by Monarch Processor.
* After this, any CPU can schedule any task.
*/
void smp_commence(void)
{
smp_commenced = 1;
mb();
return;
}
/*
* XXX FIXME : do nothing
*/
void smp_cpus_done(unsigned int cpu_max)
{
smp_threads_ready = 1;
}
void __init smp_prepare_cpus(unsigned int max_cpus)
{
smp_boot_cpus();
return;
}
void __devinit smp_prepare_boot_cpu(void)
{
cpu_set(smp_processor_id(), cpu_online_map);
cpu_set(smp_processor_id(), cpu_present_mask);
}
int __devinit __cpu_up(unsigned int cpu)
{
......@@ -748,7 +676,7 @@ int sys_cpus(int argc, char **argv)
#ifdef DUMP_MORE_STATE
for(i=0; i<NR_CPUS; i++) {
int cpus_per_line = 4;
if(IS_LOGGED_IN(i)) {
if(cpu_online(i)) {
if (j++ % cpus_per_line)
printk(" %3d",i);
else
......@@ -763,7 +691,7 @@ int sys_cpus(int argc, char **argv)
printk("\nCPUSTATE TASK CPUNUM CPUID HARDCPU(HPA)\n");
#ifdef DUMP_MORE_STATE
for(i=0;i<NR_CPUS;i++) {
if (!IS_LOGGED_IN(i))
if (!cpu_online(i))
continue;
if (cpu_data[i].cpuid != NO_PROC_ID) {
switch(cpu_data[i].state) {
......@@ -783,7 +711,7 @@ int sys_cpus(int argc, char **argv)
printk("%08x?", cpu_data[i].state);
break;
}
if(IS_LOGGED_IN(i)) {
if(cpu_online(i)) {
printk(" %4d",current_pid(i));
}
printk(" %6d",cpu_number_map(i));
......@@ -799,7 +727,7 @@ int sys_cpus(int argc, char **argv)
#ifdef DUMP_MORE_STATE
printk("\nCPUSTATE CPUID\n");
for (i=0;i<NR_CPUS;i++) {
if (!IS_LOGGED_IN(i))
if (!cpu_online(i))
continue;
if (cpu_data[i].cpuid != NO_PROC_ID) {
switch(cpu_data[i].state) {
......
......@@ -93,7 +93,7 @@ static unsigned long get_shared_area(struct address_space *mapping,
unsigned long addr, unsigned long len, unsigned long pgoff)
{
struct vm_area_struct *vma;
int offset = get_offset(mapping);
int offset = mapping ? get_offset(mapping) : 0;
addr = DCACHE_ALIGN(addr - offset) + offset;
......@@ -117,8 +117,10 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
if (!addr)
addr = TASK_UNMAPPED_BASE;
if (filp && (flags & MAP_SHARED)) {
if (filp) {
addr = get_shared_area(filp->f_mapping, addr, len, pgoff);
} else if(flags & MAP_SHARED) {
addr = get_shared_area(NULL, addr, len, pgoff);
} else {
addr = get_unshared_area(addr, len);
}
......
......@@ -155,9 +155,10 @@ linux_gateway_entry:
stw %r21, -56(%r30) /* 6th argument */
#endif
/* Are we being ptraced? */
mfctl %cr30, %r1
LDREG TI_FLAGS(%r1), %r19
bb,<,n %r19,31-TIF_SYSCALL_TRACE,.Ltracesys
LDREG TASK_PTRACE(%r1), %r1
bb,<,n %r1,31,.Ltracesys
/* Note! We cannot use the syscall table that is mapped
nearby since the gateway page is mapped execute-only. */
......
......@@ -334,3 +334,12 @@
ENTRY_SAME(epoll_ctl) /* 225 */
ENTRY_SAME(epoll_wait)
ENTRY_SAME(remap_file_pages)
ENTRY_SAME(semtimedop)
ENTRY_SAME(mq_open)
ENTRY_SAME(mq_unlink) /* 230 */
ENTRY_SAME(mq_timedsend)
ENTRY_SAME(mq_timedreceive)
ENTRY_SAME(mq_notify)
ENTRY_SAME(mq_getsetattr)
/* Nothing yet */ /* 235 */
/*
* Kernel unwinding support
*
* (c) 2002-2004 Randolph Chung <tausq@debian.org>
*
* Derived partially from the IA64 implementation. The PA-RISC
* Runtime Architecture Document is also a useful reference to
* understand what is happening here
*/
/*
* J. David Anglin writes:
*
* "You have to adjust the current sp to that at the begining of the function.
* There can be up to two stack additions to allocate the frame in the
* prologue. Similar things happen in the epilogue. In the presence of
* interrupts, you have to be concerned about where you are in the function
* and what stack adjustments have taken place."
*
* For now these cases are not handled, but they should be!
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/unwind.h>
/* #define DEBUG 1 */
#ifdef DEBUG
#define dbg(x...) printk(x)
#else
#define dbg(x...)
#endif
extern const struct unwind_table_entry __start___unwind[];
extern const struct unwind_table_entry __stop___unwind[];
static spinlock_t unwind_lock;
/*
* the kernel unwind block is not dynamically allocated so that
* we can call unwind_init as early in the bootup process as
* possible (before the slab allocator is initialized)
*/
static struct unwind_table kernel_unwind_table;
static struct unwind_table *unwind_tables, *unwind_tables_end;
static inline const struct unwind_table_entry *
find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
{
const struct unwind_table_entry *e = 0;
unsigned long lo, hi, mid;
addr -= table->base_addr;
for (lo = 0, hi = table->length; lo < hi; )
{
mid = (lo + hi) / 2;
e = &table->table[mid];
if (addr < e->region_start)
hi = mid;
else if (addr > e->region_end)
lo = mid + 1;
else
break;
}
return e;
}
static inline const struct unwind_table_entry *
find_unwind_entry(unsigned long addr)
{
struct unwind_table *table = unwind_tables;
const struct unwind_table_entry *e = NULL;
if (addr >= kernel_unwind_table.start &&
addr <= kernel_unwind_table.end)
e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
else
for (; table; table = table->next)
{
if (addr >= table->start &&
addr <= table->end)
e = find_unwind_entry_in_table(table, addr);
if (e)
break;
}
return e;
}
static void
unwind_table_init(struct unwind_table *table, const char *name,
unsigned long base_addr, unsigned long gp,
const void *table_start, const void *table_end)
{
const struct unwind_table_entry *start = table_start;
const struct unwind_table_entry *end = table_end - 1;
table->name = name;
table->base_addr = base_addr;
table->gp = gp;
table->start = base_addr + start->region_start;
table->end = base_addr + end->region_end;
table->table = (struct unwind_table_entry *)table_start;
table->length = end - start;
table->next = NULL;
}
void *
unwind_table_add(const char *name, unsigned long base_addr,
unsigned long gp,
const void *start, const void *end)
{
struct unwind_table *table;
unsigned long flags;
table = kmalloc(sizeof(struct unwind_table), GFP_USER);
if (table == NULL)
return 0;
unwind_table_init(table, name, base_addr, gp, start, end);
spin_lock_irqsave(&unwind_lock, flags);
if (unwind_tables)
{
unwind_tables_end->next = table;
unwind_tables_end = table;
}
else
{
unwind_tables = unwind_tables_end = table;
}
spin_unlock_irqrestore(&unwind_lock, flags);
return table;
}
/* Called from setup_arch to import the kernel unwind info */
static int unwind_init(void)
{
long start, stop;
register unsigned long gp __asm__ ("r27");
start = (long)&__start___unwind[0];
stop = (long)&__stop___unwind[0];
printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n",
start, stop,
(stop - start) / sizeof(struct unwind_table_entry));
unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
gp,
&__start___unwind[0], &__stop___unwind[0]);
#if 0
{
int i;
for (i = 0; i < 10; i++)
{
printk("region 0x%x-0x%x\n",
__start___unwind[i].region_start,
__start___unwind[i].region_end);
}
}
#endif
return 0;
}
static void unwind_frame_regs(struct unwind_frame_info *info)
{
const struct unwind_table_entry *e;
unsigned long npc;
unsigned int insn;
long frame_size = 0;
int looking_for_rp, rpoffset = 0;
e = find_unwind_entry(info->ip);
if (!e) {
unsigned long sp;
extern char _stext[], _etext[];
dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
/* Since we are doing the unwinding blind, we don't know if
we are adjusting the stack correctly or extracting the rp
correctly. The rp is checked to see if it belongs to the
kernel text section, if not we assume we don't have a
correct stack frame and we continue to unwind the stack.
This is not quite correct, and will fail for loadable
modules. */
sp = info->sp & ~63;
do {
info->prev_sp = sp - 64;
/* FIXME: what happens if we unwind too far so that
sp no longer falls in a mapped kernel page? */
#ifndef __LP64__
info->prev_ip = *(unsigned long *)(info->prev_sp - 20);
#else
info->prev_ip = *(unsigned long *)(info->prev_sp - 16);
#endif
sp = info->prev_sp;
} while (info->prev_ip < (unsigned long)_stext ||
info->prev_ip > (unsigned long)_etext);
} else {
dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, Save_RP = %d size = %u\n",
e->region_start, e->region_end, e->Save_SP, e->Save_RP, e->Total_frame_size);
looking_for_rp = e->Save_RP;
for (npc = e->region_start;
(frame_size < (e->Total_frame_size << 3) || looking_for_rp) &&
npc < info->ip;
npc += 4) {
insn = *(unsigned int *)npc;
if ((insn & 0xffffc000) == 0x37de0000 ||
(insn & 0xffe00000) == 0x6fc00000) {
/* ldo X(sp), sp, or stwm X,D(sp) */
frame_size += (insn & 0x1 ? -1 << 13 : 0) |
((insn & 0x3fff) >> 1);
} else if ((insn & 0xffe00008) == 0x7ec00008) {
/* std,ma X,D(sp) */
frame_size += (insn & 0x1 ? -1 << 13 : 0) |
(((insn >> 4) & 0x3ff) << 3);
} else if (insn == 0x6bc23fd9) {
/* stw rp,-20(sp) */
rpoffset = 20;
looking_for_rp = 0;
} else if (insn == 0x0fc212c1) {
/* std rp,-16(sr0,sp) */
rpoffset = 16;
looking_for_rp = 0;
}
}
info->prev_sp = info->sp - frame_size;
if (rpoffset)
info->prev_ip = *(unsigned long *)(info->prev_sp - rpoffset);
}
}
void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t,
struct pt_regs *regs)
{
memset(info, 0, sizeof(struct unwind_frame_info));
info->t = t;
info->sp = regs->ksp;
info->ip = regs->kpc;
dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", (int)t->pid, info->sp, info->ip);
}
void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
{
struct pt_regs *regs = &t->thread.regs;
unwind_frame_init(info, t, regs);
}
int unwind_once(struct unwind_frame_info *next_frame)
{
unwind_frame_regs(next_frame);
if (next_frame->prev_sp == 0 ||
next_frame->prev_ip == 0)
return -1;
next_frame->sp = next_frame->prev_sp;
next_frame->ip = next_frame->prev_ip;
next_frame->prev_sp = 0;
next_frame->prev_ip = 0;
dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", (int)next_frame->t->pid, next_frame->sp, next_frame->ip);
return 0;
}
int unwind_to_user(struct unwind_frame_info *info)
{
int ret;
do {
ret = unwind_once(info);
} while (!ret && !(info->ip & 3));
return ret;
}
module_init(unwind_init);
......@@ -26,6 +26,7 @@
#include <asm-generic/vmlinux.lds.h>
/* needed for the processor specific cache alignment size */
#include <asm/cache.h>
#include <asm/page.h>
/* ld script to make hppa Linux kernel */
#ifndef CONFIG_PARISC64
......@@ -45,13 +46,17 @@ jiffies = jiffies_64;
SECTIONS
{
. = 0x10100000;
. = KERNEL_BINARY_TEXT_START;
_text = .; /* Text and read-only data */
.text ALIGN(16) : {
*(.text*)
*(.text)
SCHED_TEXT
*(.PARISC.unwind)
*(.text.do_softirq)
*(.text.sys_exit)
*(.text.do_sigaltstack)
*(.text.do_fork)
*(.text.*)
*(.fixup)
*(.lock.text) /* out-of-line lock text */
*(.gnu.warning)
......@@ -72,6 +77,10 @@ SECTIONS
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
__start___unwind = .; /* unwind info */
.PARISC.unwind : { *(.PARISC.unwind) }
__stop___unwind = .;
.data : { /* Data */
*(.data)
CONSTRUCTORS
......@@ -88,6 +97,10 @@ SECTIONS
. = ALIGN(L1_CACHE_BYTES);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
/* PA-RISC locks requires 16-byte alignment */
. = ALIGN(16);
.data.lock_aligned : { *(.data.lock_aligned) }
_edata = .; /* End of data section */
. = ALIGN(16384); /* init_task */
......
......@@ -13,22 +13,20 @@
#include <asm/atomic.h>
#ifdef CONFIG_SMP
spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] = {
[0 ... (ATOMIC_HASH_SIZE-1)] = SPIN_LOCK_UNLOCKED
atomic_lock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned = {
[0 ... (ATOMIC_HASH_SIZE-1)] = (atomic_lock_t) { { 1, 1, 1, 1 } }
};
#endif
spinlock_t __atomic_lock = SPIN_LOCK_UNLOCKED;
#ifdef __LP64__
unsigned long __xchg64(unsigned long x, unsigned long *ptr)
{
unsigned long temp, flags;
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
temp = *ptr;
*ptr = x;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
return temp;
}
#endif
......@@ -38,10 +36,10 @@ unsigned long __xchg32(int x, int *ptr)
unsigned long flags;
unsigned long temp;
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
(long) temp = (long) *ptr; /* XXX - sign extension wanted? */
*ptr = x;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
return temp;
}
......@@ -51,10 +49,10 @@ unsigned long __xchg8(char x, char *ptr)
unsigned long flags;
unsigned long temp;
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
(long) temp = (long) *ptr; /* XXX - sign extension wanted? */
*ptr = x;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
return temp;
}
......@@ -65,10 +63,10 @@ unsigned long __cmpxchg_u64(volatile unsigned long *ptr, unsigned long old, unsi
unsigned long flags;
unsigned long prev;
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
if ((prev = *ptr) == old)
*ptr = new;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
return prev;
}
#endif
......@@ -78,9 +76,9 @@ unsigned long __cmpxchg_u32(volatile unsigned int *ptr, unsigned int old, unsign
unsigned long flags;
unsigned int prev;
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(ptr), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
if ((prev = *ptr) == old)
*ptr = new;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(ptr), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
return (unsigned long)prev;
}
......@@ -424,7 +424,12 @@ void free_initmem(void)
* a hole of 4kB between each vmalloced area for the same reason.
*/
#define MAP_START 0x4000 /* Leave room for gateway page expansion */
/* Leave room for gateway page expansion */
#if KERNEL_MAP_START < GATEWAY_PAGE_SIZE
#error KERNEL_MAP_START is in gateway reserved region
#endif
#define MAP_START (KERNEL_MAP_START)
#define VM_MAP_OFFSET (32*1024)
#define SET_MAP_OFFSET(x) ((void *)(((unsigned long)(x) + VM_MAP_OFFSET) \
& ~(VM_MAP_OFFSET-1)))
......@@ -545,7 +550,7 @@ static void __init map_pages(unsigned long start_vaddr, unsigned long start_padd
*/
if (!pmd) {
pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE << PMD_ORDER);
pmd = (pmd_t *) __pa(pmd);
}
......
......@@ -63,7 +63,6 @@
#include <linux/ioport.h>
#include <linux/serial.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/parport.h>
#include <linux/parport_pc.h>
#include <linux/termios.h>
......@@ -71,6 +70,7 @@
#include <linux/serial_core.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/irq.h>
......
......@@ -17,7 +17,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <asm/io.h>
......
......@@ -3,7 +3,6 @@
#include <linux/config.h>
#include <asm/system.h>
/* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>. */
/*
......@@ -15,33 +14,47 @@
*/
#ifdef CONFIG_SMP
#include <asm/cache.h> /* we use L1_CACHE_BYTES */
typedef spinlock_t atomic_lock_t;
/* Use an array of spinlocks for our atomic_ts.
** Hash function to index into a different SPINLOCK.
** Since "a" is usually an address, ">>8" makes one spinlock per 64-bytes.
*/
* Hash function to index into a different SPINLOCK.
* Since "a" is usually an address, use one spinlock per cacheline.
*/
# define ATOMIC_HASH_SIZE 4
# define ATOMIC_HASH(a) (&__atomic_hash[(((unsigned long) a)>>8)&(ATOMIC_HASH_SIZE-1)])
# define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) a)/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ]))
extern atomic_lock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
extern spinlock_t __atomic_hash[ATOMIC_HASH_SIZE];
/* copied from <asm/spinlock.h> and modified */
# define SPIN_LOCK(x) \
do { while(__ldcw(&(x)->lock) == 0); } while(0)
static inline void atomic_spin_lock(atomic_lock_t *a)
{
while (__ldcw(a) == 0)
while (a->lock[0] == 0);
}
static inline void atomic_spin_unlock(atomic_lock_t *a)
{
a->lock[0] = 1;
}
# define SPIN_UNLOCK(x) \
do { (x)->lock = 1; } while(0)
#else
# define ATOMIC_HASH_SIZE 1
# define ATOMIC_HASH(a) (0)
/* copied from <linux/spinlock.h> and modified */
# define SPIN_LOCK(x) (void)(x)
# define SPIN_UNLOCK(x) do { } while(0)
# define atomic_spin_lock(x) (void)(x)
# define atomic_spin_unlock(x) do { } while(0)
#endif
/* copied from <linux/spinlock.h> and modified */
#define SPIN_LOCK_IRQSAVE(lock, flags) do { local_irq_save(flags); SPIN_LOCK(lock); } while (0)
#define SPIN_UNLOCK_IRQRESTORE(lock, flags) do { SPIN_UNLOCK(lock); local_irq_restore(flags); } while (0)
#define atomic_spin_lock_irqsave(lock, flags) do { \
local_irq_save(flags); \
atomic_spin_lock(lock); \
} while (0)
#define atomic_spin_unlock_irqrestore(lock, flags) do { \
atomic_spin_unlock(lock); \
local_irq_restore(flags); \
} while (0)
/* Note that we need not lock read accesses - aligned word writes/reads
* are atomic, so a reader never sees unconsistent values.
......@@ -137,22 +150,22 @@ static __inline__ int __atomic_add_return(int i, atomic_t *v)
{
int ret;
unsigned long flags;
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(v), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(v), flags);
ret = (v->counter += i);
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(v), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
return ret;
}
static __inline__ void atomic_set(atomic_t *v, int i)
{
unsigned long flags;
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(v), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(v), flags);
v->counter = i;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(v), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
}
static __inline__ int atomic_read(const atomic_t *v)
......
......@@ -38,9 +38,9 @@ static __inline__ void set_bit(int nr, void * address)
addr += (nr >> SHIFT_PER_LONG);
mask = 1L << CHOP_SHIFTCOUNT(nr);
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
*addr |= mask;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
}
static __inline__ void __set_bit(int nr, void * address)
......@@ -61,9 +61,9 @@ static __inline__ void clear_bit(int nr, void * address)
addr += (nr >> SHIFT_PER_LONG);
mask = 1L << CHOP_SHIFTCOUNT(nr);
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
*addr &= ~mask;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
}
static __inline__ void __clear_bit(unsigned long nr, volatile void * address)
......@@ -84,9 +84,9 @@ static __inline__ void change_bit(int nr, void * address)
addr += (nr >> SHIFT_PER_LONG);
mask = 1L << CHOP_SHIFTCOUNT(nr);
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
*addr ^= mask;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
}
static __inline__ void __change_bit(int nr, void * address)
......@@ -108,10 +108,10 @@ static __inline__ int test_and_set_bit(int nr, void * address)
addr += (nr >> SHIFT_PER_LONG);
mask = 1L << CHOP_SHIFTCOUNT(nr);
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
oldbit = (*addr & mask) ? 1 : 0;
*addr |= mask;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
return oldbit;
}
......@@ -139,10 +139,10 @@ static __inline__ int test_and_clear_bit(int nr, void * address)
addr += (nr >> SHIFT_PER_LONG);
mask = 1L << CHOP_SHIFTCOUNT(nr);
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
oldbit = (*addr & mask) ? 1 : 0;
*addr &= ~mask;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
return oldbit;
}
......@@ -170,10 +170,10 @@ static __inline__ int test_and_change_bit(int nr, void * address)
addr += (nr >> SHIFT_PER_LONG);
mask = 1L << CHOP_SHIFTCOUNT(nr);
SPIN_LOCK_IRQSAVE(ATOMIC_HASH(addr), flags);
atomic_spin_lock_irqsave(ATOMIC_HASH(addr), flags);
oldbit = (*addr & mask) ? 1 : 0;
*addr ^= mask;
SPIN_UNLOCK_IRQRESTORE(ATOMIC_HASH(addr), flags);
atomic_spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
return oldbit;
}
......@@ -427,6 +427,17 @@ static __inline__ unsigned long find_next_bit(unsigned long *addr, unsigned long
return result + __ffs(tmp);
}
/**
* find_first_bit - find the first set bit in a memory region
* @addr: The address to start the search at
* @size: The maximum size to search
*
* Returns the bit-number of the first set bit, not the number of the byte
* containing a bit.
*/
#define find_first_bit(addr, size) \
find_next_bit((addr), (size), 0)
#define _EXT2_HAVE_ASM_BITOPS_
#ifdef __KERNEL__
......
......@@ -52,6 +52,8 @@ extern void disable_sr_hashing(void); /* turns off space register hashing */
extern void disable_sr_hashing_asm(int); /* low level support for above */
extern void free_sid(unsigned long);
unsigned long alloc_sid(void);
extern void flush_user_dcache_page(unsigned long);
extern void flush_user_icache_page(unsigned long);
struct seq_file;
extern void show_cache_info(struct seq_file *m);
......
......@@ -82,13 +82,9 @@ static inline void flush_dcache_page(struct page *page)
#define flush_icache_range(s,e) do { flush_kernel_dcache_range_asm(s,e); flush_kernel_icache_range_asm(s,e); } while (0)
#define flush_icache_user_range(vma, page, addr, len) do { \
flush_user_dcache_range(addr, addr + len); \
flush_user_icache_range(addr, addr + len); } while (0)
#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
do { memcpy(dst, src, len); \
flush_icache_user_range(vma, page, vaddr, len); \
flush_kernel_dcache_range_asm((unsigned long)dst, (unsigned long)dst + len); \
} while (0)
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
memcpy(dst, src, len)
......@@ -112,27 +108,85 @@ static inline void flush_cache_range(struct vm_area_struct *vma,
}
}
static inline void
flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr)
/* Simple function to work out if we have an existing address translation
* for a user space vma. */
static inline int translation_exists(struct vm_area_struct *vma,
unsigned long addr)
{
int sr3;
pgd_t *pgd = pgd_offset(vma->vm_mm, addr);
pmd_t *pmd;
pte_t *pte;
if (!vma->vm_mm->context) {
BUG();
return;
}
if(pgd_none(*pgd))
return 0;
sr3 = mfsp(3);
if (vma->vm_mm->context == sr3) {
flush_user_dcache_range(vmaddr,vmaddr + PAGE_SIZE);
pmd = pmd_offset(pgd, addr);
if(pmd_none(*pmd) || pmd_bad(*pmd))
return 0;
pte = pte_offset_map(pmd, addr);
/* The PA flush mappings show up as pte_none, but they're
* valid none the less */
if(pte_none(*pte) && ((pte_val(*pte) & _PAGE_FLUSH) == 0))
return 0;
return 1;
}
/* Private function to flush a page from the cache of a non-current
* process. cr25 contains the Page Directory of the current user
* process; we're going to hijack both it and the user space %sr3 to
* temporarily make the non-current process current. We have to do
* this because cache flushing may cause a non-access tlb miss which
* the handlers have to fill in from the pgd of the non-current
* process. */
static inline void
flush_user_cache_page_non_current(struct vm_area_struct *vma,
unsigned long vmaddr)
{
/* save the current process space and pgd */
unsigned long space = mfsp(3), pgd = mfctl(25);
/* we don't mind taking interrups since they may not
* do anything with user space, but we can't
* be preempted here */
preempt_disable();
/* make us current */
mtctl(__pa(vma->vm_mm->pgd), 25);
mtsp(vma->vm_mm->context, 3);
flush_user_dcache_page(vmaddr);
if(vma->vm_flags & VM_EXEC)
flush_user_icache_page(vmaddr);
/* put the old current process back */
mtsp(space, 3);
mtctl(pgd, 25);
preempt_enable();
}
static inline void
__flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr)
{
if (likely(vma->vm_mm->context == mfsp(3))) {
flush_user_dcache_page(vmaddr);
if (vma->vm_flags & VM_EXEC)
flush_user_icache_range(vmaddr,vmaddr + PAGE_SIZE);
flush_user_icache_page(vmaddr);
} else {
if (vma->vm_flags & VM_EXEC)
flush_cache_all();
else
flush_data_cache();
flush_user_cache_page_non_current(vma, vmaddr);
}
}
static inline void
flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr)
{
BUG_ON(!vma->vm_mm->context);
if(likely(translation_exists(vma, vmaddr)))
__flush_cache_page(vma, vmaddr);
}
#endif
......@@ -247,4 +247,7 @@ struct parisc_device;
void * sba_get_iommu(struct parisc_device *dev);
#endif
/* At the moment, we panic on error for IOMMU resource exaustion */
#define dma_mapping_error(x) 0
#endif
......@@ -2,18 +2,22 @@
#define _ASM_FIXMAP_H
/*
* Allocate a 8 Mb temporary mapping area for copy_user_page/clear_user_page.
* This area needs to be aligned on a 8 Mb boundary.
* This file defines the locations of the fixed mappings on parisc.
*
* FIXME:
* All of the values in this file are machine virtual addresses.
*
* For PA-RISC, this has no meaning. It is starting to be used on x86
* for vsyscalls. PA will probably do this using space registers.
*/
* All of the values in this file must be <4GB (because of assembly
* loading restrictions). If you place this region anywhere above
* __PAGE_OFFSET, you must adjust the memory map accordingly */
/* This TMPALIAS_MAP_START reserves some of the memory where the
* FIXMAP region is on x86. It's only real use is to constrain
* VMALLOC_END (see pktable.h) */
#define TMPALIAS_MAP_START (__PAGE_OFFSET - 0x01000000)
/* The alias region is used in kernel space to do copy/clear to or
* from areas congruently mapped with user space. It is 8MB large
* and must be 16MB aligned */
#define TMPALIAS_MAP_START ((__PAGE_OFFSET) - 16*1024*1024)
/* This is the kernel area for all maps (vmalloc, dma etc.) most
* usually, it extends up to TMPALIAS_MAP_START. Virtual addresses
* 0..GATEWAY_PAGE_SIZE are reserved for the gateway page */
#define KERNEL_MAP_START (GATEWAY_PAGE_SIZE)
#define KERNEL_MAP_END (TMPALIAS_MAP_START)
#endif
......@@ -36,7 +36,8 @@ enum cpu_type {
pcxu_ = 7, /* pa8200 (u+) pa 2.0 */
pcxw = 8, /* pa8500 pa 2.0 */
pcxw_ = 9, /* pa8600 (w+) pa 2.0 */
pcxw2 = 10 /* pa8700 pa 2.0 */
pcxw2 = 10, /* pa8700 pa 2.0 */
mako = 11 /* pa8800 pa 2.0 */
};
extern char *cpu_name_version[][2]; /* mapping from enum cpu_type to strings */
......
......@@ -10,6 +10,7 @@
#include <linux/config.h>
#ifndef __ASSEMBLY__
#include <asm/types.h>
#include <asm/cache.h>
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
......@@ -39,12 +40,26 @@ clear_user_page(void *page, unsigned long vaddr, struct page *pg)
/*
* These are used to make use of C type-checking..
*/
#ifdef __LP64__
typedef struct { unsigned long pte; } pte_t;
typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pgd; } pgd_t;
#else
typedef struct {
unsigned long pte;
unsigned long flags;
} pte_t;
#endif
/* NOTE: even on 64 bits, these entries are __u32 because we allocate
* the pmd and pgd in ZONE_DMA (i.e. under 4GB) */
typedef struct { __u32 pmd; } pmd_t;
typedef struct { __u32 pgd; } pgd_t;
typedef struct { unsigned long pgprot; } pgprot_t;
#define pte_val(x) ((x).pte)
#ifdef __LP64__
#define pte_flags(x) (*(__u32 *)&((x).pte))
#else
#define pte_flags(x) ((x).flags)
#endif
#define pmd_val(x) ((x).pmd)
#define pgd_val(x) ((x).pgd)
#define pgprot_val(x) ((x).pgprot)
......@@ -84,14 +99,43 @@ extern int npmem_ranges;
#endif /* !__ASSEMBLY__ */
/* WARNING: The definitions below must match exactly to sizeof(pte_t)
* etc
*/
#ifdef __LP64__
#define BITS_PER_PTE_ENTRY 3
#define BITS_PER_PMD_ENTRY 2
#define BITS_PER_PGD_ENTRY 2
#else
#define BITS_PER_PTE_ENTRY 3
#define BITS_PER_PMD_ENTRY 2
#define BITS_PER_PGD_ENTRY BITS_PER_PMD_ENTRY
#endif
#define PGD_ENTRY_SIZE (1UL << BITS_PER_PGD_ENTRY)
#define PMD_ENTRY_SIZE (1UL << BITS_PER_PMD_ENTRY)
#define PTE_ENTRY_SIZE (1UL << BITS_PER_PTE_ENTRY)
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
#define LINUX_GATEWAY_SPACE 0
/* This governs the relationship between virtual and physical addresses.
* If you alter it, make sure to take care of our various fixed mapping
* segments in fixmap.h */
#define __PAGE_OFFSET (0x10000000)
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
/* The size of the gateway page (we leave lots of room for expansion) */
#define GATEWAY_PAGE_SIZE 0x4000
/* The start of the actual kernel binary---used in vmlinux.lds.S
* Leave some space after __PAGE_OFFSET for detecting kernel null
* ptr derefs */
#define KERNEL_BINARY_TEXT_START (__PAGE_OFFSET + 0x100000)
/* These macros don't work for 64-bit C code -- don't allow in C at all */
#ifdef __ASSEMBLY__
# define PA(x) ((x)-__PAGE_OFFSET)
......
......@@ -953,6 +953,7 @@ int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
struct pdc_memory_table *tbl, unsigned long entries);
#endif
void set_firmware_width(void);
int pdc_do_firm_test_reset(unsigned long ftc_bitmap);
int pdc_do_reset(void);
int pdc_soft_power_info(unsigned long *power_reg);
......
......@@ -10,39 +10,75 @@
#include <asm/pgtable.h>
#include <asm/cache.h>
/* Allocate the top level pgd (page directory)
*
* Here (for 64 bit kernels) we implement a Hybrid L2/L3 scheme: we
* allocate the first pmd adjacent to the pgd. This means that we can
* subtract a constant offset to get to it. The pmd and pgd sizes are
* arranged so that a single pmd covers 4GB (giving a full LP64
* process access to 8TB) so our lookups are effectively L2 for the
* first 4GB of the kernel (i.e. for all ILP32 processes and all the
* kernel for machines with under 4GB of memory) */
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
if (likely(pgd != NULL))
clear_page(pgd);
return pgd;
pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL|GFP_DMA,
PGD_ALLOC_ORDER);
pgd_t *actual_pgd = pgd;
if (likely(pgd != NULL)) {
memset(pgd, 0, PAGE_SIZE<<PGD_ALLOC_ORDER);
#ifdef __LP64__
actual_pgd += PTRS_PER_PGD;
/* Populate first pmd with allocated memory. We mark it
* with _PAGE_GATEWAY as a signal to the system that this
* pmd entry may not be cleared. */
pgd_val(*actual_pgd) = (_PAGE_TABLE | _PAGE_GATEWAY) +
(__u32)__pa((unsigned long)pgd);
/* The first pmd entry also is marked with _PAGE_GATEWAY as
* a signal that this pmd may not be freed */
pgd_val(*pgd) = _PAGE_GATEWAY;
#endif
}
return actual_pgd;
}
static inline void pgd_free(pgd_t *pgd)
{
free_page((unsigned long)pgd);
#ifdef __LP64__
pgd -= PTRS_PER_PGD;
#endif
free_pages((unsigned long)pgd, PGD_ALLOC_ORDER);
}
#ifdef __LP64__
#if PT_NLEVELS == 3
/* Three Level Page Table Support for pmd's */
static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
{
pgd_val(*pgd) = _PAGE_TABLE + __pa((unsigned long)pmd);
pgd_val(*pgd) = _PAGE_TABLE + (__u32)__pa((unsigned long)pmd);
}
/* NOTE: pmd must be in ZONE_DMA (<4GB) so the pgd pointer can be
* housed in 32 bits */
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
{
pmd_t *pmd = (pmd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
pmd_t *pmd = (pmd_t *)__get_free_pages(GFP_KERNEL|__GFP_REPEAT|GFP_DMA,
PMD_ORDER);
if (pmd)
clear_page(pmd);
memset(pmd, 0, PAGE_SIZE<<PMD_ORDER);
return pmd;
}
static inline void pmd_free(pmd_t *pmd)
{
free_page((unsigned long)pmd);
#ifdef __LP64__
if(pmd_val(*pmd) & _PAGE_GATEWAY)
/* This is the permanent pmd attached to the pgd;
* cannot free it */
return;
#endif
free_pages((unsigned long)pmd, PMD_ORDER);
}
#else
......@@ -63,16 +99,26 @@ static inline void pmd_free(pmd_t *pmd)
static inline void
pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
{
pmd_val(*pmd) = _PAGE_TABLE + __pa((unsigned long)pte);
#ifdef __LP64__
/* preserve the gateway marker if this is the beginning of
* the permanent pmd */
if(pmd_val(*pmd) & _PAGE_GATEWAY)
pmd_val(*pmd) = (_PAGE_TABLE | _PAGE_GATEWAY)
+ (__u32)__pa((unsigned long)pte);
else
#endif
pmd_val(*pmd) = _PAGE_TABLE + (__u32)__pa((unsigned long)pte);
}
#define pmd_populate(mm, pmd, pte_page) \
pmd_populate_kernel(mm, pmd, page_address(pte_page))
/* NOTE: pte must be in ZONE_DMA (<4GB) so that the pmd pointer
* can be housed in 32 bits */
static inline struct page *
pte_alloc_one(struct mm_struct *mm, unsigned long address)
{
struct page *page = alloc_page(GFP_KERNEL|__GFP_REPEAT);
struct page *page = alloc_page(GFP_KERNEL|__GFP_REPEAT|GFP_DMA);
if (likely(page != NULL))
clear_page(page_address(page));
return page;
......@@ -81,7 +127,7 @@ pte_alloc_one(struct mm_struct *mm, unsigned long address)
static inline pte_t *
pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
{
pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|GFP_DMA);
if (likely(pte != NULL))
clear_page(pte);
return pte;
......
......@@ -43,9 +43,9 @@
#define pte_ERROR(e) \
printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
#define pmd_ERROR(e) \
printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, (unsigned long)pmd_val(e))
#define pgd_ERROR(e) \
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
/* Note: If you change ISTACK_SIZE, you need to change the corresponding
* values in vmlinux.lds and vmlinux64.lds (init_istack section). Also,
......@@ -55,49 +55,59 @@
#define ISTACK_SIZE 32768 /* Interrupt Stack Size */
#define ISTACK_ORDER 3
/*
* NOTE: Many of the below macros use PT_NLEVELS because
* it is convenient that PT_NLEVELS == LOG2(pte size in bytes),
* i.e. we use 3 level page tables when we use 8 byte pte's
* (for 64 bit) and 2 level page tables when we use 4 byte pte's
*/
/* This is the size of the initially mapped kernel memory (i.e. currently
* 0 to 1<<23 == 8MB */
#define KERNEL_INITIAL_ORDER 23
#define KERNEL_INITIAL_SIZE (1 << KERNEL_INITIAL_ORDER)
#ifdef __LP64__
#define PT_NLEVELS 3
#define PT_INITIAL 4 /* Number of initial page tables */
#define PGD_ORDER 1 /* Number of pages per pgd */
#define PMD_ORDER 1 /* Number of pages per pmd */
#define PGD_ALLOC_ORDER 2 /* first pgd contains pmd */
#else
#define PT_NLEVELS 2
#define PT_INITIAL 2 /* Number of initial page tables */
#define PGD_ORDER 1 /* Number of pages per pgd */
#define PGD_ALLOC_ORDER PGD_ORDER
#endif
#define MAX_ADDRBITS (PAGE_SHIFT + (PT_NLEVELS)*(PAGE_SHIFT - PT_NLEVELS))
#define MAX_ADDRESS (1UL << MAX_ADDRBITS)
#define SPACEID_SHIFT (MAX_ADDRBITS - 32)
/* Definitions for 1st level */
#define PGDIR_SHIFT (PAGE_SHIFT + (PT_NLEVELS - 1)*(PAGE_SHIFT - PT_NLEVELS))
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
#define PTRS_PER_PGD (1UL << (PAGE_SHIFT - PT_NLEVELS))
#define USER_PTRS_PER_PGD PTRS_PER_PGD
/* Definitions for 3rd level (we use PLD here for Page Lower directory
* because PTE_SHIFT is used lower down to mean shift that has to be
* done to get usable bits out of the PTE) */
#define PLD_SHIFT PAGE_SHIFT
#define PLD_SIZE PAGE_SIZE
#define BITS_PER_PTE (PAGE_SHIFT - BITS_PER_PTE_ENTRY)
#define PTRS_PER_PTE (1UL << BITS_PER_PTE)
/* Definitions for 2nd level */
#define pgtable_cache_init() do { } while (0)
#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT - PT_NLEVELS))
#define PMD_SHIFT (PLD_SHIFT + BITS_PER_PTE)
#define PMD_SIZE (1UL << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
#if PT_NLEVELS == 3
#define PTRS_PER_PMD (1UL << (PAGE_SHIFT - PT_NLEVELS))
#define BITS_PER_PMD (PAGE_SHIFT + PMD_ORDER - BITS_PER_PMD_ENTRY)
#else
#define PTRS_PER_PMD 1
#define BITS_PER_PMD 0
#endif
#define PTRS_PER_PMD (1UL << BITS_PER_PMD)
/* Definitions for 3rd level */
/* Definitions for 1st level */
#define PGDIR_SHIFT (PMD_SHIFT + BITS_PER_PMD)
#define BITS_PER_PGD (PAGE_SHIFT + PGD_ORDER - BITS_PER_PGD_ENTRY)
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
#define PTRS_PER_PGD (1UL << BITS_PER_PGD)
#define USER_PTRS_PER_PGD PTRS_PER_PGD
#define MAX_ADDRBITS (PGDIR_SHIFT + BITS_PER_PGD)
#define MAX_ADDRESS (1UL << MAX_ADDRBITS)
#define PTRS_PER_PTE (1UL << (PAGE_SHIFT - PT_NLEVELS))
#define SPACEID_SHIFT (MAX_ADDRBITS - 32)
/* This calculates the number of initial pages we need for the initial
* page tables */
#define PT_INITIAL (1 << (KERNEL_INITIAL_ORDER - PMD_SHIFT))
/*
* pgd entries used up by user/kernel:
......@@ -110,7 +120,7 @@ extern void *vmalloc_start;
#define PCXL_DMA_MAP_SIZE (8*1024*1024)
#define VMALLOC_START ((unsigned long)vmalloc_start)
/* this is a fixmap remnant, see fixmap.h */
#define VMALLOC_END (TMPALIAS_MAP_START)
#define VMALLOC_END (KERNEL_MAP_END)
#endif
/* NB: The tlb miss handlers make certain assumptions about the order */
......@@ -217,7 +227,7 @@ extern pgd_t swapper_pg_dir[]; /* declared in init_task.c */
/* initial page tables for 0-8MB for kernel */
extern unsigned long pg0[];
extern pte_t pg0[];
/* zero page used for uninitialized stuff */
......@@ -234,22 +244,50 @@ extern unsigned long *empty_zero_page;
#define pte_present(x) (pte_val(x) & _PAGE_PRESENT)
#define pte_clear(xp) do { pte_val(*(xp)) = 0; } while (0)
#ifdef __LP64__
/* The first entry of the permanent pmd is not there if it contains
* the gateway marker */
#define pmd_none(x) (!pmd_val(x) || pmd_val(x) == _PAGE_GATEWAY)
#define pmd_bad(x) ((pmd_val(x) & ~PAGE_MASK) != _PAGE_TABLE && (pmd_val(x) & ~PAGE_MASK) != (_PAGE_TABLE | _PAGE_GATEWAY))
#else
#define pmd_none(x) (!pmd_val(x))
#define pmd_bad(x) ((pmd_val(x) & ~PAGE_MASK) != _PAGE_TABLE)
#endif
#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
#define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0)
static inline void pmd_clear(pmd_t *pmd) {
#ifdef __LP64__
if(pmd_val(*pmd) & _PAGE_GATEWAY)
/* This is the entry pointing to the permanent pmd
* attached to the pgd; cannot clear it */
pmd_val(*pmd) = _PAGE_GATEWAY;
else
#endif
pmd_val(*pmd) = 0;
}
#ifdef __LP64__
#if PT_NLEVELS == 3
#define pgd_page(pgd) ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
/* For 64 bit we have three level tables */
#define pgd_none(x) (!pgd_val(x))
#ifdef __LP64__
#define pgd_bad(x) ((pgd_val(x) & ~PAGE_MASK) != _PAGE_TABLE && (pgd_val(x) & ~PAGE_MASK) != (_PAGE_TABLE | _PAGE_GATEWAY))
#else
#define pgd_bad(x) ((pgd_val(x) & ~PAGE_MASK) != _PAGE_TABLE)
#endif
#define pgd_present(x) (pgd_val(x) & _PAGE_PRESENT)
#define pgd_clear(xp) do { pgd_val(*(xp)) = 0; } while (0)
static inline void pgd_clear(pgd_t *pgd) {
#ifdef __LP64__
if(pgd_val(*pgd) & _PAGE_GATEWAY)
/* This is the permanent pmd attached to the pgd; cannot
* free it */
return;
#endif
pgd_val(*pgd) = 0;
}
#else
/*
* The "pgd_xxx()" functions here are trivial for a folded two-level
......@@ -337,7 +375,7 @@ extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
/* Find an entry in the second-level page table.. */
#ifdef __LP64__
#if PT_NLEVELS == 3
#define pmd_offset(dir,address) \
((pmd_t *) pgd_page(*(dir)) + (((address)>>PMD_SHIFT) & (PTRS_PER_PMD-1)))
#else
......
......@@ -52,11 +52,11 @@
#ifndef __ASSEMBLY__
/*
** Data detected about CPUs at boot time which is the same for all CPU's.
** HP boxes are SMP - ie identical processors.
**
** FIXME: some CPU rev info may be processor specific...
*/
* Data detected about CPUs at boot time which is the same for all CPU's.
* HP boxes are SMP - ie identical processors.
*
* FIXME: some CPU rev info may be processor specific...
*/
struct system_cpuinfo_parisc {
unsigned int cpu_count;
unsigned int cpu_hz;
......@@ -77,9 +77,7 @@ struct system_cpuinfo_parisc {
};
/*
** Per CPU data structure - ie varies per CPU.
*/
/* Per CPU data structure - ie varies per CPU. */
struct cpuinfo_parisc {
unsigned long it_value; /* Interval Timer at last timer Intr */
unsigned long it_delta; /* Interval delta (tic_10ms / HZ * 100) */
......@@ -116,6 +114,8 @@ typedef struct {
int seg;
} mm_segment_t;
#define ARCH_MIN_TASKALIGN 8
struct thread_struct {
struct pt_regs regs;
unsigned long task_size;
......@@ -309,22 +309,31 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm);
static inline unsigned long get_wchan(struct task_struct *p)
{
return 0xdeadbeef; /* XXX */
}
extern unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) ((tsk)->thread.regs.iaoq[0])
#define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30])
#ifdef CONFIG_PA20
/*
* PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
* In addition, many implementations do hardware prefetching of both
* instructions and data.
*
* PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
* to gr0 but not in a way that Linux can use. If the load would cause an
* interruption (eg due to prefetching 0), it is suppressed on PA2.0
* processors, but not on 7300LC.
*/
#ifdef CONFIG_PREFETCH
#define ARCH_HAS_PREFETCH
#define ARCH_HAS_PREFETCHW
extern inline void prefetch(const void *addr)
{
__asm__("ldw 0(%0), %%r0" : : "r" (addr));
}
#define ARCH_HAS_PREFETCHW
extern inline void prefetchw(const void *addr)
{
__asm__("ldd 0(%0), %%r0" : : "r" (addr));
......
......@@ -54,8 +54,6 @@ extern unsigned long cpu_present_mask;
#define smp_processor_id() (current_thread_info()->cpu)
#define cpu_online(cpu) cpu_isset(cpu, cpu_online_map)
#define cpu_possible_map cpu_present_map
#endif /* CONFIG_SMP */
#define NO_PROC_ID 0xFF /* No processor magic marker */
......
......@@ -4,35 +4,42 @@
#include <asm/system.h>
/* Note that PA-RISC has to use `1' to mean unlocked and `0' to mean locked
* since it only has load-and-zero.
* since it only has load-and-zero. Moreover, at least on some PA processors,
* the semaphore address has to be 16-byte aligned.
*/
#undef SPIN_LOCK_UNLOCKED
#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
#define SPIN_LOCK_UNLOCKED (spinlock_t) { { 1, 1, 1, 1 } }
#define spin_lock_init(x) do { (x)->lock = 1; } while(0)
#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
#define spin_is_locked(x) ((x)->lock == 0)
static inline int spin_is_locked(spinlock_t *x)
{
volatile unsigned int *a = __ldcw_align(x);
return *a == 0;
}
#define spin_unlock_wait(x) do { barrier(); } while(((volatile spinlock_t *)(x))->lock == 0)
#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
#if 1
#define _raw_spin_lock(x) do { \
while (__ldcw (&(x)->lock) == 0) \
while (((x)->lock) == 0) ; } while (0)
#else
#define _raw_spin_lock(x) \
do { while(__ldcw(&(x)->lock) == 0); } while(0)
#endif
#define _raw_spin_unlock(x) \
do { (x)->lock = 1; } while(0)
#define _raw_spin_trylock(x) (__ldcw(&(x)->lock) != 0)
static inline void _raw_spin_lock(spinlock_t *x)
{
volatile unsigned int *a = __ldcw_align(x);
while (__ldcw(a) == 0)
while (*a == 0);
}
static inline void _raw_spin_unlock(spinlock_t *x)
{
volatile unsigned int *a = __ldcw_align(x);
*a = 1;
}
static inline int _raw_spin_trylock(spinlock_t *x)
{
volatile unsigned int *a = __ldcw_align(x);
return __ldcw(a) != 0;
}
/*
* Read-write spinlocks, allowing multiple readers
......@@ -43,7 +50,7 @@ typedef struct {
volatile int counter;
} rwlock_t;
#define RW_LOCK_UNLOCKED (rwlock_t) { {1}, 0 }
#define RW_LOCK_UNLOCKED (rwlock_t) { { { 1, 1, 1, 1 } }, 0 }
#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while (0)
......
......@@ -145,6 +145,19 @@ static inline void set_eiem(unsigned long val)
__ret; \
})
/* Because kmalloc only guarantees 8-byte alignment for kmalloc'd data,
and GCC only guarantees 8-byte alignment for stack locals, we can't
be assured of 16-byte alignment for atomic lock data even if we
specify "__attribute ((aligned(16)))" in the type declaration. So,
we use a struct containing an array of four ints for the atomic lock
type and dynamically select the 16-byte aligned int from the array
for the semaphore. */
#define __PA_LDCW_ALIGNMENT 16
#define __ldcw_align(a) ({ \
unsigned long __ret = (unsigned long) a; \
__ret = (__ret + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); \
(volatile unsigned int *) __ret; \
})
#ifdef CONFIG_SMP
/*
......@@ -152,8 +165,13 @@ static inline void set_eiem(unsigned long val)
*/
typedef struct {
volatile unsigned int __attribute__((aligned(16))) lock;
volatile unsigned int lock[4];
} spinlock_t;
#define __lock_aligned __attribute__((__section__(".data.lock_aligned")))
#endif
#define KERNEL_START (0x10100000 - 0x1000)
#endif
......@@ -721,74 +721,126 @@
#define __NR_epoll_wait (__NR_Linux + 226)
#define __NR_remap_file_pages (__NR_Linux + 227)
#define __NR_semtimedop (__NR_Linux + 228)
#define __NR_mq_open (__NR_Linux + 229) /* Keep the mq_* syscalls together */
#define __NR_mq_unlink (__NR_Linux + 230)
#define __NR_mq_timedsend (__NR_Linux + 231)
#define __NR_mq_timedreceive (__NR_Linux + 232)
#define __NR_mq_notify (__NR_Linux + 233)
#define __NR_mq_getsetattr (__NR_Linux + 234)
#define __NR_Linux_syscalls 228
#define __NR_Linux_syscalls 235
#define HPUX_GATEWAY_ADDR 0xC0000004
#define LINUX_GATEWAY_ADDR 0x100
#ifndef __ASSEMBLY__
/* The old syscall code here didn't work, and it looks like it's only used
* by applications such as fdisk which for some reason need to produce
* their own syscall instead of using same from libc. The code below
* is leveraged from glibc/sysdeps/unix/sysv/linux/hppa/sysdep.h where
* it is essentially duplicated -- which sucks. -PB
*/
#define SYS_ify(syscall_name) __NR_##syscall_name
/* The system call number MUST ALWAYS be loaded in the delay slot of
the ble instruction, or restarting system calls WILL NOT WORK. See
arch/parisc/kernel/signal.c - dhd, 2000-07-26 */
/* Assume all syscalls are done from PIC code just to be
* safe. The worst case scenario is that you lose a register
* and save/restore r19 across the syscall. */
#define PIC
#ifndef ASM_LINE_SEP
# define ASM_LINE_SEP ;
#endif
/* Definition taken from glibc 2.3.3
* sysdeps/unix/sysv/linux/hppa/sysdep.h
*/
#ifdef PIC
/* WARNING: CANNOT BE USED IN A NOP! */
# define K_STW_PIC stw %r19, -32(%sr0, %sp) ASM_LINE_SEP
# define K_LDW_PIC ldw -32(%sr0, %sp), %r19 ASM_LINE_SEP
# define K_STW_ASM_PIC " copy %%r19, %%r4\n"
# define K_LDW_ASM_PIC " copy %%r4, %%r19\n"
# define K_USING_GR4 "%r4",
#else
# define K_STW_PIC ASM_LINE_SEP
# define K_LDW_PIC ASM_LINE_SEP
# define K_STW_ASM_PIC " \n"
# define K_LDW_ASM_PIC " \n"
# define K_USING_GR4
#endif
/* GCC has to be warned that a syscall may clobber all the ABI
registers listed as "caller-saves", see page 8, Table 2
in section 2.2.6 of the PA-RISC RUN-TIME architecture
document. However! r28 is the result and will conflict with
the clobber list so it is left out. Also the input arguments
registers r20 -> r26 will conflict with the list so they
are treated specially. Although r19 is clobbered by the syscall
we cannot say this because it would violate ABI, thus we say
r4 is clobbered and use that register to save/restore r19
across the syscall. */
#define K_CALL_CLOB_REGS "%r1", "%r2", K_USING_GR4 \
"%r20", "%r29", "%r31"
#undef K_INLINE_SYSCALL
#define K_INLINE_SYSCALL(name, nr, args...) ({ \
unsigned long __sys_res; \
long __sys_res; \
{ \
register unsigned long __res asm("r28"); \
K_LOAD_ARGS_##nr(args) \
/* FIXME: HACK stw/ldw r19 around syscall */ \
asm volatile( \
"ble 0x100(%%sr2, %%r0)\n\t" \
" ldi %1, %%r20" \
K_STW_ASM_PIC \
" ble 0x100(%%sr2, %%r0)\n" \
" ldi %1, %%r20\n" \
K_LDW_ASM_PIC \
: "=r" (__res) \
: "i" (SYS_ify(name)) K_ASM_ARGS_##nr \
: K_CALL_CLOB_REGS K_CLOB_ARGS_##nr \
); \
__sys_res = __res; \
__sys_res = (long)__res; \
} \
if (__sys_res >= (unsigned long)-4095) { \
errno = -__sys_res; \
__sys_res = (unsigned long)-1; \
if ( (unsigned long)__sys_res >= (unsigned long)-4095 ){ \
errno = -__sys_res); \
__sys_res = -1; \
} \
__sys_res; \
})
#define K_LOAD_ARGS_0()
#define K_LOAD_ARGS_1(r26) \
register unsigned long __r26 __asm__("r26") = (unsigned long)r26; \
register unsigned long __r26 __asm__("r26") = (unsigned long)(r26); \
K_LOAD_ARGS_0()
#define K_LOAD_ARGS_2(r26,r25) \
register unsigned long __r25 __asm__("r25") = (unsigned long)r25; \
register unsigned long __r25 __asm__("r25") = (unsigned long)(r25); \
K_LOAD_ARGS_1(r26)
#define K_LOAD_ARGS_3(r26,r25,r24) \
register unsigned long __r24 __asm__("r24") = (unsigned long)r24; \
register unsigned long __r24 __asm__("r24") = (unsigned long)(r24); \
K_LOAD_ARGS_2(r26,r25)
#define K_LOAD_ARGS_4(r26,r25,r24,r23) \
register unsigned long __r23 __asm__("r23") = (unsigned long)r23; \
register unsigned long __r23 __asm__("r23") = (unsigned long)(r23); \
K_LOAD_ARGS_3(r26,r25,r24)
#define K_LOAD_ARGS_5(r26,r25,r24,r23,r22) \
register unsigned long __r22 __asm__("r22") = (unsigned long)r22; \
register unsigned long __r22 __asm__("r22") = (unsigned long)(r22); \
K_LOAD_ARGS_4(r26,r25,r24,r23)
#define K_LOAD_ARGS_6(r26,r25,r24,r23,r22,r21) \
register unsigned long __r21 __asm__("r21") = (unsigned long)r21; \
register unsigned long __r21 __asm__("r21") = (unsigned long)(r21); \
K_LOAD_ARGS_5(r26,r25,r24,r23,r22)
/* Even with zero args we use r20 for the syscall number */
#define K_ASM_ARGS_0
#define K_ASM_ARGS_1 , "r" (__r26)
#define K_ASM_ARGS_2 , "r" (__r26), "r" (__r25)
#define K_ASM_ARGS_3 , "r" (__r26), "r" (__r25), "r" (__r24)
#define K_ASM_ARGS_4 , "r" (__r26), "r" (__r25), "r" (__r24), "r" (__r23)
#define K_ASM_ARGS_5 , "r" (__r26), "r" (__r25), "r" (__r24), "r" (__r23), "r" (__r22)
#define K_ASM_ARGS_6 , "r" (__r26), "r" (__r25), "r" (__r24), "r" (__r23), "r" (__r22), "r" (__r21)
#define K_ASM_ARGS_1 K_ASM_ARGS_0, "r" (__r26)
#define K_ASM_ARGS_2 K_ASM_ARGS_1, "r" (__r25)
#define K_ASM_ARGS_3 K_ASM_ARGS_2, "r" (__r24)
#define K_ASM_ARGS_4 K_ASM_ARGS_3, "r" (__r23)
#define K_ASM_ARGS_5 K_ASM_ARGS_4, "r" (__r22)
#define K_ASM_ARGS_6 K_ASM_ARGS_5, "r" (__r21)
/* The registers not listed as inputs but clobbered */
#define K_CLOB_ARGS_6
#define K_CLOB_ARGS_5 K_CLOB_ARGS_6, "%r21"
#define K_CLOB_ARGS_4 K_CLOB_ARGS_5, "%r22"
#define K_CLOB_ARGS_3 K_CLOB_ARGS_4, "%r23"
#define K_CLOB_ARGS_2 K_CLOB_ARGS_3, "%r24"
#define K_CLOB_ARGS_1 K_CLOB_ARGS_2, "%r25"
#define K_CLOB_ARGS_0 K_CLOB_ARGS_1, "%r26"
#define _syscall0(type,name) \
type name(void) \
......@@ -829,14 +881,12 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
/* mmap & mmap2 take 6 arguments */
#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \
{ \
return K_INLINE_SYSCALL(name, 6, arg1, arg2, arg3, arg4, arg5, arg6); \
}
#ifdef __KERNEL_SYSCALLS__
#include <asm/current.h>
......
#ifndef _UNWIND_H_
#define _UNWIND_H_
/* From ABI specifications */
struct unwind_table_entry {
unsigned int region_start;
unsigned int region_end;
unsigned int Cannot_unwind:1; /* 0 */
unsigned int Millicode:1; /* 1 */
unsigned int Millicode_save_sr0:1; /* 2 */
unsigned int Region_description:2; /* 3..4 */
unsigned int reserved1:1; /* 5 */
unsigned int Entry_SR:1; /* 6 */
unsigned int Entry_FR:4; /* number saved *//* 7..10 */
unsigned int Entry_GR:5; /* number saved *//* 11..15 */
unsigned int Args_stored:1; /* 16 */
unsigned int Variable_Frame:1; /* 17 */
unsigned int Separate_Package_Body:1; /* 18 */
unsigned int Frame_Extension_Millicode:1; /* 19 */
unsigned int Stack_Overflow_Check:1; /* 20 */
unsigned int Two_Instruction_SP_Increment:1; /* 21 */
unsigned int Ada_Region:1; /* 22 */
unsigned int cxx_info:1; /* 23 */
unsigned int cxx_try_catch:1; /* 24 */
unsigned int sched_entry_seq:1; /* 25 */
unsigned int reserved2:1; /* 26 */
unsigned int Save_SP:1; /* 27 */
unsigned int Save_RP:1; /* 28 */
unsigned int Save_MRP_in_frame:1; /* 29 */
unsigned int extn_ptr_defined:1; /* 30 */
unsigned int Cleanup_defined:1; /* 31 */
unsigned int MPE_XL_interrupt_marker:1; /* 0 */
unsigned int HP_UX_interrupt_marker:1; /* 1 */
unsigned int Large_frame:1; /* 2 */
unsigned int Pseudo_SP_Set:1; /* 3 */
unsigned int reserved4:1; /* 4 */
unsigned int Total_frame_size:27; /* 5..31 */
};
struct unwind_table {
struct unwind_table *next;
const char *name;
unsigned long gp;
unsigned long base_addr;
unsigned long start;
unsigned long end;
const struct unwind_table_entry *table;
unsigned long length;
};
struct unwind_frame_info {
unsigned long sp;
unsigned long ip;
struct task_struct *t;
/* Eventually we would like to be able to get at any of the registers
available; but for now we only try to get the sp and ip for each
frame */
/* struct pt_regs regs; */
unsigned long prev_sp, prev_ip;
};
void * unwind_table_add(const char *name, unsigned long base_addr,
unsigned long gp,
const void *start, const void *end);
void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t,
struct pt_regs *regs);
void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t);
int unwind_once(struct unwind_frame_info *info);
int unwind_to_user(struct unwind_frame_info *info);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment