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);
/* 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);
/* All user shared mappings should be equivalently mapped,
* so once we've flushed one we should be ok
*/
/* 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);
......
This diff is collapsed.
......@@ -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
if((address & 0xff000000) == 0xf0000000)
return 0xf0f0f0f000000000 | (u32)address;
#ifdef __LP64__
if(unlikely(parisc_narrow_firmware)) {
if((address & 0xff000000) == 0xf0000000)
return 0xf0f0f0f000000000 | (u32)address;
if((address & 0xf0000000) == 0xf0000000)
return 0xffffffff00000000 | (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;
for(i = 31; i >= 0; --i)
addr[i] = p[i];
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 */
......@@ -574,6 +573,95 @@ flush_kernel_dcache_page:
.exit
.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
......
......@@ -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
printk(KERN_INFO "Kernel is using PDC in 32-bit mode.\n");
#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 */
cpumask_t cpu_online_map = CPU_MASK_NONE; /* Bitmap of online CPUs */
#define IS_LOGGED_IN(cpunum) (cpu_isset(cpunum, cpu_online_map))
static volatile int cpu_now_booting = 0; /* track which CPU is booting */
static int parisc_max_cpus = -1; /* Command line */
EXPORT_SYMBOL(cpu_online_map);
unsigned long cache_decay_ticks; /* declared by include/linux/sched.h */
cpumask_t cpu_online_map = CPU_MASK_NONE; /* Bitmap of online CPUs */
cpumask_t cpu_possible_map = CPU_MASK_NONE; /* Bitmap of Present CPUs */
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_online_map);
EXPORT_SYMBOL(cpu_possible_map);
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 */
#ifdef ENTRY_SYS_CPUS
cpu_data[0].state = STATE_RUNNING;
#endif
/* 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);
cpu_set(bootstrap_processor, cpu_online_map);
cpu_set(bootstrap_processor, cpu_possible_map);
/* 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);
/* Mark Boostrap processor as present */
current->active_mm = &init_mm;
/* We found more than one CPU.... */
if (boot_cpu_data.cpu_count > 1) {
cache_decay_ticks = HZ/100; /* FIXME very rough. */
}
for (i = 0; i < NR_CPUS; i++) {
if (cpu_data[i].cpuid == NO_PROC_ID ||
cpu_data[i].cpuid == bootstrap_processor)
continue;
if (smp_boot_one_cpu(cpu_data[i].cpuid, cpu_count) < 0)
continue;
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)])
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)
# define SPIN_UNLOCK(x) \
do { (x)->lock = 1; } while(0)
# 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;
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;
}
#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 PT_NLEVELS 3
#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 PT_NLEVELS 2
#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 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
/* Definitions for 3rd level */
#define MAX_ADDRBITS (PGDIR_SHIFT + BITS_PER_PGD)
#define MAX_ADDRESS (1UL << MAX_ADDRBITS)
#define SPACEID_SHIFT (MAX_ADDRBITS - 32)
#define PTRS_PER_PTE (1UL << (PAGE_SHIFT - PT_NLEVELS))
/* 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));
......
......@@ -52,9 +52,7 @@ extern void smp_send_reschedule(int cpu);
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
#define cpu_online(cpu) cpu_isset(cpu, cpu_online_map)
#endif /* CONFIG_SMP */
......
......@@ -4,36 +4,43 @@
#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
* but only one writer.
......@@ -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
This diff is collapsed.
#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