diff options
-rw-r--r-- | arch/s390/defconfig | 131 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/process.c | 18 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 65 | ||||
-rw-r--r-- | arch/s390/lib/uaccess_pt.c | 90 | ||||
-rw-r--r-- | arch/s390/mm/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/mm/init.c | 32 | ||||
-rw-r--r-- | arch/s390/mm/pgtable.c | 94 | ||||
-rw-r--r-- | arch/s390/mm/vmem.c | 53 | ||||
-rw-r--r-- | drivers/s390/char/raw3270.c | 26 | ||||
-rw-r--r-- | drivers/s390/char/tape_class.c | 19 | ||||
-rw-r--r-- | drivers/s390/char/tape_class.h | 4 | ||||
-rw-r--r-- | drivers/s390/char/vmlogrdr.c | 15 | ||||
-rw-r--r-- | drivers/s390/cio/chp.c | 12 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 9 | ||||
-rw-r--r-- | include/asm-s390/cpu.h | 25 | ||||
-rw-r--r-- | include/asm-s390/mmu_context.h | 50 | ||||
-rw-r--r-- | include/asm-s390/page.h | 4 | ||||
-rw-r--r-- | include/asm-s390/pgalloc.h | 250 | ||||
-rw-r--r-- | include/asm-s390/pgtable.h | 429 | ||||
-rw-r--r-- | include/asm-s390/processor.h | 20 | ||||
-rw-r--r-- | include/asm-s390/tlb.h | 129 | ||||
-rw-r--r-- | include/asm-s390/tlbflush.h | 152 |
23 files changed, 918 insertions, 713 deletions
diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 2aae23dba4bb..ece7b99da895 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Linux kernel version: 2.6.22 | 3 | # Linux kernel version: 2.6.23 |
4 | # Tue Jul 17 12:50:23 2007 | 4 | # Mon Oct 22 12:10:44 2007 |
5 | # | 5 | # |
6 | CONFIG_MMU=y | 6 | CONFIG_MMU=y |
7 | CONFIG_ZONE_DMA=y | 7 | CONFIG_ZONE_DMA=y |
@@ -19,15 +19,11 @@ CONFIG_S390=y | |||
19 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 19 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
20 | 20 | ||
21 | # | 21 | # |
22 | # Code maturity level options | 22 | # General setup |
23 | # | 23 | # |
24 | CONFIG_EXPERIMENTAL=y | 24 | CONFIG_EXPERIMENTAL=y |
25 | CONFIG_LOCK_KERNEL=y | 25 | CONFIG_LOCK_KERNEL=y |
26 | CONFIG_INIT_ENV_ARG_LIMIT=32 | 26 | CONFIG_INIT_ENV_ARG_LIMIT=32 |
27 | |||
28 | # | ||
29 | # General setup | ||
30 | # | ||
31 | CONFIG_LOCALVERSION="" | 27 | CONFIG_LOCALVERSION="" |
32 | CONFIG_LOCALVERSION_AUTO=y | 28 | CONFIG_LOCALVERSION_AUTO=y |
33 | CONFIG_SWAP=y | 29 | CONFIG_SWAP=y |
@@ -42,7 +38,14 @@ CONFIG_AUDIT=y | |||
42 | CONFIG_IKCONFIG=y | 38 | CONFIG_IKCONFIG=y |
43 | CONFIG_IKCONFIG_PROC=y | 39 | CONFIG_IKCONFIG_PROC=y |
44 | CONFIG_LOG_BUF_SHIFT=17 | 40 | CONFIG_LOG_BUF_SHIFT=17 |
41 | CONFIG_CGROUPS=y | ||
42 | # CONFIG_CGROUP_DEBUG is not set | ||
43 | CONFIG_CGROUP_NS=y | ||
44 | CONFIG_CGROUP_CPUACCT=y | ||
45 | # CONFIG_CPUSETS is not set | 45 | # CONFIG_CPUSETS is not set |
46 | CONFIG_FAIR_GROUP_SCHED=y | ||
47 | CONFIG_FAIR_USER_SCHED=y | ||
48 | # CONFIG_FAIR_CGROUP_SCHED is not set | ||
46 | CONFIG_SYSFS_DEPRECATED=y | 49 | CONFIG_SYSFS_DEPRECATED=y |
47 | # CONFIG_RELAY is not set | 50 | # CONFIG_RELAY is not set |
48 | CONFIG_BLK_DEV_INITRD=y | 51 | CONFIG_BLK_DEV_INITRD=y |
@@ -63,7 +66,6 @@ CONFIG_FUTEX=y | |||
63 | CONFIG_ANON_INODES=y | 66 | CONFIG_ANON_INODES=y |
64 | CONFIG_EPOLL=y | 67 | CONFIG_EPOLL=y |
65 | CONFIG_SIGNALFD=y | 68 | CONFIG_SIGNALFD=y |
66 | CONFIG_TIMERFD=y | ||
67 | CONFIG_EVENTFD=y | 69 | CONFIG_EVENTFD=y |
68 | CONFIG_SHMEM=y | 70 | CONFIG_SHMEM=y |
69 | CONFIG_VM_EVENT_COUNTERS=y | 71 | CONFIG_VM_EVENT_COUNTERS=y |
@@ -83,6 +85,7 @@ CONFIG_STOP_MACHINE=y | |||
83 | CONFIG_BLOCK=y | 85 | CONFIG_BLOCK=y |
84 | # CONFIG_BLK_DEV_IO_TRACE is not set | 86 | # CONFIG_BLK_DEV_IO_TRACE is not set |
85 | CONFIG_BLK_DEV_BSG=y | 87 | CONFIG_BLK_DEV_BSG=y |
88 | CONFIG_BLOCK_COMPAT=y | ||
86 | 89 | ||
87 | # | 90 | # |
88 | # IO Schedulers | 91 | # IO Schedulers |
@@ -108,7 +111,6 @@ CONFIG_64BIT=y | |||
108 | CONFIG_SMP=y | 111 | CONFIG_SMP=y |
109 | CONFIG_NR_CPUS=32 | 112 | CONFIG_NR_CPUS=32 |
110 | CONFIG_HOTPLUG_CPU=y | 113 | CONFIG_HOTPLUG_CPU=y |
111 | CONFIG_DEFAULT_MIGRATION_COST=1000000 | ||
112 | CONFIG_COMPAT=y | 114 | CONFIG_COMPAT=y |
113 | CONFIG_SYSVIPC_COMPAT=y | 115 | CONFIG_SYSVIPC_COMPAT=y |
114 | CONFIG_AUDIT_ARCH=y | 116 | CONFIG_AUDIT_ARCH=y |
@@ -143,9 +145,11 @@ CONFIG_FLATMEM_MANUAL=y | |||
143 | CONFIG_FLATMEM=y | 145 | CONFIG_FLATMEM=y |
144 | CONFIG_FLAT_NODE_MEM_MAP=y | 146 | CONFIG_FLAT_NODE_MEM_MAP=y |
145 | # CONFIG_SPARSEMEM_STATIC is not set | 147 | # CONFIG_SPARSEMEM_STATIC is not set |
148 | # CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set | ||
146 | CONFIG_SPLIT_PTLOCK_CPUS=4 | 149 | CONFIG_SPLIT_PTLOCK_CPUS=4 |
147 | CONFIG_RESOURCES_64BIT=y | 150 | CONFIG_RESOURCES_64BIT=y |
148 | CONFIG_ZONE_DMA_FLAG=1 | 151 | CONFIG_ZONE_DMA_FLAG=1 |
152 | CONFIG_BOUNCE=y | ||
149 | CONFIG_VIRT_TO_BUS=y | 153 | CONFIG_VIRT_TO_BUS=y |
150 | CONFIG_HOLES_IN_ZONE=y | 154 | CONFIG_HOLES_IN_ZONE=y |
151 | 155 | ||
@@ -219,12 +223,14 @@ CONFIG_INET_TUNNEL=y | |||
219 | CONFIG_INET_XFRM_MODE_TRANSPORT=y | 223 | CONFIG_INET_XFRM_MODE_TRANSPORT=y |
220 | CONFIG_INET_XFRM_MODE_TUNNEL=y | 224 | CONFIG_INET_XFRM_MODE_TUNNEL=y |
221 | CONFIG_INET_XFRM_MODE_BEET=y | 225 | CONFIG_INET_XFRM_MODE_BEET=y |
226 | CONFIG_INET_LRO=y | ||
222 | CONFIG_INET_DIAG=y | 227 | CONFIG_INET_DIAG=y |
223 | CONFIG_INET_TCP_DIAG=y | 228 | CONFIG_INET_TCP_DIAG=y |
224 | # CONFIG_TCP_CONG_ADVANCED is not set | 229 | # CONFIG_TCP_CONG_ADVANCED is not set |
225 | CONFIG_TCP_CONG_CUBIC=y | 230 | CONFIG_TCP_CONG_CUBIC=y |
226 | CONFIG_DEFAULT_TCP_CONG="cubic" | 231 | CONFIG_DEFAULT_TCP_CONG="cubic" |
227 | # CONFIG_TCP_MD5SIG is not set | 232 | # CONFIG_TCP_MD5SIG is not set |
233 | # CONFIG_IP_VS is not set | ||
228 | CONFIG_IPV6=y | 234 | CONFIG_IPV6=y |
229 | # CONFIG_IPV6_PRIVACY is not set | 235 | # CONFIG_IPV6_PRIVACY is not set |
230 | # CONFIG_IPV6_ROUTER_PREF is not set | 236 | # CONFIG_IPV6_ROUTER_PREF is not set |
@@ -243,7 +249,48 @@ CONFIG_IPV6_SIT=y | |||
243 | # CONFIG_IPV6_TUNNEL is not set | 249 | # CONFIG_IPV6_TUNNEL is not set |
244 | # CONFIG_IPV6_MULTIPLE_TABLES is not set | 250 | # CONFIG_IPV6_MULTIPLE_TABLES is not set |
245 | # CONFIG_NETWORK_SECMARK is not set | 251 | # CONFIG_NETWORK_SECMARK is not set |
246 | # CONFIG_NETFILTER is not set | 252 | CONFIG_NETFILTER=y |
253 | # CONFIG_NETFILTER_DEBUG is not set | ||
254 | |||
255 | # | ||
256 | # Core Netfilter Configuration | ||
257 | # | ||
258 | CONFIG_NETFILTER_NETLINK=m | ||
259 | CONFIG_NETFILTER_NETLINK_QUEUE=m | ||
260 | CONFIG_NETFILTER_NETLINK_LOG=m | ||
261 | CONFIG_NF_CONNTRACK_ENABLED=m | ||
262 | CONFIG_NF_CONNTRACK=m | ||
263 | # CONFIG_NF_CT_ACCT is not set | ||
264 | # CONFIG_NF_CONNTRACK_MARK is not set | ||
265 | # CONFIG_NF_CONNTRACK_EVENTS is not set | ||
266 | # CONFIG_NF_CT_PROTO_SCTP is not set | ||
267 | # CONFIG_NF_CT_PROTO_UDPLITE is not set | ||
268 | # CONFIG_NF_CONNTRACK_AMANDA is not set | ||
269 | # CONFIG_NF_CONNTRACK_FTP is not set | ||
270 | # CONFIG_NF_CONNTRACK_H323 is not set | ||
271 | # CONFIG_NF_CONNTRACK_IRC is not set | ||
272 | # CONFIG_NF_CONNTRACK_NETBIOS_NS is not set | ||
273 | # CONFIG_NF_CONNTRACK_PPTP is not set | ||
274 | # CONFIG_NF_CONNTRACK_SANE is not set | ||
275 | # CONFIG_NF_CONNTRACK_SIP is not set | ||
276 | # CONFIG_NF_CONNTRACK_TFTP is not set | ||
277 | # CONFIG_NF_CT_NETLINK is not set | ||
278 | # CONFIG_NETFILTER_XTABLES is not set | ||
279 | |||
280 | # | ||
281 | # IP: Netfilter Configuration | ||
282 | # | ||
283 | # CONFIG_NF_CONNTRACK_IPV4 is not set | ||
284 | # CONFIG_IP_NF_QUEUE is not set | ||
285 | # CONFIG_IP_NF_IPTABLES is not set | ||
286 | # CONFIG_IP_NF_ARPTABLES is not set | ||
287 | |||
288 | # | ||
289 | # IPv6: Netfilter Configuration (EXPERIMENTAL) | ||
290 | # | ||
291 | # CONFIG_NF_CONNTRACK_IPV6 is not set | ||
292 | # CONFIG_IP6_NF_QUEUE is not set | ||
293 | # CONFIG_IP6_NF_IPTABLES is not set | ||
247 | # CONFIG_IP_DCCP is not set | 294 | # CONFIG_IP_DCCP is not set |
248 | CONFIG_IP_SCTP=m | 295 | CONFIG_IP_SCTP=m |
249 | # CONFIG_SCTP_DBG_MSG is not set | 296 | # CONFIG_SCTP_DBG_MSG is not set |
@@ -263,12 +310,7 @@ CONFIG_SCTP_HMAC_MD5=y | |||
263 | # CONFIG_LAPB is not set | 310 | # CONFIG_LAPB is not set |
264 | # CONFIG_ECONET is not set | 311 | # CONFIG_ECONET is not set |
265 | # CONFIG_WAN_ROUTER is not set | 312 | # CONFIG_WAN_ROUTER is not set |
266 | |||
267 | # | ||
268 | # QoS and/or fair queueing | ||
269 | # | ||
270 | CONFIG_NET_SCHED=y | 313 | CONFIG_NET_SCHED=y |
271 | CONFIG_NET_SCH_FIFO=y | ||
272 | 314 | ||
273 | # | 315 | # |
274 | # Queueing/Scheduling | 316 | # Queueing/Scheduling |
@@ -306,10 +348,12 @@ CONFIG_NET_CLS_ACT=y | |||
306 | CONFIG_NET_ACT_POLICE=y | 348 | CONFIG_NET_ACT_POLICE=y |
307 | # CONFIG_NET_ACT_GACT is not set | 349 | # CONFIG_NET_ACT_GACT is not set |
308 | # CONFIG_NET_ACT_MIRRED is not set | 350 | # CONFIG_NET_ACT_MIRRED is not set |
351 | CONFIG_NET_ACT_NAT=m | ||
309 | # CONFIG_NET_ACT_PEDIT is not set | 352 | # CONFIG_NET_ACT_PEDIT is not set |
310 | # CONFIG_NET_ACT_SIMP is not set | 353 | # CONFIG_NET_ACT_SIMP is not set |
311 | CONFIG_NET_CLS_POLICE=y | 354 | CONFIG_NET_CLS_POLICE=y |
312 | # CONFIG_NET_CLS_IND is not set | 355 | # CONFIG_NET_CLS_IND is not set |
356 | CONFIG_NET_SCH_FIFO=y | ||
313 | 357 | ||
314 | # | 358 | # |
315 | # Network testing | 359 | # Network testing |
@@ -329,6 +373,7 @@ CONFIG_CCW=y | |||
329 | # | 373 | # |
330 | # Generic Driver Options | 374 | # Generic Driver Options |
331 | # | 375 | # |
376 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | ||
332 | CONFIG_STANDALONE=y | 377 | CONFIG_STANDALONE=y |
333 | CONFIG_PREVENT_FIRMWARE_BUILD=y | 378 | CONFIG_PREVENT_FIRMWARE_BUILD=y |
334 | # CONFIG_FW_LOADER is not set | 379 | # CONFIG_FW_LOADER is not set |
@@ -400,17 +445,11 @@ CONFIG_SCSI_FC_ATTRS=y | |||
400 | # CONFIG_SCSI_ISCSI_ATTRS is not set | 445 | # CONFIG_SCSI_ISCSI_ATTRS is not set |
401 | # CONFIG_SCSI_SAS_ATTRS is not set | 446 | # CONFIG_SCSI_SAS_ATTRS is not set |
402 | # CONFIG_SCSI_SAS_LIBSAS is not set | 447 | # CONFIG_SCSI_SAS_LIBSAS is not set |
403 | 448 | # CONFIG_SCSI_SRP_ATTRS is not set | |
404 | # | 449 | CONFIG_SCSI_LOWLEVEL=y |
405 | # SCSI low-level drivers | ||
406 | # | ||
407 | # CONFIG_ISCSI_TCP is not set | 450 | # CONFIG_ISCSI_TCP is not set |
408 | # CONFIG_SCSI_DEBUG is not set | 451 | # CONFIG_SCSI_DEBUG is not set |
409 | CONFIG_ZFCP=y | 452 | CONFIG_ZFCP=y |
410 | |||
411 | # | ||
412 | # Multi-device support (RAID and LVM) | ||
413 | # | ||
414 | CONFIG_MD=y | 453 | CONFIG_MD=y |
415 | CONFIG_BLK_DEV_MD=y | 454 | CONFIG_BLK_DEV_MD=y |
416 | CONFIG_MD_LINEAR=m | 455 | CONFIG_MD_LINEAR=m |
@@ -429,7 +468,9 @@ CONFIG_DM_ZERO=y | |||
429 | CONFIG_DM_MULTIPATH=y | 468 | CONFIG_DM_MULTIPATH=y |
430 | # CONFIG_DM_MULTIPATH_EMC is not set | 469 | # CONFIG_DM_MULTIPATH_EMC is not set |
431 | # CONFIG_DM_MULTIPATH_RDAC is not set | 470 | # CONFIG_DM_MULTIPATH_RDAC is not set |
471 | # CONFIG_DM_MULTIPATH_HP is not set | ||
432 | # CONFIG_DM_DELAY is not set | 472 | # CONFIG_DM_DELAY is not set |
473 | # CONFIG_DM_UEVENT is not set | ||
433 | CONFIG_NETDEVICES=y | 474 | CONFIG_NETDEVICES=y |
434 | # CONFIG_NETDEVICES_MULTIQUEUE is not set | 475 | # CONFIG_NETDEVICES_MULTIQUEUE is not set |
435 | # CONFIG_IFB is not set | 476 | # CONFIG_IFB is not set |
@@ -438,8 +479,13 @@ CONFIG_BONDING=m | |||
438 | # CONFIG_MACVLAN is not set | 479 | # CONFIG_MACVLAN is not set |
439 | CONFIG_EQUALIZER=m | 480 | CONFIG_EQUALIZER=m |
440 | CONFIG_TUN=m | 481 | CONFIG_TUN=m |
482 | CONFIG_VETH=m | ||
441 | CONFIG_NET_ETHERNET=y | 483 | CONFIG_NET_ETHERNET=y |
442 | # CONFIG_MII is not set | 484 | # CONFIG_MII is not set |
485 | # CONFIG_IBM_NEW_EMAC_ZMII is not set | ||
486 | # CONFIG_IBM_NEW_EMAC_RGMII is not set | ||
487 | # CONFIG_IBM_NEW_EMAC_TAH is not set | ||
488 | # CONFIG_IBM_NEW_EMAC_EMAC4 is not set | ||
443 | CONFIG_NETDEV_1000=y | 489 | CONFIG_NETDEV_1000=y |
444 | CONFIG_NETDEV_10000=y | 490 | CONFIG_NETDEV_10000=y |
445 | # CONFIG_TR is not set | 491 | # CONFIG_TR is not set |
@@ -473,7 +519,6 @@ CONFIG_CCWGROUP=y | |||
473 | CONFIG_UNIX98_PTYS=y | 519 | CONFIG_UNIX98_PTYS=y |
474 | CONFIG_LEGACY_PTYS=y | 520 | CONFIG_LEGACY_PTYS=y |
475 | CONFIG_LEGACY_PTY_COUNT=256 | 521 | CONFIG_LEGACY_PTY_COUNT=256 |
476 | # CONFIG_WATCHDOG is not set | ||
477 | CONFIG_HW_RANDOM=m | 522 | CONFIG_HW_RANDOM=m |
478 | # CONFIG_R3964 is not set | 523 | # CONFIG_R3964 is not set |
479 | CONFIG_RAW_DRIVER=m | 524 | CONFIG_RAW_DRIVER=m |
@@ -490,7 +535,6 @@ CONFIG_TN3270_CONSOLE=y | |||
490 | CONFIG_TN3215=y | 535 | CONFIG_TN3215=y |
491 | CONFIG_TN3215_CONSOLE=y | 536 | CONFIG_TN3215_CONSOLE=y |
492 | CONFIG_CCW_CONSOLE=y | 537 | CONFIG_CCW_CONSOLE=y |
493 | CONFIG_SCLP=y | ||
494 | CONFIG_SCLP_TTY=y | 538 | CONFIG_SCLP_TTY=y |
495 | CONFIG_SCLP_CONSOLE=y | 539 | CONFIG_SCLP_CONSOLE=y |
496 | CONFIG_SCLP_VT220_TTY=y | 540 | CONFIG_SCLP_VT220_TTY=y |
@@ -514,6 +558,11 @@ CONFIG_S390_TAPE_34XX=m | |||
514 | CONFIG_MONWRITER=m | 558 | CONFIG_MONWRITER=m |
515 | CONFIG_S390_VMUR=m | 559 | CONFIG_S390_VMUR=m |
516 | # CONFIG_POWER_SUPPLY is not set | 560 | # CONFIG_POWER_SUPPLY is not set |
561 | # CONFIG_WATCHDOG is not set | ||
562 | |||
563 | # | ||
564 | # Sonics Silicon Backplane | ||
565 | # | ||
517 | 566 | ||
518 | # | 567 | # |
519 | # File systems | 568 | # File systems |
@@ -569,7 +618,6 @@ CONFIG_SYSFS=y | |||
569 | CONFIG_TMPFS=y | 618 | CONFIG_TMPFS=y |
570 | CONFIG_TMPFS_POSIX_ACL=y | 619 | CONFIG_TMPFS_POSIX_ACL=y |
571 | # CONFIG_HUGETLB_PAGE is not set | 620 | # CONFIG_HUGETLB_PAGE is not set |
572 | CONFIG_RAMFS=y | ||
573 | CONFIG_CONFIGFS_FS=m | 621 | CONFIG_CONFIGFS_FS=m |
574 | 622 | ||
575 | # | 623 | # |
@@ -588,10 +636,7 @@ CONFIG_CONFIGFS_FS=m | |||
588 | # CONFIG_QNX4FS_FS is not set | 636 | # CONFIG_QNX4FS_FS is not set |
589 | # CONFIG_SYSV_FS is not set | 637 | # CONFIG_SYSV_FS is not set |
590 | # CONFIG_UFS_FS is not set | 638 | # CONFIG_UFS_FS is not set |
591 | 639 | CONFIG_NETWORK_FILESYSTEMS=y | |
592 | # | ||
593 | # Network File Systems | ||
594 | # | ||
595 | CONFIG_NFS_FS=y | 640 | CONFIG_NFS_FS=y |
596 | CONFIG_NFS_V3=y | 641 | CONFIG_NFS_V3=y |
597 | # CONFIG_NFS_V3_ACL is not set | 642 | # CONFIG_NFS_V3_ACL is not set |
@@ -638,27 +683,13 @@ CONFIG_MSDOS_PARTITION=y | |||
638 | # CONFIG_KARMA_PARTITION is not set | 683 | # CONFIG_KARMA_PARTITION is not set |
639 | # CONFIG_EFI_PARTITION is not set | 684 | # CONFIG_EFI_PARTITION is not set |
640 | # CONFIG_SYSV68_PARTITION is not set | 685 | # CONFIG_SYSV68_PARTITION is not set |
641 | |||
642 | # | ||
643 | # Native Language Support | ||
644 | # | ||
645 | # CONFIG_NLS is not set | 686 | # CONFIG_NLS is not set |
646 | |||
647 | # | ||
648 | # Distributed Lock Manager | ||
649 | # | ||
650 | CONFIG_DLM=m | 687 | CONFIG_DLM=m |
651 | # CONFIG_DLM_DEBUG is not set | 688 | # CONFIG_DLM_DEBUG is not set |
652 | 689 | CONFIG_INSTRUMENTATION=y | |
653 | # | ||
654 | # Instrumentation Support | ||
655 | # | ||
656 | |||
657 | # | ||
658 | # Profiling support | ||
659 | # | ||
660 | # CONFIG_PROFILING is not set | 690 | # CONFIG_PROFILING is not set |
661 | CONFIG_KPROBES=y | 691 | CONFIG_KPROBES=y |
692 | # CONFIG_MARKERS is not set | ||
662 | 693 | ||
663 | # | 694 | # |
664 | # Kernel hacking | 695 | # Kernel hacking |
@@ -682,6 +713,7 @@ CONFIG_DEBUG_SPINLOCK=y | |||
682 | CONFIG_DEBUG_MUTEXES=y | 713 | CONFIG_DEBUG_MUTEXES=y |
683 | # CONFIG_DEBUG_LOCK_ALLOC is not set | 714 | # CONFIG_DEBUG_LOCK_ALLOC is not set |
684 | # CONFIG_PROVE_LOCKING is not set | 715 | # CONFIG_PROVE_LOCKING is not set |
716 | # CONFIG_LOCK_STAT is not set | ||
685 | CONFIG_DEBUG_SPINLOCK_SLEEP=y | 717 | CONFIG_DEBUG_SPINLOCK_SLEEP=y |
686 | # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set | 718 | # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set |
687 | # CONFIG_DEBUG_KOBJECT is not set | 719 | # CONFIG_DEBUG_KOBJECT is not set |
@@ -694,14 +726,17 @@ CONFIG_FORCED_INLINING=y | |||
694 | # CONFIG_RCU_TORTURE_TEST is not set | 726 | # CONFIG_RCU_TORTURE_TEST is not set |
695 | # CONFIG_LKDTM is not set | 727 | # CONFIG_LKDTM is not set |
696 | # CONFIG_FAULT_INJECTION is not set | 728 | # CONFIG_FAULT_INJECTION is not set |
729 | CONFIG_SAMPLES=y | ||
697 | 730 | ||
698 | # | 731 | # |
699 | # Security options | 732 | # Security options |
700 | # | 733 | # |
701 | # CONFIG_KEYS is not set | 734 | # CONFIG_KEYS is not set |
702 | # CONFIG_SECURITY is not set | 735 | # CONFIG_SECURITY is not set |
736 | # CONFIG_SECURITY_FILE_CAPABILITIES is not set | ||
703 | CONFIG_CRYPTO=y | 737 | CONFIG_CRYPTO=y |
704 | CONFIG_CRYPTO_ALGAPI=y | 738 | CONFIG_CRYPTO_ALGAPI=y |
739 | CONFIG_CRYPTO_AEAD=m | ||
705 | CONFIG_CRYPTO_BLKCIPHER=y | 740 | CONFIG_CRYPTO_BLKCIPHER=y |
706 | CONFIG_CRYPTO_HASH=m | 741 | CONFIG_CRYPTO_HASH=m |
707 | CONFIG_CRYPTO_MANAGER=y | 742 | CONFIG_CRYPTO_MANAGER=y |
@@ -720,6 +755,7 @@ CONFIG_CRYPTO_ECB=m | |||
720 | CONFIG_CRYPTO_CBC=y | 755 | CONFIG_CRYPTO_CBC=y |
721 | CONFIG_CRYPTO_PCBC=m | 756 | CONFIG_CRYPTO_PCBC=m |
722 | # CONFIG_CRYPTO_LRW is not set | 757 | # CONFIG_CRYPTO_LRW is not set |
758 | # CONFIG_CRYPTO_XTS is not set | ||
723 | # CONFIG_CRYPTO_CRYPTD is not set | 759 | # CONFIG_CRYPTO_CRYPTD is not set |
724 | # CONFIG_CRYPTO_DES is not set | 760 | # CONFIG_CRYPTO_DES is not set |
725 | CONFIG_CRYPTO_FCRYPT=m | 761 | CONFIG_CRYPTO_FCRYPT=m |
@@ -733,11 +769,13 @@ CONFIG_CRYPTO_FCRYPT=m | |||
733 | # CONFIG_CRYPTO_ARC4 is not set | 769 | # CONFIG_CRYPTO_ARC4 is not set |
734 | # CONFIG_CRYPTO_KHAZAD is not set | 770 | # CONFIG_CRYPTO_KHAZAD is not set |
735 | # CONFIG_CRYPTO_ANUBIS is not set | 771 | # CONFIG_CRYPTO_ANUBIS is not set |
772 | CONFIG_CRYPTO_SEED=m | ||
736 | # CONFIG_CRYPTO_DEFLATE is not set | 773 | # CONFIG_CRYPTO_DEFLATE is not set |
737 | # CONFIG_CRYPTO_MICHAEL_MIC is not set | 774 | # CONFIG_CRYPTO_MICHAEL_MIC is not set |
738 | # CONFIG_CRYPTO_CRC32C is not set | 775 | # CONFIG_CRYPTO_CRC32C is not set |
739 | CONFIG_CRYPTO_CAMELLIA=m | 776 | CONFIG_CRYPTO_CAMELLIA=m |
740 | # CONFIG_CRYPTO_TEST is not set | 777 | # CONFIG_CRYPTO_TEST is not set |
778 | CONFIG_CRYPTO_AUTHENC=m | ||
741 | CONFIG_CRYPTO_HW=y | 779 | CONFIG_CRYPTO_HW=y |
742 | # CONFIG_CRYPTO_SHA1_S390 is not set | 780 | # CONFIG_CRYPTO_SHA1_S390 is not set |
743 | # CONFIG_CRYPTO_SHA256_S390 is not set | 781 | # CONFIG_CRYPTO_SHA256_S390 is not set |
@@ -755,5 +793,6 @@ CONFIG_BITREVERSE=m | |||
755 | # CONFIG_CRC16 is not set | 793 | # CONFIG_CRC16 is not set |
756 | # CONFIG_CRC_ITU_T is not set | 794 | # CONFIG_CRC_ITU_T is not set |
757 | CONFIG_CRC32=m | 795 | CONFIG_CRC32=m |
796 | CONFIG_CRC7=m | ||
758 | # CONFIG_LIBCRC32C is not set | 797 | # CONFIG_LIBCRC32C is not set |
759 | CONFIG_PLIST=y | 798 | CONFIG_PLIST=y |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 66b51901c87d..ce0856d32500 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -648,6 +648,8 @@ static int dump_set_type(enum dump_type type) | |||
648 | case DUMP_TYPE_CCW: | 648 | case DUMP_TYPE_CCW: |
649 | if (MACHINE_IS_VM) | 649 | if (MACHINE_IS_VM) |
650 | dump_method = DUMP_METHOD_CCW_VM; | 650 | dump_method = DUMP_METHOD_CCW_VM; |
651 | else if (diag308_set_works) | ||
652 | dump_method = DUMP_METHOD_CCW_DIAG; | ||
651 | else | 653 | else |
652 | dump_method = DUMP_METHOD_CCW_CIO; | 654 | dump_method = DUMP_METHOD_CCW_CIO; |
653 | break; | 655 | break; |
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 70c57378f426..96492cf2d491 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <asm/processor.h> | 44 | #include <asm/processor.h> |
45 | #include <asm/irq.h> | 45 | #include <asm/irq.h> |
46 | #include <asm/timer.h> | 46 | #include <asm/timer.h> |
47 | #include <asm/cpu.h> | ||
47 | 48 | ||
48 | asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); | 49 | asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); |
49 | 50 | ||
@@ -91,6 +92,14 @@ EXPORT_SYMBOL(unregister_idle_notifier); | |||
91 | 92 | ||
92 | void do_monitor_call(struct pt_regs *regs, long interruption_code) | 93 | void do_monitor_call(struct pt_regs *regs, long interruption_code) |
93 | { | 94 | { |
95 | struct s390_idle_data *idle; | ||
96 | |||
97 | idle = &__get_cpu_var(s390_idle); | ||
98 | spin_lock(&idle->lock); | ||
99 | idle->idle_time += get_clock() - idle->idle_enter; | ||
100 | idle->in_idle = 0; | ||
101 | spin_unlock(&idle->lock); | ||
102 | |||
94 | /* disable monitor call class 0 */ | 103 | /* disable monitor call class 0 */ |
95 | __ctl_clear_bit(8, 15); | 104 | __ctl_clear_bit(8, 15); |
96 | 105 | ||
@@ -105,6 +114,7 @@ extern void s390_handle_mcck(void); | |||
105 | static void default_idle(void) | 114 | static void default_idle(void) |
106 | { | 115 | { |
107 | int cpu, rc; | 116 | int cpu, rc; |
117 | struct s390_idle_data *idle; | ||
108 | 118 | ||
109 | /* CPU is going idle. */ | 119 | /* CPU is going idle. */ |
110 | cpu = smp_processor_id(); | 120 | cpu = smp_processor_id(); |
@@ -142,6 +152,12 @@ static void default_idle(void) | |||
142 | return; | 152 | return; |
143 | } | 153 | } |
144 | 154 | ||
155 | idle = &__get_cpu_var(s390_idle); | ||
156 | spin_lock(&idle->lock); | ||
157 | idle->idle_count++; | ||
158 | idle->in_idle = 1; | ||
159 | idle->idle_enter = get_clock(); | ||
160 | spin_unlock(&idle->lock); | ||
145 | trace_hardirqs_on(); | 161 | trace_hardirqs_on(); |
146 | /* Wait for external, I/O or machine check interrupt. */ | 162 | /* Wait for external, I/O or machine check interrupt. */ |
147 | __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | | 163 | __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | |
@@ -254,14 +270,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, | |||
254 | save_fp_regs(¤t->thread.fp_regs); | 270 | save_fp_regs(¤t->thread.fp_regs); |
255 | memcpy(&p->thread.fp_regs, ¤t->thread.fp_regs, | 271 | memcpy(&p->thread.fp_regs, ¤t->thread.fp_regs, |
256 | sizeof(s390_fp_regs)); | 272 | sizeof(s390_fp_regs)); |
257 | p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE; | ||
258 | /* Set a new TLS ? */ | 273 | /* Set a new TLS ? */ |
259 | if (clone_flags & CLONE_SETTLS) | 274 | if (clone_flags & CLONE_SETTLS) |
260 | p->thread.acrs[0] = regs->gprs[6]; | 275 | p->thread.acrs[0] = regs->gprs[6]; |
261 | #else /* CONFIG_64BIT */ | 276 | #else /* CONFIG_64BIT */ |
262 | /* Save the fpu registers to new thread structure. */ | 277 | /* Save the fpu registers to new thread structure. */ |
263 | save_fp_regs(&p->thread.fp_regs); | 278 | save_fp_regs(&p->thread.fp_regs); |
264 | p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE; | ||
265 | /* Set a new TLS ? */ | 279 | /* Set a new TLS ? */ |
266 | if (clone_flags & CLONE_SETTLS) { | 280 | if (clone_flags & CLONE_SETTLS) { |
267 | if (test_thread_flag(TIF_31BIT)) { | 281 | if (test_thread_flag(TIF_31BIT)) { |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 35edbef1d222..1d97fe1c0e53 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <asm/tlbflush.h> | 42 | #include <asm/tlbflush.h> |
43 | #include <asm/timer.h> | 43 | #include <asm/timer.h> |
44 | #include <asm/lowcore.h> | 44 | #include <asm/lowcore.h> |
45 | #include <asm/cpu.h> | ||
45 | 46 | ||
46 | /* | 47 | /* |
47 | * An array with a pointer the lowcore of every CPU. | 48 | * An array with a pointer the lowcore of every CPU. |
@@ -325,7 +326,7 @@ static void smp_ext_bitcall(int cpu, ec_bit_sig sig) | |||
325 | */ | 326 | */ |
326 | void smp_ptlb_callback(void *info) | 327 | void smp_ptlb_callback(void *info) |
327 | { | 328 | { |
328 | local_flush_tlb(); | 329 | __tlb_flush_local(); |
329 | } | 330 | } |
330 | 331 | ||
331 | void smp_ptlb_all(void) | 332 | void smp_ptlb_all(void) |
@@ -494,6 +495,8 @@ int __cpuinit start_secondary(void *cpuvoid) | |||
494 | return 0; | 495 | return 0; |
495 | } | 496 | } |
496 | 497 | ||
498 | DEFINE_PER_CPU(struct s390_idle_data, s390_idle); | ||
499 | |||
497 | static void __init smp_create_idle(unsigned int cpu) | 500 | static void __init smp_create_idle(unsigned int cpu) |
498 | { | 501 | { |
499 | struct task_struct *p; | 502 | struct task_struct *p; |
@@ -506,6 +509,7 @@ static void __init smp_create_idle(unsigned int cpu) | |||
506 | if (IS_ERR(p)) | 509 | if (IS_ERR(p)) |
507 | panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); | 510 | panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); |
508 | current_set[cpu] = p; | 511 | current_set[cpu] = p; |
512 | spin_lock_init(&(&per_cpu(s390_idle, cpu))->lock); | ||
509 | } | 513 | } |
510 | 514 | ||
511 | static int cpu_stopped(int cpu) | 515 | static int cpu_stopped(int cpu) |
@@ -724,6 +728,7 @@ void __init smp_prepare_boot_cpu(void) | |||
724 | cpu_set(0, cpu_online_map); | 728 | cpu_set(0, cpu_online_map); |
725 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; | 729 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; |
726 | current_set[0] = current; | 730 | current_set[0] = current; |
731 | spin_lock_init(&(&__get_cpu_var(s390_idle))->lock); | ||
727 | } | 732 | } |
728 | 733 | ||
729 | void __init smp_cpus_done(unsigned int max_cpus) | 734 | void __init smp_cpus_done(unsigned int max_cpus) |
@@ -756,22 +761,71 @@ static ssize_t show_capability(struct sys_device *dev, char *buf) | |||
756 | } | 761 | } |
757 | static SYSDEV_ATTR(capability, 0444, show_capability, NULL); | 762 | static SYSDEV_ATTR(capability, 0444, show_capability, NULL); |
758 | 763 | ||
764 | static ssize_t show_idle_count(struct sys_device *dev, char *buf) | ||
765 | { | ||
766 | struct s390_idle_data *idle; | ||
767 | unsigned long long idle_count; | ||
768 | |||
769 | idle = &per_cpu(s390_idle, dev->id); | ||
770 | spin_lock_irq(&idle->lock); | ||
771 | idle_count = idle->idle_count; | ||
772 | spin_unlock_irq(&idle->lock); | ||
773 | return sprintf(buf, "%llu\n", idle_count); | ||
774 | } | ||
775 | static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL); | ||
776 | |||
777 | static ssize_t show_idle_time(struct sys_device *dev, char *buf) | ||
778 | { | ||
779 | struct s390_idle_data *idle; | ||
780 | unsigned long long new_time; | ||
781 | |||
782 | idle = &per_cpu(s390_idle, dev->id); | ||
783 | spin_lock_irq(&idle->lock); | ||
784 | if (idle->in_idle) { | ||
785 | new_time = get_clock(); | ||
786 | idle->idle_time += new_time - idle->idle_enter; | ||
787 | idle->idle_enter = new_time; | ||
788 | } | ||
789 | new_time = idle->idle_time; | ||
790 | spin_unlock_irq(&idle->lock); | ||
791 | return sprintf(buf, "%llu us\n", new_time >> 12); | ||
792 | } | ||
793 | static SYSDEV_ATTR(idle_time, 0444, show_idle_time, NULL); | ||
794 | |||
795 | static struct attribute *cpu_attrs[] = { | ||
796 | &attr_capability.attr, | ||
797 | &attr_idle_count.attr, | ||
798 | &attr_idle_time.attr, | ||
799 | NULL, | ||
800 | }; | ||
801 | |||
802 | static struct attribute_group cpu_attr_group = { | ||
803 | .attrs = cpu_attrs, | ||
804 | }; | ||
805 | |||
759 | static int __cpuinit smp_cpu_notify(struct notifier_block *self, | 806 | static int __cpuinit smp_cpu_notify(struct notifier_block *self, |
760 | unsigned long action, void *hcpu) | 807 | unsigned long action, void *hcpu) |
761 | { | 808 | { |
762 | unsigned int cpu = (unsigned int)(long)hcpu; | 809 | unsigned int cpu = (unsigned int)(long)hcpu; |
763 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 810 | struct cpu *c = &per_cpu(cpu_devices, cpu); |
764 | struct sys_device *s = &c->sysdev; | 811 | struct sys_device *s = &c->sysdev; |
812 | struct s390_idle_data *idle; | ||
765 | 813 | ||
766 | switch (action) { | 814 | switch (action) { |
767 | case CPU_ONLINE: | 815 | case CPU_ONLINE: |
768 | case CPU_ONLINE_FROZEN: | 816 | case CPU_ONLINE_FROZEN: |
769 | if (sysdev_create_file(s, &attr_capability)) | 817 | idle = &per_cpu(s390_idle, cpu); |
818 | spin_lock_irq(&idle->lock); | ||
819 | idle->idle_enter = 0; | ||
820 | idle->idle_time = 0; | ||
821 | idle->idle_count = 0; | ||
822 | spin_unlock_irq(&idle->lock); | ||
823 | if (sysfs_create_group(&s->kobj, &cpu_attr_group)) | ||
770 | return NOTIFY_BAD; | 824 | return NOTIFY_BAD; |
771 | break; | 825 | break; |
772 | case CPU_DEAD: | 826 | case CPU_DEAD: |
773 | case CPU_DEAD_FROZEN: | 827 | case CPU_DEAD_FROZEN: |
774 | sysdev_remove_file(s, &attr_capability); | 828 | sysfs_remove_group(&s->kobj, &cpu_attr_group); |
775 | break; | 829 | break; |
776 | } | 830 | } |
777 | return NOTIFY_OK; | 831 | return NOTIFY_OK; |
@@ -784,6 +838,7 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = { | |||
784 | static int __init topology_init(void) | 838 | static int __init topology_init(void) |
785 | { | 839 | { |
786 | int cpu; | 840 | int cpu; |
841 | int rc; | ||
787 | 842 | ||
788 | register_cpu_notifier(&smp_cpu_nb); | 843 | register_cpu_notifier(&smp_cpu_nb); |
789 | 844 | ||
@@ -796,7 +851,9 @@ static int __init topology_init(void) | |||
796 | if (!cpu_online(cpu)) | 851 | if (!cpu_online(cpu)) |
797 | continue; | 852 | continue; |
798 | s = &c->sysdev; | 853 | s = &c->sysdev; |
799 | sysdev_create_file(s, &attr_capability); | 854 | rc = sysfs_create_group(&s->kobj, &cpu_attr_group); |
855 | if (rc) | ||
856 | return rc; | ||
800 | } | 857 | } |
801 | return 0; | 858 | return 0; |
802 | } | 859 | } |
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index b159a9d65680..7e8efaade2ea 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c | |||
@@ -15,6 +15,27 @@ | |||
15 | #include <asm/futex.h> | 15 | #include <asm/futex.h> |
16 | #include "uaccess.h" | 16 | #include "uaccess.h" |
17 | 17 | ||
18 | static inline pte_t *follow_table(struct mm_struct *mm, unsigned long addr) | ||
19 | { | ||
20 | pgd_t *pgd; | ||
21 | pud_t *pud; | ||
22 | pmd_t *pmd; | ||
23 | |||
24 | pgd = pgd_offset(mm, addr); | ||
25 | if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) | ||
26 | return NULL; | ||
27 | |||
28 | pud = pud_offset(pgd, addr); | ||
29 | if (pud_none(*pud) || unlikely(pud_bad(*pud))) | ||
30 | return NULL; | ||
31 | |||
32 | pmd = pmd_offset(pud, addr); | ||
33 | if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) | ||
34 | return NULL; | ||
35 | |||
36 | return pte_offset_map(pmd, addr); | ||
37 | } | ||
38 | |||
18 | static int __handle_fault(struct mm_struct *mm, unsigned long address, | 39 | static int __handle_fault(struct mm_struct *mm, unsigned long address, |
19 | int write_access) | 40 | int write_access) |
20 | { | 41 | { |
@@ -85,8 +106,6 @@ static size_t __user_copy_pt(unsigned long uaddr, void *kptr, | |||
85 | { | 106 | { |
86 | struct mm_struct *mm = current->mm; | 107 | struct mm_struct *mm = current->mm; |
87 | unsigned long offset, pfn, done, size; | 108 | unsigned long offset, pfn, done, size; |
88 | pgd_t *pgd; | ||
89 | pmd_t *pmd; | ||
90 | pte_t *pte; | 109 | pte_t *pte; |
91 | void *from, *to; | 110 | void *from, *to; |
92 | 111 | ||
@@ -94,15 +113,7 @@ static size_t __user_copy_pt(unsigned long uaddr, void *kptr, | |||
94 | retry: | 113 | retry: |
95 | spin_lock(&mm->page_table_lock); | 114 | spin_lock(&mm->page_table_lock); |
96 | do { | 115 | do { |
97 | pgd = pgd_offset(mm, uaddr); | 116 | pte = follow_table(mm, uaddr); |
98 | if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) | ||
99 | goto fault; | ||
100 | |||
101 | pmd = pmd_offset(pgd, uaddr); | ||
102 | if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) | ||
103 | goto fault; | ||
104 | |||
105 | pte = pte_offset_map(pmd, uaddr); | ||
106 | if (!pte || !pte_present(*pte) || | 117 | if (!pte || !pte_present(*pte) || |
107 | (write_user && !pte_write(*pte))) | 118 | (write_user && !pte_write(*pte))) |
108 | goto fault; | 119 | goto fault; |
@@ -142,22 +153,12 @@ static unsigned long __dat_user_addr(unsigned long uaddr) | |||
142 | { | 153 | { |
143 | struct mm_struct *mm = current->mm; | 154 | struct mm_struct *mm = current->mm; |
144 | unsigned long pfn, ret; | 155 | unsigned long pfn, ret; |
145 | pgd_t *pgd; | ||
146 | pmd_t *pmd; | ||
147 | pte_t *pte; | 156 | pte_t *pte; |
148 | int rc; | 157 | int rc; |
149 | 158 | ||
150 | ret = 0; | 159 | ret = 0; |
151 | retry: | 160 | retry: |
152 | pgd = pgd_offset(mm, uaddr); | 161 | pte = follow_table(mm, uaddr); |
153 | if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) | ||
154 | goto fault; | ||
155 | |||
156 | pmd = pmd_offset(pgd, uaddr); | ||
157 | if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) | ||
158 | goto fault; | ||
159 | |||
160 | pte = pte_offset_map(pmd, uaddr); | ||
161 | if (!pte || !pte_present(*pte)) | 162 | if (!pte || !pte_present(*pte)) |
162 | goto fault; | 163 | goto fault; |
163 | 164 | ||
@@ -229,8 +230,6 @@ static size_t strnlen_user_pt(size_t count, const char __user *src) | |||
229 | unsigned long uaddr = (unsigned long) src; | 230 | unsigned long uaddr = (unsigned long) src; |
230 | struct mm_struct *mm = current->mm; | 231 | struct mm_struct *mm = current->mm; |
231 | unsigned long offset, pfn, done, len; | 232 | unsigned long offset, pfn, done, len; |
232 | pgd_t *pgd; | ||
233 | pmd_t *pmd; | ||
234 | pte_t *pte; | 233 | pte_t *pte; |
235 | size_t len_str; | 234 | size_t len_str; |
236 | 235 | ||
@@ -240,15 +239,7 @@ static size_t strnlen_user_pt(size_t count, const char __user *src) | |||
240 | retry: | 239 | retry: |
241 | spin_lock(&mm->page_table_lock); | 240 | spin_lock(&mm->page_table_lock); |
242 | do { | 241 | do { |
243 | pgd = pgd_offset(mm, uaddr); | 242 | pte = follow_table(mm, uaddr); |
244 | if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) | ||
245 | goto fault; | ||
246 | |||
247 | pmd = pmd_offset(pgd, uaddr); | ||
248 | if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) | ||
249 | goto fault; | ||
250 | |||
251 | pte = pte_offset_map(pmd, uaddr); | ||
252 | if (!pte || !pte_present(*pte)) | 243 | if (!pte || !pte_present(*pte)) |
253 | goto fault; | 244 | goto fault; |
254 | 245 | ||
@@ -308,8 +299,6 @@ static size_t copy_in_user_pt(size_t n, void __user *to, | |||
308 | uaddr, done, size; | 299 | uaddr, done, size; |
309 | unsigned long uaddr_from = (unsigned long) from; | 300 | unsigned long uaddr_from = (unsigned long) from; |
310 | unsigned long uaddr_to = (unsigned long) to; | 301 | unsigned long uaddr_to = (unsigned long) to; |
311 | pgd_t *pgd_from, *pgd_to; | ||
312 | pmd_t *pmd_from, *pmd_to; | ||
313 | pte_t *pte_from, *pte_to; | 302 | pte_t *pte_from, *pte_to; |
314 | int write_user; | 303 | int write_user; |
315 | 304 | ||
@@ -317,39 +306,14 @@ static size_t copy_in_user_pt(size_t n, void __user *to, | |||
317 | retry: | 306 | retry: |
318 | spin_lock(&mm->page_table_lock); | 307 | spin_lock(&mm->page_table_lock); |
319 | do { | 308 | do { |
320 | pgd_from = pgd_offset(mm, uaddr_from); | 309 | pte_from = follow_table(mm, uaddr_from); |
321 | if (pgd_none(*pgd_from) || unlikely(pgd_bad(*pgd_from))) { | ||
322 | uaddr = uaddr_from; | ||
323 | write_user = 0; | ||
324 | goto fault; | ||
325 | } | ||
326 | pgd_to = pgd_offset(mm, uaddr_to); | ||
327 | if (pgd_none(*pgd_to) || unlikely(pgd_bad(*pgd_to))) { | ||
328 | uaddr = uaddr_to; | ||
329 | write_user = 1; | ||
330 | goto fault; | ||
331 | } | ||
332 | |||
333 | pmd_from = pmd_offset(pgd_from, uaddr_from); | ||
334 | if (pmd_none(*pmd_from) || unlikely(pmd_bad(*pmd_from))) { | ||
335 | uaddr = uaddr_from; | ||
336 | write_user = 0; | ||
337 | goto fault; | ||
338 | } | ||
339 | pmd_to = pmd_offset(pgd_to, uaddr_to); | ||
340 | if (pmd_none(*pmd_to) || unlikely(pmd_bad(*pmd_to))) { | ||
341 | uaddr = uaddr_to; | ||
342 | write_user = 1; | ||
343 | goto fault; | ||
344 | } | ||
345 | |||
346 | pte_from = pte_offset_map(pmd_from, uaddr_from); | ||
347 | if (!pte_from || !pte_present(*pte_from)) { | 310 | if (!pte_from || !pte_present(*pte_from)) { |
348 | uaddr = uaddr_from; | 311 | uaddr = uaddr_from; |
349 | write_user = 0; | 312 | write_user = 0; |
350 | goto fault; | 313 | goto fault; |
351 | } | 314 | } |
352 | pte_to = pte_offset_map(pmd_to, uaddr_to); | 315 | |
316 | pte_to = follow_table(mm, uaddr_to); | ||
353 | if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) { | 317 | if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) { |
354 | uaddr = uaddr_to; | 318 | uaddr = uaddr_to; |
355 | write_user = 1; | 319 | write_user = 1; |
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile index f95449b29fa5..66401930f83e 100644 --- a/arch/s390/mm/Makefile +++ b/arch/s390/mm/Makefile | |||
@@ -2,6 +2,6 @@ | |||
2 | # Makefile for the linux s390-specific parts of the memory manager. | 2 | # Makefile for the linux s390-specific parts of the memory manager. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y := init.o fault.o extmem.o mmap.o vmem.o | 5 | obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o |
6 | obj-$(CONFIG_CMM) += cmm.o | 6 | obj-$(CONFIG_CMM) += cmm.o |
7 | 7 | ||
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 3a25bbf2eb0a..b234bb4a6da7 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c | |||
@@ -81,6 +81,7 @@ void show_mem(void) | |||
81 | static void __init setup_ro_region(void) | 81 | static void __init setup_ro_region(void) |
82 | { | 82 | { |
83 | pgd_t *pgd; | 83 | pgd_t *pgd; |
84 | pud_t *pud; | ||
84 | pmd_t *pmd; | 85 | pmd_t *pmd; |
85 | pte_t *pte; | 86 | pte_t *pte; |
86 | pte_t new_pte; | 87 | pte_t new_pte; |
@@ -91,7 +92,8 @@ static void __init setup_ro_region(void) | |||
91 | 92 | ||
92 | for (; address < end; address += PAGE_SIZE) { | 93 | for (; address < end; address += PAGE_SIZE) { |
93 | pgd = pgd_offset_k(address); | 94 | pgd = pgd_offset_k(address); |
94 | pmd = pmd_offset(pgd, address); | 95 | pud = pud_offset(pgd, address); |
96 | pmd = pmd_offset(pud, address); | ||
95 | pte = pte_offset_kernel(pmd, address); | 97 | pte = pte_offset_kernel(pmd, address); |
96 | new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO)); | 98 | new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO)); |
97 | *pte = new_pte; | 99 | *pte = new_pte; |
@@ -103,32 +105,28 @@ static void __init setup_ro_region(void) | |||
103 | */ | 105 | */ |
104 | void __init paging_init(void) | 106 | void __init paging_init(void) |
105 | { | 107 | { |
106 | pgd_t *pg_dir; | ||
107 | int i; | ||
108 | unsigned long pgdir_k; | ||
109 | static const int ssm_mask = 0x04000000L; | 108 | static const int ssm_mask = 0x04000000L; |
110 | unsigned long max_zone_pfns[MAX_NR_ZONES]; | 109 | unsigned long max_zone_pfns[MAX_NR_ZONES]; |
110 | unsigned long pgd_type; | ||
111 | 111 | ||
112 | pg_dir = swapper_pg_dir; | 112 | init_mm.pgd = swapper_pg_dir; |
113 | 113 | S390_lowcore.kernel_asce = __pa(init_mm.pgd) & PAGE_MASK; | |
114 | #ifdef CONFIG_64BIT | 114 | #ifdef CONFIG_64BIT |
115 | pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE; | 115 | S390_lowcore.kernel_asce |= _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH; |
116 | for (i = 0; i < PTRS_PER_PGD; i++) | 116 | pgd_type = _REGION3_ENTRY_EMPTY; |
117 | pgd_clear_kernel(pg_dir + i); | ||
118 | #else | 117 | #else |
119 | pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE; | 118 | S390_lowcore.kernel_asce |= _ASCE_TABLE_LENGTH; |
120 | for (i = 0; i < PTRS_PER_PGD; i++) | 119 | pgd_type = _SEGMENT_ENTRY_EMPTY; |
121 | pmd_clear_kernel((pmd_t *)(pg_dir + i)); | ||
122 | #endif | 120 | #endif |
121 | clear_table((unsigned long *) init_mm.pgd, pgd_type, | ||
122 | sizeof(unsigned long)*2048); | ||
123 | vmem_map_init(); | 123 | vmem_map_init(); |
124 | setup_ro_region(); | 124 | setup_ro_region(); |
125 | 125 | ||
126 | S390_lowcore.kernel_asce = pgdir_k; | ||
127 | |||
128 | /* enable virtual mapping in kernel mode */ | 126 | /* enable virtual mapping in kernel mode */ |
129 | __ctl_load(pgdir_k, 1, 1); | 127 | __ctl_load(S390_lowcore.kernel_asce, 1, 1); |
130 | __ctl_load(pgdir_k, 7, 7); | 128 | __ctl_load(S390_lowcore.kernel_asce, 7, 7); |
131 | __ctl_load(pgdir_k, 13, 13); | 129 | __ctl_load(S390_lowcore.kernel_asce, 13, 13); |
132 | __raw_local_irq_ssm(ssm_mask); | 130 | __raw_local_irq_ssm(ssm_mask); |
133 | 131 | ||
134 | memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); | 132 | memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c new file mode 100644 index 000000000000..e60e0ae13402 --- /dev/null +++ b/arch/s390/mm/pgtable.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * arch/s390/mm/pgtable.c | ||
3 | * | ||
4 | * Copyright IBM Corp. 2007 | ||
5 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/sched.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <linux/swap.h> | ||
13 | #include <linux/smp.h> | ||
14 | #include <linux/highmem.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/pagemap.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/quicklist.h> | ||
20 | |||
21 | #include <asm/system.h> | ||
22 | #include <asm/pgtable.h> | ||
23 | #include <asm/pgalloc.h> | ||
24 | #include <asm/tlb.h> | ||
25 | #include <asm/tlbflush.h> | ||
26 | |||
27 | #ifndef CONFIG_64BIT | ||
28 | #define ALLOC_ORDER 1 | ||
29 | #else | ||
30 | #define ALLOC_ORDER 2 | ||
31 | #endif | ||
32 | |||
33 | unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec) | ||
34 | { | ||
35 | struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER); | ||
36 | |||
37 | if (!page) | ||
38 | return NULL; | ||
39 | page->index = 0; | ||
40 | if (noexec) { | ||
41 | struct page *shadow = alloc_pages(GFP_KERNEL, ALLOC_ORDER); | ||
42 | if (!shadow) { | ||
43 | __free_pages(page, ALLOC_ORDER); | ||
44 | return NULL; | ||
45 | } | ||
46 | page->index = page_to_phys(shadow); | ||
47 | } | ||
48 | return (unsigned long *) page_to_phys(page); | ||
49 | } | ||
50 | |||
51 | void crst_table_free(unsigned long *table) | ||
52 | { | ||
53 | unsigned long *shadow = get_shadow_table(table); | ||
54 | |||
55 | if (shadow) | ||
56 | free_pages((unsigned long) shadow, ALLOC_ORDER); | ||
57 | free_pages((unsigned long) table, ALLOC_ORDER); | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * page table entry allocation/free routines. | ||
62 | */ | ||
63 | unsigned long *page_table_alloc(int noexec) | ||
64 | { | ||
65 | struct page *page = alloc_page(GFP_KERNEL); | ||
66 | unsigned long *table; | ||
67 | |||
68 | if (!page) | ||
69 | return NULL; | ||
70 | page->index = 0; | ||
71 | if (noexec) { | ||
72 | struct page *shadow = alloc_page(GFP_KERNEL); | ||
73 | if (!shadow) { | ||
74 | __free_page(page); | ||
75 | return NULL; | ||
76 | } | ||
77 | table = (unsigned long *) page_to_phys(shadow); | ||
78 | clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE); | ||
79 | page->index = (addr_t) table; | ||
80 | } | ||
81 | table = (unsigned long *) page_to_phys(page); | ||
82 | clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE); | ||
83 | return table; | ||
84 | } | ||
85 | |||
86 | void page_table_free(unsigned long *table) | ||
87 | { | ||
88 | unsigned long *shadow = get_shadow_pte(table); | ||
89 | |||
90 | if (shadow) | ||
91 | free_page((unsigned long) shadow); | ||
92 | free_page((unsigned long) table); | ||
93 | |||
94 | } | ||
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index fd594d5fe142..fb9c5a85aa56 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c | |||
@@ -73,31 +73,28 @@ static void __init_refok *vmem_alloc_pages(unsigned int order) | |||
73 | return alloc_bootmem_pages((1 << order) * PAGE_SIZE); | 73 | return alloc_bootmem_pages((1 << order) * PAGE_SIZE); |
74 | } | 74 | } |
75 | 75 | ||
76 | #define vmem_pud_alloc() ({ BUG(); ((pud_t *) NULL); }) | ||
77 | |||
76 | static inline pmd_t *vmem_pmd_alloc(void) | 78 | static inline pmd_t *vmem_pmd_alloc(void) |
77 | { | 79 | { |
78 | pmd_t *pmd; | 80 | pmd_t *pmd = NULL; |
79 | int i; | ||
80 | 81 | ||
81 | pmd = vmem_alloc_pages(PMD_ALLOC_ORDER); | 82 | #ifdef CONFIG_64BIT |
83 | pmd = vmem_alloc_pages(2); | ||
82 | if (!pmd) | 84 | if (!pmd) |
83 | return NULL; | 85 | return NULL; |
84 | for (i = 0; i < PTRS_PER_PMD; i++) | 86 | clear_table((unsigned long *) pmd, _SEGMENT_ENTRY_EMPTY, PAGE_SIZE*4); |
85 | pmd_clear_kernel(pmd + i); | 87 | #endif |
86 | return pmd; | 88 | return pmd; |
87 | } | 89 | } |
88 | 90 | ||
89 | static inline pte_t *vmem_pte_alloc(void) | 91 | static inline pte_t *vmem_pte_alloc(void) |
90 | { | 92 | { |
91 | pte_t *pte; | 93 | pte_t *pte = vmem_alloc_pages(0); |
92 | pte_t empty_pte; | ||
93 | int i; | ||
94 | 94 | ||
95 | pte = vmem_alloc_pages(PTE_ALLOC_ORDER); | ||
96 | if (!pte) | 95 | if (!pte) |
97 | return NULL; | 96 | return NULL; |
98 | pte_val(empty_pte) = _PAGE_TYPE_EMPTY; | 97 | clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY, PAGE_SIZE); |
99 | for (i = 0; i < PTRS_PER_PTE; i++) | ||
100 | pte[i] = empty_pte; | ||
101 | return pte; | 98 | return pte; |
102 | } | 99 | } |
103 | 100 | ||
@@ -108,6 +105,7 @@ static int vmem_add_range(unsigned long start, unsigned long size) | |||
108 | { | 105 | { |
109 | unsigned long address; | 106 | unsigned long address; |
110 | pgd_t *pg_dir; | 107 | pgd_t *pg_dir; |
108 | pud_t *pu_dir; | ||
111 | pmd_t *pm_dir; | 109 | pmd_t *pm_dir; |
112 | pte_t *pt_dir; | 110 | pte_t *pt_dir; |
113 | pte_t pte; | 111 | pte_t pte; |
@@ -116,13 +114,21 @@ static int vmem_add_range(unsigned long start, unsigned long size) | |||
116 | for (address = start; address < start + size; address += PAGE_SIZE) { | 114 | for (address = start; address < start + size; address += PAGE_SIZE) { |
117 | pg_dir = pgd_offset_k(address); | 115 | pg_dir = pgd_offset_k(address); |
118 | if (pgd_none(*pg_dir)) { | 116 | if (pgd_none(*pg_dir)) { |
117 | pu_dir = vmem_pud_alloc(); | ||
118 | if (!pu_dir) | ||
119 | goto out; | ||
120 | pgd_populate_kernel(&init_mm, pg_dir, pu_dir); | ||
121 | } | ||
122 | |||
123 | pu_dir = pud_offset(pg_dir, address); | ||
124 | if (pud_none(*pu_dir)) { | ||
119 | pm_dir = vmem_pmd_alloc(); | 125 | pm_dir = vmem_pmd_alloc(); |
120 | if (!pm_dir) | 126 | if (!pm_dir) |
121 | goto out; | 127 | goto out; |
122 | pgd_populate_kernel(&init_mm, pg_dir, pm_dir); | 128 | pud_populate_kernel(&init_mm, pu_dir, pm_dir); |
123 | } | 129 | } |
124 | 130 | ||
125 | pm_dir = pmd_offset(pg_dir, address); | 131 | pm_dir = pmd_offset(pu_dir, address); |
126 | if (pmd_none(*pm_dir)) { | 132 | if (pmd_none(*pm_dir)) { |
127 | pt_dir = vmem_pte_alloc(); | 133 | pt_dir = vmem_pte_alloc(); |
128 | if (!pt_dir) | 134 | if (!pt_dir) |
@@ -148,6 +154,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size) | |||
148 | { | 154 | { |
149 | unsigned long address; | 155 | unsigned long address; |
150 | pgd_t *pg_dir; | 156 | pgd_t *pg_dir; |
157 | pud_t *pu_dir; | ||
151 | pmd_t *pm_dir; | 158 | pmd_t *pm_dir; |
152 | pte_t *pt_dir; | 159 | pte_t *pt_dir; |
153 | pte_t pte; | 160 | pte_t pte; |
@@ -155,9 +162,10 @@ static void vmem_remove_range(unsigned long start, unsigned long size) | |||
155 | pte_val(pte) = _PAGE_TYPE_EMPTY; | 162 | pte_val(pte) = _PAGE_TYPE_EMPTY; |
156 | for (address = start; address < start + size; address += PAGE_SIZE) { | 163 | for (address = start; address < start + size; address += PAGE_SIZE) { |
157 | pg_dir = pgd_offset_k(address); | 164 | pg_dir = pgd_offset_k(address); |
158 | if (pgd_none(*pg_dir)) | 165 | pu_dir = pud_offset(pg_dir, address); |
166 | if (pud_none(*pu_dir)) | ||
159 | continue; | 167 | continue; |
160 | pm_dir = pmd_offset(pg_dir, address); | 168 | pm_dir = pmd_offset(pu_dir, address); |
161 | if (pmd_none(*pm_dir)) | 169 | if (pmd_none(*pm_dir)) |
162 | continue; | 170 | continue; |
163 | pt_dir = pte_offset_kernel(pm_dir, address); | 171 | pt_dir = pte_offset_kernel(pm_dir, address); |
@@ -174,6 +182,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size) | |||
174 | unsigned long address, start_addr, end_addr; | 182 | unsigned long address, start_addr, end_addr; |
175 | struct page *map_start, *map_end; | 183 | struct page *map_start, *map_end; |
176 | pgd_t *pg_dir; | 184 | pgd_t *pg_dir; |
185 | pud_t *pu_dir; | ||
177 | pmd_t *pm_dir; | 186 | pmd_t *pm_dir; |
178 | pte_t *pt_dir; | 187 | pte_t *pt_dir; |
179 | pte_t pte; | 188 | pte_t pte; |
@@ -188,13 +197,21 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size) | |||
188 | for (address = start_addr; address < end_addr; address += PAGE_SIZE) { | 197 | for (address = start_addr; address < end_addr; address += PAGE_SIZE) { |
189 | pg_dir = pgd_offset_k(address); | 198 | pg_dir = pgd_offset_k(address); |
190 | if (pgd_none(*pg_dir)) { | 199 | if (pgd_none(*pg_dir)) { |
200 | pu_dir = vmem_pud_alloc(); | ||
201 | if (!pu_dir) | ||
202 | goto out; | ||
203 | pgd_populate_kernel(&init_mm, pg_dir, pu_dir); | ||
204 | } | ||
205 | |||
206 | pu_dir = pud_offset(pg_dir, address); | ||
207 | if (pud_none(*pu_dir)) { | ||
191 | pm_dir = vmem_pmd_alloc(); | 208 | pm_dir = vmem_pmd_alloc(); |
192 | if (!pm_dir) | 209 | if (!pm_dir) |
193 | goto out; | 210 | goto out; |
194 | pgd_populate_kernel(&init_mm, pg_dir, pm_dir); | 211 | pud_populate_kernel(&init_mm, pu_dir, pm_dir); |
195 | } | 212 | } |
196 | 213 | ||
197 | pm_dir = pmd_offset(pg_dir, address); | 214 | pm_dir = pmd_offset(pu_dir, address); |
198 | if (pmd_none(*pm_dir)) { | 215 | if (pmd_none(*pm_dir)) { |
199 | pt_dir = vmem_pte_alloc(); | 216 | pt_dir = vmem_pte_alloc(); |
200 | if (!pt_dir) | 217 | if (!pt_dir) |
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 2edd5fb6d3dc..8d1c64a24dec 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
@@ -48,8 +48,8 @@ struct raw3270 { | |||
48 | struct timer_list timer; /* Device timer. */ | 48 | struct timer_list timer; /* Device timer. */ |
49 | 49 | ||
50 | unsigned char *ascebc; /* ascii -> ebcdic table */ | 50 | unsigned char *ascebc; /* ascii -> ebcdic table */ |
51 | struct class_device *clttydev; /* 3270-class tty device ptr */ | 51 | struct device *clttydev; /* 3270-class tty device ptr */ |
52 | struct class_device *cltubdev; /* 3270-class tub device ptr */ | 52 | struct device *cltubdev; /* 3270-class tub device ptr */ |
53 | 53 | ||
54 | struct raw3270_request init_request; | 54 | struct raw3270_request init_request; |
55 | unsigned char init_data[256]; | 55 | unsigned char init_data[256]; |
@@ -1107,11 +1107,9 @@ raw3270_delete_device(struct raw3270 *rp) | |||
1107 | /* Remove from device chain. */ | 1107 | /* Remove from device chain. */ |
1108 | mutex_lock(&raw3270_mutex); | 1108 | mutex_lock(&raw3270_mutex); |
1109 | if (rp->clttydev && !IS_ERR(rp->clttydev)) | 1109 | if (rp->clttydev && !IS_ERR(rp->clttydev)) |
1110 | class_device_destroy(class3270, | 1110 | device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor)); |
1111 | MKDEV(IBM_TTY3270_MAJOR, rp->minor)); | ||
1112 | if (rp->cltubdev && !IS_ERR(rp->cltubdev)) | 1111 | if (rp->cltubdev && !IS_ERR(rp->cltubdev)) |
1113 | class_device_destroy(class3270, | 1112 | device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, rp->minor)); |
1114 | MKDEV(IBM_FS3270_MAJOR, rp->minor)); | ||
1115 | list_del_init(&rp->list); | 1113 | list_del_init(&rp->list); |
1116 | mutex_unlock(&raw3270_mutex); | 1114 | mutex_unlock(&raw3270_mutex); |
1117 | 1115 | ||
@@ -1181,24 +1179,22 @@ static int raw3270_create_attributes(struct raw3270 *rp) | |||
1181 | if (rc) | 1179 | if (rc) |
1182 | goto out; | 1180 | goto out; |
1183 | 1181 | ||
1184 | rp->clttydev = class_device_create(class3270, NULL, | 1182 | rp->clttydev = device_create(class3270, &rp->cdev->dev, |
1185 | MKDEV(IBM_TTY3270_MAJOR, rp->minor), | 1183 | MKDEV(IBM_TTY3270_MAJOR, rp->minor), |
1186 | &rp->cdev->dev, "tty%s", | 1184 | "tty%s", rp->cdev->dev.bus_id); |
1187 | rp->cdev->dev.bus_id); | ||
1188 | if (IS_ERR(rp->clttydev)) { | 1185 | if (IS_ERR(rp->clttydev)) { |
1189 | rc = PTR_ERR(rp->clttydev); | 1186 | rc = PTR_ERR(rp->clttydev); |
1190 | goto out_ttydev; | 1187 | goto out_ttydev; |
1191 | } | 1188 | } |
1192 | 1189 | ||
1193 | rp->cltubdev = class_device_create(class3270, NULL, | 1190 | rp->cltubdev = device_create(class3270, &rp->cdev->dev, |
1194 | MKDEV(IBM_FS3270_MAJOR, rp->minor), | 1191 | MKDEV(IBM_FS3270_MAJOR, rp->minor), |
1195 | &rp->cdev->dev, "tub%s", | 1192 | "tub%s", rp->cdev->dev.bus_id); |
1196 | rp->cdev->dev.bus_id); | ||
1197 | if (!IS_ERR(rp->cltubdev)) | 1193 | if (!IS_ERR(rp->cltubdev)) |
1198 | goto out; | 1194 | goto out; |
1199 | 1195 | ||
1200 | rc = PTR_ERR(rp->cltubdev); | 1196 | rc = PTR_ERR(rp->cltubdev); |
1201 | class_device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor)); | 1197 | device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor)); |
1202 | 1198 | ||
1203 | out_ttydev: | 1199 | out_ttydev: |
1204 | sysfs_remove_group(&rp->cdev->dev.kobj, &raw3270_attr_group); | 1200 | sysfs_remove_group(&rp->cdev->dev.kobj, &raw3270_attr_group); |
diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c index 2e0d29730b67..aa7f166f4034 100644 --- a/drivers/s390/char/tape_class.c +++ b/drivers/s390/char/tape_class.c | |||
@@ -69,12 +69,9 @@ struct tape_class_device *register_tape_dev( | |||
69 | if (rc) | 69 | if (rc) |
70 | goto fail_with_cdev; | 70 | goto fail_with_cdev; |
71 | 71 | ||
72 | tcd->class_device = class_device_create( | 72 | tcd->class_device = device_create(tape_class, device, |
73 | tape_class, | 73 | tcd->char_device->dev, |
74 | NULL, | 74 | "%s", tcd->device_name |
75 | tcd->char_device->dev, | ||
76 | device, | ||
77 | "%s", tcd->device_name | ||
78 | ); | 75 | ); |
79 | rc = IS_ERR(tcd->class_device) ? PTR_ERR(tcd->class_device) : 0; | 76 | rc = IS_ERR(tcd->class_device) ? PTR_ERR(tcd->class_device) : 0; |
80 | if (rc) | 77 | if (rc) |
@@ -90,7 +87,7 @@ struct tape_class_device *register_tape_dev( | |||
90 | return tcd; | 87 | return tcd; |
91 | 88 | ||
92 | fail_with_class_device: | 89 | fail_with_class_device: |
93 | class_device_destroy(tape_class, tcd->char_device->dev); | 90 | device_destroy(tape_class, tcd->char_device->dev); |
94 | 91 | ||
95 | fail_with_cdev: | 92 | fail_with_cdev: |
96 | cdev_del(tcd->char_device); | 93 | cdev_del(tcd->char_device); |
@@ -105,11 +102,9 @@ EXPORT_SYMBOL(register_tape_dev); | |||
105 | void unregister_tape_dev(struct tape_class_device *tcd) | 102 | void unregister_tape_dev(struct tape_class_device *tcd) |
106 | { | 103 | { |
107 | if (tcd != NULL && !IS_ERR(tcd)) { | 104 | if (tcd != NULL && !IS_ERR(tcd)) { |
108 | sysfs_remove_link( | 105 | sysfs_remove_link(&tcd->class_device->kobj, |
109 | &tcd->class_device->dev->kobj, | 106 | tcd->mode_name); |
110 | tcd->mode_name | 107 | device_destroy(tape_class, tcd->char_device->dev); |
111 | ); | ||
112 | class_device_destroy(tape_class, tcd->char_device->dev); | ||
113 | cdev_del(tcd->char_device); | 108 | cdev_del(tcd->char_device); |
114 | kfree(tcd); | 109 | kfree(tcd); |
115 | } | 110 | } |
diff --git a/drivers/s390/char/tape_class.h b/drivers/s390/char/tape_class.h index a8bd9b47fad6..e2b5ac918acf 100644 --- a/drivers/s390/char/tape_class.h +++ b/drivers/s390/char/tape_class.h | |||
@@ -24,8 +24,8 @@ | |||
24 | #define TAPECLASS_NAME_LEN 32 | 24 | #define TAPECLASS_NAME_LEN 32 |
25 | 25 | ||
26 | struct tape_class_device { | 26 | struct tape_class_device { |
27 | struct cdev * char_device; | 27 | struct cdev *char_device; |
28 | struct class_device * class_device; | 28 | struct device *class_device; |
29 | char device_name[TAPECLASS_NAME_LEN]; | 29 | char device_name[TAPECLASS_NAME_LEN]; |
30 | char mode_name[TAPECLASS_NAME_LEN]; | 30 | char mode_name[TAPECLASS_NAME_LEN]; |
31 | }; | 31 | }; |
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 12f7a4ce82c1..e0c4c508e121 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c | |||
@@ -74,7 +74,7 @@ struct vmlogrdr_priv_t { | |||
74 | int dev_in_use; /* 1: already opened, 0: not opened*/ | 74 | int dev_in_use; /* 1: already opened, 0: not opened*/ |
75 | spinlock_t priv_lock; | 75 | spinlock_t priv_lock; |
76 | struct device *device; | 76 | struct device *device; |
77 | struct class_device *class_device; | 77 | struct device *class_device; |
78 | int autorecording; | 78 | int autorecording; |
79 | int autopurge; | 79 | int autopurge; |
80 | }; | 80 | }; |
@@ -762,12 +762,10 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) | |||
762 | device_unregister(dev); | 762 | device_unregister(dev); |
763 | return ret; | 763 | return ret; |
764 | } | 764 | } |
765 | priv->class_device = class_device_create( | 765 | priv->class_device = device_create(vmlogrdr_class, dev, |
766 | vmlogrdr_class, | 766 | MKDEV(vmlogrdr_major, |
767 | NULL, | 767 | priv->minor_num), |
768 | MKDEV(vmlogrdr_major, priv->minor_num), | 768 | "%s", dev->bus_id); |
769 | dev, | ||
770 | "%s", dev->bus_id ); | ||
771 | if (IS_ERR(priv->class_device)) { | 769 | if (IS_ERR(priv->class_device)) { |
772 | ret = PTR_ERR(priv->class_device); | 770 | ret = PTR_ERR(priv->class_device); |
773 | priv->class_device=NULL; | 771 | priv->class_device=NULL; |
@@ -783,8 +781,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) | |||
783 | 781 | ||
784 | static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv) | 782 | static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv) |
785 | { | 783 | { |
786 | class_device_destroy(vmlogrdr_class, | 784 | device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num)); |
787 | MKDEV(vmlogrdr_major, priv->minor_num)); | ||
788 | if (priv->device != NULL) { | 785 | if (priv->device != NULL) { |
789 | sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group); | 786 | sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group); |
790 | device_unregister(priv->device); | 787 | device_unregister(priv->device); |
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 42c1f4659adb..297cdceb0ca4 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c | |||
@@ -246,7 +246,7 @@ int chp_add_cmg_attr(struct channel_path *chp) | |||
246 | static ssize_t chp_status_show(struct device *dev, | 246 | static ssize_t chp_status_show(struct device *dev, |
247 | struct device_attribute *attr, char *buf) | 247 | struct device_attribute *attr, char *buf) |
248 | { | 248 | { |
249 | struct channel_path *chp = container_of(dev, struct channel_path, dev); | 249 | struct channel_path *chp = to_channelpath(dev); |
250 | 250 | ||
251 | if (!chp) | 251 | if (!chp) |
252 | return 0; | 252 | return 0; |
@@ -258,7 +258,7 @@ static ssize_t chp_status_write(struct device *dev, | |||
258 | struct device_attribute *attr, | 258 | struct device_attribute *attr, |
259 | const char *buf, size_t count) | 259 | const char *buf, size_t count) |
260 | { | 260 | { |
261 | struct channel_path *cp = container_of(dev, struct channel_path, dev); | 261 | struct channel_path *cp = to_channelpath(dev); |
262 | char cmd[10]; | 262 | char cmd[10]; |
263 | int num_args; | 263 | int num_args; |
264 | int error; | 264 | int error; |
@@ -286,7 +286,7 @@ static ssize_t chp_configure_show(struct device *dev, | |||
286 | struct channel_path *cp; | 286 | struct channel_path *cp; |
287 | int status; | 287 | int status; |
288 | 288 | ||
289 | cp = container_of(dev, struct channel_path, dev); | 289 | cp = to_channelpath(dev); |
290 | status = chp_info_get_status(cp->chpid); | 290 | status = chp_info_get_status(cp->chpid); |
291 | if (status < 0) | 291 | if (status < 0) |
292 | return status; | 292 | return status; |
@@ -308,7 +308,7 @@ static ssize_t chp_configure_write(struct device *dev, | |||
308 | return -EINVAL; | 308 | return -EINVAL; |
309 | if (val != 0 && val != 1) | 309 | if (val != 0 && val != 1) |
310 | return -EINVAL; | 310 | return -EINVAL; |
311 | cp = container_of(dev, struct channel_path, dev); | 311 | cp = to_channelpath(dev); |
312 | chp_cfg_schedule(cp->chpid, val); | 312 | chp_cfg_schedule(cp->chpid, val); |
313 | cfg_wait_idle(); | 313 | cfg_wait_idle(); |
314 | 314 | ||
@@ -320,7 +320,7 @@ static DEVICE_ATTR(configure, 0644, chp_configure_show, chp_configure_write); | |||
320 | static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr, | 320 | static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr, |
321 | char *buf) | 321 | char *buf) |
322 | { | 322 | { |
323 | struct channel_path *chp = container_of(dev, struct channel_path, dev); | 323 | struct channel_path *chp = to_channelpath(dev); |
324 | 324 | ||
325 | if (!chp) | 325 | if (!chp) |
326 | return 0; | 326 | return 0; |
@@ -374,7 +374,7 @@ static void chp_release(struct device *dev) | |||
374 | { | 374 | { |
375 | struct channel_path *cp; | 375 | struct channel_path *cp; |
376 | 376 | ||
377 | cp = container_of(dev, struct channel_path, dev); | 377 | cp = to_channelpath(dev); |
378 | kfree(cp); | 378 | kfree(cp); |
379 | } | 379 | } |
380 | 380 | ||
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 5d83dd471461..838f7ac0dc32 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -182,6 +182,15 @@ static int css_register_subchannel(struct subchannel *sch) | |||
182 | sch->dev.bus = &css_bus_type; | 182 | sch->dev.bus = &css_bus_type; |
183 | sch->dev.release = &css_subchannel_release; | 183 | sch->dev.release = &css_subchannel_release; |
184 | sch->dev.groups = subch_attr_groups; | 184 | sch->dev.groups = subch_attr_groups; |
185 | /* | ||
186 | * We don't want to generate uevents for I/O subchannels that don't | ||
187 | * have a working ccw device behind them since they will be | ||
188 | * unregistered before they can be used anyway, so we delay the add | ||
189 | * uevent until after device recognition was successful. | ||
190 | */ | ||
191 | if (!cio_is_console(sch->schid)) | ||
192 | /* Console is special, no need to suppress. */ | ||
193 | sch->dev.uevent_suppress = 1; | ||
185 | css_update_ssd_info(sch); | 194 | css_update_ssd_info(sch); |
186 | /* make it known to the system */ | 195 | /* make it known to the system */ |
187 | ret = css_sch_device_register(sch); | 196 | ret = css_sch_device_register(sch); |
diff --git a/include/asm-s390/cpu.h b/include/asm-s390/cpu.h new file mode 100644 index 000000000000..352dde194f3c --- /dev/null +++ b/include/asm-s390/cpu.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * include/asm-s390/cpu.h | ||
3 | * | ||
4 | * Copyright IBM Corp. 2007 | ||
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #ifndef _ASM_S390_CPU_H_ | ||
9 | #define _ASM_S390_CPU_H_ | ||
10 | |||
11 | #include <linux/types.h> | ||
12 | #include <linux/percpu.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | |||
15 | struct s390_idle_data { | ||
16 | spinlock_t lock; | ||
17 | unsigned int in_idle; | ||
18 | unsigned long long idle_count; | ||
19 | unsigned long long idle_enter; | ||
20 | unsigned long long idle_time; | ||
21 | }; | ||
22 | |||
23 | DECLARE_PER_CPU(struct s390_idle_data, s390_idle); | ||
24 | |||
25 | #endif /* _ASM_S390_CPU_H_ */ | ||
diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h index 501cb9b06314..05b842126b99 100644 --- a/include/asm-s390/mmu_context.h +++ b/include/asm-s390/mmu_context.h | |||
@@ -21,45 +21,43 @@ | |||
21 | 21 | ||
22 | #ifndef __s390x__ | 22 | #ifndef __s390x__ |
23 | #define LCTL_OPCODE "lctl" | 23 | #define LCTL_OPCODE "lctl" |
24 | #define PGTABLE_BITS (_SEGMENT_TABLE|USER_STD_MASK) | ||
25 | #else | 24 | #else |
26 | #define LCTL_OPCODE "lctlg" | 25 | #define LCTL_OPCODE "lctlg" |
27 | #define PGTABLE_BITS (_REGION_TABLE|USER_STD_MASK) | ||
28 | #endif | 26 | #endif |
29 | 27 | ||
30 | static inline void enter_lazy_tlb(struct mm_struct *mm, | 28 | static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk) |
31 | struct task_struct *tsk) | ||
32 | { | 29 | { |
30 | pgd_t *pgd = mm->pgd; | ||
31 | unsigned long asce_bits; | ||
32 | |||
33 | /* Calculate asce bits from the first pgd table entry. */ | ||
34 | asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; | ||
35 | #ifdef CONFIG_64BIT | ||
36 | asce_bits |= _ASCE_TYPE_REGION3; | ||
37 | #endif | ||
38 | S390_lowcore.user_asce = asce_bits | __pa(pgd); | ||
39 | if (switch_amode) { | ||
40 | /* Load primary space page table origin. */ | ||
41 | pgd_t *shadow_pgd = get_shadow_table(pgd) ? : pgd; | ||
42 | S390_lowcore.user_exec_asce = asce_bits | __pa(shadow_pgd); | ||
43 | asm volatile(LCTL_OPCODE" 1,1,%0\n" | ||
44 | : : "m" (S390_lowcore.user_exec_asce) ); | ||
45 | } else | ||
46 | /* Load home space page table origin. */ | ||
47 | asm volatile(LCTL_OPCODE" 13,13,%0" | ||
48 | : : "m" (S390_lowcore.user_asce) ); | ||
33 | } | 49 | } |
34 | 50 | ||
35 | static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, | 51 | static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, |
36 | struct task_struct *tsk) | 52 | struct task_struct *tsk) |
37 | { | 53 | { |
38 | pgd_t *shadow_pgd = get_shadow_pgd(next->pgd); | 54 | if (unlikely(prev == next)) |
39 | 55 | return; | |
40 | if (prev != next) { | ||
41 | S390_lowcore.user_asce = (__pa(next->pgd) & PAGE_MASK) | | ||
42 | PGTABLE_BITS; | ||
43 | if (shadow_pgd) { | ||
44 | /* Load primary/secondary space page table origin. */ | ||
45 | S390_lowcore.user_exec_asce = | ||
46 | (__pa(shadow_pgd) & PAGE_MASK) | PGTABLE_BITS; | ||
47 | asm volatile(LCTL_OPCODE" 1,1,%0\n" | ||
48 | LCTL_OPCODE" 7,7,%1" | ||
49 | : : "m" (S390_lowcore.user_exec_asce), | ||
50 | "m" (S390_lowcore.user_asce) ); | ||
51 | } else if (switch_amode) { | ||
52 | /* Load primary space page table origin. */ | ||
53 | asm volatile(LCTL_OPCODE" 1,1,%0" | ||
54 | : : "m" (S390_lowcore.user_asce) ); | ||
55 | } else | ||
56 | /* Load home space page table origin. */ | ||
57 | asm volatile(LCTL_OPCODE" 13,13,%0" | ||
58 | : : "m" (S390_lowcore.user_asce) ); | ||
59 | } | ||
60 | cpu_set(smp_processor_id(), next->cpu_vm_mask); | 56 | cpu_set(smp_processor_id(), next->cpu_vm_mask); |
57 | update_mm(next, tsk); | ||
61 | } | 58 | } |
62 | 59 | ||
60 | #define enter_lazy_tlb(mm,tsk) do { } while (0) | ||
63 | #define deactivate_mm(tsk,mm) do { } while (0) | 61 | #define deactivate_mm(tsk,mm) do { } while (0) |
64 | 62 | ||
65 | static inline void activate_mm(struct mm_struct *prev, | 63 | static inline void activate_mm(struct mm_struct *prev, |
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h index ceec3826a67c..584d0ee3c7f6 100644 --- a/include/asm-s390/page.h +++ b/include/asm-s390/page.h | |||
@@ -82,6 +82,7 @@ typedef struct { unsigned long pte; } pte_t; | |||
82 | #ifndef __s390x__ | 82 | #ifndef __s390x__ |
83 | 83 | ||
84 | typedef struct { unsigned long pmd; } pmd_t; | 84 | typedef struct { unsigned long pmd; } pmd_t; |
85 | typedef struct { unsigned long pud; } pud_t; | ||
85 | typedef struct { | 86 | typedef struct { |
86 | unsigned long pgd0; | 87 | unsigned long pgd0; |
87 | unsigned long pgd1; | 88 | unsigned long pgd1; |
@@ -90,6 +91,7 @@ typedef struct { | |||
90 | } pgd_t; | 91 | } pgd_t; |
91 | 92 | ||
92 | #define pmd_val(x) ((x).pmd) | 93 | #define pmd_val(x) ((x).pmd) |
94 | #define pud_val(x) ((x).pud) | ||
93 | #define pgd_val(x) ((x).pgd0) | 95 | #define pgd_val(x) ((x).pgd0) |
94 | 96 | ||
95 | #else /* __s390x__ */ | 97 | #else /* __s390x__ */ |
@@ -98,10 +100,12 @@ typedef struct { | |||
98 | unsigned long pmd0; | 100 | unsigned long pmd0; |
99 | unsigned long pmd1; | 101 | unsigned long pmd1; |
100 | } pmd_t; | 102 | } pmd_t; |
103 | typedef struct { unsigned long pud; } pud_t; | ||
101 | typedef struct { unsigned long pgd; } pgd_t; | 104 | typedef struct { unsigned long pgd; } pgd_t; |
102 | 105 | ||
103 | #define pmd_val(x) ((x).pmd0) | 106 | #define pmd_val(x) ((x).pmd0) |
104 | #define pmd_val1(x) ((x).pmd1) | 107 | #define pmd_val1(x) ((x).pmd1) |
108 | #define pud_val(x) ((x).pud) | ||
105 | #define pgd_val(x) ((x).pgd) | 109 | #define pgd_val(x) ((x).pgd) |
106 | 110 | ||
107 | #endif /* __s390x__ */ | 111 | #endif /* __s390x__ */ |
diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h index e45d3c9a4b7e..709dd1740956 100644 --- a/include/asm-s390/pgalloc.h +++ b/include/asm-s390/pgalloc.h | |||
@@ -19,140 +19,115 @@ | |||
19 | 19 | ||
20 | #define check_pgt_cache() do {} while (0) | 20 | #define check_pgt_cache() do {} while (0) |
21 | 21 | ||
22 | /* | 22 | unsigned long *crst_table_alloc(struct mm_struct *, int); |
23 | * Page allocation orders. | 23 | void crst_table_free(unsigned long *); |
24 | */ | ||
25 | #ifndef __s390x__ | ||
26 | # define PTE_ALLOC_ORDER 0 | ||
27 | # define PMD_ALLOC_ORDER 0 | ||
28 | # define PGD_ALLOC_ORDER 1 | ||
29 | #else /* __s390x__ */ | ||
30 | # define PTE_ALLOC_ORDER 0 | ||
31 | # define PMD_ALLOC_ORDER 2 | ||
32 | # define PGD_ALLOC_ORDER 2 | ||
33 | #endif /* __s390x__ */ | ||
34 | 24 | ||
35 | /* | 25 | unsigned long *page_table_alloc(int); |
36 | * Allocate and free page tables. The xxx_kernel() versions are | 26 | void page_table_free(unsigned long *); |
37 | * used to allocate a kernel page table - this turns on ASN bits | ||
38 | * if any. | ||
39 | */ | ||
40 | 27 | ||
41 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | 28 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) |
42 | { | 29 | { |
43 | pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_ALLOC_ORDER); | 30 | *s = val; |
44 | int i; | 31 | n = (n / 256) - 1; |
45 | 32 | asm volatile( | |
46 | if (!pgd) | 33 | #ifdef CONFIG_64BIT |
47 | return NULL; | 34 | " mvc 8(248,%0),0(%0)\n" |
48 | if (s390_noexec) { | ||
49 | pgd_t *shadow_pgd = (pgd_t *) | ||
50 | __get_free_pages(GFP_KERNEL, PGD_ALLOC_ORDER); | ||
51 | struct page *page = virt_to_page(pgd); | ||
52 | |||
53 | if (!shadow_pgd) { | ||
54 | free_pages((unsigned long) pgd, PGD_ALLOC_ORDER); | ||
55 | return NULL; | ||
56 | } | ||
57 | page->lru.next = (void *) shadow_pgd; | ||
58 | } | ||
59 | for (i = 0; i < PTRS_PER_PGD; i++) | ||
60 | #ifndef __s390x__ | ||
61 | pmd_clear(pmd_offset(pgd + i, i*PGDIR_SIZE)); | ||
62 | #else | 35 | #else |
63 | pgd_clear(pgd + i); | 36 | " mvc 4(252,%0),0(%0)\n" |
64 | #endif | 37 | #endif |
65 | return pgd; | 38 | "0: mvc 256(256,%0),0(%0)\n" |
39 | " la %0,256(%0)\n" | ||
40 | " brct %1,0b\n" | ||
41 | : "+a" (s), "+d" (n)); | ||
66 | } | 42 | } |
67 | 43 | ||
68 | static inline void pgd_free(pgd_t *pgd) | 44 | static inline void crst_table_init(unsigned long *crst, unsigned long entry) |
69 | { | 45 | { |
70 | pgd_t *shadow_pgd = get_shadow_pgd(pgd); | 46 | clear_table(crst, entry, sizeof(unsigned long)*2048); |
71 | 47 | crst = get_shadow_table(crst); | |
72 | if (shadow_pgd) | 48 | if (crst) |
73 | free_pages((unsigned long) shadow_pgd, PGD_ALLOC_ORDER); | 49 | clear_table(crst, entry, sizeof(unsigned long)*2048); |
74 | free_pages((unsigned long) pgd, PGD_ALLOC_ORDER); | ||
75 | } | 50 | } |
76 | 51 | ||
77 | #ifndef __s390x__ | 52 | #ifndef __s390x__ |
78 | /* | 53 | |
79 | * page middle directory allocation/free routines. | 54 | static inline unsigned long pgd_entry_type(struct mm_struct *mm) |
80 | * We use pmd cache only on s390x, so these are dummy routines. This | ||
81 | * code never triggers because the pgd will always be present. | ||
82 | */ | ||
83 | #define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) | ||
84 | #define pmd_free(x) do { } while (0) | ||
85 | #define __pmd_free_tlb(tlb,x) do { } while (0) | ||
86 | #define pgd_populate(mm, pmd, pte) BUG() | ||
87 | #define pgd_populate_kernel(mm, pmd, pte) BUG() | ||
88 | #else /* __s390x__ */ | ||
89 | static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) | ||
90 | { | 55 | { |
91 | pmd_t *pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, PMD_ALLOC_ORDER); | 56 | return _SEGMENT_ENTRY_EMPTY; |
92 | int i; | ||
93 | |||
94 | if (!pmd) | ||
95 | return NULL; | ||
96 | if (s390_noexec) { | ||
97 | pmd_t *shadow_pmd = (pmd_t *) | ||
98 | __get_free_pages(GFP_KERNEL, PMD_ALLOC_ORDER); | ||
99 | struct page *page = virt_to_page(pmd); | ||
100 | |||
101 | if (!shadow_pmd) { | ||
102 | free_pages((unsigned long) pmd, PMD_ALLOC_ORDER); | ||
103 | return NULL; | ||
104 | } | ||
105 | page->lru.next = (void *) shadow_pmd; | ||
106 | } | ||
107 | for (i=0; i < PTRS_PER_PMD; i++) | ||
108 | pmd_clear(pmd + i); | ||
109 | return pmd; | ||
110 | } | 57 | } |
111 | 58 | ||
112 | static inline void pmd_free (pmd_t *pmd) | 59 | #define pud_alloc_one(mm,address) ({ BUG(); ((pud_t *)2); }) |
60 | #define pud_free(x) do { } while (0) | ||
61 | |||
62 | #define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) | ||
63 | #define pmd_free(x) do { } while (0) | ||
64 | |||
65 | #define pgd_populate(mm, pgd, pud) BUG() | ||
66 | #define pgd_populate_kernel(mm, pgd, pud) BUG() | ||
67 | |||
68 | #define pud_populate(mm, pud, pmd) BUG() | ||
69 | #define pud_populate_kernel(mm, pud, pmd) BUG() | ||
70 | |||
71 | #else /* __s390x__ */ | ||
72 | |||
73 | static inline unsigned long pgd_entry_type(struct mm_struct *mm) | ||
113 | { | 74 | { |
114 | pmd_t *shadow_pmd = get_shadow_pmd(pmd); | 75 | return _REGION3_ENTRY_EMPTY; |
76 | } | ||
77 | |||
78 | #define pud_alloc_one(mm,address) ({ BUG(); ((pud_t *)2); }) | ||
79 | #define pud_free(x) do { } while (0) | ||
115 | 80 | ||
116 | if (shadow_pmd) | 81 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) |
117 | free_pages((unsigned long) shadow_pmd, PMD_ALLOC_ORDER); | 82 | { |
118 | free_pages((unsigned long) pmd, PMD_ALLOC_ORDER); | 83 | unsigned long *crst = crst_table_alloc(mm, s390_noexec); |
84 | if (crst) | ||
85 | crst_table_init(crst, _SEGMENT_ENTRY_EMPTY); | ||
86 | return (pmd_t *) crst; | ||
119 | } | 87 | } |
88 | #define pmd_free(pmd) crst_table_free((unsigned long *) pmd) | ||
120 | 89 | ||
121 | #define __pmd_free_tlb(tlb,pmd) \ | 90 | #define pgd_populate(mm, pgd, pud) BUG() |
122 | do { \ | 91 | #define pgd_populate_kernel(mm, pgd, pud) BUG() |
123 | tlb_flush_mmu(tlb, 0, 0); \ | ||
124 | pmd_free(pmd); \ | ||
125 | } while (0) | ||
126 | 92 | ||
127 | static inline void | 93 | static inline void pud_populate_kernel(struct mm_struct *mm, |
128 | pgd_populate_kernel(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) | 94 | pud_t *pud, pmd_t *pmd) |
129 | { | 95 | { |
130 | pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd); | 96 | pud_val(*pud) = _REGION3_ENTRY | __pa(pmd); |
131 | } | 97 | } |
132 | 98 | ||
133 | static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) | 99 | static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) |
134 | { | 100 | { |
135 | pgd_t *shadow_pgd = get_shadow_pgd(pgd); | 101 | pud_t *shadow_pud = get_shadow_table(pud); |
136 | pmd_t *shadow_pmd = get_shadow_pmd(pmd); | 102 | pmd_t *shadow_pmd = get_shadow_table(pmd); |
137 | 103 | ||
138 | if (shadow_pgd && shadow_pmd) | 104 | if (shadow_pud && shadow_pmd) |
139 | pgd_populate_kernel(mm, shadow_pgd, shadow_pmd); | 105 | pud_populate_kernel(mm, shadow_pud, shadow_pmd); |
140 | pgd_populate_kernel(mm, pgd, pmd); | 106 | pud_populate_kernel(mm, pud, pmd); |
141 | } | 107 | } |
142 | 108 | ||
143 | #endif /* __s390x__ */ | 109 | #endif /* __s390x__ */ |
144 | 110 | ||
111 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | ||
112 | { | ||
113 | unsigned long *crst = crst_table_alloc(mm, s390_noexec); | ||
114 | if (crst) | ||
115 | crst_table_init(crst, pgd_entry_type(mm)); | ||
116 | return (pgd_t *) crst; | ||
117 | } | ||
118 | #define pgd_free(pgd) crst_table_free((unsigned long *) pgd) | ||
119 | |||
145 | static inline void | 120 | static inline void |
146 | pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) | 121 | pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) |
147 | { | 122 | { |
148 | #ifndef __s390x__ | 123 | #ifndef __s390x__ |
149 | pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte); | 124 | pmd_val(pmd[0]) = _SEGMENT_ENTRY + __pa(pte); |
150 | pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte+256); | 125 | pmd_val(pmd[1]) = _SEGMENT_ENTRY + __pa(pte+256); |
151 | pmd_val(pmd[2]) = _PAGE_TABLE + __pa(pte+512); | 126 | pmd_val(pmd[2]) = _SEGMENT_ENTRY + __pa(pte+512); |
152 | pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte+768); | 127 | pmd_val(pmd[3]) = _SEGMENT_ENTRY + __pa(pte+768); |
153 | #else /* __s390x__ */ | 128 | #else /* __s390x__ */ |
154 | pmd_val(*pmd) = _PMD_ENTRY + __pa(pte); | 129 | pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte); |
155 | pmd_val1(*pmd) = _PMD_ENTRY + __pa(pte+256); | 130 | pmd_val1(*pmd) = _SEGMENT_ENTRY + __pa(pte+256); |
156 | #endif /* __s390x__ */ | 131 | #endif /* __s390x__ */ |
157 | } | 132 | } |
158 | 133 | ||
@@ -160,7 +135,7 @@ static inline void | |||
160 | pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page) | 135 | pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page) |
161 | { | 136 | { |
162 | pte_t *pte = (pte_t *)page_to_phys(page); | 137 | pte_t *pte = (pte_t *)page_to_phys(page); |
163 | pmd_t *shadow_pmd = get_shadow_pmd(pmd); | 138 | pmd_t *shadow_pmd = get_shadow_table(pmd); |
164 | pte_t *shadow_pte = get_shadow_pte(pte); | 139 | pte_t *shadow_pte = get_shadow_pte(pte); |
165 | 140 | ||
166 | pmd_populate_kernel(mm, pmd, pte); | 141 | pmd_populate_kernel(mm, pmd, pte); |
@@ -171,67 +146,14 @@ pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page) | |||
171 | /* | 146 | /* |
172 | * page table entry allocation/free routines. | 147 | * page table entry allocation/free routines. |
173 | */ | 148 | */ |
174 | static inline pte_t * | 149 | #define pte_alloc_one_kernel(mm, vmaddr) \ |
175 | pte_alloc_one_kernel(struct mm_struct *mm, unsigned long vmaddr) | 150 | ((pte_t *) page_table_alloc(s390_noexec)) |
176 | { | 151 | #define pte_alloc_one(mm, vmaddr) \ |
177 | pte_t *pte = (pte_t *) __get_free_page(GFP_KERNEL|__GFP_REPEAT); | 152 | virt_to_page(page_table_alloc(s390_noexec)) |
178 | int i; | 153 | |
179 | 154 | #define pte_free_kernel(pte) \ | |
180 | if (!pte) | 155 | page_table_free((unsigned long *) pte) |
181 | return NULL; | 156 | #define pte_free(pte) \ |
182 | if (s390_noexec) { | 157 | page_table_free((unsigned long *) page_to_phys((struct page *) pte)) |
183 | pte_t *shadow_pte = (pte_t *) | ||
184 | __get_free_page(GFP_KERNEL|__GFP_REPEAT); | ||
185 | struct page *page = virt_to_page(pte); | ||
186 | |||
187 | if (!shadow_pte) { | ||
188 | free_page((unsigned long) pte); | ||
189 | return NULL; | ||
190 | } | ||
191 | page->lru.next = (void *) shadow_pte; | ||
192 | } | ||
193 | for (i=0; i < PTRS_PER_PTE; i++) { | ||
194 | pte_clear(mm, vmaddr, pte + i); | ||
195 | vmaddr += PAGE_SIZE; | ||
196 | } | ||
197 | return pte; | ||
198 | } | ||
199 | |||
200 | static inline struct page * | ||
201 | pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr) | ||
202 | { | ||
203 | pte_t *pte = pte_alloc_one_kernel(mm, vmaddr); | ||
204 | if (pte) | ||
205 | return virt_to_page(pte); | ||
206 | return NULL; | ||
207 | } | ||
208 | |||
209 | static inline void pte_free_kernel(pte_t *pte) | ||
210 | { | ||
211 | pte_t *shadow_pte = get_shadow_pte(pte); | ||
212 | |||
213 | if (shadow_pte) | ||
214 | free_page((unsigned long) shadow_pte); | ||
215 | free_page((unsigned long) pte); | ||
216 | } | ||
217 | |||
218 | static inline void pte_free(struct page *pte) | ||
219 | { | ||
220 | struct page *shadow_page = get_shadow_page(pte); | ||
221 | |||
222 | if (shadow_page) | ||
223 | __free_page(shadow_page); | ||
224 | __free_page(pte); | ||
225 | } | ||
226 | |||
227 | #define __pte_free_tlb(tlb, pte) \ | ||
228 | ({ \ | ||
229 | struct mmu_gather *__tlb = (tlb); \ | ||
230 | struct page *__pte = (pte); \ | ||
231 | struct page *shadow_page = get_shadow_page(__pte); \ | ||
232 | if (shadow_page) \ | ||
233 | tlb_remove_page(__tlb, shadow_page); \ | ||
234 | tlb_remove_page(__tlb, __pte); \ | ||
235 | }) | ||
236 | 158 | ||
237 | #endif /* _S390_PGALLOC_H */ | 159 | #endif /* _S390_PGALLOC_H */ |
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 39bb5192dc31..f2cc25b74adf 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h | |||
@@ -13,8 +13,6 @@ | |||
13 | #ifndef _ASM_S390_PGTABLE_H | 13 | #ifndef _ASM_S390_PGTABLE_H |
14 | #define _ASM_S390_PGTABLE_H | 14 | #define _ASM_S390_PGTABLE_H |
15 | 15 | ||
16 | #include <asm-generic/4level-fixup.h> | ||
17 | |||
18 | /* | 16 | /* |
19 | * The Linux memory management assumes a three-level page table setup. For | 17 | * The Linux memory management assumes a three-level page table setup. For |
20 | * s390 31 bit we "fold" the mid level into the top-level page table, so | 18 | * s390 31 bit we "fold" the mid level into the top-level page table, so |
@@ -35,9 +33,6 @@ | |||
35 | #include <asm/bug.h> | 33 | #include <asm/bug.h> |
36 | #include <asm/processor.h> | 34 | #include <asm/processor.h> |
37 | 35 | ||
38 | struct vm_area_struct; /* forward declaration (include/linux/mm.h) */ | ||
39 | struct mm_struct; | ||
40 | |||
41 | extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); | 36 | extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); |
42 | extern void paging_init(void); | 37 | extern void paging_init(void); |
43 | extern void vmem_map_init(void); | 38 | extern void vmem_map_init(void); |
@@ -63,14 +58,18 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
63 | */ | 58 | */ |
64 | #ifndef __s390x__ | 59 | #ifndef __s390x__ |
65 | # define PMD_SHIFT 22 | 60 | # define PMD_SHIFT 22 |
61 | # define PUD_SHIFT 22 | ||
66 | # define PGDIR_SHIFT 22 | 62 | # define PGDIR_SHIFT 22 |
67 | #else /* __s390x__ */ | 63 | #else /* __s390x__ */ |
68 | # define PMD_SHIFT 21 | 64 | # define PMD_SHIFT 21 |
65 | # define PUD_SHIFT 31 | ||
69 | # define PGDIR_SHIFT 31 | 66 | # define PGDIR_SHIFT 31 |
70 | #endif /* __s390x__ */ | 67 | #endif /* __s390x__ */ |
71 | 68 | ||
72 | #define PMD_SIZE (1UL << PMD_SHIFT) | 69 | #define PMD_SIZE (1UL << PMD_SHIFT) |
73 | #define PMD_MASK (~(PMD_SIZE-1)) | 70 | #define PMD_MASK (~(PMD_SIZE-1)) |
71 | #define PUD_SIZE (1UL << PUD_SHIFT) | ||
72 | #define PUD_MASK (~(PUD_SIZE-1)) | ||
74 | #define PGDIR_SIZE (1UL << PGDIR_SHIFT) | 73 | #define PGDIR_SIZE (1UL << PGDIR_SHIFT) |
75 | #define PGDIR_MASK (~(PGDIR_SIZE-1)) | 74 | #define PGDIR_MASK (~(PGDIR_SIZE-1)) |
76 | 75 | ||
@@ -83,10 +82,12 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
83 | #ifndef __s390x__ | 82 | #ifndef __s390x__ |
84 | # define PTRS_PER_PTE 1024 | 83 | # define PTRS_PER_PTE 1024 |
85 | # define PTRS_PER_PMD 1 | 84 | # define PTRS_PER_PMD 1 |
85 | # define PTRS_PER_PUD 1 | ||
86 | # define PTRS_PER_PGD 512 | 86 | # define PTRS_PER_PGD 512 |
87 | #else /* __s390x__ */ | 87 | #else /* __s390x__ */ |
88 | # define PTRS_PER_PTE 512 | 88 | # define PTRS_PER_PTE 512 |
89 | # define PTRS_PER_PMD 1024 | 89 | # define PTRS_PER_PMD 1024 |
90 | # define PTRS_PER_PUD 1 | ||
90 | # define PTRS_PER_PGD 2048 | 91 | # define PTRS_PER_PGD 2048 |
91 | #endif /* __s390x__ */ | 92 | #endif /* __s390x__ */ |
92 | 93 | ||
@@ -96,6 +97,8 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
96 | printk("%s:%d: bad pte %p.\n", __FILE__, __LINE__, (void *) pte_val(e)) | 97 | printk("%s:%d: bad pte %p.\n", __FILE__, __LINE__, (void *) pte_val(e)) |
97 | #define pmd_ERROR(e) \ | 98 | #define pmd_ERROR(e) \ |
98 | printk("%s:%d: bad pmd %p.\n", __FILE__, __LINE__, (void *) pmd_val(e)) | 99 | printk("%s:%d: bad pmd %p.\n", __FILE__, __LINE__, (void *) pmd_val(e)) |
100 | #define pud_ERROR(e) \ | ||
101 | printk("%s:%d: bad pud %p.\n", __FILE__, __LINE__, (void *) pud_val(e)) | ||
99 | #define pgd_ERROR(e) \ | 102 | #define pgd_ERROR(e) \ |
100 | printk("%s:%d: bad pgd %p.\n", __FILE__, __LINE__, (void *) pgd_val(e)) | 103 | printk("%s:%d: bad pgd %p.\n", __FILE__, __LINE__, (void *) pgd_val(e)) |
101 | 104 | ||
@@ -195,7 +198,7 @@ extern unsigned long vmalloc_end; | |||
195 | * I Segment-Invalid Bit: Segment is not available for address-translation | 198 | * I Segment-Invalid Bit: Segment is not available for address-translation |
196 | * TT Type 01 | 199 | * TT Type 01 |
197 | * TF | 200 | * TF |
198 | * TL Table lenght | 201 | * TL Table length |
199 | * | 202 | * |
200 | * The 64 bit regiontable origin of S390 has following format: | 203 | * The 64 bit regiontable origin of S390 has following format: |
201 | * | region table origon | DTTL | 204 | * | region table origon | DTTL |
@@ -221,6 +224,8 @@ extern unsigned long vmalloc_end; | |||
221 | /* Hardware bits in the page table entry */ | 224 | /* Hardware bits in the page table entry */ |
222 | #define _PAGE_RO 0x200 /* HW read-only bit */ | 225 | #define _PAGE_RO 0x200 /* HW read-only bit */ |
223 | #define _PAGE_INVALID 0x400 /* HW invalid bit */ | 226 | #define _PAGE_INVALID 0x400 /* HW invalid bit */ |
227 | |||
228 | /* Software bits in the page table entry */ | ||
224 | #define _PAGE_SWT 0x001 /* SW pte type bit t */ | 229 | #define _PAGE_SWT 0x001 /* SW pte type bit t */ |
225 | #define _PAGE_SWX 0x002 /* SW pte type bit x */ | 230 | #define _PAGE_SWX 0x002 /* SW pte type bit x */ |
226 | 231 | ||
@@ -264,60 +269,75 @@ extern unsigned long vmalloc_end; | |||
264 | 269 | ||
265 | #ifndef __s390x__ | 270 | #ifndef __s390x__ |
266 | 271 | ||
267 | /* Bits in the segment table entry */ | 272 | /* Bits in the segment table address-space-control-element */ |
268 | #define _PAGE_TABLE_LEN 0xf /* only full page-tables */ | 273 | #define _ASCE_SPACE_SWITCH 0x80000000UL /* space switch event */ |
269 | #define _PAGE_TABLE_COM 0x10 /* common page-table */ | 274 | #define _ASCE_ORIGIN_MASK 0x7ffff000UL /* segment table origin */ |
270 | #define _PAGE_TABLE_INV 0x20 /* invalid page-table */ | 275 | #define _ASCE_PRIVATE_SPACE 0x100 /* private space control */ |
271 | #define _SEG_PRESENT 0x001 /* Software (overlap with PTL) */ | 276 | #define _ASCE_ALT_EVENT 0x80 /* storage alteration event control */ |
272 | 277 | #define _ASCE_TABLE_LENGTH 0x7f /* 128 x 64 entries = 8k */ | |
273 | /* Bits int the storage key */ | ||
274 | #define _PAGE_CHANGED 0x02 /* HW changed bit */ | ||
275 | #define _PAGE_REFERENCED 0x04 /* HW referenced bit */ | ||
276 | |||
277 | #define _USER_SEG_TABLE_LEN 0x7f /* user-segment-table up to 2 GB */ | ||
278 | #define _KERNEL_SEG_TABLE_LEN 0x7f /* kernel-segment-table up to 2 GB */ | ||
279 | |||
280 | /* | ||
281 | * User and Kernel pagetables are identical | ||
282 | */ | ||
283 | #define _PAGE_TABLE _PAGE_TABLE_LEN | ||
284 | #define _KERNPG_TABLE _PAGE_TABLE_LEN | ||
285 | |||
286 | /* | ||
287 | * The Kernel segment-tables includes the User segment-table | ||
288 | */ | ||
289 | 278 | ||
290 | #define _SEGMENT_TABLE (_USER_SEG_TABLE_LEN|0x80000000|0x100) | 279 | /* Bits in the segment table entry */ |
291 | #define _KERNSEG_TABLE _KERNEL_SEG_TABLE_LEN | 280 | #define _SEGMENT_ENTRY_ORIGIN 0x7fffffc0UL /* page table origin */ |
281 | #define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */ | ||
282 | #define _SEGMENT_ENTRY_COMMON 0x10 /* common segment bit */ | ||
283 | #define _SEGMENT_ENTRY_PTL 0x0f /* page table length */ | ||
292 | 284 | ||
293 | #define USER_STD_MASK 0x00000080UL | 285 | #define _SEGMENT_ENTRY (_SEGMENT_ENTRY_PTL) |
286 | #define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INV) | ||
294 | 287 | ||
295 | #else /* __s390x__ */ | 288 | #else /* __s390x__ */ |
296 | 289 | ||
290 | /* Bits in the segment/region table address-space-control-element */ | ||
291 | #define _ASCE_ORIGIN ~0xfffUL/* segment table origin */ | ||
292 | #define _ASCE_PRIVATE_SPACE 0x100 /* private space control */ | ||
293 | #define _ASCE_ALT_EVENT 0x80 /* storage alteration event control */ | ||
294 | #define _ASCE_SPACE_SWITCH 0x40 /* space switch event */ | ||
295 | #define _ASCE_REAL_SPACE 0x20 /* real space control */ | ||
296 | #define _ASCE_TYPE_MASK 0x0c /* asce table type mask */ | ||
297 | #define _ASCE_TYPE_REGION1 0x0c /* region first table type */ | ||
298 | #define _ASCE_TYPE_REGION2 0x08 /* region second table type */ | ||
299 | #define _ASCE_TYPE_REGION3 0x04 /* region third table type */ | ||
300 | #define _ASCE_TYPE_SEGMENT 0x00 /* segment table type */ | ||
301 | #define _ASCE_TABLE_LENGTH 0x03 /* region table length */ | ||
302 | |||
303 | /* Bits in the region table entry */ | ||
304 | #define _REGION_ENTRY_ORIGIN ~0xfffUL/* region/segment table origin */ | ||
305 | #define _REGION_ENTRY_INV 0x20 /* invalid region table entry */ | ||
306 | #define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */ | ||
307 | #define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */ | ||
308 | #define _REGION_ENTRY_TYPE_R2 0x08 /* region second table type */ | ||
309 | #define _REGION_ENTRY_TYPE_R3 0x04 /* region third table type */ | ||
310 | #define _REGION_ENTRY_LENGTH 0x03 /* region third length */ | ||
311 | |||
312 | #define _REGION1_ENTRY (_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_LENGTH) | ||
313 | #define _REGION1_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INV) | ||
314 | #define _REGION2_ENTRY (_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_LENGTH) | ||
315 | #define _REGION2_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INV) | ||
316 | #define _REGION3_ENTRY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH) | ||
317 | #define _REGION3_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INV) | ||
318 | |||
297 | /* Bits in the segment table entry */ | 319 | /* Bits in the segment table entry */ |
298 | #define _PMD_ENTRY_INV 0x20 /* invalid segment table entry */ | 320 | #define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */ |
299 | #define _PMD_ENTRY 0x00 | 321 | #define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */ |
322 | #define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */ | ||
323 | |||
324 | #define _SEGMENT_ENTRY (0) | ||
325 | #define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INV) | ||
300 | 326 | ||
301 | /* Bits in the region third table entry */ | 327 | #endif /* __s390x__ */ |
302 | #define _PGD_ENTRY_INV 0x20 /* invalid region table entry */ | ||
303 | #define _PGD_ENTRY 0x07 | ||
304 | 328 | ||
305 | /* | 329 | /* |
306 | * User and kernel page directory | 330 | * A user page table pointer has the space-switch-event bit, the |
331 | * private-space-control bit and the storage-alteration-event-control | ||
332 | * bit set. A kernel page table pointer doesn't need them. | ||
307 | */ | 333 | */ |
308 | #define _REGION_THIRD 0x4 | 334 | #define _ASCE_USER_BITS (_ASCE_SPACE_SWITCH | _ASCE_PRIVATE_SPACE | \ |
309 | #define _REGION_THIRD_LEN 0x3 | 335 | _ASCE_ALT_EVENT) |
310 | #define _REGION_TABLE (_REGION_THIRD|_REGION_THIRD_LEN|0x40|0x100) | ||
311 | #define _KERN_REGION_TABLE (_REGION_THIRD|_REGION_THIRD_LEN) | ||
312 | |||
313 | #define USER_STD_MASK 0x0000000000000080UL | ||
314 | 336 | ||
315 | /* Bits in the storage key */ | 337 | /* Bits int the storage key */ |
316 | #define _PAGE_CHANGED 0x02 /* HW changed bit */ | 338 | #define _PAGE_CHANGED 0x02 /* HW changed bit */ |
317 | #define _PAGE_REFERENCED 0x04 /* HW referenced bit */ | 339 | #define _PAGE_REFERENCED 0x04 /* HW referenced bit */ |
318 | 340 | ||
319 | #endif /* __s390x__ */ | ||
320 | |||
321 | /* | 341 | /* |
322 | * Page protection definitions. | 342 | * Page protection definitions. |
323 | */ | 343 | */ |
@@ -358,65 +378,38 @@ extern unsigned long vmalloc_end; | |||
358 | #define __S111 PAGE_EX_RW | 378 | #define __S111 PAGE_EX_RW |
359 | 379 | ||
360 | #ifndef __s390x__ | 380 | #ifndef __s390x__ |
361 | # define PMD_SHADOW_SHIFT 1 | 381 | # define PxD_SHADOW_SHIFT 1 |
362 | # define PGD_SHADOW_SHIFT 1 | ||
363 | #else /* __s390x__ */ | 382 | #else /* __s390x__ */ |
364 | # define PMD_SHADOW_SHIFT 2 | 383 | # define PxD_SHADOW_SHIFT 2 |
365 | # define PGD_SHADOW_SHIFT 2 | ||
366 | #endif /* __s390x__ */ | 384 | #endif /* __s390x__ */ |
367 | 385 | ||
368 | static inline struct page *get_shadow_page(struct page *page) | 386 | static inline struct page *get_shadow_page(struct page *page) |
369 | { | 387 | { |
370 | if (s390_noexec && !list_empty(&page->lru)) | 388 | if (s390_noexec && page->index) |
371 | return virt_to_page(page->lru.next); | 389 | return virt_to_page((void *)(addr_t) page->index); |
372 | return NULL; | ||
373 | } | ||
374 | |||
375 | static inline pte_t *get_shadow_pte(pte_t *ptep) | ||
376 | { | ||
377 | unsigned long pteptr = (unsigned long) (ptep); | ||
378 | |||
379 | if (s390_noexec) { | ||
380 | unsigned long offset = pteptr & (PAGE_SIZE - 1); | ||
381 | void *addr = (void *) (pteptr ^ offset); | ||
382 | struct page *page = virt_to_page(addr); | ||
383 | if (!list_empty(&page->lru)) | ||
384 | return (pte_t *) ((unsigned long) page->lru.next | | ||
385 | offset); | ||
386 | } | ||
387 | return NULL; | 390 | return NULL; |
388 | } | 391 | } |
389 | 392 | ||
390 | static inline pmd_t *get_shadow_pmd(pmd_t *pmdp) | 393 | static inline void *get_shadow_pte(void *table) |
391 | { | 394 | { |
392 | unsigned long pmdptr = (unsigned long) (pmdp); | 395 | unsigned long addr, offset; |
396 | struct page *page; | ||
393 | 397 | ||
394 | if (s390_noexec) { | 398 | addr = (unsigned long) table; |
395 | unsigned long offset = pmdptr & | 399 | offset = addr & (PAGE_SIZE - 1); |
396 | ((PAGE_SIZE << PMD_SHADOW_SHIFT) - 1); | 400 | page = virt_to_page((void *)(addr ^ offset)); |
397 | void *addr = (void *) (pmdptr ^ offset); | 401 | return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL); |
398 | struct page *page = virt_to_page(addr); | ||
399 | if (!list_empty(&page->lru)) | ||
400 | return (pmd_t *) ((unsigned long) page->lru.next | | ||
401 | offset); | ||
402 | } | ||
403 | return NULL; | ||
404 | } | 402 | } |
405 | 403 | ||
406 | static inline pgd_t *get_shadow_pgd(pgd_t *pgdp) | 404 | static inline void *get_shadow_table(void *table) |
407 | { | 405 | { |
408 | unsigned long pgdptr = (unsigned long) (pgdp); | 406 | unsigned long addr, offset; |
407 | struct page *page; | ||
409 | 408 | ||
410 | if (s390_noexec) { | 409 | addr = (unsigned long) table; |
411 | unsigned long offset = pgdptr & | 410 | offset = addr & ((PAGE_SIZE << PxD_SHADOW_SHIFT) - 1); |
412 | ((PAGE_SIZE << PGD_SHADOW_SHIFT) - 1); | 411 | page = virt_to_page((void *)(addr ^ offset)); |
413 | void *addr = (void *) (pgdptr ^ offset); | 412 | return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL); |
414 | struct page *page = virt_to_page(addr); | ||
415 | if (!list_empty(&page->lru)) | ||
416 | return (pgd_t *) ((unsigned long) page->lru.next | | ||
417 | offset); | ||
418 | } | ||
419 | return NULL; | ||
420 | } | 413 | } |
421 | 414 | ||
422 | /* | 415 | /* |
@@ -424,7 +417,8 @@ static inline pgd_t *get_shadow_pgd(pgd_t *pgdp) | |||
424 | * within a page table are directly modified. Thus, the following | 417 | * within a page table are directly modified. Thus, the following |
425 | * hook is made available. | 418 | * hook is made available. |
426 | */ | 419 | */ |
427 | static inline void set_pte(pte_t *pteptr, pte_t pteval) | 420 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, |
421 | pte_t *pteptr, pte_t pteval) | ||
428 | { | 422 | { |
429 | pte_t *shadow_pte = get_shadow_pte(pteptr); | 423 | pte_t *shadow_pte = get_shadow_pte(pteptr); |
430 | 424 | ||
@@ -437,7 +431,6 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval) | |||
437 | pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY; | 431 | pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY; |
438 | } | 432 | } |
439 | } | 433 | } |
440 | #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) | ||
441 | 434 | ||
442 | /* | 435 | /* |
443 | * pgd/pmd/pte query functions | 436 | * pgd/pmd/pte query functions |
@@ -448,47 +441,50 @@ static inline int pgd_present(pgd_t pgd) { return 1; } | |||
448 | static inline int pgd_none(pgd_t pgd) { return 0; } | 441 | static inline int pgd_none(pgd_t pgd) { return 0; } |
449 | static inline int pgd_bad(pgd_t pgd) { return 0; } | 442 | static inline int pgd_bad(pgd_t pgd) { return 0; } |
450 | 443 | ||
451 | static inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _SEG_PRESENT; } | 444 | static inline int pud_present(pud_t pud) { return 1; } |
452 | static inline int pmd_none(pmd_t pmd) { return pmd_val(pmd) & _PAGE_TABLE_INV; } | 445 | static inline int pud_none(pud_t pud) { return 0; } |
453 | static inline int pmd_bad(pmd_t pmd) | 446 | static inline int pud_bad(pud_t pud) { return 0; } |
454 | { | ||
455 | return (pmd_val(pmd) & (~PAGE_MASK & ~_PAGE_TABLE_INV)) != _PAGE_TABLE; | ||
456 | } | ||
457 | 447 | ||
458 | #else /* __s390x__ */ | 448 | #else /* __s390x__ */ |
459 | 449 | ||
460 | static inline int pgd_present(pgd_t pgd) | 450 | static inline int pgd_present(pgd_t pgd) { return 1; } |
451 | static inline int pgd_none(pgd_t pgd) { return 0; } | ||
452 | static inline int pgd_bad(pgd_t pgd) { return 0; } | ||
453 | |||
454 | static inline int pud_present(pud_t pud) | ||
461 | { | 455 | { |
462 | return (pgd_val(pgd) & ~PAGE_MASK) == _PGD_ENTRY; | 456 | return pud_val(pud) & _REGION_ENTRY_ORIGIN; |
463 | } | 457 | } |
464 | 458 | ||
465 | static inline int pgd_none(pgd_t pgd) | 459 | static inline int pud_none(pud_t pud) |
466 | { | 460 | { |
467 | return pgd_val(pgd) & _PGD_ENTRY_INV; | 461 | return pud_val(pud) & _REGION_ENTRY_INV; |
468 | } | 462 | } |
469 | 463 | ||
470 | static inline int pgd_bad(pgd_t pgd) | 464 | static inline int pud_bad(pud_t pud) |
471 | { | 465 | { |
472 | return (pgd_val(pgd) & (~PAGE_MASK & ~_PGD_ENTRY_INV)) != _PGD_ENTRY; | 466 | unsigned long mask = ~_REGION_ENTRY_ORIGIN & ~_REGION_ENTRY_INV; |
467 | return (pud_val(pud) & mask) != _REGION3_ENTRY; | ||
473 | } | 468 | } |
474 | 469 | ||
470 | #endif /* __s390x__ */ | ||
471 | |||
475 | static inline int pmd_present(pmd_t pmd) | 472 | static inline int pmd_present(pmd_t pmd) |
476 | { | 473 | { |
477 | return (pmd_val(pmd) & ~PAGE_MASK) == _PMD_ENTRY; | 474 | return pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN; |
478 | } | 475 | } |
479 | 476 | ||
480 | static inline int pmd_none(pmd_t pmd) | 477 | static inline int pmd_none(pmd_t pmd) |
481 | { | 478 | { |
482 | return pmd_val(pmd) & _PMD_ENTRY_INV; | 479 | return pmd_val(pmd) & _SEGMENT_ENTRY_INV; |
483 | } | 480 | } |
484 | 481 | ||
485 | static inline int pmd_bad(pmd_t pmd) | 482 | static inline int pmd_bad(pmd_t pmd) |
486 | { | 483 | { |
487 | return (pmd_val(pmd) & (~PAGE_MASK & ~_PMD_ENTRY_INV)) != _PMD_ENTRY; | 484 | unsigned long mask = ~_SEGMENT_ENTRY_ORIGIN & ~_SEGMENT_ENTRY_INV; |
485 | return (pmd_val(pmd) & mask) != _SEGMENT_ENTRY; | ||
488 | } | 486 | } |
489 | 487 | ||
490 | #endif /* __s390x__ */ | ||
491 | |||
492 | static inline int pte_none(pte_t pte) | 488 | static inline int pte_none(pte_t pte) |
493 | { | 489 | { |
494 | return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT); | 490 | return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT); |
@@ -508,7 +504,8 @@ static inline int pte_file(pte_t pte) | |||
508 | return (pte_val(pte) & mask) == _PAGE_TYPE_FILE; | 504 | return (pte_val(pte) & mask) == _PAGE_TYPE_FILE; |
509 | } | 505 | } |
510 | 506 | ||
511 | #define pte_same(a,b) (pte_val(a) == pte_val(b)) | 507 | #define __HAVE_ARCH_PTE_SAME |
508 | #define pte_same(a,b) (pte_val(a) == pte_val(b)) | ||
512 | 509 | ||
513 | /* | 510 | /* |
514 | * query functions pte_write/pte_dirty/pte_young only work if | 511 | * query functions pte_write/pte_dirty/pte_young only work if |
@@ -543,58 +540,52 @@ static inline int pte_young(pte_t pte) | |||
543 | 540 | ||
544 | #ifndef __s390x__ | 541 | #ifndef __s390x__ |
545 | 542 | ||
546 | static inline void pgd_clear(pgd_t * pgdp) { } | 543 | #define pgd_clear(pgd) do { } while (0) |
544 | #define pud_clear(pud) do { } while (0) | ||
547 | 545 | ||
548 | static inline void pmd_clear_kernel(pmd_t * pmdp) | 546 | static inline void pmd_clear_kernel(pmd_t * pmdp) |
549 | { | 547 | { |
550 | pmd_val(pmdp[0]) = _PAGE_TABLE_INV; | 548 | pmd_val(pmdp[0]) = _SEGMENT_ENTRY_EMPTY; |
551 | pmd_val(pmdp[1]) = _PAGE_TABLE_INV; | 549 | pmd_val(pmdp[1]) = _SEGMENT_ENTRY_EMPTY; |
552 | pmd_val(pmdp[2]) = _PAGE_TABLE_INV; | 550 | pmd_val(pmdp[2]) = _SEGMENT_ENTRY_EMPTY; |
553 | pmd_val(pmdp[3]) = _PAGE_TABLE_INV; | 551 | pmd_val(pmdp[3]) = _SEGMENT_ENTRY_EMPTY; |
554 | } | ||
555 | |||
556 | static inline void pmd_clear(pmd_t * pmdp) | ||
557 | { | ||
558 | pmd_t *shadow_pmd = get_shadow_pmd(pmdp); | ||
559 | |||
560 | pmd_clear_kernel(pmdp); | ||
561 | if (shadow_pmd) | ||
562 | pmd_clear_kernel(shadow_pmd); | ||
563 | } | 552 | } |
564 | 553 | ||
565 | #else /* __s390x__ */ | 554 | #else /* __s390x__ */ |
566 | 555 | ||
567 | static inline void pgd_clear_kernel(pgd_t * pgdp) | 556 | #define pgd_clear(pgd) do { } while (0) |
557 | |||
558 | static inline void pud_clear_kernel(pud_t *pud) | ||
568 | { | 559 | { |
569 | pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY; | 560 | pud_val(*pud) = _REGION3_ENTRY_EMPTY; |
570 | } | 561 | } |
571 | 562 | ||
572 | static inline void pgd_clear(pgd_t * pgdp) | 563 | static inline void pud_clear(pud_t * pud) |
573 | { | 564 | { |
574 | pgd_t *shadow_pgd = get_shadow_pgd(pgdp); | 565 | pud_t *shadow = get_shadow_table(pud); |
575 | 566 | ||
576 | pgd_clear_kernel(pgdp); | 567 | pud_clear_kernel(pud); |
577 | if (shadow_pgd) | 568 | if (shadow) |
578 | pgd_clear_kernel(shadow_pgd); | 569 | pud_clear_kernel(shadow); |
579 | } | 570 | } |
580 | 571 | ||
581 | static inline void pmd_clear_kernel(pmd_t * pmdp) | 572 | static inline void pmd_clear_kernel(pmd_t * pmdp) |
582 | { | 573 | { |
583 | pmd_val(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY; | 574 | pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY; |
584 | pmd_val1(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY; | 575 | pmd_val1(*pmdp) = _SEGMENT_ENTRY_EMPTY; |
585 | } | 576 | } |
586 | 577 | ||
578 | #endif /* __s390x__ */ | ||
579 | |||
587 | static inline void pmd_clear(pmd_t * pmdp) | 580 | static inline void pmd_clear(pmd_t * pmdp) |
588 | { | 581 | { |
589 | pmd_t *shadow_pmd = get_shadow_pmd(pmdp); | 582 | pmd_t *shadow_pmd = get_shadow_table(pmdp); |
590 | 583 | ||
591 | pmd_clear_kernel(pmdp); | 584 | pmd_clear_kernel(pmdp); |
592 | if (shadow_pmd) | 585 | if (shadow_pmd) |
593 | pmd_clear_kernel(shadow_pmd); | 586 | pmd_clear_kernel(shadow_pmd); |
594 | } | 587 | } |
595 | 588 | ||
596 | #endif /* __s390x__ */ | ||
597 | |||
598 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 589 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
599 | { | 590 | { |
600 | pte_t *shadow_pte = get_shadow_pte(ptep); | 591 | pte_t *shadow_pte = get_shadow_pte(ptep); |
@@ -663,24 +654,19 @@ static inline pte_t pte_mkyoung(pte_t pte) | |||
663 | return pte; | 654 | return pte; |
664 | } | 655 | } |
665 | 656 | ||
666 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) | 657 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG |
658 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, | ||
659 | unsigned long addr, pte_t *ptep) | ||
667 | { | 660 | { |
668 | return 0; | 661 | return 0; |
669 | } | 662 | } |
670 | 663 | ||
671 | static inline int | 664 | #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH |
672 | ptep_clear_flush_young(struct vm_area_struct *vma, | 665 | static inline int ptep_clear_flush_young(struct vm_area_struct *vma, |
673 | unsigned long address, pte_t *ptep) | 666 | unsigned long address, pte_t *ptep) |
674 | { | 667 | { |
675 | /* No need to flush TLB; bits are in storage key */ | 668 | /* No need to flush TLB; bits are in storage key */ |
676 | return ptep_test_and_clear_young(vma, address, ptep); | 669 | return 0; |
677 | } | ||
678 | |||
679 | static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | ||
680 | { | ||
681 | pte_t pte = *ptep; | ||
682 | pte_clear(mm, addr, ptep); | ||
683 | return pte; | ||
684 | } | 670 | } |
685 | 671 | ||
686 | static inline void __ptep_ipte(unsigned long address, pte_t *ptep) | 672 | static inline void __ptep_ipte(unsigned long address, pte_t *ptep) |
@@ -709,6 +695,32 @@ static inline void ptep_invalidate(unsigned long address, pte_t *ptep) | |||
709 | __ptep_ipte(address, ptep); | 695 | __ptep_ipte(address, ptep); |
710 | } | 696 | } |
711 | 697 | ||
698 | /* | ||
699 | * This is hard to understand. ptep_get_and_clear and ptep_clear_flush | ||
700 | * both clear the TLB for the unmapped pte. The reason is that | ||
701 | * ptep_get_and_clear is used in common code (e.g. change_pte_range) | ||
702 | * to modify an active pte. The sequence is | ||
703 | * 1) ptep_get_and_clear | ||
704 | * 2) set_pte_at | ||
705 | * 3) flush_tlb_range | ||
706 | * On s390 the tlb needs to get flushed with the modification of the pte | ||
707 | * if the pte is active. The only way how this can be implemented is to | ||
708 | * have ptep_get_and_clear do the tlb flush. In exchange flush_tlb_range | ||
709 | * is a nop. | ||
710 | */ | ||
711 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR | ||
712 | #define ptep_get_and_clear(__mm, __address, __ptep) \ | ||
713 | ({ \ | ||
714 | pte_t __pte = *(__ptep); \ | ||
715 | if (atomic_read(&(__mm)->mm_users) > 1 || \ | ||
716 | (__mm) != current->active_mm) \ | ||
717 | ptep_invalidate(__address, __ptep); \ | ||
718 | else \ | ||
719 | pte_clear((__mm), (__address), (__ptep)); \ | ||
720 | __pte; \ | ||
721 | }) | ||
722 | |||
723 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH | ||
712 | static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, | 724 | static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, |
713 | unsigned long address, pte_t *ptep) | 725 | unsigned long address, pte_t *ptep) |
714 | { | 726 | { |
@@ -717,12 +729,40 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, | |||
717 | return pte; | 729 | return pte; |
718 | } | 730 | } |
719 | 731 | ||
720 | static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 732 | /* |
733 | * The batched pte unmap code uses ptep_get_and_clear_full to clear the | ||
734 | * ptes. Here an optimization is possible. tlb_gather_mmu flushes all | ||
735 | * tlbs of an mm if it can guarantee that the ptes of the mm_struct | ||
736 | * cannot be accessed while the batched unmap is running. In this case | ||
737 | * full==1 and a simple pte_clear is enough. See tlb.h. | ||
738 | */ | ||
739 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL | ||
740 | static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, | ||
741 | unsigned long addr, | ||
742 | pte_t *ptep, int full) | ||
721 | { | 743 | { |
722 | pte_t old_pte = *ptep; | 744 | pte_t pte = *ptep; |
723 | set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte)); | 745 | |
746 | if (full) | ||
747 | pte_clear(mm, addr, ptep); | ||
748 | else | ||
749 | ptep_invalidate(addr, ptep); | ||
750 | return pte; | ||
724 | } | 751 | } |
725 | 752 | ||
753 | #define __HAVE_ARCH_PTEP_SET_WRPROTECT | ||
754 | #define ptep_set_wrprotect(__mm, __addr, __ptep) \ | ||
755 | ({ \ | ||
756 | pte_t __pte = *(__ptep); \ | ||
757 | if (pte_write(__pte)) { \ | ||
758 | if (atomic_read(&(__mm)->mm_users) > 1 || \ | ||
759 | (__mm) != current->active_mm) \ | ||
760 | ptep_invalidate(__addr, __ptep); \ | ||
761 | set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \ | ||
762 | } \ | ||
763 | }) | ||
764 | |||
765 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS | ||
726 | #define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ | 766 | #define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ |
727 | ({ \ | 767 | ({ \ |
728 | int __changed = !pte_same(*(__ptep), __entry); \ | 768 | int __changed = !pte_same(*(__ptep), __entry); \ |
@@ -740,11 +780,13 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, | |||
740 | * should therefore only be called if it is not mapped in any | 780 | * should therefore only be called if it is not mapped in any |
741 | * address space. | 781 | * address space. |
742 | */ | 782 | */ |
783 | #define __HAVE_ARCH_PAGE_TEST_DIRTY | ||
743 | static inline int page_test_dirty(struct page *page) | 784 | static inline int page_test_dirty(struct page *page) |
744 | { | 785 | { |
745 | return (page_get_storage_key(page_to_phys(page)) & _PAGE_CHANGED) != 0; | 786 | return (page_get_storage_key(page_to_phys(page)) & _PAGE_CHANGED) != 0; |
746 | } | 787 | } |
747 | 788 | ||
789 | #define __HAVE_ARCH_PAGE_CLEAR_DIRTY | ||
748 | static inline void page_clear_dirty(struct page *page) | 790 | static inline void page_clear_dirty(struct page *page) |
749 | { | 791 | { |
750 | page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY); | 792 | page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY); |
@@ -753,6 +795,7 @@ static inline void page_clear_dirty(struct page *page) | |||
753 | /* | 795 | /* |
754 | * Test and clear referenced bit in storage key. | 796 | * Test and clear referenced bit in storage key. |
755 | */ | 797 | */ |
798 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | ||
756 | static inline int page_test_and_clear_young(struct page *page) | 799 | static inline int page_test_and_clear_young(struct page *page) |
757 | { | 800 | { |
758 | unsigned long physpage = page_to_phys(page); | 801 | unsigned long physpage = page_to_phys(page); |
@@ -784,63 +827,48 @@ static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) | |||
784 | return mk_pte_phys(physpage, pgprot); | 827 | return mk_pte_phys(physpage, pgprot); |
785 | } | 828 | } |
786 | 829 | ||
787 | static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot) | 830 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) |
788 | { | 831 | #define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) |
789 | unsigned long physpage = __pa((pfn) << PAGE_SHIFT); | 832 | #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) |
790 | 833 | #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE-1)) | |
791 | return mk_pte_phys(physpage, pgprot); | ||
792 | } | ||
793 | |||
794 | #ifdef __s390x__ | ||
795 | |||
796 | static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot) | ||
797 | { | ||
798 | unsigned long physpage = __pa((pfn) << PAGE_SHIFT); | ||
799 | |||
800 | return __pmd(physpage + pgprot_val(pgprot)); | ||
801 | } | ||
802 | |||
803 | #endif /* __s390x__ */ | ||
804 | |||
805 | #define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT) | ||
806 | #define pte_page(x) pfn_to_page(pte_pfn(x)) | ||
807 | 834 | ||
808 | #define pmd_page_vaddr(pmd) (pmd_val(pmd) & PAGE_MASK) | 835 | #define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) |
836 | #define pgd_offset_k(address) pgd_offset(&init_mm, address) | ||
809 | 837 | ||
810 | #define pmd_page(pmd) pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT) | 838 | #ifndef __s390x__ |
811 | 839 | ||
812 | #define pgd_page_vaddr(pgd) (pgd_val(pgd) & PAGE_MASK) | 840 | #define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN) |
841 | #define pud_deref(pmd) ({ BUG(); 0UL; }) | ||
842 | #define pgd_deref(pmd) ({ BUG(); 0UL; }) | ||
813 | 843 | ||
814 | #define pgd_page(pgd) pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT) | 844 | #define pud_offset(pgd, address) ((pud_t *) pgd) |
845 | #define pmd_offset(pud, address) ((pmd_t *) pud + pmd_index(address)) | ||
815 | 846 | ||
816 | /* to find an entry in a page-table-directory */ | 847 | #else /* __s390x__ */ |
817 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) | ||
818 | #define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) | ||
819 | 848 | ||
820 | /* to find an entry in a kernel page-table-directory */ | 849 | #define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN) |
821 | #define pgd_offset_k(address) pgd_offset(&init_mm, address) | 850 | #define pud_deref(pud) (pud_val(pud) & _REGION_ENTRY_ORIGIN) |
851 | #define pgd_deref(pgd) ({ BUG(); 0UL; }) | ||
822 | 852 | ||
823 | #ifndef __s390x__ | 853 | #define pud_offset(pgd, address) ((pud_t *) pgd) |
824 | 854 | ||
825 | /* Find an entry in the second-level page table.. */ | 855 | static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) |
826 | static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) | ||
827 | { | 856 | { |
828 | return (pmd_t *) dir; | 857 | pmd_t *pmd = (pmd_t *) pud_deref(*pud); |
858 | return pmd + pmd_index(address); | ||
829 | } | 859 | } |
830 | 860 | ||
831 | #else /* __s390x__ */ | 861 | #endif /* __s390x__ */ |
832 | 862 | ||
833 | /* Find an entry in the second-level page table.. */ | 863 | #define pfn_pte(pfn,pgprot) mk_pte_phys(__pa((pfn) << PAGE_SHIFT),(pgprot)) |
834 | #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) | 864 | #define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT) |
835 | #define pmd_offset(dir,addr) \ | 865 | #define pte_page(x) pfn_to_page(pte_pfn(x)) |
836 | ((pmd_t *) pgd_page_vaddr(*(dir)) + pmd_index(addr)) | ||
837 | 866 | ||
838 | #endif /* __s390x__ */ | 867 | #define pmd_page(pmd) pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT) |
839 | 868 | ||
840 | /* Find an entry in the third-level page table.. */ | 869 | /* Find an entry in the lowest level page table.. */ |
841 | #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE-1)) | 870 | #define pte_offset(pmd, addr) ((pte_t *) pmd_deref(*(pmd)) + pte_index(addr)) |
842 | #define pte_offset_kernel(pmd, address) \ | 871 | #define pte_offset_kernel(pmd, address) pte_offset(pmd,address) |
843 | ((pte_t *) pmd_page_vaddr(*(pmd)) + pte_index(address)) | ||
844 | #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address) | 872 | #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address) |
845 | #define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address) | 873 | #define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address) |
846 | #define pte_unmap(pte) do { } while (0) | 874 | #define pte_unmap(pte) do { } while (0) |
@@ -930,17 +958,6 @@ extern int remove_shared_memory(unsigned long start, unsigned long size); | |||
930 | #define __HAVE_ARCH_MEMMAP_INIT | 958 | #define __HAVE_ARCH_MEMMAP_INIT |
931 | extern void memmap_init(unsigned long, int, unsigned long, unsigned long); | 959 | extern void memmap_init(unsigned long, int, unsigned long, unsigned long); |
932 | 960 | ||
933 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS | ||
934 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG | ||
935 | #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH | ||
936 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR | ||
937 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH | ||
938 | #define __HAVE_ARCH_PTEP_SET_WRPROTECT | ||
939 | #define __HAVE_ARCH_PTE_SAME | ||
940 | #define __HAVE_ARCH_PAGE_TEST_DIRTY | ||
941 | #define __HAVE_ARCH_PAGE_CLEAR_DIRTY | ||
942 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | ||
943 | #include <asm-generic/pgtable.h> | 961 | #include <asm-generic/pgtable.h> |
944 | 962 | ||
945 | #endif /* _S390_PAGE_H */ | 963 | #endif /* _S390_PAGE_H */ |
946 | |||
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index 3b972d4c6b29..21d40a19355e 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h | |||
@@ -93,7 +93,6 @@ struct thread_struct { | |||
93 | s390_fp_regs fp_regs; | 93 | s390_fp_regs fp_regs; |
94 | unsigned int acrs[NUM_ACRS]; | 94 | unsigned int acrs[NUM_ACRS]; |
95 | unsigned long ksp; /* kernel stack pointer */ | 95 | unsigned long ksp; /* kernel stack pointer */ |
96 | unsigned long user_seg; /* HSTD */ | ||
97 | mm_segment_t mm_segment; | 96 | mm_segment_t mm_segment; |
98 | unsigned long prot_addr; /* address of protection-excep. */ | 97 | unsigned long prot_addr; /* address of protection-excep. */ |
99 | unsigned int error_code; /* error-code of last prog-excep. */ | 98 | unsigned int error_code; /* error-code of last prog-excep. */ |
@@ -128,22 +127,9 @@ struct stack_frame { | |||
128 | 127 | ||
129 | #define ARCH_MIN_TASKALIGN 8 | 128 | #define ARCH_MIN_TASKALIGN 8 |
130 | 129 | ||
131 | #ifndef __s390x__ | 130 | #define INIT_THREAD { \ |
132 | # define __SWAPPER_PG_DIR __pa(&swapper_pg_dir[0]) + _SEGMENT_TABLE | 131 | .ksp = sizeof(init_stack) + (unsigned long) &init_stack, \ |
133 | #else /* __s390x__ */ | 132 | } |
134 | # define __SWAPPER_PG_DIR __pa(&swapper_pg_dir[0]) + _REGION_TABLE | ||
135 | #endif /* __s390x__ */ | ||
136 | |||
137 | #define INIT_THREAD {{0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \ | ||
138 | {0},{0},{0},{0},{0},{0}}}, \ | ||
139 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ | ||
140 | sizeof(init_stack) + (unsigned long) &init_stack, \ | ||
141 | __SWAPPER_PG_DIR, \ | ||
142 | {0}, \ | ||
143 | 0,0,0, \ | ||
144 | (per_struct) {{{{0,}}},0,0,0,0,{{0,}}}, \ | ||
145 | 0, 0 \ | ||
146 | } | ||
147 | 133 | ||
148 | /* | 134 | /* |
149 | * Do necessary setup to start up a new thread. | 135 | * Do necessary setup to start up a new thread. |
diff --git a/include/asm-s390/tlb.h b/include/asm-s390/tlb.h index 51bd957b85bd..618693cfc10f 100644 --- a/include/asm-s390/tlb.h +++ b/include/asm-s390/tlb.h | |||
@@ -2,19 +2,130 @@ | |||
2 | #define _S390_TLB_H | 2 | #define _S390_TLB_H |
3 | 3 | ||
4 | /* | 4 | /* |
5 | * s390 doesn't need any special per-pte or | 5 | * TLB flushing on s390 is complicated. The following requirement |
6 | * per-vma handling.. | 6 | * from the principles of operation is the most arduous: |
7 | * | ||
8 | * "A valid table entry must not be changed while it is attached | ||
9 | * to any CPU and may be used for translation by that CPU except to | ||
10 | * (1) invalidate the entry by using INVALIDATE PAGE TABLE ENTRY, | ||
11 | * or INVALIDATE DAT TABLE ENTRY, (2) alter bits 56-63 of a page | ||
12 | * table entry, or (3) make a change by means of a COMPARE AND SWAP | ||
13 | * AND PURGE instruction that purges the TLB." | ||
14 | * | ||
15 | * The modification of a pte of an active mm struct therefore is | ||
16 | * a two step process: i) invalidate the pte, ii) store the new pte. | ||
17 | * This is true for the page protection bit as well. | ||
18 | * The only possible optimization is to flush at the beginning of | ||
19 | * a tlb_gather_mmu cycle if the mm_struct is currently not in use. | ||
20 | * | ||
21 | * Pages used for the page tables is a different story. FIXME: more | ||
7 | */ | 22 | */ |
8 | #define tlb_start_vma(tlb, vma) do { } while (0) | 23 | |
9 | #define tlb_end_vma(tlb, vma) do { } while (0) | 24 | #include <linux/mm.h> |
10 | #define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) | 25 | #include <linux/swap.h> |
26 | #include <asm/processor.h> | ||
27 | #include <asm/pgalloc.h> | ||
28 | #include <asm/smp.h> | ||
29 | #include <asm/tlbflush.h> | ||
30 | |||
31 | #ifndef CONFIG_SMP | ||
32 | #define TLB_NR_PTRS 1 | ||
33 | #else | ||
34 | #define TLB_NR_PTRS 508 | ||
35 | #endif | ||
36 | |||
37 | struct mmu_gather { | ||
38 | struct mm_struct *mm; | ||
39 | unsigned int fullmm; | ||
40 | unsigned int nr_ptes; | ||
41 | unsigned int nr_pmds; | ||
42 | void *array[TLB_NR_PTRS]; | ||
43 | }; | ||
44 | |||
45 | DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); | ||
46 | |||
47 | static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, | ||
48 | unsigned int full_mm_flush) | ||
49 | { | ||
50 | struct mmu_gather *tlb = &get_cpu_var(mmu_gathers); | ||
51 | |||
52 | tlb->mm = mm; | ||
53 | tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) || | ||
54 | (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm); | ||
55 | tlb->nr_ptes = 0; | ||
56 | tlb->nr_pmds = TLB_NR_PTRS; | ||
57 | if (tlb->fullmm) | ||
58 | __tlb_flush_mm(mm); | ||
59 | return tlb; | ||
60 | } | ||
61 | |||
62 | static inline void tlb_flush_mmu(struct mmu_gather *tlb, | ||
63 | unsigned long start, unsigned long end) | ||
64 | { | ||
65 | if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pmds < TLB_NR_PTRS)) | ||
66 | __tlb_flush_mm(tlb->mm); | ||
67 | while (tlb->nr_ptes > 0) | ||
68 | pte_free(tlb->array[--tlb->nr_ptes]); | ||
69 | while (tlb->nr_pmds < TLB_NR_PTRS) | ||
70 | pmd_free((pmd_t *) tlb->array[tlb->nr_pmds++]); | ||
71 | } | ||
72 | |||
73 | static inline void tlb_finish_mmu(struct mmu_gather *tlb, | ||
74 | unsigned long start, unsigned long end) | ||
75 | { | ||
76 | tlb_flush_mmu(tlb, start, end); | ||
77 | |||
78 | /* keep the page table cache within bounds */ | ||
79 | check_pgt_cache(); | ||
80 | |||
81 | put_cpu_var(mmu_gathers); | ||
82 | } | ||
11 | 83 | ||
12 | /* | 84 | /* |
13 | * .. because we flush the whole mm when it | 85 | * Release the page cache reference for a pte removed by |
14 | * fills up. | 86 | * tlb_ptep_clear_flush. In both flush modes the tlb fo a page cache page |
87 | * has already been freed, so just do free_page_and_swap_cache. | ||
15 | */ | 88 | */ |
16 | #define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) | 89 | static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) |
90 | { | ||
91 | free_page_and_swap_cache(page); | ||
92 | } | ||
17 | 93 | ||
18 | #include <asm-generic/tlb.h> | 94 | /* |
95 | * pte_free_tlb frees a pte table and clears the CRSTE for the | ||
96 | * page table from the tlb. | ||
97 | */ | ||
98 | static inline void pte_free_tlb(struct mmu_gather *tlb, struct page *page) | ||
99 | { | ||
100 | if (!tlb->fullmm) { | ||
101 | tlb->array[tlb->nr_ptes++] = page; | ||
102 | if (tlb->nr_ptes >= tlb->nr_pmds) | ||
103 | tlb_flush_mmu(tlb, 0, 0); | ||
104 | } else | ||
105 | pte_free(page); | ||
106 | } | ||
19 | 107 | ||
108 | /* | ||
109 | * pmd_free_tlb frees a pmd table and clears the CRSTE for the | ||
110 | * segment table entry from the tlb. | ||
111 | */ | ||
112 | static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd) | ||
113 | { | ||
114 | #ifdef __s390x__ | ||
115 | if (!tlb->fullmm) { | ||
116 | tlb->array[--tlb->nr_pmds] = (struct page *) pmd; | ||
117 | if (tlb->nr_ptes >= tlb->nr_pmds) | ||
118 | tlb_flush_mmu(tlb, 0, 0); | ||
119 | } else | ||
120 | pmd_free(pmd); | ||
20 | #endif | 121 | #endif |
122 | } | ||
123 | |||
124 | #define pud_free_tlb(tlb, pud) do { } while (0) | ||
125 | |||
126 | #define tlb_start_vma(tlb, vma) do { } while (0) | ||
127 | #define tlb_end_vma(tlb, vma) do { } while (0) | ||
128 | #define tlb_remove_tlb_entry(tlb, ptep, addr) do { } while (0) | ||
129 | #define tlb_migrate_finish(mm) do { } while (0) | ||
130 | |||
131 | #endif /* _S390_TLB_H */ | ||
diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h index 6de2632a3e4f..a69bd2490d52 100644 --- a/include/asm-s390/tlbflush.h +++ b/include/asm-s390/tlbflush.h | |||
@@ -6,68 +6,19 @@ | |||
6 | #include <asm/pgalloc.h> | 6 | #include <asm/pgalloc.h> |
7 | 7 | ||
8 | /* | 8 | /* |
9 | * TLB flushing: | 9 | * Flush all tlb entries on the local cpu. |
10 | * | ||
11 | * - flush_tlb() flushes the current mm struct TLBs | ||
12 | * - flush_tlb_all() flushes all processes TLBs | ||
13 | * - flush_tlb_mm(mm) flushes the specified mm context TLB's | ||
14 | * - flush_tlb_page(vma, vmaddr) flushes one page | ||
15 | * - flush_tlb_range(vma, start, end) flushes a range of pages | ||
16 | * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages | ||
17 | */ | ||
18 | |||
19 | /* | ||
20 | * S/390 has three ways of flushing TLBs | ||
21 | * 'ptlb' does a flush of the local processor | ||
22 | * 'csp' flushes the TLBs on all PUs of a SMP | ||
23 | * 'ipte' invalidates a pte in a page table and flushes that out of | ||
24 | * the TLBs of all PUs of a SMP | ||
25 | */ | ||
26 | |||
27 | #define local_flush_tlb() \ | ||
28 | do { asm volatile("ptlb": : :"memory"); } while (0) | ||
29 | |||
30 | #ifndef CONFIG_SMP | ||
31 | |||
32 | /* | ||
33 | * We always need to flush, since s390 does not flush tlb | ||
34 | * on each context switch | ||
35 | */ | 10 | */ |
36 | 11 | static inline void __tlb_flush_local(void) | |
37 | static inline void flush_tlb(void) | ||
38 | { | 12 | { |
39 | local_flush_tlb(); | 13 | asm volatile("ptlb" : : : "memory"); |
40 | } | 14 | } |
41 | static inline void flush_tlb_all(void) | ||
42 | { | ||
43 | local_flush_tlb(); | ||
44 | } | ||
45 | static inline void flush_tlb_mm(struct mm_struct *mm) | ||
46 | { | ||
47 | local_flush_tlb(); | ||
48 | } | ||
49 | static inline void flush_tlb_page(struct vm_area_struct *vma, | ||
50 | unsigned long addr) | ||
51 | { | ||
52 | local_flush_tlb(); | ||
53 | } | ||
54 | static inline void flush_tlb_range(struct vm_area_struct *vma, | ||
55 | unsigned long start, unsigned long end) | ||
56 | { | ||
57 | local_flush_tlb(); | ||
58 | } | ||
59 | |||
60 | #define flush_tlb_kernel_range(start, end) \ | ||
61 | local_flush_tlb(); | ||
62 | |||
63 | #else | ||
64 | 15 | ||
65 | #include <asm/smp.h> | 16 | /* |
66 | 17 | * Flush all tlb entries on all cpus. | |
67 | extern void smp_ptlb_all(void); | 18 | */ |
68 | 19 | static inline void __tlb_flush_global(void) | |
69 | static inline void global_flush_tlb(void) | ||
70 | { | 20 | { |
21 | extern void smp_ptlb_all(void); | ||
71 | register unsigned long reg2 asm("2"); | 22 | register unsigned long reg2 asm("2"); |
72 | register unsigned long reg3 asm("3"); | 23 | register unsigned long reg3 asm("3"); |
73 | register unsigned long reg4 asm("4"); | 24 | register unsigned long reg4 asm("4"); |
@@ -89,66 +40,75 @@ static inline void global_flush_tlb(void) | |||
89 | } | 40 | } |
90 | 41 | ||
91 | /* | 42 | /* |
92 | * We only have to do global flush of tlb if process run since last | 43 | * Flush all tlb entries of a page table on all cpus. |
93 | * flush on any other pu than current. | ||
94 | * If we have threads (mm->count > 1) we always do a global flush, | ||
95 | * since the process runs on more than one processor at the same time. | ||
96 | */ | 44 | */ |
45 | static inline void __tlb_flush_idte(pgd_t *pgd) | ||
46 | { | ||
47 | asm volatile( | ||
48 | " .insn rrf,0xb98e0000,0,%0,%1,0" | ||
49 | : : "a" (2048), "a" (__pa(pgd) & PAGE_MASK) : "cc" ); | ||
50 | } | ||
97 | 51 | ||
98 | static inline void __flush_tlb_mm(struct mm_struct * mm) | 52 | static inline void __tlb_flush_mm(struct mm_struct * mm) |
99 | { | 53 | { |
100 | cpumask_t local_cpumask; | 54 | cpumask_t local_cpumask; |
101 | 55 | ||
102 | if (unlikely(cpus_empty(mm->cpu_vm_mask))) | 56 | if (unlikely(cpus_empty(mm->cpu_vm_mask))) |
103 | return; | 57 | return; |
58 | /* | ||
59 | * If the machine has IDTE we prefer to do a per mm flush | ||
60 | * on all cpus instead of doing a local flush if the mm | ||
61 | * only ran on the local cpu. | ||
62 | */ | ||
104 | if (MACHINE_HAS_IDTE) { | 63 | if (MACHINE_HAS_IDTE) { |
105 | pgd_t *shadow_pgd = get_shadow_pgd(mm->pgd); | 64 | pgd_t *shadow_pgd = get_shadow_table(mm->pgd); |
106 | 65 | ||
107 | if (shadow_pgd) { | 66 | if (shadow_pgd) |
108 | asm volatile( | 67 | __tlb_flush_idte(shadow_pgd); |
109 | " .insn rrf,0xb98e0000,0,%0,%1,0" | 68 | __tlb_flush_idte(mm->pgd); |
110 | : : "a" (2048), | ||
111 | "a" (__pa(shadow_pgd) & PAGE_MASK) : "cc" ); | ||
112 | } | ||
113 | asm volatile( | ||
114 | " .insn rrf,0xb98e0000,0,%0,%1,0" | ||
115 | : : "a" (2048), "a" (__pa(mm->pgd)&PAGE_MASK) : "cc"); | ||
116 | return; | 69 | return; |
117 | } | 70 | } |
118 | preempt_disable(); | 71 | preempt_disable(); |
72 | /* | ||
73 | * If the process only ran on the local cpu, do a local flush. | ||
74 | */ | ||
119 | local_cpumask = cpumask_of_cpu(smp_processor_id()); | 75 | local_cpumask = cpumask_of_cpu(smp_processor_id()); |
120 | if (cpus_equal(mm->cpu_vm_mask, local_cpumask)) | 76 | if (cpus_equal(mm->cpu_vm_mask, local_cpumask)) |
121 | local_flush_tlb(); | 77 | __tlb_flush_local(); |
122 | else | 78 | else |
123 | global_flush_tlb(); | 79 | __tlb_flush_global(); |
124 | preempt_enable(); | 80 | preempt_enable(); |
125 | } | 81 | } |
126 | 82 | ||
127 | static inline void flush_tlb(void) | 83 | static inline void __tlb_flush_mm_cond(struct mm_struct * mm) |
128 | { | ||
129 | __flush_tlb_mm(current->mm); | ||
130 | } | ||
131 | static inline void flush_tlb_all(void) | ||
132 | { | ||
133 | global_flush_tlb(); | ||
134 | } | ||
135 | static inline void flush_tlb_mm(struct mm_struct *mm) | ||
136 | { | ||
137 | __flush_tlb_mm(mm); | ||
138 | } | ||
139 | static inline void flush_tlb_page(struct vm_area_struct *vma, | ||
140 | unsigned long addr) | ||
141 | { | ||
142 | __flush_tlb_mm(vma->vm_mm); | ||
143 | } | ||
144 | static inline void flush_tlb_range(struct vm_area_struct *vma, | ||
145 | unsigned long start, unsigned long end) | ||
146 | { | 84 | { |
147 | __flush_tlb_mm(vma->vm_mm); | 85 | if (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm) |
86 | __tlb_flush_mm(mm); | ||
148 | } | 87 | } |
149 | 88 | ||
150 | #define flush_tlb_kernel_range(start, end) global_flush_tlb() | 89 | /* |
90 | * TLB flushing: | ||
91 | * flush_tlb() - flushes the current mm struct TLBs | ||
92 | * flush_tlb_all() - flushes all processes TLBs | ||
93 | * flush_tlb_mm(mm) - flushes the specified mm context TLB's | ||
94 | * flush_tlb_page(vma, vmaddr) - flushes one page | ||
95 | * flush_tlb_range(vma, start, end) - flushes a range of pages | ||
96 | * flush_tlb_kernel_range(start, end) - flushes a range of kernel pages | ||
97 | */ | ||
151 | 98 | ||
152 | #endif | 99 | /* |
100 | * flush_tlb_mm goes together with ptep_set_wrprotect for the | ||
101 | * copy_page_range operation and flush_tlb_range is related to | ||
102 | * ptep_get_and_clear for change_protection. ptep_set_wrprotect and | ||
103 | * ptep_get_and_clear do not flush the TLBs directly if the mm has | ||
104 | * only one user. At the end of the update the flush_tlb_mm and | ||
105 | * flush_tlb_range functions need to do the flush. | ||
106 | */ | ||
107 | #define flush_tlb() do { } while (0) | ||
108 | #define flush_tlb_all() do { } while (0) | ||
109 | #define flush_tlb_mm(mm) __tlb_flush_mm_cond(mm) | ||
110 | #define flush_tlb_page(vma, addr) do { } while (0) | ||
111 | #define flush_tlb_range(vma, start, end) __tlb_flush_mm_cond(mm) | ||
112 | #define flush_tlb_kernel_range(start, end) __tlb_flush_mm(&init_mm) | ||
153 | 113 | ||
154 | #endif /* _S390_TLBFLUSH_H */ | 114 | #endif /* _S390_TLBFLUSH_H */ |