diff options
119 files changed, 7415 insertions, 2185 deletions
diff --git a/arch/s390/Kbuild b/arch/s390/Kbuild index 9858476fa0fe..cc45d25487b0 100644 --- a/arch/s390/Kbuild +++ b/arch/s390/Kbuild | |||
| @@ -5,3 +5,4 @@ obj-$(CONFIG_CRYPTO_HW) += crypto/ | |||
| 5 | obj-$(CONFIG_S390_HYPFS_FS) += hypfs/ | 5 | obj-$(CONFIG_S390_HYPFS_FS) += hypfs/ |
| 6 | obj-$(CONFIG_APPLDATA_BASE) += appldata/ | 6 | obj-$(CONFIG_APPLDATA_BASE) += appldata/ |
| 7 | obj-$(CONFIG_MATHEMU) += math-emu/ | 7 | obj-$(CONFIG_MATHEMU) += math-emu/ |
| 8 | obj-y += net/ | ||
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index f5ab543396da..f9acddd9ace3 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
| @@ -52,6 +52,12 @@ config PGSTE | |||
| 52 | config ARCH_SUPPORTS_DEBUG_PAGEALLOC | 52 | config ARCH_SUPPORTS_DEBUG_PAGEALLOC |
| 53 | def_bool y | 53 | def_bool y |
| 54 | 54 | ||
| 55 | config KEXEC | ||
| 56 | def_bool y | ||
| 57 | |||
| 58 | config AUDIT_ARCH | ||
| 59 | def_bool y | ||
| 60 | |||
| 55 | config S390 | 61 | config S390 |
| 56 | def_bool y | 62 | def_bool y |
| 57 | select USE_GENERIC_SMP_HELPERS if SMP | 63 | select USE_GENERIC_SMP_HELPERS if SMP |
| @@ -81,11 +87,13 @@ config S390 | |||
| 81 | select HAVE_KERNEL_XZ | 87 | select HAVE_KERNEL_XZ |
| 82 | select HAVE_ARCH_MUTEX_CPU_RELAX | 88 | select HAVE_ARCH_MUTEX_CPU_RELAX |
| 83 | select HAVE_ARCH_JUMP_LABEL if !MARCH_G5 | 89 | select HAVE_ARCH_JUMP_LABEL if !MARCH_G5 |
| 90 | select HAVE_BPF_JIT if 64BIT && PACK_STACK | ||
| 84 | select ARCH_SAVE_PAGE_KEYS if HIBERNATION | 91 | select ARCH_SAVE_PAGE_KEYS if HIBERNATION |
| 85 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE | 92 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE |
| 86 | select HAVE_MEMBLOCK | 93 | select HAVE_MEMBLOCK |
| 87 | select HAVE_MEMBLOCK_NODE_MAP | 94 | select HAVE_MEMBLOCK_NODE_MAP |
| 88 | select HAVE_CMPXCHG_LOCAL | 95 | select HAVE_CMPXCHG_LOCAL |
| 96 | select HAVE_CMPXCHG_DOUBLE | ||
| 89 | select HAVE_VIRT_CPU_ACCOUNTING | 97 | select HAVE_VIRT_CPU_ACCOUNTING |
| 90 | select VIRT_CPU_ACCOUNTING | 98 | select VIRT_CPU_ACCOUNTING |
| 91 | select ARCH_DISCARD_MEMBLOCK | 99 | select ARCH_DISCARD_MEMBLOCK |
| @@ -132,9 +140,79 @@ source "init/Kconfig" | |||
| 132 | 140 | ||
| 133 | source "kernel/Kconfig.freezer" | 141 | source "kernel/Kconfig.freezer" |
| 134 | 142 | ||
| 135 | menu "Base setup" | 143 | menu "Processor type and features" |
| 144 | |||
| 145 | config HAVE_MARCH_Z900_FEATURES | ||
| 146 | def_bool n | ||
| 147 | |||
| 148 | config HAVE_MARCH_Z990_FEATURES | ||
| 149 | def_bool n | ||
| 150 | select HAVE_MARCH_Z900_FEATURES | ||
| 151 | |||
| 152 | config HAVE_MARCH_Z9_109_FEATURES | ||
| 153 | def_bool n | ||
| 154 | select HAVE_MARCH_Z990_FEATURES | ||
| 155 | |||
| 156 | config HAVE_MARCH_Z10_FEATURES | ||
| 157 | def_bool n | ||
| 158 | select HAVE_MARCH_Z9_109_FEATURES | ||
| 159 | |||
| 160 | config HAVE_MARCH_Z196_FEATURES | ||
| 161 | def_bool n | ||
| 162 | select HAVE_MARCH_Z10_FEATURES | ||
| 163 | |||
| 164 | choice | ||
| 165 | prompt "Processor type" | ||
| 166 | default MARCH_G5 | ||
| 167 | |||
| 168 | config MARCH_G5 | ||
| 169 | bool "System/390 model G5 and G6" | ||
| 170 | depends on !64BIT | ||
| 171 | help | ||
| 172 | Select this to build a 31 bit kernel that works | ||
| 173 | on all ESA/390 and z/Architecture machines. | ||
| 136 | 174 | ||
| 137 | comment "Processor type and features" | 175 | config MARCH_Z900 |
| 176 | bool "IBM zSeries model z800 and z900" | ||
| 177 | select HAVE_MARCH_Z900_FEATURES if 64BIT | ||
| 178 | help | ||
| 179 | Select this to enable optimizations for model z800/z900 (2064 and | ||
| 180 | 2066 series). This will enable some optimizations that are not | ||
| 181 | available on older ESA/390 (31 Bit) only CPUs. | ||
| 182 | |||
| 183 | config MARCH_Z990 | ||
| 184 | bool "IBM zSeries model z890 and z990" | ||
| 185 | select HAVE_MARCH_Z990_FEATURES if 64BIT | ||
| 186 | help | ||
| 187 | Select this to enable optimizations for model z890/z990 (2084 and | ||
| 188 | 2086 series). The kernel will be slightly faster but will not work | ||
| 189 | on older machines. | ||
| 190 | |||
| 191 | config MARCH_Z9_109 | ||
| 192 | bool "IBM System z9" | ||
| 193 | select HAVE_MARCH_Z9_109_FEATURES if 64BIT | ||
| 194 | help | ||
| 195 | Select this to enable optimizations for IBM System z9 (2094 and | ||
| 196 | 2096 series). The kernel will be slightly faster but will not work | ||
| 197 | on older machines. | ||
| 198 | |||
| 199 | config MARCH_Z10 | ||
| 200 | bool "IBM System z10" | ||
| 201 | select HAVE_MARCH_Z10_FEATURES if 64BIT | ||
| 202 | help | ||
| 203 | Select this to enable optimizations for IBM System z10 (2097 and | ||
| 204 | 2098 series). The kernel will be slightly faster but will not work | ||
| 205 | on older machines. | ||
| 206 | |||
| 207 | config MARCH_Z196 | ||
| 208 | bool "IBM zEnterprise 114 and 196" | ||
| 209 | select HAVE_MARCH_Z196_FEATURES if 64BIT | ||
| 210 | help | ||
| 211 | Select this to enable optimizations for IBM zEnterprise 114 and 196 | ||
| 212 | (2818 and 2817 series). The kernel will be slightly faster but will | ||
| 213 | not work on older machines. | ||
| 214 | |||
| 215 | endchoice | ||
| 138 | 216 | ||
| 139 | config 64BIT | 217 | config 64BIT |
| 140 | def_bool y | 218 | def_bool y |
| @@ -146,6 +224,24 @@ config 64BIT | |||
| 146 | config 32BIT | 224 | config 32BIT |
| 147 | def_bool y if !64BIT | 225 | def_bool y if !64BIT |
| 148 | 226 | ||
| 227 | config COMPAT | ||
| 228 | def_bool y | ||
| 229 | prompt "Kernel support for 31 bit emulation" | ||
| 230 | depends on 64BIT | ||
| 231 | select COMPAT_BINFMT_ELF if BINFMT_ELF | ||
| 232 | select ARCH_WANT_OLD_COMPAT_IPC | ||
| 233 | help | ||
| 234 | Select this option if you want to enable your system kernel to | ||
| 235 | handle system-calls from ELF binaries for 31 bit ESA. This option | ||
| 236 | (and some other stuff like libraries and such) is needed for | ||
| 237 | executing 31 bit applications. It is safe to say "Y". | ||
| 238 | |||
| 239 | config SYSVIPC_COMPAT | ||
| 240 | def_bool y if COMPAT && SYSVIPC | ||
| 241 | |||
| 242 | config KEYS_COMPAT | ||
| 243 | def_bool y if COMPAT && KEYS | ||
| 244 | |||
| 149 | config SMP | 245 | config SMP |
| 150 | def_bool y | 246 | def_bool y |
| 151 | prompt "Symmetric multi-processing support" | 247 | prompt "Symmetric multi-processing support" |
| @@ -201,6 +297,8 @@ config SCHED_BOOK | |||
| 201 | Book scheduler support improves the CPU scheduler's decision making | 297 | Book scheduler support improves the CPU scheduler's decision making |
| 202 | when dealing with machines that have several books. | 298 | when dealing with machines that have several books. |
| 203 | 299 | ||
| 300 | source kernel/Kconfig.preempt | ||
| 301 | |||
| 204 | config MATHEMU | 302 | config MATHEMU |
| 205 | def_bool y | 303 | def_bool y |
| 206 | prompt "IEEE FPU emulation" | 304 | prompt "IEEE FPU emulation" |
| @@ -210,100 +308,35 @@ config MATHEMU | |||
| 210 | on older ESA/390 machines. Say Y unless you know your machine doesn't | 308 | on older ESA/390 machines. Say Y unless you know your machine doesn't |
| 211 | need this. | 309 | need this. |
| 212 | 310 | ||
| 213 | config COMPAT | 311 | source kernel/Kconfig.hz |
| 214 | def_bool y | ||
| 215 | prompt "Kernel support for 31 bit emulation" | ||
| 216 | depends on 64BIT | ||
| 217 | select COMPAT_BINFMT_ELF if BINFMT_ELF | ||
| 218 | select ARCH_WANT_OLD_COMPAT_IPC | ||
| 219 | help | ||
| 220 | Select this option if you want to enable your system kernel to | ||
| 221 | handle system-calls from ELF binaries for 31 bit ESA. This option | ||
| 222 | (and some other stuff like libraries and such) is needed for | ||
| 223 | executing 31 bit applications. It is safe to say "Y". | ||
| 224 | 312 | ||
| 225 | config SYSVIPC_COMPAT | 313 | endmenu |
| 226 | def_bool y if COMPAT && SYSVIPC | ||
| 227 | 314 | ||
| 228 | config KEYS_COMPAT | 315 | menu "Memory setup" |
| 229 | def_bool y if COMPAT && KEYS | ||
| 230 | 316 | ||
| 231 | config AUDIT_ARCH | 317 | config ARCH_SPARSEMEM_ENABLE |
| 232 | def_bool y | 318 | def_bool y |
| 319 | select SPARSEMEM_VMEMMAP_ENABLE | ||
| 320 | select SPARSEMEM_VMEMMAP | ||
| 321 | select SPARSEMEM_STATIC if !64BIT | ||
| 233 | 322 | ||
| 234 | config HAVE_MARCH_Z900_FEATURES | 323 | config ARCH_SPARSEMEM_DEFAULT |
| 235 | def_bool n | 324 | def_bool y |
| 236 | |||
| 237 | config HAVE_MARCH_Z990_FEATURES | ||
| 238 | def_bool n | ||
| 239 | select HAVE_MARCH_Z900_FEATURES | ||
| 240 | |||
| 241 | config HAVE_MARCH_Z9_109_FEATURES | ||
| 242 | def_bool n | ||
| 243 | select HAVE_MARCH_Z990_FEATURES | ||
| 244 | |||
| 245 | config HAVE_MARCH_Z10_FEATURES | ||
| 246 | def_bool n | ||
| 247 | select HAVE_MARCH_Z9_109_FEATURES | ||
| 248 | |||
| 249 | config HAVE_MARCH_Z196_FEATURES | ||
| 250 | def_bool n | ||
| 251 | select HAVE_MARCH_Z10_FEATURES | ||
| 252 | |||
| 253 | comment "Code generation options" | ||
| 254 | |||
| 255 | choice | ||
| 256 | prompt "Processor type" | ||
| 257 | default MARCH_G5 | ||
| 258 | |||
| 259 | config MARCH_G5 | ||
| 260 | bool "System/390 model G5 and G6" | ||
| 261 | depends on !64BIT | ||
| 262 | help | ||
| 263 | Select this to build a 31 bit kernel that works | ||
| 264 | on all ESA/390 and z/Architecture machines. | ||
| 265 | |||
| 266 | config MARCH_Z900 | ||
| 267 | bool "IBM zSeries model z800 and z900" | ||
| 268 | select HAVE_MARCH_Z900_FEATURES if 64BIT | ||
| 269 | help | ||
| 270 | Select this to enable optimizations for model z800/z900 (2064 and | ||
| 271 | 2066 series). This will enable some optimizations that are not | ||
| 272 | available on older ESA/390 (31 Bit) only CPUs. | ||
| 273 | 325 | ||
| 274 | config MARCH_Z990 | 326 | config ARCH_SELECT_MEMORY_MODEL |
| 275 | bool "IBM zSeries model z890 and z990" | 327 | def_bool y |
| 276 | select HAVE_MARCH_Z990_FEATURES if 64BIT | ||
| 277 | help | ||
| 278 | Select this to enable optimizations for model z890/z990 (2084 and | ||
| 279 | 2086 series). The kernel will be slightly faster but will not work | ||
| 280 | on older machines. | ||
| 281 | 328 | ||
| 282 | config MARCH_Z9_109 | 329 | config ARCH_ENABLE_MEMORY_HOTPLUG |
| 283 | bool "IBM System z9" | 330 | def_bool y if SPARSEMEM |
| 284 | select HAVE_MARCH_Z9_109_FEATURES if 64BIT | ||
| 285 | help | ||
| 286 | Select this to enable optimizations for IBM System z9 (2094 and | ||
| 287 | 2096 series). The kernel will be slightly faster but will not work | ||
| 288 | on older machines. | ||
| 289 | 331 | ||
| 290 | config MARCH_Z10 | 332 | config ARCH_ENABLE_MEMORY_HOTREMOVE |
| 291 | bool "IBM System z10" | 333 | def_bool y |
| 292 | select HAVE_MARCH_Z10_FEATURES if 64BIT | ||
| 293 | help | ||
| 294 | Select this to enable optimizations for IBM System z10 (2097 and | ||
| 295 | 2098 series). The kernel will be slightly faster but will not work | ||
| 296 | on older machines. | ||
| 297 | 334 | ||
| 298 | config MARCH_Z196 | 335 | config FORCE_MAX_ZONEORDER |
| 299 | bool "IBM zEnterprise 114 and 196" | 336 | int |
| 300 | select HAVE_MARCH_Z196_FEATURES if 64BIT | 337 | default "9" |
| 301 | help | ||
| 302 | Select this to enable optimizations for IBM zEnterprise 114 and 196 | ||
| 303 | (2818 and 2817 series). The kernel will be slightly faster but will | ||
| 304 | not work on older machines. | ||
| 305 | 338 | ||
| 306 | endchoice | 339 | source "mm/Kconfig" |
| 307 | 340 | ||
| 308 | config PACK_STACK | 341 | config PACK_STACK |
| 309 | def_bool y | 342 | def_bool y |
| @@ -367,34 +400,9 @@ config WARN_DYNAMIC_STACK | |||
| 367 | 400 | ||
| 368 | Say N if you are unsure. | 401 | Say N if you are unsure. |
| 369 | 402 | ||
| 370 | comment "Kernel preemption" | 403 | endmenu |
| 371 | |||
| 372 | source "kernel/Kconfig.preempt" | ||
| 373 | |||
| 374 | config ARCH_SPARSEMEM_ENABLE | ||
| 375 | def_bool y | ||
| 376 | select SPARSEMEM_VMEMMAP_ENABLE | ||
| 377 | select SPARSEMEM_VMEMMAP | ||
| 378 | select SPARSEMEM_STATIC if !64BIT | ||
| 379 | |||
| 380 | config ARCH_SPARSEMEM_DEFAULT | ||
| 381 | def_bool y | ||
| 382 | |||
| 383 | config ARCH_SELECT_MEMORY_MODEL | ||
| 384 | def_bool y | ||
| 385 | |||
| 386 | config ARCH_ENABLE_MEMORY_HOTPLUG | ||
| 387 | def_bool y if SPARSEMEM | ||
| 388 | |||
| 389 | config ARCH_ENABLE_MEMORY_HOTREMOVE | ||
| 390 | def_bool y | ||
| 391 | |||
| 392 | config ARCH_HIBERNATION_POSSIBLE | ||
| 393 | def_bool y if 64BIT | ||
| 394 | |||
| 395 | source "mm/Kconfig" | ||
| 396 | 404 | ||
| 397 | comment "I/O subsystem configuration" | 405 | menu "I/O subsystem" |
| 398 | 406 | ||
| 399 | config QDIO | 407 | config QDIO |
| 400 | def_tristate y | 408 | def_tristate y |
| @@ -425,13 +433,102 @@ config CHSC_SCH | |||
| 425 | 433 | ||
| 426 | If unsure, say N. | 434 | If unsure, say N. |
| 427 | 435 | ||
| 428 | comment "Misc" | 436 | config SCM_BUS |
| 437 | def_bool y | ||
| 438 | depends on 64BIT | ||
| 439 | prompt "SCM bus driver" | ||
| 440 | help | ||
| 441 | Bus driver for Storage Class Memory. | ||
| 442 | |||
| 443 | config EADM_SCH | ||
| 444 | def_tristate m | ||
| 445 | prompt "Support for EADM subchannels" | ||
| 446 | depends on SCM_BUS | ||
| 447 | help | ||
| 448 | This driver allows usage of EADM subchannels. EADM subchannels act | ||
| 449 | as a communication vehicle for SCM increments. | ||
| 450 | |||
| 451 | To compile this driver as a module, choose M here: the | ||
| 452 | module will be called eadm_sch. | ||
| 453 | |||
| 454 | endmenu | ||
| 455 | |||
| 456 | menu "Dump support" | ||
| 457 | |||
| 458 | config CRASH_DUMP | ||
| 459 | bool "kernel crash dumps" | ||
| 460 | depends on 64BIT && SMP | ||
| 461 | select KEXEC | ||
| 462 | help | ||
| 463 | Generate crash dump after being started by kexec. | ||
| 464 | Crash dump kernels are loaded in the main kernel with kexec-tools | ||
| 465 | into a specially reserved region and then later executed after | ||
| 466 | a crash by kdump/kexec. | ||
| 467 | For more details see Documentation/kdump/kdump.txt | ||
| 468 | |||
| 469 | config ZFCPDUMP | ||
| 470 | def_bool n | ||
| 471 | prompt "zfcpdump support" | ||
| 472 | select SMP | ||
| 473 | help | ||
| 474 | Select this option if you want to build an zfcpdump enabled kernel. | ||
| 475 | Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this. | ||
| 476 | |||
| 477 | endmenu | ||
| 478 | |||
| 479 | menu "Executable file formats / Emulations" | ||
| 429 | 480 | ||
| 430 | source "fs/Kconfig.binfmt" | 481 | source "fs/Kconfig.binfmt" |
| 431 | 482 | ||
| 432 | config FORCE_MAX_ZONEORDER | 483 | config SECCOMP |
| 433 | int | 484 | def_bool y |
| 434 | default "9" | 485 | prompt "Enable seccomp to safely compute untrusted bytecode" |
| 486 | depends on PROC_FS | ||
| 487 | help | ||
| 488 | This kernel feature is useful for number crunching applications | ||
| 489 | that may need to compute untrusted bytecode during their | ||
| 490 | execution. By using pipes or other transports made available to | ||
| 491 | the process as file descriptors supporting the read/write | ||
| 492 | syscalls, it's possible to isolate those applications in | ||
| 493 | their own address space using seccomp. Once seccomp is | ||
| 494 | enabled via /proc/<pid>/seccomp, it cannot be disabled | ||
| 495 | and the task is only allowed to execute a few safe syscalls | ||
| 496 | defined by each seccomp mode. | ||
| 497 | |||
| 498 | If unsure, say Y. | ||
| 499 | |||
| 500 | endmenu | ||
| 501 | |||
| 502 | menu "Power Management" | ||
| 503 | |||
| 504 | config ARCH_HIBERNATION_POSSIBLE | ||
| 505 | def_bool y if 64BIT | ||
| 506 | |||
| 507 | source "kernel/power/Kconfig" | ||
| 508 | |||
| 509 | endmenu | ||
| 510 | |||
| 511 | source "net/Kconfig" | ||
| 512 | |||
| 513 | config PCMCIA | ||
| 514 | def_bool n | ||
| 515 | |||
| 516 | config CCW | ||
| 517 | def_bool y | ||
| 518 | |||
| 519 | source "drivers/Kconfig" | ||
| 520 | |||
| 521 | source "fs/Kconfig" | ||
| 522 | |||
| 523 | source "arch/s390/Kconfig.debug" | ||
| 524 | |||
| 525 | source "security/Kconfig" | ||
| 526 | |||
| 527 | source "crypto/Kconfig" | ||
| 528 | |||
| 529 | source "lib/Kconfig" | ||
| 530 | |||
| 531 | menu "Virtualization" | ||
| 435 | 532 | ||
| 436 | config PFAULT | 533 | config PFAULT |
| 437 | def_bool y | 534 | def_bool y |
| @@ -447,8 +544,8 @@ config PFAULT | |||
| 447 | this option. | 544 | this option. |
| 448 | 545 | ||
| 449 | config SHARED_KERNEL | 546 | config SHARED_KERNEL |
| 450 | def_bool y | 547 | bool "VM shared kernel support" |
| 451 | prompt "VM shared kernel support" | 548 | depends on !JUMP_LABEL |
| 452 | help | 549 | help |
| 453 | Select this option, if you want to share the text segment of the | 550 | Select this option, if you want to share the text segment of the |
| 454 | Linux kernel between different VM guests. This reduces memory | 551 | Linux kernel between different VM guests. This reduces memory |
| @@ -543,8 +640,6 @@ config APPLDATA_NET_SUM | |||
| 543 | This can also be compiled as a module, which will be called | 640 | This can also be compiled as a module, which will be called |
| 544 | appldata_net_sum.o. | 641 | appldata_net_sum.o. |
| 545 | 642 | ||
| 546 | source kernel/Kconfig.hz | ||
| 547 | |||
| 548 | config S390_HYPFS_FS | 643 | config S390_HYPFS_FS |
| 549 | def_bool y | 644 | def_bool y |
| 550 | prompt "s390 hypervisor file system support" | 645 | prompt "s390 hypervisor file system support" |
| @@ -553,90 +648,21 @@ config S390_HYPFS_FS | |||
| 553 | This is a virtual file system intended to provide accounting | 648 | This is a virtual file system intended to provide accounting |
| 554 | information in an s390 hypervisor environment. | 649 | information in an s390 hypervisor environment. |
| 555 | 650 | ||
| 556 | config KEXEC | 651 | source "arch/s390/kvm/Kconfig" |
| 557 | def_bool n | ||
| 558 | prompt "kexec system call" | ||
| 559 | help | ||
| 560 | kexec is a system call that implements the ability to shutdown your | ||
| 561 | current kernel, and to start another kernel. It is like a reboot | ||
| 562 | but is independent of hardware/microcode support. | ||
| 563 | |||
| 564 | config CRASH_DUMP | ||
| 565 | bool "kernel crash dumps" | ||
| 566 | depends on 64BIT && SMP | ||
| 567 | select KEXEC | ||
| 568 | help | ||
| 569 | Generate crash dump after being started by kexec. | ||
| 570 | Crash dump kernels are loaded in the main kernel with kexec-tools | ||
| 571 | into a specially reserved region and then later executed after | ||
| 572 | a crash by kdump/kexec. | ||
| 573 | For more details see Documentation/kdump/kdump.txt | ||
| 574 | |||
| 575 | config ZFCPDUMP | ||
| 576 | def_bool n | ||
| 577 | prompt "zfcpdump support" | ||
| 578 | select SMP | ||
| 579 | help | ||
| 580 | Select this option if you want to build an zfcpdump enabled kernel. | ||
| 581 | Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this. | ||
| 582 | 652 | ||
| 583 | config S390_GUEST | 653 | config S390_GUEST |
| 584 | def_bool y | 654 | def_bool y |
| 585 | prompt "s390 guest support for KVM (EXPERIMENTAL)" | 655 | prompt "s390 support for virtio devices (EXPERIMENTAL)" |
| 586 | depends on 64BIT && EXPERIMENTAL | 656 | depends on 64BIT && EXPERIMENTAL |
| 587 | select VIRTUALIZATION | 657 | select VIRTUALIZATION |
| 588 | select VIRTIO | 658 | select VIRTIO |
| 589 | select VIRTIO_RING | 659 | select VIRTIO_RING |
| 590 | select VIRTIO_CONSOLE | 660 | select VIRTIO_CONSOLE |
| 591 | help | 661 | help |
| 592 | Select this option if you want to run the kernel as a guest under | 662 | Enabling this option adds support for virtio based paravirtual device |
| 593 | the KVM hypervisor. This will add detection for KVM as well as a | 663 | drivers on s390. |
| 594 | virtio transport. If KVM is detected, the virtio console will be | ||
| 595 | the default console. | ||
| 596 | |||
| 597 | config SECCOMP | ||
| 598 | def_bool y | ||
| 599 | prompt "Enable seccomp to safely compute untrusted bytecode" | ||
| 600 | depends on PROC_FS | ||
| 601 | help | ||
| 602 | This kernel feature is useful for number crunching applications | ||
| 603 | that may need to compute untrusted bytecode during their | ||
| 604 | execution. By using pipes or other transports made available to | ||
| 605 | the process as file descriptors supporting the read/write | ||
| 606 | syscalls, it's possible to isolate those applications in | ||
| 607 | their own address space using seccomp. Once seccomp is | ||
| 608 | enabled via /proc/<pid>/seccomp, it cannot be disabled | ||
| 609 | and the task is only allowed to execute a few safe syscalls | ||
| 610 | defined by each seccomp mode. | ||
| 611 | |||
| 612 | If unsure, say Y. | ||
| 613 | |||
| 614 | endmenu | ||
| 615 | 664 | ||
| 616 | menu "Power Management" | 665 | Select this option if you want to run the kernel as a guest under |
| 617 | 666 | the KVM hypervisor. | |
| 618 | source "kernel/power/Kconfig" | ||
| 619 | 667 | ||
| 620 | endmenu | 668 | endmenu |
| 621 | |||
| 622 | source "net/Kconfig" | ||
| 623 | |||
| 624 | config PCMCIA | ||
| 625 | def_bool n | ||
| 626 | |||
| 627 | config CCW | ||
| 628 | def_bool y | ||
| 629 | |||
| 630 | source "drivers/Kconfig" | ||
| 631 | |||
| 632 | source "fs/Kconfig" | ||
| 633 | |||
| 634 | source "arch/s390/Kconfig.debug" | ||
| 635 | |||
| 636 | source "security/Kconfig" | ||
| 637 | |||
| 638 | source "crypto/Kconfig" | ||
| 639 | |||
| 640 | source "lib/Kconfig" | ||
| 641 | |||
| 642 | source "arch/s390/kvm/Kconfig" | ||
diff --git a/arch/s390/boot/compressed/Makefile b/arch/s390/boot/compressed/Makefile index 10e22c4ec4a7..3ad8f61c9985 100644 --- a/arch/s390/boot/compressed/Makefile +++ b/arch/s390/boot/compressed/Makefile | |||
| @@ -11,6 +11,7 @@ targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \ | |||
| 11 | sizes.h head$(BITS).o | 11 | sizes.h head$(BITS).o |
| 12 | 12 | ||
| 13 | KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 | 13 | KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 |
| 14 | KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING | ||
| 14 | KBUILD_CFLAGS += $(cflags-y) | 15 | KBUILD_CFLAGS += $(cflags-y) |
| 15 | KBUILD_CFLAGS += $(call cc-option,-mpacked-stack) | 16 | KBUILD_CFLAGS += $(call cc-option,-mpacked-stack) |
| 16 | KBUILD_CFLAGS += $(call cc-option,-ffreestanding) | 17 | KBUILD_CFLAGS += $(call cc-option,-ffreestanding) |
diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c index 465eca756feb..c4c6a1cf221b 100644 --- a/arch/s390/boot/compressed/misc.c +++ b/arch/s390/boot/compressed/misc.c | |||
| @@ -71,34 +71,37 @@ void *memset(void *s, int c, size_t n) | |||
| 71 | { | 71 | { |
| 72 | char *xs; | 72 | char *xs; |
| 73 | 73 | ||
| 74 | if (c == 0) | 74 | xs = s; |
| 75 | return __builtin_memset(s, 0, n); | 75 | while (n--) |
| 76 | 76 | *xs++ = c; | |
| 77 | xs = (char *) s; | ||
| 78 | if (n > 0) | ||
| 79 | do { | ||
| 80 | *xs++ = c; | ||
| 81 | } while (--n > 0); | ||
| 82 | return s; | 77 | return s; |
| 83 | } | 78 | } |
| 84 | 79 | ||
| 85 | void *memcpy(void *__dest, __const void *__src, size_t __n) | 80 | void *memcpy(void *dest, const void *src, size_t n) |
| 86 | { | 81 | { |
| 87 | return __builtin_memcpy(__dest, __src, __n); | 82 | const char *s = src; |
| 83 | char *d = dest; | ||
| 84 | |||
| 85 | while (n--) | ||
| 86 | *d++ = *s++; | ||
| 87 | return dest; | ||
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | void *memmove(void *__dest, __const void *__src, size_t __n) | 90 | void *memmove(void *dest, const void *src, size_t n) |
| 91 | { | 91 | { |
| 92 | char *d; | 92 | const char *s = src; |
| 93 | const char *s; | 93 | char *d = dest; |
| 94 | 94 | ||
| 95 | if (__dest <= __src) | 95 | if (d <= s) { |
| 96 | return __builtin_memcpy(__dest, __src, __n); | 96 | while (n--) |
| 97 | d = __dest + __n; | 97 | *d++ = *s++; |
| 98 | s = __src + __n; | 98 | } else { |
| 99 | while (__n--) | 99 | d += n; |
| 100 | *--d = *--s; | 100 | s += n; |
| 101 | return __dest; | 101 | while (n--) |
| 102 | *--d = *--s; | ||
| 103 | } | ||
| 104 | return dest; | ||
| 102 | } | 105 | } |
| 103 | 106 | ||
| 104 | static void error(char *x) | 107 | static void error(char *x) |
diff --git a/arch/s390/defconfig b/arch/s390/defconfig index f39cd710980b..b74400e3e035 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig | |||
| @@ -16,8 +16,8 @@ CONFIG_CGROUPS=y | |||
| 16 | CONFIG_CPUSETS=y | 16 | CONFIG_CPUSETS=y |
| 17 | CONFIG_CGROUP_CPUACCT=y | 17 | CONFIG_CGROUP_CPUACCT=y |
| 18 | CONFIG_RESOURCE_COUNTERS=y | 18 | CONFIG_RESOURCE_COUNTERS=y |
| 19 | CONFIG_CGROUP_MEMCG=y | 19 | CONFIG_MEMCG=y |
| 20 | CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y | 20 | CONFIG_MEMCG_SWAP=y |
| 21 | CONFIG_CGROUP_SCHED=y | 21 | CONFIG_CGROUP_SCHED=y |
| 22 | CONFIG_RT_GROUP_SCHED=y | 22 | CONFIG_RT_GROUP_SCHED=y |
| 23 | CONFIG_BLK_CGROUP=y | 23 | CONFIG_BLK_CGROUP=y |
| @@ -32,20 +32,19 @@ CONFIG_EXPERT=y | |||
| 32 | CONFIG_PROFILING=y | 32 | CONFIG_PROFILING=y |
| 33 | CONFIG_OPROFILE=y | 33 | CONFIG_OPROFILE=y |
| 34 | CONFIG_KPROBES=y | 34 | CONFIG_KPROBES=y |
| 35 | CONFIG_JUMP_LABEL=y | ||
| 35 | CONFIG_MODULES=y | 36 | CONFIG_MODULES=y |
| 36 | CONFIG_MODULE_UNLOAD=y | 37 | CONFIG_MODULE_UNLOAD=y |
| 37 | CONFIG_MODVERSIONS=y | 38 | CONFIG_MODVERSIONS=y |
| 38 | CONFIG_PARTITION_ADVANCED=y | 39 | CONFIG_PARTITION_ADVANCED=y |
| 39 | CONFIG_IBM_PARTITION=y | 40 | CONFIG_IBM_PARTITION=y |
| 40 | CONFIG_DEFAULT_DEADLINE=y | 41 | CONFIG_DEFAULT_DEADLINE=y |
| 41 | CONFIG_PREEMPT=y | 42 | CONFIG_HZ_100=y |
| 42 | CONFIG_MEMORY_HOTPLUG=y | 43 | CONFIG_MEMORY_HOTPLUG=y |
| 43 | CONFIG_MEMORY_HOTREMOVE=y | 44 | CONFIG_MEMORY_HOTREMOVE=y |
| 44 | CONFIG_KSM=y | 45 | CONFIG_KSM=y |
| 45 | CONFIG_BINFMT_MISC=m | ||
| 46 | CONFIG_CMM=m | ||
| 47 | CONFIG_HZ_100=y | ||
| 48 | CONFIG_CRASH_DUMP=y | 46 | CONFIG_CRASH_DUMP=y |
| 47 | CONFIG_BINFMT_MISC=m | ||
| 49 | CONFIG_HIBERNATION=y | 48 | CONFIG_HIBERNATION=y |
| 50 | CONFIG_PACKET=y | 49 | CONFIG_PACKET=y |
| 51 | CONFIG_UNIX=y | 50 | CONFIG_UNIX=y |
| @@ -75,6 +74,7 @@ CONFIG_NET_CLS_RSVP=m | |||
| 75 | CONFIG_NET_CLS_RSVP6=m | 74 | CONFIG_NET_CLS_RSVP6=m |
| 76 | CONFIG_NET_CLS_ACT=y | 75 | CONFIG_NET_CLS_ACT=y |
| 77 | CONFIG_NET_ACT_POLICE=y | 76 | CONFIG_NET_ACT_POLICE=y |
| 77 | CONFIG_BPF_JIT=y | ||
| 78 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | 78 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" |
| 79 | CONFIG_DEVTMPFS=y | 79 | CONFIG_DEVTMPFS=y |
| 80 | CONFIG_BLK_DEV_LOOP=m | 80 | CONFIG_BLK_DEV_LOOP=m |
| @@ -121,7 +121,6 @@ CONFIG_DEBUG_NOTIFIERS=y | |||
| 121 | CONFIG_RCU_TRACE=y | 121 | CONFIG_RCU_TRACE=y |
| 122 | CONFIG_KPROBES_SANITY_TEST=y | 122 | CONFIG_KPROBES_SANITY_TEST=y |
| 123 | CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y | 123 | CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y |
| 124 | CONFIG_CPU_NOTIFIER_ERROR_INJECT=m | ||
| 125 | CONFIG_LATENCYTOP=y | 124 | CONFIG_LATENCYTOP=y |
| 126 | CONFIG_DEBUG_PAGEALLOC=y | 125 | CONFIG_DEBUG_PAGEALLOC=y |
| 127 | CONFIG_BLK_DEV_IO_TRACE=y | 126 | CONFIG_BLK_DEV_IO_TRACE=y |
| @@ -173,3 +172,4 @@ CONFIG_CRYPTO_SHA512_S390=m | |||
| 173 | CONFIG_CRYPTO_DES_S390=m | 172 | CONFIG_CRYPTO_DES_S390=m |
| 174 | CONFIG_CRYPTO_AES_S390=m | 173 | CONFIG_CRYPTO_AES_S390=m |
| 175 | CONFIG_CRC7=m | 174 | CONFIG_CRC7=m |
| 175 | CONFIG_CMM=m | ||
diff --git a/arch/s390/include/asm/appldata.h b/arch/s390/include/asm/appldata.h index f328294faeae..32a705987156 100644 --- a/arch/s390/include/asm/appldata.h +++ b/arch/s390/include/asm/appldata.h | |||
| @@ -70,7 +70,7 @@ static inline int appldata_asm(struct appldata_product_id *id, | |||
| 70 | int ry; | 70 | int ry; |
| 71 | 71 | ||
| 72 | if (!MACHINE_IS_VM) | 72 | if (!MACHINE_IS_VM) |
| 73 | return -ENOSYS; | 73 | return -EOPNOTSUPP; |
| 74 | parm_list.diag = 0xdc; | 74 | parm_list.diag = 0xdc; |
| 75 | parm_list.function = fn; | 75 | parm_list.function = fn; |
| 76 | parm_list.parlist_length = sizeof(parm_list); | 76 | parm_list.parlist_length = sizeof(parm_list); |
diff --git a/arch/s390/include/asm/chsc.h b/arch/s390/include/asm/chsc.h index bf115b49f444..aea451fd182e 100644 --- a/arch/s390/include/asm/chsc.h +++ b/arch/s390/include/asm/chsc.h | |||
| @@ -125,32 +125,4 @@ struct chsc_cpd_info { | |||
| 125 | #define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info) | 125 | #define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info) |
| 126 | #define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal) | 126 | #define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal) |
| 127 | 127 | ||
| 128 | #ifdef __KERNEL__ | ||
| 129 | |||
| 130 | struct css_general_char { | ||
| 131 | u64 : 12; | ||
| 132 | u32 dynio : 1; /* bit 12 */ | ||
| 133 | u32 : 28; | ||
| 134 | u32 aif : 1; /* bit 41 */ | ||
| 135 | u32 : 3; | ||
| 136 | u32 mcss : 1; /* bit 45 */ | ||
| 137 | u32 fcs : 1; /* bit 46 */ | ||
| 138 | u32 : 1; | ||
| 139 | u32 ext_mb : 1; /* bit 48 */ | ||
| 140 | u32 : 7; | ||
| 141 | u32 aif_tdd : 1; /* bit 56 */ | ||
| 142 | u32 : 1; | ||
| 143 | u32 qebsm : 1; /* bit 58 */ | ||
| 144 | u32 : 8; | ||
| 145 | u32 aif_osa : 1; /* bit 67 */ | ||
| 146 | u32 : 14; | ||
| 147 | u32 cib : 1; /* bit 82 */ | ||
| 148 | u32 : 5; | ||
| 149 | u32 fcx : 1; /* bit 88 */ | ||
| 150 | u32 : 7; | ||
| 151 | }__attribute__((packed)); | ||
| 152 | |||
| 153 | extern struct css_general_char css_general_characteristics; | ||
| 154 | |||
| 155 | #endif /* __KERNEL__ */ | ||
| 156 | #endif | 128 | #endif |
diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h index 77043aa44d67..55bde6035216 100644 --- a/arch/s390/include/asm/cio.h +++ b/arch/s390/include/asm/cio.h | |||
| @@ -80,6 +80,18 @@ struct erw { | |||
| 80 | } __attribute__ ((packed)); | 80 | } __attribute__ ((packed)); |
| 81 | 81 | ||
| 82 | /** | 82 | /** |
| 83 | * struct erw_eadm - EADM Subchannel extended report word | ||
| 84 | * @b: aob error | ||
| 85 | * @r: arsb error | ||
| 86 | */ | ||
| 87 | struct erw_eadm { | ||
| 88 | __u32 : 16; | ||
| 89 | __u32 b : 1; | ||
| 90 | __u32 r : 1; | ||
| 91 | __u32 : 14; | ||
| 92 | } __packed; | ||
| 93 | |||
| 94 | /** | ||
| 83 | * struct sublog - subchannel logout area | 95 | * struct sublog - subchannel logout area |
| 84 | * @res0: reserved | 96 | * @res0: reserved |
| 85 | * @esf: extended status flags | 97 | * @esf: extended status flags |
| @@ -170,9 +182,22 @@ struct esw3 { | |||
| 170 | } __attribute__ ((packed)); | 182 | } __attribute__ ((packed)); |
| 171 | 183 | ||
| 172 | /** | 184 | /** |
| 185 | * struct esw_eadm - EADM Subchannel Extended Status Word (ESW) | ||
| 186 | * @sublog: subchannel logout | ||
| 187 | * @erw: extended report word | ||
| 188 | */ | ||
| 189 | struct esw_eadm { | ||
| 190 | __u32 sublog; | ||
| 191 | struct erw_eadm erw; | ||
| 192 | __u32 : 32; | ||
| 193 | __u32 : 32; | ||
| 194 | __u32 : 32; | ||
| 195 | } __packed; | ||
| 196 | |||
| 197 | /** | ||
| 173 | * struct irb - interruption response block | 198 | * struct irb - interruption response block |
| 174 | * @scsw: subchannel status word | 199 | * @scsw: subchannel status word |
| 175 | * @esw: extened status word, 4 formats | 200 | * @esw: extened status word |
| 176 | * @ecw: extended control word | 201 | * @ecw: extended control word |
| 177 | * | 202 | * |
| 178 | * The irb that is handed to the device driver when an interrupt occurs. For | 203 | * The irb that is handed to the device driver when an interrupt occurs. For |
| @@ -191,6 +216,7 @@ struct irb { | |||
| 191 | struct esw1 esw1; | 216 | struct esw1 esw1; |
| 192 | struct esw2 esw2; | 217 | struct esw2 esw2; |
| 193 | struct esw3 esw3; | 218 | struct esw3 esw3; |
| 219 | struct esw_eadm eadm; | ||
| 194 | } esw; | 220 | } esw; |
| 195 | __u8 ecw[32]; | 221 | __u8 ecw[32]; |
| 196 | } __attribute__ ((packed,aligned(4))); | 222 | } __attribute__ ((packed,aligned(4))); |
diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h index 8d798e962b63..0f636cbdf342 100644 --- a/arch/s390/include/asm/cmpxchg.h +++ b/arch/s390/include/asm/cmpxchg.h | |||
| @@ -7,7 +7,9 @@ | |||
| 7 | #ifndef __ASM_CMPXCHG_H | 7 | #ifndef __ASM_CMPXCHG_H |
| 8 | #define __ASM_CMPXCHG_H | 8 | #define __ASM_CMPXCHG_H |
| 9 | 9 | ||
| 10 | #include <linux/mmdebug.h> | ||
| 10 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 12 | #include <linux/bug.h> | ||
| 11 | 13 | ||
| 12 | extern void __xchg_called_with_bad_pointer(void); | 14 | extern void __xchg_called_with_bad_pointer(void); |
| 13 | 15 | ||
| @@ -203,6 +205,65 @@ static inline unsigned long long __cmpxchg64(void *ptr, | |||
| 203 | }) | 205 | }) |
| 204 | #endif /* CONFIG_64BIT */ | 206 | #endif /* CONFIG_64BIT */ |
| 205 | 207 | ||
| 208 | #define __cmpxchg_double_op(p1, p2, o1, o2, n1, n2, insn) \ | ||
| 209 | ({ \ | ||
| 210 | register __typeof__(*(p1)) __old1 asm("2") = (o1); \ | ||
| 211 | register __typeof__(*(p2)) __old2 asm("3") = (o2); \ | ||
| 212 | register __typeof__(*(p1)) __new1 asm("4") = (n1); \ | ||
| 213 | register __typeof__(*(p2)) __new2 asm("5") = (n2); \ | ||
| 214 | int cc; \ | ||
| 215 | asm volatile( \ | ||
| 216 | insn " %[old],%[new],%[ptr]\n" \ | ||
| 217 | " ipm %[cc]\n" \ | ||
| 218 | " srl %[cc],28" \ | ||
| 219 | : [cc] "=d" (cc), [old] "+d" (__old1), "+d" (__old2) \ | ||
| 220 | : [new] "d" (__new1), "d" (__new2), \ | ||
| 221 | [ptr] "Q" (*(p1)), "Q" (*(p2)) \ | ||
| 222 | : "memory", "cc"); \ | ||
| 223 | !cc; \ | ||
| 224 | }) | ||
| 225 | |||
| 226 | #define __cmpxchg_double_4(p1, p2, o1, o2, n1, n2) \ | ||
| 227 | __cmpxchg_double_op(p1, p2, o1, o2, n1, n2, "cds") | ||
| 228 | |||
| 229 | #define __cmpxchg_double_8(p1, p2, o1, o2, n1, n2) \ | ||
| 230 | __cmpxchg_double_op(p1, p2, o1, o2, n1, n2, "cdsg") | ||
| 231 | |||
| 232 | extern void __cmpxchg_double_called_with_bad_pointer(void); | ||
| 233 | |||
| 234 | #define __cmpxchg_double(p1, p2, o1, o2, n1, n2) \ | ||
| 235 | ({ \ | ||
| 236 | int __ret; \ | ||
| 237 | switch (sizeof(*(p1))) { \ | ||
| 238 | case 4: \ | ||
| 239 | __ret = __cmpxchg_double_4(p1, p2, o1, o2, n1, n2); \ | ||
| 240 | break; \ | ||
| 241 | case 8: \ | ||
| 242 | __ret = __cmpxchg_double_8(p1, p2, o1, o2, n1, n2); \ | ||
| 243 | break; \ | ||
| 244 | default: \ | ||
| 245 | __cmpxchg_double_called_with_bad_pointer(); \ | ||
| 246 | } \ | ||
| 247 | __ret; \ | ||
| 248 | }) | ||
| 249 | |||
| 250 | #define cmpxchg_double(p1, p2, o1, o2, n1, n2) \ | ||
| 251 | ({ \ | ||
| 252 | __typeof__(p1) __p1 = (p1); \ | ||
| 253 | __typeof__(p2) __p2 = (p2); \ | ||
| 254 | int __ret; \ | ||
| 255 | BUILD_BUG_ON(sizeof(*(p1)) != sizeof(long)); \ | ||
| 256 | BUILD_BUG_ON(sizeof(*(p2)) != sizeof(long)); \ | ||
| 257 | VM_BUG_ON((unsigned long)((__p1) + 1) != (unsigned long)(__p2));\ | ||
| 258 | if (sizeof(long) == 4) \ | ||
| 259 | __ret = __cmpxchg_double_4(__p1, __p2, o1, o2, n1, n2); \ | ||
| 260 | else \ | ||
| 261 | __ret = __cmpxchg_double_8(__p1, __p2, o1, o2, n1, n2); \ | ||
| 262 | __ret; \ | ||
| 263 | }) | ||
| 264 | |||
| 265 | #define system_has_cmpxchg_double() 1 | ||
| 266 | |||
| 206 | #include <asm-generic/cmpxchg-local.h> | 267 | #include <asm-generic/cmpxchg-local.h> |
| 207 | 268 | ||
| 208 | static inline unsigned long __cmpxchg_local(void *ptr, | 269 | static inline unsigned long __cmpxchg_local(void *ptr, |
diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index a3afecdae145..35f0020b7ba7 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h | |||
| @@ -21,11 +21,15 @@ | |||
| 21 | #define CPU_MF_INT_SF_LSDA (1 << 22) /* loss of sample data alert */ | 21 | #define CPU_MF_INT_SF_LSDA (1 << 22) /* loss of sample data alert */ |
| 22 | #define CPU_MF_INT_CF_CACA (1 << 7) /* counter auth. change alert */ | 22 | #define CPU_MF_INT_CF_CACA (1 << 7) /* counter auth. change alert */ |
| 23 | #define CPU_MF_INT_CF_LCDA (1 << 6) /* loss of counter data alert */ | 23 | #define CPU_MF_INT_CF_LCDA (1 << 6) /* loss of counter data alert */ |
| 24 | #define CPU_MF_INT_RI_HALTED (1 << 5) /* run-time instr. halted */ | ||
| 25 | #define CPU_MF_INT_RI_BUF_FULL (1 << 4) /* run-time instr. program | ||
| 26 | buffer full */ | ||
| 24 | 27 | ||
| 25 | #define CPU_MF_INT_CF_MASK (CPU_MF_INT_CF_CACA|CPU_MF_INT_CF_LCDA) | 28 | #define CPU_MF_INT_CF_MASK (CPU_MF_INT_CF_CACA|CPU_MF_INT_CF_LCDA) |
| 26 | #define CPU_MF_INT_SF_MASK (CPU_MF_INT_SF_IAE|CPU_MF_INT_SF_ISE| \ | 29 | #define CPU_MF_INT_SF_MASK (CPU_MF_INT_SF_IAE|CPU_MF_INT_SF_ISE| \ |
| 27 | CPU_MF_INT_SF_PRA|CPU_MF_INT_SF_SACA| \ | 30 | CPU_MF_INT_SF_PRA|CPU_MF_INT_SF_SACA| \ |
| 28 | CPU_MF_INT_SF_LSDA) | 31 | CPU_MF_INT_SF_LSDA) |
| 32 | #define CPU_MF_INT_RI_MASK (CPU_MF_INT_RI_HALTED|CPU_MF_INT_RI_BUF_FULL) | ||
| 29 | 33 | ||
| 30 | /* CPU measurement facility support */ | 34 | /* CPU measurement facility support */ |
| 31 | static inline int cpum_cf_avail(void) | 35 | static inline int cpum_cf_avail(void) |
diff --git a/arch/s390/include/asm/css_chars.h b/arch/s390/include/asm/css_chars.h new file mode 100644 index 000000000000..a06ebc2623fb --- /dev/null +++ b/arch/s390/include/asm/css_chars.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | #ifndef _ASM_CSS_CHARS_H | ||
| 2 | #define _ASM_CSS_CHARS_H | ||
| 3 | |||
| 4 | #include <linux/types.h> | ||
| 5 | |||
| 6 | #ifdef __KERNEL__ | ||
| 7 | |||
| 8 | struct css_general_char { | ||
| 9 | u64 : 12; | ||
| 10 | u32 dynio : 1; /* bit 12 */ | ||
| 11 | u32 : 4; | ||
| 12 | u32 eadm : 1; /* bit 17 */ | ||
| 13 | u32 : 23; | ||
| 14 | u32 aif : 1; /* bit 41 */ | ||
| 15 | u32 : 3; | ||
| 16 | u32 mcss : 1; /* bit 45 */ | ||
| 17 | u32 fcs : 1; /* bit 46 */ | ||
| 18 | u32 : 1; | ||
| 19 | u32 ext_mb : 1; /* bit 48 */ | ||
| 20 | u32 : 7; | ||
| 21 | u32 aif_tdd : 1; /* bit 56 */ | ||
| 22 | u32 : 1; | ||
| 23 | u32 qebsm : 1; /* bit 58 */ | ||
| 24 | u32 : 8; | ||
| 25 | u32 aif_osa : 1; /* bit 67 */ | ||
| 26 | u32 : 12; | ||
| 27 | u32 eadm_rf : 1; /* bit 80 */ | ||
| 28 | u32 : 1; | ||
| 29 | u32 cib : 1; /* bit 82 */ | ||
| 30 | u32 : 5; | ||
| 31 | u32 fcx : 1; /* bit 88 */ | ||
| 32 | u32 : 19; | ||
| 33 | u32 alt_ssi : 1; /* bit 108 */ | ||
| 34 | } __packed; | ||
| 35 | |||
| 36 | extern struct css_general_char css_general_characteristics; | ||
| 37 | |||
| 38 | #endif /* __KERNEL__ */ | ||
| 39 | #endif | ||
diff --git a/arch/s390/include/asm/eadm.h b/arch/s390/include/asm/eadm.h new file mode 100644 index 000000000000..8d4847191ecc --- /dev/null +++ b/arch/s390/include/asm/eadm.h | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | #ifndef _ASM_S390_EADM_H | ||
| 2 | #define _ASM_S390_EADM_H | ||
| 3 | |||
| 4 | #include <linux/types.h> | ||
| 5 | #include <linux/device.h> | ||
| 6 | |||
| 7 | struct arqb { | ||
| 8 | u64 data; | ||
| 9 | u16 fmt:4; | ||
| 10 | u16:12; | ||
| 11 | u16 cmd_code; | ||
| 12 | u16:16; | ||
| 13 | u16 msb_count; | ||
| 14 | u32 reserved[12]; | ||
| 15 | } __packed; | ||
| 16 | |||
| 17 | #define ARQB_CMD_MOVE 1 | ||
| 18 | |||
| 19 | struct arsb { | ||
| 20 | u16 fmt:4; | ||
| 21 | u32:28; | ||
| 22 | u8 ef; | ||
| 23 | u8:8; | ||
| 24 | u8 ecbi; | ||
| 25 | u8:8; | ||
| 26 | u8 fvf; | ||
| 27 | u16:16; | ||
| 28 | u8 eqc; | ||
| 29 | u32:32; | ||
| 30 | u64 fail_msb; | ||
| 31 | u64 fail_aidaw; | ||
| 32 | u64 fail_ms; | ||
| 33 | u64 fail_scm; | ||
| 34 | u32 reserved[4]; | ||
| 35 | } __packed; | ||
| 36 | |||
| 37 | struct msb { | ||
| 38 | u8 fmt:4; | ||
| 39 | u8 oc:4; | ||
| 40 | u8 flags; | ||
| 41 | u16:12; | ||
| 42 | u16 bs:4; | ||
| 43 | u32 blk_count; | ||
| 44 | u64 data_addr; | ||
| 45 | u64 scm_addr; | ||
| 46 | u64:64; | ||
| 47 | } __packed; | ||
| 48 | |||
| 49 | struct aidaw { | ||
| 50 | u8 flags; | ||
| 51 | u32 :24; | ||
| 52 | u32 :32; | ||
| 53 | u64 data_addr; | ||
| 54 | } __packed; | ||
| 55 | |||
| 56 | #define MSB_OC_CLEAR 0 | ||
| 57 | #define MSB_OC_READ 1 | ||
| 58 | #define MSB_OC_WRITE 2 | ||
| 59 | #define MSB_OC_RELEASE 3 | ||
| 60 | |||
| 61 | #define MSB_FLAG_BNM 0x80 | ||
| 62 | #define MSB_FLAG_IDA 0x40 | ||
| 63 | |||
| 64 | #define MSB_BS_4K 0 | ||
| 65 | #define MSB_BS_1M 1 | ||
| 66 | |||
| 67 | #define AOB_NR_MSB 124 | ||
| 68 | |||
| 69 | struct aob { | ||
| 70 | struct arqb request; | ||
| 71 | struct arsb response; | ||
| 72 | struct msb msb[AOB_NR_MSB]; | ||
| 73 | } __packed __aligned(PAGE_SIZE); | ||
| 74 | |||
| 75 | struct aob_rq_header { | ||
| 76 | struct scm_device *scmdev; | ||
| 77 | char data[0]; | ||
| 78 | }; | ||
| 79 | |||
| 80 | struct scm_device { | ||
| 81 | u64 address; | ||
| 82 | u64 size; | ||
| 83 | unsigned int nr_max_block; | ||
| 84 | struct device dev; | ||
| 85 | struct { | ||
| 86 | unsigned int persistence:4; | ||
| 87 | unsigned int oper_state:4; | ||
| 88 | unsigned int data_state:4; | ||
| 89 | unsigned int rank:4; | ||
| 90 | unsigned int release:1; | ||
| 91 | unsigned int res_id:8; | ||
| 92 | } __packed attrs; | ||
| 93 | }; | ||
| 94 | |||
| 95 | #define OP_STATE_GOOD 1 | ||
| 96 | #define OP_STATE_TEMP_ERR 2 | ||
| 97 | #define OP_STATE_PERM_ERR 3 | ||
| 98 | |||
| 99 | struct scm_driver { | ||
| 100 | struct device_driver drv; | ||
| 101 | int (*probe) (struct scm_device *scmdev); | ||
| 102 | int (*remove) (struct scm_device *scmdev); | ||
| 103 | void (*notify) (struct scm_device *scmdev); | ||
| 104 | void (*handler) (struct scm_device *scmdev, void *data, int error); | ||
| 105 | }; | ||
| 106 | |||
| 107 | int scm_driver_register(struct scm_driver *scmdrv); | ||
| 108 | void scm_driver_unregister(struct scm_driver *scmdrv); | ||
| 109 | |||
| 110 | int scm_start_aob(struct aob *aob); | ||
| 111 | void scm_irq_handler(struct aob *aob, int error); | ||
| 112 | |||
| 113 | struct eadm_ops { | ||
| 114 | int (*eadm_start) (struct aob *aob); | ||
| 115 | struct module *owner; | ||
| 116 | }; | ||
| 117 | |||
| 118 | int scm_get_ref(void); | ||
| 119 | void scm_put_ref(void); | ||
| 120 | |||
| 121 | void register_eadm_ops(struct eadm_ops *ops); | ||
| 122 | void unregister_eadm_ops(struct eadm_ops *ops); | ||
| 123 | |||
| 124 | #endif /* _ASM_S390_EADM_H */ | ||
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 9b94a160fe7f..178ff966a8ba 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h | |||
| @@ -101,6 +101,7 @@ | |||
| 101 | #define HWCAP_S390_HPAGE 128 | 101 | #define HWCAP_S390_HPAGE 128 |
| 102 | #define HWCAP_S390_ETF3EH 256 | 102 | #define HWCAP_S390_ETF3EH 256 |
| 103 | #define HWCAP_S390_HIGH_GPRS 512 | 103 | #define HWCAP_S390_HIGH_GPRS 512 |
| 104 | #define HWCAP_S390_TE 1024 | ||
| 104 | 105 | ||
| 105 | /* | 106 | /* |
| 106 | * These are used to set parameters in the core dumps. | 107 | * These are used to set parameters in the core dumps. |
| @@ -212,4 +213,6 @@ int arch_setup_additional_pages(struct linux_binprm *, int); | |||
| 212 | extern unsigned long arch_randomize_brk(struct mm_struct *mm); | 213 | extern unsigned long arch_randomize_brk(struct mm_struct *mm); |
| 213 | #define arch_randomize_brk arch_randomize_brk | 214 | #define arch_randomize_brk arch_randomize_brk |
| 214 | 215 | ||
| 216 | void *fill_cpu_elf_notes(void *ptr, struct save_area *sa); | ||
| 217 | |||
| 215 | #endif | 218 | #endif |
diff --git a/arch/s390/include/asm/etr.h b/arch/s390/include/asm/etr.h index a24b03b9fb64..629b79a93165 100644 --- a/arch/s390/include/asm/etr.h +++ b/arch/s390/include/asm/etr.h | |||
| @@ -140,7 +140,7 @@ struct etr_ptff_qto { | |||
| 140 | /* Inline assembly helper functions */ | 140 | /* Inline assembly helper functions */ |
| 141 | static inline int etr_setr(struct etr_eacr *ctrl) | 141 | static inline int etr_setr(struct etr_eacr *ctrl) |
| 142 | { | 142 | { |
| 143 | int rc = -ENOSYS; | 143 | int rc = -EOPNOTSUPP; |
| 144 | 144 | ||
| 145 | asm volatile( | 145 | asm volatile( |
| 146 | " .insn s,0xb2160000,%1\n" | 146 | " .insn s,0xb2160000,%1\n" |
| @@ -154,7 +154,7 @@ static inline int etr_setr(struct etr_eacr *ctrl) | |||
| 154 | /* Stores a format 1 aib with 64 bytes */ | 154 | /* Stores a format 1 aib with 64 bytes */ |
| 155 | static inline int etr_stetr(struct etr_aib *aib) | 155 | static inline int etr_stetr(struct etr_aib *aib) |
| 156 | { | 156 | { |
| 157 | int rc = -ENOSYS; | 157 | int rc = -EOPNOTSUPP; |
| 158 | 158 | ||
| 159 | asm volatile( | 159 | asm volatile( |
| 160 | " .insn s,0xb2170000,%1\n" | 160 | " .insn s,0xb2170000,%1\n" |
| @@ -169,7 +169,7 @@ static inline int etr_stetr(struct etr_aib *aib) | |||
| 169 | static inline int etr_steai(struct etr_aib *aib, unsigned int func) | 169 | static inline int etr_steai(struct etr_aib *aib, unsigned int func) |
| 170 | { | 170 | { |
| 171 | register unsigned int reg0 asm("0") = func; | 171 | register unsigned int reg0 asm("0") = func; |
| 172 | int rc = -ENOSYS; | 172 | int rc = -EOPNOTSUPP; |
| 173 | 173 | ||
| 174 | asm volatile( | 174 | asm volatile( |
| 175 | " .insn s,0xb2b30000,%1\n" | 175 | " .insn s,0xb2b30000,%1\n" |
| @@ -190,7 +190,7 @@ static inline int etr_ptff(void *ptff_block, unsigned int func) | |||
| 190 | { | 190 | { |
| 191 | register unsigned int reg0 asm("0") = func; | 191 | register unsigned int reg0 asm("0") = func; |
| 192 | register unsigned long reg1 asm("1") = (unsigned long) ptff_block; | 192 | register unsigned long reg1 asm("1") = (unsigned long) ptff_block; |
| 193 | int rc = -ENOSYS; | 193 | int rc = -EOPNOTSUPP; |
| 194 | 194 | ||
| 195 | asm volatile( | 195 | asm volatile( |
| 196 | " .word 0x0104\n" | 196 | " .word 0x0104\n" |
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index 2b9d41899d21..6703dd986fd4 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h | |||
| @@ -19,6 +19,7 @@ enum interruption_class { | |||
| 19 | EXTINT_IUC, | 19 | EXTINT_IUC, |
| 20 | EXTINT_CMS, | 20 | EXTINT_CMS, |
| 21 | EXTINT_CMC, | 21 | EXTINT_CMC, |
| 22 | EXTINT_CMR, | ||
| 22 | IOINT_CIO, | 23 | IOINT_CIO, |
| 23 | IOINT_QAI, | 24 | IOINT_QAI, |
| 24 | IOINT_DAS, | 25 | IOINT_DAS, |
| @@ -30,6 +31,7 @@ enum interruption_class { | |||
| 30 | IOINT_CLW, | 31 | IOINT_CLW, |
| 31 | IOINT_CTC, | 32 | IOINT_CTC, |
| 32 | IOINT_APB, | 33 | IOINT_APB, |
| 34 | IOINT_ADM, | ||
| 33 | IOINT_CSC, | 35 | IOINT_CSC, |
| 34 | NMI_NMI, | 36 | NMI_NMI, |
| 35 | NR_IRQS, | 37 | NR_IRQS, |
diff --git a/arch/s390/include/asm/isc.h b/arch/s390/include/asm/isc.h index 1420a1115948..5ae606456b0a 100644 --- a/arch/s390/include/asm/isc.h +++ b/arch/s390/include/asm/isc.h | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | /* Regular I/O interrupts. */ | 14 | /* Regular I/O interrupts. */ |
| 15 | #define IO_SCH_ISC 3 /* regular I/O subchannels */ | 15 | #define IO_SCH_ISC 3 /* regular I/O subchannels */ |
| 16 | #define CONSOLE_ISC 1 /* console I/O subchannel */ | 16 | #define CONSOLE_ISC 1 /* console I/O subchannel */ |
| 17 | #define EADM_SCH_ISC 4 /* EADM subchannels */ | ||
| 17 | #define CHSC_SCH_ISC 7 /* CHSC subchannels */ | 18 | #define CHSC_SCH_ISC 7 /* CHSC subchannels */ |
| 18 | /* Adapter interrupts. */ | 19 | /* Adapter interrupts. */ |
| 19 | #define QDIO_AIRQ_ISC IO_SCH_ISC /* I/O subchannel in qdio mode */ | 20 | #define QDIO_AIRQ_ISC IO_SCH_ISC /* I/O subchannel in qdio mode */ |
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index aab5555bbbda..bbf8141408cd 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
| @@ -329,9 +329,13 @@ struct _lowcore { | |||
| 329 | __u8 pad_0x1338[0x1340-0x1338]; /* 0x1338 */ | 329 | __u8 pad_0x1338[0x1340-0x1338]; /* 0x1338 */ |
| 330 | __u32 access_regs_save_area[16]; /* 0x1340 */ | 330 | __u32 access_regs_save_area[16]; /* 0x1340 */ |
| 331 | __u64 cregs_save_area[16]; /* 0x1380 */ | 331 | __u64 cregs_save_area[16]; /* 0x1380 */ |
| 332 | __u8 pad_0x1400[0x1800-0x1400]; /* 0x1400 */ | ||
| 333 | |||
| 334 | /* Transaction abort diagnostic block */ | ||
| 335 | __u8 pgm_tdb[256]; /* 0x1800 */ | ||
| 332 | 336 | ||
| 333 | /* align to the top of the prefix area */ | 337 | /* align to the top of the prefix area */ |
| 334 | __u8 pad_0x1400[0x2000-0x1400]; /* 0x1400 */ | 338 | __u8 pad_0x1900[0x2000-0x1900]; /* 0x1900 */ |
| 335 | } __packed; | 339 | } __packed; |
| 336 | 340 | ||
| 337 | #endif /* CONFIG_32BIT */ | 341 | #endif /* CONFIG_32BIT */ |
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index b749c5733657..084e7755ed9b 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h | |||
| @@ -57,7 +57,7 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk) | |||
| 57 | pgd_t *pgd = mm->pgd; | 57 | pgd_t *pgd = mm->pgd; |
| 58 | 58 | ||
| 59 | S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd); | 59 | S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd); |
| 60 | if (addressing_mode != HOME_SPACE_MODE) { | 60 | if (s390_user_mode != HOME_SPACE_MODE) { |
| 61 | /* Load primary space page table origin. */ | 61 | /* Load primary space page table origin. */ |
| 62 | asm volatile(LCTL_OPCODE" 1,1,%0\n" | 62 | asm volatile(LCTL_OPCODE" 1,1,%0\n" |
| 63 | : : "m" (S390_lowcore.user_asce) ); | 63 | : : "m" (S390_lowcore.user_asce) ); |
diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h index 6537e72e0853..86fe0ee2cee5 100644 --- a/arch/s390/include/asm/percpu.h +++ b/arch/s390/include/asm/percpu.h | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | #endif | 20 | #endif |
| 21 | 21 | ||
| 22 | #define arch_this_cpu_to_op(pcp, val, op) \ | 22 | #define arch_this_cpu_to_op(pcp, val, op) \ |
| 23 | do { \ | 23 | ({ \ |
| 24 | typedef typeof(pcp) pcp_op_T__; \ | 24 | typedef typeof(pcp) pcp_op_T__; \ |
| 25 | pcp_op_T__ old__, new__, prev__; \ | 25 | pcp_op_T__ old__, new__, prev__; \ |
| 26 | pcp_op_T__ *ptr__; \ | 26 | pcp_op_T__ *ptr__; \ |
| @@ -39,13 +39,19 @@ do { \ | |||
| 39 | } \ | 39 | } \ |
| 40 | } while (prev__ != old__); \ | 40 | } while (prev__ != old__); \ |
| 41 | preempt_enable(); \ | 41 | preempt_enable(); \ |
| 42 | } while (0) | 42 | new__; \ |
| 43 | }) | ||
| 43 | 44 | ||
| 44 | #define this_cpu_add_1(pcp, val) arch_this_cpu_to_op(pcp, val, +) | 45 | #define this_cpu_add_1(pcp, val) arch_this_cpu_to_op(pcp, val, +) |
| 45 | #define this_cpu_add_2(pcp, val) arch_this_cpu_to_op(pcp, val, +) | 46 | #define this_cpu_add_2(pcp, val) arch_this_cpu_to_op(pcp, val, +) |
| 46 | #define this_cpu_add_4(pcp, val) arch_this_cpu_to_op(pcp, val, +) | 47 | #define this_cpu_add_4(pcp, val) arch_this_cpu_to_op(pcp, val, +) |
| 47 | #define this_cpu_add_8(pcp, val) arch_this_cpu_to_op(pcp, val, +) | 48 | #define this_cpu_add_8(pcp, val) arch_this_cpu_to_op(pcp, val, +) |
| 48 | 49 | ||
| 50 | #define this_cpu_add_return_1(pcp, val) arch_this_cpu_to_op(pcp, val, +) | ||
| 51 | #define this_cpu_add_return_2(pcp, val) arch_this_cpu_to_op(pcp, val, +) | ||
| 52 | #define this_cpu_add_return_4(pcp, val) arch_this_cpu_to_op(pcp, val, +) | ||
| 53 | #define this_cpu_add_return_8(pcp, val) arch_this_cpu_to_op(pcp, val, +) | ||
| 54 | |||
| 49 | #define this_cpu_and_1(pcp, val) arch_this_cpu_to_op(pcp, val, &) | 55 | #define this_cpu_and_1(pcp, val) arch_this_cpu_to_op(pcp, val, &) |
| 50 | #define this_cpu_and_2(pcp, val) arch_this_cpu_to_op(pcp, val, &) | 56 | #define this_cpu_and_2(pcp, val) arch_this_cpu_to_op(pcp, val, &) |
| 51 | #define this_cpu_and_4(pcp, val) arch_this_cpu_to_op(pcp, val, &) | 57 | #define this_cpu_and_4(pcp, val) arch_this_cpu_to_op(pcp, val, &) |
| @@ -61,7 +67,7 @@ do { \ | |||
| 61 | #define this_cpu_xor_4(pcp, val) arch_this_cpu_to_op(pcp, val, ^) | 67 | #define this_cpu_xor_4(pcp, val) arch_this_cpu_to_op(pcp, val, ^) |
| 62 | #define this_cpu_xor_8(pcp, val) arch_this_cpu_to_op(pcp, val, ^) | 68 | #define this_cpu_xor_8(pcp, val) arch_this_cpu_to_op(pcp, val, ^) |
| 63 | 69 | ||
| 64 | #define arch_this_cpu_cmpxchg(pcp, oval, nval) \ | 70 | #define arch_this_cpu_cmpxchg(pcp, oval, nval) \ |
| 65 | ({ \ | 71 | ({ \ |
| 66 | typedef typeof(pcp) pcp_op_T__; \ | 72 | typedef typeof(pcp) pcp_op_T__; \ |
| 67 | pcp_op_T__ ret__; \ | 73 | pcp_op_T__ ret__; \ |
| @@ -84,6 +90,44 @@ do { \ | |||
| 84 | #define this_cpu_cmpxchg_4(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval) | 90 | #define this_cpu_cmpxchg_4(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval) |
| 85 | #define this_cpu_cmpxchg_8(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval) | 91 | #define this_cpu_cmpxchg_8(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval) |
| 86 | 92 | ||
| 93 | #define arch_this_cpu_xchg(pcp, nval) \ | ||
| 94 | ({ \ | ||
| 95 | typeof(pcp) *ptr__; \ | ||
| 96 | typeof(pcp) ret__; \ | ||
| 97 | preempt_disable(); \ | ||
| 98 | ptr__ = __this_cpu_ptr(&(pcp)); \ | ||
| 99 | ret__ = xchg(ptr__, nval); \ | ||
| 100 | preempt_enable(); \ | ||
| 101 | ret__; \ | ||
| 102 | }) | ||
| 103 | |||
| 104 | #define this_cpu_xchg_1(pcp, nval) arch_this_cpu_xchg(pcp, nval) | ||
| 105 | #define this_cpu_xchg_2(pcp, nval) arch_this_cpu_xchg(pcp, nval) | ||
| 106 | #define this_cpu_xchg_4(pcp, nval) arch_this_cpu_xchg(pcp, nval) | ||
| 107 | #ifdef CONFIG_64BIT | ||
| 108 | #define this_cpu_xchg_8(pcp, nval) arch_this_cpu_xchg(pcp, nval) | ||
| 109 | #endif | ||
| 110 | |||
| 111 | #define arch_this_cpu_cmpxchg_double(pcp1, pcp2, o1, o2, n1, n2) \ | ||
| 112 | ({ \ | ||
| 113 | typeof(pcp1) o1__ = (o1), n1__ = (n1); \ | ||
| 114 | typeof(pcp2) o2__ = (o2), n2__ = (n2); \ | ||
| 115 | typeof(pcp1) *p1__; \ | ||
| 116 | typeof(pcp2) *p2__; \ | ||
| 117 | int ret__; \ | ||
| 118 | preempt_disable(); \ | ||
| 119 | p1__ = __this_cpu_ptr(&(pcp1)); \ | ||
| 120 | p2__ = __this_cpu_ptr(&(pcp2)); \ | ||
| 121 | ret__ = __cmpxchg_double(p1__, p2__, o1__, o2__, n1__, n2__); \ | ||
| 122 | preempt_enable(); \ | ||
| 123 | ret__; \ | ||
| 124 | }) | ||
| 125 | |||
| 126 | #define this_cpu_cmpxchg_double_4 arch_this_cpu_cmpxchg_double | ||
| 127 | #ifdef CONFIG_64BIT | ||
| 128 | #define this_cpu_cmpxchg_double_8 arch_this_cpu_cmpxchg_double | ||
| 129 | #endif | ||
| 130 | |||
| 87 | #include <asm-generic/percpu.h> | 131 | #include <asm-generic/percpu.h> |
| 88 | 132 | ||
| 89 | #endif /* __ARCH_S390_PERCPU__ */ | 133 | #endif /* __ARCH_S390_PERCPU__ */ |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 11e4e3236937..f3e0aabfc6bc 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
| @@ -11,12 +11,15 @@ | |||
| 11 | #ifndef __ASM_S390_PROCESSOR_H | 11 | #ifndef __ASM_S390_PROCESSOR_H |
| 12 | #define __ASM_S390_PROCESSOR_H | 12 | #define __ASM_S390_PROCESSOR_H |
| 13 | 13 | ||
| 14 | #ifndef __ASSEMBLY__ | ||
| 15 | |||
| 14 | #include <linux/linkage.h> | 16 | #include <linux/linkage.h> |
| 15 | #include <linux/irqflags.h> | 17 | #include <linux/irqflags.h> |
| 16 | #include <asm/cpu.h> | 18 | #include <asm/cpu.h> |
| 17 | #include <asm/page.h> | 19 | #include <asm/page.h> |
| 18 | #include <asm/ptrace.h> | 20 | #include <asm/ptrace.h> |
| 19 | #include <asm/setup.h> | 21 | #include <asm/setup.h> |
| 22 | #include <asm/runtime_instr.h> | ||
| 20 | 23 | ||
| 21 | /* | 24 | /* |
| 22 | * Default implementation of macro that returns current | 25 | * Default implementation of macro that returns current |
| @@ -75,11 +78,20 @@ struct thread_struct { | |||
| 75 | unsigned long gmap_addr; /* address of last gmap fault. */ | 78 | unsigned long gmap_addr; /* address of last gmap fault. */ |
| 76 | struct per_regs per_user; /* User specified PER registers */ | 79 | struct per_regs per_user; /* User specified PER registers */ |
| 77 | struct per_event per_event; /* Cause of the last PER trap */ | 80 | struct per_event per_event; /* Cause of the last PER trap */ |
| 81 | unsigned long per_flags; /* Flags to control debug behavior */ | ||
| 78 | /* pfault_wait is used to block the process on a pfault event */ | 82 | /* pfault_wait is used to block the process on a pfault event */ |
| 79 | unsigned long pfault_wait; | 83 | unsigned long pfault_wait; |
| 80 | struct list_head list; | 84 | struct list_head list; |
| 85 | /* cpu runtime instrumentation */ | ||
| 86 | struct runtime_instr_cb *ri_cb; | ||
| 87 | int ri_signum; | ||
| 88 | #ifdef CONFIG_64BIT | ||
| 89 | unsigned char trap_tdb[256]; /* Transaction abort diagnose block */ | ||
| 90 | #endif | ||
| 81 | }; | 91 | }; |
| 82 | 92 | ||
| 93 | #define PER_FLAG_NO_TE 1UL /* Flag to disable transactions. */ | ||
| 94 | |||
| 83 | typedef struct thread_struct thread_struct; | 95 | typedef struct thread_struct thread_struct; |
| 84 | 96 | ||
| 85 | /* | 97 | /* |
| @@ -130,6 +142,12 @@ struct task_struct; | |||
| 130 | struct mm_struct; | 142 | struct mm_struct; |
| 131 | struct seq_file; | 143 | struct seq_file; |
| 132 | 144 | ||
| 145 | #ifdef CONFIG_64BIT | ||
| 146 | extern void show_cacheinfo(struct seq_file *m); | ||
| 147 | #else | ||
| 148 | static inline void show_cacheinfo(struct seq_file *m) { } | ||
| 149 | #endif | ||
| 150 | |||
| 133 | /* Free all resources held by a thread. */ | 151 | /* Free all resources held by a thread. */ |
| 134 | extern void release_thread(struct task_struct *); | 152 | extern void release_thread(struct task_struct *); |
| 135 | extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | 153 | extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); |
| @@ -140,6 +158,7 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | |||
| 140 | extern unsigned long thread_saved_pc(struct task_struct *t); | 158 | extern unsigned long thread_saved_pc(struct task_struct *t); |
| 141 | 159 | ||
| 142 | extern void show_code(struct pt_regs *regs); | 160 | extern void show_code(struct pt_regs *regs); |
| 161 | extern void print_fn_code(unsigned char *code, unsigned long len); | ||
| 143 | 162 | ||
| 144 | unsigned long get_wchan(struct task_struct *p); | 163 | unsigned long get_wchan(struct task_struct *p); |
| 145 | #define task_pt_regs(tsk) ((struct pt_regs *) \ | 164 | #define task_pt_regs(tsk) ((struct pt_regs *) \ |
| @@ -331,23 +350,6 @@ extern void (*s390_base_ext_handler_fn)(void); | |||
| 331 | 350 | ||
| 332 | #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL | 351 | #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL |
| 333 | 352 | ||
| 334 | /* | ||
| 335 | * Helper macro for exception table entries | ||
| 336 | */ | ||
| 337 | #ifndef CONFIG_64BIT | ||
| 338 | #define EX_TABLE(_fault,_target) \ | ||
| 339 | ".section __ex_table,\"a\"\n" \ | ||
| 340 | " .align 4\n" \ | ||
| 341 | " .long " #_fault "," #_target "\n" \ | ||
| 342 | ".previous\n" | ||
| 343 | #else | ||
| 344 | #define EX_TABLE(_fault,_target) \ | ||
| 345 | ".section __ex_table,\"a\"\n" \ | ||
| 346 | " .align 8\n" \ | ||
| 347 | " .quad " #_fault "," #_target "\n" \ | ||
| 348 | ".previous\n" | ||
| 349 | #endif | ||
| 350 | |||
| 351 | extern int memcpy_real(void *, void *, size_t); | 353 | extern int memcpy_real(void *, void *, size_t); |
| 352 | extern void memcpy_absolute(void *, void *, size_t); | 354 | extern void memcpy_absolute(void *, void *, size_t); |
| 353 | 355 | ||
| @@ -358,4 +360,25 @@ extern void memcpy_absolute(void *, void *, size_t); | |||
| 358 | memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \ | 360 | memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \ |
| 359 | } | 361 | } |
| 360 | 362 | ||
| 361 | #endif /* __ASM_S390_PROCESSOR_H */ | 363 | /* |
| 364 | * Helper macro for exception table entries | ||
| 365 | */ | ||
| 366 | #define EX_TABLE(_fault, _target) \ | ||
| 367 | ".section __ex_table,\"a\"\n" \ | ||
| 368 | ".align 4\n" \ | ||
| 369 | ".long (" #_fault ") - .\n" \ | ||
| 370 | ".long (" #_target ") - .\n" \ | ||
| 371 | ".previous\n" | ||
| 372 | |||
| 373 | #else /* __ASSEMBLY__ */ | ||
| 374 | |||
| 375 | #define EX_TABLE(_fault, _target) \ | ||
| 376 | .section __ex_table,"a" ; \ | ||
| 377 | .align 4 ; \ | ||
| 378 | .long (_fault) - . ; \ | ||
| 379 | .long (_target) - . ; \ | ||
| 380 | .previous | ||
| 381 | |||
| 382 | #endif /* __ASSEMBLY__ */ | ||
| 383 | |||
| 384 | #endif /* __ASM_S390_PROCESSOR_H */ | ||
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index d5f08ea566ed..ce20a53afe91 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h | |||
| @@ -235,6 +235,7 @@ typedef struct | |||
| 235 | #define PSW_MASK_ASC 0x0000C000UL | 235 | #define PSW_MASK_ASC 0x0000C000UL |
| 236 | #define PSW_MASK_CC 0x00003000UL | 236 | #define PSW_MASK_CC 0x00003000UL |
| 237 | #define PSW_MASK_PM 0x00000F00UL | 237 | #define PSW_MASK_PM 0x00000F00UL |
| 238 | #define PSW_MASK_RI 0x00000000UL | ||
| 238 | #define PSW_MASK_EA 0x00000000UL | 239 | #define PSW_MASK_EA 0x00000000UL |
| 239 | #define PSW_MASK_BA 0x00000000UL | 240 | #define PSW_MASK_BA 0x00000000UL |
| 240 | 241 | ||
| @@ -264,10 +265,11 @@ typedef struct | |||
| 264 | #define PSW_MASK_ASC 0x0000C00000000000UL | 265 | #define PSW_MASK_ASC 0x0000C00000000000UL |
| 265 | #define PSW_MASK_CC 0x0000300000000000UL | 266 | #define PSW_MASK_CC 0x0000300000000000UL |
| 266 | #define PSW_MASK_PM 0x00000F0000000000UL | 267 | #define PSW_MASK_PM 0x00000F0000000000UL |
| 268 | #define PSW_MASK_RI 0x0000008000000000UL | ||
| 267 | #define PSW_MASK_EA 0x0000000100000000UL | 269 | #define PSW_MASK_EA 0x0000000100000000UL |
| 268 | #define PSW_MASK_BA 0x0000000080000000UL | 270 | #define PSW_MASK_BA 0x0000000080000000UL |
| 269 | 271 | ||
| 270 | #define PSW_MASK_USER 0x00003F0180000000UL | 272 | #define PSW_MASK_USER 0x00003F8180000000UL |
| 271 | 273 | ||
| 272 | #define PSW_ADDR_AMODE 0x0000000000000000UL | 274 | #define PSW_ADDR_AMODE 0x0000000000000000UL |
| 273 | #define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL | 275 | #define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL |
| @@ -359,17 +361,19 @@ struct per_struct_kernel { | |||
| 359 | unsigned char access_id; /* PER trap access identification */ | 361 | unsigned char access_id; /* PER trap access identification */ |
| 360 | }; | 362 | }; |
| 361 | 363 | ||
| 362 | #define PER_EVENT_MASK 0xE9000000UL | 364 | #define PER_EVENT_MASK 0xEB000000UL |
| 363 | 365 | ||
| 364 | #define PER_EVENT_BRANCH 0x80000000UL | 366 | #define PER_EVENT_BRANCH 0x80000000UL |
| 365 | #define PER_EVENT_IFETCH 0x40000000UL | 367 | #define PER_EVENT_IFETCH 0x40000000UL |
| 366 | #define PER_EVENT_STORE 0x20000000UL | 368 | #define PER_EVENT_STORE 0x20000000UL |
| 367 | #define PER_EVENT_STORE_REAL 0x08000000UL | 369 | #define PER_EVENT_STORE_REAL 0x08000000UL |
| 370 | #define PER_EVENT_TRANSACTION_END 0x02000000UL | ||
| 368 | #define PER_EVENT_NULLIFICATION 0x01000000UL | 371 | #define PER_EVENT_NULLIFICATION 0x01000000UL |
| 369 | 372 | ||
| 370 | #define PER_CONTROL_MASK 0x00a00000UL | 373 | #define PER_CONTROL_MASK 0x00e00000UL |
| 371 | 374 | ||
| 372 | #define PER_CONTROL_BRANCH_ADDRESS 0x00800000UL | 375 | #define PER_CONTROL_BRANCH_ADDRESS 0x00800000UL |
| 376 | #define PER_CONTROL_SUSPENSION 0x00400000UL | ||
| 373 | #define PER_CONTROL_ALTERATION 0x00200000UL | 377 | #define PER_CONTROL_ALTERATION 0x00200000UL |
| 374 | 378 | ||
| 375 | #endif | 379 | #endif |
| @@ -483,6 +487,8 @@ typedef struct | |||
| 483 | #define PTRACE_GET_LAST_BREAK 0x5006 | 487 | #define PTRACE_GET_LAST_BREAK 0x5006 |
| 484 | #define PTRACE_PEEK_SYSTEM_CALL 0x5007 | 488 | #define PTRACE_PEEK_SYSTEM_CALL 0x5007 |
| 485 | #define PTRACE_POKE_SYSTEM_CALL 0x5008 | 489 | #define PTRACE_POKE_SYSTEM_CALL 0x5008 |
| 490 | #define PTRACE_ENABLE_TE 0x5009 | ||
| 491 | #define PTRACE_DISABLE_TE 0x5010 | ||
| 486 | 492 | ||
| 487 | /* | 493 | /* |
| 488 | * PT_PROT definition is loosely based on hppa bsd definition in | 494 | * PT_PROT definition is loosely based on hppa bsd definition in |
diff --git a/arch/s390/include/asm/runtime_instr.h b/arch/s390/include/asm/runtime_instr.h new file mode 100644 index 000000000000..830da737ff85 --- /dev/null +++ b/arch/s390/include/asm/runtime_instr.h | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | #ifndef _RUNTIME_INSTR_H | ||
| 2 | #define _RUNTIME_INSTR_H | ||
| 3 | |||
| 4 | #define S390_RUNTIME_INSTR_START 0x1 | ||
| 5 | #define S390_RUNTIME_INSTR_STOP 0x2 | ||
| 6 | |||
| 7 | struct runtime_instr_cb { | ||
| 8 | __u64 buf_current; | ||
| 9 | __u64 buf_origin; | ||
| 10 | __u64 buf_limit; | ||
| 11 | |||
| 12 | __u32 valid : 1; | ||
| 13 | __u32 pstate : 1; | ||
| 14 | __u32 pstate_set_buf : 1; | ||
| 15 | __u32 home_space : 1; | ||
| 16 | __u32 altered : 1; | ||
| 17 | __u32 : 3; | ||
| 18 | __u32 pstate_sample : 1; | ||
| 19 | __u32 sstate_sample : 1; | ||
| 20 | __u32 pstate_collect : 1; | ||
| 21 | __u32 sstate_collect : 1; | ||
| 22 | __u32 : 1; | ||
| 23 | __u32 halted_int : 1; | ||
| 24 | __u32 int_requested : 1; | ||
| 25 | __u32 buffer_full_int : 1; | ||
| 26 | __u32 key : 4; | ||
| 27 | __u32 : 9; | ||
| 28 | __u32 rgs : 3; | ||
| 29 | |||
| 30 | __u32 mode : 4; | ||
| 31 | __u32 next : 1; | ||
| 32 | __u32 mae : 1; | ||
| 33 | __u32 : 2; | ||
| 34 | __u32 call_type_br : 1; | ||
| 35 | __u32 return_type_br : 1; | ||
| 36 | __u32 other_type_br : 1; | ||
| 37 | __u32 bc_other_type : 1; | ||
| 38 | __u32 emit : 1; | ||
| 39 | __u32 tx_abort : 1; | ||
| 40 | __u32 : 2; | ||
| 41 | __u32 bp_xn : 1; | ||
| 42 | __u32 bp_xt : 1; | ||
| 43 | __u32 bp_ti : 1; | ||
| 44 | __u32 bp_ni : 1; | ||
| 45 | __u32 suppr_y : 1; | ||
| 46 | __u32 suppr_z : 1; | ||
| 47 | |||
| 48 | __u32 dc_miss_extra : 1; | ||
| 49 | __u32 lat_lev_ignore : 1; | ||
| 50 | __u32 ic_lat_lev : 4; | ||
| 51 | __u32 dc_lat_lev : 4; | ||
| 52 | |||
| 53 | __u64 reserved1; | ||
| 54 | __u64 scaling_factor; | ||
| 55 | __u64 rsic; | ||
| 56 | __u64 reserved2; | ||
| 57 | } __packed __aligned(8); | ||
| 58 | |||
| 59 | extern struct runtime_instr_cb runtime_instr_empty_cb; | ||
| 60 | |||
| 61 | static inline void load_runtime_instr_cb(struct runtime_instr_cb *cb) | ||
| 62 | { | ||
| 63 | asm volatile(".insn rsy,0xeb0000000060,0,0,%0" /* LRIC */ | ||
| 64 | : : "Q" (*cb)); | ||
| 65 | } | ||
| 66 | |||
| 67 | static inline void store_runtime_instr_cb(struct runtime_instr_cb *cb) | ||
| 68 | { | ||
| 69 | asm volatile(".insn rsy,0xeb0000000061,0,0,%0" /* STRIC */ | ||
| 70 | : "=Q" (*cb) : : "cc"); | ||
| 71 | } | ||
| 72 | |||
| 73 | static inline void save_ri_cb(struct runtime_instr_cb *cb_prev) | ||
| 74 | { | ||
| 75 | #ifdef CONFIG_64BIT | ||
| 76 | if (cb_prev) | ||
| 77 | store_runtime_instr_cb(cb_prev); | ||
| 78 | #endif | ||
| 79 | } | ||
| 80 | |||
| 81 | static inline void restore_ri_cb(struct runtime_instr_cb *cb_next, | ||
| 82 | struct runtime_instr_cb *cb_prev) | ||
| 83 | { | ||
| 84 | #ifdef CONFIG_64BIT | ||
| 85 | if (cb_next) | ||
| 86 | load_runtime_instr_cb(cb_next); | ||
| 87 | else if (cb_prev) | ||
| 88 | load_runtime_instr_cb(&runtime_instr_empty_cb); | ||
| 89 | #endif | ||
| 90 | } | ||
| 91 | |||
| 92 | #ifdef CONFIG_64BIT | ||
| 93 | extern void exit_thread_runtime_instr(void); | ||
| 94 | #else | ||
| 95 | static inline void exit_thread_runtime_instr(void) { } | ||
| 96 | #endif | ||
| 97 | |||
| 98 | #endif /* _RUNTIME_INSTR_H */ | ||
diff --git a/arch/s390/include/asm/scsw.h b/arch/s390/include/asm/scsw.h index 4071d00978cb..4af99cdaddf5 100644 --- a/arch/s390/include/asm/scsw.h +++ b/arch/s390/include/asm/scsw.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Helper functions for scsw access. | 2 | * Helper functions for scsw access. |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2008, 2009 | 4 | * Copyright IBM Corp. 2008, 2012 |
| 5 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 5 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| @@ -9,7 +9,7 @@ | |||
| 9 | #define _ASM_S390_SCSW_H_ | 9 | #define _ASM_S390_SCSW_H_ |
| 10 | 10 | ||
| 11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 12 | #include <asm/chsc.h> | 12 | #include <asm/css_chars.h> |
| 13 | #include <asm/cio.h> | 13 | #include <asm/cio.h> |
| 14 | 14 | ||
| 15 | /** | 15 | /** |
| @@ -100,14 +100,46 @@ struct tm_scsw { | |||
| 100 | } __attribute__ ((packed)); | 100 | } __attribute__ ((packed)); |
| 101 | 101 | ||
| 102 | /** | 102 | /** |
| 103 | * struct eadm_scsw - subchannel status word for eadm subchannels | ||
| 104 | * @key: subchannel key | ||
| 105 | * @eswf: esw format | ||
| 106 | * @cc: deferred condition code | ||
| 107 | * @ectl: extended control | ||
| 108 | * @fctl: function control | ||
| 109 | * @actl: activity control | ||
| 110 | * @stctl: status control | ||
| 111 | * @aob: AOB address | ||
| 112 | * @dstat: device status | ||
| 113 | * @cstat: subchannel status | ||
| 114 | */ | ||
| 115 | struct eadm_scsw { | ||
| 116 | u32 key:4; | ||
| 117 | u32:1; | ||
| 118 | u32 eswf:1; | ||
| 119 | u32 cc:2; | ||
| 120 | u32:6; | ||
| 121 | u32 ectl:1; | ||
| 122 | u32:2; | ||
| 123 | u32 fctl:3; | ||
| 124 | u32 actl:7; | ||
| 125 | u32 stctl:5; | ||
| 126 | u32 aob; | ||
| 127 | u32 dstat:8; | ||
| 128 | u32 cstat:8; | ||
| 129 | u32:16; | ||
| 130 | } __packed; | ||
| 131 | |||
| 132 | /** | ||
| 103 | * union scsw - subchannel status word | 133 | * union scsw - subchannel status word |
| 104 | * @cmd: command-mode SCSW | 134 | * @cmd: command-mode SCSW |
| 105 | * @tm: transport-mode SCSW | 135 | * @tm: transport-mode SCSW |
| 136 | * @eadm: eadm SCSW | ||
| 106 | */ | 137 | */ |
| 107 | union scsw { | 138 | union scsw { |
| 108 | struct cmd_scsw cmd; | 139 | struct cmd_scsw cmd; |
| 109 | struct tm_scsw tm; | 140 | struct tm_scsw tm; |
| 110 | } __attribute__ ((packed)); | 141 | struct eadm_scsw eadm; |
| 142 | } __packed; | ||
| 111 | 143 | ||
| 112 | #define SCSW_FCTL_CLEAR_FUNC 0x1 | 144 | #define SCSW_FCTL_CLEAR_FUNC 0x1 |
| 113 | #define SCSW_FCTL_HALT_FUNC 0x2 | 145 | #define SCSW_FCTL_HALT_FUNC 0x2 |
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index e6859d16ee2d..87b47ca954f1 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h | |||
| @@ -60,7 +60,7 @@ void create_mem_hole(struct mem_chunk memory_chunk[], unsigned long addr, | |||
| 60 | #define SECONDARY_SPACE_MODE 2 | 60 | #define SECONDARY_SPACE_MODE 2 |
| 61 | #define HOME_SPACE_MODE 3 | 61 | #define HOME_SPACE_MODE 3 |
| 62 | 62 | ||
| 63 | extern unsigned int addressing_mode; | 63 | extern unsigned int s390_user_mode; |
| 64 | 64 | ||
| 65 | /* | 65 | /* |
| 66 | * Machine features detected in head.S | 66 | * Machine features detected in head.S |
| @@ -80,6 +80,7 @@ extern unsigned int addressing_mode; | |||
| 80 | #define MACHINE_FLAG_LPAR (1UL << 12) | 80 | #define MACHINE_FLAG_LPAR (1UL << 12) |
| 81 | #define MACHINE_FLAG_SPP (1UL << 13) | 81 | #define MACHINE_FLAG_SPP (1UL << 13) |
| 82 | #define MACHINE_FLAG_TOPOLOGY (1UL << 14) | 82 | #define MACHINE_FLAG_TOPOLOGY (1UL << 14) |
| 83 | #define MACHINE_FLAG_TE (1UL << 15) | ||
| 83 | 84 | ||
| 84 | #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) | 85 | #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) |
| 85 | #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) | 86 | #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) |
| @@ -98,6 +99,7 @@ extern unsigned int addressing_mode; | |||
| 98 | #define MACHINE_HAS_PFMF (0) | 99 | #define MACHINE_HAS_PFMF (0) |
| 99 | #define MACHINE_HAS_SPP (0) | 100 | #define MACHINE_HAS_SPP (0) |
| 100 | #define MACHINE_HAS_TOPOLOGY (0) | 101 | #define MACHINE_HAS_TOPOLOGY (0) |
| 102 | #define MACHINE_HAS_TE (0) | ||
| 101 | #else /* CONFIG_64BIT */ | 103 | #else /* CONFIG_64BIT */ |
| 102 | #define MACHINE_HAS_IEEE (1) | 104 | #define MACHINE_HAS_IEEE (1) |
| 103 | #define MACHINE_HAS_CSP (1) | 105 | #define MACHINE_HAS_CSP (1) |
| @@ -109,6 +111,7 @@ extern unsigned int addressing_mode; | |||
| 109 | #define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF) | 111 | #define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF) |
| 110 | #define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP) | 112 | #define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP) |
| 111 | #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) | 113 | #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) |
| 114 | #define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE) | ||
| 112 | #endif /* CONFIG_64BIT */ | 115 | #endif /* CONFIG_64BIT */ |
| 113 | 116 | ||
| 114 | #define ZFCPDUMP_HSA_SIZE (32UL<<20) | 117 | #define ZFCPDUMP_HSA_SIZE (32UL<<20) |
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index ce26ac3cb162..b64f15c3b4cc 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h | |||
| @@ -30,6 +30,8 @@ extern int smp_vcpu_scheduled(int cpu); | |||
| 30 | extern void smp_yield_cpu(int cpu); | 30 | extern void smp_yield_cpu(int cpu); |
| 31 | extern void smp_yield(void); | 31 | extern void smp_yield(void); |
| 32 | extern void smp_stop_cpu(void); | 32 | extern void smp_stop_cpu(void); |
| 33 | extern void smp_cpu_set_polarization(int cpu, int val); | ||
| 34 | extern int smp_cpu_get_polarization(int cpu); | ||
| 33 | 35 | ||
| 34 | #else /* CONFIG_SMP */ | 36 | #else /* CONFIG_SMP */ |
| 35 | 37 | ||
| @@ -43,7 +45,7 @@ static inline void smp_call_online_cpu(void (*func)(void *), void *data) | |||
| 43 | func(data); | 45 | func(data); |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | static inline int smp_find_processor_id(int address) { return 0; } | 48 | static inline int smp_find_processor_id(u16 address) { return 0; } |
| 47 | static inline int smp_store_status(int cpu) { return 0; } | 49 | static inline int smp_store_status(int cpu) { return 0; } |
| 48 | static inline int smp_vcpu_scheduled(int cpu) { return 1; } | 50 | static inline int smp_vcpu_scheduled(int cpu) { return 1; } |
| 49 | static inline void smp_yield_cpu(int cpu) { } | 51 | static inline void smp_yield_cpu(int cpu) { } |
diff --git a/arch/s390/include/asm/string.h b/arch/s390/include/asm/string.h index 1bd1352fa3b5..7e2dcd7c57ef 100644 --- a/arch/s390/include/asm/string.h +++ b/arch/s390/include/asm/string.h | |||
| @@ -96,7 +96,6 @@ static inline char *strcat(char *dst, const char *src) | |||
| 96 | 96 | ||
| 97 | static inline char *strcpy(char *dst, const char *src) | 97 | static inline char *strcpy(char *dst, const char *src) |
| 98 | { | 98 | { |
| 99 | #if __GNUC__ < 4 | ||
| 100 | register int r0 asm("0") = 0; | 99 | register int r0 asm("0") = 0; |
| 101 | char *ret = dst; | 100 | char *ret = dst; |
| 102 | 101 | ||
| @@ -106,14 +105,10 @@ static inline char *strcpy(char *dst, const char *src) | |||
| 106 | : "+&a" (dst), "+&a" (src) : "d" (r0) | 105 | : "+&a" (dst), "+&a" (src) : "d" (r0) |
| 107 | : "cc", "memory"); | 106 | : "cc", "memory"); |
| 108 | return ret; | 107 | return ret; |
| 109 | #else | ||
| 110 | return __builtin_strcpy(dst, src); | ||
| 111 | #endif | ||
| 112 | } | 108 | } |
| 113 | 109 | ||
| 114 | static inline size_t strlen(const char *s) | 110 | static inline size_t strlen(const char *s) |
| 115 | { | 111 | { |
| 116 | #if __GNUC__ < 4 | ||
| 117 | register unsigned long r0 asm("0") = 0; | 112 | register unsigned long r0 asm("0") = 0; |
| 118 | const char *tmp = s; | 113 | const char *tmp = s; |
| 119 | 114 | ||
| @@ -122,9 +117,6 @@ static inline size_t strlen(const char *s) | |||
| 122 | " jo 0b" | 117 | " jo 0b" |
| 123 | : "+d" (r0), "+a" (tmp) : : "cc"); | 118 | : "+d" (r0), "+a" (tmp) : : "cc"); |
| 124 | return r0 - (unsigned long) s; | 119 | return r0 - (unsigned long) s; |
| 125 | #else | ||
| 126 | return __builtin_strlen(s); | ||
| 127 | #endif | ||
| 128 | } | 120 | } |
| 129 | 121 | ||
| 130 | static inline size_t strnlen(const char * s, size_t n) | 122 | static inline size_t strnlen(const char * s, size_t n) |
diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h index 314cc9426fc4..f3a9e0f92704 100644 --- a/arch/s390/include/asm/switch_to.h +++ b/arch/s390/include/asm/switch_to.h | |||
| @@ -80,10 +80,12 @@ static inline void restore_access_regs(unsigned int *acrs) | |||
| 80 | if (prev->mm) { \ | 80 | if (prev->mm) { \ |
| 81 | save_fp_regs(&prev->thread.fp_regs); \ | 81 | save_fp_regs(&prev->thread.fp_regs); \ |
| 82 | save_access_regs(&prev->thread.acrs[0]); \ | 82 | save_access_regs(&prev->thread.acrs[0]); \ |
| 83 | save_ri_cb(prev->thread.ri_cb); \ | ||
| 83 | } \ | 84 | } \ |
| 84 | if (next->mm) { \ | 85 | if (next->mm) { \ |
| 85 | restore_fp_regs(&next->thread.fp_regs); \ | 86 | restore_fp_regs(&next->thread.fp_regs); \ |
| 86 | restore_access_regs(&next->thread.acrs[0]); \ | 87 | restore_access_regs(&next->thread.acrs[0]); \ |
| 88 | restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \ | ||
| 87 | update_per_regs(next); \ | 89 | update_per_regs(next); \ |
| 88 | } \ | 90 | } \ |
| 89 | prev = __switch_to(prev,next); \ | 91 | prev = __switch_to(prev,next); \ |
diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h index 282ee36f6162..f92428e459f8 100644 --- a/arch/s390/include/asm/sysinfo.h +++ b/arch/s390/include/asm/sysinfo.h | |||
| @@ -17,7 +17,10 @@ | |||
| 17 | #include <asm/bitsperlong.h> | 17 | #include <asm/bitsperlong.h> |
| 18 | 18 | ||
| 19 | struct sysinfo_1_1_1 { | 19 | struct sysinfo_1_1_1 { |
| 20 | unsigned short :16; | 20 | unsigned char p:1; |
| 21 | unsigned char :6; | ||
| 22 | unsigned char t:1; | ||
| 23 | unsigned char :8; | ||
| 21 | unsigned char ccr; | 24 | unsigned char ccr; |
| 22 | unsigned char cai; | 25 | unsigned char cai; |
| 23 | char reserved_0[28]; | 26 | char reserved_0[28]; |
| @@ -30,9 +33,14 @@ struct sysinfo_1_1_1 { | |||
| 30 | char model[16]; | 33 | char model[16]; |
| 31 | char model_perm_cap[16]; | 34 | char model_perm_cap[16]; |
| 32 | char model_temp_cap[16]; | 35 | char model_temp_cap[16]; |
| 33 | char model_cap_rating[4]; | 36 | unsigned int model_cap_rating; |
| 34 | char model_perm_cap_rating[4]; | 37 | unsigned int model_perm_cap_rating; |
| 35 | char model_temp_cap_rating[4]; | 38 | unsigned int model_temp_cap_rating; |
| 39 | unsigned char typepct[5]; | ||
| 40 | unsigned char reserved_2[3]; | ||
| 41 | unsigned int ncr; | ||
| 42 | unsigned int npr; | ||
| 43 | unsigned int ntr; | ||
| 36 | }; | 44 | }; |
| 37 | 45 | ||
| 38 | struct sysinfo_1_2_1 { | 46 | struct sysinfo_1_2_1 { |
| @@ -47,8 +55,9 @@ struct sysinfo_1_2_2 { | |||
| 47 | char format; | 55 | char format; |
| 48 | char reserved_0[1]; | 56 | char reserved_0[1]; |
| 49 | unsigned short acc_offset; | 57 | unsigned short acc_offset; |
| 50 | char reserved_1[24]; | 58 | char reserved_1[20]; |
| 51 | unsigned int secondary_capability; | 59 | unsigned int nominal_cap; |
| 60 | unsigned int secondary_cap; | ||
| 52 | unsigned int capability; | 61 | unsigned int capability; |
| 53 | unsigned short cpus_total; | 62 | unsigned short cpus_total; |
| 54 | unsigned short cpus_configured; | 63 | unsigned short cpus_configured; |
| @@ -109,6 +118,8 @@ struct sysinfo_3_2_2 { | |||
| 109 | char reserved_544[3552]; | 118 | char reserved_544[3552]; |
| 110 | }; | 119 | }; |
| 111 | 120 | ||
| 121 | extern int topology_max_mnest; | ||
| 122 | |||
| 112 | #define TOPOLOGY_CPU_BITS 64 | 123 | #define TOPOLOGY_CPU_BITS 64 |
| 113 | #define TOPOLOGY_NR_MAG 6 | 124 | #define TOPOLOGY_NR_MAG 6 |
| 114 | 125 | ||
| @@ -142,21 +153,7 @@ struct sysinfo_15_1_x { | |||
| 142 | union topology_entry tle[0]; | 153 | union topology_entry tle[0]; |
| 143 | }; | 154 | }; |
| 144 | 155 | ||
| 145 | static inline int stsi(void *sysinfo, int fc, int sel1, int sel2) | 156 | int stsi(void *sysinfo, int fc, int sel1, int sel2); |
| 146 | { | ||
| 147 | register int r0 asm("0") = (fc << 28) | sel1; | ||
| 148 | register int r1 asm("1") = sel2; | ||
| 149 | |||
| 150 | asm volatile( | ||
| 151 | " stsi 0(%2)\n" | ||
| 152 | "0: jz 2f\n" | ||
| 153 | "1: lhi %0,%3\n" | ||
| 154 | "2:\n" | ||
| 155 | EX_TABLE(0b, 1b) | ||
| 156 | : "+d" (r0) : "d" (r1), "a" (sysinfo), "K" (-ENOSYS) | ||
| 157 | : "cc", "memory"); | ||
| 158 | return r0; | ||
| 159 | } | ||
| 160 | 157 | ||
| 161 | /* | 158 | /* |
| 162 | * Service level reporting interface. | 159 | * Service level reporting interface. |
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index 0837de80c351..9ca305383760 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h | |||
| @@ -2,8 +2,8 @@ | |||
| 2 | #define _ASM_S390_TOPOLOGY_H | 2 | #define _ASM_S390_TOPOLOGY_H |
| 3 | 3 | ||
| 4 | #include <linux/cpumask.h> | 4 | #include <linux/cpumask.h> |
| 5 | #include <asm/sysinfo.h> | ||
| 6 | 5 | ||
| 6 | struct sysinfo_15_1_x; | ||
| 7 | struct cpu; | 7 | struct cpu; |
| 8 | 8 | ||
| 9 | #ifdef CONFIG_SCHED_BOOK | 9 | #ifdef CONFIG_SCHED_BOOK |
| @@ -51,24 +51,6 @@ static inline void topology_expect_change(void) { } | |||
| 51 | #define POLARIZATION_VM (2) | 51 | #define POLARIZATION_VM (2) |
| 52 | #define POLARIZATION_VH (3) | 52 | #define POLARIZATION_VH (3) |
| 53 | 53 | ||
| 54 | extern int cpu_polarization[]; | ||
| 55 | |||
| 56 | static inline void cpu_set_polarization(int cpu, int val) | ||
| 57 | { | ||
| 58 | #ifdef CONFIG_SCHED_BOOK | ||
| 59 | cpu_polarization[cpu] = val; | ||
| 60 | #endif | ||
| 61 | } | ||
| 62 | |||
| 63 | static inline int cpu_read_polarization(int cpu) | ||
| 64 | { | ||
| 65 | #ifdef CONFIG_SCHED_BOOK | ||
| 66 | return cpu_polarization[cpu]; | ||
| 67 | #else | ||
| 68 | return POLARIZATION_HRZ; | ||
| 69 | #endif | ||
| 70 | } | ||
| 71 | |||
| 72 | #ifdef CONFIG_SCHED_BOOK | 54 | #ifdef CONFIG_SCHED_BOOK |
| 73 | void s390_init_cpu_topology(void); | 55 | void s390_init_cpu_topology(void); |
| 74 | #else | 56 | #else |
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index a8ab18b18b54..34268df959a3 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h | |||
| @@ -76,9 +76,22 @@ static inline int __range_ok(unsigned long addr, unsigned long size) | |||
| 76 | 76 | ||
| 77 | struct exception_table_entry | 77 | struct exception_table_entry |
| 78 | { | 78 | { |
| 79 | unsigned long insn, fixup; | 79 | int insn, fixup; |
| 80 | }; | 80 | }; |
| 81 | 81 | ||
| 82 | static inline unsigned long extable_insn(const struct exception_table_entry *x) | ||
| 83 | { | ||
| 84 | return (unsigned long)&x->insn + x->insn; | ||
| 85 | } | ||
| 86 | |||
| 87 | static inline unsigned long extable_fixup(const struct exception_table_entry *x) | ||
| 88 | { | ||
| 89 | return (unsigned long)&x->fixup + x->fixup; | ||
| 90 | } | ||
| 91 | |||
| 92 | #define ARCH_HAS_SORT_EXTABLE | ||
| 93 | #define ARCH_HAS_SEARCH_EXTABLE | ||
| 94 | |||
| 82 | struct uaccess_ops { | 95 | struct uaccess_ops { |
| 83 | size_t (*copy_from_user)(size_t, const void __user *, void *); | 96 | size_t (*copy_from_user)(size_t, const void __user *, void *); |
| 84 | size_t (*copy_from_user_small)(size_t, const void __user *, void *); | 97 | size_t (*copy_from_user_small)(size_t, const void __user *, void *); |
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index 6756e78f4808..4e64b5cd1558 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h | |||
| @@ -277,7 +277,9 @@ | |||
| 277 | #define __NR_setns 339 | 277 | #define __NR_setns 339 |
| 278 | #define __NR_process_vm_readv 340 | 278 | #define __NR_process_vm_readv 340 |
| 279 | #define __NR_process_vm_writev 341 | 279 | #define __NR_process_vm_writev 341 |
| 280 | #define NR_syscalls 342 | 280 | #define __NR_s390_runtime_instr 342 |
| 281 | #define __NR_kcmp 343 | ||
| 282 | #define NR_syscalls 344 | ||
| 281 | 283 | ||
| 282 | /* | 284 | /* |
| 283 | * There are some system calls that are not present on 64 bit, some | 285 | * There are some system calls that are not present on 64 bit, some |
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 9733b3f0eb6d..4da52fe31743 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
| @@ -23,10 +23,11 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w | |||
| 23 | obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \ | 23 | obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \ |
| 24 | processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \ | 24 | processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \ |
| 25 | debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \ | 25 | debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \ |
| 26 | sysinfo.o jump_label.o lgr.o os_info.o | 26 | sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o |
| 27 | 27 | ||
| 28 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) | 28 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) |
| 29 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) | 29 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) |
| 30 | obj-y += $(if $(CONFIG_64BIT),relocate_kernel64.o,relocate_kernel.o) | ||
| 30 | 31 | ||
| 31 | extra-y += head.o vmlinux.lds | 32 | extra-y += head.o vmlinux.lds |
| 32 | extra-y += $(if $(CONFIG_64BIT),head64.o,head31.o) | 33 | extra-y += $(if $(CONFIG_64BIT),head64.o,head31.o) |
| @@ -48,12 +49,11 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | |||
| 48 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 49 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
| 49 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o | 50 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o |
| 50 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | 51 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o |
| 51 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o | ||
| 52 | 52 | ||
| 53 | # Kexec part | 53 | ifdef CONFIG_64BIT |
| 54 | S390_KEXEC_OBJS := machine_kexec.o crash.o | 54 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o |
| 55 | S390_KEXEC_OBJS += $(if $(CONFIG_64BIT),relocate_kernel64.o,relocate_kernel.o) | 55 | obj-y += runtime_instr.o cache.o |
| 56 | obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS) | 56 | endif |
| 57 | 57 | ||
| 58 | # vdso | 58 | # vdso |
| 59 | obj-$(CONFIG_64BIT) += vdso64/ | 59 | obj-$(CONFIG_64BIT) += vdso64/ |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 45ef1a7b08f9..fface87056eb 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
| @@ -157,6 +157,8 @@ int main(void) | |||
| 157 | DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr)); | 157 | DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr)); |
| 158 | DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data)); | 158 | DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data)); |
| 159 | DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap)); | 159 | DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap)); |
| 160 | DEFINE(__LC_PGM_TDB, offsetof(struct _lowcore, pgm_tdb)); | ||
| 161 | DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb)); | ||
| 160 | DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce)); | 162 | DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce)); |
| 161 | #endif /* CONFIG_32BIT */ | 163 | #endif /* CONFIG_32BIT */ |
| 162 | return 0; | 164 | return 0; |
diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c new file mode 100644 index 000000000000..8df8d8a19c98 --- /dev/null +++ b/arch/s390/kernel/cache.c | |||
| @@ -0,0 +1,385 @@ | |||
| 1 | /* | ||
| 2 | * Extract CPU cache information and expose them via sysfs. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/notifier.h> | ||
| 9 | #include <linux/seq_file.h> | ||
| 10 | #include <linux/init.h> | ||
| 11 | #include <linux/list.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/cpu.h> | ||
| 14 | #include <asm/facility.h> | ||
| 15 | |||
| 16 | struct cache { | ||
| 17 | unsigned long size; | ||
| 18 | unsigned int line_size; | ||
| 19 | unsigned int associativity; | ||
| 20 | unsigned int nr_sets; | ||
| 21 | unsigned int level : 3; | ||
| 22 | unsigned int type : 2; | ||
| 23 | unsigned int private : 1; | ||
| 24 | struct list_head list; | ||
| 25 | }; | ||
| 26 | |||
| 27 | struct cache_dir { | ||
| 28 | struct kobject *kobj; | ||
| 29 | struct cache_index_dir *index; | ||
| 30 | }; | ||
| 31 | |||
| 32 | struct cache_index_dir { | ||
| 33 | struct kobject kobj; | ||
| 34 | int cpu; | ||
| 35 | struct cache *cache; | ||
| 36 | struct cache_index_dir *next; | ||
| 37 | }; | ||
| 38 | |||
| 39 | enum { | ||
| 40 | CACHE_SCOPE_NOTEXISTS, | ||
| 41 | CACHE_SCOPE_PRIVATE, | ||
| 42 | CACHE_SCOPE_SHARED, | ||
| 43 | CACHE_SCOPE_RESERVED, | ||
| 44 | }; | ||
| 45 | |||
| 46 | enum { | ||
| 47 | CACHE_TYPE_SEPARATE, | ||
| 48 | CACHE_TYPE_DATA, | ||
| 49 | CACHE_TYPE_INSTRUCTION, | ||
| 50 | CACHE_TYPE_UNIFIED, | ||
| 51 | }; | ||
| 52 | |||
| 53 | enum { | ||
| 54 | EXTRACT_TOPOLOGY, | ||
| 55 | EXTRACT_LINE_SIZE, | ||
| 56 | EXTRACT_SIZE, | ||
| 57 | EXTRACT_ASSOCIATIVITY, | ||
| 58 | }; | ||
| 59 | |||
| 60 | enum { | ||
| 61 | CACHE_TI_UNIFIED = 0, | ||
| 62 | CACHE_TI_INSTRUCTION = 0, | ||
| 63 | CACHE_TI_DATA, | ||
| 64 | }; | ||
| 65 | |||
| 66 | struct cache_info { | ||
| 67 | unsigned char : 4; | ||
| 68 | unsigned char scope : 2; | ||
| 69 | unsigned char type : 2; | ||
| 70 | }; | ||
| 71 | |||
| 72 | #define CACHE_MAX_LEVEL 8 | ||
| 73 | |||
| 74 | union cache_topology { | ||
| 75 | struct cache_info ci[CACHE_MAX_LEVEL]; | ||
| 76 | unsigned long long raw; | ||
| 77 | }; | ||
| 78 | |||
| 79 | static const char * const cache_type_string[] = { | ||
| 80 | "Data", | ||
| 81 | "Instruction", | ||
| 82 | "Unified", | ||
| 83 | }; | ||
| 84 | |||
| 85 | static struct cache_dir *cache_dir_cpu[NR_CPUS]; | ||
| 86 | static LIST_HEAD(cache_list); | ||
| 87 | |||
| 88 | void show_cacheinfo(struct seq_file *m) | ||
| 89 | { | ||
| 90 | struct cache *cache; | ||
| 91 | int index = 0; | ||
| 92 | |||
| 93 | list_for_each_entry(cache, &cache_list, list) { | ||
| 94 | seq_printf(m, "cache%-11d: ", index); | ||
| 95 | seq_printf(m, "level=%d ", cache->level); | ||
| 96 | seq_printf(m, "type=%s ", cache_type_string[cache->type]); | ||
| 97 | seq_printf(m, "scope=%s ", cache->private ? "Private" : "Shared"); | ||
| 98 | seq_printf(m, "size=%luK ", cache->size >> 10); | ||
| 99 | seq_printf(m, "line_size=%u ", cache->line_size); | ||
| 100 | seq_printf(m, "associativity=%d", cache->associativity); | ||
| 101 | seq_puts(m, "\n"); | ||
| 102 | index++; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | static inline unsigned long ecag(int ai, int li, int ti) | ||
| 107 | { | ||
| 108 | unsigned long cmd, val; | ||
| 109 | |||
| 110 | cmd = ai << 4 | li << 1 | ti; | ||
| 111 | asm volatile(".insn rsy,0xeb000000004c,%0,0,0(%1)" /* ecag */ | ||
| 112 | : "=d" (val) : "a" (cmd)); | ||
| 113 | return val; | ||
| 114 | } | ||
| 115 | |||
| 116 | static int __init cache_add(int level, int private, int type) | ||
| 117 | { | ||
| 118 | struct cache *cache; | ||
| 119 | int ti; | ||
| 120 | |||
| 121 | cache = kzalloc(sizeof(*cache), GFP_KERNEL); | ||
| 122 | if (!cache) | ||
| 123 | return -ENOMEM; | ||
| 124 | ti = type == CACHE_TYPE_DATA ? CACHE_TI_DATA : CACHE_TI_UNIFIED; | ||
| 125 | cache->size = ecag(EXTRACT_SIZE, level, ti); | ||
| 126 | cache->line_size = ecag(EXTRACT_LINE_SIZE, level, ti); | ||
| 127 | cache->associativity = ecag(EXTRACT_ASSOCIATIVITY, level, ti); | ||
| 128 | cache->nr_sets = cache->size / cache->associativity; | ||
| 129 | cache->nr_sets /= cache->line_size; | ||
| 130 | cache->private = private; | ||
| 131 | cache->level = level + 1; | ||
| 132 | cache->type = type - 1; | ||
| 133 | list_add_tail(&cache->list, &cache_list); | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | static void __init cache_build_info(void) | ||
| 138 | { | ||
| 139 | struct cache *cache, *next; | ||
| 140 | union cache_topology ct; | ||
| 141 | int level, private, rc; | ||
| 142 | |||
| 143 | ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0); | ||
| 144 | for (level = 0; level < CACHE_MAX_LEVEL; level++) { | ||
| 145 | switch (ct.ci[level].scope) { | ||
| 146 | case CACHE_SCOPE_NOTEXISTS: | ||
| 147 | case CACHE_SCOPE_RESERVED: | ||
| 148 | return; | ||
| 149 | case CACHE_SCOPE_SHARED: | ||
| 150 | private = 0; | ||
| 151 | break; | ||
| 152 | case CACHE_SCOPE_PRIVATE: | ||
| 153 | private = 1; | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | if (ct.ci[level].type == CACHE_TYPE_SEPARATE) { | ||
| 157 | rc = cache_add(level, private, CACHE_TYPE_DATA); | ||
| 158 | rc |= cache_add(level, private, CACHE_TYPE_INSTRUCTION); | ||
| 159 | } else { | ||
| 160 | rc = cache_add(level, private, ct.ci[level].type); | ||
| 161 | } | ||
| 162 | if (rc) | ||
| 163 | goto error; | ||
| 164 | } | ||
| 165 | return; | ||
| 166 | error: | ||
| 167 | list_for_each_entry_safe(cache, next, &cache_list, list) { | ||
| 168 | list_del(&cache->list); | ||
| 169 | kfree(cache); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | static struct cache_dir *__cpuinit cache_create_cache_dir(int cpu) | ||
| 174 | { | ||
| 175 | struct cache_dir *cache_dir; | ||
| 176 | struct kobject *kobj = NULL; | ||
| 177 | struct device *dev; | ||
| 178 | |||
| 179 | dev = get_cpu_device(cpu); | ||
| 180 | if (!dev) | ||
| 181 | goto out; | ||
| 182 | kobj = kobject_create_and_add("cache", &dev->kobj); | ||
| 183 | if (!kobj) | ||
| 184 | goto out; | ||
| 185 | cache_dir = kzalloc(sizeof(*cache_dir), GFP_KERNEL); | ||
| 186 | if (!cache_dir) | ||
| 187 | goto out; | ||
| 188 | cache_dir->kobj = kobj; | ||
| 189 | cache_dir_cpu[cpu] = cache_dir; | ||
| 190 | return cache_dir; | ||
| 191 | out: | ||
| 192 | kobject_put(kobj); | ||
| 193 | return NULL; | ||
| 194 | } | ||
| 195 | |||
| 196 | static struct cache_index_dir *kobj_to_cache_index_dir(struct kobject *kobj) | ||
| 197 | { | ||
| 198 | return container_of(kobj, struct cache_index_dir, kobj); | ||
| 199 | } | ||
| 200 | |||
| 201 | static void cache_index_release(struct kobject *kobj) | ||
| 202 | { | ||
| 203 | struct cache_index_dir *index; | ||
| 204 | |||
| 205 | index = kobj_to_cache_index_dir(kobj); | ||
| 206 | kfree(index); | ||
| 207 | } | ||
| 208 | |||
| 209 | static ssize_t cache_index_show(struct kobject *kobj, | ||
| 210 | struct attribute *attr, char *buf) | ||
| 211 | { | ||
| 212 | struct kobj_attribute *kobj_attr; | ||
| 213 | |||
| 214 | kobj_attr = container_of(attr, struct kobj_attribute, attr); | ||
| 215 | return kobj_attr->show(kobj, kobj_attr, buf); | ||
| 216 | } | ||
| 217 | |||
| 218 | #define DEFINE_CACHE_ATTR(_name, _format, _value) \ | ||
| 219 | static ssize_t cache_##_name##_show(struct kobject *kobj, \ | ||
| 220 | struct kobj_attribute *attr, \ | ||
| 221 | char *buf) \ | ||
| 222 | { \ | ||
| 223 | struct cache_index_dir *index; \ | ||
| 224 | \ | ||
| 225 | index = kobj_to_cache_index_dir(kobj); \ | ||
| 226 | return sprintf(buf, _format, _value); \ | ||
| 227 | } \ | ||
| 228 | static struct kobj_attribute cache_##_name##_attr = \ | ||
| 229 | __ATTR(_name, 0444, cache_##_name##_show, NULL); | ||
| 230 | |||
| 231 | DEFINE_CACHE_ATTR(size, "%luK\n", index->cache->size >> 10); | ||
| 232 | DEFINE_CACHE_ATTR(coherency_line_size, "%u\n", index->cache->line_size); | ||
| 233 | DEFINE_CACHE_ATTR(number_of_sets, "%u\n", index->cache->nr_sets); | ||
| 234 | DEFINE_CACHE_ATTR(ways_of_associativity, "%u\n", index->cache->associativity); | ||
| 235 | DEFINE_CACHE_ATTR(type, "%s\n", cache_type_string[index->cache->type]); | ||
| 236 | DEFINE_CACHE_ATTR(level, "%d\n", index->cache->level); | ||
| 237 | |||
| 238 | static ssize_t shared_cpu_map_func(struct kobject *kobj, int type, char *buf) | ||
| 239 | { | ||
| 240 | struct cache_index_dir *index; | ||
| 241 | int len; | ||
| 242 | |||
| 243 | index = kobj_to_cache_index_dir(kobj); | ||
| 244 | len = type ? | ||
| 245 | cpulist_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu)) : | ||
| 246 | cpumask_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu)); | ||
| 247 | len += sprintf(&buf[len], "\n"); | ||
| 248 | return len; | ||
| 249 | } | ||
| 250 | |||
| 251 | static ssize_t shared_cpu_map_show(struct kobject *kobj, | ||
| 252 | struct kobj_attribute *attr, char *buf) | ||
| 253 | { | ||
| 254 | return shared_cpu_map_func(kobj, 0, buf); | ||
| 255 | } | ||
| 256 | static struct kobj_attribute cache_shared_cpu_map_attr = | ||
| 257 | __ATTR(shared_cpu_map, 0444, shared_cpu_map_show, NULL); | ||
| 258 | |||
| 259 | static ssize_t shared_cpu_list_show(struct kobject *kobj, | ||
| 260 | struct kobj_attribute *attr, char *buf) | ||
| 261 | { | ||
| 262 | return shared_cpu_map_func(kobj, 1, buf); | ||
| 263 | } | ||
| 264 | static struct kobj_attribute cache_shared_cpu_list_attr = | ||
| 265 | __ATTR(shared_cpu_list, 0444, shared_cpu_list_show, NULL); | ||
| 266 | |||
| 267 | static struct attribute *cache_index_default_attrs[] = { | ||
| 268 | &cache_type_attr.attr, | ||
| 269 | &cache_size_attr.attr, | ||
| 270 | &cache_number_of_sets_attr.attr, | ||
| 271 | &cache_ways_of_associativity_attr.attr, | ||
| 272 | &cache_level_attr.attr, | ||
| 273 | &cache_coherency_line_size_attr.attr, | ||
| 274 | &cache_shared_cpu_map_attr.attr, | ||
| 275 | &cache_shared_cpu_list_attr.attr, | ||
| 276 | NULL, | ||
| 277 | }; | ||
| 278 | |||
| 279 | static const struct sysfs_ops cache_index_ops = { | ||
| 280 | .show = cache_index_show, | ||
| 281 | }; | ||
| 282 | |||
| 283 | static struct kobj_type cache_index_type = { | ||
| 284 | .sysfs_ops = &cache_index_ops, | ||
| 285 | .release = cache_index_release, | ||
| 286 | .default_attrs = cache_index_default_attrs, | ||
| 287 | }; | ||
| 288 | |||
| 289 | static int __cpuinit cache_create_index_dir(struct cache_dir *cache_dir, | ||
| 290 | struct cache *cache, int index, | ||
| 291 | int cpu) | ||
| 292 | { | ||
| 293 | struct cache_index_dir *index_dir; | ||
| 294 | int rc; | ||
| 295 | |||
| 296 | index_dir = kzalloc(sizeof(*index_dir), GFP_KERNEL); | ||
| 297 | if (!index_dir) | ||
| 298 | return -ENOMEM; | ||
| 299 | index_dir->cache = cache; | ||
| 300 | index_dir->cpu = cpu; | ||
| 301 | rc = kobject_init_and_add(&index_dir->kobj, &cache_index_type, | ||
| 302 | cache_dir->kobj, "index%d", index); | ||
| 303 | if (rc) | ||
| 304 | goto out; | ||
| 305 | index_dir->next = cache_dir->index; | ||
| 306 | cache_dir->index = index_dir; | ||
| 307 | return 0; | ||
| 308 | out: | ||
| 309 | kfree(index_dir); | ||
| 310 | return rc; | ||
| 311 | } | ||
| 312 | |||
| 313 | static int __cpuinit cache_add_cpu(int cpu) | ||
| 314 | { | ||
| 315 | struct cache_dir *cache_dir; | ||
| 316 | struct cache *cache; | ||
| 317 | int rc, index = 0; | ||
| 318 | |||
| 319 | if (list_empty(&cache_list)) | ||
| 320 | return 0; | ||
| 321 | cache_dir = cache_create_cache_dir(cpu); | ||
| 322 | if (!cache_dir) | ||
| 323 | return -ENOMEM; | ||
| 324 | list_for_each_entry(cache, &cache_list, list) { | ||
| 325 | if (!cache->private) | ||
| 326 | break; | ||
| 327 | rc = cache_create_index_dir(cache_dir, cache, index, cpu); | ||
| 328 | if (rc) | ||
| 329 | return rc; | ||
| 330 | index++; | ||
| 331 | } | ||
| 332 | return 0; | ||
| 333 | } | ||
| 334 | |||
| 335 | static void __cpuinit cache_remove_cpu(int cpu) | ||
| 336 | { | ||
| 337 | struct cache_index_dir *index, *next; | ||
| 338 | struct cache_dir *cache_dir; | ||
| 339 | |||
| 340 | cache_dir = cache_dir_cpu[cpu]; | ||
| 341 | if (!cache_dir) | ||
| 342 | return; | ||
| 343 | index = cache_dir->index; | ||
| 344 | while (index) { | ||
| 345 | next = index->next; | ||
| 346 | kobject_put(&index->kobj); | ||
| 347 | index = next; | ||
| 348 | } | ||
| 349 | kobject_put(cache_dir->kobj); | ||
| 350 | kfree(cache_dir); | ||
| 351 | cache_dir_cpu[cpu] = NULL; | ||
| 352 | } | ||
| 353 | |||
| 354 | static int __cpuinit cache_hotplug(struct notifier_block *nfb, | ||
| 355 | unsigned long action, void *hcpu) | ||
| 356 | { | ||
| 357 | int cpu = (long)hcpu; | ||
| 358 | int rc = 0; | ||
| 359 | |||
| 360 | switch (action & ~CPU_TASKS_FROZEN) { | ||
| 361 | case CPU_ONLINE: | ||
| 362 | rc = cache_add_cpu(cpu); | ||
| 363 | if (rc) | ||
| 364 | cache_remove_cpu(cpu); | ||
| 365 | break; | ||
| 366 | case CPU_DEAD: | ||
| 367 | cache_remove_cpu(cpu); | ||
| 368 | break; | ||
| 369 | } | ||
| 370 | return rc ? NOTIFY_BAD : NOTIFY_OK; | ||
| 371 | } | ||
| 372 | |||
| 373 | static int __init cache_init(void) | ||
| 374 | { | ||
| 375 | int cpu; | ||
| 376 | |||
| 377 | if (!test_facility(34)) | ||
| 378 | return 0; | ||
| 379 | cache_build_info(); | ||
| 380 | for_each_online_cpu(cpu) | ||
| 381 | cache_add_cpu(cpu); | ||
| 382 | hotcpu_notifier(cache_hotplug, 0); | ||
| 383 | return 0; | ||
| 384 | } | ||
| 385 | device_initcall(cache_init); | ||
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 2d82cfcbce5b..3afba804fe97 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S | |||
| @@ -1646,3 +1646,16 @@ ENTRY(compat_sys_process_vm_writev_wrapper) | |||
| 1646 | llgf %r0,164(%r15) # unsigned long | 1646 | llgf %r0,164(%r15) # unsigned long |
| 1647 | stg %r0,160(%r15) | 1647 | stg %r0,160(%r15) |
| 1648 | jg compat_sys_process_vm_writev | 1648 | jg compat_sys_process_vm_writev |
| 1649 | |||
| 1650 | ENTRY(sys_s390_runtime_instr_wrapper) | ||
| 1651 | lgfr %r2,%r2 # int | ||
| 1652 | lgfr %r3,%r3 # int | ||
| 1653 | jg sys_s390_runtime_instr | ||
| 1654 | |||
| 1655 | ENTRY(sys_kcmp_wrapper) | ||
| 1656 | lgfr %r2,%r2 # pid_t | ||
| 1657 | lgfr %r3,%r3 # pid_t | ||
| 1658 | lgfr %r4,%r4 # int | ||
| 1659 | llgfr %r5,%r5 # unsigned long | ||
| 1660 | llgfr %r6,%r6 # unsigned long | ||
| 1661 | jg sys_kcmp | ||
diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c deleted file mode 100644 index 3819153de8bd..000000000000 --- a/arch/s390/kernel/crash.c +++ /dev/null | |||
| @@ -1,14 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright IBM Corp. 2005 | ||
| 3 | * | ||
| 4 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/threads.h> | ||
| 9 | #include <linux/kexec.h> | ||
| 10 | #include <linux/reboot.h> | ||
| 11 | |||
| 12 | void machine_crash_shutdown(struct pt_regs *regs) | ||
| 13 | { | ||
| 14 | } | ||
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index cc1172b26873..fb8d8781a011 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c | |||
| @@ -13,8 +13,9 @@ | |||
| 13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 14 | #include <linux/bootmem.h> | 14 | #include <linux/bootmem.h> |
| 15 | #include <linux/elf.h> | 15 | #include <linux/elf.h> |
| 16 | #include <asm/ipl.h> | ||
| 17 | #include <asm/os_info.h> | 16 | #include <asm/os_info.h> |
| 17 | #include <asm/elf.h> | ||
| 18 | #include <asm/ipl.h> | ||
| 18 | 19 | ||
| 19 | #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y))) | 20 | #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y))) |
| 20 | #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) | 21 | #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) |
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index 619c5d350726..cc84a24c023f 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c | |||
| @@ -315,6 +315,11 @@ enum { | |||
| 315 | LONG_INSN_POPCNT, | 315 | LONG_INSN_POPCNT, |
| 316 | LONG_INSN_RISBHG, | 316 | LONG_INSN_RISBHG, |
| 317 | LONG_INSN_RISBLG, | 317 | LONG_INSN_RISBLG, |
| 318 | LONG_INSN_RINEXT, | ||
| 319 | LONG_INSN_RIEMIT, | ||
| 320 | LONG_INSN_TABORT, | ||
| 321 | LONG_INSN_TBEGIN, | ||
| 322 | LONG_INSN_TBEGINC, | ||
| 318 | }; | 323 | }; |
| 319 | 324 | ||
| 320 | static char *long_insn_name[] = { | 325 | static char *long_insn_name[] = { |
| @@ -329,7 +334,12 @@ static char *long_insn_name[] = { | |||
| 329 | [LONG_INSN_LLGHRL] = "llghrl", | 334 | [LONG_INSN_LLGHRL] = "llghrl", |
| 330 | [LONG_INSN_POPCNT] = "popcnt", | 335 | [LONG_INSN_POPCNT] = "popcnt", |
| 331 | [LONG_INSN_RISBHG] = "risbhg", | 336 | [LONG_INSN_RISBHG] = "risbhg", |
| 332 | [LONG_INSN_RISBLG] = "risblk", | 337 | [LONG_INSN_RISBLG] = "risblg", |
| 338 | [LONG_INSN_RINEXT] = "rinext", | ||
| 339 | [LONG_INSN_RIEMIT] = "riemit", | ||
| 340 | [LONG_INSN_TABORT] = "tabort", | ||
| 341 | [LONG_INSN_TBEGIN] = "tbegin", | ||
| 342 | [LONG_INSN_TBEGINC] = "tbeginc", | ||
| 333 | }; | 343 | }; |
| 334 | 344 | ||
| 335 | static struct insn opcode[] = { | 345 | static struct insn opcode[] = { |
| @@ -582,6 +592,17 @@ static struct insn opcode_a7[] = { | |||
| 582 | { "", 0, INSTR_INVALID } | 592 | { "", 0, INSTR_INVALID } |
| 583 | }; | 593 | }; |
| 584 | 594 | ||
| 595 | static struct insn opcode_aa[] = { | ||
| 596 | #ifdef CONFIG_64BIT | ||
| 597 | { { 0, LONG_INSN_RINEXT }, 0x00, INSTR_RI_RI }, | ||
| 598 | { "rion", 0x01, INSTR_RI_RI }, | ||
| 599 | { "tric", 0x02, INSTR_RI_RI }, | ||
| 600 | { "rioff", 0x03, INSTR_RI_RI }, | ||
| 601 | { { 0, LONG_INSN_RIEMIT }, 0x04, INSTR_RI_RI }, | ||
| 602 | #endif | ||
| 603 | { "", 0, INSTR_INVALID } | ||
| 604 | }; | ||
| 605 | |||
| 585 | static struct insn opcode_b2[] = { | 606 | static struct insn opcode_b2[] = { |
| 586 | #ifdef CONFIG_64BIT | 607 | #ifdef CONFIG_64BIT |
| 587 | { "sske", 0x2b, INSTR_RRF_M0RR }, | 608 | { "sske", 0x2b, INSTR_RRF_M0RR }, |
| @@ -594,6 +615,9 @@ static struct insn opcode_b2[] = { | |||
| 594 | { "lpswe", 0xb2, INSTR_S_RD }, | 615 | { "lpswe", 0xb2, INSTR_S_RD }, |
| 595 | { "srnmt", 0xb9, INSTR_S_RD }, | 616 | { "srnmt", 0xb9, INSTR_S_RD }, |
| 596 | { "lfas", 0xbd, INSTR_S_RD }, | 617 | { "lfas", 0xbd, INSTR_S_RD }, |
| 618 | { "etndg", 0xec, INSTR_RRE_R0 }, | ||
| 619 | { { 0, LONG_INSN_TABORT }, 0xfc, INSTR_S_RD }, | ||
| 620 | { "tend", 0xf8, INSTR_S_RD }, | ||
| 597 | #endif | 621 | #endif |
| 598 | { "stidp", 0x02, INSTR_S_RD }, | 622 | { "stidp", 0x02, INSTR_S_RD }, |
| 599 | { "sck", 0x04, INSTR_S_RD }, | 623 | { "sck", 0x04, INSTR_S_RD }, |
| @@ -1150,6 +1174,7 @@ static struct insn opcode_e3[] = { | |||
| 1150 | { "stfh", 0xcb, INSTR_RXY_RRRD }, | 1174 | { "stfh", 0xcb, INSTR_RXY_RRRD }, |
| 1151 | { "chf", 0xcd, INSTR_RXY_RRRD }, | 1175 | { "chf", 0xcd, INSTR_RXY_RRRD }, |
| 1152 | { "clhf", 0xcf, INSTR_RXY_RRRD }, | 1176 | { "clhf", 0xcf, INSTR_RXY_RRRD }, |
| 1177 | { "ntstg", 0x25, INSTR_RXY_RRRD }, | ||
| 1153 | #endif | 1178 | #endif |
| 1154 | { "lrv", 0x1e, INSTR_RXY_RRRD }, | 1179 | { "lrv", 0x1e, INSTR_RXY_RRRD }, |
| 1155 | { "lrvh", 0x1f, INSTR_RXY_RRRD }, | 1180 | { "lrvh", 0x1f, INSTR_RXY_RRRD }, |
| @@ -1173,6 +1198,8 @@ static struct insn opcode_e5[] = { | |||
| 1173 | { "mvhhi", 0x44, INSTR_SIL_RDI }, | 1198 | { "mvhhi", 0x44, INSTR_SIL_RDI }, |
| 1174 | { "mvhi", 0x4c, INSTR_SIL_RDI }, | 1199 | { "mvhi", 0x4c, INSTR_SIL_RDI }, |
| 1175 | { "mvghi", 0x48, INSTR_SIL_RDI }, | 1200 | { "mvghi", 0x48, INSTR_SIL_RDI }, |
| 1201 | { { 0, LONG_INSN_TBEGIN }, 0x60, INSTR_SIL_RDU }, | ||
| 1202 | { { 0, LONG_INSN_TBEGINC }, 0x61, INSTR_SIL_RDU }, | ||
| 1176 | #endif | 1203 | #endif |
| 1177 | { "lasp", 0x00, INSTR_SSE_RDRD }, | 1204 | { "lasp", 0x00, INSTR_SSE_RDRD }, |
| 1178 | { "tprot", 0x01, INSTR_SSE_RDRD }, | 1205 | { "tprot", 0x01, INSTR_SSE_RDRD }, |
| @@ -1210,6 +1237,9 @@ static struct insn opcode_eb[] = { | |||
| 1210 | { "cliy", 0x55, INSTR_SIY_URD }, | 1237 | { "cliy", 0x55, INSTR_SIY_URD }, |
| 1211 | { "oiy", 0x56, INSTR_SIY_URD }, | 1238 | { "oiy", 0x56, INSTR_SIY_URD }, |
| 1212 | { "xiy", 0x57, INSTR_SIY_URD }, | 1239 | { "xiy", 0x57, INSTR_SIY_URD }, |
| 1240 | { "lric", 0x60, INSTR_RSY_RDRM }, | ||
| 1241 | { "stric", 0x61, INSTR_RSY_RDRM }, | ||
| 1242 | { "mric", 0x62, INSTR_RSY_RDRM }, | ||
| 1213 | { "icmh", 0x80, INSTR_RSE_RURD }, | 1243 | { "icmh", 0x80, INSTR_RSE_RURD }, |
| 1214 | { "icmh", 0x80, INSTR_RSY_RURD }, | 1244 | { "icmh", 0x80, INSTR_RSY_RURD }, |
| 1215 | { "icmy", 0x81, INSTR_RSY_RURD }, | 1245 | { "icmy", 0x81, INSTR_RSY_RURD }, |
| @@ -1408,6 +1438,9 @@ static struct insn *find_insn(unsigned char *code) | |||
| 1408 | case 0xa7: | 1438 | case 0xa7: |
| 1409 | table = opcode_a7; | 1439 | table = opcode_a7; |
| 1410 | break; | 1440 | break; |
| 1441 | case 0xaa: | ||
| 1442 | table = opcode_aa; | ||
| 1443 | break; | ||
| 1411 | case 0xb2: | 1444 | case 0xb2: |
| 1412 | table = opcode_b2; | 1445 | table = opcode_b2; |
| 1413 | break; | 1446 | break; |
| @@ -1601,3 +1634,26 @@ void show_code(struct pt_regs *regs) | |||
| 1601 | } | 1634 | } |
| 1602 | printk("\n"); | 1635 | printk("\n"); |
| 1603 | } | 1636 | } |
| 1637 | |||
| 1638 | void print_fn_code(unsigned char *code, unsigned long len) | ||
| 1639 | { | ||
| 1640 | char buffer[64], *ptr; | ||
| 1641 | int opsize, i; | ||
| 1642 | |||
| 1643 | while (len) { | ||
| 1644 | ptr = buffer; | ||
| 1645 | opsize = insn_length(*code); | ||
| 1646 | ptr += sprintf(ptr, "%p: ", code); | ||
| 1647 | for (i = 0; i < opsize; i++) | ||
| 1648 | ptr += sprintf(ptr, "%02x", code[i]); | ||
| 1649 | *ptr++ = '\t'; | ||
| 1650 | if (i < 4) | ||
| 1651 | *ptr++ = '\t'; | ||
| 1652 | ptr += print_insn(ptr, code, (unsigned long) code); | ||
| 1653 | *ptr++ = '\n'; | ||
| 1654 | *ptr++ = 0; | ||
| 1655 | printk(buffer); | ||
| 1656 | code += opsize; | ||
| 1657 | len -= opsize; | ||
| 1658 | } | ||
| 1659 | } | ||
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 83c3271c442b..7f4717675c19 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
| @@ -215,36 +215,54 @@ static noinline __init void init_kernel_storage_key(void) | |||
| 215 | PAGE_DEFAULT_KEY, 0); | 215 | PAGE_DEFAULT_KEY, 0); |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE); | 218 | static __initdata char sysinfo_page[PAGE_SIZE] __aligned(PAGE_SIZE); |
| 219 | 219 | ||
| 220 | static noinline __init void detect_machine_type(void) | 220 | static noinline __init void detect_machine_type(void) |
| 221 | { | 221 | { |
| 222 | struct sysinfo_3_2_2 *vmms = (struct sysinfo_3_2_2 *)&sysinfo_page; | ||
| 223 | |||
| 222 | /* Check current-configuration-level */ | 224 | /* Check current-configuration-level */ |
| 223 | if ((stsi(NULL, 0, 0, 0) >> 28) <= 2) { | 225 | if (stsi(NULL, 0, 0, 0) <= 2) { |
| 224 | S390_lowcore.machine_flags |= MACHINE_FLAG_LPAR; | 226 | S390_lowcore.machine_flags |= MACHINE_FLAG_LPAR; |
| 225 | return; | 227 | return; |
| 226 | } | 228 | } |
| 227 | /* Get virtual-machine cpu information. */ | 229 | /* Get virtual-machine cpu information. */ |
| 228 | if (stsi(&vmms, 3, 2, 2) == -ENOSYS || !vmms.count) | 230 | if (stsi(vmms, 3, 2, 2) || !vmms->count) |
| 229 | return; | 231 | return; |
| 230 | 232 | ||
| 231 | /* Running under KVM? If not we assume z/VM */ | 233 | /* Running under KVM? If not we assume z/VM */ |
| 232 | if (!memcmp(vmms.vm[0].cpi, "\xd2\xe5\xd4", 3)) | 234 | if (!memcmp(vmms->vm[0].cpi, "\xd2\xe5\xd4", 3)) |
| 233 | S390_lowcore.machine_flags |= MACHINE_FLAG_KVM; | 235 | S390_lowcore.machine_flags |= MACHINE_FLAG_KVM; |
| 234 | else | 236 | else |
| 235 | S390_lowcore.machine_flags |= MACHINE_FLAG_VM; | 237 | S390_lowcore.machine_flags |= MACHINE_FLAG_VM; |
| 236 | } | 238 | } |
| 237 | 239 | ||
| 240 | static __init void setup_topology(void) | ||
| 241 | { | ||
| 242 | #ifdef CONFIG_64BIT | ||
| 243 | int max_mnest; | ||
| 244 | |||
| 245 | if (!test_facility(11)) | ||
| 246 | return; | ||
| 247 | S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY; | ||
| 248 | for (max_mnest = 6; max_mnest > 1; max_mnest--) { | ||
| 249 | if (stsi(&sysinfo_page, 15, 1, max_mnest) == 0) | ||
| 250 | break; | ||
| 251 | } | ||
| 252 | topology_max_mnest = max_mnest; | ||
| 253 | #endif | ||
| 254 | } | ||
| 255 | |||
| 238 | static void early_pgm_check_handler(void) | 256 | static void early_pgm_check_handler(void) |
| 239 | { | 257 | { |
| 240 | unsigned long addr; | ||
| 241 | const struct exception_table_entry *fixup; | 258 | const struct exception_table_entry *fixup; |
| 259 | unsigned long addr; | ||
| 242 | 260 | ||
| 243 | addr = S390_lowcore.program_old_psw.addr; | 261 | addr = S390_lowcore.program_old_psw.addr; |
| 244 | fixup = search_exception_tables(addr & PSW_ADDR_INSN); | 262 | fixup = search_exception_tables(addr & PSW_ADDR_INSN); |
| 245 | if (!fixup) | 263 | if (!fixup) |
| 246 | disabled_wait(0); | 264 | disabled_wait(0); |
| 247 | S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE; | 265 | S390_lowcore.program_old_psw.addr = extable_fixup(fixup)|PSW_ADDR_AMODE; |
| 248 | } | 266 | } |
| 249 | 267 | ||
| 250 | static noinline __init void setup_lowcore_early(void) | 268 | static noinline __init void setup_lowcore_early(void) |
| @@ -267,12 +285,10 @@ static noinline __init void setup_facility_list(void) | |||
| 267 | 285 | ||
| 268 | static noinline __init void setup_hpage(void) | 286 | static noinline __init void setup_hpage(void) |
| 269 | { | 287 | { |
| 270 | #ifndef CONFIG_DEBUG_PAGEALLOC | ||
| 271 | if (!test_facility(2) || !test_facility(8)) | 288 | if (!test_facility(2) || !test_facility(8)) |
| 272 | return; | 289 | return; |
| 273 | S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE; | 290 | S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE; |
| 274 | __ctl_set_bit(0, 23); | 291 | __ctl_set_bit(0, 23); |
| 275 | #endif | ||
| 276 | } | 292 | } |
| 277 | 293 | ||
| 278 | static __init void detect_mvpg(void) | 294 | static __init void detect_mvpg(void) |
| @@ -366,12 +382,12 @@ static __init void detect_machine_facilities(void) | |||
| 366 | S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; | 382 | S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; |
| 367 | if (test_facility(8)) | 383 | if (test_facility(8)) |
| 368 | S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF; | 384 | S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF; |
| 369 | if (test_facility(11)) | ||
| 370 | S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY; | ||
| 371 | if (test_facility(27)) | 385 | if (test_facility(27)) |
| 372 | S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; | 386 | S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; |
| 373 | if (test_facility(40)) | 387 | if (test_facility(40)) |
| 374 | S390_lowcore.machine_flags |= MACHINE_FLAG_SPP; | 388 | S390_lowcore.machine_flags |= MACHINE_FLAG_SPP; |
| 389 | if (test_facility(50) && test_facility(73)) | ||
| 390 | S390_lowcore.machine_flags |= MACHINE_FLAG_TE; | ||
| 375 | #endif | 391 | #endif |
| 376 | } | 392 | } |
| 377 | 393 | ||
| @@ -441,7 +457,6 @@ static void __init setup_boot_command_line(void) | |||
| 441 | append_to_cmdline(append_ipl_scpdata); | 457 | append_to_cmdline(append_ipl_scpdata); |
| 442 | } | 458 | } |
| 443 | 459 | ||
| 444 | |||
| 445 | /* | 460 | /* |
| 446 | * Save ipl parameters, clear bss memory, initialize storage keys | 461 | * Save ipl parameters, clear bss memory, initialize storage keys |
| 447 | * and create a kernel NSS at startup if the SAVESYS= parm is defined | 462 | * and create a kernel NSS at startup if the SAVESYS= parm is defined |
| @@ -468,6 +483,7 @@ void __init startup_init(void) | |||
| 468 | detect_diag44(); | 483 | detect_diag44(); |
| 469 | detect_machine_facilities(); | 484 | detect_machine_facilities(); |
| 470 | setup_hpage(); | 485 | setup_hpage(); |
| 486 | setup_topology(); | ||
| 471 | sclp_facilities_detect(); | 487 | sclp_facilities_detect(); |
| 472 | detect_memory_layout(memory_chunk); | 488 | detect_memory_layout(memory_chunk); |
| 473 | #ifdef CONFIG_DYNAMIC_FTRACE | 489 | #ifdef CONFIG_DYNAMIC_FTRACE |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 349b7eeb348a..7549985402f7 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
| 12 | #include <linux/linkage.h> | 12 | #include <linux/linkage.h> |
| 13 | #include <asm/processor.h> | ||
| 13 | #include <asm/cache.h> | 14 | #include <asm/cache.h> |
| 14 | #include <asm/errno.h> | 15 | #include <asm/errno.h> |
| 15 | #include <asm/ptrace.h> | 16 | #include <asm/ptrace.h> |
| @@ -412,6 +413,11 @@ ENTRY(pgm_check_handler) | |||
| 412 | 1: UPDATE_VTIME %r14,__LC_SYNC_ENTER_TIMER | 413 | 1: UPDATE_VTIME %r14,__LC_SYNC_ENTER_TIMER |
| 413 | LAST_BREAK %r14 | 414 | LAST_BREAK %r14 |
| 414 | lg %r15,__LC_KERNEL_STACK | 415 | lg %r15,__LC_KERNEL_STACK |
| 416 | lg %r14,__TI_task(%r12) | ||
| 417 | lghi %r13,__LC_PGM_TDB | ||
| 418 | tm __LC_PGM_ILC+2,0x02 # check for transaction abort | ||
| 419 | jz 2f | ||
| 420 | mvc __THREAD_trap_tdb(256,%r14),0(%r13) | ||
| 415 | 2: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 421 | 2: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
| 416 | la %r11,STACK_FRAME_OVERHEAD(%r15) | 422 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
| 417 | stmg %r0,%r7,__PT_R0(%r11) | 423 | stmg %r0,%r7,__PT_R0(%r11) |
| @@ -422,13 +428,12 @@ ENTRY(pgm_check_handler) | |||
| 422 | stg %r10,__PT_ARGS(%r11) | 428 | stg %r10,__PT_ARGS(%r11) |
| 423 | tm __LC_PGM_ILC+3,0x80 # check for per exception | 429 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
| 424 | jz 0f | 430 | jz 0f |
| 425 | lg %r1,__TI_task(%r12) | ||
| 426 | tmhh %r8,0x0001 # kernel per event ? | 431 | tmhh %r8,0x0001 # kernel per event ? |
| 427 | jz pgm_kprobe | 432 | jz pgm_kprobe |
| 428 | oi __TI_flags+7(%r12),_TIF_PER_TRAP | 433 | oi __TI_flags+7(%r12),_TIF_PER_TRAP |
| 429 | mvc __THREAD_per_address(8,%r1),__LC_PER_ADDRESS | 434 | mvc __THREAD_per_address(8,%r14),__LC_PER_ADDRESS |
| 430 | mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE | 435 | mvc __THREAD_per_cause(2,%r14),__LC_PER_CAUSE |
| 431 | mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID | 436 | mvc __THREAD_per_paid(1,%r14),__LC_PER_PAID |
| 432 | 0: REENABLE_IRQS | 437 | 0: REENABLE_IRQS |
| 433 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 438 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
| 434 | larl %r1,pgm_check_table | 439 | larl %r1,pgm_check_table |
| @@ -1004,9 +1009,7 @@ sie_fault: | |||
| 1004 | .Lhost_id: | 1009 | .Lhost_id: |
| 1005 | .quad 0 | 1010 | .quad 0 |
| 1006 | 1011 | ||
| 1007 | .section __ex_table,"a" | 1012 | EX_TABLE(sie_loop,sie_fault) |
| 1008 | .quad sie_loop,sie_fault | ||
| 1009 | .previous | ||
| 1010 | #endif | 1013 | #endif |
| 1011 | 1014 | ||
| 1012 | .section .rodata, "a" | 1015 | .section .rodata, "a" |
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index dd7630d8aab7..6cdc55b26d68 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
| @@ -30,33 +30,35 @@ struct irq_class { | |||
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | static const struct irq_class intrclass_names[] = { | 32 | static const struct irq_class intrclass_names[] = { |
| 33 | {.name = "EXT" }, | 33 | [EXTERNAL_INTERRUPT] = {.name = "EXT"}, |
| 34 | {.name = "I/O" }, | 34 | [IO_INTERRUPT] = {.name = "I/O"}, |
| 35 | {.name = "CLK", .desc = "[EXT] Clock Comparator" }, | 35 | [EXTINT_CLK] = {.name = "CLK", .desc = "[EXT] Clock Comparator"}, |
| 36 | {.name = "EXC", .desc = "[EXT] External Call" }, | 36 | [EXTINT_EXC] = {.name = "EXC", .desc = "[EXT] External Call"}, |
| 37 | {.name = "EMS", .desc = "[EXT] Emergency Signal" }, | 37 | [EXTINT_EMS] = {.name = "EMS", .desc = "[EXT] Emergency Signal"}, |
| 38 | {.name = "TMR", .desc = "[EXT] CPU Timer" }, | 38 | [EXTINT_TMR] = {.name = "TMR", .desc = "[EXT] CPU Timer"}, |
| 39 | {.name = "TAL", .desc = "[EXT] Timing Alert" }, | 39 | [EXTINT_TLA] = {.name = "TAL", .desc = "[EXT] Timing Alert"}, |
| 40 | {.name = "PFL", .desc = "[EXT] Pseudo Page Fault" }, | 40 | [EXTINT_PFL] = {.name = "PFL", .desc = "[EXT] Pseudo Page Fault"}, |
| 41 | {.name = "DSD", .desc = "[EXT] DASD Diag" }, | 41 | [EXTINT_DSD] = {.name = "DSD", .desc = "[EXT] DASD Diag"}, |
| 42 | {.name = "VRT", .desc = "[EXT] Virtio" }, | 42 | [EXTINT_VRT] = {.name = "VRT", .desc = "[EXT] Virtio"}, |
| 43 | {.name = "SCP", .desc = "[EXT] Service Call" }, | 43 | [EXTINT_SCP] = {.name = "SCP", .desc = "[EXT] Service Call"}, |
| 44 | {.name = "IUC", .desc = "[EXT] IUCV" }, | 44 | [EXTINT_IUC] = {.name = "IUC", .desc = "[EXT] IUCV"}, |
| 45 | {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling" }, | 45 | [EXTINT_CMS] = {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"}, |
| 46 | {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter" }, | 46 | [EXTINT_CMC] = {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"}, |
| 47 | {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt" }, | 47 | [EXTINT_CMR] = {.name = "CMR", .desc = "[EXT] CPU-Measurement: RI"}, |
| 48 | {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, | 48 | [IOINT_CIO] = {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"}, |
| 49 | {.name = "DAS", .desc = "[I/O] DASD" }, | 49 | [IOINT_QAI] = {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"}, |
| 50 | {.name = "C15", .desc = "[I/O] 3215" }, | 50 | [IOINT_DAS] = {.name = "DAS", .desc = "[I/O] DASD"}, |
| 51 | {.name = "C70", .desc = "[I/O] 3270" }, | 51 | [IOINT_C15] = {.name = "C15", .desc = "[I/O] 3215"}, |
| 52 | {.name = "TAP", .desc = "[I/O] Tape" }, | 52 | [IOINT_C70] = {.name = "C70", .desc = "[I/O] 3270"}, |
| 53 | {.name = "VMR", .desc = "[I/O] Unit Record Devices" }, | 53 | [IOINT_TAP] = {.name = "TAP", .desc = "[I/O] Tape"}, |
| 54 | {.name = "LCS", .desc = "[I/O] LCS" }, | 54 | [IOINT_VMR] = {.name = "VMR", .desc = "[I/O] Unit Record Devices"}, |
| 55 | {.name = "CLW", .desc = "[I/O] CLAW" }, | 55 | [IOINT_LCS] = {.name = "LCS", .desc = "[I/O] LCS"}, |
| 56 | {.name = "CTC", .desc = "[I/O] CTC" }, | 56 | [IOINT_CLW] = {.name = "CLW", .desc = "[I/O] CLAW"}, |
| 57 | {.name = "APB", .desc = "[I/O] AP Bus" }, | 57 | [IOINT_CTC] = {.name = "CTC", .desc = "[I/O] CTC"}, |
| 58 | {.name = "CSC", .desc = "[I/O] CHSC Subchannel" }, | 58 | [IOINT_APB] = {.name = "APB", .desc = "[I/O] AP Bus"}, |
| 59 | {.name = "NMI", .desc = "[NMI] Machine Check" }, | 59 | [IOINT_ADM] = {.name = "ADM", .desc = "[I/O] EADM Subchannel"}, |
| 60 | [IOINT_CSC] = {.name = "CSC", .desc = "[I/O] CHSC Subchannel"}, | ||
| 61 | [NMI_NMI] = {.name = "NMI", .desc = "[NMI] Machine Check"}, | ||
| 60 | }; | 62 | }; |
| 61 | 63 | ||
| 62 | /* | 64 | /* |
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 8aa634f5944b..d1c7214e157c 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
| @@ -547,7 +547,7 @@ static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr) | |||
| 547 | */ | 547 | */ |
| 548 | entry = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); | 548 | entry = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); |
| 549 | if (entry) { | 549 | if (entry) { |
| 550 | regs->psw.addr = entry->fixup | PSW_ADDR_AMODE; | 550 | regs->psw.addr = extable_fixup(entry) | PSW_ADDR_AMODE; |
| 551 | return 1; | 551 | return 1; |
| 552 | } | 552 | } |
| 553 | 553 | ||
diff --git a/arch/s390/kernel/lgr.c b/arch/s390/kernel/lgr.c index eca94e74d19a..6ea6d69339b5 100644 --- a/arch/s390/kernel/lgr.c +++ b/arch/s390/kernel/lgr.c | |||
| @@ -51,16 +51,6 @@ static struct lgr_info lgr_info_cur; | |||
| 51 | static struct debug_info *lgr_dbf; | 51 | static struct debug_info *lgr_dbf; |
| 52 | 52 | ||
| 53 | /* | 53 | /* |
| 54 | * Return number of valid stsi levels | ||
| 55 | */ | ||
| 56 | static inline int stsi_0(void) | ||
| 57 | { | ||
| 58 | int rc = stsi(NULL, 0, 0, 0); | ||
| 59 | |||
| 60 | return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28); | ||
| 61 | } | ||
| 62 | |||
| 63 | /* | ||
| 64 | * Copy buffer and then convert it to ASCII | 54 | * Copy buffer and then convert it to ASCII |
| 65 | */ | 55 | */ |
| 66 | static void cpascii(char *dst, char *src, int size) | 56 | static void cpascii(char *dst, char *src, int size) |
| @@ -76,7 +66,7 @@ static void lgr_stsi_1_1_1(struct lgr_info *lgr_info) | |||
| 76 | { | 66 | { |
| 77 | struct sysinfo_1_1_1 *si = (void *) lgr_page; | 67 | struct sysinfo_1_1_1 *si = (void *) lgr_page; |
| 78 | 68 | ||
| 79 | if (stsi(si, 1, 1, 1) == -ENOSYS) | 69 | if (stsi(si, 1, 1, 1)) |
| 80 | return; | 70 | return; |
| 81 | cpascii(lgr_info->manufacturer, si->manufacturer, | 71 | cpascii(lgr_info->manufacturer, si->manufacturer, |
| 82 | sizeof(si->manufacturer)); | 72 | sizeof(si->manufacturer)); |
| @@ -93,7 +83,7 @@ static void lgr_stsi_2_2_2(struct lgr_info *lgr_info) | |||
| 93 | { | 83 | { |
| 94 | struct sysinfo_2_2_2 *si = (void *) lgr_page; | 84 | struct sysinfo_2_2_2 *si = (void *) lgr_page; |
| 95 | 85 | ||
| 96 | if (stsi(si, 2, 2, 2) == -ENOSYS) | 86 | if (stsi(si, 2, 2, 2)) |
| 97 | return; | 87 | return; |
| 98 | cpascii(lgr_info->name, si->name, sizeof(si->name)); | 88 | cpascii(lgr_info->name, si->name, sizeof(si->name)); |
| 99 | memcpy(&lgr_info->lpar_number, &si->lpar_number, | 89 | memcpy(&lgr_info->lpar_number, &si->lpar_number, |
| @@ -108,7 +98,7 @@ static void lgr_stsi_3_2_2(struct lgr_info *lgr_info) | |||
| 108 | struct sysinfo_3_2_2 *si = (void *) lgr_page; | 98 | struct sysinfo_3_2_2 *si = (void *) lgr_page; |
| 109 | int i; | 99 | int i; |
| 110 | 100 | ||
| 111 | if (stsi(si, 3, 2, 2) == -ENOSYS) | 101 | if (stsi(si, 3, 2, 2)) |
| 112 | return; | 102 | return; |
| 113 | for (i = 0; i < min_t(u8, si->count, VM_LEVEL_MAX); i++) { | 103 | for (i = 0; i < min_t(u8, si->count, VM_LEVEL_MAX); i++) { |
| 114 | cpascii(lgr_info->vm[i].name, si->vm[i].name, | 104 | cpascii(lgr_info->vm[i].name, si->vm[i].name, |
| @@ -124,16 +114,17 @@ static void lgr_stsi_3_2_2(struct lgr_info *lgr_info) | |||
| 124 | */ | 114 | */ |
| 125 | static void lgr_info_get(struct lgr_info *lgr_info) | 115 | static void lgr_info_get(struct lgr_info *lgr_info) |
| 126 | { | 116 | { |
| 117 | int level; | ||
| 118 | |||
| 127 | memset(lgr_info, 0, sizeof(*lgr_info)); | 119 | memset(lgr_info, 0, sizeof(*lgr_info)); |
| 128 | stfle(lgr_info->stfle_fac_list, ARRAY_SIZE(lgr_info->stfle_fac_list)); | 120 | stfle(lgr_info->stfle_fac_list, ARRAY_SIZE(lgr_info->stfle_fac_list)); |
| 129 | lgr_info->level = stsi_0(); | 121 | level = stsi(NULL, 0, 0, 0); |
| 130 | if (lgr_info->level == -ENOSYS) | 122 | lgr_info->level = level; |
| 131 | return; | 123 | if (level >= 1) |
| 132 | if (lgr_info->level >= 1) | ||
| 133 | lgr_stsi_1_1_1(lgr_info); | 124 | lgr_stsi_1_1_1(lgr_info); |
| 134 | if (lgr_info->level >= 2) | 125 | if (level >= 2) |
| 135 | lgr_stsi_2_2_2(lgr_info); | 126 | lgr_stsi_2_2_2(lgr_info); |
| 136 | if (lgr_info->level >= 3) | 127 | if (level >= 3) |
| 137 | lgr_stsi_3_2_2(lgr_info); | 128 | lgr_stsi_3_2_2(lgr_info); |
| 138 | } | 129 | } |
| 139 | 130 | ||
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index 493304bdf1c7..b3de27700016 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <asm/reset.h> | 21 | #include <asm/reset.h> |
| 22 | #include <asm/ipl.h> | 22 | #include <asm/ipl.h> |
| 23 | #include <asm/diag.h> | 23 | #include <asm/diag.h> |
| 24 | #include <asm/elf.h> | ||
| 24 | #include <asm/asm-offsets.h> | 25 | #include <asm/asm-offsets.h> |
| 25 | #include <asm/os_info.h> | 26 | #include <asm/os_info.h> |
| 26 | 27 | ||
| @@ -31,8 +32,6 @@ extern const unsigned long long relocate_kernel_len; | |||
| 31 | 32 | ||
| 32 | #ifdef CONFIG_CRASH_DUMP | 33 | #ifdef CONFIG_CRASH_DUMP |
| 33 | 34 | ||
| 34 | void *fill_cpu_elf_notes(void *ptr, struct save_area *sa); | ||
| 35 | |||
| 36 | /* | 35 | /* |
| 37 | * Create ELF notes for one CPU | 36 | * Create ELF notes for one CPU |
| 38 | */ | 37 | */ |
| @@ -159,7 +158,7 @@ int machine_kexec_prepare(struct kimage *image) | |||
| 159 | 158 | ||
| 160 | /* Can't replace kernel image since it is read-only. */ | 159 | /* Can't replace kernel image since it is read-only. */ |
| 161 | if (ipl_flags & IPL_NSS_VALID) | 160 | if (ipl_flags & IPL_NSS_VALID) |
| 162 | return -ENOSYS; | 161 | return -EOPNOTSUPP; |
| 163 | 162 | ||
| 164 | if (image->type == KEXEC_TYPE_CRASH) | 163 | if (image->type == KEXEC_TYPE_CRASH) |
| 165 | return machine_kexec_prepare_kdump(); | 164 | return machine_kexec_prepare_kdump(); |
| @@ -191,6 +190,10 @@ void machine_shutdown(void) | |||
| 191 | { | 190 | { |
| 192 | } | 191 | } |
| 193 | 192 | ||
| 193 | void machine_crash_shutdown(struct pt_regs *regs) | ||
| 194 | { | ||
| 195 | } | ||
| 196 | |||
| 194 | /* | 197 | /* |
| 195 | * Do normal kexec | 198 | * Do normal kexec |
| 196 | */ | 199 | */ |
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 733175373a4c..5024be27df44 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
| @@ -26,10 +26,12 @@ | |||
| 26 | #include <asm/io.h> | 26 | #include <asm/io.h> |
| 27 | #include <asm/processor.h> | 27 | #include <asm/processor.h> |
| 28 | #include <asm/vtimer.h> | 28 | #include <asm/vtimer.h> |
| 29 | #include <asm/exec.h> | ||
| 29 | #include <asm/irq.h> | 30 | #include <asm/irq.h> |
| 30 | #include <asm/nmi.h> | 31 | #include <asm/nmi.h> |
| 31 | #include <asm/smp.h> | 32 | #include <asm/smp.h> |
| 32 | #include <asm/switch_to.h> | 33 | #include <asm/switch_to.h> |
| 34 | #include <asm/runtime_instr.h> | ||
| 33 | #include "entry.h" | 35 | #include "entry.h" |
| 34 | 36 | ||
| 35 | asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); | 37 | asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); |
| @@ -132,6 +134,7 @@ EXPORT_SYMBOL(kernel_thread); | |||
| 132 | */ | 134 | */ |
| 133 | void exit_thread(void) | 135 | void exit_thread(void) |
| 134 | { | 136 | { |
| 137 | exit_thread_runtime_instr(); | ||
| 135 | } | 138 | } |
| 136 | 139 | ||
| 137 | void flush_thread(void) | 140 | void flush_thread(void) |
| @@ -170,6 +173,11 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | |||
| 170 | /* Save access registers to new thread structure. */ | 173 | /* Save access registers to new thread structure. */ |
| 171 | save_access_regs(&p->thread.acrs[0]); | 174 | save_access_regs(&p->thread.acrs[0]); |
| 172 | 175 | ||
| 176 | /* Don't copy runtime instrumentation info */ | ||
| 177 | p->thread.ri_cb = NULL; | ||
| 178 | p->thread.ri_signum = 0; | ||
| 179 | frame->childregs.psw.mask &= ~PSW_MASK_RI; | ||
| 180 | |||
| 173 | #ifndef CONFIG_64BIT | 181 | #ifndef CONFIG_64BIT |
| 174 | /* | 182 | /* |
| 175 | * save fprs to current->thread.fp_regs to merge them with | 183 | * save fprs to current->thread.fp_regs to merge them with |
diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 572d4c9cb33b..753c41d0ffd3 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c | |||
| @@ -39,9 +39,9 @@ void __cpuinit cpu_init(void) | |||
| 39 | */ | 39 | */ |
| 40 | static int show_cpuinfo(struct seq_file *m, void *v) | 40 | static int show_cpuinfo(struct seq_file *m, void *v) |
| 41 | { | 41 | { |
| 42 | static const char *hwcap_str[10] = { | 42 | static const char *hwcap_str[] = { |
| 43 | "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", | 43 | "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", |
| 44 | "edat", "etf3eh", "highgprs" | 44 | "edat", "etf3eh", "highgprs", "te" |
| 45 | }; | 45 | }; |
| 46 | unsigned long n = (unsigned long) v - 1; | 46 | unsigned long n = (unsigned long) v - 1; |
| 47 | int i; | 47 | int i; |
| @@ -54,10 +54,11 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
| 54 | num_online_cpus(), loops_per_jiffy/(500000/HZ), | 54 | num_online_cpus(), loops_per_jiffy/(500000/HZ), |
| 55 | (loops_per_jiffy/(5000/HZ))%100); | 55 | (loops_per_jiffy/(5000/HZ))%100); |
| 56 | seq_puts(m, "features\t: "); | 56 | seq_puts(m, "features\t: "); |
| 57 | for (i = 0; i < 10; i++) | 57 | for (i = 0; i < ARRAY_SIZE(hwcap_str); i++) |
| 58 | if (hwcap_str[i] && (elf_hwcap & (1UL << i))) | 58 | if (hwcap_str[i] && (elf_hwcap & (1UL << i))) |
| 59 | seq_printf(m, "%s ", hwcap_str[i]); | 59 | seq_printf(m, "%s ", hwcap_str[i]); |
| 60 | seq_puts(m, "\n"); | 60 | seq_puts(m, "\n"); |
| 61 | show_cacheinfo(m); | ||
| 61 | } | 62 | } |
| 62 | get_online_cpus(); | 63 | get_online_cpus(); |
| 63 | if (cpu_online(n)) { | 64 | if (cpu_online(n)) { |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index e4be113fbac6..a314c57f4e94 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
| @@ -42,6 +42,7 @@ enum s390_regset { | |||
| 42 | REGSET_GENERAL, | 42 | REGSET_GENERAL, |
| 43 | REGSET_FP, | 43 | REGSET_FP, |
| 44 | REGSET_LAST_BREAK, | 44 | REGSET_LAST_BREAK, |
| 45 | REGSET_TDB, | ||
| 45 | REGSET_SYSTEM_CALL, | 46 | REGSET_SYSTEM_CALL, |
| 46 | REGSET_GENERAL_EXTENDED, | 47 | REGSET_GENERAL_EXTENDED, |
| 47 | }; | 48 | }; |
| @@ -52,6 +53,22 @@ void update_per_regs(struct task_struct *task) | |||
| 52 | struct thread_struct *thread = &task->thread; | 53 | struct thread_struct *thread = &task->thread; |
| 53 | struct per_regs old, new; | 54 | struct per_regs old, new; |
| 54 | 55 | ||
| 56 | #ifdef CONFIG_64BIT | ||
| 57 | /* Take care of the enable/disable of transactional execution. */ | ||
| 58 | if (MACHINE_HAS_TE) { | ||
| 59 | unsigned long cr0, cr0_new; | ||
| 60 | |||
| 61 | __ctl_store(cr0, 0, 0); | ||
| 62 | /* set or clear transaction execution bits 8 and 9. */ | ||
| 63 | if (task->thread.per_flags & PER_FLAG_NO_TE) | ||
| 64 | cr0_new = cr0 & ~(3UL << 54); | ||
| 65 | else | ||
| 66 | cr0_new = cr0 | (3UL << 54); | ||
| 67 | /* Only load control register 0 if necessary. */ | ||
| 68 | if (cr0 != cr0_new) | ||
| 69 | __ctl_load(cr0_new, 0, 0); | ||
| 70 | } | ||
| 71 | #endif | ||
| 55 | /* Copy user specified PER registers */ | 72 | /* Copy user specified PER registers */ |
| 56 | new.control = thread->per_user.control; | 73 | new.control = thread->per_user.control; |
| 57 | new.start = thread->per_user.start; | 74 | new.start = thread->per_user.start; |
| @@ -60,6 +77,10 @@ void update_per_regs(struct task_struct *task) | |||
| 60 | /* merge TIF_SINGLE_STEP into user specified PER registers. */ | 77 | /* merge TIF_SINGLE_STEP into user specified PER registers. */ |
| 61 | if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) { | 78 | if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) { |
| 62 | new.control |= PER_EVENT_IFETCH; | 79 | new.control |= PER_EVENT_IFETCH; |
| 80 | #ifdef CONFIG_64BIT | ||
| 81 | new.control |= PER_CONTROL_SUSPENSION; | ||
| 82 | new.control |= PER_EVENT_TRANSACTION_END; | ||
| 83 | #endif | ||
| 63 | new.start = 0; | 84 | new.start = 0; |
| 64 | new.end = PSW_ADDR_INSN; | 85 | new.end = PSW_ADDR_INSN; |
| 65 | } | 86 | } |
| @@ -100,6 +121,7 @@ void ptrace_disable(struct task_struct *task) | |||
| 100 | memset(&task->thread.per_event, 0, sizeof(task->thread.per_event)); | 121 | memset(&task->thread.per_event, 0, sizeof(task->thread.per_event)); |
| 101 | clear_tsk_thread_flag(task, TIF_SINGLE_STEP); | 122 | clear_tsk_thread_flag(task, TIF_SINGLE_STEP); |
| 102 | clear_tsk_thread_flag(task, TIF_PER_TRAP); | 123 | clear_tsk_thread_flag(task, TIF_PER_TRAP); |
| 124 | task->thread.per_flags = 0; | ||
| 103 | } | 125 | } |
| 104 | 126 | ||
| 105 | #ifndef CONFIG_64BIT | 127 | #ifndef CONFIG_64BIT |
| @@ -416,6 +438,16 @@ long arch_ptrace(struct task_struct *child, long request, | |||
| 416 | put_user(task_thread_info(child)->last_break, | 438 | put_user(task_thread_info(child)->last_break, |
| 417 | (unsigned long __user *) data); | 439 | (unsigned long __user *) data); |
| 418 | return 0; | 440 | return 0; |
| 441 | case PTRACE_ENABLE_TE: | ||
| 442 | if (!MACHINE_HAS_TE) | ||
| 443 | return -EIO; | ||
| 444 | child->thread.per_flags &= ~PER_FLAG_NO_TE; | ||
| 445 | return 0; | ||
| 446 | case PTRACE_DISABLE_TE: | ||
| 447 | if (!MACHINE_HAS_TE) | ||
| 448 | return -EIO; | ||
| 449 | child->thread.per_flags |= PER_FLAG_NO_TE; | ||
| 450 | return 0; | ||
| 419 | default: | 451 | default: |
| 420 | /* Removing high order bit from addr (only for 31 bit). */ | 452 | /* Removing high order bit from addr (only for 31 bit). */ |
| 421 | addr &= PSW_ADDR_INSN; | 453 | addr &= PSW_ADDR_INSN; |
| @@ -903,6 +935,28 @@ static int s390_last_break_set(struct task_struct *target, | |||
| 903 | return 0; | 935 | return 0; |
| 904 | } | 936 | } |
| 905 | 937 | ||
| 938 | static int s390_tdb_get(struct task_struct *target, | ||
| 939 | const struct user_regset *regset, | ||
| 940 | unsigned int pos, unsigned int count, | ||
| 941 | void *kbuf, void __user *ubuf) | ||
| 942 | { | ||
| 943 | struct pt_regs *regs = task_pt_regs(target); | ||
| 944 | unsigned char *data; | ||
| 945 | |||
| 946 | if (!(regs->int_code & 0x200)) | ||
| 947 | return -ENODATA; | ||
| 948 | data = target->thread.trap_tdb; | ||
| 949 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, data, 0, 256); | ||
| 950 | } | ||
| 951 | |||
| 952 | static int s390_tdb_set(struct task_struct *target, | ||
| 953 | const struct user_regset *regset, | ||
| 954 | unsigned int pos, unsigned int count, | ||
| 955 | const void *kbuf, const void __user *ubuf) | ||
| 956 | { | ||
| 957 | return 0; | ||
| 958 | } | ||
| 959 | |||
| 906 | #endif | 960 | #endif |
| 907 | 961 | ||
| 908 | static int s390_system_call_get(struct task_struct *target, | 962 | static int s390_system_call_get(struct task_struct *target, |
| @@ -951,6 +1005,14 @@ static const struct user_regset s390_regsets[] = { | |||
| 951 | .get = s390_last_break_get, | 1005 | .get = s390_last_break_get, |
| 952 | .set = s390_last_break_set, | 1006 | .set = s390_last_break_set, |
| 953 | }, | 1007 | }, |
| 1008 | [REGSET_TDB] = { | ||
| 1009 | .core_note_type = NT_S390_TDB, | ||
| 1010 | .n = 1, | ||
| 1011 | .size = 256, | ||
| 1012 | .align = 1, | ||
| 1013 | .get = s390_tdb_get, | ||
| 1014 | .set = s390_tdb_set, | ||
| 1015 | }, | ||
| 954 | #endif | 1016 | #endif |
| 955 | [REGSET_SYSTEM_CALL] = { | 1017 | [REGSET_SYSTEM_CALL] = { |
| 956 | .core_note_type = NT_S390_SYSTEM_CALL, | 1018 | .core_note_type = NT_S390_SYSTEM_CALL, |
| @@ -1148,6 +1210,14 @@ static const struct user_regset s390_compat_regsets[] = { | |||
| 1148 | .get = s390_compat_last_break_get, | 1210 | .get = s390_compat_last_break_get, |
| 1149 | .set = s390_compat_last_break_set, | 1211 | .set = s390_compat_last_break_set, |
| 1150 | }, | 1212 | }, |
| 1213 | [REGSET_TDB] = { | ||
| 1214 | .core_note_type = NT_S390_TDB, | ||
| 1215 | .n = 1, | ||
| 1216 | .size = 256, | ||
| 1217 | .align = 1, | ||
| 1218 | .get = s390_tdb_get, | ||
| 1219 | .set = s390_tdb_set, | ||
| 1220 | }, | ||
| 1151 | [REGSET_SYSTEM_CALL] = { | 1221 | [REGSET_SYSTEM_CALL] = { |
| 1152 | .core_note_type = NT_S390_SYSTEM_CALL, | 1222 | .core_note_type = NT_S390_SYSTEM_CALL, |
| 1153 | .n = 1, | 1223 | .n = 1, |
diff --git a/arch/s390/kernel/runtime_instr.c b/arch/s390/kernel/runtime_instr.c new file mode 100644 index 000000000000..61066f6f71a5 --- /dev/null +++ b/arch/s390/kernel/runtime_instr.c | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | /* | ||
| 2 | * Copyright IBM Corp. 2012 | ||
| 3 | * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/kernel.h> | ||
| 7 | #include <linux/syscalls.h> | ||
| 8 | #include <linux/signal.h> | ||
| 9 | #include <linux/mm.h> | ||
| 10 | #include <linux/slab.h> | ||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/errno.h> | ||
| 13 | #include <linux/kernel_stat.h> | ||
| 14 | #include <asm/runtime_instr.h> | ||
| 15 | #include <asm/cpu_mf.h> | ||
| 16 | #include <asm/irq.h> | ||
| 17 | |||
| 18 | /* empty control block to disable RI by loading it */ | ||
| 19 | struct runtime_instr_cb runtime_instr_empty_cb; | ||
| 20 | |||
| 21 | static int runtime_instr_avail(void) | ||
| 22 | { | ||
| 23 | return test_facility(64); | ||
| 24 | } | ||
| 25 | |||
| 26 | static void disable_runtime_instr(void) | ||
| 27 | { | ||
| 28 | struct pt_regs *regs = task_pt_regs(current); | ||
| 29 | |||
| 30 | load_runtime_instr_cb(&runtime_instr_empty_cb); | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Make sure the RI bit is deleted from the PSW. If the user did not | ||
| 34 | * switch off RI before the system call the process will get a | ||
| 35 | * specification exception otherwise. | ||
| 36 | */ | ||
| 37 | regs->psw.mask &= ~PSW_MASK_RI; | ||
| 38 | } | ||
| 39 | |||
| 40 | static void init_runtime_instr_cb(struct runtime_instr_cb *cb) | ||
| 41 | { | ||
| 42 | cb->buf_limit = 0xfff; | ||
| 43 | if (s390_user_mode == HOME_SPACE_MODE) | ||
| 44 | cb->home_space = 1; | ||
| 45 | cb->int_requested = 1; | ||
| 46 | cb->pstate = 1; | ||
| 47 | cb->pstate_set_buf = 1; | ||
| 48 | cb->pstate_sample = 1; | ||
| 49 | cb->pstate_collect = 1; | ||
| 50 | cb->key = PAGE_DEFAULT_KEY; | ||
| 51 | cb->valid = 1; | ||
| 52 | } | ||
| 53 | |||
| 54 | void exit_thread_runtime_instr(void) | ||
| 55 | { | ||
| 56 | struct task_struct *task = current; | ||
| 57 | |||
| 58 | if (!task->thread.ri_cb) | ||
| 59 | return; | ||
| 60 | disable_runtime_instr(); | ||
| 61 | kfree(task->thread.ri_cb); | ||
| 62 | task->thread.ri_signum = 0; | ||
| 63 | task->thread.ri_cb = NULL; | ||
| 64 | } | ||
| 65 | |||
| 66 | static void runtime_instr_int_handler(struct ext_code ext_code, | ||
| 67 | unsigned int param32, unsigned long param64) | ||
| 68 | { | ||
| 69 | struct siginfo info; | ||
| 70 | |||
| 71 | if (!(param32 & CPU_MF_INT_RI_MASK)) | ||
| 72 | return; | ||
| 73 | |||
| 74 | kstat_cpu(smp_processor_id()).irqs[EXTINT_CMR]++; | ||
| 75 | |||
| 76 | if (!current->thread.ri_cb) | ||
| 77 | return; | ||
| 78 | if (current->thread.ri_signum < SIGRTMIN || | ||
| 79 | current->thread.ri_signum > SIGRTMAX) { | ||
| 80 | WARN_ON_ONCE(1); | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | |||
| 84 | memset(&info, 0, sizeof(info)); | ||
| 85 | info.si_signo = current->thread.ri_signum; | ||
| 86 | info.si_code = SI_QUEUE; | ||
| 87 | if (param32 & CPU_MF_INT_RI_BUF_FULL) | ||
| 88 | info.si_int = ENOBUFS; | ||
| 89 | else if (param32 & CPU_MF_INT_RI_HALTED) | ||
| 90 | info.si_int = ECANCELED; | ||
| 91 | else | ||
| 92 | return; /* unknown reason */ | ||
| 93 | |||
| 94 | send_sig_info(current->thread.ri_signum, &info, current); | ||
| 95 | } | ||
| 96 | |||
| 97 | SYSCALL_DEFINE2(s390_runtime_instr, int, command, int, signum) | ||
| 98 | { | ||
| 99 | struct runtime_instr_cb *cb; | ||
| 100 | |||
| 101 | if (!runtime_instr_avail()) | ||
| 102 | return -EOPNOTSUPP; | ||
| 103 | |||
| 104 | if (command == S390_RUNTIME_INSTR_STOP) { | ||
| 105 | preempt_disable(); | ||
| 106 | exit_thread_runtime_instr(); | ||
| 107 | preempt_enable(); | ||
| 108 | return 0; | ||
| 109 | } | ||
| 110 | |||
| 111 | if (command != S390_RUNTIME_INSTR_START || | ||
| 112 | (signum < SIGRTMIN || signum > SIGRTMAX)) | ||
| 113 | return -EINVAL; | ||
| 114 | |||
| 115 | if (!current->thread.ri_cb) { | ||
| 116 | cb = kzalloc(sizeof(*cb), GFP_KERNEL); | ||
| 117 | if (!cb) | ||
| 118 | return -ENOMEM; | ||
| 119 | } else { | ||
| 120 | cb = current->thread.ri_cb; | ||
| 121 | memset(cb, 0, sizeof(*cb)); | ||
| 122 | } | ||
| 123 | |||
| 124 | init_runtime_instr_cb(cb); | ||
| 125 | current->thread.ri_signum = signum; | ||
| 126 | |||
| 127 | /* now load the control block to make it available */ | ||
| 128 | preempt_disable(); | ||
| 129 | current->thread.ri_cb = cb; | ||
| 130 | load_runtime_instr_cb(cb); | ||
| 131 | preempt_enable(); | ||
| 132 | return 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int __init runtime_instr_init(void) | ||
| 136 | { | ||
| 137 | int rc; | ||
| 138 | |||
| 139 | if (!runtime_instr_avail()) | ||
| 140 | return 0; | ||
| 141 | |||
| 142 | measurement_alert_subclass_register(); | ||
| 143 | rc = register_external_interrupt(0x1407, runtime_instr_int_handler); | ||
| 144 | if (rc) | ||
| 145 | measurement_alert_subclass_unregister(); | ||
| 146 | else | ||
| 147 | pr_info("Runtime instrumentation facility initialized\n"); | ||
| 148 | return rc; | ||
| 149 | } | ||
| 150 | device_initcall(runtime_instr_init); | ||
diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 57b536649b00..9bdbcef1da9e 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c | |||
| @@ -8,3 +8,5 @@ EXPORT_SYMBOL(_mcount); | |||
| 8 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | 8 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) |
| 9 | EXPORT_SYMBOL(sie64a); | 9 | EXPORT_SYMBOL(sie64a); |
| 10 | #endif | 10 | #endif |
| 11 | EXPORT_SYMBOL(memcpy); | ||
| 12 | EXPORT_SYMBOL(memset); | ||
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 40b57693de38..afa9fdba200e 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
| @@ -302,10 +302,10 @@ static int __init parse_vmalloc(char *arg) | |||
| 302 | } | 302 | } |
| 303 | early_param("vmalloc", parse_vmalloc); | 303 | early_param("vmalloc", parse_vmalloc); |
| 304 | 304 | ||
| 305 | unsigned int addressing_mode = HOME_SPACE_MODE; | 305 | unsigned int s390_user_mode = PRIMARY_SPACE_MODE; |
| 306 | EXPORT_SYMBOL_GPL(addressing_mode); | 306 | EXPORT_SYMBOL_GPL(s390_user_mode); |
| 307 | 307 | ||
| 308 | static int set_amode_primary(void) | 308 | static void __init set_user_mode_primary(void) |
| 309 | { | 309 | { |
| 310 | psw_kernel_bits = (psw_kernel_bits & ~PSW_MASK_ASC) | PSW_ASC_HOME; | 310 | psw_kernel_bits = (psw_kernel_bits & ~PSW_MASK_ASC) | PSW_ASC_HOME; |
| 311 | psw_user_bits = (psw_user_bits & ~PSW_MASK_ASC) | PSW_ASC_PRIMARY; | 311 | psw_user_bits = (psw_user_bits & ~PSW_MASK_ASC) | PSW_ASC_PRIMARY; |
| @@ -313,48 +313,30 @@ static int set_amode_primary(void) | |||
| 313 | psw32_user_bits = | 313 | psw32_user_bits = |
| 314 | (psw32_user_bits & ~PSW32_MASK_ASC) | PSW32_ASC_PRIMARY; | 314 | (psw32_user_bits & ~PSW32_MASK_ASC) | PSW32_ASC_PRIMARY; |
| 315 | #endif | 315 | #endif |
| 316 | 316 | uaccess = MACHINE_HAS_MVCOS ? uaccess_mvcos_switch : uaccess_pt; | |
| 317 | if (MACHINE_HAS_MVCOS) { | ||
| 318 | memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess)); | ||
| 319 | return 1; | ||
| 320 | } else { | ||
| 321 | memcpy(&uaccess, &uaccess_pt, sizeof(uaccess)); | ||
| 322 | return 0; | ||
| 323 | } | ||
| 324 | } | ||
| 325 | |||
| 326 | /* | ||
| 327 | * Switch kernel/user addressing modes? | ||
| 328 | */ | ||
| 329 | static int __init early_parse_switch_amode(char *p) | ||
| 330 | { | ||
| 331 | addressing_mode = PRIMARY_SPACE_MODE; | ||
| 332 | return 0; | ||
| 333 | } | 317 | } |
| 334 | early_param("switch_amode", early_parse_switch_amode); | ||
| 335 | 318 | ||
| 336 | static int __init early_parse_user_mode(char *p) | 319 | static int __init early_parse_user_mode(char *p) |
| 337 | { | 320 | { |
| 338 | if (p && strcmp(p, "primary") == 0) | 321 | if (p && strcmp(p, "primary") == 0) |
| 339 | addressing_mode = PRIMARY_SPACE_MODE; | 322 | s390_user_mode = PRIMARY_SPACE_MODE; |
| 340 | else if (!p || strcmp(p, "home") == 0) | 323 | else if (!p || strcmp(p, "home") == 0) |
| 341 | addressing_mode = HOME_SPACE_MODE; | 324 | s390_user_mode = HOME_SPACE_MODE; |
| 342 | else | 325 | else |
| 343 | return 1; | 326 | return 1; |
| 344 | return 0; | 327 | return 0; |
| 345 | } | 328 | } |
| 346 | early_param("user_mode", early_parse_user_mode); | 329 | early_param("user_mode", early_parse_user_mode); |
| 347 | 330 | ||
| 348 | static void setup_addressing_mode(void) | 331 | static void __init setup_addressing_mode(void) |
| 349 | { | 332 | { |
| 350 | if (addressing_mode == PRIMARY_SPACE_MODE) { | 333 | if (s390_user_mode != PRIMARY_SPACE_MODE) |
| 351 | if (set_amode_primary()) | 334 | return; |
| 352 | pr_info("Address spaces switched, " | 335 | set_user_mode_primary(); |
| 353 | "mvcos available\n"); | 336 | if (MACHINE_HAS_MVCOS) |
| 354 | else | 337 | pr_info("Address spaces switched, mvcos available\n"); |
| 355 | pr_info("Address spaces switched, " | 338 | else |
| 356 | "mvcos not available\n"); | 339 | pr_info("Address spaces switched, mvcos not available\n"); |
| 357 | } | ||
| 358 | } | 340 | } |
| 359 | 341 | ||
| 360 | void *restart_stack __attribute__((__section__(".data"))); | 342 | void *restart_stack __attribute__((__section__(".data"))); |
| @@ -602,9 +584,7 @@ static void __init setup_memory_end(void) | |||
| 602 | 584 | ||
| 603 | static void __init setup_vmcoreinfo(void) | 585 | static void __init setup_vmcoreinfo(void) |
| 604 | { | 586 | { |
| 605 | #ifdef CONFIG_KEXEC | ||
| 606 | mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note()); | 587 | mem_assign_absolute(S390_lowcore.vmcore_info, paddr_vmcoreinfo_note()); |
| 607 | #endif | ||
| 608 | } | 588 | } |
| 609 | 589 | ||
| 610 | #ifdef CONFIG_CRASH_DUMP | 590 | #ifdef CONFIG_CRASH_DUMP |
| @@ -980,6 +960,12 @@ static void __init setup_hwcaps(void) | |||
| 980 | * HWCAP_S390_HIGH_GPRS is bit 9. | 960 | * HWCAP_S390_HIGH_GPRS is bit 9. |
| 981 | */ | 961 | */ |
| 982 | elf_hwcap |= HWCAP_S390_HIGH_GPRS; | 962 | elf_hwcap |= HWCAP_S390_HIGH_GPRS; |
| 963 | |||
| 964 | /* | ||
| 965 | * Transactional execution support HWCAP_S390_TE is bit 10. | ||
| 966 | */ | ||
| 967 | if (test_facility(50) && test_facility(73)) | ||
| 968 | elf_hwcap |= HWCAP_S390_TE; | ||
| 983 | #endif | 969 | #endif |
| 984 | 970 | ||
| 985 | get_cpu_id(&cpu_id); | 971 | get_cpu_id(&cpu_id); |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 720fda1620f2..ea431e551c6b 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
| @@ -66,7 +66,7 @@ struct pcpu { | |||
| 66 | unsigned long panic_stack; /* panic stack for the cpu */ | 66 | unsigned long panic_stack; /* panic stack for the cpu */ |
| 67 | unsigned long ec_mask; /* bit mask for ec_xxx functions */ | 67 | unsigned long ec_mask; /* bit mask for ec_xxx functions */ |
| 68 | int state; /* physical cpu state */ | 68 | int state; /* physical cpu state */ |
| 69 | u32 status; /* last status received via sigp */ | 69 | int polarization; /* physical polarization */ |
| 70 | u16 address; /* physical cpu address */ | 70 | u16 address; /* physical cpu address */ |
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| @@ -74,6 +74,10 @@ static u8 boot_cpu_type; | |||
| 74 | static u16 boot_cpu_address; | 74 | static u16 boot_cpu_address; |
| 75 | static struct pcpu pcpu_devices[NR_CPUS]; | 75 | static struct pcpu pcpu_devices[NR_CPUS]; |
| 76 | 76 | ||
| 77 | /* | ||
| 78 | * The smp_cpu_state_mutex must be held when changing the state or polarization | ||
| 79 | * member of a pcpu data structure within the pcpu_devices arreay. | ||
| 80 | */ | ||
| 77 | DEFINE_MUTEX(smp_cpu_state_mutex); | 81 | DEFINE_MUTEX(smp_cpu_state_mutex); |
| 78 | 82 | ||
| 79 | /* | 83 | /* |
| @@ -99,7 +103,7 @@ static inline int __pcpu_sigp_relax(u16 addr, u8 order, u32 parm, u32 *status) | |||
| 99 | int cc; | 103 | int cc; |
| 100 | 104 | ||
| 101 | while (1) { | 105 | while (1) { |
| 102 | cc = __pcpu_sigp(addr, order, parm, status); | 106 | cc = __pcpu_sigp(addr, order, parm, NULL); |
| 103 | if (cc != SIGP_CC_BUSY) | 107 | if (cc != SIGP_CC_BUSY) |
| 104 | return cc; | 108 | return cc; |
| 105 | cpu_relax(); | 109 | cpu_relax(); |
| @@ -111,7 +115,7 @@ static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm) | |||
| 111 | int cc, retry; | 115 | int cc, retry; |
| 112 | 116 | ||
| 113 | for (retry = 0; ; retry++) { | 117 | for (retry = 0; ; retry++) { |
| 114 | cc = __pcpu_sigp(pcpu->address, order, parm, &pcpu->status); | 118 | cc = __pcpu_sigp(pcpu->address, order, parm, NULL); |
| 115 | if (cc != SIGP_CC_BUSY) | 119 | if (cc != SIGP_CC_BUSY) |
| 116 | break; | 120 | break; |
| 117 | if (retry >= 3) | 121 | if (retry >= 3) |
| @@ -122,16 +126,18 @@ static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm) | |||
| 122 | 126 | ||
| 123 | static inline int pcpu_stopped(struct pcpu *pcpu) | 127 | static inline int pcpu_stopped(struct pcpu *pcpu) |
| 124 | { | 128 | { |
| 129 | u32 uninitialized_var(status); | ||
| 130 | |||
| 125 | if (__pcpu_sigp(pcpu->address, SIGP_SENSE, | 131 | if (__pcpu_sigp(pcpu->address, SIGP_SENSE, |
| 126 | 0, &pcpu->status) != SIGP_CC_STATUS_STORED) | 132 | 0, &status) != SIGP_CC_STATUS_STORED) |
| 127 | return 0; | 133 | return 0; |
| 128 | return !!(pcpu->status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED)); | 134 | return !!(status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED)); |
| 129 | } | 135 | } |
| 130 | 136 | ||
| 131 | static inline int pcpu_running(struct pcpu *pcpu) | 137 | static inline int pcpu_running(struct pcpu *pcpu) |
| 132 | { | 138 | { |
| 133 | if (__pcpu_sigp(pcpu->address, SIGP_SENSE_RUNNING, | 139 | if (__pcpu_sigp(pcpu->address, SIGP_SENSE_RUNNING, |
| 134 | 0, &pcpu->status) != SIGP_CC_STATUS_STORED) | 140 | 0, NULL) != SIGP_CC_STATUS_STORED) |
| 135 | return 1; | 141 | return 1; |
| 136 | /* Status stored condition code is equivalent to cpu not running. */ | 142 | /* Status stored condition code is equivalent to cpu not running. */ |
| 137 | return 0; | 143 | return 0; |
| @@ -586,6 +592,16 @@ static inline void smp_get_save_area(int cpu, u16 address) { } | |||
| 586 | 592 | ||
| 587 | #endif /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */ | 593 | #endif /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */ |
| 588 | 594 | ||
| 595 | void smp_cpu_set_polarization(int cpu, int val) | ||
| 596 | { | ||
| 597 | pcpu_devices[cpu].polarization = val; | ||
| 598 | } | ||
| 599 | |||
| 600 | int smp_cpu_get_polarization(int cpu) | ||
| 601 | { | ||
| 602 | return pcpu_devices[cpu].polarization; | ||
| 603 | } | ||
| 604 | |||
| 589 | static struct sclp_cpu_info *smp_get_cpu_info(void) | 605 | static struct sclp_cpu_info *smp_get_cpu_info(void) |
| 590 | { | 606 | { |
| 591 | static int use_sigp_detection; | 607 | static int use_sigp_detection; |
| @@ -628,7 +644,7 @@ static int __devinit __smp_rescan_cpus(struct sclp_cpu_info *info, | |||
| 628 | pcpu->address = info->cpu[i].address; | 644 | pcpu->address = info->cpu[i].address; |
| 629 | pcpu->state = (cpu >= info->configured) ? | 645 | pcpu->state = (cpu >= info->configured) ? |
| 630 | CPU_STATE_STANDBY : CPU_STATE_CONFIGURED; | 646 | CPU_STATE_STANDBY : CPU_STATE_CONFIGURED; |
| 631 | cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); | 647 | smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); |
| 632 | set_cpu_present(cpu, true); | 648 | set_cpu_present(cpu, true); |
| 633 | if (sysfs_add && smp_add_present_cpu(cpu) != 0) | 649 | if (sysfs_add && smp_add_present_cpu(cpu) != 0) |
| 634 | set_cpu_present(cpu, false); | 650 | set_cpu_present(cpu, false); |
| @@ -796,7 +812,7 @@ void __init smp_prepare_boot_cpu(void) | |||
| 796 | pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE; | 812 | pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE; |
| 797 | pcpu->panic_stack = S390_lowcore.panic_stack - PAGE_SIZE; | 813 | pcpu->panic_stack = S390_lowcore.panic_stack - PAGE_SIZE; |
| 798 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; | 814 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; |
| 799 | cpu_set_polarization(0, POLARIZATION_UNKNOWN); | 815 | smp_cpu_set_polarization(0, POLARIZATION_UNKNOWN); |
| 800 | set_cpu_present(0, true); | 816 | set_cpu_present(0, true); |
| 801 | set_cpu_online(0, true); | 817 | set_cpu_online(0, true); |
| 802 | } | 818 | } |
| @@ -862,7 +878,7 @@ static ssize_t cpu_configure_store(struct device *dev, | |||
| 862 | if (rc) | 878 | if (rc) |
| 863 | break; | 879 | break; |
| 864 | pcpu->state = CPU_STATE_STANDBY; | 880 | pcpu->state = CPU_STATE_STANDBY; |
| 865 | cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); | 881 | smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); |
| 866 | topology_expect_change(); | 882 | topology_expect_change(); |
| 867 | break; | 883 | break; |
| 868 | case 1: | 884 | case 1: |
| @@ -872,7 +888,7 @@ static ssize_t cpu_configure_store(struct device *dev, | |||
| 872 | if (rc) | 888 | if (rc) |
| 873 | break; | 889 | break; |
| 874 | pcpu->state = CPU_STATE_CONFIGURED; | 890 | pcpu->state = CPU_STATE_CONFIGURED; |
| 875 | cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); | 891 | smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); |
| 876 | topology_expect_change(); | 892 | topology_expect_change(); |
| 877 | break; | 893 | break; |
| 878 | default: | 894 | default: |
| @@ -959,23 +975,17 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self, | |||
| 959 | struct device *s = &c->dev; | 975 | struct device *s = &c->dev; |
| 960 | int err = 0; | 976 | int err = 0; |
| 961 | 977 | ||
| 962 | switch (action) { | 978 | switch (action & ~CPU_TASKS_FROZEN) { |
| 963 | case CPU_ONLINE: | 979 | case CPU_ONLINE: |
| 964 | case CPU_ONLINE_FROZEN: | ||
| 965 | err = sysfs_create_group(&s->kobj, &cpu_online_attr_group); | 980 | err = sysfs_create_group(&s->kobj, &cpu_online_attr_group); |
| 966 | break; | 981 | break; |
| 967 | case CPU_DEAD: | 982 | case CPU_DEAD: |
| 968 | case CPU_DEAD_FROZEN: | ||
| 969 | sysfs_remove_group(&s->kobj, &cpu_online_attr_group); | 983 | sysfs_remove_group(&s->kobj, &cpu_online_attr_group); |
| 970 | break; | 984 | break; |
| 971 | } | 985 | } |
| 972 | return notifier_from_errno(err); | 986 | return notifier_from_errno(err); |
| 973 | } | 987 | } |
| 974 | 988 | ||
| 975 | static struct notifier_block __cpuinitdata smp_cpu_nb = { | ||
| 976 | .notifier_call = smp_cpu_notify, | ||
| 977 | }; | ||
| 978 | |||
| 979 | static int __devinit smp_add_present_cpu(int cpu) | 989 | static int __devinit smp_add_present_cpu(int cpu) |
| 980 | { | 990 | { |
| 981 | struct cpu *c = &pcpu_devices[cpu].cpu; | 991 | struct cpu *c = &pcpu_devices[cpu].cpu; |
| @@ -1050,7 +1060,7 @@ static int __init s390_smp_init(void) | |||
| 1050 | { | 1060 | { |
| 1051 | int cpu, rc; | 1061 | int cpu, rc; |
| 1052 | 1062 | ||
| 1053 | register_cpu_notifier(&smp_cpu_nb); | 1063 | hotcpu_notifier(smp_cpu_notify, 0); |
| 1054 | #ifdef CONFIG_HOTPLUG_CPU | 1064 | #ifdef CONFIG_HOTPLUG_CPU |
| 1055 | rc = device_create_file(cpu_subsys.dev_root, &dev_attr_rescan); | 1065 | rc = device_create_file(cpu_subsys.dev_root, &dev_attr_rescan); |
| 1056 | if (rc) | 1066 | if (rc) |
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index bcab2f04ba58..48174850f3b0 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S | |||
| @@ -350,3 +350,5 @@ SYSCALL(sys_syncfs,sys_syncfs,sys_syncfs_wrapper) | |||
| 350 | SYSCALL(sys_setns,sys_setns,sys_setns_wrapper) | 350 | SYSCALL(sys_setns,sys_setns,sys_setns_wrapper) |
| 351 | SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv_wrapper) /* 340 */ | 351 | SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv_wrapper) /* 340 */ |
| 352 | SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper) | 352 | SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper) |
| 353 | SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper) | ||
| 354 | SYSCALL(sys_kcmp,sys_kcmp,sys_kcmp_wrapper) | ||
diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c index fa0eb238dac7..62f89d98e880 100644 --- a/arch/s390/kernel/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c | |||
| @@ -22,17 +22,41 @@ | |||
| 22 | #include <math-emu/soft-fp.h> | 22 | #include <math-emu/soft-fp.h> |
| 23 | #include <math-emu/single.h> | 23 | #include <math-emu/single.h> |
| 24 | 24 | ||
| 25 | static inline int stsi_0(void) | 25 | int topology_max_mnest; |
| 26 | |||
| 27 | /* | ||
| 28 | * stsi - store system information | ||
| 29 | * | ||
| 30 | * Returns the current configuration level if function code 0 was specified. | ||
| 31 | * Otherwise returns 0 on success or a negative value on error. | ||
| 32 | */ | ||
| 33 | int stsi(void *sysinfo, int fc, int sel1, int sel2) | ||
| 26 | { | 34 | { |
| 27 | int rc = stsi(NULL, 0, 0, 0); | 35 | register int r0 asm("0") = (fc << 28) | sel1; |
| 28 | return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28); | 36 | register int r1 asm("1") = sel2; |
| 37 | int rc = 0; | ||
| 38 | |||
| 39 | asm volatile( | ||
| 40 | " stsi 0(%3)\n" | ||
| 41 | "0: jz 2f\n" | ||
| 42 | "1: lhi %1,%4\n" | ||
| 43 | "2:\n" | ||
| 44 | EX_TABLE(0b, 1b) | ||
| 45 | : "+d" (r0), "+d" (rc) | ||
| 46 | : "d" (r1), "a" (sysinfo), "K" (-EOPNOTSUPP) | ||
| 47 | : "cc", "memory"); | ||
| 48 | if (rc) | ||
| 49 | return rc; | ||
| 50 | return fc ? 0 : ((unsigned int) r0) >> 28; | ||
| 29 | } | 51 | } |
| 52 | EXPORT_SYMBOL(stsi); | ||
| 30 | 53 | ||
| 31 | static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len) | 54 | static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info) |
| 32 | { | 55 | { |
| 33 | if (stsi(info, 1, 1, 1) == -ENOSYS) | 56 | int i; |
| 34 | return len; | ||
| 35 | 57 | ||
| 58 | if (stsi(info, 1, 1, 1)) | ||
| 59 | return; | ||
| 36 | EBCASC(info->manufacturer, sizeof(info->manufacturer)); | 60 | EBCASC(info->manufacturer, sizeof(info->manufacturer)); |
| 37 | EBCASC(info->type, sizeof(info->type)); | 61 | EBCASC(info->type, sizeof(info->type)); |
| 38 | EBCASC(info->model, sizeof(info->model)); | 62 | EBCASC(info->model, sizeof(info->model)); |
| @@ -41,242 +65,197 @@ static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len) | |||
| 41 | EBCASC(info->model_capacity, sizeof(info->model_capacity)); | 65 | EBCASC(info->model_capacity, sizeof(info->model_capacity)); |
| 42 | EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap)); | 66 | EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap)); |
| 43 | EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap)); | 67 | EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap)); |
| 44 | len += sprintf(page + len, "Manufacturer: %-16.16s\n", | 68 | seq_printf(m, "Manufacturer: %-16.16s\n", info->manufacturer); |
| 45 | info->manufacturer); | 69 | seq_printf(m, "Type: %-4.4s\n", info->type); |
| 46 | len += sprintf(page + len, "Type: %-4.4s\n", | 70 | /* |
| 47 | info->type); | 71 | * Sigh: the model field has been renamed with System z9 |
| 72 | * to model_capacity and a new model field has been added | ||
| 73 | * after the plant field. To avoid confusing older programs | ||
| 74 | * the "Model:" prints "model_capacity model" or just | ||
| 75 | * "model_capacity" if the model string is empty . | ||
| 76 | */ | ||
| 77 | seq_printf(m, "Model: %-16.16s", info->model_capacity); | ||
| 48 | if (info->model[0] != '\0') | 78 | if (info->model[0] != '\0') |
| 49 | /* | 79 | seq_printf(m, " %-16.16s", info->model); |
| 50 | * Sigh: the model field has been renamed with System z9 | 80 | seq_putc(m, '\n'); |
| 51 | * to model_capacity and a new model field has been added | 81 | seq_printf(m, "Sequence Code: %-16.16s\n", info->sequence); |
| 52 | * after the plant field. To avoid confusing older programs | 82 | seq_printf(m, "Plant: %-4.4s\n", info->plant); |
| 53 | * the "Model:" prints "model_capacity model" or just | 83 | seq_printf(m, "Model Capacity: %-16.16s %08u\n", |
| 54 | * "model_capacity" if the model string is empty . | 84 | info->model_capacity, info->model_cap_rating); |
| 55 | */ | 85 | if (info->model_perm_cap_rating) |
| 56 | len += sprintf(page + len, | 86 | seq_printf(m, "Model Perm. Capacity: %-16.16s %08u\n", |
| 57 | "Model: %-16.16s %-16.16s\n", | 87 | info->model_perm_cap, |
| 58 | info->model_capacity, info->model); | 88 | info->model_perm_cap_rating); |
| 59 | else | 89 | if (info->model_temp_cap_rating) |
| 60 | len += sprintf(page + len, "Model: %-16.16s\n", | 90 | seq_printf(m, "Model Temp. Capacity: %-16.16s %08u\n", |
| 61 | info->model_capacity); | 91 | info->model_temp_cap, |
| 62 | len += sprintf(page + len, "Sequence Code: %-16.16s\n", | 92 | info->model_temp_cap_rating); |
| 63 | info->sequence); | 93 | if (info->ncr) |
| 64 | len += sprintf(page + len, "Plant: %-4.4s\n", | 94 | seq_printf(m, "Nominal Cap. Rating: %08u\n", info->ncr); |
| 65 | info->plant); | 95 | if (info->npr) |
| 66 | len += sprintf(page + len, "Model Capacity: %-16.16s %08u\n", | 96 | seq_printf(m, "Nominal Perm. Rating: %08u\n", info->npr); |
| 67 | info->model_capacity, *(u32 *) info->model_cap_rating); | 97 | if (info->ntr) |
| 68 | if (info->model_perm_cap[0] != '\0') | 98 | seq_printf(m, "Nominal Temp. Rating: %08u\n", info->ntr); |
| 69 | len += sprintf(page + len, | ||
| 70 | "Model Perm. Capacity: %-16.16s %08u\n", | ||
| 71 | info->model_perm_cap, | ||
| 72 | *(u32 *) info->model_perm_cap_rating); | ||
| 73 | if (info->model_temp_cap[0] != '\0') | ||
| 74 | len += sprintf(page + len, | ||
| 75 | "Model Temp. Capacity: %-16.16s %08u\n", | ||
| 76 | info->model_temp_cap, | ||
| 77 | *(u32 *) info->model_temp_cap_rating); | ||
| 78 | if (info->cai) { | 99 | if (info->cai) { |
| 79 | len += sprintf(page + len, | 100 | seq_printf(m, "Capacity Adj. Ind.: %d\n", info->cai); |
| 80 | "Capacity Adj. Ind.: %d\n", | 101 | seq_printf(m, "Capacity Ch. Reason: %d\n", info->ccr); |
| 81 | info->cai); | 102 | seq_printf(m, "Capacity Transient: %d\n", info->t); |
| 82 | len += sprintf(page + len, "Capacity Ch. Reason: %d\n", | 103 | } |
| 83 | info->ccr); | 104 | if (info->p) { |
| 105 | for (i = 1; i <= ARRAY_SIZE(info->typepct); i++) { | ||
| 106 | seq_printf(m, "Type %d Percentage: %d\n", | ||
| 107 | i, info->typepct[i - 1]); | ||
| 108 | } | ||
| 84 | } | 109 | } |
| 85 | return len; | ||
| 86 | } | 110 | } |
| 87 | 111 | ||
| 88 | static int stsi_15_1_x(struct sysinfo_15_1_x *info, char *page, int len) | 112 | static void stsi_15_1_x(struct seq_file *m, struct sysinfo_15_1_x *info) |
| 89 | { | 113 | { |
| 90 | static int max_mnest; | 114 | static int max_mnest; |
| 91 | int i, rc; | 115 | int i, rc; |
| 92 | 116 | ||
| 93 | len += sprintf(page + len, "\n"); | 117 | seq_putc(m, '\n'); |
| 94 | if (!MACHINE_HAS_TOPOLOGY) | 118 | if (!MACHINE_HAS_TOPOLOGY) |
| 95 | return len; | 119 | return; |
| 96 | if (max_mnest) { | 120 | if (stsi(info, 15, 1, topology_max_mnest)) |
| 97 | stsi(info, 15, 1, max_mnest); | 121 | return; |
| 98 | } else { | 122 | seq_printf(m, "CPU Topology HW: "); |
| 99 | for (max_mnest = 6; max_mnest > 1; max_mnest--) { | ||
| 100 | rc = stsi(info, 15, 1, max_mnest); | ||
| 101 | if (rc != -ENOSYS) | ||
| 102 | break; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | len += sprintf(page + len, "CPU Topology HW: "); | ||
| 106 | for (i = 0; i < TOPOLOGY_NR_MAG; i++) | 123 | for (i = 0; i < TOPOLOGY_NR_MAG; i++) |
| 107 | len += sprintf(page + len, " %d", info->mag[i]); | 124 | seq_printf(m, " %d", info->mag[i]); |
| 108 | len += sprintf(page + len, "\n"); | 125 | seq_putc(m, '\n'); |
| 109 | #ifdef CONFIG_SCHED_MC | 126 | #ifdef CONFIG_SCHED_MC |
| 110 | store_topology(info); | 127 | store_topology(info); |
| 111 | len += sprintf(page + len, "CPU Topology SW: "); | 128 | seq_printf(m, "CPU Topology SW: "); |
| 112 | for (i = 0; i < TOPOLOGY_NR_MAG; i++) | 129 | for (i = 0; i < TOPOLOGY_NR_MAG; i++) |
| 113 | len += sprintf(page + len, " %d", info->mag[i]); | 130 | seq_printf(m, " %d", info->mag[i]); |
| 114 | len += sprintf(page + len, "\n"); | 131 | seq_putc(m, '\n'); |
| 115 | #endif | 132 | #endif |
| 116 | return len; | ||
| 117 | } | 133 | } |
| 118 | 134 | ||
| 119 | static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len) | 135 | static void stsi_1_2_2(struct seq_file *m, struct sysinfo_1_2_2 *info) |
| 120 | { | 136 | { |
| 121 | struct sysinfo_1_2_2_extension *ext; | 137 | struct sysinfo_1_2_2_extension *ext; |
| 122 | int i; | 138 | int i; |
| 123 | 139 | ||
| 124 | if (stsi(info, 1, 2, 2) == -ENOSYS) | 140 | if (stsi(info, 1, 2, 2)) |
| 125 | return len; | 141 | return; |
| 126 | ext = (struct sysinfo_1_2_2_extension *) | 142 | ext = (struct sysinfo_1_2_2_extension *) |
| 127 | ((unsigned long) info + info->acc_offset); | 143 | ((unsigned long) info + info->acc_offset); |
| 128 | 144 | seq_printf(m, "CPUs Total: %d\n", info->cpus_total); | |
| 129 | len += sprintf(page + len, "CPUs Total: %d\n", | 145 | seq_printf(m, "CPUs Configured: %d\n", info->cpus_configured); |
| 130 | info->cpus_total); | 146 | seq_printf(m, "CPUs Standby: %d\n", info->cpus_standby); |
| 131 | len += sprintf(page + len, "CPUs Configured: %d\n", | 147 | seq_printf(m, "CPUs Reserved: %d\n", info->cpus_reserved); |
| 132 | info->cpus_configured); | 148 | /* |
| 133 | len += sprintf(page + len, "CPUs Standby: %d\n", | 149 | * Sigh 2. According to the specification the alternate |
| 134 | info->cpus_standby); | 150 | * capability field is a 32 bit floating point number |
| 135 | len += sprintf(page + len, "CPUs Reserved: %d\n", | 151 | * if the higher order 8 bits are not zero. Printing |
| 136 | info->cpus_reserved); | 152 | * a floating point number in the kernel is a no-no, |
| 137 | 153 | * always print the number as 32 bit unsigned integer. | |
| 138 | if (info->format == 1) { | 154 | * The user-space needs to know about the strange |
| 139 | /* | 155 | * encoding of the alternate cpu capability. |
| 140 | * Sigh 2. According to the specification the alternate | 156 | */ |
| 141 | * capability field is a 32 bit floating point number | 157 | seq_printf(m, "Capability: %u", info->capability); |
| 142 | * if the higher order 8 bits are not zero. Printing | 158 | if (info->format == 1) |
| 143 | * a floating point number in the kernel is a no-no, | 159 | seq_printf(m, " %u", ext->alt_capability); |
| 144 | * always print the number as 32 bit unsigned integer. | 160 | seq_putc(m, '\n'); |
| 145 | * The user-space needs to know about the strange | 161 | if (info->nominal_cap) |
| 146 | * encoding of the alternate cpu capability. | 162 | seq_printf(m, "Nominal Capability: %d\n", info->nominal_cap); |
| 147 | */ | 163 | if (info->secondary_cap) |
| 148 | len += sprintf(page + len, "Capability: %u %u\n", | 164 | seq_printf(m, "Secondary Capability: %d\n", info->secondary_cap); |
| 149 | info->capability, ext->alt_capability); | 165 | for (i = 2; i <= info->cpus_total; i++) { |
| 150 | for (i = 2; i <= info->cpus_total; i++) | 166 | seq_printf(m, "Adjustment %02d-way: %u", |
| 151 | len += sprintf(page + len, | 167 | i, info->adjustment[i-2]); |
| 152 | "Adjustment %02d-way: %u %u\n", | 168 | if (info->format == 1) |
| 153 | i, info->adjustment[i-2], | 169 | seq_printf(m, " %u", ext->alt_adjustment[i-2]); |
| 154 | ext->alt_adjustment[i-2]); | 170 | seq_putc(m, '\n'); |
| 155 | |||
| 156 | } else { | ||
| 157 | len += sprintf(page + len, "Capability: %u\n", | ||
| 158 | info->capability); | ||
| 159 | for (i = 2; i <= info->cpus_total; i++) | ||
| 160 | len += sprintf(page + len, | ||
| 161 | "Adjustment %02d-way: %u\n", | ||
| 162 | i, info->adjustment[i-2]); | ||
| 163 | } | 171 | } |
| 164 | |||
| 165 | if (info->secondary_capability != 0) | ||
| 166 | len += sprintf(page + len, "Secondary Capability: %d\n", | ||
| 167 | info->secondary_capability); | ||
| 168 | return len; | ||
| 169 | } | 172 | } |
| 170 | 173 | ||
| 171 | static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len) | 174 | static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info) |
| 172 | { | 175 | { |
| 173 | if (stsi(info, 2, 2, 2) == -ENOSYS) | 176 | if (stsi(info, 2, 2, 2)) |
| 174 | return len; | 177 | return; |
| 175 | |||
| 176 | EBCASC(info->name, sizeof(info->name)); | 178 | EBCASC(info->name, sizeof(info->name)); |
| 177 | 179 | seq_putc(m, '\n'); | |
| 178 | len += sprintf(page + len, "\n"); | 180 | seq_printf(m, "LPAR Number: %d\n", info->lpar_number); |
| 179 | len += sprintf(page + len, "LPAR Number: %d\n", | 181 | seq_printf(m, "LPAR Characteristics: "); |
| 180 | info->lpar_number); | ||
| 181 | |||
| 182 | len += sprintf(page + len, "LPAR Characteristics: "); | ||
| 183 | if (info->characteristics & LPAR_CHAR_DEDICATED) | 182 | if (info->characteristics & LPAR_CHAR_DEDICATED) |
| 184 | len += sprintf(page + len, "Dedicated "); | 183 | seq_printf(m, "Dedicated "); |
| 185 | if (info->characteristics & LPAR_CHAR_SHARED) | 184 | if (info->characteristics & LPAR_CHAR_SHARED) |
| 186 | len += sprintf(page + len, "Shared "); | 185 | seq_printf(m, "Shared "); |
| 187 | if (info->characteristics & LPAR_CHAR_LIMITED) | 186 | if (info->characteristics & LPAR_CHAR_LIMITED) |
| 188 | len += sprintf(page + len, "Limited "); | 187 | seq_printf(m, "Limited "); |
| 189 | len += sprintf(page + len, "\n"); | 188 | seq_putc(m, '\n'); |
| 190 | 189 | seq_printf(m, "LPAR Name: %-8.8s\n", info->name); | |
| 191 | len += sprintf(page + len, "LPAR Name: %-8.8s\n", | 190 | seq_printf(m, "LPAR Adjustment: %d\n", info->caf); |
| 192 | info->name); | 191 | seq_printf(m, "LPAR CPUs Total: %d\n", info->cpus_total); |
| 193 | 192 | seq_printf(m, "LPAR CPUs Configured: %d\n", info->cpus_configured); | |
| 194 | len += sprintf(page + len, "LPAR Adjustment: %d\n", | 193 | seq_printf(m, "LPAR CPUs Standby: %d\n", info->cpus_standby); |
| 195 | info->caf); | 194 | seq_printf(m, "LPAR CPUs Reserved: %d\n", info->cpus_reserved); |
| 196 | 195 | seq_printf(m, "LPAR CPUs Dedicated: %d\n", info->cpus_dedicated); | |
| 197 | len += sprintf(page + len, "LPAR CPUs Total: %d\n", | 196 | seq_printf(m, "LPAR CPUs Shared: %d\n", info->cpus_shared); |
| 198 | info->cpus_total); | ||
| 199 | len += sprintf(page + len, "LPAR CPUs Configured: %d\n", | ||
| 200 | info->cpus_configured); | ||
| 201 | len += sprintf(page + len, "LPAR CPUs Standby: %d\n", | ||
| 202 | info->cpus_standby); | ||
| 203 | len += sprintf(page + len, "LPAR CPUs Reserved: %d\n", | ||
| 204 | info->cpus_reserved); | ||
| 205 | len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n", | ||
| 206 | info->cpus_dedicated); | ||
| 207 | len += sprintf(page + len, "LPAR CPUs Shared: %d\n", | ||
| 208 | info->cpus_shared); | ||
| 209 | return len; | ||
| 210 | } | 197 | } |
| 211 | 198 | ||
| 212 | static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len) | 199 | static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info) |
| 213 | { | 200 | { |
| 214 | int i; | 201 | int i; |
| 215 | 202 | ||
| 216 | if (stsi(info, 3, 2, 2) == -ENOSYS) | 203 | if (stsi(info, 3, 2, 2)) |
| 217 | return len; | 204 | return; |
| 218 | for (i = 0; i < info->count; i++) { | 205 | for (i = 0; i < info->count; i++) { |
| 219 | EBCASC(info->vm[i].name, sizeof(info->vm[i].name)); | 206 | EBCASC(info->vm[i].name, sizeof(info->vm[i].name)); |
| 220 | EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi)); | 207 | EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi)); |
| 221 | len += sprintf(page + len, "\n"); | 208 | seq_putc(m, '\n'); |
| 222 | len += sprintf(page + len, "VM%02d Name: %-8.8s\n", | 209 | seq_printf(m, "VM%02d Name: %-8.8s\n", i, info->vm[i].name); |
| 223 | i, info->vm[i].name); | 210 | seq_printf(m, "VM%02d Control Program: %-16.16s\n", i, info->vm[i].cpi); |
| 224 | len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n", | 211 | seq_printf(m, "VM%02d Adjustment: %d\n", i, info->vm[i].caf); |
| 225 | i, info->vm[i].cpi); | 212 | seq_printf(m, "VM%02d CPUs Total: %d\n", i, info->vm[i].cpus_total); |
| 226 | 213 | seq_printf(m, "VM%02d CPUs Configured: %d\n", i, info->vm[i].cpus_configured); | |
| 227 | len += sprintf(page + len, "VM%02d Adjustment: %d\n", | 214 | seq_printf(m, "VM%02d CPUs Standby: %d\n", i, info->vm[i].cpus_standby); |
| 228 | i, info->vm[i].caf); | 215 | seq_printf(m, "VM%02d CPUs Reserved: %d\n", i, info->vm[i].cpus_reserved); |
| 229 | |||
| 230 | len += sprintf(page + len, "VM%02d CPUs Total: %d\n", | ||
| 231 | i, info->vm[i].cpus_total); | ||
| 232 | len += sprintf(page + len, "VM%02d CPUs Configured: %d\n", | ||
| 233 | i, info->vm[i].cpus_configured); | ||
| 234 | len += sprintf(page + len, "VM%02d CPUs Standby: %d\n", | ||
| 235 | i, info->vm[i].cpus_standby); | ||
| 236 | len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n", | ||
| 237 | i, info->vm[i].cpus_reserved); | ||
| 238 | } | 216 | } |
| 239 | return len; | ||
| 240 | } | 217 | } |
| 241 | 218 | ||
| 242 | static int proc_read_sysinfo(char *page, char **start, | 219 | static int sysinfo_show(struct seq_file *m, void *v) |
| 243 | off_t off, int count, | ||
| 244 | int *eof, void *data) | ||
| 245 | { | 220 | { |
| 246 | unsigned long info = get_zeroed_page(GFP_KERNEL); | 221 | void *info = (void *)get_zeroed_page(GFP_KERNEL); |
| 247 | int level, len; | 222 | int level; |
| 248 | 223 | ||
| 249 | if (!info) | 224 | if (!info) |
| 250 | return 0; | 225 | return 0; |
| 251 | 226 | level = stsi(NULL, 0, 0, 0); | |
| 252 | len = 0; | ||
| 253 | level = stsi_0(); | ||
| 254 | if (level >= 1) | 227 | if (level >= 1) |
| 255 | len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len); | 228 | stsi_1_1_1(m, info); |
| 256 | |||
| 257 | if (level >= 1) | 229 | if (level >= 1) |
| 258 | len = stsi_15_1_x((struct sysinfo_15_1_x *) info, page, len); | 230 | stsi_15_1_x(m, info); |
| 259 | |||
| 260 | if (level >= 1) | 231 | if (level >= 1) |
| 261 | len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len); | 232 | stsi_1_2_2(m, info); |
| 262 | |||
| 263 | if (level >= 2) | 233 | if (level >= 2) |
| 264 | len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len); | 234 | stsi_2_2_2(m, info); |
| 265 | |||
| 266 | if (level >= 3) | 235 | if (level >= 3) |
| 267 | len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len); | 236 | stsi_3_2_2(m, info); |
| 237 | free_page((unsigned long)info); | ||
| 238 | return 0; | ||
| 239 | } | ||
| 268 | 240 | ||
| 269 | free_page(info); | 241 | static int sysinfo_open(struct inode *inode, struct file *file) |
| 270 | return len; | 242 | { |
| 243 | return single_open(file, sysinfo_show, NULL); | ||
| 271 | } | 244 | } |
| 272 | 245 | ||
| 273 | static __init int create_proc_sysinfo(void) | 246 | static const struct file_operations sysinfo_fops = { |
| 247 | .open = sysinfo_open, | ||
| 248 | .read = seq_read, | ||
| 249 | .llseek = seq_lseek, | ||
| 250 | .release = single_release, | ||
| 251 | }; | ||
| 252 | |||
| 253 | static int __init sysinfo_create_proc(void) | ||
| 274 | { | 254 | { |
| 275 | create_proc_read_entry("sysinfo", 0444, NULL, | 255 | proc_create("sysinfo", 0444, NULL, &sysinfo_fops); |
| 276 | proc_read_sysinfo, NULL); | ||
| 277 | return 0; | 256 | return 0; |
| 278 | } | 257 | } |
| 279 | device_initcall(create_proc_sysinfo); | 258 | device_initcall(sysinfo_create_proc); |
| 280 | 259 | ||
| 281 | /* | 260 | /* |
| 282 | * Service levels interface. | 261 | * Service levels interface. |
| @@ -407,7 +386,7 @@ void s390_adjust_jiffies(void) | |||
| 407 | if (!info) | 386 | if (!info) |
| 408 | return; | 387 | return; |
| 409 | 388 | ||
| 410 | if (stsi(info, 1, 2, 2) != -ENOSYS) { | 389 | if (stsi(info, 1, 2, 2) == 0) { |
| 411 | /* | 390 | /* |
| 412 | * Major sigh. The cpu capability encoding is "special". | 391 | * Major sigh. The cpu capability encoding is "special". |
| 413 | * If the first 9 bits of info->capability are 0 then it | 392 | * If the first 9 bits of info->capability are 0 then it |
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index dcec960fc724..2db1011b8b19 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
| @@ -329,7 +329,7 @@ static unsigned long clock_sync_flags; | |||
| 329 | * The synchronous get_clock function. It will write the current clock | 329 | * The synchronous get_clock function. It will write the current clock |
| 330 | * value to the clock pointer and return 0 if the clock is in sync with | 330 | * value to the clock pointer and return 0 if the clock is in sync with |
| 331 | * the external time source. If the clock mode is local it will return | 331 | * the external time source. If the clock mode is local it will return |
| 332 | * -ENOSYS and -EAGAIN if the clock is not in sync with the external | 332 | * -EOPNOTSUPP and -EAGAIN if the clock is not in sync with the external |
| 333 | * reference. | 333 | * reference. |
| 334 | */ | 334 | */ |
| 335 | int get_sync_clock(unsigned long long *clock) | 335 | int get_sync_clock(unsigned long long *clock) |
| @@ -347,7 +347,7 @@ int get_sync_clock(unsigned long long *clock) | |||
| 347 | return 0; | 347 | return 0; |
| 348 | if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags) && | 348 | if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags) && |
| 349 | !test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) | 349 | !test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) |
| 350 | return -ENOSYS; | 350 | return -EOPNOTSUPP; |
| 351 | if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags) && | 351 | if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags) && |
| 352 | !test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) | 352 | !test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) |
| 353 | return -EACCES; | 353 | return -EACCES; |
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 05151e06c388..54d93f4b6818 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/cpu.h> | 17 | #include <linux/cpu.h> |
| 18 | #include <linux/smp.h> | 18 | #include <linux/smp.h> |
| 19 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
| 20 | #include <asm/sysinfo.h> | ||
| 20 | 21 | ||
| 21 | #define PTF_HORIZONTAL (0UL) | 22 | #define PTF_HORIZONTAL (0UL) |
| 22 | #define PTF_VERTICAL (1UL) | 23 | #define PTF_VERTICAL (1UL) |
| @@ -44,9 +45,6 @@ static struct mask_info book_info; | |||
| 44 | cpumask_t cpu_book_map[NR_CPUS]; | 45 | cpumask_t cpu_book_map[NR_CPUS]; |
| 45 | unsigned char cpu_book_id[NR_CPUS]; | 46 | unsigned char cpu_book_id[NR_CPUS]; |
| 46 | 47 | ||
| 47 | /* smp_cpu_state_mutex must be held when accessing this array */ | ||
| 48 | int cpu_polarization[NR_CPUS]; | ||
| 49 | |||
| 50 | static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) | 48 | static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) |
| 51 | { | 49 | { |
| 52 | cpumask_t mask; | 50 | cpumask_t mask; |
| @@ -75,10 +73,7 @@ static struct mask_info *add_cpus_to_mask(struct topology_cpu *tl_cpu, | |||
| 75 | { | 73 | { |
| 76 | unsigned int cpu; | 74 | unsigned int cpu; |
| 77 | 75 | ||
| 78 | for (cpu = find_first_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS); | 76 | for_each_set_bit(cpu, &tl_cpu->mask[0], TOPOLOGY_CPU_BITS) { |
| 79 | cpu < TOPOLOGY_CPU_BITS; | ||
| 80 | cpu = find_next_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS, cpu + 1)) | ||
| 81 | { | ||
| 82 | unsigned int rcpu; | 77 | unsigned int rcpu; |
| 83 | int lcpu; | 78 | int lcpu; |
| 84 | 79 | ||
| @@ -94,7 +89,7 @@ static struct mask_info *add_cpus_to_mask(struct topology_cpu *tl_cpu, | |||
| 94 | } else { | 89 | } else { |
| 95 | cpu_core_id[lcpu] = core->id; | 90 | cpu_core_id[lcpu] = core->id; |
| 96 | } | 91 | } |
| 97 | cpu_set_polarization(lcpu, tl_cpu->pp); | 92 | smp_cpu_set_polarization(lcpu, tl_cpu->pp); |
| 98 | } | 93 | } |
| 99 | } | 94 | } |
| 100 | return core; | 95 | return core; |
| @@ -201,7 +196,7 @@ static void topology_update_polarization_simple(void) | |||
| 201 | 196 | ||
| 202 | mutex_lock(&smp_cpu_state_mutex); | 197 | mutex_lock(&smp_cpu_state_mutex); |
| 203 | for_each_possible_cpu(cpu) | 198 | for_each_possible_cpu(cpu) |
| 204 | cpu_set_polarization(cpu, POLARIZATION_HRZ); | 199 | smp_cpu_set_polarization(cpu, POLARIZATION_HRZ); |
| 205 | mutex_unlock(&smp_cpu_state_mutex); | 200 | mutex_unlock(&smp_cpu_state_mutex); |
| 206 | } | 201 | } |
| 207 | 202 | ||
| @@ -231,7 +226,7 @@ int topology_set_cpu_management(int fc) | |||
| 231 | if (rc) | 226 | if (rc) |
| 232 | return -EBUSY; | 227 | return -EBUSY; |
| 233 | for_each_possible_cpu(cpu) | 228 | for_each_possible_cpu(cpu) |
| 234 | cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); | 229 | smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); |
| 235 | return rc; | 230 | return rc; |
| 236 | } | 231 | } |
| 237 | 232 | ||
| @@ -250,12 +245,10 @@ static void update_cpu_core_map(void) | |||
| 250 | 245 | ||
| 251 | void store_topology(struct sysinfo_15_1_x *info) | 246 | void store_topology(struct sysinfo_15_1_x *info) |
| 252 | { | 247 | { |
| 253 | int rc; | 248 | if (topology_max_mnest >= 3) |
| 254 | 249 | stsi(info, 15, 1, 3); | |
| 255 | rc = stsi(info, 15, 1, 3); | 250 | else |
| 256 | if (rc != -ENOSYS) | 251 | stsi(info, 15, 1, 2); |
| 257 | return; | ||
| 258 | stsi(info, 15, 1, 2); | ||
| 259 | } | 252 | } |
| 260 | 253 | ||
| 261 | int arch_update_cpu_topology(void) | 254 | int arch_update_cpu_topology(void) |
| @@ -415,7 +408,7 @@ static ssize_t cpu_polarization_show(struct device *dev, | |||
| 415 | ssize_t count; | 408 | ssize_t count; |
| 416 | 409 | ||
| 417 | mutex_lock(&smp_cpu_state_mutex); | 410 | mutex_lock(&smp_cpu_state_mutex); |
| 418 | switch (cpu_read_polarization(cpu)) { | 411 | switch (smp_cpu_get_polarization(cpu)) { |
| 419 | case POLARIZATION_HRZ: | 412 | case POLARIZATION_HRZ: |
| 420 | count = sprintf(buf, "horizontal\n"); | 413 | count = sprintf(buf, "horizontal\n"); |
| 421 | break; | 414 | break; |
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 01775c04a90e..3d2b0fa37db0 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
| @@ -57,6 +57,23 @@ static int kstack_depth_to_print = 12; | |||
| 57 | static int kstack_depth_to_print = 20; | 57 | static int kstack_depth_to_print = 20; |
| 58 | #endif /* CONFIG_64BIT */ | 58 | #endif /* CONFIG_64BIT */ |
| 59 | 59 | ||
| 60 | static inline void __user *get_trap_ip(struct pt_regs *regs) | ||
| 61 | { | ||
| 62 | #ifdef CONFIG_64BIT | ||
| 63 | unsigned long address; | ||
| 64 | |||
| 65 | if (regs->int_code & 0x200) | ||
| 66 | address = *(unsigned long *)(current->thread.trap_tdb + 24); | ||
| 67 | else | ||
| 68 | address = regs->psw.addr; | ||
| 69 | return (void __user *) | ||
| 70 | ((address - (regs->int_code >> 16)) & PSW_ADDR_INSN); | ||
| 71 | #else | ||
| 72 | return (void __user *) | ||
| 73 | ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN); | ||
| 74 | #endif | ||
| 75 | } | ||
| 76 | |||
| 60 | /* | 77 | /* |
| 61 | * For show_trace we have tree different stack to consider: | 78 | * For show_trace we have tree different stack to consider: |
| 62 | * - the panic stack which is used if the kernel stack has overflown | 79 | * - the panic stack which is used if the kernel stack has overflown |
| @@ -214,7 +231,6 @@ void show_registers(struct pt_regs *regs) | |||
| 214 | 231 | ||
| 215 | void show_regs(struct pt_regs *regs) | 232 | void show_regs(struct pt_regs *regs) |
| 216 | { | 233 | { |
| 217 | print_modules(); | ||
| 218 | printk("CPU: %d %s %s %.*s\n", | 234 | printk("CPU: %d %s %s %.*s\n", |
| 219 | task_thread_info(current)->cpu, print_tainted(), | 235 | task_thread_info(current)->cpu, print_tainted(), |
| 220 | init_utsname()->release, | 236 | init_utsname()->release, |
| @@ -254,6 +270,7 @@ void die(struct pt_regs *regs, const char *str) | |||
| 254 | #endif | 270 | #endif |
| 255 | printk("\n"); | 271 | printk("\n"); |
| 256 | notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV); | 272 | notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV); |
| 273 | print_modules(); | ||
| 257 | show_regs(regs); | 274 | show_regs(regs); |
| 258 | bust_spinlocks(0); | 275 | bust_spinlocks(0); |
| 259 | add_taint(TAINT_DIE); | 276 | add_taint(TAINT_DIE); |
| @@ -285,12 +302,6 @@ int is_valid_bugaddr(unsigned long addr) | |||
| 285 | return 1; | 302 | return 1; |
| 286 | } | 303 | } |
| 287 | 304 | ||
| 288 | static inline void __user *get_psw_address(struct pt_regs *regs) | ||
| 289 | { | ||
| 290 | return (void __user *) | ||
| 291 | ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN); | ||
| 292 | } | ||
| 293 | |||
| 294 | static void __kprobes do_trap(struct pt_regs *regs, | 305 | static void __kprobes do_trap(struct pt_regs *regs, |
| 295 | int si_signo, int si_code, char *str) | 306 | int si_signo, int si_code, char *str) |
| 296 | { | 307 | { |
| @@ -304,14 +315,14 @@ static void __kprobes do_trap(struct pt_regs *regs, | |||
| 304 | info.si_signo = si_signo; | 315 | info.si_signo = si_signo; |
| 305 | info.si_errno = 0; | 316 | info.si_errno = 0; |
| 306 | info.si_code = si_code; | 317 | info.si_code = si_code; |
| 307 | info.si_addr = get_psw_address(regs); | 318 | info.si_addr = get_trap_ip(regs); |
| 308 | force_sig_info(si_signo, &info, current); | 319 | force_sig_info(si_signo, &info, current); |
| 309 | report_user_fault(regs, si_signo); | 320 | report_user_fault(regs, si_signo); |
| 310 | } else { | 321 | } else { |
| 311 | const struct exception_table_entry *fixup; | 322 | const struct exception_table_entry *fixup; |
| 312 | fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); | 323 | fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); |
| 313 | if (fixup) | 324 | if (fixup) |
| 314 | regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE; | 325 | regs->psw.addr = extable_fixup(fixup) | PSW_ADDR_AMODE; |
| 315 | else { | 326 | else { |
| 316 | enum bug_trap_type btt; | 327 | enum bug_trap_type btt; |
| 317 | 328 | ||
| @@ -381,6 +392,11 @@ DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, | |||
| 381 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, | 392 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, |
| 382 | "translation exception") | 393 | "translation exception") |
| 383 | 394 | ||
| 395 | #ifdef CONFIG_64BIT | ||
| 396 | DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN, | ||
| 397 | "transaction constraint exception") | ||
| 398 | #endif | ||
| 399 | |||
| 384 | static inline void do_fp_trap(struct pt_regs *regs, int fpc) | 400 | static inline void do_fp_trap(struct pt_regs *regs, int fpc) |
| 385 | { | 401 | { |
| 386 | int si_code = 0; | 402 | int si_code = 0; |
| @@ -408,7 +424,7 @@ static void __kprobes illegal_op(struct pt_regs *regs) | |||
| 408 | __u16 __user *location; | 424 | __u16 __user *location; |
| 409 | int signal = 0; | 425 | int signal = 0; |
| 410 | 426 | ||
| 411 | location = get_psw_address(regs); | 427 | location = get_trap_ip(regs); |
| 412 | 428 | ||
| 413 | if (user_mode(regs)) { | 429 | if (user_mode(regs)) { |
| 414 | if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) | 430 | if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) |
| @@ -476,7 +492,7 @@ void specification_exception(struct pt_regs *regs) | |||
| 476 | __u16 __user *location = NULL; | 492 | __u16 __user *location = NULL; |
| 477 | int signal = 0; | 493 | int signal = 0; |
| 478 | 494 | ||
| 479 | location = (__u16 __user *) get_psw_address(regs); | 495 | location = (__u16 __user *) get_trap_ip(regs); |
| 480 | 496 | ||
| 481 | if (user_mode(regs)) { | 497 | if (user_mode(regs)) { |
| 482 | get_user(*((__u16 *) opcode), location); | 498 | get_user(*((__u16 *) opcode), location); |
| @@ -525,7 +541,7 @@ static void data_exception(struct pt_regs *regs) | |||
| 525 | __u16 __user *location; | 541 | __u16 __user *location; |
| 526 | int signal = 0; | 542 | int signal = 0; |
| 527 | 543 | ||
| 528 | location = get_psw_address(regs); | 544 | location = get_trap_ip(regs); |
| 529 | 545 | ||
| 530 | if (MACHINE_HAS_IEEE) | 546 | if (MACHINE_HAS_IEEE) |
| 531 | asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); | 547 | asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); |
| @@ -641,6 +657,7 @@ void __init trap_init(void) | |||
| 641 | pgm_check_table[0x12] = &translation_exception; | 657 | pgm_check_table[0x12] = &translation_exception; |
| 642 | pgm_check_table[0x13] = &special_op_exception; | 658 | pgm_check_table[0x13] = &special_op_exception; |
| 643 | #ifdef CONFIG_64BIT | 659 | #ifdef CONFIG_64BIT |
| 660 | pgm_check_table[0x18] = &transaction_exception; | ||
| 644 | pgm_check_table[0x38] = &do_asce_exception; | 661 | pgm_check_table[0x38] = &do_asce_exception; |
| 645 | pgm_check_table[0x39] = &do_dat_exception; | 662 | pgm_check_table[0x39] = &do_dat_exception; |
| 646 | pgm_check_table[0x3A] = &do_dat_exception; | 663 | pgm_check_table[0x3A] = &do_dat_exception; |
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index 9a19ca367c17..d7776281cb60 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c | |||
| @@ -85,7 +85,7 @@ struct vdso_data *vdso_data = &vdso_data_store.data; | |||
| 85 | static void vdso_init_data(struct vdso_data *vd) | 85 | static void vdso_init_data(struct vdso_data *vd) |
| 86 | { | 86 | { |
| 87 | vd->ectg_available = | 87 | vd->ectg_available = |
| 88 | addressing_mode != HOME_SPACE_MODE && test_facility(31); | 88 | s390_user_mode != HOME_SPACE_MODE && test_facility(31); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | #ifdef CONFIG_64BIT | 91 | #ifdef CONFIG_64BIT |
| @@ -102,7 +102,7 @@ int vdso_alloc_per_cpu(struct _lowcore *lowcore) | |||
| 102 | 102 | ||
| 103 | lowcore->vdso_per_cpu_data = __LC_PASTE; | 103 | lowcore->vdso_per_cpu_data = __LC_PASTE; |
| 104 | 104 | ||
| 105 | if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled) | 105 | if (s390_user_mode == HOME_SPACE_MODE || !vdso_enabled) |
| 106 | return 0; | 106 | return 0; |
| 107 | 107 | ||
| 108 | segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER); | 108 | segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER); |
| @@ -147,7 +147,7 @@ void vdso_free_per_cpu(struct _lowcore *lowcore) | |||
| 147 | unsigned long segment_table, page_table, page_frame; | 147 | unsigned long segment_table, page_table, page_frame; |
| 148 | u32 *psal, *aste; | 148 | u32 *psal, *aste; |
| 149 | 149 | ||
| 150 | if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled) | 150 | if (s390_user_mode == HOME_SPACE_MODE || !vdso_enabled) |
| 151 | return; | 151 | return; |
| 152 | 152 | ||
| 153 | psal = (u32 *)(addr_t) lowcore->paste[4]; | 153 | psal = (u32 *)(addr_t) lowcore->paste[4]; |
| @@ -165,7 +165,7 @@ static void vdso_init_cr5(void) | |||
| 165 | { | 165 | { |
| 166 | unsigned long cr5; | 166 | unsigned long cr5; |
| 167 | 167 | ||
| 168 | if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled) | 168 | if (s390_user_mode == HOME_SPACE_MODE || !vdso_enabled) |
| 169 | return; | 169 | return; |
| 170 | cr5 = offsetof(struct _lowcore, paste); | 170 | cr5 = offsetof(struct _lowcore, paste); |
| 171 | __ctl_load(cr5, 5, 5); | 171 | __ctl_load(cr5, 5, 5); |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index cb5093c26d16..790334427895 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
| @@ -378,9 +378,8 @@ static int __cpuinit s390_nohz_notify(struct notifier_block *self, | |||
| 378 | long cpu = (long) hcpu; | 378 | long cpu = (long) hcpu; |
| 379 | 379 | ||
| 380 | idle = &per_cpu(s390_idle, cpu); | 380 | idle = &per_cpu(s390_idle, cpu); |
| 381 | switch (action) { | 381 | switch (action & ~CPU_TASKS_FROZEN) { |
| 382 | case CPU_DYING: | 382 | case CPU_DYING: |
| 383 | case CPU_DYING_FROZEN: | ||
| 384 | idle->nohz_delay = 0; | 383 | idle->nohz_delay = 0; |
| 385 | default: | 384 | default: |
| 386 | break; | 385 | break; |
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 78eb9847008f..9b04a32e5695 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig | |||
| @@ -5,7 +5,7 @@ source "virt/kvm/Kconfig" | |||
| 5 | 5 | ||
| 6 | menuconfig VIRTUALIZATION | 6 | menuconfig VIRTUALIZATION |
| 7 | def_bool y | 7 | def_bool y |
| 8 | prompt "Virtualization" | 8 | prompt "KVM" |
| 9 | ---help--- | 9 | ---help--- |
| 10 | Say Y here to get to see options for using your Linux host to run other | 10 | Say Y here to get to see options for using your Linux host to run other |
| 11 | operating systems inside virtual machines (guests). | 11 | operating systems inside virtual machines (guests). |
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 60da903d6f3e..310be61bead7 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
| @@ -211,7 +211,7 @@ static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem) | |||
| 211 | spin_unlock(&fi->lock); | 211 | spin_unlock(&fi->lock); |
| 212 | 212 | ||
| 213 | /* deal with other level 3 hypervisors */ | 213 | /* deal with other level 3 hypervisors */ |
| 214 | if (stsi(mem, 3, 2, 2) == -ENOSYS) | 214 | if (stsi(mem, 3, 2, 2)) |
| 215 | mem->count = 0; | 215 | mem->count = 0; |
| 216 | if (mem->count < 8) | 216 | if (mem->count < 8) |
| 217 | mem->count++; | 217 | mem->count++; |
| @@ -259,7 +259,7 @@ static int handle_stsi(struct kvm_vcpu *vcpu) | |||
| 259 | mem = get_zeroed_page(GFP_KERNEL); | 259 | mem = get_zeroed_page(GFP_KERNEL); |
| 260 | if (!mem) | 260 | if (!mem) |
| 261 | goto out_fail; | 261 | goto out_fail; |
| 262 | if (stsi((void *) mem, fc, sel1, sel2) == -ENOSYS) | 262 | if (stsi((void *) mem, fc, sel1, sel2)) |
| 263 | goto out_mem; | 263 | goto out_mem; |
| 264 | break; | 264 | break; |
| 265 | case 3: | 265 | case 3: |
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index 761ab8b56afc..6ab0d0b5cec8 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | lib-y += delay.o string.o uaccess_std.o uaccess_pt.o | 5 | lib-y += delay.o string.o uaccess_std.o uaccess_pt.o |
| 6 | obj-y += usercopy.o | 6 | obj-y += usercopy.o |
| 7 | obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o | 7 | obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o |
| 8 | obj-$(CONFIG_64BIT) += mem64.o | ||
| 8 | lib-$(CONFIG_64BIT) += uaccess_mvcos.o | 9 | lib-$(CONFIG_64BIT) += uaccess_mvcos.o |
| 9 | lib-$(CONFIG_SMP) += spinlock.o | 10 | lib-$(CONFIG_SMP) += spinlock.o |
diff --git a/arch/s390/lib/mem32.S b/arch/s390/lib/mem32.S new file mode 100644 index 000000000000..14ca9244b615 --- /dev/null +++ b/arch/s390/lib/mem32.S | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | /* | ||
| 2 | * String handling functions. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/linkage.h> | ||
| 8 | |||
| 9 | /* | ||
| 10 | * memset implementation | ||
| 11 | * | ||
| 12 | * This code corresponds to the C construct below. We do distinguish | ||
| 13 | * between clearing (c == 0) and setting a memory array (c != 0) simply | ||
| 14 | * because nearly all memset invocations in the kernel clear memory and | ||
| 15 | * the xc instruction is preferred in such cases. | ||
| 16 | * | ||
| 17 | * void *memset(void *s, int c, size_t n) | ||
| 18 | * { | ||
| 19 | * if (likely(c == 0)) | ||
| 20 | * return __builtin_memset(s, 0, n); | ||
| 21 | * return __builtin_memset(s, c, n); | ||
| 22 | * } | ||
| 23 | */ | ||
| 24 | ENTRY(memset) | ||
| 25 | basr %r5,%r0 | ||
| 26 | .Lmemset_base: | ||
| 27 | ltr %r4,%r4 | ||
| 28 | bzr %r14 | ||
| 29 | ltr %r3,%r3 | ||
| 30 | jnz .Lmemset_fill | ||
| 31 | ahi %r4,-1 | ||
| 32 | lr %r3,%r4 | ||
| 33 | srl %r3,8 | ||
| 34 | ltr %r3,%r3 | ||
| 35 | lr %r1,%r2 | ||
| 36 | je .Lmemset_clear_rest | ||
| 37 | .Lmemset_clear_loop: | ||
| 38 | xc 0(256,%r1),0(%r1) | ||
| 39 | la %r1,256(%r1) | ||
| 40 | brct %r3,.Lmemset_clear_loop | ||
| 41 | .Lmemset_clear_rest: | ||
| 42 | ex %r4,.Lmemset_xc-.Lmemset_base(%r5) | ||
| 43 | br %r14 | ||
| 44 | .Lmemset_fill: | ||
| 45 | stc %r3,0(%r2) | ||
| 46 | chi %r4,1 | ||
| 47 | lr %r1,%r2 | ||
| 48 | ber %r14 | ||
| 49 | ahi %r4,-2 | ||
| 50 | lr %r3,%r4 | ||
| 51 | srl %r3,8 | ||
| 52 | ltr %r3,%r3 | ||
| 53 | je .Lmemset_fill_rest | ||
| 54 | .Lmemset_fill_loop: | ||
| 55 | mvc 1(256,%r1),0(%r1) | ||
| 56 | la %r1,256(%r1) | ||
| 57 | brct %r3,.Lmemset_fill_loop | ||
| 58 | .Lmemset_fill_rest: | ||
| 59 | ex %r4,.Lmemset_mvc-.Lmemset_base(%r5) | ||
| 60 | br %r14 | ||
| 61 | .Lmemset_xc: | ||
| 62 | xc 0(1,%r1),0(%r1) | ||
| 63 | .Lmemset_mvc: | ||
| 64 | mvc 1(1,%r1),0(%r1) | ||
| 65 | |||
| 66 | /* | ||
| 67 | * memcpy implementation | ||
| 68 | * | ||
| 69 | * void *memcpy(void *dest, const void *src, size_t n) | ||
| 70 | */ | ||
| 71 | ENTRY(memcpy) | ||
| 72 | basr %r5,%r0 | ||
| 73 | .Lmemcpy_base: | ||
| 74 | ltr %r4,%r4 | ||
| 75 | bzr %r14 | ||
| 76 | ahi %r4,-1 | ||
| 77 | lr %r0,%r4 | ||
| 78 | srl %r0,8 | ||
| 79 | ltr %r0,%r0 | ||
| 80 | lr %r1,%r2 | ||
| 81 | jnz .Lmemcpy_loop | ||
| 82 | .Lmemcpy_rest: | ||
| 83 | ex %r4,.Lmemcpy_mvc-.Lmemcpy_base(%r5) | ||
| 84 | br %r14 | ||
| 85 | .Lmemcpy_loop: | ||
| 86 | mvc 0(256,%r1),0(%r3) | ||
| 87 | la %r1,256(%r1) | ||
| 88 | la %r3,256(%r3) | ||
| 89 | brct %r0,.Lmemcpy_loop | ||
| 90 | j .Lmemcpy_rest | ||
| 91 | .Lmemcpy_mvc: | ||
| 92 | mvc 0(1,%r1),0(%r3) | ||
diff --git a/arch/s390/lib/mem64.S b/arch/s390/lib/mem64.S new file mode 100644 index 000000000000..c6d553e85ab1 --- /dev/null +++ b/arch/s390/lib/mem64.S | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | /* | ||
| 2 | * String handling functions. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/linkage.h> | ||
| 8 | |||
| 9 | /* | ||
| 10 | * memset implementation | ||
| 11 | * | ||
| 12 | * This code corresponds to the C construct below. We do distinguish | ||
| 13 | * between clearing (c == 0) and setting a memory array (c != 0) simply | ||
| 14 | * because nearly all memset invocations in the kernel clear memory and | ||
| 15 | * the xc instruction is preferred in such cases. | ||
| 16 | * | ||
| 17 | * void *memset(void *s, int c, size_t n) | ||
| 18 | * { | ||
| 19 | * if (likely(c == 0)) | ||
| 20 | * return __builtin_memset(s, 0, n); | ||
| 21 | * return __builtin_memset(s, c, n); | ||
| 22 | * } | ||
| 23 | */ | ||
| 24 | ENTRY(memset) | ||
| 25 | ltgr %r4,%r4 | ||
| 26 | bzr %r14 | ||
| 27 | ltgr %r3,%r3 | ||
| 28 | jnz .Lmemset_fill | ||
| 29 | aghi %r4,-1 | ||
| 30 | srlg %r3,%r4,8 | ||
| 31 | ltgr %r3,%r3 | ||
| 32 | lgr %r1,%r2 | ||
| 33 | jz .Lmemset_clear_rest | ||
| 34 | .Lmemset_clear_loop: | ||
| 35 | xc 0(256,%r1),0(%r1) | ||
| 36 | la %r1,256(%r1) | ||
| 37 | brctg %r3,.Lmemset_clear_loop | ||
| 38 | .Lmemset_clear_rest: | ||
| 39 | larl %r3,.Lmemset_xc | ||
| 40 | ex %r4,0(%r3) | ||
| 41 | br %r14 | ||
| 42 | .Lmemset_fill: | ||
| 43 | stc %r3,0(%r2) | ||
| 44 | cghi %r4,1 | ||
| 45 | lgr %r1,%r2 | ||
| 46 | ber %r14 | ||
| 47 | aghi %r4,-2 | ||
| 48 | srlg %r3,%r4,8 | ||
| 49 | ltgr %r3,%r3 | ||
| 50 | jz .Lmemset_fill_rest | ||
| 51 | .Lmemset_fill_loop: | ||
| 52 | mvc 1(256,%r1),0(%r1) | ||
| 53 | la %r1,256(%r1) | ||
| 54 | brctg %r3,.Lmemset_fill_loop | ||
| 55 | .Lmemset_fill_rest: | ||
| 56 | larl %r3,.Lmemset_mvc | ||
| 57 | ex %r4,0(%r3) | ||
| 58 | br %r14 | ||
| 59 | .Lmemset_xc: | ||
| 60 | xc 0(1,%r1),0(%r1) | ||
| 61 | .Lmemset_mvc: | ||
| 62 | mvc 1(1,%r1),0(%r1) | ||
| 63 | |||
| 64 | /* | ||
| 65 | * memcpy implementation | ||
| 66 | * | ||
| 67 | * void *memcpy(void *dest, const void *src, size_t n) | ||
| 68 | */ | ||
| 69 | ENTRY(memcpy) | ||
| 70 | ltgr %r4,%r4 | ||
| 71 | bzr %r14 | ||
| 72 | aghi %r4,-1 | ||
| 73 | srlg %r5,%r4,8 | ||
| 74 | ltgr %r5,%r5 | ||
| 75 | lgr %r1,%r2 | ||
| 76 | jnz .Lmemcpy_loop | ||
| 77 | .Lmemcpy_rest: | ||
| 78 | larl %r5,.Lmemcpy_mvc | ||
| 79 | ex %r4,0(%r5) | ||
| 80 | br %r14 | ||
| 81 | .Lmemcpy_loop: | ||
| 82 | mvc 0(256,%r1),0(%r3) | ||
| 83 | la %r1,256(%r1) | ||
| 84 | la %r3,256(%r3) | ||
| 85 | brctg %r5,.Lmemcpy_loop | ||
| 86 | j .Lmemcpy_rest | ||
| 87 | .Lmemcpy_mvc: | ||
| 88 | mvc 0(1,%r1),0(%r3) | ||
diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c index 846ec64ab2c9..b647d5ff0ad9 100644 --- a/arch/s390/lib/string.c +++ b/arch/s390/lib/string.c | |||
| @@ -43,11 +43,7 @@ static inline char *__strnend(const char *s, size_t n) | |||
| 43 | */ | 43 | */ |
| 44 | size_t strlen(const char *s) | 44 | size_t strlen(const char *s) |
| 45 | { | 45 | { |
| 46 | #if __GNUC__ < 4 | ||
| 47 | return __strend(s) - s; | 46 | return __strend(s) - s; |
| 48 | #else | ||
| 49 | return __builtin_strlen(s); | ||
| 50 | #endif | ||
| 51 | } | 47 | } |
| 52 | EXPORT_SYMBOL(strlen); | 48 | EXPORT_SYMBOL(strlen); |
| 53 | 49 | ||
| @@ -73,7 +69,6 @@ EXPORT_SYMBOL(strnlen); | |||
| 73 | */ | 69 | */ |
| 74 | char *strcpy(char *dest, const char *src) | 70 | char *strcpy(char *dest, const char *src) |
| 75 | { | 71 | { |
| 76 | #if __GNUC__ < 4 | ||
| 77 | register int r0 asm("0") = 0; | 72 | register int r0 asm("0") = 0; |
| 78 | char *ret = dest; | 73 | char *ret = dest; |
| 79 | 74 | ||
| @@ -82,9 +77,6 @@ char *strcpy(char *dest, const char *src) | |||
| 82 | : "+&a" (dest), "+&a" (src) : "d" (r0) | 77 | : "+&a" (dest), "+&a" (src) : "d" (r0) |
| 83 | : "cc", "memory" ); | 78 | : "cc", "memory" ); |
| 84 | return ret; | 79 | return ret; |
| 85 | #else | ||
| 86 | return __builtin_strcpy(dest, src); | ||
| 87 | #endif | ||
| 88 | } | 80 | } |
| 89 | EXPORT_SYMBOL(strcpy); | 81 | EXPORT_SYMBOL(strcpy); |
| 90 | 82 | ||
| @@ -106,7 +98,7 @@ size_t strlcpy(char *dest, const char *src, size_t size) | |||
| 106 | if (size) { | 98 | if (size) { |
| 107 | size_t len = (ret >= size) ? size-1 : ret; | 99 | size_t len = (ret >= size) ? size-1 : ret; |
| 108 | dest[len] = '\0'; | 100 | dest[len] = '\0'; |
| 109 | __builtin_memcpy(dest, src, len); | 101 | memcpy(dest, src, len); |
| 110 | } | 102 | } |
| 111 | return ret; | 103 | return ret; |
| 112 | } | 104 | } |
| @@ -124,8 +116,8 @@ EXPORT_SYMBOL(strlcpy); | |||
| 124 | char *strncpy(char *dest, const char *src, size_t n) | 116 | char *strncpy(char *dest, const char *src, size_t n) |
| 125 | { | 117 | { |
| 126 | size_t len = __strnend(src, n) - src; | 118 | size_t len = __strnend(src, n) - src; |
| 127 | __builtin_memset(dest + len, 0, n - len); | 119 | memset(dest + len, 0, n - len); |
| 128 | __builtin_memcpy(dest, src, len); | 120 | memcpy(dest, src, len); |
| 129 | return dest; | 121 | return dest; |
| 130 | } | 122 | } |
| 131 | EXPORT_SYMBOL(strncpy); | 123 | EXPORT_SYMBOL(strncpy); |
| @@ -171,7 +163,7 @@ size_t strlcat(char *dest, const char *src, size_t n) | |||
| 171 | if (len >= n) | 163 | if (len >= n) |
| 172 | len = n - 1; | 164 | len = n - 1; |
| 173 | dest[len] = '\0'; | 165 | dest[len] = '\0'; |
| 174 | __builtin_memcpy(dest, src, len); | 166 | memcpy(dest, src, len); |
| 175 | } | 167 | } |
| 176 | return res; | 168 | return res; |
| 177 | } | 169 | } |
| @@ -194,7 +186,7 @@ char *strncat(char *dest, const char *src, size_t n) | |||
| 194 | char *p = __strend(dest); | 186 | char *p = __strend(dest); |
| 195 | 187 | ||
| 196 | p[len] = '\0'; | 188 | p[len] = '\0'; |
| 197 | __builtin_memcpy(p, src, len); | 189 | memcpy(p, src, len); |
| 198 | return dest; | 190 | return dest; |
| 199 | } | 191 | } |
| 200 | EXPORT_SYMBOL(strncat); | 192 | EXPORT_SYMBOL(strncat); |
| @@ -348,41 +340,3 @@ void *memscan(void *s, int c, size_t n) | |||
| 348 | return (void *) ret; | 340 | return (void *) ret; |
| 349 | } | 341 | } |
| 350 | EXPORT_SYMBOL(memscan); | 342 | EXPORT_SYMBOL(memscan); |
| 351 | |||
| 352 | /** | ||
| 353 | * memcpy - Copy one area of memory to another | ||
| 354 | * @dest: Where to copy to | ||
| 355 | * @src: Where to copy from | ||
| 356 | * @n: The size of the area. | ||
| 357 | * | ||
| 358 | * returns a pointer to @dest | ||
| 359 | */ | ||
| 360 | void *memcpy(void *dest, const void *src, size_t n) | ||
| 361 | { | ||
| 362 | return __builtin_memcpy(dest, src, n); | ||
| 363 | } | ||
| 364 | EXPORT_SYMBOL(memcpy); | ||
| 365 | |||
| 366 | /** | ||
| 367 | * memset - Fill a region of memory with the given value | ||
| 368 | * @s: Pointer to the start of the area. | ||
| 369 | * @c: The byte to fill the area with | ||
| 370 | * @n: The size of the area. | ||
| 371 | * | ||
| 372 | * returns a pointer to @s | ||
| 373 | */ | ||
| 374 | void *memset(void *s, int c, size_t n) | ||
| 375 | { | ||
| 376 | char *xs; | ||
| 377 | |||
| 378 | if (c == 0) | ||
| 379 | return __builtin_memset(s, 0, n); | ||
| 380 | |||
| 381 | xs = (char *) s; | ||
| 382 | if (n > 0) | ||
| 383 | do { | ||
| 384 | *xs++ = c; | ||
| 385 | } while (--n > 0); | ||
| 386 | return s; | ||
| 387 | } | ||
| 388 | EXPORT_SYMBOL(memset); | ||
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile index d98fe9004a52..0f5536b0c1a1 100644 --- a/arch/s390/mm/Makefile +++ b/arch/s390/mm/Makefile | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \ | 5 | obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \ |
| 6 | page-states.o gup.o | 6 | page-states.o gup.o extable.o |
| 7 | obj-$(CONFIG_CMM) += cmm.o | 7 | obj-$(CONFIG_CMM) += cmm.o |
| 8 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 8 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
| 9 | obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o | 9 | obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o |
diff --git a/arch/s390/mm/extable.c b/arch/s390/mm/extable.c new file mode 100644 index 000000000000..4d1ee88864e8 --- /dev/null +++ b/arch/s390/mm/extable.c | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | #include <linux/module.h> | ||
| 2 | #include <linux/sort.h> | ||
| 3 | #include <asm/uaccess.h> | ||
| 4 | |||
| 5 | /* | ||
| 6 | * Search one exception table for an entry corresponding to the | ||
| 7 | * given instruction address, and return the address of the entry, | ||
| 8 | * or NULL if none is found. | ||
| 9 | * We use a binary search, and thus we assume that the table is | ||
| 10 | * already sorted. | ||
| 11 | */ | ||
| 12 | const struct exception_table_entry * | ||
| 13 | search_extable(const struct exception_table_entry *first, | ||
| 14 | const struct exception_table_entry *last, | ||
| 15 | unsigned long value) | ||
| 16 | { | ||
| 17 | const struct exception_table_entry *mid; | ||
| 18 | unsigned long addr; | ||
| 19 | |||
| 20 | while (first <= last) { | ||
| 21 | mid = ((last - first) >> 1) + first; | ||
| 22 | addr = extable_insn(mid); | ||
| 23 | if (addr < value) | ||
| 24 | first = mid + 1; | ||
| 25 | else if (addr > value) | ||
| 26 | last = mid - 1; | ||
| 27 | else | ||
| 28 | return mid; | ||
| 29 | } | ||
| 30 | return NULL; | ||
| 31 | } | ||
| 32 | |||
| 33 | /* | ||
| 34 | * The exception table needs to be sorted so that the binary | ||
| 35 | * search that we use to find entries in it works properly. | ||
| 36 | * This is used both for the kernel exception table and for | ||
| 37 | * the exception tables of modules that get loaded. | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | static int cmp_ex(const void *a, const void *b) | ||
| 41 | { | ||
| 42 | const struct exception_table_entry *x = a, *y = b; | ||
| 43 | |||
| 44 | /* This compare is only valid after normalization. */ | ||
| 45 | return x->insn - y->insn; | ||
| 46 | } | ||
| 47 | |||
| 48 | void sort_extable(struct exception_table_entry *start, | ||
| 49 | struct exception_table_entry *finish) | ||
| 50 | { | ||
| 51 | struct exception_table_entry *p; | ||
| 52 | int i; | ||
| 53 | |||
| 54 | /* Normalize entries to being relative to the start of the section */ | ||
| 55 | for (p = start, i = 0; p < finish; p++, i += 8) | ||
| 56 | p->insn += i; | ||
| 57 | sort(start, finish - start, sizeof(*start), cmp_ex, NULL); | ||
| 58 | /* Denormalize all entries */ | ||
| 59 | for (p = start, i = 0; p < finish; p++, i += 8) | ||
| 60 | p->insn -= i; | ||
| 61 | } | ||
| 62 | |||
| 63 | #ifdef CONFIG_MODULES | ||
| 64 | /* | ||
| 65 | * If the exception table is sorted, any referring to the module init | ||
| 66 | * will be at the beginning or the end. | ||
| 67 | */ | ||
| 68 | void trim_init_extable(struct module *m) | ||
| 69 | { | ||
| 70 | /* Trim the beginning */ | ||
| 71 | while (m->num_exentries && | ||
| 72 | within_module_init(extable_insn(&m->extable[0]), m)) { | ||
| 73 | m->extable++; | ||
| 74 | m->num_exentries--; | ||
| 75 | } | ||
| 76 | /* Trim the end */ | ||
| 77 | while (m->num_exentries && | ||
| 78 | within_module_init(extable_insn(&m->extable[m->num_exentries-1]), m)) | ||
| 79 | m->num_exentries--; | ||
| 80 | } | ||
| 81 | #endif /* CONFIG_MODULES */ | ||
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 6c013f544146..ac9122ca1152 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
| @@ -111,7 +111,7 @@ static inline int user_space_fault(unsigned long trans_exc_code) | |||
| 111 | if (trans_exc_code == 2) | 111 | if (trans_exc_code == 2) |
| 112 | /* Access via secondary space, set_fs setting decides */ | 112 | /* Access via secondary space, set_fs setting decides */ |
| 113 | return current->thread.mm_segment.ar4; | 113 | return current->thread.mm_segment.ar4; |
| 114 | if (addressing_mode == HOME_SPACE_MODE) | 114 | if (s390_user_mode == HOME_SPACE_MODE) |
| 115 | /* User space if the access has been done via home space. */ | 115 | /* User space if the access has been done via home space. */ |
| 116 | return trans_exc_code == 3; | 116 | return trans_exc_code == 3; |
| 117 | /* | 117 | /* |
| @@ -163,7 +163,7 @@ static noinline void do_no_context(struct pt_regs *regs) | |||
| 163 | /* Are we prepared to handle this kernel fault? */ | 163 | /* Are we prepared to handle this kernel fault? */ |
| 164 | fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); | 164 | fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); |
| 165 | if (fixup) { | 165 | if (fixup) { |
| 166 | regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE; | 166 | regs->psw.addr = extable_fixup(fixup) | PSW_ADDR_AMODE; |
| 167 | return; | 167 | return; |
| 168 | } | 168 | } |
| 169 | 169 | ||
| @@ -628,9 +628,8 @@ static int __cpuinit pfault_cpu_notify(struct notifier_block *self, | |||
| 628 | struct thread_struct *thread, *next; | 628 | struct thread_struct *thread, *next; |
| 629 | struct task_struct *tsk; | 629 | struct task_struct *tsk; |
| 630 | 630 | ||
| 631 | switch (action) { | 631 | switch (action & ~CPU_TASKS_FROZEN) { |
| 632 | case CPU_DEAD: | 632 | case CPU_DEAD: |
| 633 | case CPU_DEAD_FROZEN: | ||
| 634 | spin_lock_irq(&pfault_lock); | 633 | spin_lock_irq(&pfault_lock); |
| 635 | list_for_each_entry_safe(thread, next, &pfault_list, list) { | 634 | list_for_each_entry_safe(thread, next, &pfault_list, list) { |
| 636 | thread->pfault_wait = 0; | 635 | thread->pfault_wait = 0; |
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index 65cb06e2af4e..eeaf8023851f 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c | |||
| @@ -154,6 +154,43 @@ static inline int gup_pud_range(pgd_t *pgdp, pgd_t pgd, unsigned long addr, | |||
| 154 | return 1; | 154 | return 1; |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | /* | ||
| 158 | * Like get_user_pages_fast() except its IRQ-safe in that it won't fall | ||
| 159 | * back to the regular GUP. | ||
| 160 | */ | ||
| 161 | int __get_user_pages_fast(unsigned long start, int nr_pages, int write, | ||
| 162 | struct page **pages) | ||
| 163 | { | ||
| 164 | struct mm_struct *mm = current->mm; | ||
| 165 | unsigned long addr, len, end; | ||
| 166 | unsigned long next, flags; | ||
| 167 | pgd_t *pgdp, pgd; | ||
| 168 | int nr = 0; | ||
| 169 | |||
| 170 | start &= PAGE_MASK; | ||
| 171 | addr = start; | ||
| 172 | len = (unsigned long) nr_pages << PAGE_SHIFT; | ||
| 173 | end = start + len; | ||
| 174 | if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, | ||
| 175 | (void __user *)start, len))) | ||
| 176 | return 0; | ||
| 177 | |||
| 178 | local_irq_save(flags); | ||
| 179 | pgdp = pgd_offset(mm, addr); | ||
| 180 | do { | ||
| 181 | pgd = *pgdp; | ||
| 182 | barrier(); | ||
| 183 | next = pgd_addr_end(addr, end); | ||
| 184 | if (pgd_none(pgd)) | ||
| 185 | break; | ||
| 186 | if (!gup_pud_range(pgdp, pgd, addr, next, write, pages, &nr)) | ||
| 187 | break; | ||
| 188 | } while (pgdp++, addr = next, addr != end); | ||
| 189 | local_irq_restore(flags); | ||
| 190 | |||
| 191 | return nr; | ||
| 192 | } | ||
| 193 | |||
| 157 | /** | 194 | /** |
| 158 | * get_user_pages_fast() - pin user pages in memory | 195 | * get_user_pages_fast() - pin user pages in memory |
| 159 | * @start: starting user address | 196 | * @start: starting user address |
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 6adbc082618a..81e596c65dee 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c | |||
| @@ -42,7 +42,7 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); | |||
| 42 | unsigned long empty_zero_page, zero_page_mask; | 42 | unsigned long empty_zero_page, zero_page_mask; |
| 43 | EXPORT_SYMBOL(empty_zero_page); | 43 | EXPORT_SYMBOL(empty_zero_page); |
| 44 | 44 | ||
| 45 | static unsigned long setup_zero_pages(void) | 45 | static unsigned long __init setup_zero_pages(void) |
| 46 | { | 46 | { |
| 47 | struct cpuid cpu_id; | 47 | struct cpuid cpu_id; |
| 48 | unsigned int order; | 48 | unsigned int order; |
| @@ -212,7 +212,7 @@ void free_initmem(void) | |||
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | #ifdef CONFIG_BLK_DEV_INITRD | 214 | #ifdef CONFIG_BLK_DEV_INITRD |
| 215 | void free_initrd_mem(unsigned long start, unsigned long end) | 215 | void __init free_initrd_mem(unsigned long start, unsigned long end) |
| 216 | { | 216 | { |
| 217 | free_init_pages("initrd memory", start, end); | 217 | free_init_pages("initrd memory", start, end); |
| 218 | } | 218 | } |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 18df31d1f2c9..b402991e43d7 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
| @@ -609,8 +609,8 @@ static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits) | |||
| 609 | */ | 609 | */ |
| 610 | unsigned long *page_table_alloc(struct mm_struct *mm, unsigned long vmaddr) | 610 | unsigned long *page_table_alloc(struct mm_struct *mm, unsigned long vmaddr) |
| 611 | { | 611 | { |
| 612 | struct page *page; | 612 | unsigned long *uninitialized_var(table); |
| 613 | unsigned long *table; | 613 | struct page *uninitialized_var(page); |
| 614 | unsigned int mask, bit; | 614 | unsigned int mask, bit; |
| 615 | 615 | ||
| 616 | if (mm_has_pgste(mm)) | 616 | if (mm_has_pgste(mm)) |
| @@ -796,7 +796,7 @@ int s390_enable_sie(void) | |||
| 796 | struct mm_struct *mm, *old_mm; | 796 | struct mm_struct *mm, *old_mm; |
| 797 | 797 | ||
| 798 | /* Do we have switched amode? If no, we cannot do sie */ | 798 | /* Do we have switched amode? If no, we cannot do sie */ |
| 799 | if (addressing_mode == HOME_SPACE_MODE) | 799 | if (s390_user_mode == HOME_SPACE_MODE) |
| 800 | return -EINVAL; | 800 | return -EINVAL; |
| 801 | 801 | ||
| 802 | /* Do we have pgstes? if yes, we are done */ | 802 | /* Do we have pgstes? if yes, we are done */ |
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 6f896e75ab49..c22abf900c9e 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c | |||
| @@ -107,7 +107,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
| 107 | pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0)); | 107 | pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0)); |
| 108 | pm_dir = pmd_offset(pu_dir, address); | 108 | pm_dir = pmd_offset(pu_dir, address); |
| 109 | 109 | ||
| 110 | #ifdef CONFIG_64BIT | 110 | #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) |
| 111 | if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) && | 111 | if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) && |
| 112 | (address + HPAGE_SIZE <= start + size) && | 112 | (address + HPAGE_SIZE <= start + size) && |
| 113 | (address >= HPAGE_SIZE)) { | 113 | (address >= HPAGE_SIZE)) { |
diff --git a/arch/s390/net/Makefile b/arch/s390/net/Makefile new file mode 100644 index 000000000000..90568c33ddb0 --- /dev/null +++ b/arch/s390/net/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | # | ||
| 2 | # Arch-specific network modules | ||
| 3 | # | ||
| 4 | obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o | ||
diff --git a/arch/s390/net/bpf_jit.S b/arch/s390/net/bpf_jit.S new file mode 100644 index 000000000000..7e45d13816c1 --- /dev/null +++ b/arch/s390/net/bpf_jit.S | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | /* | ||
| 2 | * BPF Jit compiler for s390, help functions. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * | ||
| 6 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 7 | */ | ||
| 8 | #include <linux/linkage.h> | ||
| 9 | |||
| 10 | /* | ||
| 11 | * Calling convention: | ||
| 12 | * registers %r2, %r6-%r8, %r10-%r11, %r13, %r15 are call saved | ||
| 13 | * %r2: skb pointer | ||
| 14 | * %r3: offset parameter | ||
| 15 | * %r5: BPF A accumulator | ||
| 16 | * %r8: return address | ||
| 17 | * %r9: save register for skb pointer | ||
| 18 | * %r10: skb->data | ||
| 19 | * %r11: skb->len - skb->data_len (headlen) | ||
| 20 | * %r12: BPF X accumulator | ||
| 21 | * | ||
| 22 | * skb_copy_bits takes 4 parameters: | ||
| 23 | * %r2 = skb pointer | ||
| 24 | * %r3 = offset into skb data | ||
| 25 | * %r4 = length to copy | ||
| 26 | * %r5 = pointer to temp buffer | ||
| 27 | */ | ||
| 28 | #define SKBDATA %r8 | ||
| 29 | |||
| 30 | /* A = *(u32 *) (skb->data+K+X) */ | ||
| 31 | ENTRY(sk_load_word_ind) | ||
| 32 | ar %r3,%r12 # offset += X | ||
| 33 | bmr %r8 # < 0 -> return with cc | ||
| 34 | |||
| 35 | /* A = *(u32 *) (skb->data+K) */ | ||
| 36 | ENTRY(sk_load_word) | ||
| 37 | llgfr %r1,%r3 # extend offset | ||
| 38 | ahi %r3,4 # offset + 4 | ||
| 39 | clr %r11,%r3 # hlen <= offset + 4 ? | ||
| 40 | jl sk_load_word_slow | ||
| 41 | l %r5,0(%r1,%r10) # get word from skb | ||
| 42 | xr %r1,%r1 # set cc to zero | ||
| 43 | br %r8 | ||
| 44 | |||
| 45 | sk_load_word_slow: | ||
| 46 | lgr %r9,%r2 # save %r2 | ||
| 47 | lhi %r4,4 # 4 bytes | ||
| 48 | la %r5,160(%r15) # pointer to temp buffer | ||
| 49 | brasl %r14,skb_copy_bits # get data from skb | ||
| 50 | l %r5,160(%r15) # load result from temp buffer | ||
| 51 | ltgr %r2,%r2 # set cc to (%r2 != 0) | ||
| 52 | lgr %r2,%r9 # restore %r2 | ||
| 53 | br %r8 | ||
| 54 | |||
| 55 | /* A = *(u16 *) (skb->data+K+X) */ | ||
| 56 | ENTRY(sk_load_half_ind) | ||
| 57 | ar %r3,%r12 # offset += X | ||
| 58 | bmr %r8 # < 0 -> return with cc | ||
| 59 | |||
| 60 | /* A = *(u16 *) (skb->data+K) */ | ||
| 61 | ENTRY(sk_load_half) | ||
| 62 | llgfr %r1,%r3 # extend offset | ||
| 63 | ahi %r3,2 # offset + 2 | ||
| 64 | clr %r11,%r3 # hlen <= offset + 2 ? | ||
| 65 | jl sk_load_half_slow | ||
| 66 | llgh %r5,0(%r1,%r10) # get half from skb | ||
| 67 | xr %r1,%r1 # set cc to zero | ||
| 68 | br %r8 | ||
| 69 | |||
| 70 | sk_load_half_slow: | ||
| 71 | lgr %r9,%r2 # save %r2 | ||
| 72 | lhi %r4,2 # 2 bytes | ||
| 73 | la %r5,162(%r15) # pointer to temp buffer | ||
| 74 | brasl %r14,skb_copy_bits # get data from skb | ||
| 75 | xc 160(2,%r15),160(%r15) | ||
| 76 | l %r5,160(%r15) # load result from temp buffer | ||
| 77 | ltgr %r2,%r2 # set cc to (%r2 != 0) | ||
| 78 | lgr %r2,%r9 # restore %r2 | ||
| 79 | br %r8 | ||
| 80 | |||
| 81 | /* A = *(u8 *) (skb->data+K+X) */ | ||
| 82 | ENTRY(sk_load_byte_ind) | ||
| 83 | ar %r3,%r12 # offset += X | ||
| 84 | bmr %r8 # < 0 -> return with cc | ||
| 85 | |||
| 86 | /* A = *(u8 *) (skb->data+K) */ | ||
| 87 | ENTRY(sk_load_byte) | ||
| 88 | llgfr %r1,%r3 # extend offset | ||
| 89 | clr %r11,%r3 # hlen < offset ? | ||
| 90 | jle sk_load_byte_slow | ||
| 91 | lhi %r5,0 | ||
| 92 | ic %r5,0(%r1,%r10) # get byte from skb | ||
| 93 | xr %r1,%r1 # set cc to zero | ||
| 94 | br %r8 | ||
| 95 | |||
| 96 | sk_load_byte_slow: | ||
| 97 | lgr %r9,%r2 # save %r2 | ||
| 98 | lhi %r4,1 # 1 bytes | ||
| 99 | la %r5,163(%r15) # pointer to temp buffer | ||
| 100 | brasl %r14,skb_copy_bits # get data from skb | ||
| 101 | xc 160(3,%r15),160(%r15) | ||
| 102 | l %r5,160(%r15) # load result from temp buffer | ||
| 103 | ltgr %r2,%r2 # set cc to (%r2 != 0) | ||
| 104 | lgr %r2,%r9 # restore %r2 | ||
| 105 | br %r8 | ||
| 106 | |||
| 107 | /* A = (*(u8 *)(skb->data+K) & 0xf) << 2 */ | ||
| 108 | ENTRY(sk_load_byte_msh) | ||
| 109 | llgfr %r1,%r3 # extend offset | ||
| 110 | clr %r11,%r3 # hlen < offset ? | ||
| 111 | jle sk_load_byte_slow | ||
| 112 | lhi %r12,0 | ||
| 113 | ic %r12,0(%r1,%r10) # get byte from skb | ||
| 114 | nill %r12,0x0f | ||
| 115 | sll %r12,2 | ||
| 116 | xr %r1,%r1 # set cc to zero | ||
| 117 | br %r8 | ||
| 118 | |||
| 119 | sk_load_byte_msh_slow: | ||
| 120 | lgr %r9,%r2 # save %r2 | ||
| 121 | lhi %r4,2 # 2 bytes | ||
| 122 | la %r5,162(%r15) # pointer to temp buffer | ||
| 123 | brasl %r14,skb_copy_bits # get data from skb | ||
| 124 | xc 160(3,%r15),160(%r15) | ||
| 125 | l %r12,160(%r15) # load result from temp buffer | ||
| 126 | nill %r12,0x0f | ||
| 127 | sll %r12,2 | ||
| 128 | ltgr %r2,%r2 # set cc to (%r2 != 0) | ||
| 129 | lgr %r2,%r9 # restore %r2 | ||
| 130 | br %r8 | ||
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c new file mode 100644 index 000000000000..9b355b406afa --- /dev/null +++ b/arch/s390/net/bpf_jit_comp.c | |||
| @@ -0,0 +1,776 @@ | |||
| 1 | /* | ||
| 2 | * BPF Jit compiler for s390. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * | ||
| 6 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 7 | */ | ||
| 8 | #include <linux/moduleloader.h> | ||
| 9 | #include <linux/netdevice.h> | ||
| 10 | #include <linux/filter.h> | ||
| 11 | #include <asm/cacheflush.h> | ||
| 12 | #include <asm/processor.h> | ||
| 13 | #include <asm/facility.h> | ||
| 14 | |||
| 15 | /* | ||
| 16 | * Conventions: | ||
| 17 | * %r2 = skb pointer | ||
| 18 | * %r3 = offset parameter | ||
| 19 | * %r4 = scratch register / length parameter | ||
| 20 | * %r5 = BPF A accumulator | ||
| 21 | * %r8 = return address | ||
| 22 | * %r9 = save register for skb pointer | ||
| 23 | * %r10 = skb->data | ||
| 24 | * %r11 = skb->len - skb->data_len (headlen) | ||
| 25 | * %r12 = BPF X accumulator | ||
| 26 | * %r13 = literal pool pointer | ||
| 27 | * 0(%r15) - 63(%r15) scratch memory array with BPF_MEMWORDS | ||
| 28 | */ | ||
| 29 | int bpf_jit_enable __read_mostly; | ||
| 30 | |||
| 31 | /* | ||
| 32 | * assembly code in arch/x86/net/bpf_jit.S | ||
| 33 | */ | ||
| 34 | extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[]; | ||
| 35 | extern u8 sk_load_word_ind[], sk_load_half_ind[], sk_load_byte_ind[]; | ||
| 36 | |||
| 37 | struct bpf_jit { | ||
| 38 | unsigned int seen; | ||
| 39 | u8 *start; | ||
| 40 | u8 *prg; | ||
| 41 | u8 *mid; | ||
| 42 | u8 *lit; | ||
| 43 | u8 *end; | ||
| 44 | u8 *base_ip; | ||
| 45 | u8 *ret0_ip; | ||
| 46 | u8 *exit_ip; | ||
| 47 | unsigned int off_load_word; | ||
| 48 | unsigned int off_load_half; | ||
| 49 | unsigned int off_load_byte; | ||
| 50 | unsigned int off_load_bmsh; | ||
| 51 | unsigned int off_load_iword; | ||
| 52 | unsigned int off_load_ihalf; | ||
| 53 | unsigned int off_load_ibyte; | ||
| 54 | }; | ||
| 55 | |||
| 56 | #define BPF_SIZE_MAX 4096 /* Max size for program */ | ||
| 57 | |||
| 58 | #define SEEN_DATAREF 1 /* might call external helpers */ | ||
| 59 | #define SEEN_XREG 2 /* ebx is used */ | ||
| 60 | #define SEEN_MEM 4 /* use mem[] for temporary storage */ | ||
| 61 | #define SEEN_RET0 8 /* pc_ret0 points to a valid return 0 */ | ||
| 62 | #define SEEN_LITERAL 16 /* code uses literals */ | ||
| 63 | #define SEEN_LOAD_WORD 32 /* code uses sk_load_word */ | ||
| 64 | #define SEEN_LOAD_HALF 64 /* code uses sk_load_half */ | ||
| 65 | #define SEEN_LOAD_BYTE 128 /* code uses sk_load_byte */ | ||
| 66 | #define SEEN_LOAD_BMSH 256 /* code uses sk_load_byte_msh */ | ||
| 67 | #define SEEN_LOAD_IWORD 512 /* code uses sk_load_word_ind */ | ||
| 68 | #define SEEN_LOAD_IHALF 1024 /* code uses sk_load_half_ind */ | ||
| 69 | #define SEEN_LOAD_IBYTE 2048 /* code uses sk_load_byte_ind */ | ||
| 70 | |||
| 71 | #define EMIT2(op) \ | ||
| 72 | ({ \ | ||
| 73 | if (jit->prg + 2 <= jit->mid) \ | ||
| 74 | *(u16 *) jit->prg = op; \ | ||
| 75 | jit->prg += 2; \ | ||
| 76 | }) | ||
| 77 | |||
| 78 | #define EMIT4(op) \ | ||
| 79 | ({ \ | ||
| 80 | if (jit->prg + 4 <= jit->mid) \ | ||
| 81 | *(u32 *) jit->prg = op; \ | ||
| 82 | jit->prg += 4; \ | ||
| 83 | }) | ||
| 84 | |||
| 85 | #define EMIT4_DISP(op, disp) \ | ||
| 86 | ({ \ | ||
| 87 | unsigned int __disp = (disp) & 0xfff; \ | ||
| 88 | EMIT4(op | __disp); \ | ||
| 89 | }) | ||
| 90 | |||
| 91 | #define EMIT4_IMM(op, imm) \ | ||
| 92 | ({ \ | ||
| 93 | unsigned int __imm = (imm) & 0xffff; \ | ||
| 94 | EMIT4(op | __imm); \ | ||
| 95 | }) | ||
| 96 | |||
| 97 | #define EMIT4_PCREL(op, pcrel) \ | ||
| 98 | ({ \ | ||
| 99 | long __pcrel = ((pcrel) >> 1) & 0xffff; \ | ||
| 100 | EMIT4(op | __pcrel); \ | ||
| 101 | }) | ||
| 102 | |||
| 103 | #define EMIT6(op1, op2) \ | ||
| 104 | ({ \ | ||
| 105 | if (jit->prg + 6 <= jit->mid) { \ | ||
| 106 | *(u32 *) jit->prg = op1; \ | ||
| 107 | *(u16 *) (jit->prg + 4) = op2; \ | ||
| 108 | } \ | ||
| 109 | jit->prg += 6; \ | ||
| 110 | }) | ||
| 111 | |||
| 112 | #define EMIT6_DISP(op1, op2, disp) \ | ||
| 113 | ({ \ | ||
| 114 | unsigned int __disp = (disp) & 0xfff; \ | ||
| 115 | EMIT6(op1 | __disp, op2); \ | ||
| 116 | }) | ||
| 117 | |||
| 118 | #define EMIT6_IMM(op, imm) \ | ||
| 119 | ({ \ | ||
| 120 | unsigned int __imm = (imm); \ | ||
| 121 | EMIT6(op | (__imm >> 16), __imm & 0xffff); \ | ||
| 122 | }) | ||
| 123 | |||
| 124 | #define EMIT_CONST(val) \ | ||
| 125 | ({ \ | ||
| 126 | unsigned int ret; \ | ||
| 127 | ret = (unsigned int) (jit->lit - jit->base_ip); \ | ||
| 128 | jit->seen |= SEEN_LITERAL; \ | ||
| 129 | if (jit->lit + 4 <= jit->end) \ | ||
| 130 | *(u32 *) jit->lit = val; \ | ||
| 131 | jit->lit += 4; \ | ||
| 132 | ret; \ | ||
| 133 | }) | ||
| 134 | |||
| 135 | #define EMIT_FN_CONST(bit, fn) \ | ||
| 136 | ({ \ | ||
| 137 | unsigned int ret; \ | ||
| 138 | ret = (unsigned int) (jit->lit - jit->base_ip); \ | ||
| 139 | if (jit->seen & bit) { \ | ||
| 140 | jit->seen |= SEEN_LITERAL; \ | ||
| 141 | if (jit->lit + 8 <= jit->end) \ | ||
| 142 | *(void **) jit->lit = fn; \ | ||
| 143 | jit->lit += 8; \ | ||
| 144 | } \ | ||
| 145 | ret; \ | ||
| 146 | }) | ||
| 147 | |||
| 148 | static void bpf_jit_prologue(struct bpf_jit *jit) | ||
| 149 | { | ||
| 150 | /* Save registers and create stack frame if necessary */ | ||
| 151 | if (jit->seen & SEEN_DATAREF) { | ||
| 152 | /* stmg %r8,%r15,88(%r15) */ | ||
| 153 | EMIT6(0xeb8ff058, 0x0024); | ||
| 154 | /* lgr %r14,%r15 */ | ||
| 155 | EMIT4(0xb90400ef); | ||
| 156 | /* ahi %r15,<offset> */ | ||
| 157 | EMIT4_IMM(0xa7fa0000, (jit->seen & SEEN_MEM) ? -112 : -80); | ||
| 158 | /* stg %r14,152(%r15) */ | ||
| 159 | EMIT6(0xe3e0f098, 0x0024); | ||
| 160 | } else if ((jit->seen & SEEN_XREG) && (jit->seen & SEEN_LITERAL)) | ||
| 161 | /* stmg %r12,%r13,120(%r15) */ | ||
| 162 | EMIT6(0xebcdf078, 0x0024); | ||
| 163 | else if (jit->seen & SEEN_XREG) | ||
| 164 | /* stg %r12,120(%r15) */ | ||
| 165 | EMIT6(0xe3c0f078, 0x0024); | ||
| 166 | else if (jit->seen & SEEN_LITERAL) | ||
| 167 | /* stg %r13,128(%r15) */ | ||
| 168 | EMIT6(0xe3d0f080, 0x0024); | ||
| 169 | |||
| 170 | /* Setup literal pool */ | ||
| 171 | if (jit->seen & SEEN_LITERAL) { | ||
| 172 | /* basr %r13,0 */ | ||
| 173 | EMIT2(0x0dd0); | ||
| 174 | jit->base_ip = jit->prg; | ||
| 175 | } | ||
| 176 | jit->off_load_word = EMIT_FN_CONST(SEEN_LOAD_WORD, sk_load_word); | ||
| 177 | jit->off_load_half = EMIT_FN_CONST(SEEN_LOAD_HALF, sk_load_half); | ||
| 178 | jit->off_load_byte = EMIT_FN_CONST(SEEN_LOAD_BYTE, sk_load_byte); | ||
| 179 | jit->off_load_bmsh = EMIT_FN_CONST(SEEN_LOAD_BMSH, sk_load_byte_msh); | ||
| 180 | jit->off_load_iword = EMIT_FN_CONST(SEEN_LOAD_IWORD, sk_load_word_ind); | ||
| 181 | jit->off_load_ihalf = EMIT_FN_CONST(SEEN_LOAD_IHALF, sk_load_half_ind); | ||
| 182 | jit->off_load_ibyte = EMIT_FN_CONST(SEEN_LOAD_IBYTE, sk_load_byte_ind); | ||
| 183 | |||
| 184 | /* Filter needs to access skb data */ | ||
| 185 | if (jit->seen & SEEN_DATAREF) { | ||
| 186 | /* l %r11,<len>(%r2) */ | ||
| 187 | EMIT4_DISP(0x58b02000, offsetof(struct sk_buff, len)); | ||
| 188 | /* s %r11,<data_len>(%r2) */ | ||
| 189 | EMIT4_DISP(0x5bb02000, offsetof(struct sk_buff, data_len)); | ||
| 190 | /* lg %r10,<data>(%r2) */ | ||
| 191 | EMIT6_DISP(0xe3a02000, 0x0004, | ||
| 192 | offsetof(struct sk_buff, data)); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | static void bpf_jit_epilogue(struct bpf_jit *jit) | ||
| 197 | { | ||
| 198 | /* Return 0 */ | ||
| 199 | if (jit->seen & SEEN_RET0) { | ||
| 200 | jit->ret0_ip = jit->prg; | ||
| 201 | /* lghi %r2,0 */ | ||
| 202 | EMIT4(0xa7290000); | ||
| 203 | } | ||
| 204 | jit->exit_ip = jit->prg; | ||
| 205 | /* Restore registers */ | ||
| 206 | if (jit->seen & SEEN_DATAREF) | ||
| 207 | /* lmg %r8,%r15,<offset>(%r15) */ | ||
| 208 | EMIT6_DISP(0xeb8ff000, 0x0004, | ||
| 209 | (jit->seen & SEEN_MEM) ? 200 : 168); | ||
| 210 | else if ((jit->seen & SEEN_XREG) && (jit->seen & SEEN_LITERAL)) | ||
| 211 | /* lmg %r12,%r13,120(%r15) */ | ||
| 212 | EMIT6(0xebcdf078, 0x0004); | ||
| 213 | else if (jit->seen & SEEN_XREG) | ||
| 214 | /* lg %r12,120(%r15) */ | ||
| 215 | EMIT6(0xe3c0f078, 0x0004); | ||
| 216 | else if (jit->seen & SEEN_LITERAL) | ||
| 217 | /* lg %r13,128(%r15) */ | ||
| 218 | EMIT6(0xe3d0f080, 0x0004); | ||
| 219 | /* br %r14 */ | ||
| 220 | EMIT2(0x07fe); | ||
| 221 | } | ||
| 222 | |||
| 223 | /* | ||
| 224 | * make sure we dont leak kernel information to user | ||
| 225 | */ | ||
| 226 | static void bpf_jit_noleaks(struct bpf_jit *jit, struct sock_filter *filter) | ||
| 227 | { | ||
| 228 | /* Clear temporary memory if (seen & SEEN_MEM) */ | ||
| 229 | if (jit->seen & SEEN_MEM) | ||
| 230 | /* xc 0(64,%r15),0(%r15) */ | ||
| 231 | EMIT6(0xd73ff000, 0xf000); | ||
| 232 | /* Clear X if (seen & SEEN_XREG) */ | ||
| 233 | if (jit->seen & SEEN_XREG) | ||
| 234 | /* lhi %r12,0 */ | ||
| 235 | EMIT4(0xa7c80000); | ||
| 236 | /* Clear A if the first register does not set it. */ | ||
| 237 | switch (filter[0].code) { | ||
| 238 | case BPF_S_LD_W_ABS: | ||
| 239 | case BPF_S_LD_H_ABS: | ||
| 240 | case BPF_S_LD_B_ABS: | ||
| 241 | case BPF_S_LD_W_LEN: | ||
| 242 | case BPF_S_LD_W_IND: | ||
| 243 | case BPF_S_LD_H_IND: | ||
| 244 | case BPF_S_LD_B_IND: | ||
| 245 | case BPF_S_LDX_B_MSH: | ||
| 246 | case BPF_S_LD_IMM: | ||
| 247 | case BPF_S_LD_MEM: | ||
| 248 | case BPF_S_MISC_TXA: | ||
| 249 | case BPF_S_ANC_PROTOCOL: | ||
| 250 | case BPF_S_ANC_PKTTYPE: | ||
| 251 | case BPF_S_ANC_IFINDEX: | ||
| 252 | case BPF_S_ANC_MARK: | ||
| 253 | case BPF_S_ANC_QUEUE: | ||
| 254 | case BPF_S_ANC_HATYPE: | ||
| 255 | case BPF_S_ANC_RXHASH: | ||
| 256 | case BPF_S_ANC_CPU: | ||
| 257 | case BPF_S_RET_K: | ||
| 258 | /* first instruction sets A register */ | ||
| 259 | break; | ||
| 260 | default: /* A = 0 */ | ||
| 261 | /* lhi %r5,0 */ | ||
| 262 | EMIT4(0xa7580000); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter, | ||
| 267 | unsigned int *addrs, int i, int last) | ||
| 268 | { | ||
| 269 | unsigned int K; | ||
| 270 | int offset; | ||
| 271 | unsigned int mask; | ||
| 272 | |||
| 273 | K = filter->k; | ||
| 274 | switch (filter->code) { | ||
| 275 | case BPF_S_ALU_ADD_X: /* A += X */ | ||
| 276 | jit->seen |= SEEN_XREG; | ||
| 277 | /* ar %r5,%r12 */ | ||
| 278 | EMIT2(0x1a5c); | ||
| 279 | break; | ||
| 280 | case BPF_S_ALU_ADD_K: /* A += K */ | ||
| 281 | if (!K) | ||
| 282 | break; | ||
| 283 | if (K <= 16383) | ||
| 284 | /* ahi %r5,<K> */ | ||
| 285 | EMIT4_IMM(0xa75a0000, K); | ||
| 286 | else if (test_facility(21)) | ||
| 287 | /* alfi %r5,<K> */ | ||
| 288 | EMIT6_IMM(0xc25b0000, K); | ||
| 289 | else | ||
| 290 | /* a %r5,<d(K)>(%r13) */ | ||
| 291 | EMIT4_DISP(0x5a50d000, EMIT_CONST(K)); | ||
| 292 | break; | ||
| 293 | case BPF_S_ALU_SUB_X: /* A -= X */ | ||
| 294 | jit->seen |= SEEN_XREG; | ||
| 295 | /* sr %r5,%r12 */ | ||
| 296 | EMIT2(0x1b5c); | ||
| 297 | break; | ||
| 298 | case BPF_S_ALU_SUB_K: /* A -= K */ | ||
| 299 | if (!K) | ||
| 300 | break; | ||
| 301 | if (K <= 16384) | ||
| 302 | /* ahi %r5,-K */ | ||
| 303 | EMIT4_IMM(0xa75a0000, -K); | ||
| 304 | else if (test_facility(21)) | ||
| 305 | /* alfi %r5,-K */ | ||
| 306 | EMIT6_IMM(0xc25b0000, -K); | ||
| 307 | else | ||
| 308 | /* s %r5,<d(K)>(%r13) */ | ||
| 309 | EMIT4_DISP(0x5b50d000, EMIT_CONST(K)); | ||
| 310 | break; | ||
| 311 | case BPF_S_ALU_MUL_X: /* A *= X */ | ||
| 312 | jit->seen |= SEEN_XREG; | ||
| 313 | /* msr %r5,%r12 */ | ||
| 314 | EMIT4(0xb252005c); | ||
| 315 | break; | ||
| 316 | case BPF_S_ALU_MUL_K: /* A *= K */ | ||
| 317 | if (K <= 16383) | ||
| 318 | /* mhi %r5,K */ | ||
| 319 | EMIT4_IMM(0xa75c0000, K); | ||
| 320 | else if (test_facility(34)) | ||
| 321 | /* msfi %r5,<K> */ | ||
| 322 | EMIT6_IMM(0xc2510000, K); | ||
| 323 | else | ||
| 324 | /* ms %r5,<d(K)>(%r13) */ | ||
| 325 | EMIT4_DISP(0x7150d000, EMIT_CONST(K)); | ||
| 326 | break; | ||
| 327 | case BPF_S_ALU_DIV_X: /* A /= X */ | ||
| 328 | jit->seen |= SEEN_XREG | SEEN_RET0; | ||
| 329 | /* ltr %r12,%r12 */ | ||
| 330 | EMIT2(0x12cc); | ||
| 331 | /* jz <ret0> */ | ||
| 332 | EMIT4_PCREL(0xa7840000, (jit->ret0_ip - jit->prg)); | ||
| 333 | /* lhi %r4,0 */ | ||
| 334 | EMIT4(0xa7480000); | ||
| 335 | /* dr %r4,%r12 */ | ||
| 336 | EMIT2(0x1d4c); | ||
| 337 | break; | ||
| 338 | case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K) */ | ||
| 339 | /* m %r4,<d(K)>(%r13) */ | ||
| 340 | EMIT4_DISP(0x5c40d000, EMIT_CONST(K)); | ||
| 341 | /* lr %r5,%r4 */ | ||
| 342 | EMIT2(0x1854); | ||
| 343 | break; | ||
| 344 | case BPF_S_ALU_AND_X: /* A &= X */ | ||
| 345 | jit->seen |= SEEN_XREG; | ||
| 346 | /* nr %r5,%r12 */ | ||
| 347 | EMIT2(0x145c); | ||
| 348 | break; | ||
| 349 | case BPF_S_ALU_AND_K: /* A &= K */ | ||
| 350 | if (test_facility(21)) | ||
| 351 | /* nilf %r5,<K> */ | ||
| 352 | EMIT6_IMM(0xc05b0000, K); | ||
| 353 | else | ||
| 354 | /* n %r5,<d(K)>(%r13) */ | ||
| 355 | EMIT4_DISP(0x5450d000, EMIT_CONST(K)); | ||
| 356 | break; | ||
| 357 | case BPF_S_ALU_OR_X: /* A |= X */ | ||
| 358 | jit->seen |= SEEN_XREG; | ||
| 359 | /* or %r5,%r12 */ | ||
| 360 | EMIT2(0x165c); | ||
| 361 | break; | ||
| 362 | case BPF_S_ALU_OR_K: /* A |= K */ | ||
| 363 | if (test_facility(21)) | ||
| 364 | /* oilf %r5,<K> */ | ||
| 365 | EMIT6_IMM(0xc05d0000, K); | ||
| 366 | else | ||
| 367 | /* o %r5,<d(K)>(%r13) */ | ||
| 368 | EMIT4_DISP(0x5650d000, EMIT_CONST(K)); | ||
| 369 | break; | ||
| 370 | case BPF_S_ANC_ALU_XOR_X: /* A ^= X; */ | ||
| 371 | jit->seen |= SEEN_XREG; | ||
| 372 | /* xr %r5,%r12 */ | ||
| 373 | EMIT2(0x175c); | ||
| 374 | break; | ||
| 375 | case BPF_S_ALU_LSH_X: /* A <<= X; */ | ||
| 376 | jit->seen |= SEEN_XREG; | ||
| 377 | /* sll %r5,0(%r12) */ | ||
| 378 | EMIT4(0x8950c000); | ||
| 379 | break; | ||
| 380 | case BPF_S_ALU_LSH_K: /* A <<= K */ | ||
| 381 | if (K == 0) | ||
| 382 | break; | ||
| 383 | /* sll %r5,K */ | ||
| 384 | EMIT4_DISP(0x89500000, K); | ||
| 385 | break; | ||
| 386 | case BPF_S_ALU_RSH_X: /* A >>= X; */ | ||
| 387 | jit->seen |= SEEN_XREG; | ||
| 388 | /* srl %r5,0(%r12) */ | ||
| 389 | EMIT4(0x8850c000); | ||
| 390 | break; | ||
| 391 | case BPF_S_ALU_RSH_K: /* A >>= K; */ | ||
| 392 | if (K == 0) | ||
| 393 | break; | ||
| 394 | /* srl %r5,K */ | ||
| 395 | EMIT4_DISP(0x88500000, K); | ||
| 396 | break; | ||
| 397 | case BPF_S_ALU_NEG: /* A = -A */ | ||
| 398 | /* lnr %r5,%r5 */ | ||
| 399 | EMIT2(0x1155); | ||
| 400 | break; | ||
| 401 | case BPF_S_JMP_JA: /* ip += K */ | ||
| 402 | offset = addrs[i + K] + jit->start - jit->prg; | ||
| 403 | EMIT4_PCREL(0xa7f40000, offset); | ||
| 404 | break; | ||
| 405 | case BPF_S_JMP_JGT_K: /* ip += (A > K) ? jt : jf */ | ||
| 406 | mask = 0x200000; /* jh */ | ||
| 407 | goto kbranch; | ||
| 408 | case BPF_S_JMP_JGE_K: /* ip += (A >= K) ? jt : jf */ | ||
| 409 | mask = 0xa00000; /* jhe */ | ||
| 410 | goto kbranch; | ||
| 411 | case BPF_S_JMP_JEQ_K: /* ip += (A == K) ? jt : jf */ | ||
| 412 | mask = 0x800000; /* je */ | ||
| 413 | kbranch: /* Emit compare if the branch targets are different */ | ||
| 414 | if (filter->jt != filter->jf) { | ||
| 415 | if (K <= 16383) | ||
| 416 | /* chi %r5,<K> */ | ||
| 417 | EMIT4_IMM(0xa75e0000, K); | ||
| 418 | else if (test_facility(21)) | ||
| 419 | /* clfi %r5,<K> */ | ||
| 420 | EMIT6_IMM(0xc25f0000, K); | ||
| 421 | else | ||
| 422 | /* c %r5,<d(K)>(%r13) */ | ||
| 423 | EMIT4_DISP(0x5950d000, EMIT_CONST(K)); | ||
| 424 | } | ||
| 425 | branch: if (filter->jt == filter->jf) { | ||
| 426 | if (filter->jt == 0) | ||
| 427 | break; | ||
| 428 | /* j <jt> */ | ||
| 429 | offset = addrs[i + filter->jt] + jit->start - jit->prg; | ||
| 430 | EMIT4_PCREL(0xa7f40000, offset); | ||
| 431 | break; | ||
| 432 | } | ||
| 433 | if (filter->jt != 0) { | ||
| 434 | /* brc <mask>,<jt> */ | ||
| 435 | offset = addrs[i + filter->jt] + jit->start - jit->prg; | ||
| 436 | EMIT4_PCREL(0xa7040000 | mask, offset); | ||
| 437 | } | ||
| 438 | if (filter->jf != 0) { | ||
| 439 | /* brc <mask^15>,<jf> */ | ||
| 440 | offset = addrs[i + filter->jf] + jit->start - jit->prg; | ||
| 441 | EMIT4_PCREL(0xa7040000 | (mask ^ 0xf00000), offset); | ||
| 442 | } | ||
| 443 | break; | ||
| 444 | case BPF_S_JMP_JSET_K: /* ip += (A & K) ? jt : jf */ | ||
| 445 | mask = 0x700000; /* jnz */ | ||
| 446 | /* Emit test if the branch targets are different */ | ||
| 447 | if (filter->jt != filter->jf) { | ||
| 448 | if (K > 65535) { | ||
| 449 | /* lr %r4,%r5 */ | ||
| 450 | EMIT2(0x1845); | ||
| 451 | /* n %r4,<d(K)>(%r13) */ | ||
| 452 | EMIT4_DISP(0x5440d000, EMIT_CONST(K)); | ||
| 453 | } else | ||
| 454 | /* tmll %r5,K */ | ||
| 455 | EMIT4_IMM(0xa7510000, K); | ||
| 456 | } | ||
| 457 | goto branch; | ||
| 458 | case BPF_S_JMP_JGT_X: /* ip += (A > X) ? jt : jf */ | ||
| 459 | mask = 0x200000; /* jh */ | ||
| 460 | goto xbranch; | ||
| 461 | case BPF_S_JMP_JGE_X: /* ip += (A >= X) ? jt : jf */ | ||
| 462 | mask = 0xa00000; /* jhe */ | ||
| 463 | goto xbranch; | ||
| 464 | case BPF_S_JMP_JEQ_X: /* ip += (A == X) ? jt : jf */ | ||
| 465 | mask = 0x800000; /* je */ | ||
| 466 | xbranch: /* Emit compare if the branch targets are different */ | ||
| 467 | if (filter->jt != filter->jf) { | ||
| 468 | jit->seen |= SEEN_XREG; | ||
| 469 | /* cr %r5,%r12 */ | ||
| 470 | EMIT2(0x195c); | ||
| 471 | } | ||
| 472 | goto branch; | ||
| 473 | case BPF_S_JMP_JSET_X: /* ip += (A & X) ? jt : jf */ | ||
| 474 | mask = 0x700000; /* jnz */ | ||
| 475 | /* Emit test if the branch targets are different */ | ||
| 476 | if (filter->jt != filter->jf) { | ||
| 477 | jit->seen |= SEEN_XREG; | ||
| 478 | /* lr %r4,%r5 */ | ||
| 479 | EMIT2(0x1845); | ||
| 480 | /* nr %r4,%r12 */ | ||
| 481 | EMIT2(0x144c); | ||
| 482 | } | ||
| 483 | goto branch; | ||
| 484 | case BPF_S_LD_W_ABS: /* A = *(u32 *) (skb->data+K) */ | ||
| 485 | jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_WORD; | ||
| 486 | offset = jit->off_load_word; | ||
| 487 | goto load_abs; | ||
| 488 | case BPF_S_LD_H_ABS: /* A = *(u16 *) (skb->data+K) */ | ||
| 489 | jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_HALF; | ||
| 490 | offset = jit->off_load_half; | ||
| 491 | goto load_abs; | ||
| 492 | case BPF_S_LD_B_ABS: /* A = *(u8 *) (skb->data+K) */ | ||
| 493 | jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_BYTE; | ||
| 494 | offset = jit->off_load_byte; | ||
| 495 | load_abs: if ((int) K < 0) | ||
| 496 | goto out; | ||
| 497 | call_fn: /* lg %r1,<d(function)>(%r13) */ | ||
| 498 | EMIT6_DISP(0xe310d000, 0x0004, offset); | ||
| 499 | /* l %r3,<d(K)>(%r13) */ | ||
| 500 | EMIT4_DISP(0x5830d000, EMIT_CONST(K)); | ||
| 501 | /* basr %r8,%r1 */ | ||
| 502 | EMIT2(0x0d81); | ||
| 503 | /* jnz <ret0> */ | ||
| 504 | EMIT4_PCREL(0xa7740000, (jit->ret0_ip - jit->prg)); | ||
| 505 | break; | ||
| 506 | case BPF_S_LD_W_IND: /* A = *(u32 *) (skb->data+K+X) */ | ||
| 507 | jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IWORD; | ||
| 508 | offset = jit->off_load_iword; | ||
| 509 | goto call_fn; | ||
| 510 | case BPF_S_LD_H_IND: /* A = *(u16 *) (skb->data+K+X) */ | ||
| 511 | jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IHALF; | ||
| 512 | offset = jit->off_load_ihalf; | ||
| 513 | goto call_fn; | ||
| 514 | case BPF_S_LD_B_IND: /* A = *(u8 *) (skb->data+K+X) */ | ||
| 515 | jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IBYTE; | ||
| 516 | offset = jit->off_load_ibyte; | ||
| 517 | goto call_fn; | ||
| 518 | case BPF_S_LDX_B_MSH: | ||
| 519 | /* X = (*(u8 *)(skb->data+K) & 0xf) << 2 */ | ||
| 520 | jit->seen |= SEEN_RET0; | ||
| 521 | if ((int) K < 0) { | ||
| 522 | /* j <ret0> */ | ||
| 523 | EMIT4_PCREL(0xa7f40000, (jit->ret0_ip - jit->prg)); | ||
| 524 | break; | ||
| 525 | } | ||
| 526 | jit->seen |= SEEN_DATAREF | SEEN_LOAD_BMSH; | ||
| 527 | offset = jit->off_load_bmsh; | ||
| 528 | goto call_fn; | ||
| 529 | case BPF_S_LD_W_LEN: /* A = skb->len; */ | ||
| 530 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4); | ||
| 531 | /* l %r5,<d(len)>(%r2) */ | ||
| 532 | EMIT4_DISP(0x58502000, offsetof(struct sk_buff, len)); | ||
| 533 | break; | ||
| 534 | case BPF_S_LDX_W_LEN: /* X = skb->len; */ | ||
| 535 | jit->seen |= SEEN_XREG; | ||
| 536 | /* l %r12,<d(len)>(%r2) */ | ||
| 537 | EMIT4_DISP(0x58c02000, offsetof(struct sk_buff, len)); | ||
| 538 | break; | ||
| 539 | case BPF_S_LD_IMM: /* A = K */ | ||
| 540 | if (K <= 16383) | ||
| 541 | /* lhi %r5,K */ | ||
| 542 | EMIT4_IMM(0xa7580000, K); | ||
| 543 | else if (test_facility(21)) | ||
| 544 | /* llilf %r5,<K> */ | ||
| 545 | EMIT6_IMM(0xc05f0000, K); | ||
| 546 | else | ||
| 547 | /* l %r5,<d(K)>(%r13) */ | ||
| 548 | EMIT4_DISP(0x5850d000, EMIT_CONST(K)); | ||
| 549 | break; | ||
| 550 | case BPF_S_LDX_IMM: /* X = K */ | ||
| 551 | jit->seen |= SEEN_XREG; | ||
| 552 | if (K <= 16383) | ||
| 553 | /* lhi %r12,<K> */ | ||
| 554 | EMIT4_IMM(0xa7c80000, K); | ||
| 555 | else if (test_facility(21)) | ||
| 556 | /* llilf %r12,<K> */ | ||
| 557 | EMIT6_IMM(0xc0cf0000, K); | ||
| 558 | else | ||
| 559 | /* l %r12,<d(K)>(%r13) */ | ||
| 560 | EMIT4_DISP(0x58c0d000, EMIT_CONST(K)); | ||
| 561 | break; | ||
| 562 | case BPF_S_LD_MEM: /* A = mem[K] */ | ||
| 563 | jit->seen |= SEEN_MEM; | ||
| 564 | /* l %r5,<K>(%r15) */ | ||
| 565 | EMIT4_DISP(0x5850f000, | ||
| 566 | (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4); | ||
| 567 | break; | ||
| 568 | case BPF_S_LDX_MEM: /* X = mem[K] */ | ||
| 569 | jit->seen |= SEEN_XREG | SEEN_MEM; | ||
| 570 | /* l %r12,<K>(%r15) */ | ||
| 571 | EMIT4_DISP(0x58c0f000, | ||
| 572 | (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4); | ||
| 573 | break; | ||
| 574 | case BPF_S_MISC_TAX: /* X = A */ | ||
| 575 | jit->seen |= SEEN_XREG; | ||
| 576 | /* lr %r12,%r5 */ | ||
| 577 | EMIT2(0x18c5); | ||
| 578 | break; | ||
| 579 | case BPF_S_MISC_TXA: /* A = X */ | ||
| 580 | jit->seen |= SEEN_XREG; | ||
| 581 | /* lr %r5,%r12 */ | ||
| 582 | EMIT2(0x185c); | ||
| 583 | break; | ||
| 584 | case BPF_S_RET_K: | ||
| 585 | if (K == 0) { | ||
| 586 | jit->seen |= SEEN_RET0; | ||
| 587 | if (last) | ||
| 588 | break; | ||
| 589 | /* j <ret0> */ | ||
| 590 | EMIT4_PCREL(0xa7f40000, jit->ret0_ip - jit->prg); | ||
| 591 | } else { | ||
| 592 | if (K <= 16383) | ||
| 593 | /* lghi %r2,K */ | ||
| 594 | EMIT4_IMM(0xa7290000, K); | ||
| 595 | else | ||
| 596 | /* llgf %r2,<K>(%r13) */ | ||
| 597 | EMIT6_DISP(0xe320d000, 0x0016, EMIT_CONST(K)); | ||
| 598 | /* j <exit> */ | ||
| 599 | if (last && !(jit->seen & SEEN_RET0)) | ||
| 600 | break; | ||
| 601 | EMIT4_PCREL(0xa7f40000, jit->exit_ip - jit->prg); | ||
| 602 | } | ||
| 603 | break; | ||
| 604 | case BPF_S_RET_A: | ||
| 605 | /* llgfr %r2,%r5 */ | ||
| 606 | EMIT4(0xb9160025); | ||
| 607 | /* j <exit> */ | ||
| 608 | EMIT4_PCREL(0xa7f40000, jit->exit_ip - jit->prg); | ||
| 609 | break; | ||
| 610 | case BPF_S_ST: /* mem[K] = A */ | ||
| 611 | jit->seen |= SEEN_MEM; | ||
| 612 | /* st %r5,<K>(%r15) */ | ||
| 613 | EMIT4_DISP(0x5050f000, | ||
| 614 | (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4); | ||
| 615 | break; | ||
| 616 | case BPF_S_STX: /* mem[K] = X : mov %ebx,off8(%rbp) */ | ||
| 617 | jit->seen |= SEEN_XREG | SEEN_MEM; | ||
| 618 | /* st %r12,<K>(%r15) */ | ||
| 619 | EMIT4_DISP(0x50c0f000, | ||
| 620 | (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4); | ||
| 621 | break; | ||
| 622 | case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */ | ||
| 623 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2); | ||
| 624 | /* lhi %r5,0 */ | ||
| 625 | EMIT4(0xa7580000); | ||
| 626 | /* icm %r5,3,<d(protocol)>(%r2) */ | ||
| 627 | EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, protocol)); | ||
| 628 | break; | ||
| 629 | case BPF_S_ANC_IFINDEX: /* if (!skb->dev) return 0; | ||
| 630 | * A = skb->dev->ifindex */ | ||
| 631 | BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4); | ||
| 632 | jit->seen |= SEEN_RET0; | ||
| 633 | /* lg %r1,<d(dev)>(%r2) */ | ||
| 634 | EMIT6_DISP(0xe3102000, 0x0004, offsetof(struct sk_buff, dev)); | ||
| 635 | /* ltgr %r1,%r1 */ | ||
| 636 | EMIT4(0xb9020011); | ||
| 637 | /* jz <ret0> */ | ||
| 638 | EMIT4_PCREL(0xa7840000, jit->ret0_ip - jit->prg); | ||
| 639 | /* l %r5,<d(ifindex)>(%r1) */ | ||
| 640 | EMIT4_DISP(0x58501000, offsetof(struct net_device, ifindex)); | ||
| 641 | break; | ||
| 642 | case BPF_S_ANC_MARK: /* A = skb->mark */ | ||
| 643 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4); | ||
| 644 | /* l %r5,<d(mark)>(%r2) */ | ||
| 645 | EMIT4_DISP(0x58502000, offsetof(struct sk_buff, mark)); | ||
| 646 | break; | ||
| 647 | case BPF_S_ANC_QUEUE: /* A = skb->queue_mapping */ | ||
| 648 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2); | ||
| 649 | /* lhi %r5,0 */ | ||
| 650 | EMIT4(0xa7580000); | ||
| 651 | /* icm %r5,3,<d(queue_mapping)>(%r2) */ | ||
| 652 | EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, queue_mapping)); | ||
| 653 | break; | ||
| 654 | case BPF_S_ANC_HATYPE: /* if (!skb->dev) return 0; | ||
| 655 | * A = skb->dev->type */ | ||
| 656 | BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, type) != 2); | ||
| 657 | jit->seen |= SEEN_RET0; | ||
| 658 | /* lg %r1,<d(dev)>(%r2) */ | ||
| 659 | EMIT6_DISP(0xe3102000, 0x0004, offsetof(struct sk_buff, dev)); | ||
| 660 | /* ltgr %r1,%r1 */ | ||
| 661 | EMIT4(0xb9020011); | ||
| 662 | /* jz <ret0> */ | ||
| 663 | EMIT4_PCREL(0xa7840000, jit->ret0_ip - jit->prg); | ||
| 664 | /* lhi %r5,0 */ | ||
| 665 | EMIT4(0xa7580000); | ||
| 666 | /* icm %r5,3,<d(type)>(%r1) */ | ||
| 667 | EMIT4_DISP(0xbf531000, offsetof(struct net_device, type)); | ||
| 668 | break; | ||
| 669 | case BPF_S_ANC_RXHASH: /* A = skb->rxhash */ | ||
| 670 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4); | ||
| 671 | /* l %r5,<d(rxhash)>(%r2) */ | ||
| 672 | EMIT4_DISP(0x58502000, offsetof(struct sk_buff, rxhash)); | ||
| 673 | break; | ||
| 674 | case BPF_S_ANC_CPU: /* A = smp_processor_id() */ | ||
| 675 | #ifdef CONFIG_SMP | ||
| 676 | /* l %r5,<d(cpu_nr)> */ | ||
| 677 | EMIT4_DISP(0x58500000, offsetof(struct _lowcore, cpu_nr)); | ||
| 678 | #else | ||
| 679 | /* lhi %r5,0 */ | ||
| 680 | EMIT4(0xa7580000); | ||
| 681 | #endif | ||
| 682 | break; | ||
| 683 | default: /* too complex, give up */ | ||
| 684 | goto out; | ||
| 685 | } | ||
| 686 | addrs[i] = jit->prg - jit->start; | ||
| 687 | return 0; | ||
| 688 | out: | ||
| 689 | return -1; | ||
| 690 | } | ||
| 691 | |||
| 692 | void bpf_jit_compile(struct sk_filter *fp) | ||
| 693 | { | ||
| 694 | unsigned long size, prg_len, lit_len; | ||
| 695 | struct bpf_jit jit, cjit; | ||
| 696 | unsigned int *addrs; | ||
| 697 | int pass, i; | ||
| 698 | |||
| 699 | if (!bpf_jit_enable) | ||
| 700 | return; | ||
| 701 | addrs = kmalloc(fp->len * sizeof(*addrs), GFP_KERNEL); | ||
| 702 | if (addrs == NULL) | ||
| 703 | return; | ||
| 704 | memset(addrs, 0, fp->len * sizeof(*addrs)); | ||
| 705 | memset(&jit, 0, sizeof(cjit)); | ||
| 706 | memset(&cjit, 0, sizeof(cjit)); | ||
| 707 | |||
| 708 | for (pass = 0; pass < 10; pass++) { | ||
| 709 | jit.prg = jit.start; | ||
| 710 | jit.lit = jit.mid; | ||
| 711 | |||
| 712 | bpf_jit_prologue(&jit); | ||
| 713 | bpf_jit_noleaks(&jit, fp->insns); | ||
| 714 | for (i = 0; i < fp->len; i++) { | ||
| 715 | if (bpf_jit_insn(&jit, fp->insns + i, addrs, i, | ||
| 716 | i == fp->len - 1)) | ||
| 717 | goto out; | ||
| 718 | } | ||
| 719 | bpf_jit_epilogue(&jit); | ||
| 720 | if (jit.start) { | ||
| 721 | WARN_ON(jit.prg > cjit.prg || jit.lit > cjit.lit); | ||
| 722 | if (memcmp(&jit, &cjit, sizeof(jit)) == 0) | ||
| 723 | break; | ||
| 724 | } else if (jit.prg == cjit.prg && jit.lit == cjit.lit) { | ||
| 725 | prg_len = jit.prg - jit.start; | ||
| 726 | lit_len = jit.lit - jit.mid; | ||
| 727 | size = max_t(unsigned long, prg_len + lit_len, | ||
| 728 | sizeof(struct work_struct)); | ||
| 729 | if (size >= BPF_SIZE_MAX) | ||
| 730 | goto out; | ||
| 731 | jit.start = module_alloc(size); | ||
| 732 | if (!jit.start) | ||
| 733 | goto out; | ||
| 734 | jit.prg = jit.mid = jit.start + prg_len; | ||
| 735 | jit.lit = jit.end = jit.start + prg_len + lit_len; | ||
| 736 | jit.base_ip += (unsigned long) jit.start; | ||
| 737 | jit.exit_ip += (unsigned long) jit.start; | ||
| 738 | jit.ret0_ip += (unsigned long) jit.start; | ||
| 739 | } | ||
| 740 | cjit = jit; | ||
| 741 | } | ||
| 742 | if (bpf_jit_enable > 1) { | ||
| 743 | pr_err("flen=%d proglen=%lu pass=%d image=%p\n", | ||
| 744 | fp->len, jit.end - jit.start, pass, jit.start); | ||
| 745 | if (jit.start) { | ||
| 746 | printk(KERN_ERR "JIT code:\n"); | ||
| 747 | print_fn_code(jit.start, jit.mid - jit.start); | ||
| 748 | print_hex_dump(KERN_ERR, "JIT literals:\n", | ||
| 749 | DUMP_PREFIX_ADDRESS, 16, 1, | ||
| 750 | jit.mid, jit.end - jit.mid, false); | ||
| 751 | } | ||
| 752 | } | ||
| 753 | if (jit.start) | ||
| 754 | fp->bpf_func = (void *) jit.start; | ||
| 755 | out: | ||
| 756 | kfree(addrs); | ||
| 757 | } | ||
| 758 | |||
| 759 | static void jit_free_defer(struct work_struct *arg) | ||
| 760 | { | ||
| 761 | module_free(NULL, arg); | ||
| 762 | } | ||
| 763 | |||
| 764 | /* run from softirq, we must use a work_struct to call | ||
| 765 | * module_free() from process context | ||
| 766 | */ | ||
| 767 | void bpf_jit_free(struct sk_filter *fp) | ||
| 768 | { | ||
| 769 | struct work_struct *work; | ||
| 770 | |||
| 771 | if (fp->bpf_func == sk_run_filter) | ||
| 772 | return; | ||
| 773 | work = (struct work_struct *)fp->bpf_func; | ||
| 774 | INIT_WORK(work, jit_free_defer); | ||
| 775 | schedule_work(work); | ||
| 776 | } | ||
diff --git a/block/partitions/ibm.c b/block/partitions/ibm.c index 1104acac780b..47a61474e795 100644 --- a/block/partitions/ibm.c +++ b/block/partitions/ibm.c | |||
| @@ -1,9 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * File...........: linux/fs/partitions/ibm.c | ||
| 3 | * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> | 2 | * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> |
| 4 | * Volker Sameske <sameske@de.ibm.com> | 3 | * Volker Sameske <sameske@de.ibm.com> |
| 5 | * Bugreports.to..: <Linux390@de.ibm.com> | 4 | * Bugreports.to..: <Linux390@de.ibm.com> |
| 6 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 | 5 | * Copyright IBM Corp. 1999, 2012 |
| 7 | */ | 6 | */ |
| 8 | 7 | ||
| 9 | #include <linux/buffer_head.h> | 8 | #include <linux/buffer_head.h> |
| @@ -17,17 +16,23 @@ | |||
| 17 | #include "check.h" | 16 | #include "check.h" |
| 18 | #include "ibm.h" | 17 | #include "ibm.h" |
| 19 | 18 | ||
| 19 | |||
| 20 | union label_t { | ||
| 21 | struct vtoc_volume_label_cdl vol; | ||
| 22 | struct vtoc_volume_label_ldl lnx; | ||
| 23 | struct vtoc_cms_label cms; | ||
| 24 | }; | ||
| 25 | |||
| 20 | /* | 26 | /* |
| 21 | * compute the block number from a | 27 | * compute the block number from a |
| 22 | * cyl-cyl-head-head structure | 28 | * cyl-cyl-head-head structure |
| 23 | */ | 29 | */ |
| 24 | static sector_t | 30 | static sector_t cchh2blk(struct vtoc_cchh *ptr, struct hd_geometry *geo) |
| 25 | cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) { | 31 | { |
| 26 | |||
| 27 | sector_t cyl; | 32 | sector_t cyl; |
| 28 | __u16 head; | 33 | __u16 head; |
| 29 | 34 | ||
| 30 | /*decode cylinder and heads for large volumes */ | 35 | /* decode cylinder and heads for large volumes */ |
| 31 | cyl = ptr->hh & 0xFFF0; | 36 | cyl = ptr->hh & 0xFFF0; |
| 32 | cyl <<= 12; | 37 | cyl <<= 12; |
| 33 | cyl |= ptr->cc; | 38 | cyl |= ptr->cc; |
| @@ -40,13 +45,12 @@ cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) { | |||
| 40 | * compute the block number from a | 45 | * compute the block number from a |
| 41 | * cyl-cyl-head-head-block structure | 46 | * cyl-cyl-head-head-block structure |
| 42 | */ | 47 | */ |
| 43 | static sector_t | 48 | static sector_t cchhb2blk(struct vtoc_cchhb *ptr, struct hd_geometry *geo) |
| 44 | cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) { | 49 | { |
| 45 | |||
| 46 | sector_t cyl; | 50 | sector_t cyl; |
| 47 | __u16 head; | 51 | __u16 head; |
| 48 | 52 | ||
| 49 | /*decode cylinder and heads for large volumes */ | 53 | /* decode cylinder and heads for large volumes */ |
| 50 | cyl = ptr->hh & 0xFFF0; | 54 | cyl = ptr->hh & 0xFFF0; |
| 51 | cyl <<= 12; | 55 | cyl <<= 12; |
| 52 | cyl |= ptr->cc; | 56 | cyl |= ptr->cc; |
| @@ -56,26 +60,243 @@ cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) { | |||
| 56 | ptr->b; | 60 | ptr->b; |
| 57 | } | 61 | } |
| 58 | 62 | ||
| 63 | static int find_label(struct parsed_partitions *state, | ||
| 64 | dasd_information2_t *info, | ||
| 65 | struct hd_geometry *geo, | ||
| 66 | int blocksize, | ||
| 67 | sector_t *labelsect, | ||
| 68 | char name[], | ||
| 69 | char type[], | ||
| 70 | union label_t *label) | ||
| 71 | { | ||
| 72 | Sector sect; | ||
| 73 | unsigned char *data; | ||
| 74 | sector_t testsect[3]; | ||
| 75 | unsigned char temp[5]; | ||
| 76 | int found = 0; | ||
| 77 | int i, testcount; | ||
| 78 | |||
| 79 | /* There a three places where we may find a valid label: | ||
| 80 | * - on an ECKD disk it's block 2 | ||
| 81 | * - on an FBA disk it's block 1 | ||
| 82 | * - on an CMS formatted FBA disk it is sector 1, even if the block size | ||
| 83 | * is larger than 512 bytes (possible if the DIAG discipline is used) | ||
| 84 | * If we have a valid info structure, then we know exactly which case we | ||
| 85 | * have, otherwise we just search through all possebilities. | ||
| 86 | */ | ||
| 87 | if (info) { | ||
| 88 | if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) || | ||
| 89 | (info->cu_type == 0x3880 && info->dev_type == 0x3370)) | ||
| 90 | testsect[0] = info->label_block; | ||
| 91 | else | ||
| 92 | testsect[0] = info->label_block * (blocksize >> 9); | ||
| 93 | testcount = 1; | ||
| 94 | } else { | ||
| 95 | testsect[0] = 1; | ||
| 96 | testsect[1] = (blocksize >> 9); | ||
| 97 | testsect[2] = 2 * (blocksize >> 9); | ||
| 98 | testcount = 3; | ||
| 99 | } | ||
| 100 | for (i = 0; i < testcount; ++i) { | ||
| 101 | data = read_part_sector(state, testsect[i], §); | ||
| 102 | if (data == NULL) | ||
| 103 | continue; | ||
| 104 | memcpy(label, data, sizeof(*label)); | ||
| 105 | memcpy(temp, data, 4); | ||
| 106 | temp[4] = 0; | ||
| 107 | EBCASC(temp, 4); | ||
| 108 | put_dev_sector(sect); | ||
| 109 | if (!strcmp(temp, "VOL1") || | ||
| 110 | !strcmp(temp, "LNX1") || | ||
| 111 | !strcmp(temp, "CMS1")) { | ||
| 112 | if (!strcmp(temp, "VOL1")) { | ||
| 113 | strncpy(type, label->vol.vollbl, 4); | ||
| 114 | strncpy(name, label->vol.volid, 6); | ||
| 115 | } else { | ||
| 116 | strncpy(type, label->lnx.vollbl, 4); | ||
| 117 | strncpy(name, label->lnx.volid, 6); | ||
| 118 | } | ||
| 119 | EBCASC(type, 4); | ||
| 120 | EBCASC(name, 6); | ||
| 121 | *labelsect = testsect[i]; | ||
| 122 | found = 1; | ||
| 123 | break; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | if (!found) | ||
| 127 | memset(label, 0, sizeof(*label)); | ||
| 128 | |||
| 129 | return found; | ||
| 130 | } | ||
| 131 | |||
| 132 | static int find_vol1_partitions(struct parsed_partitions *state, | ||
| 133 | struct hd_geometry *geo, | ||
| 134 | int blocksize, | ||
| 135 | char name[], | ||
| 136 | union label_t *label) | ||
| 137 | { | ||
| 138 | sector_t blk; | ||
| 139 | int counter; | ||
| 140 | char tmp[64]; | ||
| 141 | Sector sect; | ||
| 142 | unsigned char *data; | ||
| 143 | loff_t offset, size; | ||
| 144 | struct vtoc_format1_label f1; | ||
| 145 | int secperblk; | ||
| 146 | |||
| 147 | snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name); | ||
| 148 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 149 | /* | ||
| 150 | * get start of VTOC from the disk label and then search for format1 | ||
| 151 | * and format8 labels | ||
| 152 | */ | ||
| 153 | secperblk = blocksize >> 9; | ||
| 154 | blk = cchhb2blk(&label->vol.vtoc, geo) + 1; | ||
| 155 | counter = 0; | ||
| 156 | data = read_part_sector(state, blk * secperblk, §); | ||
| 157 | while (data != NULL) { | ||
| 158 | memcpy(&f1, data, sizeof(struct vtoc_format1_label)); | ||
| 159 | put_dev_sector(sect); | ||
| 160 | /* skip FMT4 / FMT5 / FMT7 labels */ | ||
| 161 | if (f1.DS1FMTID == _ascebc['4'] | ||
| 162 | || f1.DS1FMTID == _ascebc['5'] | ||
| 163 | || f1.DS1FMTID == _ascebc['7'] | ||
| 164 | || f1.DS1FMTID == _ascebc['9']) { | ||
| 165 | blk++; | ||
| 166 | data = read_part_sector(state, blk * secperblk, §); | ||
| 167 | continue; | ||
| 168 | } | ||
| 169 | /* only FMT1 and 8 labels valid at this point */ | ||
| 170 | if (f1.DS1FMTID != _ascebc['1'] && | ||
| 171 | f1.DS1FMTID != _ascebc['8']) | ||
| 172 | break; | ||
| 173 | /* OK, we got valid partition data */ | ||
| 174 | offset = cchh2blk(&f1.DS1EXT1.llimit, geo); | ||
| 175 | size = cchh2blk(&f1.DS1EXT1.ulimit, geo) - | ||
| 176 | offset + geo->sectors; | ||
| 177 | offset *= secperblk; | ||
| 178 | size *= secperblk; | ||
| 179 | if (counter >= state->limit) | ||
| 180 | break; | ||
| 181 | put_partition(state, counter + 1, offset, size); | ||
| 182 | counter++; | ||
| 183 | blk++; | ||
| 184 | data = read_part_sector(state, blk * secperblk, §); | ||
| 185 | } | ||
| 186 | strlcat(state->pp_buf, "\n", PAGE_SIZE); | ||
| 187 | |||
| 188 | if (!data) | ||
| 189 | return -1; | ||
| 190 | |||
| 191 | return 1; | ||
| 192 | } | ||
| 193 | |||
| 194 | static int find_lnx1_partitions(struct parsed_partitions *state, | ||
| 195 | struct hd_geometry *geo, | ||
| 196 | int blocksize, | ||
| 197 | char name[], | ||
| 198 | union label_t *label, | ||
| 199 | sector_t labelsect, | ||
| 200 | loff_t i_size, | ||
| 201 | dasd_information2_t *info) | ||
| 202 | { | ||
| 203 | loff_t offset, geo_size, size; | ||
| 204 | char tmp[64]; | ||
| 205 | int secperblk; | ||
| 206 | |||
| 207 | snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name); | ||
| 208 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 209 | secperblk = blocksize >> 9; | ||
| 210 | if (label->lnx.ldl_version == 0xf2) { | ||
| 211 | size = label->lnx.formatted_blocks * secperblk; | ||
| 212 | } else { | ||
| 213 | /* | ||
| 214 | * Formated w/o large volume support. If the sanity check | ||
| 215 | * 'size based on geo == size based on i_size' is true, then | ||
| 216 | * we can safely assume that we know the formatted size of | ||
| 217 | * the disk, otherwise we need additional information | ||
| 218 | * that we can only get from a real DASD device. | ||
| 219 | */ | ||
| 220 | geo_size = geo->cylinders * geo->heads | ||
| 221 | * geo->sectors * secperblk; | ||
| 222 | size = i_size >> 9; | ||
| 223 | if (size != geo_size) { | ||
| 224 | if (!info) { | ||
| 225 | strlcat(state->pp_buf, "\n", PAGE_SIZE); | ||
| 226 | return 1; | ||
| 227 | } | ||
| 228 | if (!strcmp(info->type, "ECKD")) | ||
| 229 | if (geo_size < size) | ||
| 230 | size = geo_size; | ||
| 231 | /* else keep size based on i_size */ | ||
| 232 | } | ||
| 233 | } | ||
| 234 | /* first and only partition starts in the first block after the label */ | ||
| 235 | offset = labelsect + secperblk; | ||
| 236 | put_partition(state, 1, offset, size - offset); | ||
| 237 | strlcat(state->pp_buf, "\n", PAGE_SIZE); | ||
| 238 | return 1; | ||
| 239 | } | ||
| 240 | |||
| 241 | static int find_cms1_partitions(struct parsed_partitions *state, | ||
| 242 | struct hd_geometry *geo, | ||
| 243 | int blocksize, | ||
| 244 | char name[], | ||
| 245 | union label_t *label, | ||
| 246 | sector_t labelsect) | ||
| 247 | { | ||
| 248 | loff_t offset, size; | ||
| 249 | char tmp[64]; | ||
| 250 | int secperblk; | ||
| 251 | |||
| 252 | /* | ||
| 253 | * VM style CMS1 labeled disk | ||
| 254 | */ | ||
| 255 | blocksize = label->cms.block_size; | ||
| 256 | secperblk = blocksize >> 9; | ||
| 257 | if (label->cms.disk_offset != 0) { | ||
| 258 | snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name); | ||
| 259 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 260 | /* disk is reserved minidisk */ | ||
| 261 | offset = label->cms.disk_offset * secperblk; | ||
| 262 | size = (label->cms.block_count - 1) * secperblk; | ||
| 263 | } else { | ||
| 264 | snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name); | ||
| 265 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 266 | /* | ||
| 267 | * Special case for FBA devices: | ||
| 268 | * If an FBA device is CMS formatted with blocksize > 512 byte | ||
| 269 | * and the DIAG discipline is used, then the CMS label is found | ||
| 270 | * in sector 1 instead of block 1. However, the partition is | ||
| 271 | * still supposed to start in block 2. | ||
| 272 | */ | ||
| 273 | if (labelsect == 1) | ||
| 274 | offset = 2 * secperblk; | ||
| 275 | else | ||
| 276 | offset = labelsect + secperblk; | ||
| 277 | size = label->cms.block_count * secperblk; | ||
| 278 | } | ||
| 279 | |||
| 280 | put_partition(state, 1, offset, size-offset); | ||
| 281 | strlcat(state->pp_buf, "\n", PAGE_SIZE); | ||
| 282 | return 1; | ||
| 283 | } | ||
| 284 | |||
| 285 | |||
| 59 | /* | 286 | /* |
| 287 | * This is the main function, called by check.c | ||
| 60 | */ | 288 | */ |
| 61 | int ibm_partition(struct parsed_partitions *state) | 289 | int ibm_partition(struct parsed_partitions *state) |
| 62 | { | 290 | { |
| 63 | struct block_device *bdev = state->bdev; | 291 | struct block_device *bdev = state->bdev; |
| 64 | int blocksize, res; | 292 | int blocksize, res; |
| 65 | loff_t i_size, offset, size, fmt_size; | 293 | loff_t i_size, offset, size; |
| 66 | dasd_information2_t *info; | 294 | dasd_information2_t *info; |
| 67 | struct hd_geometry *geo; | 295 | struct hd_geometry *geo; |
| 68 | char type[5] = {0,}; | 296 | char type[5] = {0,}; |
| 69 | char name[7] = {0,}; | 297 | char name[7] = {0,}; |
| 70 | union label_t { | ||
| 71 | struct vtoc_volume_label_cdl vol; | ||
| 72 | struct vtoc_volume_label_ldl lnx; | ||
| 73 | struct vtoc_cms_label cms; | ||
| 74 | } *label; | ||
| 75 | unsigned char *data; | ||
| 76 | Sector sect; | ||
| 77 | sector_t labelsect; | 298 | sector_t labelsect; |
| 78 | char tmp[64]; | 299 | union label_t *label; |
| 79 | 300 | ||
| 80 | res = 0; | 301 | res = 0; |
| 81 | blocksize = bdev_logical_block_size(bdev); | 302 | blocksize = bdev_logical_block_size(bdev); |
| @@ -84,7 +305,6 @@ int ibm_partition(struct parsed_partitions *state) | |||
| 84 | i_size = i_size_read(bdev->bd_inode); | 305 | i_size = i_size_read(bdev->bd_inode); |
| 85 | if (i_size == 0) | 306 | if (i_size == 0) |
| 86 | goto out_exit; | 307 | goto out_exit; |
| 87 | |||
| 88 | info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL); | 308 | info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL); |
| 89 | if (info == NULL) | 309 | if (info == NULL) |
| 90 | goto out_exit; | 310 | goto out_exit; |
| @@ -94,176 +314,45 @@ int ibm_partition(struct parsed_partitions *state) | |||
| 94 | label = kmalloc(sizeof(union label_t), GFP_KERNEL); | 314 | label = kmalloc(sizeof(union label_t), GFP_KERNEL); |
| 95 | if (label == NULL) | 315 | if (label == NULL) |
| 96 | goto out_nolab; | 316 | goto out_nolab; |
| 97 | 317 | if (ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0) | |
| 98 | if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0 || | ||
| 99 | ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0) | ||
| 100 | goto out_freeall; | 318 | goto out_freeall; |
| 101 | 319 | if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0) { | |
| 102 | /* | 320 | kfree(info); |
| 103 | * Special case for FBA disks: label sector does not depend on | 321 | info = NULL; |
| 104 | * blocksize. | ||
| 105 | */ | ||
| 106 | if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) || | ||
| 107 | (info->cu_type == 0x3880 && info->dev_type == 0x3370)) | ||
| 108 | labelsect = info->label_block; | ||
| 109 | else | ||
| 110 | labelsect = info->label_block * (blocksize >> 9); | ||
| 111 | |||
| 112 | /* | ||
| 113 | * Get volume label, extract name and type. | ||
| 114 | */ | ||
| 115 | data = read_part_sector(state, labelsect, §); | ||
| 116 | if (data == NULL) | ||
| 117 | goto out_readerr; | ||
| 118 | |||
| 119 | memcpy(label, data, sizeof(union label_t)); | ||
| 120 | put_dev_sector(sect); | ||
| 121 | |||
| 122 | if ((!info->FBA_layout) && (!strcmp(info->type, "ECKD"))) { | ||
| 123 | strncpy(type, label->vol.vollbl, 4); | ||
| 124 | strncpy(name, label->vol.volid, 6); | ||
| 125 | } else { | ||
| 126 | strncpy(type, label->lnx.vollbl, 4); | ||
| 127 | strncpy(name, label->lnx.volid, 6); | ||
| 128 | } | 322 | } |
| 129 | EBCASC(type, 4); | ||
| 130 | EBCASC(name, 6); | ||
| 131 | |||
| 132 | res = 1; | ||
| 133 | 323 | ||
| 134 | /* | 324 | if (find_label(state, info, geo, blocksize, &labelsect, name, type, |
| 135 | * Three different formats: LDL, CDL and unformated disk | 325 | label)) { |
| 136 | * | 326 | if (!strncmp(type, "VOL1", 4)) { |
| 137 | * identified by info->format | 327 | res = find_vol1_partitions(state, geo, blocksize, name, |
| 138 | * | 328 | label); |
| 139 | * unformated disks we do not have to care about | 329 | } else if (!strncmp(type, "LNX1", 4)) { |
| 140 | */ | 330 | res = find_lnx1_partitions(state, geo, blocksize, name, |
| 141 | if (info->format == DASD_FORMAT_LDL) { | 331 | label, labelsect, i_size, |
| 142 | if (strncmp(type, "CMS1", 4) == 0) { | 332 | info); |
| 143 | /* | 333 | } else if (!strncmp(type, "CMS1", 4)) { |
| 144 | * VM style CMS1 labeled disk | 334 | res = find_cms1_partitions(state, geo, blocksize, name, |
| 145 | */ | 335 | label, labelsect); |
| 146 | blocksize = label->cms.block_size; | ||
| 147 | if (label->cms.disk_offset != 0) { | ||
| 148 | snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name); | ||
| 149 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 150 | /* disk is reserved minidisk */ | ||
| 151 | offset = label->cms.disk_offset; | ||
| 152 | size = (label->cms.block_count - 1) | ||
| 153 | * (blocksize >> 9); | ||
| 154 | } else { | ||
| 155 | snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name); | ||
| 156 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 157 | offset = (info->label_block + 1); | ||
| 158 | size = label->cms.block_count | ||
| 159 | * (blocksize >> 9); | ||
| 160 | } | ||
| 161 | put_partition(state, 1, offset*(blocksize >> 9), | ||
| 162 | size-offset*(blocksize >> 9)); | ||
| 163 | } else { | ||
| 164 | if (strncmp(type, "LNX1", 4) == 0) { | ||
| 165 | snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name); | ||
| 166 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 167 | if (label->lnx.ldl_version == 0xf2) { | ||
| 168 | fmt_size = label->lnx.formatted_blocks | ||
| 169 | * (blocksize >> 9); | ||
| 170 | } else if (!strcmp(info->type, "ECKD")) { | ||
| 171 | /* formated w/o large volume support */ | ||
| 172 | fmt_size = geo->cylinders * geo->heads | ||
| 173 | * geo->sectors * (blocksize >> 9); | ||
| 174 | } else { | ||
| 175 | /* old label and no usable disk geometry | ||
| 176 | * (e.g. DIAG) */ | ||
| 177 | fmt_size = i_size >> 9; | ||
| 178 | } | ||
| 179 | size = i_size >> 9; | ||
| 180 | if (fmt_size < size) | ||
| 181 | size = fmt_size; | ||
| 182 | offset = (info->label_block + 1); | ||
| 183 | } else { | ||
| 184 | /* unlabeled disk */ | ||
| 185 | strlcat(state->pp_buf, "(nonl)", PAGE_SIZE); | ||
| 186 | size = i_size >> 9; | ||
| 187 | offset = (info->label_block + 1); | ||
| 188 | } | ||
| 189 | put_partition(state, 1, offset*(blocksize >> 9), | ||
| 190 | size-offset*(blocksize >> 9)); | ||
| 191 | } | 336 | } |
| 192 | } else if (info->format == DASD_FORMAT_CDL) { | 337 | } else if (info) { |
| 193 | /* | ||
| 194 | * New style CDL formatted disk | ||
| 195 | */ | ||
| 196 | sector_t blk; | ||
| 197 | int counter; | ||
| 198 | |||
| 199 | /* | 338 | /* |
| 200 | * check if VOL1 label is available | 339 | * ugly but needed for backward compatibility: |
| 201 | * if not, something is wrong, skipping partition detection | 340 | * If the block device is a DASD (i.e. BIODASDINFO2 works), |
| 341 | * then we claim it in any case, even though it has no valid | ||
| 342 | * label. If it has the LDL format, then we simply define a | ||
| 343 | * partition as if it had an LNX1 label. | ||
| 202 | */ | 344 | */ |
| 203 | if (strncmp(type, "VOL1", 4) == 0) { | 345 | res = 1; |
| 204 | snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name); | 346 | if (info->format == DASD_FORMAT_LDL) { |
| 205 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | 347 | strlcat(state->pp_buf, "(nonl)", PAGE_SIZE); |
| 206 | /* | 348 | size = i_size >> 9; |
| 207 | * get block number and read then go through format1 | 349 | offset = (info->label_block + 1) * (blocksize >> 9); |
| 208 | * labels | 350 | put_partition(state, 1, offset, size-offset); |
| 209 | */ | 351 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 210 | blk = cchhb2blk(&label->vol.vtoc, geo) + 1; | 352 | } |
| 211 | counter = 0; | 353 | } else |
| 212 | data = read_part_sector(state, blk * (blocksize/512), | 354 | res = 0; |
| 213 | §); | ||
| 214 | while (data != NULL) { | ||
| 215 | struct vtoc_format1_label f1; | ||
| 216 | |||
| 217 | memcpy(&f1, data, | ||
| 218 | sizeof(struct vtoc_format1_label)); | ||
| 219 | put_dev_sector(sect); | ||
| 220 | |||
| 221 | /* skip FMT4 / FMT5 / FMT7 labels */ | ||
| 222 | if (f1.DS1FMTID == _ascebc['4'] | ||
| 223 | || f1.DS1FMTID == _ascebc['5'] | ||
| 224 | || f1.DS1FMTID == _ascebc['7'] | ||
| 225 | || f1.DS1FMTID == _ascebc['9']) { | ||
| 226 | blk++; | ||
| 227 | data = read_part_sector(state, | ||
| 228 | blk * (blocksize/512), §); | ||
| 229 | continue; | ||
| 230 | } | ||
| 231 | |||
| 232 | /* only FMT1 and 8 labels valid at this point */ | ||
| 233 | if (f1.DS1FMTID != _ascebc['1'] && | ||
| 234 | f1.DS1FMTID != _ascebc['8']) | ||
| 235 | break; | ||
| 236 | |||
| 237 | /* OK, we got valid partition data */ | ||
| 238 | offset = cchh2blk(&f1.DS1EXT1.llimit, geo); | ||
| 239 | size = cchh2blk(&f1.DS1EXT1.ulimit, geo) - | ||
| 240 | offset + geo->sectors; | ||
| 241 | if (counter >= state->limit) | ||
| 242 | break; | ||
| 243 | put_partition(state, counter + 1, | ||
| 244 | offset * (blocksize >> 9), | ||
| 245 | size * (blocksize >> 9)); | ||
| 246 | counter++; | ||
| 247 | blk++; | ||
| 248 | data = read_part_sector(state, | ||
| 249 | blk * (blocksize/512), §); | ||
| 250 | } | ||
| 251 | |||
| 252 | if (!data) | ||
| 253 | /* Are we not supposed to report this ? */ | ||
| 254 | goto out_readerr; | ||
| 255 | } else | ||
| 256 | printk(KERN_INFO "Expected Label VOL1 not " | ||
| 257 | "found, treating as CDL formated Disk"); | ||
| 258 | |||
| 259 | } | ||
| 260 | |||
| 261 | strlcat(state->pp_buf, "\n", PAGE_SIZE); | ||
| 262 | goto out_freeall; | ||
| 263 | |||
| 264 | 355 | ||
| 265 | out_readerr: | ||
| 266 | res = -1; | ||
| 267 | out_freeall: | 356 | out_freeall: |
| 268 | kfree(label); | 357 | kfree(label); |
| 269 | out_nolab: | 358 | out_nolab: |
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index 8e477bb1f3f6..4a3b62326183 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig | |||
| @@ -70,3 +70,21 @@ config DASD_EER | |||
| 70 | This driver provides a character device interface to the | 70 | This driver provides a character device interface to the |
| 71 | DASD extended error reporting. This is only needed if you want to | 71 | DASD extended error reporting. This is only needed if you want to |
| 72 | use applications written for the EER facility. | 72 | use applications written for the EER facility. |
| 73 | |||
| 74 | config SCM_BLOCK | ||
| 75 | def_tristate m | ||
| 76 | prompt "Support for Storage Class Memory" | ||
| 77 | depends on S390 && BLOCK && EADM_SCH && SCM_BUS | ||
| 78 | help | ||
| 79 | Block device driver for Storage Class Memory (SCM). This driver | ||
| 80 | provides a block device interface for each available SCM increment. | ||
| 81 | |||
| 82 | To compile this driver as a module, choose M here: the | ||
| 83 | module will be called scm_block. | ||
| 84 | |||
| 85 | config SCM_BLOCK_CLUSTER_WRITE | ||
| 86 | def_bool y | ||
| 87 | prompt "SCM force cluster writes" | ||
| 88 | depends on SCM_BLOCK | ||
| 89 | help | ||
| 90 | Force writes to Storage Class Memory (SCM) to be in done in clusters. | ||
diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile index 0a89e080b389..c2f4e673e031 100644 --- a/drivers/s390/block/Makefile +++ b/drivers/s390/block/Makefile | |||
| @@ -17,3 +17,9 @@ obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o | |||
| 17 | obj-$(CONFIG_DASD_FBA) += dasd_fba_mod.o | 17 | obj-$(CONFIG_DASD_FBA) += dasd_fba_mod.o |
| 18 | obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o | 18 | obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o |
| 19 | obj-$(CONFIG_DCSSBLK) += dcssblk.o | 19 | obj-$(CONFIG_DCSSBLK) += dcssblk.o |
| 20 | |||
| 21 | scm_block-objs := scm_drv.o scm_blk.o | ||
| 22 | ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
| 23 | scm_block-objs += scm_blk_cluster.o | ||
| 24 | endif | ||
| 25 | obj-$(CONFIG_SCM_BLOCK) += scm_block.o | ||
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index c48c72abbefc..108332b44d98 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/compat.h> | 20 | #include <linux/compat.h> |
| 21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
| 22 | 22 | ||
| 23 | #include <asm/css_chars.h> | ||
| 23 | #include <asm/debug.h> | 24 | #include <asm/debug.h> |
| 24 | #include <asm/idals.h> | 25 | #include <asm/idals.h> |
| 25 | #include <asm/ebcdic.h> | 26 | #include <asm/ebcdic.h> |
| @@ -31,8 +32,6 @@ | |||
| 31 | 32 | ||
| 32 | #include "dasd_int.h" | 33 | #include "dasd_int.h" |
| 33 | #include "dasd_eckd.h" | 34 | #include "dasd_eckd.h" |
| 34 | #include "../cio/chsc.h" | ||
| 35 | |||
| 36 | 35 | ||
| 37 | #ifdef PRINTK_HEADER | 36 | #ifdef PRINTK_HEADER |
| 38 | #undef PRINTK_HEADER | 37 | #undef PRINTK_HEADER |
| @@ -140,6 +139,10 @@ dasd_eckd_set_online(struct ccw_device *cdev) | |||
| 140 | static const int sizes_trk0[] = { 28, 148, 84 }; | 139 | static const int sizes_trk0[] = { 28, 148, 84 }; |
| 141 | #define LABEL_SIZE 140 | 140 | #define LABEL_SIZE 140 |
| 142 | 141 | ||
| 142 | /* head and record addresses of count_area read in analysis ccw */ | ||
| 143 | static const int count_area_head[] = { 0, 0, 0, 0, 2 }; | ||
| 144 | static const int count_area_rec[] = { 1, 2, 3, 4, 1 }; | ||
| 145 | |||
| 143 | static inline unsigned int | 146 | static inline unsigned int |
| 144 | round_up_multiple(unsigned int no, unsigned int mult) | 147 | round_up_multiple(unsigned int no, unsigned int mult) |
| 145 | { | 148 | { |
| @@ -212,7 +215,7 @@ check_XRC (struct ccw1 *de_ccw, | |||
| 212 | 215 | ||
| 213 | rc = get_sync_clock(&data->ep_sys_time); | 216 | rc = get_sync_clock(&data->ep_sys_time); |
| 214 | /* Ignore return code if sync clock is switched off. */ | 217 | /* Ignore return code if sync clock is switched off. */ |
| 215 | if (rc == -ENOSYS || rc == -EACCES) | 218 | if (rc == -EOPNOTSUPP || rc == -EACCES) |
| 216 | rc = 0; | 219 | rc = 0; |
| 217 | 220 | ||
| 218 | de_ccw->count = sizeof(struct DE_eckd_data); | 221 | de_ccw->count = sizeof(struct DE_eckd_data); |
| @@ -323,7 +326,7 @@ static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata, | |||
| 323 | 326 | ||
| 324 | rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time); | 327 | rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time); |
| 325 | /* Ignore return code if sync clock is switched off. */ | 328 | /* Ignore return code if sync clock is switched off. */ |
| 326 | if (rc == -ENOSYS || rc == -EACCES) | 329 | if (rc == -EOPNOTSUPP || rc == -EACCES) |
| 327 | rc = 0; | 330 | rc = 0; |
| 328 | return rc; | 331 | return rc; |
| 329 | } | 332 | } |
| @@ -1940,7 +1943,10 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
| 1940 | count_area = NULL; | 1943 | count_area = NULL; |
| 1941 | for (i = 0; i < 3; i++) { | 1944 | for (i = 0; i < 3; i++) { |
| 1942 | if (private->count_area[i].kl != 4 || | 1945 | if (private->count_area[i].kl != 4 || |
| 1943 | private->count_area[i].dl != dasd_eckd_cdl_reclen(i) - 4) { | 1946 | private->count_area[i].dl != dasd_eckd_cdl_reclen(i) - 4 || |
| 1947 | private->count_area[i].cyl != 0 || | ||
| 1948 | private->count_area[i].head != count_area_head[i] || | ||
| 1949 | private->count_area[i].record != count_area_rec[i]) { | ||
| 1944 | private->uses_cdl = 0; | 1950 | private->uses_cdl = 0; |
| 1945 | break; | 1951 | break; |
| 1946 | } | 1952 | } |
| @@ -1952,7 +1958,10 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
| 1952 | for (i = 0; i < 5; i++) { | 1958 | for (i = 0; i < 5; i++) { |
| 1953 | if ((private->count_area[i].kl != 0) || | 1959 | if ((private->count_area[i].kl != 0) || |
| 1954 | (private->count_area[i].dl != | 1960 | (private->count_area[i].dl != |
| 1955 | private->count_area[0].dl)) | 1961 | private->count_area[0].dl) || |
| 1962 | private->count_area[i].cyl != 0 || | ||
| 1963 | private->count_area[i].head != count_area_head[i] || | ||
| 1964 | private->count_area[i].record != count_area_rec[i]) | ||
| 1956 | break; | 1965 | break; |
| 1957 | } | 1966 | } |
| 1958 | if (i == 5) | 1967 | if (i == 5) |
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 654c6921a6d4..8252f37d04ed 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c | |||
| @@ -292,12 +292,12 @@ out: | |||
| 292 | #else | 292 | #else |
| 293 | static int dasd_ioctl_reset_profile(struct dasd_block *block) | 293 | static int dasd_ioctl_reset_profile(struct dasd_block *block) |
| 294 | { | 294 | { |
| 295 | return -ENOSYS; | 295 | return -ENOTTY; |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp) | 298 | static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp) |
| 299 | { | 299 | { |
| 300 | return -ENOSYS; | 300 | return -ENOTTY; |
| 301 | } | 301 | } |
| 302 | #endif | 302 | #endif |
| 303 | 303 | ||
diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c new file mode 100644 index 000000000000..9978ad4433cb --- /dev/null +++ b/drivers/s390/block/scm_blk.c | |||
| @@ -0,0 +1,445 @@ | |||
| 1 | /* | ||
| 2 | * Block driver for s390 storage class memory. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #define KMSG_COMPONENT "scm_block" | ||
| 9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
| 10 | |||
| 11 | #include <linux/interrupt.h> | ||
| 12 | #include <linux/spinlock.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/blkdev.h> | ||
| 15 | #include <linux/genhd.h> | ||
| 16 | #include <linux/slab.h> | ||
| 17 | #include <linux/list.h> | ||
| 18 | #include <asm/eadm.h> | ||
| 19 | #include "scm_blk.h" | ||
| 20 | |||
| 21 | debug_info_t *scm_debug; | ||
| 22 | static int scm_major; | ||
| 23 | static DEFINE_SPINLOCK(list_lock); | ||
| 24 | static LIST_HEAD(inactive_requests); | ||
| 25 | static unsigned int nr_requests = 64; | ||
| 26 | static atomic_t nr_devices = ATOMIC_INIT(0); | ||
| 27 | module_param(nr_requests, uint, S_IRUGO); | ||
| 28 | MODULE_PARM_DESC(nr_requests, "Number of parallel requests."); | ||
| 29 | |||
| 30 | MODULE_DESCRIPTION("Block driver for s390 storage class memory."); | ||
| 31 | MODULE_LICENSE("GPL"); | ||
| 32 | MODULE_ALIAS("scm:scmdev*"); | ||
| 33 | |||
| 34 | static void __scm_free_rq(struct scm_request *scmrq) | ||
| 35 | { | ||
| 36 | struct aob_rq_header *aobrq = to_aobrq(scmrq); | ||
| 37 | |||
| 38 | free_page((unsigned long) scmrq->aob); | ||
| 39 | free_page((unsigned long) scmrq->aidaw); | ||
| 40 | __scm_free_rq_cluster(scmrq); | ||
| 41 | kfree(aobrq); | ||
| 42 | } | ||
| 43 | |||
| 44 | static void scm_free_rqs(void) | ||
| 45 | { | ||
| 46 | struct list_head *iter, *safe; | ||
| 47 | struct scm_request *scmrq; | ||
| 48 | |||
| 49 | spin_lock_irq(&list_lock); | ||
| 50 | list_for_each_safe(iter, safe, &inactive_requests) { | ||
| 51 | scmrq = list_entry(iter, struct scm_request, list); | ||
| 52 | list_del(&scmrq->list); | ||
| 53 | __scm_free_rq(scmrq); | ||
| 54 | } | ||
| 55 | spin_unlock_irq(&list_lock); | ||
| 56 | } | ||
| 57 | |||
| 58 | static int __scm_alloc_rq(void) | ||
| 59 | { | ||
| 60 | struct aob_rq_header *aobrq; | ||
| 61 | struct scm_request *scmrq; | ||
| 62 | |||
| 63 | aobrq = kzalloc(sizeof(*aobrq) + sizeof(*scmrq), GFP_KERNEL); | ||
| 64 | if (!aobrq) | ||
| 65 | return -ENOMEM; | ||
| 66 | |||
| 67 | scmrq = (void *) aobrq->data; | ||
| 68 | scmrq->aidaw = (void *) get_zeroed_page(GFP_DMA); | ||
| 69 | scmrq->aob = (void *) get_zeroed_page(GFP_DMA); | ||
| 70 | if (!scmrq->aob || !scmrq->aidaw) { | ||
| 71 | __scm_free_rq(scmrq); | ||
| 72 | return -ENOMEM; | ||
| 73 | } | ||
| 74 | |||
| 75 | if (__scm_alloc_rq_cluster(scmrq)) { | ||
| 76 | __scm_free_rq(scmrq); | ||
| 77 | return -ENOMEM; | ||
| 78 | } | ||
| 79 | |||
| 80 | INIT_LIST_HEAD(&scmrq->list); | ||
| 81 | spin_lock_irq(&list_lock); | ||
| 82 | list_add(&scmrq->list, &inactive_requests); | ||
| 83 | spin_unlock_irq(&list_lock); | ||
| 84 | |||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | static int scm_alloc_rqs(unsigned int nrqs) | ||
| 89 | { | ||
| 90 | int ret = 0; | ||
| 91 | |||
| 92 | while (nrqs-- && !ret) | ||
| 93 | ret = __scm_alloc_rq(); | ||
| 94 | |||
| 95 | return ret; | ||
| 96 | } | ||
| 97 | |||
| 98 | static struct scm_request *scm_request_fetch(void) | ||
| 99 | { | ||
| 100 | struct scm_request *scmrq = NULL; | ||
| 101 | |||
| 102 | spin_lock(&list_lock); | ||
| 103 | if (list_empty(&inactive_requests)) | ||
| 104 | goto out; | ||
| 105 | scmrq = list_first_entry(&inactive_requests, struct scm_request, list); | ||
| 106 | list_del(&scmrq->list); | ||
| 107 | out: | ||
| 108 | spin_unlock(&list_lock); | ||
| 109 | return scmrq; | ||
| 110 | } | ||
| 111 | |||
| 112 | static void scm_request_done(struct scm_request *scmrq) | ||
| 113 | { | ||
| 114 | unsigned long flags; | ||
| 115 | |||
| 116 | spin_lock_irqsave(&list_lock, flags); | ||
| 117 | list_add(&scmrq->list, &inactive_requests); | ||
| 118 | spin_unlock_irqrestore(&list_lock, flags); | ||
| 119 | } | ||
| 120 | |||
| 121 | static int scm_open(struct block_device *blkdev, fmode_t mode) | ||
| 122 | { | ||
| 123 | return scm_get_ref(); | ||
| 124 | } | ||
| 125 | |||
| 126 | static int scm_release(struct gendisk *gendisk, fmode_t mode) | ||
| 127 | { | ||
| 128 | scm_put_ref(); | ||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | static const struct block_device_operations scm_blk_devops = { | ||
| 133 | .owner = THIS_MODULE, | ||
| 134 | .open = scm_open, | ||
| 135 | .release = scm_release, | ||
| 136 | }; | ||
| 137 | |||
| 138 | static void scm_request_prepare(struct scm_request *scmrq) | ||
| 139 | { | ||
| 140 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 141 | struct scm_device *scmdev = bdev->gendisk->private_data; | ||
| 142 | struct aidaw *aidaw = scmrq->aidaw; | ||
| 143 | struct msb *msb = &scmrq->aob->msb[0]; | ||
| 144 | struct req_iterator iter; | ||
| 145 | struct bio_vec *bv; | ||
| 146 | |||
| 147 | msb->bs = MSB_BS_4K; | ||
| 148 | scmrq->aob->request.msb_count = 1; | ||
| 149 | msb->scm_addr = scmdev->address + | ||
| 150 | ((u64) blk_rq_pos(scmrq->request) << 9); | ||
| 151 | msb->oc = (rq_data_dir(scmrq->request) == READ) ? | ||
| 152 | MSB_OC_READ : MSB_OC_WRITE; | ||
| 153 | msb->flags |= MSB_FLAG_IDA; | ||
| 154 | msb->data_addr = (u64) aidaw; | ||
| 155 | |||
| 156 | rq_for_each_segment(bv, scmrq->request, iter) { | ||
| 157 | WARN_ON(bv->bv_offset); | ||
| 158 | msb->blk_count += bv->bv_len >> 12; | ||
| 159 | aidaw->data_addr = (u64) page_address(bv->bv_page); | ||
| 160 | aidaw++; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | static inline void scm_request_init(struct scm_blk_dev *bdev, | ||
| 165 | struct scm_request *scmrq, | ||
| 166 | struct request *req) | ||
| 167 | { | ||
| 168 | struct aob_rq_header *aobrq = to_aobrq(scmrq); | ||
| 169 | struct aob *aob = scmrq->aob; | ||
| 170 | |||
| 171 | memset(aob, 0, sizeof(*aob)); | ||
| 172 | memset(scmrq->aidaw, 0, PAGE_SIZE); | ||
| 173 | aobrq->scmdev = bdev->scmdev; | ||
| 174 | aob->request.cmd_code = ARQB_CMD_MOVE; | ||
| 175 | aob->request.data = (u64) aobrq; | ||
| 176 | scmrq->request = req; | ||
| 177 | scmrq->bdev = bdev; | ||
| 178 | scmrq->retries = 4; | ||
| 179 | scmrq->error = 0; | ||
| 180 | scm_request_cluster_init(scmrq); | ||
| 181 | } | ||
| 182 | |||
| 183 | static void scm_ensure_queue_restart(struct scm_blk_dev *bdev) | ||
| 184 | { | ||
| 185 | if (atomic_read(&bdev->queued_reqs)) { | ||
| 186 | /* Queue restart is triggered by the next interrupt. */ | ||
| 187 | return; | ||
| 188 | } | ||
| 189 | blk_delay_queue(bdev->rq, SCM_QUEUE_DELAY); | ||
| 190 | } | ||
| 191 | |||
| 192 | void scm_request_requeue(struct scm_request *scmrq) | ||
| 193 | { | ||
| 194 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 195 | |||
| 196 | scm_release_cluster(scmrq); | ||
| 197 | blk_requeue_request(bdev->rq, scmrq->request); | ||
| 198 | scm_request_done(scmrq); | ||
| 199 | scm_ensure_queue_restart(bdev); | ||
| 200 | } | ||
| 201 | |||
| 202 | void scm_request_finish(struct scm_request *scmrq) | ||
| 203 | { | ||
| 204 | scm_release_cluster(scmrq); | ||
| 205 | blk_end_request_all(scmrq->request, scmrq->error); | ||
| 206 | scm_request_done(scmrq); | ||
| 207 | } | ||
| 208 | |||
| 209 | static void scm_blk_request(struct request_queue *rq) | ||
| 210 | { | ||
| 211 | struct scm_device *scmdev = rq->queuedata; | ||
| 212 | struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev); | ||
| 213 | struct scm_request *scmrq; | ||
| 214 | struct request *req; | ||
| 215 | int ret; | ||
| 216 | |||
| 217 | while ((req = blk_peek_request(rq))) { | ||
| 218 | if (req->cmd_type != REQ_TYPE_FS) | ||
| 219 | continue; | ||
| 220 | |||
| 221 | scmrq = scm_request_fetch(); | ||
| 222 | if (!scmrq) { | ||
| 223 | SCM_LOG(5, "no request"); | ||
| 224 | scm_ensure_queue_restart(bdev); | ||
| 225 | return; | ||
| 226 | } | ||
| 227 | scm_request_init(bdev, scmrq, req); | ||
| 228 | if (!scm_reserve_cluster(scmrq)) { | ||
| 229 | SCM_LOG(5, "cluster busy"); | ||
| 230 | scm_request_done(scmrq); | ||
| 231 | return; | ||
| 232 | } | ||
| 233 | if (scm_need_cluster_request(scmrq)) { | ||
| 234 | blk_start_request(req); | ||
| 235 | scm_initiate_cluster_request(scmrq); | ||
| 236 | return; | ||
| 237 | } | ||
| 238 | scm_request_prepare(scmrq); | ||
| 239 | blk_start_request(req); | ||
| 240 | |||
| 241 | ret = scm_start_aob(scmrq->aob); | ||
| 242 | if (ret) { | ||
| 243 | SCM_LOG(5, "no subchannel"); | ||
| 244 | scm_request_requeue(scmrq); | ||
| 245 | return; | ||
| 246 | } | ||
| 247 | atomic_inc(&bdev->queued_reqs); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | static void __scmrq_log_error(struct scm_request *scmrq) | ||
| 252 | { | ||
| 253 | struct aob *aob = scmrq->aob; | ||
| 254 | |||
| 255 | if (scmrq->error == -ETIMEDOUT) | ||
| 256 | SCM_LOG(1, "Request timeout"); | ||
| 257 | else { | ||
| 258 | SCM_LOG(1, "Request error"); | ||
| 259 | SCM_LOG_HEX(1, &aob->response, sizeof(aob->response)); | ||
| 260 | } | ||
| 261 | if (scmrq->retries) | ||
| 262 | SCM_LOG(1, "Retry request"); | ||
| 263 | else | ||
| 264 | pr_err("An I/O operation to SCM failed with rc=%d\n", | ||
| 265 | scmrq->error); | ||
| 266 | } | ||
| 267 | |||
| 268 | void scm_blk_irq(struct scm_device *scmdev, void *data, int error) | ||
| 269 | { | ||
| 270 | struct scm_request *scmrq = data; | ||
| 271 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 272 | |||
| 273 | scmrq->error = error; | ||
| 274 | if (error) | ||
| 275 | __scmrq_log_error(scmrq); | ||
| 276 | |||
| 277 | spin_lock(&bdev->lock); | ||
| 278 | list_add_tail(&scmrq->list, &bdev->finished_requests); | ||
| 279 | spin_unlock(&bdev->lock); | ||
| 280 | tasklet_hi_schedule(&bdev->tasklet); | ||
| 281 | } | ||
| 282 | |||
| 283 | static void scm_blk_tasklet(struct scm_blk_dev *bdev) | ||
| 284 | { | ||
| 285 | struct scm_request *scmrq; | ||
| 286 | unsigned long flags; | ||
| 287 | |||
| 288 | spin_lock_irqsave(&bdev->lock, flags); | ||
| 289 | while (!list_empty(&bdev->finished_requests)) { | ||
| 290 | scmrq = list_first_entry(&bdev->finished_requests, | ||
| 291 | struct scm_request, list); | ||
| 292 | list_del(&scmrq->list); | ||
| 293 | spin_unlock_irqrestore(&bdev->lock, flags); | ||
| 294 | |||
| 295 | if (scmrq->error && scmrq->retries-- > 0) { | ||
| 296 | if (scm_start_aob(scmrq->aob)) { | ||
| 297 | spin_lock_irqsave(&bdev->rq_lock, flags); | ||
| 298 | scm_request_requeue(scmrq); | ||
| 299 | spin_unlock_irqrestore(&bdev->rq_lock, flags); | ||
| 300 | } | ||
| 301 | /* Request restarted or requeued, handle next. */ | ||
| 302 | spin_lock_irqsave(&bdev->lock, flags); | ||
| 303 | continue; | ||
| 304 | } | ||
| 305 | |||
| 306 | if (scm_test_cluster_request(scmrq)) { | ||
| 307 | scm_cluster_request_irq(scmrq); | ||
| 308 | spin_lock_irqsave(&bdev->lock, flags); | ||
| 309 | continue; | ||
| 310 | } | ||
| 311 | |||
| 312 | scm_request_finish(scmrq); | ||
| 313 | atomic_dec(&bdev->queued_reqs); | ||
| 314 | spin_lock_irqsave(&bdev->lock, flags); | ||
| 315 | } | ||
| 316 | spin_unlock_irqrestore(&bdev->lock, flags); | ||
| 317 | /* Look out for more requests. */ | ||
| 318 | blk_run_queue(bdev->rq); | ||
| 319 | } | ||
| 320 | |||
| 321 | int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev) | ||
| 322 | { | ||
| 323 | struct request_queue *rq; | ||
| 324 | int len, ret = -ENOMEM; | ||
| 325 | unsigned int devindex, nr_max_blk; | ||
| 326 | |||
| 327 | devindex = atomic_inc_return(&nr_devices) - 1; | ||
| 328 | /* scma..scmz + scmaa..scmzz */ | ||
| 329 | if (devindex > 701) { | ||
| 330 | ret = -ENODEV; | ||
| 331 | goto out; | ||
| 332 | } | ||
| 333 | |||
| 334 | bdev->scmdev = scmdev; | ||
| 335 | spin_lock_init(&bdev->rq_lock); | ||
| 336 | spin_lock_init(&bdev->lock); | ||
| 337 | INIT_LIST_HEAD(&bdev->finished_requests); | ||
| 338 | atomic_set(&bdev->queued_reqs, 0); | ||
| 339 | tasklet_init(&bdev->tasklet, | ||
| 340 | (void (*)(unsigned long)) scm_blk_tasklet, | ||
| 341 | (unsigned long) bdev); | ||
| 342 | |||
| 343 | rq = blk_init_queue(scm_blk_request, &bdev->rq_lock); | ||
| 344 | if (!rq) | ||
| 345 | goto out; | ||
| 346 | |||
| 347 | bdev->rq = rq; | ||
| 348 | nr_max_blk = min(scmdev->nr_max_block, | ||
| 349 | (unsigned int) (PAGE_SIZE / sizeof(struct aidaw))); | ||
| 350 | |||
| 351 | blk_queue_logical_block_size(rq, 1 << 12); | ||
| 352 | blk_queue_max_hw_sectors(rq, nr_max_blk << 3); /* 8 * 512 = blk_size */ | ||
| 353 | blk_queue_max_segments(rq, nr_max_blk); | ||
| 354 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, rq); | ||
| 355 | scm_blk_dev_cluster_setup(bdev); | ||
| 356 | |||
| 357 | bdev->gendisk = alloc_disk(SCM_NR_PARTS); | ||
| 358 | if (!bdev->gendisk) | ||
| 359 | goto out_queue; | ||
| 360 | |||
| 361 | rq->queuedata = scmdev; | ||
| 362 | bdev->gendisk->driverfs_dev = &scmdev->dev; | ||
| 363 | bdev->gendisk->private_data = scmdev; | ||
| 364 | bdev->gendisk->fops = &scm_blk_devops; | ||
| 365 | bdev->gendisk->queue = rq; | ||
| 366 | bdev->gendisk->major = scm_major; | ||
| 367 | bdev->gendisk->first_minor = devindex * SCM_NR_PARTS; | ||
| 368 | |||
| 369 | len = snprintf(bdev->gendisk->disk_name, DISK_NAME_LEN, "scm"); | ||
| 370 | if (devindex > 25) { | ||
| 371 | len += snprintf(bdev->gendisk->disk_name + len, | ||
| 372 | DISK_NAME_LEN - len, "%c", | ||
| 373 | 'a' + (devindex / 26) - 1); | ||
| 374 | devindex = devindex % 26; | ||
| 375 | } | ||
| 376 | snprintf(bdev->gendisk->disk_name + len, DISK_NAME_LEN - len, "%c", | ||
| 377 | 'a' + devindex); | ||
| 378 | |||
| 379 | /* 512 byte sectors */ | ||
| 380 | set_capacity(bdev->gendisk, scmdev->size >> 9); | ||
| 381 | add_disk(bdev->gendisk); | ||
| 382 | return 0; | ||
| 383 | |||
| 384 | out_queue: | ||
| 385 | blk_cleanup_queue(rq); | ||
| 386 | out: | ||
| 387 | atomic_dec(&nr_devices); | ||
| 388 | return ret; | ||
| 389 | } | ||
| 390 | |||
| 391 | void scm_blk_dev_cleanup(struct scm_blk_dev *bdev) | ||
| 392 | { | ||
| 393 | tasklet_kill(&bdev->tasklet); | ||
| 394 | del_gendisk(bdev->gendisk); | ||
| 395 | blk_cleanup_queue(bdev->gendisk->queue); | ||
| 396 | put_disk(bdev->gendisk); | ||
| 397 | } | ||
| 398 | |||
| 399 | static int __init scm_blk_init(void) | ||
| 400 | { | ||
| 401 | int ret = -EINVAL; | ||
| 402 | |||
| 403 | if (!scm_cluster_size_valid()) | ||
| 404 | goto out; | ||
| 405 | |||
| 406 | ret = register_blkdev(0, "scm"); | ||
| 407 | if (ret < 0) | ||
| 408 | goto out; | ||
| 409 | |||
| 410 | scm_major = ret; | ||
| 411 | if (scm_alloc_rqs(nr_requests)) | ||
| 412 | goto out_unreg; | ||
| 413 | |||
| 414 | scm_debug = debug_register("scm_log", 16, 1, 16); | ||
| 415 | if (!scm_debug) | ||
| 416 | goto out_free; | ||
| 417 | |||
| 418 | debug_register_view(scm_debug, &debug_hex_ascii_view); | ||
| 419 | debug_set_level(scm_debug, 2); | ||
| 420 | |||
| 421 | ret = scm_drv_init(); | ||
| 422 | if (ret) | ||
| 423 | goto out_dbf; | ||
| 424 | |||
| 425 | return ret; | ||
| 426 | |||
| 427 | out_dbf: | ||
| 428 | debug_unregister(scm_debug); | ||
| 429 | out_free: | ||
| 430 | scm_free_rqs(); | ||
| 431 | out_unreg: | ||
| 432 | unregister_blkdev(scm_major, "scm"); | ||
| 433 | out: | ||
| 434 | return ret; | ||
| 435 | } | ||
| 436 | module_init(scm_blk_init); | ||
| 437 | |||
| 438 | static void __exit scm_blk_cleanup(void) | ||
| 439 | { | ||
| 440 | scm_drv_cleanup(); | ||
| 441 | debug_unregister(scm_debug); | ||
| 442 | scm_free_rqs(); | ||
| 443 | unregister_blkdev(scm_major, "scm"); | ||
| 444 | } | ||
| 445 | module_exit(scm_blk_cleanup); | ||
diff --git a/drivers/s390/block/scm_blk.h b/drivers/s390/block/scm_blk.h new file mode 100644 index 000000000000..7ac6bad919ef --- /dev/null +++ b/drivers/s390/block/scm_blk.h | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | #ifndef SCM_BLK_H | ||
| 2 | #define SCM_BLK_H | ||
| 3 | |||
| 4 | #include <linux/interrupt.h> | ||
| 5 | #include <linux/spinlock.h> | ||
| 6 | #include <linux/blkdev.h> | ||
| 7 | #include <linux/genhd.h> | ||
| 8 | #include <linux/list.h> | ||
| 9 | |||
| 10 | #include <asm/debug.h> | ||
| 11 | #include <asm/eadm.h> | ||
| 12 | |||
| 13 | #define SCM_NR_PARTS 8 | ||
| 14 | #define SCM_QUEUE_DELAY 5 | ||
| 15 | |||
| 16 | struct scm_blk_dev { | ||
| 17 | struct tasklet_struct tasklet; | ||
| 18 | struct request_queue *rq; | ||
| 19 | struct gendisk *gendisk; | ||
| 20 | struct scm_device *scmdev; | ||
| 21 | spinlock_t rq_lock; /* guard the request queue */ | ||
| 22 | spinlock_t lock; /* guard the rest of the blockdev */ | ||
| 23 | atomic_t queued_reqs; | ||
| 24 | struct list_head finished_requests; | ||
| 25 | #ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
| 26 | struct list_head cluster_list; | ||
| 27 | #endif | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct scm_request { | ||
| 31 | struct scm_blk_dev *bdev; | ||
| 32 | struct request *request; | ||
| 33 | struct aidaw *aidaw; | ||
| 34 | struct aob *aob; | ||
| 35 | struct list_head list; | ||
| 36 | u8 retries; | ||
| 37 | int error; | ||
| 38 | #ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
| 39 | struct { | ||
| 40 | enum {CLUSTER_NONE, CLUSTER_READ, CLUSTER_WRITE} state; | ||
| 41 | struct list_head list; | ||
| 42 | void **buf; | ||
| 43 | } cluster; | ||
| 44 | #endif | ||
| 45 | }; | ||
| 46 | |||
| 47 | #define to_aobrq(rq) container_of((void *) rq, struct aob_rq_header, data) | ||
| 48 | |||
| 49 | int scm_blk_dev_setup(struct scm_blk_dev *, struct scm_device *); | ||
| 50 | void scm_blk_dev_cleanup(struct scm_blk_dev *); | ||
| 51 | void scm_blk_irq(struct scm_device *, void *, int); | ||
| 52 | |||
| 53 | void scm_request_finish(struct scm_request *); | ||
| 54 | void scm_request_requeue(struct scm_request *); | ||
| 55 | |||
| 56 | int scm_drv_init(void); | ||
| 57 | void scm_drv_cleanup(void); | ||
| 58 | |||
| 59 | #ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
| 60 | void __scm_free_rq_cluster(struct scm_request *); | ||
| 61 | int __scm_alloc_rq_cluster(struct scm_request *); | ||
| 62 | void scm_request_cluster_init(struct scm_request *); | ||
| 63 | bool scm_reserve_cluster(struct scm_request *); | ||
| 64 | void scm_release_cluster(struct scm_request *); | ||
| 65 | void scm_blk_dev_cluster_setup(struct scm_blk_dev *); | ||
| 66 | bool scm_need_cluster_request(struct scm_request *); | ||
| 67 | void scm_initiate_cluster_request(struct scm_request *); | ||
| 68 | void scm_cluster_request_irq(struct scm_request *); | ||
| 69 | bool scm_test_cluster_request(struct scm_request *); | ||
| 70 | bool scm_cluster_size_valid(void); | ||
| 71 | #else | ||
| 72 | #define __scm_free_rq_cluster(scmrq) {} | ||
| 73 | #define __scm_alloc_rq_cluster(scmrq) 0 | ||
| 74 | #define scm_request_cluster_init(scmrq) {} | ||
| 75 | #define scm_reserve_cluster(scmrq) true | ||
| 76 | #define scm_release_cluster(scmrq) {} | ||
| 77 | #define scm_blk_dev_cluster_setup(bdev) {} | ||
| 78 | #define scm_need_cluster_request(scmrq) false | ||
| 79 | #define scm_initiate_cluster_request(scmrq) {} | ||
| 80 | #define scm_cluster_request_irq(scmrq) {} | ||
| 81 | #define scm_test_cluster_request(scmrq) false | ||
| 82 | #define scm_cluster_size_valid() true | ||
| 83 | #endif | ||
| 84 | |||
| 85 | extern debug_info_t *scm_debug; | ||
| 86 | |||
| 87 | #define SCM_LOG(imp, txt) do { \ | ||
| 88 | debug_text_event(scm_debug, imp, txt); \ | ||
| 89 | } while (0) | ||
| 90 | |||
| 91 | static inline void SCM_LOG_HEX(int level, void *data, int length) | ||
| 92 | { | ||
| 93 | if (level > scm_debug->level) | ||
| 94 | return; | ||
| 95 | while (length > 0) { | ||
| 96 | debug_event(scm_debug, level, data, length); | ||
| 97 | length -= scm_debug->buf_size; | ||
| 98 | data += scm_debug->buf_size; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | static inline void SCM_LOG_STATE(int level, struct scm_device *scmdev) | ||
| 103 | { | ||
| 104 | struct { | ||
| 105 | u64 address; | ||
| 106 | u8 oper_state; | ||
| 107 | u8 rank; | ||
| 108 | } __packed data = { | ||
| 109 | .address = scmdev->address, | ||
| 110 | .oper_state = scmdev->attrs.oper_state, | ||
| 111 | .rank = scmdev->attrs.rank, | ||
| 112 | }; | ||
| 113 | |||
| 114 | SCM_LOG_HEX(level, &data, sizeof(data)); | ||
| 115 | } | ||
| 116 | |||
| 117 | #endif /* SCM_BLK_H */ | ||
diff --git a/drivers/s390/block/scm_blk_cluster.c b/drivers/s390/block/scm_blk_cluster.c new file mode 100644 index 000000000000..f4bb61b0cea1 --- /dev/null +++ b/drivers/s390/block/scm_blk_cluster.c | |||
| @@ -0,0 +1,228 @@ | |||
| 1 | /* | ||
| 2 | * Block driver for s390 storage class memory. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/spinlock.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/blkdev.h> | ||
| 11 | #include <linux/genhd.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/list.h> | ||
| 14 | #include <asm/eadm.h> | ||
| 15 | #include "scm_blk.h" | ||
| 16 | |||
| 17 | static unsigned int write_cluster_size = 64; | ||
| 18 | module_param(write_cluster_size, uint, S_IRUGO); | ||
| 19 | MODULE_PARM_DESC(write_cluster_size, | ||
| 20 | "Number of pages used for contiguous writes."); | ||
| 21 | |||
| 22 | #define CLUSTER_SIZE (write_cluster_size * PAGE_SIZE) | ||
| 23 | |||
| 24 | void __scm_free_rq_cluster(struct scm_request *scmrq) | ||
| 25 | { | ||
| 26 | int i; | ||
| 27 | |||
| 28 | if (!scmrq->cluster.buf) | ||
| 29 | return; | ||
| 30 | |||
| 31 | for (i = 0; i < 2 * write_cluster_size; i++) | ||
| 32 | free_page((unsigned long) scmrq->cluster.buf[i]); | ||
| 33 | |||
| 34 | kfree(scmrq->cluster.buf); | ||
| 35 | } | ||
| 36 | |||
| 37 | int __scm_alloc_rq_cluster(struct scm_request *scmrq) | ||
| 38 | { | ||
| 39 | int i; | ||
| 40 | |||
| 41 | scmrq->cluster.buf = kzalloc(sizeof(void *) * 2 * write_cluster_size, | ||
| 42 | GFP_KERNEL); | ||
| 43 | if (!scmrq->cluster.buf) | ||
| 44 | return -ENOMEM; | ||
| 45 | |||
| 46 | for (i = 0; i < 2 * write_cluster_size; i++) { | ||
| 47 | scmrq->cluster.buf[i] = (void *) get_zeroed_page(GFP_DMA); | ||
| 48 | if (!scmrq->cluster.buf[i]) | ||
| 49 | return -ENOMEM; | ||
| 50 | } | ||
| 51 | INIT_LIST_HEAD(&scmrq->cluster.list); | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | void scm_request_cluster_init(struct scm_request *scmrq) | ||
| 56 | { | ||
| 57 | scmrq->cluster.state = CLUSTER_NONE; | ||
| 58 | } | ||
| 59 | |||
| 60 | static bool clusters_intersect(struct scm_request *A, struct scm_request *B) | ||
| 61 | { | ||
| 62 | unsigned long firstA, lastA, firstB, lastB; | ||
| 63 | |||
| 64 | firstA = ((u64) blk_rq_pos(A->request) << 9) / CLUSTER_SIZE; | ||
| 65 | lastA = (((u64) blk_rq_pos(A->request) << 9) + | ||
| 66 | blk_rq_bytes(A->request) - 1) / CLUSTER_SIZE; | ||
| 67 | |||
| 68 | firstB = ((u64) blk_rq_pos(B->request) << 9) / CLUSTER_SIZE; | ||
| 69 | lastB = (((u64) blk_rq_pos(B->request) << 9) + | ||
| 70 | blk_rq_bytes(B->request) - 1) / CLUSTER_SIZE; | ||
| 71 | |||
| 72 | return (firstB <= lastA && firstA <= lastB); | ||
| 73 | } | ||
| 74 | |||
| 75 | bool scm_reserve_cluster(struct scm_request *scmrq) | ||
| 76 | { | ||
| 77 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 78 | struct scm_request *iter; | ||
| 79 | |||
| 80 | if (write_cluster_size == 0) | ||
| 81 | return true; | ||
| 82 | |||
| 83 | spin_lock(&bdev->lock); | ||
| 84 | list_for_each_entry(iter, &bdev->cluster_list, cluster.list) { | ||
| 85 | if (clusters_intersect(scmrq, iter) && | ||
| 86 | (rq_data_dir(scmrq->request) == WRITE || | ||
| 87 | rq_data_dir(iter->request) == WRITE)) { | ||
| 88 | spin_unlock(&bdev->lock); | ||
| 89 | return false; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | list_add(&scmrq->cluster.list, &bdev->cluster_list); | ||
| 93 | spin_unlock(&bdev->lock); | ||
| 94 | |||
| 95 | return true; | ||
| 96 | } | ||
| 97 | |||
| 98 | void scm_release_cluster(struct scm_request *scmrq) | ||
| 99 | { | ||
| 100 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 101 | unsigned long flags; | ||
| 102 | |||
| 103 | if (write_cluster_size == 0) | ||
| 104 | return; | ||
| 105 | |||
| 106 | spin_lock_irqsave(&bdev->lock, flags); | ||
| 107 | list_del(&scmrq->cluster.list); | ||
| 108 | spin_unlock_irqrestore(&bdev->lock, flags); | ||
| 109 | } | ||
| 110 | |||
| 111 | void scm_blk_dev_cluster_setup(struct scm_blk_dev *bdev) | ||
| 112 | { | ||
| 113 | INIT_LIST_HEAD(&bdev->cluster_list); | ||
| 114 | blk_queue_io_opt(bdev->rq, CLUSTER_SIZE); | ||
| 115 | } | ||
| 116 | |||
| 117 | static void scm_prepare_cluster_request(struct scm_request *scmrq) | ||
| 118 | { | ||
| 119 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 120 | struct scm_device *scmdev = bdev->gendisk->private_data; | ||
| 121 | struct request *req = scmrq->request; | ||
| 122 | struct aidaw *aidaw = scmrq->aidaw; | ||
| 123 | struct msb *msb = &scmrq->aob->msb[0]; | ||
| 124 | struct req_iterator iter; | ||
| 125 | struct bio_vec *bv; | ||
| 126 | int i = 0; | ||
| 127 | u64 addr; | ||
| 128 | |||
| 129 | switch (scmrq->cluster.state) { | ||
| 130 | case CLUSTER_NONE: | ||
| 131 | scmrq->cluster.state = CLUSTER_READ; | ||
| 132 | /* fall through */ | ||
| 133 | case CLUSTER_READ: | ||
| 134 | scmrq->aob->request.msb_count = 1; | ||
| 135 | msb->bs = MSB_BS_4K; | ||
| 136 | msb->oc = MSB_OC_READ; | ||
| 137 | msb->flags = MSB_FLAG_IDA; | ||
| 138 | msb->data_addr = (u64) aidaw; | ||
| 139 | msb->blk_count = write_cluster_size; | ||
| 140 | |||
| 141 | addr = scmdev->address + ((u64) blk_rq_pos(req) << 9); | ||
| 142 | msb->scm_addr = round_down(addr, CLUSTER_SIZE); | ||
| 143 | |||
| 144 | if (msb->scm_addr != | ||
| 145 | round_down(addr + (u64) blk_rq_bytes(req) - 1, | ||
| 146 | CLUSTER_SIZE)) | ||
| 147 | msb->blk_count = 2 * write_cluster_size; | ||
| 148 | |||
| 149 | for (i = 0; i < msb->blk_count; i++) { | ||
| 150 | aidaw->data_addr = (u64) scmrq->cluster.buf[i]; | ||
| 151 | aidaw++; | ||
| 152 | } | ||
| 153 | |||
| 154 | break; | ||
| 155 | case CLUSTER_WRITE: | ||
| 156 | msb->oc = MSB_OC_WRITE; | ||
| 157 | |||
| 158 | for (addr = msb->scm_addr; | ||
| 159 | addr < scmdev->address + ((u64) blk_rq_pos(req) << 9); | ||
| 160 | addr += PAGE_SIZE) { | ||
| 161 | aidaw->data_addr = (u64) scmrq->cluster.buf[i]; | ||
| 162 | aidaw++; | ||
| 163 | i++; | ||
| 164 | } | ||
| 165 | rq_for_each_segment(bv, req, iter) { | ||
| 166 | aidaw->data_addr = (u64) page_address(bv->bv_page); | ||
| 167 | aidaw++; | ||
| 168 | i++; | ||
| 169 | } | ||
| 170 | for (; i < msb->blk_count; i++) { | ||
| 171 | aidaw->data_addr = (u64) scmrq->cluster.buf[i]; | ||
| 172 | aidaw++; | ||
| 173 | } | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | bool scm_need_cluster_request(struct scm_request *scmrq) | ||
| 179 | { | ||
| 180 | if (rq_data_dir(scmrq->request) == READ) | ||
| 181 | return false; | ||
| 182 | |||
| 183 | return blk_rq_bytes(scmrq->request) < CLUSTER_SIZE; | ||
| 184 | } | ||
| 185 | |||
| 186 | /* Called with queue lock held. */ | ||
| 187 | void scm_initiate_cluster_request(struct scm_request *scmrq) | ||
| 188 | { | ||
| 189 | scm_prepare_cluster_request(scmrq); | ||
| 190 | if (scm_start_aob(scmrq->aob)) | ||
| 191 | scm_request_requeue(scmrq); | ||
| 192 | } | ||
| 193 | |||
| 194 | bool scm_test_cluster_request(struct scm_request *scmrq) | ||
| 195 | { | ||
| 196 | return scmrq->cluster.state != CLUSTER_NONE; | ||
| 197 | } | ||
| 198 | |||
| 199 | void scm_cluster_request_irq(struct scm_request *scmrq) | ||
| 200 | { | ||
| 201 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
| 202 | unsigned long flags; | ||
| 203 | |||
| 204 | switch (scmrq->cluster.state) { | ||
| 205 | case CLUSTER_NONE: | ||
| 206 | BUG(); | ||
| 207 | break; | ||
| 208 | case CLUSTER_READ: | ||
| 209 | if (scmrq->error) { | ||
| 210 | scm_request_finish(scmrq); | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | scmrq->cluster.state = CLUSTER_WRITE; | ||
| 214 | spin_lock_irqsave(&bdev->rq_lock, flags); | ||
| 215 | scm_initiate_cluster_request(scmrq); | ||
| 216 | spin_unlock_irqrestore(&bdev->rq_lock, flags); | ||
| 217 | break; | ||
| 218 | case CLUSTER_WRITE: | ||
| 219 | scm_request_finish(scmrq); | ||
| 220 | break; | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | bool scm_cluster_size_valid(void) | ||
| 225 | { | ||
| 226 | return write_cluster_size == 0 || write_cluster_size == 32 || | ||
| 227 | write_cluster_size == 64 || write_cluster_size == 128; | ||
| 228 | } | ||
diff --git a/drivers/s390/block/scm_drv.c b/drivers/s390/block/scm_drv.c new file mode 100644 index 000000000000..9fa0a908607b --- /dev/null +++ b/drivers/s390/block/scm_drv.c | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | /* | ||
| 2 | * Device driver for s390 storage class memory. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #define KMSG_COMPONENT "scm_block" | ||
| 9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
| 10 | |||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <asm/eadm.h> | ||
| 14 | #include "scm_blk.h" | ||
| 15 | |||
| 16 | static void notify(struct scm_device *scmdev) | ||
| 17 | { | ||
| 18 | pr_info("%lu: The capabilities of the SCM increment changed\n", | ||
| 19 | (unsigned long) scmdev->address); | ||
| 20 | SCM_LOG(2, "State changed"); | ||
| 21 | SCM_LOG_STATE(2, scmdev); | ||
| 22 | } | ||
| 23 | |||
| 24 | static int scm_probe(struct scm_device *scmdev) | ||
| 25 | { | ||
| 26 | struct scm_blk_dev *bdev; | ||
| 27 | int ret; | ||
| 28 | |||
| 29 | SCM_LOG(2, "probe"); | ||
| 30 | SCM_LOG_STATE(2, scmdev); | ||
| 31 | |||
| 32 | if (scmdev->attrs.oper_state != OP_STATE_GOOD) | ||
| 33 | return -EINVAL; | ||
| 34 | |||
| 35 | bdev = kzalloc(sizeof(*bdev), GFP_KERNEL); | ||
| 36 | if (!bdev) | ||
| 37 | return -ENOMEM; | ||
| 38 | |||
| 39 | dev_set_drvdata(&scmdev->dev, bdev); | ||
| 40 | ret = scm_blk_dev_setup(bdev, scmdev); | ||
| 41 | if (ret) { | ||
| 42 | dev_set_drvdata(&scmdev->dev, NULL); | ||
| 43 | kfree(bdev); | ||
| 44 | goto out; | ||
| 45 | } | ||
| 46 | |||
| 47 | out: | ||
| 48 | return ret; | ||
| 49 | } | ||
| 50 | |||
| 51 | static int scm_remove(struct scm_device *scmdev) | ||
| 52 | { | ||
| 53 | struct scm_blk_dev *bdev = dev_get_drvdata(&scmdev->dev); | ||
| 54 | |||
| 55 | scm_blk_dev_cleanup(bdev); | ||
| 56 | dev_set_drvdata(&scmdev->dev, NULL); | ||
| 57 | kfree(bdev); | ||
| 58 | |||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | static struct scm_driver scm_drv = { | ||
| 63 | .drv = { | ||
| 64 | .name = "scm_block", | ||
| 65 | .owner = THIS_MODULE, | ||
| 66 | }, | ||
| 67 | .notify = notify, | ||
| 68 | .probe = scm_probe, | ||
| 69 | .remove = scm_remove, | ||
| 70 | .handler = scm_blk_irq, | ||
| 71 | }; | ||
| 72 | |||
| 73 | int __init scm_drv_init(void) | ||
| 74 | { | ||
| 75 | return scm_driver_register(&scm_drv); | ||
| 76 | } | ||
| 77 | |||
| 78 | void scm_drv_cleanup(void) | ||
| 79 | { | ||
| 80 | scm_driver_unregister(&scm_drv); | ||
| 81 | } | ||
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index bb07577e8fd4..699fd3e363df 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c | |||
| @@ -35,7 +35,6 @@ static struct raw3270_fn con3270_fn; | |||
| 35 | */ | 35 | */ |
| 36 | struct con3270 { | 36 | struct con3270 { |
| 37 | struct raw3270_view view; | 37 | struct raw3270_view view; |
| 38 | spinlock_t lock; | ||
| 39 | struct list_head freemem; /* list of free memory for strings. */ | 38 | struct list_head freemem; /* list of free memory for strings. */ |
| 40 | 39 | ||
| 41 | /* Output stuff. */ | 40 | /* Output stuff. */ |
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 5b8b8592d311..f4ff515db251 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c | |||
| @@ -571,8 +571,11 @@ static int __init mon_init(void) | |||
| 571 | if (rc) | 571 | if (rc) |
| 572 | goto out_iucv; | 572 | goto out_iucv; |
| 573 | monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL); | 573 | monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL); |
| 574 | if (!monreader_device) | 574 | if (!monreader_device) { |
| 575 | rc = -ENOMEM; | ||
| 575 | goto out_driver; | 576 | goto out_driver; |
| 577 | } | ||
| 578 | |||
| 576 | dev_set_name(monreader_device, "monreader-dev"); | 579 | dev_set_name(monreader_device, "monreader-dev"); |
| 577 | monreader_device->bus = &iucv_bus; | 580 | monreader_device->bus = &iucv_bus; |
| 578 | monreader_device->parent = iucv_root; | 581 | monreader_device->parent = iucv_root; |
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 3fcc000efc53..4fa21f7e2308 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c | |||
| @@ -334,7 +334,7 @@ sclp_dispatch_evbufs(struct sccb_header *sccb) | |||
| 334 | reg->receiver_fn(evbuf); | 334 | reg->receiver_fn(evbuf); |
| 335 | spin_lock_irqsave(&sclp_lock, flags); | 335 | spin_lock_irqsave(&sclp_lock, flags); |
| 336 | } else if (reg == NULL) | 336 | } else if (reg == NULL) |
| 337 | rc = -ENOSYS; | 337 | rc = -EOPNOTSUPP; |
| 338 | } | 338 | } |
| 339 | spin_unlock_irqrestore(&sclp_lock, flags); | 339 | spin_unlock_irqrestore(&sclp_lock, flags); |
| 340 | return rc; | 340 | return rc; |
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index 4be63be73445..3b13d58fe87b 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c | |||
| @@ -463,7 +463,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer, | |||
| 463 | /* Use write priority message */ | 463 | /* Use write priority message */ |
| 464 | sccb->msg_buf.header.type = EVTYP_PMSGCMD; | 464 | sccb->msg_buf.header.type = EVTYP_PMSGCMD; |
| 465 | else | 465 | else |
| 466 | return -ENOSYS; | 466 | return -EOPNOTSUPP; |
| 467 | buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; | 467 | buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; |
| 468 | buffer->request.status = SCLP_REQ_FILLED; | 468 | buffer->request.status = SCLP_REQ_FILLED; |
| 469 | buffer->request.callback = sclp_writedata_callback; | 469 | buffer->request.callback = sclp_writedata_callback; |
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index c06be6cc2fc3..ea664dd4f56d 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | #include <asm/ccwdev.h> | 15 | #include <asm/ccwdev.h> |
| 16 | #include <asm/debug.h> | 16 | #include <asm/debug.h> |
| 17 | #include <asm/idals.h> | 17 | #include <asm/idals.h> |
| 18 | #include <linux/blkdev.h> | ||
| 19 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 20 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 21 | #include <linux/mtio.h> | 20 | #include <linux/mtio.h> |
diff --git a/drivers/s390/char/tape_std.h b/drivers/s390/char/tape_std.h index c5816ad9ed7d..8c760c036832 100644 --- a/drivers/s390/char/tape_std.h +++ b/drivers/s390/char/tape_std.h | |||
| @@ -100,11 +100,7 @@ struct tape_request *tape_std_read_block(struct tape_device *, size_t); | |||
| 100 | void tape_std_read_backward(struct tape_device *device, | 100 | void tape_std_read_backward(struct tape_device *device, |
| 101 | struct tape_request *request); | 101 | struct tape_request *request); |
| 102 | struct tape_request *tape_std_write_block(struct tape_device *, size_t); | 102 | struct tape_request *tape_std_write_block(struct tape_device *, size_t); |
| 103 | struct tape_request *tape_std_bread(struct tape_device *, struct request *); | ||
| 104 | void tape_std_free_bread(struct tape_request *); | ||
| 105 | void tape_std_check_locate(struct tape_device *, struct tape_request *); | 103 | void tape_std_check_locate(struct tape_device *, struct tape_request *); |
| 106 | struct tape_request *tape_std_bwrite(struct request *, | ||
| 107 | struct tape_device *, int); | ||
| 108 | 104 | ||
| 109 | /* Some non-mtop commands. */ | 105 | /* Some non-mtop commands. */ |
| 110 | int tape_std_assign(struct tape_device *); | 106 | int tape_std_assign(struct tape_device *); |
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index c131bc40f962..9b3a24e8d3a0 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c | |||
| @@ -321,7 +321,7 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp) | |||
| 321 | * only allow for blocking reads to be open | 321 | * only allow for blocking reads to be open |
| 322 | */ | 322 | */ |
| 323 | if (filp->f_flags & O_NONBLOCK) | 323 | if (filp->f_flags & O_NONBLOCK) |
| 324 | return -ENOSYS; | 324 | return -EOPNOTSUPP; |
| 325 | 325 | ||
| 326 | /* Besure this device hasn't already been opened */ | 326 | /* Besure this device hasn't already been opened */ |
| 327 | spin_lock_bh(&logptr->priv_lock); | 327 | spin_lock_bh(&logptr->priv_lock); |
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile index e1b700a19648..8c4a386e97f6 100644 --- a/drivers/s390/cio/Makefile +++ b/drivers/s390/cio/Makefile | |||
| @@ -8,6 +8,8 @@ ccw_device-objs += device.o device_fsm.o device_ops.o | |||
| 8 | ccw_device-objs += device_id.o device_pgid.o device_status.o | 8 | ccw_device-objs += device_id.o device_pgid.o device_status.o |
| 9 | obj-y += ccw_device.o cmf.o | 9 | obj-y += ccw_device.o cmf.o |
| 10 | obj-$(CONFIG_CHSC_SCH) += chsc_sch.o | 10 | obj-$(CONFIG_CHSC_SCH) += chsc_sch.o |
| 11 | obj-$(CONFIG_EADM_SCH) += eadm_sch.o | ||
| 12 | obj-$(CONFIG_SCM_BUS) += scm.o | ||
| 11 | obj-$(CONFIG_CCWGROUP) += ccwgroup.o | 13 | obj-$(CONFIG_CCWGROUP) += ccwgroup.o |
| 12 | 14 | ||
| 13 | qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_setup.o | 15 | qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_setup.o |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index cfe0c087fe5c..4d51a7c4eb8b 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
| @@ -52,6 +52,11 @@ int chsc_error_from_response(int response) | |||
| 52 | return -EINVAL; | 52 | return -EINVAL; |
| 53 | case 0x0004: | 53 | case 0x0004: |
| 54 | return -EOPNOTSUPP; | 54 | return -EOPNOTSUPP; |
| 55 | case 0x000b: | ||
| 56 | return -EBUSY; | ||
| 57 | case 0x0100: | ||
| 58 | case 0x0102: | ||
| 59 | return -ENOMEM; | ||
| 55 | default: | 60 | default: |
| 56 | return -EIO; | 61 | return -EIO; |
| 57 | } | 62 | } |
| @@ -393,6 +398,20 @@ static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) | |||
| 393 | } | 398 | } |
| 394 | } | 399 | } |
| 395 | 400 | ||
| 401 | static void chsc_process_sei_scm_change(struct chsc_sei_area *sei_area) | ||
| 402 | { | ||
| 403 | int ret; | ||
| 404 | |||
| 405 | CIO_CRW_EVENT(4, "chsc: scm change notification\n"); | ||
| 406 | if (sei_area->rs != 7) | ||
| 407 | return; | ||
| 408 | |||
| 409 | ret = scm_update_information(); | ||
| 410 | if (ret) | ||
| 411 | CIO_CRW_EVENT(0, "chsc: updating change notification" | ||
| 412 | " failed (rc=%d).\n", ret); | ||
| 413 | } | ||
| 414 | |||
| 396 | static void chsc_process_sei(struct chsc_sei_area *sei_area) | 415 | static void chsc_process_sei(struct chsc_sei_area *sei_area) |
| 397 | { | 416 | { |
| 398 | /* Check if we might have lost some information. */ | 417 | /* Check if we might have lost some information. */ |
| @@ -414,6 +433,9 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area) | |||
| 414 | case 8: /* channel-path-configuration notification */ | 433 | case 8: /* channel-path-configuration notification */ |
| 415 | chsc_process_sei_chp_config(sei_area); | 434 | chsc_process_sei_chp_config(sei_area); |
| 416 | break; | 435 | break; |
| 436 | case 12: /* scm change notification */ | ||
| 437 | chsc_process_sei_scm_change(sei_area); | ||
| 438 | break; | ||
| 417 | default: /* other stuff */ | 439 | default: /* other stuff */ |
| 418 | CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", | 440 | CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", |
| 419 | sei_area->cc); | 441 | sei_area->cc); |
| @@ -1047,3 +1069,33 @@ out: | |||
| 1047 | return rc; | 1069 | return rc; |
| 1048 | } | 1070 | } |
| 1049 | EXPORT_SYMBOL_GPL(chsc_siosl); | 1071 | EXPORT_SYMBOL_GPL(chsc_siosl); |
| 1072 | |||
| 1073 | /** | ||
| 1074 | * chsc_scm_info() - store SCM information (SSI) | ||
| 1075 | * @scm_area: request and response block for SSI | ||
| 1076 | * @token: continuation token | ||
| 1077 | * | ||
| 1078 | * Returns 0 on success. | ||
| 1079 | */ | ||
| 1080 | int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token) | ||
| 1081 | { | ||
| 1082 | int ccode, ret; | ||
| 1083 | |||
| 1084 | memset(scm_area, 0, sizeof(*scm_area)); | ||
| 1085 | scm_area->request.length = 0x0020; | ||
| 1086 | scm_area->request.code = 0x004C; | ||
| 1087 | scm_area->reqtok = token; | ||
| 1088 | |||
| 1089 | ccode = chsc(scm_area); | ||
| 1090 | if (ccode > 0) { | ||
| 1091 | ret = (ccode == 3) ? -ENODEV : -EBUSY; | ||
| 1092 | goto out; | ||
| 1093 | } | ||
| 1094 | ret = chsc_error_from_response(scm_area->response.code); | ||
| 1095 | if (ret != 0) | ||
| 1096 | CIO_MSG_EVENT(2, "chsc: scm info failed (rc=%04x)\n", | ||
| 1097 | scm_area->response.code); | ||
| 1098 | out: | ||
| 1099 | return ret; | ||
| 1100 | } | ||
| 1101 | EXPORT_SYMBOL_GPL(chsc_scm_info); | ||
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 3f15b2aaeaea..662dab4b93e6 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
| 5 | #include <linux/device.h> | 5 | #include <linux/device.h> |
| 6 | #include <asm/css_chars.h> | ||
| 6 | #include <asm/chpid.h> | 7 | #include <asm/chpid.h> |
| 7 | #include <asm/chsc.h> | 8 | #include <asm/chsc.h> |
| 8 | #include <asm/schid.h> | 9 | #include <asm/schid.h> |
| @@ -118,4 +119,46 @@ int chsc_error_from_response(int response); | |||
| 118 | 119 | ||
| 119 | int chsc_siosl(struct subchannel_id schid); | 120 | int chsc_siosl(struct subchannel_id schid); |
| 120 | 121 | ||
| 122 | /* Functions and definitions to query storage-class memory. */ | ||
| 123 | struct sale { | ||
| 124 | u64 sa; | ||
| 125 | u32 p:4; | ||
| 126 | u32 op_state:4; | ||
| 127 | u32 data_state:4; | ||
| 128 | u32 rank:4; | ||
| 129 | u32 r:1; | ||
| 130 | u32:7; | ||
| 131 | u32 rid:8; | ||
| 132 | u32:32; | ||
| 133 | } __packed; | ||
| 134 | |||
| 135 | struct chsc_scm_info { | ||
| 136 | struct chsc_header request; | ||
| 137 | u32:32; | ||
| 138 | u64 reqtok; | ||
| 139 | u32 reserved1[4]; | ||
| 140 | struct chsc_header response; | ||
| 141 | u64:56; | ||
| 142 | u8 rq; | ||
| 143 | u32 mbc; | ||
| 144 | u64 msa; | ||
| 145 | u16 is; | ||
| 146 | u16 mmc; | ||
| 147 | u32 mci; | ||
| 148 | u64 nr_scm_ini; | ||
| 149 | u64 nr_scm_unini; | ||
| 150 | u32 reserved2[10]; | ||
| 151 | u64 restok; | ||
| 152 | struct sale scmal[248]; | ||
| 153 | } __packed; | ||
| 154 | |||
| 155 | int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token); | ||
| 156 | |||
| 157 | #ifdef CONFIG_SCM_BUS | ||
| 158 | int scm_update_information(void); | ||
| 159 | #else /* CONFIG_SCM_BUS */ | ||
| 160 | #define scm_update_information() 0 | ||
| 161 | #endif /* CONFIG_SCM_BUS */ | ||
| 162 | |||
| 163 | |||
| 121 | #endif | 164 | #endif |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 33d1ef703593..8e927b9f285f 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
| @@ -1029,7 +1029,7 @@ extern void do_reipl_asm(__u32 schid); | |||
| 1029 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ | 1029 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ |
| 1030 | void reipl_ccw_dev(struct ccw_dev_id *devid) | 1030 | void reipl_ccw_dev(struct ccw_dev_id *devid) |
| 1031 | { | 1031 | { |
| 1032 | struct subchannel_id schid; | 1032 | struct subchannel_id uninitialized_var(schid); |
| 1033 | 1033 | ||
| 1034 | s390_reset_system(NULL, NULL); | 1034 | s390_reset_system(NULL, NULL); |
| 1035 | if (reipl_find_schid(devid, &schid) != 0) | 1035 | if (reipl_find_schid(devid, &schid) != 0) |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 21908e67bf67..b4d572f65f07 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
| @@ -445,6 +445,7 @@ void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo) | |||
| 445 | put_device(&sch->dev); | 445 | put_device(&sch->dev); |
| 446 | } | 446 | } |
| 447 | } | 447 | } |
| 448 | EXPORT_SYMBOL_GPL(css_sched_sch_todo); | ||
| 448 | 449 | ||
| 449 | static void css_sch_todo(struct work_struct *work) | 450 | static void css_sch_todo(struct work_struct *work) |
| 450 | { | 451 | { |
diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c new file mode 100644 index 000000000000..6c9673400464 --- /dev/null +++ b/drivers/s390/cio/eadm_sch.c | |||
| @@ -0,0 +1,401 @@ | |||
| 1 | /* | ||
| 2 | * Driver for s390 eadm subchannels | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/kernel_stat.h> | ||
| 9 | #include <linux/workqueue.h> | ||
| 10 | #include <linux/spinlock.h> | ||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/timer.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/list.h> | ||
| 16 | |||
| 17 | #include <asm/css_chars.h> | ||
| 18 | #include <asm/debug.h> | ||
| 19 | #include <asm/isc.h> | ||
| 20 | #include <asm/cio.h> | ||
| 21 | #include <asm/scsw.h> | ||
| 22 | #include <asm/eadm.h> | ||
| 23 | |||
| 24 | #include "eadm_sch.h" | ||
| 25 | #include "ioasm.h" | ||
| 26 | #include "cio.h" | ||
| 27 | #include "css.h" | ||
| 28 | #include "orb.h" | ||
| 29 | |||
| 30 | MODULE_DESCRIPTION("driver for s390 eadm subchannels"); | ||
| 31 | MODULE_LICENSE("GPL"); | ||
| 32 | |||
| 33 | #define EADM_TIMEOUT (5 * HZ) | ||
| 34 | static DEFINE_SPINLOCK(list_lock); | ||
| 35 | static LIST_HEAD(eadm_list); | ||
| 36 | |||
| 37 | static debug_info_t *eadm_debug; | ||
| 38 | |||
| 39 | #define EADM_LOG(imp, txt) do { \ | ||
| 40 | debug_text_event(eadm_debug, imp, txt); \ | ||
| 41 | } while (0) | ||
| 42 | |||
| 43 | static void EADM_LOG_HEX(int level, void *data, int length) | ||
| 44 | { | ||
| 45 | if (level > eadm_debug->level) | ||
| 46 | return; | ||
| 47 | while (length > 0) { | ||
| 48 | debug_event(eadm_debug, level, data, length); | ||
| 49 | length -= eadm_debug->buf_size; | ||
| 50 | data += eadm_debug->buf_size; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | static void orb_init(union orb *orb) | ||
| 55 | { | ||
| 56 | memset(orb, 0, sizeof(union orb)); | ||
| 57 | orb->eadm.compat1 = 1; | ||
| 58 | orb->eadm.compat2 = 1; | ||
| 59 | orb->eadm.fmt = 1; | ||
| 60 | orb->eadm.x = 1; | ||
| 61 | } | ||
| 62 | |||
| 63 | static int eadm_subchannel_start(struct subchannel *sch, struct aob *aob) | ||
| 64 | { | ||
| 65 | union orb *orb = &get_eadm_private(sch)->orb; | ||
| 66 | int cc; | ||
| 67 | |||
| 68 | orb_init(orb); | ||
| 69 | orb->eadm.aob = (u32)__pa(aob); | ||
| 70 | orb->eadm.intparm = (u32)(addr_t)sch; | ||
| 71 | orb->eadm.key = PAGE_DEFAULT_KEY >> 4; | ||
| 72 | |||
| 73 | EADM_LOG(6, "start"); | ||
| 74 | EADM_LOG_HEX(6, &sch->schid, sizeof(sch->schid)); | ||
| 75 | |||
| 76 | cc = ssch(sch->schid, orb); | ||
| 77 | switch (cc) { | ||
| 78 | case 0: | ||
| 79 | sch->schib.scsw.eadm.actl |= SCSW_ACTL_START_PEND; | ||
| 80 | break; | ||
| 81 | case 1: /* status pending */ | ||
| 82 | case 2: /* busy */ | ||
| 83 | return -EBUSY; | ||
| 84 | case 3: /* not operational */ | ||
| 85 | return -ENODEV; | ||
| 86 | } | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | static int eadm_subchannel_clear(struct subchannel *sch) | ||
| 91 | { | ||
| 92 | int cc; | ||
| 93 | |||
| 94 | cc = csch(sch->schid); | ||
| 95 | if (cc) | ||
| 96 | return -ENODEV; | ||
| 97 | |||
| 98 | sch->schib.scsw.eadm.actl |= SCSW_ACTL_CLEAR_PEND; | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static void eadm_subchannel_timeout(unsigned long data) | ||
| 103 | { | ||
| 104 | struct subchannel *sch = (struct subchannel *) data; | ||
| 105 | |||
| 106 | spin_lock_irq(sch->lock); | ||
| 107 | EADM_LOG(1, "timeout"); | ||
| 108 | EADM_LOG_HEX(1, &sch->schid, sizeof(sch->schid)); | ||
| 109 | if (eadm_subchannel_clear(sch)) | ||
| 110 | EADM_LOG(0, "clear failed"); | ||
| 111 | spin_unlock_irq(sch->lock); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void eadm_subchannel_set_timeout(struct subchannel *sch, int expires) | ||
| 115 | { | ||
| 116 | struct eadm_private *private = get_eadm_private(sch); | ||
| 117 | |||
| 118 | if (expires == 0) { | ||
| 119 | del_timer(&private->timer); | ||
| 120 | return; | ||
| 121 | } | ||
| 122 | if (timer_pending(&private->timer)) { | ||
| 123 | if (mod_timer(&private->timer, jiffies + expires)) | ||
| 124 | return; | ||
| 125 | } | ||
| 126 | private->timer.function = eadm_subchannel_timeout; | ||
| 127 | private->timer.data = (unsigned long) sch; | ||
| 128 | private->timer.expires = jiffies + expires; | ||
| 129 | add_timer(&private->timer); | ||
| 130 | } | ||
| 131 | |||
| 132 | static void eadm_subchannel_irq(struct subchannel *sch) | ||
| 133 | { | ||
| 134 | struct eadm_private *private = get_eadm_private(sch); | ||
| 135 | struct eadm_scsw *scsw = &sch->schib.scsw.eadm; | ||
| 136 | struct irb *irb = (struct irb *)&S390_lowcore.irb; | ||
| 137 | int error = 0; | ||
| 138 | |||
| 139 | EADM_LOG(6, "irq"); | ||
| 140 | EADM_LOG_HEX(6, irb, sizeof(*irb)); | ||
| 141 | |||
| 142 | kstat_cpu(smp_processor_id()).irqs[IOINT_ADM]++; | ||
| 143 | |||
| 144 | if ((scsw->stctl & (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) | ||
| 145 | && scsw->eswf == 1 && irb->esw.eadm.erw.r) | ||
| 146 | error = -EIO; | ||
| 147 | |||
| 148 | if (scsw->fctl & SCSW_FCTL_CLEAR_FUNC) | ||
| 149 | error = -ETIMEDOUT; | ||
| 150 | |||
| 151 | eadm_subchannel_set_timeout(sch, 0); | ||
| 152 | |||
| 153 | if (private->state != EADM_BUSY) { | ||
| 154 | EADM_LOG(1, "irq unsol"); | ||
| 155 | EADM_LOG_HEX(1, irb, sizeof(*irb)); | ||
| 156 | private->state = EADM_NOT_OPER; | ||
| 157 | css_sched_sch_todo(sch, SCH_TODO_EVAL); | ||
| 158 | return; | ||
| 159 | } | ||
| 160 | scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error); | ||
| 161 | private->state = EADM_IDLE; | ||
| 162 | } | ||
| 163 | |||
| 164 | static struct subchannel *eadm_get_idle_sch(void) | ||
| 165 | { | ||
| 166 | struct eadm_private *private; | ||
| 167 | struct subchannel *sch; | ||
| 168 | unsigned long flags; | ||
| 169 | |||
| 170 | spin_lock_irqsave(&list_lock, flags); | ||
| 171 | list_for_each_entry(private, &eadm_list, head) { | ||
| 172 | sch = private->sch; | ||
| 173 | spin_lock(sch->lock); | ||
| 174 | if (private->state == EADM_IDLE) { | ||
| 175 | private->state = EADM_BUSY; | ||
| 176 | list_move_tail(&private->head, &eadm_list); | ||
| 177 | spin_unlock(sch->lock); | ||
| 178 | spin_unlock_irqrestore(&list_lock, flags); | ||
| 179 | |||
| 180 | return sch; | ||
| 181 | } | ||
| 182 | spin_unlock(sch->lock); | ||
| 183 | } | ||
| 184 | spin_unlock_irqrestore(&list_lock, flags); | ||
| 185 | |||
| 186 | return NULL; | ||
| 187 | } | ||
| 188 | |||
| 189 | static int eadm_start_aob(struct aob *aob) | ||
| 190 | { | ||
| 191 | struct eadm_private *private; | ||
| 192 | struct subchannel *sch; | ||
| 193 | unsigned long flags; | ||
| 194 | int ret; | ||
| 195 | |||
| 196 | sch = eadm_get_idle_sch(); | ||
| 197 | if (!sch) | ||
| 198 | return -EBUSY; | ||
| 199 | |||
| 200 | spin_lock_irqsave(sch->lock, flags); | ||
| 201 | eadm_subchannel_set_timeout(sch, EADM_TIMEOUT); | ||
| 202 | ret = eadm_subchannel_start(sch, aob); | ||
| 203 | if (!ret) | ||
| 204 | goto out_unlock; | ||
| 205 | |||
| 206 | /* Handle start subchannel failure. */ | ||
| 207 | eadm_subchannel_set_timeout(sch, 0); | ||
| 208 | private = get_eadm_private(sch); | ||
| 209 | private->state = EADM_NOT_OPER; | ||
| 210 | css_sched_sch_todo(sch, SCH_TODO_EVAL); | ||
| 211 | |||
| 212 | out_unlock: | ||
| 213 | spin_unlock_irqrestore(sch->lock, flags); | ||
| 214 | |||
| 215 | return ret; | ||
| 216 | } | ||
| 217 | |||
| 218 | static int eadm_subchannel_probe(struct subchannel *sch) | ||
| 219 | { | ||
| 220 | struct eadm_private *private; | ||
| 221 | int ret; | ||
| 222 | |||
| 223 | private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); | ||
| 224 | if (!private) | ||
| 225 | return -ENOMEM; | ||
| 226 | |||
| 227 | INIT_LIST_HEAD(&private->head); | ||
| 228 | init_timer(&private->timer); | ||
| 229 | |||
| 230 | spin_lock_irq(sch->lock); | ||
| 231 | set_eadm_private(sch, private); | ||
| 232 | private->state = EADM_IDLE; | ||
| 233 | private->sch = sch; | ||
| 234 | sch->isc = EADM_SCH_ISC; | ||
| 235 | ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); | ||
| 236 | if (ret) { | ||
| 237 | set_eadm_private(sch, NULL); | ||
| 238 | spin_unlock_irq(sch->lock); | ||
| 239 | kfree(private); | ||
| 240 | goto out; | ||
| 241 | } | ||
| 242 | spin_unlock_irq(sch->lock); | ||
| 243 | |||
| 244 | spin_lock_irq(&list_lock); | ||
| 245 | list_add(&private->head, &eadm_list); | ||
| 246 | spin_unlock_irq(&list_lock); | ||
| 247 | |||
| 248 | if (dev_get_uevent_suppress(&sch->dev)) { | ||
| 249 | dev_set_uevent_suppress(&sch->dev, 0); | ||
| 250 | kobject_uevent(&sch->dev.kobj, KOBJ_ADD); | ||
| 251 | } | ||
| 252 | out: | ||
| 253 | return ret; | ||
| 254 | } | ||
| 255 | |||
| 256 | static void eadm_quiesce(struct subchannel *sch) | ||
| 257 | { | ||
| 258 | int ret; | ||
| 259 | |||
| 260 | do { | ||
| 261 | spin_lock_irq(sch->lock); | ||
| 262 | ret = cio_disable_subchannel(sch); | ||
| 263 | spin_unlock_irq(sch->lock); | ||
| 264 | } while (ret == -EBUSY); | ||
| 265 | } | ||
| 266 | |||
| 267 | static int eadm_subchannel_remove(struct subchannel *sch) | ||
| 268 | { | ||
| 269 | struct eadm_private *private = get_eadm_private(sch); | ||
| 270 | |||
| 271 | spin_lock_irq(&list_lock); | ||
| 272 | list_del(&private->head); | ||
| 273 | spin_unlock_irq(&list_lock); | ||
| 274 | |||
| 275 | eadm_quiesce(sch); | ||
| 276 | |||
| 277 | spin_lock_irq(sch->lock); | ||
| 278 | set_eadm_private(sch, NULL); | ||
| 279 | spin_unlock_irq(sch->lock); | ||
| 280 | |||
| 281 | kfree(private); | ||
| 282 | |||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 286 | static void eadm_subchannel_shutdown(struct subchannel *sch) | ||
| 287 | { | ||
| 288 | eadm_quiesce(sch); | ||
| 289 | } | ||
| 290 | |||
| 291 | static int eadm_subchannel_freeze(struct subchannel *sch) | ||
| 292 | { | ||
| 293 | return cio_disable_subchannel(sch); | ||
| 294 | } | ||
| 295 | |||
| 296 | static int eadm_subchannel_restore(struct subchannel *sch) | ||
| 297 | { | ||
| 298 | return cio_enable_subchannel(sch, (u32)(unsigned long)sch); | ||
| 299 | } | ||
| 300 | |||
| 301 | /** | ||
| 302 | * eadm_subchannel_sch_event - process subchannel event | ||
| 303 | * @sch: subchannel | ||
| 304 | * @process: non-zero if function is called in process context | ||
| 305 | * | ||
| 306 | * An unspecified event occurred for this subchannel. Adjust data according | ||
| 307 | * to the current operational state of the subchannel. Return zero when the | ||
| 308 | * event has been handled sufficiently or -EAGAIN when this function should | ||
| 309 | * be called again in process context. | ||
| 310 | */ | ||
| 311 | static int eadm_subchannel_sch_event(struct subchannel *sch, int process) | ||
| 312 | { | ||
| 313 | struct eadm_private *private; | ||
| 314 | unsigned long flags; | ||
| 315 | int ret = 0; | ||
| 316 | |||
| 317 | spin_lock_irqsave(sch->lock, flags); | ||
| 318 | if (!device_is_registered(&sch->dev)) | ||
| 319 | goto out_unlock; | ||
| 320 | |||
| 321 | if (work_pending(&sch->todo_work)) | ||
| 322 | goto out_unlock; | ||
| 323 | |||
| 324 | if (cio_update_schib(sch)) { | ||
| 325 | css_sched_sch_todo(sch, SCH_TODO_UNREG); | ||
| 326 | goto out_unlock; | ||
| 327 | } | ||
| 328 | private = get_eadm_private(sch); | ||
| 329 | if (private->state == EADM_NOT_OPER) | ||
| 330 | private->state = EADM_IDLE; | ||
| 331 | |||
| 332 | out_unlock: | ||
| 333 | spin_unlock_irqrestore(sch->lock, flags); | ||
| 334 | |||
| 335 | return ret; | ||
| 336 | } | ||
| 337 | |||
| 338 | static struct css_device_id eadm_subchannel_ids[] = { | ||
| 339 | { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_ADM, }, | ||
| 340 | { /* end of list */ }, | ||
| 341 | }; | ||
| 342 | MODULE_DEVICE_TABLE(css, eadm_subchannel_ids); | ||
| 343 | |||
| 344 | static struct css_driver eadm_subchannel_driver = { | ||
| 345 | .drv = { | ||
| 346 | .name = "eadm_subchannel", | ||
| 347 | .owner = THIS_MODULE, | ||
| 348 | }, | ||
| 349 | .subchannel_type = eadm_subchannel_ids, | ||
| 350 | .irq = eadm_subchannel_irq, | ||
| 351 | .probe = eadm_subchannel_probe, | ||
| 352 | .remove = eadm_subchannel_remove, | ||
| 353 | .shutdown = eadm_subchannel_shutdown, | ||
| 354 | .sch_event = eadm_subchannel_sch_event, | ||
| 355 | .freeze = eadm_subchannel_freeze, | ||
| 356 | .thaw = eadm_subchannel_restore, | ||
| 357 | .restore = eadm_subchannel_restore, | ||
| 358 | }; | ||
| 359 | |||
| 360 | static struct eadm_ops eadm_ops = { | ||
| 361 | .eadm_start = eadm_start_aob, | ||
| 362 | .owner = THIS_MODULE, | ||
| 363 | }; | ||
| 364 | |||
| 365 | static int __init eadm_sch_init(void) | ||
| 366 | { | ||
| 367 | int ret; | ||
| 368 | |||
| 369 | if (!css_general_characteristics.eadm) | ||
| 370 | return -ENXIO; | ||
| 371 | |||
| 372 | eadm_debug = debug_register("eadm_log", 16, 1, 16); | ||
| 373 | if (!eadm_debug) | ||
| 374 | return -ENOMEM; | ||
| 375 | |||
| 376 | debug_register_view(eadm_debug, &debug_hex_ascii_view); | ||
| 377 | debug_set_level(eadm_debug, 2); | ||
| 378 | |||
| 379 | isc_register(EADM_SCH_ISC); | ||
| 380 | ret = css_driver_register(&eadm_subchannel_driver); | ||
| 381 | if (ret) | ||
| 382 | goto cleanup; | ||
| 383 | |||
| 384 | register_eadm_ops(&eadm_ops); | ||
| 385 | return ret; | ||
| 386 | |||
| 387 | cleanup: | ||
| 388 | isc_unregister(EADM_SCH_ISC); | ||
| 389 | debug_unregister(eadm_debug); | ||
| 390 | return ret; | ||
| 391 | } | ||
| 392 | |||
| 393 | static void __exit eadm_sch_exit(void) | ||
| 394 | { | ||
| 395 | unregister_eadm_ops(&eadm_ops); | ||
| 396 | css_driver_unregister(&eadm_subchannel_driver); | ||
| 397 | isc_unregister(EADM_SCH_ISC); | ||
| 398 | debug_unregister(eadm_debug); | ||
| 399 | } | ||
| 400 | module_init(eadm_sch_init); | ||
| 401 | module_exit(eadm_sch_exit); | ||
diff --git a/drivers/s390/cio/eadm_sch.h b/drivers/s390/cio/eadm_sch.h new file mode 100644 index 000000000000..2779be093982 --- /dev/null +++ b/drivers/s390/cio/eadm_sch.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #ifndef EADM_SCH_H | ||
| 2 | #define EADM_SCH_H | ||
| 3 | |||
| 4 | #include <linux/device.h> | ||
| 5 | #include <linux/timer.h> | ||
| 6 | #include <linux/list.h> | ||
| 7 | #include "orb.h" | ||
| 8 | |||
| 9 | struct eadm_private { | ||
| 10 | union orb orb; | ||
| 11 | enum {EADM_IDLE, EADM_BUSY, EADM_NOT_OPER} state; | ||
| 12 | struct timer_list timer; | ||
| 13 | struct list_head head; | ||
| 14 | struct subchannel *sch; | ||
| 15 | } __aligned(8); | ||
| 16 | |||
| 17 | #define get_eadm_private(n) ((struct eadm_private *)dev_get_drvdata(&n->dev)) | ||
| 18 | #define set_eadm_private(n, p) (dev_set_drvdata(&n->dev, p)) | ||
| 19 | |||
| 20 | #endif | ||
diff --git a/drivers/s390/cio/orb.h b/drivers/s390/cio/orb.h index 45a9865c2b36..7a640530e7f5 100644 --- a/drivers/s390/cio/orb.h +++ b/drivers/s390/cio/orb.h | |||
| @@ -59,9 +59,33 @@ struct tm_orb { | |||
| 59 | u32:32; | 59 | u32:32; |
| 60 | } __packed __aligned(4); | 60 | } __packed __aligned(4); |
| 61 | 61 | ||
| 62 | /* | ||
| 63 | * eadm operation request block | ||
| 64 | */ | ||
| 65 | struct eadm_orb { | ||
| 66 | u32 intparm; | ||
| 67 | u32 key:4; | ||
| 68 | u32:4; | ||
| 69 | u32 compat1:1; | ||
| 70 | u32 compat2:1; | ||
| 71 | u32:21; | ||
| 72 | u32 x:1; | ||
| 73 | u32 aob; | ||
| 74 | u32 css_prio:8; | ||
| 75 | u32:8; | ||
| 76 | u32 scm_prio:8; | ||
| 77 | u32:8; | ||
| 78 | u32:29; | ||
| 79 | u32 fmt:3; | ||
| 80 | u32:32; | ||
| 81 | u32:32; | ||
| 82 | u32:32; | ||
| 83 | } __packed __aligned(4); | ||
| 84 | |||
| 62 | union orb { | 85 | union orb { |
| 63 | struct cmd_orb cmd; | 86 | struct cmd_orb cmd; |
| 64 | struct tm_orb tm; | 87 | struct tm_orb tm; |
| 88 | struct eadm_orb eadm; | ||
| 65 | } __packed __aligned(4); | 89 | } __packed __aligned(4); |
| 66 | 90 | ||
| 67 | #endif /* S390_ORB_H */ | 91 | #endif /* S390_ORB_H */ |
diff --git a/drivers/s390/cio/qdio_debug.h b/drivers/s390/cio/qdio_debug.h index e1f646800ddb..7f8b973da298 100644 --- a/drivers/s390/cio/qdio_debug.h +++ b/drivers/s390/cio/qdio_debug.h | |||
| @@ -37,10 +37,14 @@ static inline int qdio_dbf_passes(debug_info_t *dbf_grp, int level) | |||
| 37 | debug_text_event(qdio_dbf_setup, DBF_ERR, debug_buffer); \ | 37 | debug_text_event(qdio_dbf_setup, DBF_ERR, debug_buffer); \ |
| 38 | } while (0) | 38 | } while (0) |
| 39 | 39 | ||
| 40 | #define DBF_HEX(addr, len) \ | 40 | static inline void DBF_HEX(void *addr, int len) |
| 41 | do { \ | 41 | { |
| 42 | debug_event(qdio_dbf_setup, DBF_ERR, (void*)(addr), len); \ | 42 | while (len > 0) { |
| 43 | } while (0) | 43 | debug_event(qdio_dbf_setup, DBF_ERR, addr, len); |
| 44 | len -= qdio_dbf_setup->buf_size; | ||
| 45 | addr += qdio_dbf_setup->buf_size; | ||
| 46 | } | ||
| 47 | } | ||
| 44 | 48 | ||
| 45 | #define DBF_ERROR(text...) \ | 49 | #define DBF_ERROR(text...) \ |
| 46 | do { \ | 50 | do { \ |
| @@ -49,11 +53,14 @@ static inline int qdio_dbf_passes(debug_info_t *dbf_grp, int level) | |||
| 49 | debug_text_event(qdio_dbf_error, DBF_ERR, debug_buffer); \ | 53 | debug_text_event(qdio_dbf_error, DBF_ERR, debug_buffer); \ |
| 50 | } while (0) | 54 | } while (0) |
| 51 | 55 | ||
| 52 | #define DBF_ERROR_HEX(addr, len) \ | 56 | static inline void DBF_ERROR_HEX(void *addr, int len) |
| 53 | do { \ | 57 | { |
| 54 | debug_event(qdio_dbf_error, DBF_ERR, (void*)(addr), len); \ | 58 | while (len > 0) { |
| 55 | } while (0) | 59 | debug_event(qdio_dbf_error, DBF_ERR, addr, len); |
| 56 | 60 | len -= qdio_dbf_error->buf_size; | |
| 61 | addr += qdio_dbf_error->buf_size; | ||
| 62 | } | ||
| 63 | } | ||
| 57 | 64 | ||
| 58 | #define DBF_DEV_EVENT(level, device, text...) \ | 65 | #define DBF_DEV_EVENT(level, device, text...) \ |
| 59 | do { \ | 66 | do { \ |
| @@ -64,10 +71,15 @@ static inline int qdio_dbf_passes(debug_info_t *dbf_grp, int level) | |||
| 64 | } \ | 71 | } \ |
| 65 | } while (0) | 72 | } while (0) |
| 66 | 73 | ||
| 67 | #define DBF_DEV_HEX(level, device, addr, len) \ | 74 | static inline void DBF_DEV_HEX(struct qdio_irq *dev, void *addr, |
| 68 | do { \ | 75 | int len, int level) |
| 69 | debug_event(device->debug_area, level, (void*)(addr), len); \ | 76 | { |
| 70 | } while (0) | 77 | while (len > 0) { |
| 78 | debug_event(dev->debug_area, level, addr, len); | ||
| 79 | len -= dev->debug_area->buf_size; | ||
| 80 | addr += dev->debug_area->buf_size; | ||
| 81 | } | ||
| 82 | } | ||
| 71 | 83 | ||
| 72 | void qdio_allocate_dbf(struct qdio_initialize *init_data, | 84 | void qdio_allocate_dbf(struct qdio_initialize *init_data, |
| 73 | struct qdio_irq *irq_ptr); | 85 | struct qdio_irq *irq_ptr); |
diff --git a/drivers/s390/cio/scm.c b/drivers/s390/cio/scm.c new file mode 100644 index 000000000000..bcf20f3aa51b --- /dev/null +++ b/drivers/s390/cio/scm.c | |||
| @@ -0,0 +1,317 @@ | |||
| 1 | /* | ||
| 2 | * Recognize and maintain s390 storage class memory. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2012 | ||
| 5 | * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/device.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/mutex.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/init.h> | ||
| 13 | #include <linux/err.h> | ||
| 14 | #include <asm/eadm.h> | ||
| 15 | #include "chsc.h" | ||
| 16 | |||
| 17 | static struct device *scm_root; | ||
| 18 | static struct eadm_ops *eadm_ops; | ||
| 19 | static DEFINE_MUTEX(eadm_ops_mutex); | ||
| 20 | |||
| 21 | #define to_scm_dev(n) container_of(n, struct scm_device, dev) | ||
| 22 | #define to_scm_drv(d) container_of(d, struct scm_driver, drv) | ||
| 23 | |||
| 24 | static int scmdev_probe(struct device *dev) | ||
| 25 | { | ||
| 26 | struct scm_device *scmdev = to_scm_dev(dev); | ||
| 27 | struct scm_driver *scmdrv = to_scm_drv(dev->driver); | ||
| 28 | |||
| 29 | return scmdrv->probe ? scmdrv->probe(scmdev) : -ENODEV; | ||
| 30 | } | ||
| 31 | |||
| 32 | static int scmdev_remove(struct device *dev) | ||
| 33 | { | ||
| 34 | struct scm_device *scmdev = to_scm_dev(dev); | ||
| 35 | struct scm_driver *scmdrv = to_scm_drv(dev->driver); | ||
| 36 | |||
| 37 | return scmdrv->remove ? scmdrv->remove(scmdev) : -ENODEV; | ||
| 38 | } | ||
| 39 | |||
| 40 | static int scmdev_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
| 41 | { | ||
| 42 | return add_uevent_var(env, "MODALIAS=scm:scmdev"); | ||
| 43 | } | ||
| 44 | |||
| 45 | static struct bus_type scm_bus_type = { | ||
| 46 | .name = "scm", | ||
| 47 | .probe = scmdev_probe, | ||
| 48 | .remove = scmdev_remove, | ||
| 49 | .uevent = scmdev_uevent, | ||
| 50 | }; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * scm_driver_register() - register a scm driver | ||
| 54 | * @scmdrv: driver to be registered | ||
| 55 | */ | ||
| 56 | int scm_driver_register(struct scm_driver *scmdrv) | ||
| 57 | { | ||
| 58 | struct device_driver *drv = &scmdrv->drv; | ||
| 59 | |||
| 60 | drv->bus = &scm_bus_type; | ||
| 61 | |||
| 62 | return driver_register(drv); | ||
| 63 | } | ||
| 64 | EXPORT_SYMBOL_GPL(scm_driver_register); | ||
| 65 | |||
| 66 | /** | ||
| 67 | * scm_driver_unregister() - deregister a scm driver | ||
| 68 | * @scmdrv: driver to be deregistered | ||
| 69 | */ | ||
| 70 | void scm_driver_unregister(struct scm_driver *scmdrv) | ||
| 71 | { | ||
| 72 | driver_unregister(&scmdrv->drv); | ||
| 73 | } | ||
| 74 | EXPORT_SYMBOL_GPL(scm_driver_unregister); | ||
| 75 | |||
| 76 | int scm_get_ref(void) | ||
| 77 | { | ||
| 78 | int ret = 0; | ||
| 79 | |||
| 80 | mutex_lock(&eadm_ops_mutex); | ||
| 81 | if (!eadm_ops || !try_module_get(eadm_ops->owner)) | ||
| 82 | ret = -ENOENT; | ||
| 83 | mutex_unlock(&eadm_ops_mutex); | ||
| 84 | |||
| 85 | return ret; | ||
| 86 | } | ||
| 87 | EXPORT_SYMBOL_GPL(scm_get_ref); | ||
| 88 | |||
| 89 | void scm_put_ref(void) | ||
| 90 | { | ||
| 91 | mutex_lock(&eadm_ops_mutex); | ||
| 92 | module_put(eadm_ops->owner); | ||
| 93 | mutex_unlock(&eadm_ops_mutex); | ||
| 94 | } | ||
| 95 | EXPORT_SYMBOL_GPL(scm_put_ref); | ||
| 96 | |||
| 97 | void register_eadm_ops(struct eadm_ops *ops) | ||
| 98 | { | ||
| 99 | mutex_lock(&eadm_ops_mutex); | ||
| 100 | eadm_ops = ops; | ||
| 101 | mutex_unlock(&eadm_ops_mutex); | ||
| 102 | } | ||
| 103 | EXPORT_SYMBOL_GPL(register_eadm_ops); | ||
| 104 | |||
| 105 | void unregister_eadm_ops(struct eadm_ops *ops) | ||
| 106 | { | ||
| 107 | mutex_lock(&eadm_ops_mutex); | ||
| 108 | eadm_ops = NULL; | ||
| 109 | mutex_unlock(&eadm_ops_mutex); | ||
| 110 | } | ||
| 111 | EXPORT_SYMBOL_GPL(unregister_eadm_ops); | ||
| 112 | |||
| 113 | int scm_start_aob(struct aob *aob) | ||
| 114 | { | ||
| 115 | return eadm_ops->eadm_start(aob); | ||
| 116 | } | ||
| 117 | EXPORT_SYMBOL_GPL(scm_start_aob); | ||
| 118 | |||
| 119 | void scm_irq_handler(struct aob *aob, int error) | ||
| 120 | { | ||
| 121 | struct aob_rq_header *aobrq = (void *) aob->request.data; | ||
| 122 | struct scm_device *scmdev = aobrq->scmdev; | ||
| 123 | struct scm_driver *scmdrv = to_scm_drv(scmdev->dev.driver); | ||
| 124 | |||
| 125 | scmdrv->handler(scmdev, aobrq->data, error); | ||
| 126 | } | ||
| 127 | EXPORT_SYMBOL_GPL(scm_irq_handler); | ||
| 128 | |||
| 129 | #define scm_attr(name) \ | ||
| 130 | static ssize_t show_##name(struct device *dev, \ | ||
| 131 | struct device_attribute *attr, char *buf) \ | ||
| 132 | { \ | ||
| 133 | struct scm_device *scmdev = to_scm_dev(dev); \ | ||
| 134 | int ret; \ | ||
| 135 | \ | ||
| 136 | device_lock(dev); \ | ||
| 137 | ret = sprintf(buf, "%u\n", scmdev->attrs.name); \ | ||
| 138 | device_unlock(dev); \ | ||
| 139 | \ | ||
| 140 | return ret; \ | ||
| 141 | } \ | ||
| 142 | static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); | ||
| 143 | |||
| 144 | scm_attr(persistence); | ||
| 145 | scm_attr(oper_state); | ||
| 146 | scm_attr(data_state); | ||
| 147 | scm_attr(rank); | ||
| 148 | scm_attr(release); | ||
| 149 | scm_attr(res_id); | ||
| 150 | |||
| 151 | static struct attribute *scmdev_attrs[] = { | ||
| 152 | &dev_attr_persistence.attr, | ||
| 153 | &dev_attr_oper_state.attr, | ||
| 154 | &dev_attr_data_state.attr, | ||
| 155 | &dev_attr_rank.attr, | ||
| 156 | &dev_attr_release.attr, | ||
| 157 | &dev_attr_res_id.attr, | ||
| 158 | NULL, | ||
| 159 | }; | ||
| 160 | |||
| 161 | static struct attribute_group scmdev_attr_group = { | ||
| 162 | .attrs = scmdev_attrs, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static const struct attribute_group *scmdev_attr_groups[] = { | ||
| 166 | &scmdev_attr_group, | ||
| 167 | NULL, | ||
| 168 | }; | ||
| 169 | |||
| 170 | static void scmdev_release(struct device *dev) | ||
| 171 | { | ||
| 172 | struct scm_device *scmdev = to_scm_dev(dev); | ||
| 173 | |||
| 174 | kfree(scmdev); | ||
| 175 | } | ||
| 176 | |||
| 177 | static void scmdev_setup(struct scm_device *scmdev, struct sale *sale, | ||
| 178 | unsigned int size, unsigned int max_blk_count) | ||
| 179 | { | ||
| 180 | dev_set_name(&scmdev->dev, "%016llx", (unsigned long long) sale->sa); | ||
| 181 | scmdev->nr_max_block = max_blk_count; | ||
| 182 | scmdev->address = sale->sa; | ||
| 183 | scmdev->size = 1UL << size; | ||
| 184 | scmdev->attrs.rank = sale->rank; | ||
| 185 | scmdev->attrs.persistence = sale->p; | ||
| 186 | scmdev->attrs.oper_state = sale->op_state; | ||
| 187 | scmdev->attrs.data_state = sale->data_state; | ||
| 188 | scmdev->attrs.rank = sale->rank; | ||
| 189 | scmdev->attrs.release = sale->r; | ||
| 190 | scmdev->attrs.res_id = sale->rid; | ||
| 191 | scmdev->dev.parent = scm_root; | ||
| 192 | scmdev->dev.bus = &scm_bus_type; | ||
| 193 | scmdev->dev.release = scmdev_release; | ||
| 194 | scmdev->dev.groups = scmdev_attr_groups; | ||
| 195 | } | ||
| 196 | |||
| 197 | /* | ||
| 198 | * Check for state-changes, notify the driver and userspace. | ||
| 199 | */ | ||
| 200 | static void scmdev_update(struct scm_device *scmdev, struct sale *sale) | ||
| 201 | { | ||
| 202 | struct scm_driver *scmdrv; | ||
| 203 | bool changed; | ||
| 204 | |||
| 205 | device_lock(&scmdev->dev); | ||
| 206 | changed = scmdev->attrs.rank != sale->rank || | ||
| 207 | scmdev->attrs.oper_state != sale->op_state; | ||
| 208 | scmdev->attrs.rank = sale->rank; | ||
| 209 | scmdev->attrs.oper_state = sale->op_state; | ||
| 210 | if (!scmdev->dev.driver) | ||
| 211 | goto out; | ||
| 212 | scmdrv = to_scm_drv(scmdev->dev.driver); | ||
| 213 | if (changed && scmdrv->notify) | ||
| 214 | scmdrv->notify(scmdev); | ||
| 215 | out: | ||
| 216 | device_unlock(&scmdev->dev); | ||
| 217 | if (changed) | ||
| 218 | kobject_uevent(&scmdev->dev.kobj, KOBJ_CHANGE); | ||
| 219 | } | ||
| 220 | |||
| 221 | static int check_address(struct device *dev, void *data) | ||
| 222 | { | ||
| 223 | struct scm_device *scmdev = to_scm_dev(dev); | ||
| 224 | struct sale *sale = data; | ||
| 225 | |||
| 226 | return scmdev->address == sale->sa; | ||
| 227 | } | ||
| 228 | |||
| 229 | static struct scm_device *scmdev_find(struct sale *sale) | ||
| 230 | { | ||
| 231 | struct device *dev; | ||
| 232 | |||
| 233 | dev = bus_find_device(&scm_bus_type, NULL, sale, check_address); | ||
| 234 | |||
| 235 | return dev ? to_scm_dev(dev) : NULL; | ||
| 236 | } | ||
| 237 | |||
| 238 | static int scm_add(struct chsc_scm_info *scm_info, size_t num) | ||
| 239 | { | ||
| 240 | struct sale *sale, *scmal = scm_info->scmal; | ||
| 241 | struct scm_device *scmdev; | ||
| 242 | int ret; | ||
| 243 | |||
| 244 | for (sale = scmal; sale < scmal + num; sale++) { | ||
| 245 | scmdev = scmdev_find(sale); | ||
| 246 | if (scmdev) { | ||
| 247 | scmdev_update(scmdev, sale); | ||
| 248 | /* Release reference from scm_find(). */ | ||
| 249 | put_device(&scmdev->dev); | ||
| 250 | continue; | ||
| 251 | } | ||
| 252 | scmdev = kzalloc(sizeof(*scmdev), GFP_KERNEL); | ||
| 253 | if (!scmdev) | ||
| 254 | return -ENODEV; | ||
| 255 | scmdev_setup(scmdev, sale, scm_info->is, scm_info->mbc); | ||
| 256 | ret = device_register(&scmdev->dev); | ||
| 257 | if (ret) { | ||
| 258 | /* Release reference from device_initialize(). */ | ||
| 259 | put_device(&scmdev->dev); | ||
| 260 | return ret; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | return 0; | ||
| 265 | } | ||
| 266 | |||
| 267 | int scm_update_information(void) | ||
| 268 | { | ||
| 269 | struct chsc_scm_info *scm_info; | ||
| 270 | u64 token = 0; | ||
| 271 | size_t num; | ||
| 272 | int ret; | ||
| 273 | |||
| 274 | scm_info = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); | ||
| 275 | if (!scm_info) | ||
| 276 | return -ENOMEM; | ||
| 277 | |||
| 278 | do { | ||
| 279 | ret = chsc_scm_info(scm_info, token); | ||
| 280 | if (ret) | ||
| 281 | break; | ||
| 282 | |||
| 283 | num = (scm_info->response.length - | ||
| 284 | (offsetof(struct chsc_scm_info, scmal) - | ||
| 285 | offsetof(struct chsc_scm_info, response)) | ||
| 286 | ) / sizeof(struct sale); | ||
| 287 | |||
| 288 | ret = scm_add(scm_info, num); | ||
| 289 | if (ret) | ||
| 290 | break; | ||
| 291 | |||
| 292 | token = scm_info->restok; | ||
| 293 | } while (token); | ||
| 294 | |||
| 295 | free_page((unsigned long)scm_info); | ||
| 296 | |||
| 297 | return ret; | ||
| 298 | } | ||
| 299 | |||
| 300 | static int __init scm_init(void) | ||
| 301 | { | ||
| 302 | int ret; | ||
| 303 | |||
| 304 | ret = bus_register(&scm_bus_type); | ||
| 305 | if (ret) | ||
| 306 | return ret; | ||
| 307 | |||
| 308 | scm_root = root_device_register("scm"); | ||
| 309 | if (IS_ERR(scm_root)) { | ||
| 310 | bus_unregister(&scm_bus_type); | ||
| 311 | return PTR_ERR(scm_root); | ||
| 312 | } | ||
| 313 | |||
| 314 | scm_update_information(); | ||
| 315 | return 0; | ||
| 316 | } | ||
| 317 | subsys_initcall_sync(scm_init); | ||
diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index af3c7f16ea88..771faf7094d6 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile | |||
| @@ -4,4 +4,5 @@ | |||
| 4 | 4 | ||
| 5 | ap-objs := ap_bus.o | 5 | ap-objs := ap_bus.o |
| 6 | obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcicc.o zcrypt_pcixcc.o | 6 | obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcicc.o zcrypt_pcixcc.o |
| 7 | obj-$(CONFIG_ZCRYPT) += zcrypt_pcica.o zcrypt_cex2a.o | 7 | obj-$(CONFIG_ZCRYPT) += zcrypt_pcica.o zcrypt_cex2a.o zcrypt_cex4.o |
| 8 | obj-$(CONFIG_ZCRYPT) += zcrypt_msgtype6.o zcrypt_msgtype50.o | ||
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index ae258a4b4e5e..7b865a7300e6 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright IBM Corp. 2006 | 2 | * Copyright IBM Corp. 2006, 2012 |
| 3 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> | 3 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> |
| 4 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 4 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 5 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 5 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| @@ -62,13 +62,14 @@ static void ap_interrupt_handler(void *unused1, void *unused2); | |||
| 62 | static void ap_reset(struct ap_device *ap_dev); | 62 | static void ap_reset(struct ap_device *ap_dev); |
| 63 | static void ap_config_timeout(unsigned long ptr); | 63 | static void ap_config_timeout(unsigned long ptr); |
| 64 | static int ap_select_domain(void); | 64 | static int ap_select_domain(void); |
| 65 | static void ap_query_configuration(void); | ||
| 65 | 66 | ||
| 66 | /* | 67 | /* |
| 67 | * Module description. | 68 | * Module description. |
| 68 | */ | 69 | */ |
| 69 | MODULE_AUTHOR("IBM Corporation"); | 70 | MODULE_AUTHOR("IBM Corporation"); |
| 70 | MODULE_DESCRIPTION("Adjunct Processor Bus driver, " | 71 | MODULE_DESCRIPTION("Adjunct Processor Bus driver, " \ |
| 71 | "Copyright IBM Corp. 2006"); | 72 | "Copyright IBM Corp. 2006, 2012"); |
| 72 | MODULE_LICENSE("GPL"); | 73 | MODULE_LICENSE("GPL"); |
| 73 | 74 | ||
| 74 | /* | 75 | /* |
| @@ -84,6 +85,7 @@ module_param_named(poll_thread, ap_thread_flag, int, 0000); | |||
| 84 | MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); | 85 | MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); |
| 85 | 86 | ||
| 86 | static struct device *ap_root_device = NULL; | 87 | static struct device *ap_root_device = NULL; |
| 88 | static struct ap_config_info *ap_configuration; | ||
| 87 | static DEFINE_SPINLOCK(ap_device_list_lock); | 89 | static DEFINE_SPINLOCK(ap_device_list_lock); |
| 88 | static LIST_HEAD(ap_device_list); | 90 | static LIST_HEAD(ap_device_list); |
| 89 | 91 | ||
| @@ -158,6 +160,19 @@ static int ap_interrupts_available(void) | |||
| 158 | } | 160 | } |
| 159 | 161 | ||
| 160 | /** | 162 | /** |
| 163 | * ap_configuration_available(): Test if AP configuration | ||
| 164 | * information is available. | ||
| 165 | * | ||
| 166 | * Returns 1 if AP configuration information is available. | ||
| 167 | */ | ||
| 168 | #ifdef CONFIG_64BIT | ||
| 169 | static int ap_configuration_available(void) | ||
| 170 | { | ||
| 171 | return test_facility(2) && test_facility(12); | ||
| 172 | } | ||
| 173 | #endif | ||
| 174 | |||
| 175 | /** | ||
| 161 | * ap_test_queue(): Test adjunct processor queue. | 176 | * ap_test_queue(): Test adjunct processor queue. |
| 162 | * @qid: The AP queue number | 177 | * @qid: The AP queue number |
| 163 | * @queue_depth: Pointer to queue depth value | 178 | * @queue_depth: Pointer to queue depth value |
| @@ -242,6 +257,26 @@ __ap_query_functions(ap_qid_t qid, unsigned int *functions) | |||
| 242 | } | 257 | } |
| 243 | #endif | 258 | #endif |
| 244 | 259 | ||
| 260 | #ifdef CONFIG_64BIT | ||
| 261 | static inline int __ap_query_configuration(struct ap_config_info *config) | ||
| 262 | { | ||
| 263 | register unsigned long reg0 asm ("0") = 0x04000000UL; | ||
| 264 | register unsigned long reg1 asm ("1") = -EINVAL; | ||
| 265 | register unsigned char *reg2 asm ("2") = (unsigned char *)config; | ||
| 266 | |||
| 267 | asm volatile( | ||
| 268 | ".long 0xb2af0000\n" /* PQAP(QCI) */ | ||
| 269 | "0: la %1,0\n" | ||
| 270 | "1:\n" | ||
| 271 | EX_TABLE(0b, 1b) | ||
| 272 | : "+d" (reg0), "+d" (reg1), "+d" (reg2) | ||
| 273 | : | ||
| 274 | : "cc"); | ||
| 275 | |||
| 276 | return reg1; | ||
| 277 | } | ||
| 278 | #endif | ||
| 279 | |||
| 245 | /** | 280 | /** |
| 246 | * ap_query_functions(): Query supported functions. | 281 | * ap_query_functions(): Query supported functions. |
| 247 | * @qid: The AP queue number | 282 | * @qid: The AP queue number |
| @@ -292,25 +327,6 @@ static int ap_query_functions(ap_qid_t qid, unsigned int *functions) | |||
| 292 | } | 327 | } |
| 293 | 328 | ||
| 294 | /** | 329 | /** |
| 295 | * ap_4096_commands_availablen(): Check for availability of 4096 bit RSA | ||
| 296 | * support. | ||
| 297 | * @qid: The AP queue number | ||
| 298 | * | ||
| 299 | * Returns 1 if 4096 bit RSA keys are support fo the AP, returns 0 if not. | ||
| 300 | */ | ||
| 301 | int ap_4096_commands_available(ap_qid_t qid) | ||
| 302 | { | ||
| 303 | unsigned int functions; | ||
| 304 | |||
| 305 | if (ap_query_functions(qid, &functions)) | ||
| 306 | return 0; | ||
| 307 | |||
| 308 | return test_ap_facility(functions, 1) && | ||
| 309 | test_ap_facility(functions, 2); | ||
| 310 | } | ||
| 311 | EXPORT_SYMBOL(ap_4096_commands_available); | ||
| 312 | |||
| 313 | /** | ||
| 314 | * ap_queue_enable_interruption(): Enable interruption on an AP. | 330 | * ap_queue_enable_interruption(): Enable interruption on an AP. |
| 315 | * @qid: The AP queue number | 331 | * @qid: The AP queue number |
| 316 | * @ind: the notification indicator byte | 332 | * @ind: the notification indicator byte |
| @@ -657,6 +673,34 @@ static ssize_t ap_request_count_show(struct device *dev, | |||
| 657 | 673 | ||
| 658 | static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL); | 674 | static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL); |
| 659 | 675 | ||
| 676 | static ssize_t ap_requestq_count_show(struct device *dev, | ||
| 677 | struct device_attribute *attr, char *buf) | ||
| 678 | { | ||
| 679 | struct ap_device *ap_dev = to_ap_dev(dev); | ||
| 680 | int rc; | ||
| 681 | |||
| 682 | spin_lock_bh(&ap_dev->lock); | ||
| 683 | rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->requestq_count); | ||
| 684 | spin_unlock_bh(&ap_dev->lock); | ||
| 685 | return rc; | ||
| 686 | } | ||
| 687 | |||
| 688 | static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); | ||
| 689 | |||
| 690 | static ssize_t ap_pendingq_count_show(struct device *dev, | ||
| 691 | struct device_attribute *attr, char *buf) | ||
| 692 | { | ||
| 693 | struct ap_device *ap_dev = to_ap_dev(dev); | ||
| 694 | int rc; | ||
| 695 | |||
| 696 | spin_lock_bh(&ap_dev->lock); | ||
| 697 | rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->pendingq_count); | ||
| 698 | spin_unlock_bh(&ap_dev->lock); | ||
| 699 | return rc; | ||
| 700 | } | ||
| 701 | |||
| 702 | static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); | ||
| 703 | |||
| 660 | static ssize_t ap_modalias_show(struct device *dev, | 704 | static ssize_t ap_modalias_show(struct device *dev, |
| 661 | struct device_attribute *attr, char *buf) | 705 | struct device_attribute *attr, char *buf) |
| 662 | { | 706 | { |
| @@ -665,11 +709,23 @@ static ssize_t ap_modalias_show(struct device *dev, | |||
| 665 | 709 | ||
| 666 | static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL); | 710 | static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL); |
| 667 | 711 | ||
| 712 | static ssize_t ap_functions_show(struct device *dev, | ||
| 713 | struct device_attribute *attr, char *buf) | ||
| 714 | { | ||
| 715 | struct ap_device *ap_dev = to_ap_dev(dev); | ||
| 716 | return snprintf(buf, PAGE_SIZE, "0x%08X\n", ap_dev->functions); | ||
| 717 | } | ||
| 718 | |||
| 719 | static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL); | ||
| 720 | |||
| 668 | static struct attribute *ap_dev_attrs[] = { | 721 | static struct attribute *ap_dev_attrs[] = { |
| 669 | &dev_attr_hwtype.attr, | 722 | &dev_attr_hwtype.attr, |
| 670 | &dev_attr_depth.attr, | 723 | &dev_attr_depth.attr, |
| 671 | &dev_attr_request_count.attr, | 724 | &dev_attr_request_count.attr, |
| 725 | &dev_attr_requestq_count.attr, | ||
| 726 | &dev_attr_pendingq_count.attr, | ||
| 672 | &dev_attr_modalias.attr, | 727 | &dev_attr_modalias.attr, |
| 728 | &dev_attr_ap_functions.attr, | ||
| 673 | NULL | 729 | NULL |
| 674 | }; | 730 | }; |
| 675 | static struct attribute_group ap_dev_attr_group = { | 731 | static struct attribute_group ap_dev_attr_group = { |
| @@ -772,6 +828,7 @@ static int ap_bus_resume(struct device *dev) | |||
| 772 | ap_suspend_flag = 0; | 828 | ap_suspend_flag = 0; |
| 773 | if (!ap_interrupts_available()) | 829 | if (!ap_interrupts_available()) |
| 774 | ap_interrupt_indicator = NULL; | 830 | ap_interrupt_indicator = NULL; |
| 831 | ap_query_configuration(); | ||
| 775 | if (!user_set_domain) { | 832 | if (!user_set_domain) { |
| 776 | ap_domain_index = -1; | 833 | ap_domain_index = -1; |
| 777 | ap_select_domain(); | 834 | ap_select_domain(); |
| @@ -895,6 +952,20 @@ void ap_driver_unregister(struct ap_driver *ap_drv) | |||
| 895 | } | 952 | } |
| 896 | EXPORT_SYMBOL(ap_driver_unregister); | 953 | EXPORT_SYMBOL(ap_driver_unregister); |
| 897 | 954 | ||
| 955 | void ap_bus_force_rescan(void) | ||
| 956 | { | ||
| 957 | /* Delete the AP bus rescan timer. */ | ||
| 958 | del_timer(&ap_config_timer); | ||
| 959 | |||
| 960 | /* processing a synchonuous bus rescan */ | ||
| 961 | ap_scan_bus(NULL); | ||
| 962 | |||
| 963 | /* Setup the AP bus rescan timer again. */ | ||
| 964 | ap_config_timer.expires = jiffies + ap_config_time * HZ; | ||
| 965 | add_timer(&ap_config_timer); | ||
| 966 | } | ||
| 967 | EXPORT_SYMBOL(ap_bus_force_rescan); | ||
| 968 | |||
| 898 | /* | 969 | /* |
| 899 | * AP bus attributes. | 970 | * AP bus attributes. |
| 900 | */ | 971 | */ |
| @@ -997,6 +1068,65 @@ static struct bus_attribute *const ap_bus_attrs[] = { | |||
| 997 | NULL, | 1068 | NULL, |
| 998 | }; | 1069 | }; |
| 999 | 1070 | ||
| 1071 | static inline int ap_test_config(unsigned int *field, unsigned int nr) | ||
| 1072 | { | ||
| 1073 | if (nr > 0xFFu) | ||
| 1074 | return 0; | ||
| 1075 | return ap_test_bit((field + (nr >> 5)), (nr & 0x1f)); | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | /* | ||
| 1079 | * ap_test_config_card_id(): Test, whether an AP card ID is configured. | ||
| 1080 | * @id AP card ID | ||
| 1081 | * | ||
| 1082 | * Returns 0 if the card is not configured | ||
| 1083 | * 1 if the card is configured or | ||
| 1084 | * if the configuration information is not available | ||
| 1085 | */ | ||
| 1086 | static inline int ap_test_config_card_id(unsigned int id) | ||
| 1087 | { | ||
| 1088 | if (!ap_configuration) | ||
| 1089 | return 1; | ||
| 1090 | return ap_test_config(ap_configuration->apm, id); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | /* | ||
| 1094 | * ap_test_config_domain(): Test, whether an AP usage domain is configured. | ||
| 1095 | * @domain AP usage domain ID | ||
| 1096 | * | ||
| 1097 | * Returns 0 if the usage domain is not configured | ||
| 1098 | * 1 if the usage domain is configured or | ||
| 1099 | * if the configuration information is not available | ||
| 1100 | */ | ||
| 1101 | static inline int ap_test_config_domain(unsigned int domain) | ||
| 1102 | { | ||
| 1103 | if (!ap_configuration) | ||
| 1104 | return 1; | ||
| 1105 | return ap_test_config(ap_configuration->aqm, domain); | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | /** | ||
| 1109 | * ap_query_configuration(): Query AP configuration information. | ||
| 1110 | * | ||
| 1111 | * Query information of installed cards and configured domains from AP. | ||
| 1112 | */ | ||
| 1113 | static void ap_query_configuration(void) | ||
| 1114 | { | ||
| 1115 | #ifdef CONFIG_64BIT | ||
| 1116 | if (ap_configuration_available()) { | ||
| 1117 | if (!ap_configuration) | ||
| 1118 | ap_configuration = | ||
| 1119 | kzalloc(sizeof(struct ap_config_info), | ||
| 1120 | GFP_KERNEL); | ||
| 1121 | if (ap_configuration) | ||
| 1122 | __ap_query_configuration(ap_configuration); | ||
| 1123 | } else | ||
| 1124 | ap_configuration = NULL; | ||
| 1125 | #else | ||
| 1126 | ap_configuration = NULL; | ||
| 1127 | #endif | ||
| 1128 | } | ||
| 1129 | |||
| 1000 | /** | 1130 | /** |
| 1001 | * ap_select_domain(): Select an AP domain. | 1131 | * ap_select_domain(): Select an AP domain. |
| 1002 | * | 1132 | * |
| @@ -1005,6 +1135,7 @@ static struct bus_attribute *const ap_bus_attrs[] = { | |||
| 1005 | static int ap_select_domain(void) | 1135 | static int ap_select_domain(void) |
| 1006 | { | 1136 | { |
| 1007 | int queue_depth, device_type, count, max_count, best_domain; | 1137 | int queue_depth, device_type, count, max_count, best_domain; |
| 1138 | ap_qid_t qid; | ||
| 1008 | int rc, i, j; | 1139 | int rc, i, j; |
| 1009 | 1140 | ||
| 1010 | /* | 1141 | /* |
| @@ -1018,9 +1149,13 @@ static int ap_select_domain(void) | |||
| 1018 | best_domain = -1; | 1149 | best_domain = -1; |
| 1019 | max_count = 0; | 1150 | max_count = 0; |
| 1020 | for (i = 0; i < AP_DOMAINS; i++) { | 1151 | for (i = 0; i < AP_DOMAINS; i++) { |
| 1152 | if (!ap_test_config_domain(i)) | ||
| 1153 | continue; | ||
| 1021 | count = 0; | 1154 | count = 0; |
| 1022 | for (j = 0; j < AP_DEVICES; j++) { | 1155 | for (j = 0; j < AP_DEVICES; j++) { |
| 1023 | ap_qid_t qid = AP_MKQID(j, i); | 1156 | if (!ap_test_config_card_id(j)) |
| 1157 | continue; | ||
| 1158 | qid = AP_MKQID(j, i); | ||
| 1024 | rc = ap_query_queue(qid, &queue_depth, &device_type); | 1159 | rc = ap_query_queue(qid, &queue_depth, &device_type); |
| 1025 | if (rc) | 1160 | if (rc) |
| 1026 | continue; | 1161 | continue; |
| @@ -1169,6 +1304,7 @@ static void ap_scan_bus(struct work_struct *unused) | |||
| 1169 | unsigned int device_functions; | 1304 | unsigned int device_functions; |
| 1170 | int rc, i; | 1305 | int rc, i; |
| 1171 | 1306 | ||
| 1307 | ap_query_configuration(); | ||
| 1172 | if (ap_select_domain() != 0) | 1308 | if (ap_select_domain() != 0) |
| 1173 | return; | 1309 | return; |
| 1174 | for (i = 0; i < AP_DEVICES; i++) { | 1310 | for (i = 0; i < AP_DEVICES; i++) { |
| @@ -1176,7 +1312,10 @@ static void ap_scan_bus(struct work_struct *unused) | |||
| 1176 | dev = bus_find_device(&ap_bus_type, NULL, | 1312 | dev = bus_find_device(&ap_bus_type, NULL, |
| 1177 | (void *)(unsigned long)qid, | 1313 | (void *)(unsigned long)qid, |
| 1178 | __ap_scan_bus); | 1314 | __ap_scan_bus); |
| 1179 | rc = ap_query_queue(qid, &queue_depth, &device_type); | 1315 | if (ap_test_config_card_id(i)) |
| 1316 | rc = ap_query_queue(qid, &queue_depth, &device_type); | ||
| 1317 | else | ||
| 1318 | rc = -ENODEV; | ||
| 1180 | if (dev) { | 1319 | if (dev) { |
| 1181 | if (rc == -EBUSY) { | 1320 | if (rc == -EBUSY) { |
| 1182 | set_current_state(TASK_UNINTERRUPTIBLE); | 1321 | set_current_state(TASK_UNINTERRUPTIBLE); |
| @@ -1217,29 +1356,22 @@ static void ap_scan_bus(struct work_struct *unused) | |||
| 1217 | (unsigned long) ap_dev); | 1356 | (unsigned long) ap_dev); |
| 1218 | switch (device_type) { | 1357 | switch (device_type) { |
| 1219 | case 0: | 1358 | case 0: |
| 1359 | /* device type probing for old cards */ | ||
| 1220 | if (ap_probe_device_type(ap_dev)) { | 1360 | if (ap_probe_device_type(ap_dev)) { |
| 1221 | kfree(ap_dev); | 1361 | kfree(ap_dev); |
| 1222 | continue; | 1362 | continue; |
| 1223 | } | 1363 | } |
| 1224 | break; | 1364 | break; |
| 1225 | case 10: | ||
| 1226 | if (ap_query_functions(qid, &device_functions)) { | ||
| 1227 | kfree(ap_dev); | ||
| 1228 | continue; | ||
| 1229 | } | ||
| 1230 | if (test_ap_facility(device_functions, 3)) | ||
| 1231 | ap_dev->device_type = AP_DEVICE_TYPE_CEX3C; | ||
| 1232 | else if (test_ap_facility(device_functions, 4)) | ||
| 1233 | ap_dev->device_type = AP_DEVICE_TYPE_CEX3A; | ||
| 1234 | else { | ||
| 1235 | kfree(ap_dev); | ||
| 1236 | continue; | ||
| 1237 | } | ||
| 1238 | break; | ||
| 1239 | default: | 1365 | default: |
| 1240 | ap_dev->device_type = device_type; | 1366 | ap_dev->device_type = device_type; |
| 1241 | } | 1367 | } |
| 1242 | 1368 | ||
| 1369 | rc = ap_query_functions(qid, &device_functions); | ||
| 1370 | if (!rc) | ||
| 1371 | ap_dev->functions = device_functions; | ||
| 1372 | else | ||
| 1373 | ap_dev->functions = 0u; | ||
| 1374 | |||
| 1243 | ap_dev->device.bus = &ap_bus_type; | 1375 | ap_dev->device.bus = &ap_bus_type; |
| 1244 | ap_dev->device.parent = ap_root_device; | 1376 | ap_dev->device.parent = ap_root_device; |
| 1245 | if (dev_set_name(&ap_dev->device, "card%02x", | 1377 | if (dev_set_name(&ap_dev->device, "card%02x", |
| @@ -1785,6 +1917,7 @@ int __init ap_module_init(void) | |||
| 1785 | goto out_root; | 1917 | goto out_root; |
| 1786 | } | 1918 | } |
| 1787 | 1919 | ||
| 1920 | ap_query_configuration(); | ||
| 1788 | if (ap_select_domain() == 0) | 1921 | if (ap_select_domain() == 0) |
| 1789 | ap_scan_bus(NULL); | 1922 | ap_scan_bus(NULL); |
| 1790 | 1923 | ||
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 52d61995af88..685f6cc022f9 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright IBM Corp. 2006 | 2 | * Copyright IBM Corp. 2006, 2012 |
| 3 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> | 3 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> |
| 4 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 4 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 5 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 5 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| @@ -83,13 +83,12 @@ int ap_queue_status_invalid_test(struct ap_queue_status *status) | |||
| 83 | return !(memcmp(status, &invalid, sizeof(struct ap_queue_status))); | 83 | return !(memcmp(status, &invalid, sizeof(struct ap_queue_status))); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | #define MAX_AP_FACILITY 31 | 86 | #define AP_MAX_BITS 31 |
| 87 | 87 | static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) | |
| 88 | static inline int test_ap_facility(unsigned int function, unsigned int nr) | ||
| 89 | { | 88 | { |
| 90 | if (nr > MAX_AP_FACILITY) | 89 | if (nr > AP_MAX_BITS) |
| 91 | return 0; | 90 | return 0; |
| 92 | return function & (unsigned int)(0x80000000 >> nr); | 91 | return (*ptr & (0x80000000u >> nr)) != 0; |
| 93 | } | 92 | } |
| 94 | 93 | ||
| 95 | #define AP_RESPONSE_NORMAL 0x00 | 94 | #define AP_RESPONSE_NORMAL 0x00 |
| @@ -117,6 +116,15 @@ static inline int test_ap_facility(unsigned int function, unsigned int nr) | |||
| 117 | #define AP_DEVICE_TYPE_CEX2C 7 | 116 | #define AP_DEVICE_TYPE_CEX2C 7 |
| 118 | #define AP_DEVICE_TYPE_CEX3A 8 | 117 | #define AP_DEVICE_TYPE_CEX3A 8 |
| 119 | #define AP_DEVICE_TYPE_CEX3C 9 | 118 | #define AP_DEVICE_TYPE_CEX3C 9 |
| 119 | #define AP_DEVICE_TYPE_CEX4 10 | ||
| 120 | |||
| 121 | /* | ||
| 122 | * Known function facilities | ||
| 123 | */ | ||
| 124 | #define AP_FUNC_MEX4K 1 | ||
| 125 | #define AP_FUNC_CRT4K 2 | ||
| 126 | #define AP_FUNC_COPRO 3 | ||
| 127 | #define AP_FUNC_ACCEL 4 | ||
| 120 | 128 | ||
| 121 | /* | 129 | /* |
| 122 | * AP reset flag states | 130 | * AP reset flag states |
| @@ -151,6 +159,7 @@ struct ap_device { | |||
| 151 | ap_qid_t qid; /* AP queue id. */ | 159 | ap_qid_t qid; /* AP queue id. */ |
| 152 | int queue_depth; /* AP queue depth.*/ | 160 | int queue_depth; /* AP queue depth.*/ |
| 153 | int device_type; /* AP device type. */ | 161 | int device_type; /* AP device type. */ |
| 162 | unsigned int functions; /* AP device function bitfield. */ | ||
| 154 | int unregistered; /* marks AP device as unregistered */ | 163 | int unregistered; /* marks AP device as unregistered */ |
| 155 | struct timer_list timeout; /* Timer for request timeouts. */ | 164 | struct timer_list timeout; /* Timer for request timeouts. */ |
| 156 | int reset; /* Reset required after req. timeout. */ | 165 | int reset; /* Reset required after req. timeout. */ |
| @@ -183,6 +192,17 @@ struct ap_message { | |||
| 183 | struct ap_message *); | 192 | struct ap_message *); |
| 184 | }; | 193 | }; |
| 185 | 194 | ||
| 195 | struct ap_config_info { | ||
| 196 | unsigned int special_command:1; | ||
| 197 | unsigned int ap_extended:1; | ||
| 198 | unsigned char reserved1:6; | ||
| 199 | unsigned char reserved2[15]; | ||
| 200 | unsigned int apm[8]; /* AP ID mask */ | ||
| 201 | unsigned int aqm[8]; /* AP queue mask */ | ||
| 202 | unsigned int adm[8]; /* AP domain mask */ | ||
| 203 | unsigned char reserved4[16]; | ||
| 204 | } __packed; | ||
| 205 | |||
| 186 | #define AP_DEVICE(dt) \ | 206 | #define AP_DEVICE(dt) \ |
| 187 | .dev_type=(dt), \ | 207 | .dev_type=(dt), \ |
| 188 | .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE, | 208 | .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE, |
| @@ -211,10 +231,9 @@ int ap_recv(ap_qid_t, unsigned long long *, void *, size_t); | |||
| 211 | void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg); | 231 | void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg); |
| 212 | void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg); | 232 | void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg); |
| 213 | void ap_flush_queue(struct ap_device *ap_dev); | 233 | void ap_flush_queue(struct ap_device *ap_dev); |
| 234 | void ap_bus_force_rescan(void); | ||
| 214 | 235 | ||
| 215 | int ap_module_init(void); | 236 | int ap_module_init(void); |
| 216 | void ap_module_exit(void); | 237 | void ap_module_exit(void); |
| 217 | 238 | ||
| 218 | int ap_4096_commands_available(ap_qid_t qid); | ||
| 219 | |||
| 220 | #endif /* _AP_BUS_H_ */ | 239 | #endif /* _AP_BUS_H_ */ |
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 2f94132246a1..31cfaa556072 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * zcrypt 2.1.0 | 2 | * zcrypt 2.1.0 |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2001, 2006 | 4 | * Copyright IBM Corp. 2001, 2012 |
| 5 | * Author(s): Robert Burroughs | 5 | * Author(s): Robert Burroughs |
| 6 | * Eric Rossman (edrossma@us.ibm.com) | 6 | * Eric Rossman (edrossma@us.ibm.com) |
| 7 | * Cornelia Huck <cornelia.huck@de.ibm.com> | 7 | * Cornelia Huck <cornelia.huck@de.ibm.com> |
| @@ -9,6 +9,7 @@ | |||
| 9 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | 9 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
| 10 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | 10 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 11 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 11 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| 12 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 12 | * | 13 | * |
| 13 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
| 14 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
| @@ -37,25 +38,39 @@ | |||
| 37 | #include <linux/atomic.h> | 38 | #include <linux/atomic.h> |
| 38 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
| 39 | #include <linux/hw_random.h> | 40 | #include <linux/hw_random.h> |
| 41 | #include <linux/debugfs.h> | ||
| 42 | #include <asm/debug.h> | ||
| 40 | 43 | ||
| 44 | #include "zcrypt_debug.h" | ||
| 41 | #include "zcrypt_api.h" | 45 | #include "zcrypt_api.h" |
| 42 | 46 | ||
| 43 | /* | 47 | /* |
| 44 | * Module description. | 48 | * Module description. |
| 45 | */ | 49 | */ |
| 46 | MODULE_AUTHOR("IBM Corporation"); | 50 | MODULE_AUTHOR("IBM Corporation"); |
| 47 | MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " | 51 | MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " \ |
| 48 | "Copyright IBM Corp. 2001, 2006"); | 52 | "Copyright IBM Corp. 2001, 2012"); |
| 49 | MODULE_LICENSE("GPL"); | 53 | MODULE_LICENSE("GPL"); |
| 50 | 54 | ||
| 51 | static DEFINE_SPINLOCK(zcrypt_device_lock); | 55 | static DEFINE_SPINLOCK(zcrypt_device_lock); |
| 52 | static LIST_HEAD(zcrypt_device_list); | 56 | static LIST_HEAD(zcrypt_device_list); |
| 53 | static int zcrypt_device_count = 0; | 57 | static int zcrypt_device_count = 0; |
| 54 | static atomic_t zcrypt_open_count = ATOMIC_INIT(0); | 58 | static atomic_t zcrypt_open_count = ATOMIC_INIT(0); |
| 59 | static atomic_t zcrypt_rescan_count = ATOMIC_INIT(0); | ||
| 60 | |||
| 61 | atomic_t zcrypt_rescan_req = ATOMIC_INIT(0); | ||
| 62 | EXPORT_SYMBOL(zcrypt_rescan_req); | ||
| 55 | 63 | ||
| 56 | static int zcrypt_rng_device_add(void); | 64 | static int zcrypt_rng_device_add(void); |
| 57 | static void zcrypt_rng_device_remove(void); | 65 | static void zcrypt_rng_device_remove(void); |
| 58 | 66 | ||
| 67 | static DEFINE_SPINLOCK(zcrypt_ops_list_lock); | ||
| 68 | static LIST_HEAD(zcrypt_ops_list); | ||
| 69 | |||
| 70 | static debug_info_t *zcrypt_dbf_common; | ||
| 71 | static debug_info_t *zcrypt_dbf_devices; | ||
| 72 | static struct dentry *debugfs_root; | ||
| 73 | |||
| 59 | /* | 74 | /* |
| 60 | * Device attributes common for all crypto devices. | 75 | * Device attributes common for all crypto devices. |
| 61 | */ | 76 | */ |
| @@ -85,6 +100,8 @@ static ssize_t zcrypt_online_store(struct device *dev, | |||
| 85 | if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) | 100 | if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) |
| 86 | return -EINVAL; | 101 | return -EINVAL; |
| 87 | zdev->online = online; | 102 | zdev->online = online; |
| 103 | ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dman", zdev->ap_dev->qid, | ||
| 104 | zdev->online); | ||
| 88 | if (!online) | 105 | if (!online) |
| 89 | ap_flush_queue(zdev->ap_dev); | 106 | ap_flush_queue(zdev->ap_dev); |
| 90 | return count; | 107 | return count; |
| @@ -103,6 +120,24 @@ static struct attribute_group zcrypt_device_attr_group = { | |||
| 103 | }; | 120 | }; |
| 104 | 121 | ||
| 105 | /** | 122 | /** |
| 123 | * Process a rescan of the transport layer. | ||
| 124 | * | ||
| 125 | * Returns 1, if the rescan has been processed, otherwise 0. | ||
| 126 | */ | ||
| 127 | static inline int zcrypt_process_rescan(void) | ||
| 128 | { | ||
| 129 | if (atomic_read(&zcrypt_rescan_req)) { | ||
| 130 | atomic_set(&zcrypt_rescan_req, 0); | ||
| 131 | atomic_inc(&zcrypt_rescan_count); | ||
| 132 | ap_bus_force_rescan(); | ||
| 133 | ZCRYPT_DBF_COMMON(DBF_INFO, "rescan%07d", | ||
| 134 | atomic_inc_return(&zcrypt_rescan_count)); | ||
| 135 | return 1; | ||
| 136 | } | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | /** | ||
| 106 | * __zcrypt_increase_preference(): Increase preference of a crypto device. | 141 | * __zcrypt_increase_preference(): Increase preference of a crypto device. |
| 107 | * @zdev: Pointer the crypto device | 142 | * @zdev: Pointer the crypto device |
| 108 | * | 143 | * |
| @@ -190,6 +225,7 @@ struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size) | |||
| 190 | zdev->reply.length = max_response_size; | 225 | zdev->reply.length = max_response_size; |
| 191 | spin_lock_init(&zdev->lock); | 226 | spin_lock_init(&zdev->lock); |
| 192 | INIT_LIST_HEAD(&zdev->list); | 227 | INIT_LIST_HEAD(&zdev->list); |
| 228 | zdev->dbf_area = zcrypt_dbf_devices; | ||
| 193 | return zdev; | 229 | return zdev; |
| 194 | 230 | ||
| 195 | out_free: | 231 | out_free: |
| @@ -215,6 +251,8 @@ int zcrypt_device_register(struct zcrypt_device *zdev) | |||
| 215 | { | 251 | { |
| 216 | int rc; | 252 | int rc; |
| 217 | 253 | ||
| 254 | if (!zdev->ops) | ||
| 255 | return -ENODEV; | ||
| 218 | rc = sysfs_create_group(&zdev->ap_dev->device.kobj, | 256 | rc = sysfs_create_group(&zdev->ap_dev->device.kobj, |
| 219 | &zcrypt_device_attr_group); | 257 | &zcrypt_device_attr_group); |
| 220 | if (rc) | 258 | if (rc) |
| @@ -223,6 +261,8 @@ int zcrypt_device_register(struct zcrypt_device *zdev) | |||
| 223 | kref_init(&zdev->refcount); | 261 | kref_init(&zdev->refcount); |
| 224 | spin_lock_bh(&zcrypt_device_lock); | 262 | spin_lock_bh(&zcrypt_device_lock); |
| 225 | zdev->online = 1; /* New devices are online by default. */ | 263 | zdev->online = 1; /* New devices are online by default. */ |
| 264 | ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dreg", zdev->ap_dev->qid, | ||
| 265 | zdev->online); | ||
| 226 | list_add_tail(&zdev->list, &zcrypt_device_list); | 266 | list_add_tail(&zdev->list, &zcrypt_device_list); |
| 227 | __zcrypt_increase_preference(zdev); | 267 | __zcrypt_increase_preference(zdev); |
| 228 | zcrypt_device_count++; | 268 | zcrypt_device_count++; |
| @@ -269,6 +309,67 @@ void zcrypt_device_unregister(struct zcrypt_device *zdev) | |||
| 269 | } | 309 | } |
| 270 | EXPORT_SYMBOL(zcrypt_device_unregister); | 310 | EXPORT_SYMBOL(zcrypt_device_unregister); |
| 271 | 311 | ||
| 312 | void zcrypt_msgtype_register(struct zcrypt_ops *zops) | ||
| 313 | { | ||
| 314 | if (zops->owner) { | ||
| 315 | spin_lock_bh(&zcrypt_ops_list_lock); | ||
| 316 | list_add_tail(&zops->list, &zcrypt_ops_list); | ||
| 317 | spin_unlock_bh(&zcrypt_ops_list_lock); | ||
| 318 | } | ||
| 319 | } | ||
| 320 | EXPORT_SYMBOL(zcrypt_msgtype_register); | ||
| 321 | |||
| 322 | void zcrypt_msgtype_unregister(struct zcrypt_ops *zops) | ||
| 323 | { | ||
| 324 | spin_lock_bh(&zcrypt_ops_list_lock); | ||
| 325 | list_del_init(&zops->list); | ||
| 326 | spin_unlock_bh(&zcrypt_ops_list_lock); | ||
| 327 | } | ||
| 328 | EXPORT_SYMBOL(zcrypt_msgtype_unregister); | ||
| 329 | |||
| 330 | static inline | ||
| 331 | struct zcrypt_ops *__ops_lookup(unsigned char *name, int variant) | ||
| 332 | { | ||
| 333 | struct zcrypt_ops *zops; | ||
| 334 | int found = 0; | ||
| 335 | |||
| 336 | spin_lock_bh(&zcrypt_ops_list_lock); | ||
| 337 | list_for_each_entry(zops, &zcrypt_ops_list, list) { | ||
| 338 | if ((zops->variant == variant) && | ||
| 339 | (!strncmp(zops->owner->name, name, MODULE_NAME_LEN))) { | ||
| 340 | found = 1; | ||
| 341 | break; | ||
| 342 | } | ||
| 343 | } | ||
| 344 | spin_unlock_bh(&zcrypt_ops_list_lock); | ||
| 345 | |||
| 346 | if (!found) | ||
| 347 | return NULL; | ||
| 348 | return zops; | ||
| 349 | } | ||
| 350 | |||
| 351 | struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *name, int variant) | ||
| 352 | { | ||
| 353 | struct zcrypt_ops *zops = NULL; | ||
| 354 | |||
| 355 | zops = __ops_lookup(name, variant); | ||
| 356 | if (!zops) { | ||
| 357 | request_module(name); | ||
| 358 | zops = __ops_lookup(name, variant); | ||
| 359 | } | ||
| 360 | if ((!zops) || (!try_module_get(zops->owner))) | ||
| 361 | return NULL; | ||
| 362 | return zops; | ||
| 363 | } | ||
| 364 | EXPORT_SYMBOL(zcrypt_msgtype_request); | ||
| 365 | |||
| 366 | void zcrypt_msgtype_release(struct zcrypt_ops *zops) | ||
| 367 | { | ||
| 368 | if (zops) | ||
| 369 | module_put(zops->owner); | ||
| 370 | } | ||
| 371 | EXPORT_SYMBOL(zcrypt_msgtype_release); | ||
| 372 | |||
| 272 | /** | 373 | /** |
| 273 | * zcrypt_read (): Not supported beyond zcrypt 1.3.1. | 374 | * zcrypt_read (): Not supported beyond zcrypt 1.3.1. |
| 274 | * | 375 | * |
| @@ -640,6 +741,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, | |||
| 640 | do { | 741 | do { |
| 641 | rc = zcrypt_rsa_modexpo(&mex); | 742 | rc = zcrypt_rsa_modexpo(&mex); |
| 642 | } while (rc == -EAGAIN); | 743 | } while (rc == -EAGAIN); |
| 744 | /* on failure: retry once again after a requested rescan */ | ||
| 745 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) | ||
| 746 | do { | ||
| 747 | rc = zcrypt_rsa_modexpo(&mex); | ||
| 748 | } while (rc == -EAGAIN); | ||
| 643 | if (rc) | 749 | if (rc) |
| 644 | return rc; | 750 | return rc; |
| 645 | return put_user(mex.outputdatalength, &umex->outputdatalength); | 751 | return put_user(mex.outputdatalength, &umex->outputdatalength); |
| @@ -652,6 +758,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, | |||
| 652 | do { | 758 | do { |
| 653 | rc = zcrypt_rsa_crt(&crt); | 759 | rc = zcrypt_rsa_crt(&crt); |
| 654 | } while (rc == -EAGAIN); | 760 | } while (rc == -EAGAIN); |
| 761 | /* on failure: retry once again after a requested rescan */ | ||
| 762 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) | ||
| 763 | do { | ||
| 764 | rc = zcrypt_rsa_crt(&crt); | ||
| 765 | } while (rc == -EAGAIN); | ||
| 655 | if (rc) | 766 | if (rc) |
| 656 | return rc; | 767 | return rc; |
| 657 | return put_user(crt.outputdatalength, &ucrt->outputdatalength); | 768 | return put_user(crt.outputdatalength, &ucrt->outputdatalength); |
| @@ -664,6 +775,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, | |||
| 664 | do { | 775 | do { |
| 665 | rc = zcrypt_send_cprb(&xcRB); | 776 | rc = zcrypt_send_cprb(&xcRB); |
| 666 | } while (rc == -EAGAIN); | 777 | } while (rc == -EAGAIN); |
| 778 | /* on failure: retry once again after a requested rescan */ | ||
| 779 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) | ||
| 780 | do { | ||
| 781 | rc = zcrypt_send_cprb(&xcRB); | ||
| 782 | } while (rc == -EAGAIN); | ||
| 667 | if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB))) | 783 | if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB))) |
| 668 | return -EFAULT; | 784 | return -EFAULT; |
| 669 | return rc; | 785 | return rc; |
| @@ -770,10 +886,15 @@ static long trans_modexpo32(struct file *filp, unsigned int cmd, | |||
| 770 | do { | 886 | do { |
| 771 | rc = zcrypt_rsa_modexpo(&mex64); | 887 | rc = zcrypt_rsa_modexpo(&mex64); |
| 772 | } while (rc == -EAGAIN); | 888 | } while (rc == -EAGAIN); |
| 773 | if (!rc) | 889 | /* on failure: retry once again after a requested rescan */ |
| 774 | rc = put_user(mex64.outputdatalength, | 890 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) |
| 775 | &umex32->outputdatalength); | 891 | do { |
| 776 | return rc; | 892 | rc = zcrypt_rsa_modexpo(&mex64); |
| 893 | } while (rc == -EAGAIN); | ||
| 894 | if (rc) | ||
| 895 | return rc; | ||
| 896 | return put_user(mex64.outputdatalength, | ||
| 897 | &umex32->outputdatalength); | ||
| 777 | } | 898 | } |
| 778 | 899 | ||
| 779 | struct compat_ica_rsa_modexpo_crt { | 900 | struct compat_ica_rsa_modexpo_crt { |
| @@ -810,10 +931,15 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd, | |||
| 810 | do { | 931 | do { |
| 811 | rc = zcrypt_rsa_crt(&crt64); | 932 | rc = zcrypt_rsa_crt(&crt64); |
| 812 | } while (rc == -EAGAIN); | 933 | } while (rc == -EAGAIN); |
| 813 | if (!rc) | 934 | /* on failure: retry once again after a requested rescan */ |
| 814 | rc = put_user(crt64.outputdatalength, | 935 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) |
| 815 | &ucrt32->outputdatalength); | 936 | do { |
| 816 | return rc; | 937 | rc = zcrypt_rsa_crt(&crt64); |
| 938 | } while (rc == -EAGAIN); | ||
| 939 | if (rc) | ||
| 940 | return rc; | ||
| 941 | return put_user(crt64.outputdatalength, | ||
| 942 | &ucrt32->outputdatalength); | ||
| 817 | } | 943 | } |
| 818 | 944 | ||
| 819 | struct compat_ica_xcRB { | 945 | struct compat_ica_xcRB { |
| @@ -869,6 +995,11 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd, | |||
| 869 | do { | 995 | do { |
| 870 | rc = zcrypt_send_cprb(&xcRB64); | 996 | rc = zcrypt_send_cprb(&xcRB64); |
| 871 | } while (rc == -EAGAIN); | 997 | } while (rc == -EAGAIN); |
| 998 | /* on failure: retry once again after a requested rescan */ | ||
| 999 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) | ||
| 1000 | do { | ||
| 1001 | rc = zcrypt_send_cprb(&xcRB64); | ||
| 1002 | } while (rc == -EAGAIN); | ||
| 872 | xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length; | 1003 | xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length; |
| 873 | xcRB32.reply_data_length = xcRB64.reply_data_length; | 1004 | xcRB32.reply_data_length = xcRB64.reply_data_length; |
| 874 | xcRB32.status = xcRB64.status; | 1005 | xcRB32.status = xcRB64.status; |
| @@ -1126,6 +1257,9 @@ static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data) | |||
| 1126 | */ | 1257 | */ |
| 1127 | if (zcrypt_rng_buffer_index == 0) { | 1258 | if (zcrypt_rng_buffer_index == 0) { |
| 1128 | rc = zcrypt_rng((char *) zcrypt_rng_buffer); | 1259 | rc = zcrypt_rng((char *) zcrypt_rng_buffer); |
| 1260 | /* on failure: retry once again after a requested rescan */ | ||
| 1261 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) | ||
| 1262 | rc = zcrypt_rng((char *) zcrypt_rng_buffer); | ||
| 1129 | if (rc < 0) | 1263 | if (rc < 0) |
| 1130 | return -EIO; | 1264 | return -EIO; |
| 1131 | zcrypt_rng_buffer_index = rc / sizeof *data; | 1265 | zcrypt_rng_buffer_index = rc / sizeof *data; |
| @@ -1178,6 +1312,30 @@ static void zcrypt_rng_device_remove(void) | |||
| 1178 | mutex_unlock(&zcrypt_rng_mutex); | 1312 | mutex_unlock(&zcrypt_rng_mutex); |
| 1179 | } | 1313 | } |
| 1180 | 1314 | ||
| 1315 | int __init zcrypt_debug_init(void) | ||
| 1316 | { | ||
| 1317 | debugfs_root = debugfs_create_dir("zcrypt", NULL); | ||
| 1318 | |||
| 1319 | zcrypt_dbf_common = debug_register("zcrypt_common", 1, 1, 16); | ||
| 1320 | debug_register_view(zcrypt_dbf_common, &debug_hex_ascii_view); | ||
| 1321 | debug_set_level(zcrypt_dbf_common, DBF_ERR); | ||
| 1322 | |||
| 1323 | zcrypt_dbf_devices = debug_register("zcrypt_devices", 1, 1, 16); | ||
| 1324 | debug_register_view(zcrypt_dbf_devices, &debug_hex_ascii_view); | ||
| 1325 | debug_set_level(zcrypt_dbf_devices, DBF_ERR); | ||
| 1326 | |||
| 1327 | return 0; | ||
| 1328 | } | ||
| 1329 | |||
| 1330 | void zcrypt_debug_exit(void) | ||
| 1331 | { | ||
| 1332 | debugfs_remove(debugfs_root); | ||
| 1333 | if (zcrypt_dbf_common) | ||
| 1334 | debug_unregister(zcrypt_dbf_common); | ||
| 1335 | if (zcrypt_dbf_devices) | ||
| 1336 | debug_unregister(zcrypt_dbf_devices); | ||
| 1337 | } | ||
| 1338 | |||
| 1181 | /** | 1339 | /** |
| 1182 | * zcrypt_api_init(): Module initialization. | 1340 | * zcrypt_api_init(): Module initialization. |
| 1183 | * | 1341 | * |
| @@ -1187,6 +1345,12 @@ int __init zcrypt_api_init(void) | |||
| 1187 | { | 1345 | { |
| 1188 | int rc; | 1346 | int rc; |
| 1189 | 1347 | ||
| 1348 | rc = zcrypt_debug_init(); | ||
| 1349 | if (rc) | ||
| 1350 | goto out; | ||
| 1351 | |||
| 1352 | atomic_set(&zcrypt_rescan_req, 0); | ||
| 1353 | |||
| 1190 | /* Register the request sprayer. */ | 1354 | /* Register the request sprayer. */ |
| 1191 | rc = misc_register(&zcrypt_misc_device); | 1355 | rc = misc_register(&zcrypt_misc_device); |
| 1192 | if (rc < 0) | 1356 | if (rc < 0) |
| @@ -1216,6 +1380,7 @@ void zcrypt_api_exit(void) | |||
| 1216 | { | 1380 | { |
| 1217 | remove_proc_entry("driver/z90crypt", NULL); | 1381 | remove_proc_entry("driver/z90crypt", NULL); |
| 1218 | misc_deregister(&zcrypt_misc_device); | 1382 | misc_deregister(&zcrypt_misc_device); |
| 1383 | zcrypt_debug_exit(); | ||
| 1219 | } | 1384 | } |
| 1220 | 1385 | ||
| 1221 | module_init(zcrypt_api_init); | 1386 | module_init(zcrypt_api_init); |
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 7a32c4bc8ef9..89632919c993 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * zcrypt 2.1.0 | 2 | * zcrypt 2.1.0 |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2001, 2006 | 4 | * Copyright IBM Corp. 2001, 2012 |
| 5 | * Author(s): Robert Burroughs | 5 | * Author(s): Robert Burroughs |
| 6 | * Eric Rossman (edrossma@us.ibm.com) | 6 | * Eric Rossman (edrossma@us.ibm.com) |
| 7 | * Cornelia Huck <cornelia.huck@de.ibm.com> | 7 | * Cornelia Huck <cornelia.huck@de.ibm.com> |
| @@ -9,6 +9,7 @@ | |||
| 9 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | 9 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
| 10 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | 10 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 11 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 11 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| 12 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 12 | * | 13 | * |
| 13 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
| 14 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
| @@ -28,8 +29,10 @@ | |||
| 28 | #ifndef _ZCRYPT_API_H_ | 29 | #ifndef _ZCRYPT_API_H_ |
| 29 | #define _ZCRYPT_API_H_ | 30 | #define _ZCRYPT_API_H_ |
| 30 | 31 | ||
| 31 | #include "ap_bus.h" | 32 | #include <linux/atomic.h> |
| 33 | #include <asm/debug.h> | ||
| 32 | #include <asm/zcrypt.h> | 34 | #include <asm/zcrypt.h> |
| 35 | #include "ap_bus.h" | ||
| 33 | 36 | ||
| 34 | /* deprecated status calls */ | 37 | /* deprecated status calls */ |
| 35 | #define ICAZ90STATUS _IOR(ZCRYPT_IOCTL_MAGIC, 0x10, struct ica_z90_status) | 38 | #define ICAZ90STATUS _IOR(ZCRYPT_IOCTL_MAGIC, 0x10, struct ica_z90_status) |
| @@ -87,6 +90,9 @@ struct zcrypt_ops { | |||
| 87 | struct ica_rsa_modexpo_crt *); | 90 | struct ica_rsa_modexpo_crt *); |
| 88 | long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *); | 91 | long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *); |
| 89 | long (*rng)(struct zcrypt_device *, char *); | 92 | long (*rng)(struct zcrypt_device *, char *); |
| 93 | struct list_head list; /* zcrypt ops list. */ | ||
| 94 | struct module *owner; | ||
| 95 | int variant; | ||
| 90 | }; | 96 | }; |
| 91 | 97 | ||
| 92 | struct zcrypt_device { | 98 | struct zcrypt_device { |
| @@ -108,14 +114,23 @@ struct zcrypt_device { | |||
| 108 | 114 | ||
| 109 | struct ap_message reply; /* Per-device reply structure. */ | 115 | struct ap_message reply; /* Per-device reply structure. */ |
| 110 | int max_exp_bit_length; | 116 | int max_exp_bit_length; |
| 117 | |||
| 118 | debug_info_t *dbf_area; /* debugging */ | ||
| 111 | }; | 119 | }; |
| 112 | 120 | ||
| 121 | /* transport layer rescanning */ | ||
| 122 | extern atomic_t zcrypt_rescan_req; | ||
| 123 | |||
| 113 | struct zcrypt_device *zcrypt_device_alloc(size_t); | 124 | struct zcrypt_device *zcrypt_device_alloc(size_t); |
| 114 | void zcrypt_device_free(struct zcrypt_device *); | 125 | void zcrypt_device_free(struct zcrypt_device *); |
| 115 | void zcrypt_device_get(struct zcrypt_device *); | 126 | void zcrypt_device_get(struct zcrypt_device *); |
| 116 | int zcrypt_device_put(struct zcrypt_device *); | 127 | int zcrypt_device_put(struct zcrypt_device *); |
| 117 | int zcrypt_device_register(struct zcrypt_device *); | 128 | int zcrypt_device_register(struct zcrypt_device *); |
| 118 | void zcrypt_device_unregister(struct zcrypt_device *); | 129 | void zcrypt_device_unregister(struct zcrypt_device *); |
| 130 | void zcrypt_msgtype_register(struct zcrypt_ops *); | ||
| 131 | void zcrypt_msgtype_unregister(struct zcrypt_ops *); | ||
| 132 | struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *, int); | ||
| 133 | void zcrypt_msgtype_release(struct zcrypt_ops *); | ||
| 119 | int zcrypt_api_init(void); | 134 | int zcrypt_api_init(void); |
| 120 | void zcrypt_api_exit(void); | 135 | void zcrypt_api_exit(void); |
| 121 | 136 | ||
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 744c668f586c..1e849d6e1dfe 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * zcrypt 2.1.0 | 2 | * zcrypt 2.1.0 |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2001, 2006 | 4 | * Copyright IBM Corp. 2001, 2012 |
| 5 | * Author(s): Robert Burroughs | 5 | * Author(s): Robert Burroughs |
| 6 | * Eric Rossman (edrossma@us.ibm.com) | 6 | * Eric Rossman (edrossma@us.ibm.com) |
| 7 | * | 7 | * |
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| 11 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 11 | * | 12 | * |
| 12 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
| @@ -35,6 +36,7 @@ | |||
| 35 | #include "zcrypt_api.h" | 36 | #include "zcrypt_api.h" |
| 36 | #include "zcrypt_error.h" | 37 | #include "zcrypt_error.h" |
| 37 | #include "zcrypt_cex2a.h" | 38 | #include "zcrypt_cex2a.h" |
| 39 | #include "zcrypt_msgtype50.h" | ||
| 38 | 40 | ||
| 39 | #define CEX2A_MIN_MOD_SIZE 1 /* 8 bits */ | 41 | #define CEX2A_MIN_MOD_SIZE 1 /* 8 bits */ |
| 40 | #define CEX2A_MAX_MOD_SIZE 256 /* 2048 bits */ | 42 | #define CEX2A_MAX_MOD_SIZE 256 /* 2048 bits */ |
| @@ -63,14 +65,12 @@ static struct ap_device_id zcrypt_cex2a_ids[] = { | |||
| 63 | 65 | ||
| 64 | MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids); | 66 | MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids); |
| 65 | MODULE_AUTHOR("IBM Corporation"); | 67 | MODULE_AUTHOR("IBM Corporation"); |
| 66 | MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " | 68 | MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " \ |
| 67 | "Copyright IBM Corp. 2001, 2006"); | 69 | "Copyright IBM Corp. 2001, 2012"); |
| 68 | MODULE_LICENSE("GPL"); | 70 | MODULE_LICENSE("GPL"); |
| 69 | 71 | ||
| 70 | static int zcrypt_cex2a_probe(struct ap_device *ap_dev); | 72 | static int zcrypt_cex2a_probe(struct ap_device *ap_dev); |
| 71 | static void zcrypt_cex2a_remove(struct ap_device *ap_dev); | 73 | static void zcrypt_cex2a_remove(struct ap_device *ap_dev); |
| 72 | static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *, | ||
| 73 | struct ap_message *); | ||
| 74 | 74 | ||
| 75 | static struct ap_driver zcrypt_cex2a_driver = { | 75 | static struct ap_driver zcrypt_cex2a_driver = { |
| 76 | .probe = zcrypt_cex2a_probe, | 76 | .probe = zcrypt_cex2a_probe, |
| @@ -80,344 +80,6 @@ static struct ap_driver zcrypt_cex2a_driver = { | |||
| 80 | }; | 80 | }; |
| 81 | 81 | ||
| 82 | /** | 82 | /** |
| 83 | * Convert a ICAMEX message to a type50 MEX message. | ||
| 84 | * | ||
| 85 | * @zdev: crypto device pointer | ||
| 86 | * @zreq: crypto request pointer | ||
| 87 | * @mex: pointer to user input data | ||
| 88 | * | ||
| 89 | * Returns 0 on success or -EFAULT. | ||
| 90 | */ | ||
| 91 | static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev, | ||
| 92 | struct ap_message *ap_msg, | ||
| 93 | struct ica_rsa_modexpo *mex) | ||
| 94 | { | ||
| 95 | unsigned char *mod, *exp, *inp; | ||
| 96 | int mod_len; | ||
| 97 | |||
| 98 | mod_len = mex->inputdatalength; | ||
| 99 | |||
| 100 | if (mod_len <= 128) { | ||
| 101 | struct type50_meb1_msg *meb1 = ap_msg->message; | ||
| 102 | memset(meb1, 0, sizeof(*meb1)); | ||
| 103 | ap_msg->length = sizeof(*meb1); | ||
| 104 | meb1->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 105 | meb1->header.msg_len = sizeof(*meb1); | ||
| 106 | meb1->keyblock_type = TYPE50_MEB1_FMT; | ||
| 107 | mod = meb1->modulus + sizeof(meb1->modulus) - mod_len; | ||
| 108 | exp = meb1->exponent + sizeof(meb1->exponent) - mod_len; | ||
| 109 | inp = meb1->message + sizeof(meb1->message) - mod_len; | ||
| 110 | } else if (mod_len <= 256) { | ||
| 111 | struct type50_meb2_msg *meb2 = ap_msg->message; | ||
| 112 | memset(meb2, 0, sizeof(*meb2)); | ||
| 113 | ap_msg->length = sizeof(*meb2); | ||
| 114 | meb2->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 115 | meb2->header.msg_len = sizeof(*meb2); | ||
| 116 | meb2->keyblock_type = TYPE50_MEB2_FMT; | ||
| 117 | mod = meb2->modulus + sizeof(meb2->modulus) - mod_len; | ||
| 118 | exp = meb2->exponent + sizeof(meb2->exponent) - mod_len; | ||
| 119 | inp = meb2->message + sizeof(meb2->message) - mod_len; | ||
| 120 | } else { | ||
| 121 | /* mod_len > 256 = 4096 bit RSA Key */ | ||
| 122 | struct type50_meb3_msg *meb3 = ap_msg->message; | ||
| 123 | memset(meb3, 0, sizeof(*meb3)); | ||
| 124 | ap_msg->length = sizeof(*meb3); | ||
| 125 | meb3->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 126 | meb3->header.msg_len = sizeof(*meb3); | ||
| 127 | meb3->keyblock_type = TYPE50_MEB3_FMT; | ||
| 128 | mod = meb3->modulus + sizeof(meb3->modulus) - mod_len; | ||
| 129 | exp = meb3->exponent + sizeof(meb3->exponent) - mod_len; | ||
| 130 | inp = meb3->message + sizeof(meb3->message) - mod_len; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (copy_from_user(mod, mex->n_modulus, mod_len) || | ||
| 134 | copy_from_user(exp, mex->b_key, mod_len) || | ||
| 135 | copy_from_user(inp, mex->inputdata, mod_len)) | ||
| 136 | return -EFAULT; | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | /** | ||
| 141 | * Convert a ICACRT message to a type50 CRT message. | ||
| 142 | * | ||
| 143 | * @zdev: crypto device pointer | ||
| 144 | * @zreq: crypto request pointer | ||
| 145 | * @crt: pointer to user input data | ||
| 146 | * | ||
| 147 | * Returns 0 on success or -EFAULT. | ||
| 148 | */ | ||
| 149 | static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, | ||
| 150 | struct ap_message *ap_msg, | ||
| 151 | struct ica_rsa_modexpo_crt *crt) | ||
| 152 | { | ||
| 153 | int mod_len, short_len, long_len, long_offset, limit; | ||
| 154 | unsigned char *p, *q, *dp, *dq, *u, *inp; | ||
| 155 | |||
| 156 | mod_len = crt->inputdatalength; | ||
| 157 | short_len = mod_len / 2; | ||
| 158 | long_len = mod_len / 2 + 8; | ||
| 159 | |||
| 160 | /* | ||
| 161 | * CEX2A cannot handle p, dp, or U > 128 bytes. | ||
| 162 | * If we have one of these, we need to do extra checking. | ||
| 163 | * For CEX3A the limit is 256 bytes. | ||
| 164 | */ | ||
| 165 | if (zdev->max_mod_size == CEX3A_MAX_MOD_SIZE) | ||
| 166 | limit = 256; | ||
| 167 | else | ||
| 168 | limit = 128; | ||
| 169 | |||
| 170 | if (long_len > limit) { | ||
| 171 | /* | ||
| 172 | * zcrypt_rsa_crt already checked for the leading | ||
| 173 | * zeroes of np_prime, bp_key and u_mult_inc. | ||
| 174 | */ | ||
| 175 | long_offset = long_len - limit; | ||
| 176 | long_len = limit; | ||
| 177 | } else | ||
| 178 | long_offset = 0; | ||
| 179 | |||
| 180 | /* | ||
| 181 | * Instead of doing extra work for p, dp, U > 64 bytes, we'll just use | ||
| 182 | * the larger message structure. | ||
| 183 | */ | ||
| 184 | if (long_len <= 64) { | ||
| 185 | struct type50_crb1_msg *crb1 = ap_msg->message; | ||
| 186 | memset(crb1, 0, sizeof(*crb1)); | ||
| 187 | ap_msg->length = sizeof(*crb1); | ||
| 188 | crb1->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 189 | crb1->header.msg_len = sizeof(*crb1); | ||
| 190 | crb1->keyblock_type = TYPE50_CRB1_FMT; | ||
| 191 | p = crb1->p + sizeof(crb1->p) - long_len; | ||
| 192 | q = crb1->q + sizeof(crb1->q) - short_len; | ||
| 193 | dp = crb1->dp + sizeof(crb1->dp) - long_len; | ||
| 194 | dq = crb1->dq + sizeof(crb1->dq) - short_len; | ||
| 195 | u = crb1->u + sizeof(crb1->u) - long_len; | ||
| 196 | inp = crb1->message + sizeof(crb1->message) - mod_len; | ||
| 197 | } else if (long_len <= 128) { | ||
| 198 | struct type50_crb2_msg *crb2 = ap_msg->message; | ||
| 199 | memset(crb2, 0, sizeof(*crb2)); | ||
| 200 | ap_msg->length = sizeof(*crb2); | ||
| 201 | crb2->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 202 | crb2->header.msg_len = sizeof(*crb2); | ||
| 203 | crb2->keyblock_type = TYPE50_CRB2_FMT; | ||
| 204 | p = crb2->p + sizeof(crb2->p) - long_len; | ||
| 205 | q = crb2->q + sizeof(crb2->q) - short_len; | ||
| 206 | dp = crb2->dp + sizeof(crb2->dp) - long_len; | ||
| 207 | dq = crb2->dq + sizeof(crb2->dq) - short_len; | ||
| 208 | u = crb2->u + sizeof(crb2->u) - long_len; | ||
| 209 | inp = crb2->message + sizeof(crb2->message) - mod_len; | ||
| 210 | } else { | ||
| 211 | /* long_len >= 256 */ | ||
| 212 | struct type50_crb3_msg *crb3 = ap_msg->message; | ||
| 213 | memset(crb3, 0, sizeof(*crb3)); | ||
| 214 | ap_msg->length = sizeof(*crb3); | ||
| 215 | crb3->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 216 | crb3->header.msg_len = sizeof(*crb3); | ||
| 217 | crb3->keyblock_type = TYPE50_CRB3_FMT; | ||
| 218 | p = crb3->p + sizeof(crb3->p) - long_len; | ||
| 219 | q = crb3->q + sizeof(crb3->q) - short_len; | ||
| 220 | dp = crb3->dp + sizeof(crb3->dp) - long_len; | ||
| 221 | dq = crb3->dq + sizeof(crb3->dq) - short_len; | ||
| 222 | u = crb3->u + sizeof(crb3->u) - long_len; | ||
| 223 | inp = crb3->message + sizeof(crb3->message) - mod_len; | ||
| 224 | } | ||
| 225 | |||
| 226 | if (copy_from_user(p, crt->np_prime + long_offset, long_len) || | ||
| 227 | copy_from_user(q, crt->nq_prime, short_len) || | ||
| 228 | copy_from_user(dp, crt->bp_key + long_offset, long_len) || | ||
| 229 | copy_from_user(dq, crt->bq_key, short_len) || | ||
| 230 | copy_from_user(u, crt->u_mult_inv + long_offset, long_len) || | ||
| 231 | copy_from_user(inp, crt->inputdata, mod_len)) | ||
| 232 | return -EFAULT; | ||
| 233 | |||
| 234 | return 0; | ||
| 235 | } | ||
| 236 | |||
| 237 | /** | ||
| 238 | * Copy results from a type 80 reply message back to user space. | ||
| 239 | * | ||
| 240 | * @zdev: crypto device pointer | ||
| 241 | * @reply: reply AP message. | ||
| 242 | * @data: pointer to user output data | ||
| 243 | * @length: size of user output data | ||
| 244 | * | ||
| 245 | * Returns 0 on success or -EFAULT. | ||
| 246 | */ | ||
| 247 | static int convert_type80(struct zcrypt_device *zdev, | ||
| 248 | struct ap_message *reply, | ||
| 249 | char __user *outputdata, | ||
| 250 | unsigned int outputdatalength) | ||
| 251 | { | ||
| 252 | struct type80_hdr *t80h = reply->message; | ||
| 253 | unsigned char *data; | ||
| 254 | |||
| 255 | if (t80h->len < sizeof(*t80h) + outputdatalength) { | ||
| 256 | /* The result is too short, the CEX2A card may not do that.. */ | ||
| 257 | zdev->online = 0; | ||
| 258 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 259 | } | ||
| 260 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 261 | BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE); | ||
| 262 | else | ||
| 263 | BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE); | ||
| 264 | data = reply->message + t80h->len - outputdatalength; | ||
| 265 | if (copy_to_user(outputdata, data, outputdatalength)) | ||
| 266 | return -EFAULT; | ||
| 267 | return 0; | ||
| 268 | } | ||
| 269 | |||
| 270 | static int convert_response(struct zcrypt_device *zdev, | ||
| 271 | struct ap_message *reply, | ||
| 272 | char __user *outputdata, | ||
| 273 | unsigned int outputdatalength) | ||
| 274 | { | ||
| 275 | /* Response type byte is the second byte in the response. */ | ||
| 276 | switch (((unsigned char *) reply->message)[1]) { | ||
| 277 | case TYPE82_RSP_CODE: | ||
| 278 | case TYPE88_RSP_CODE: | ||
| 279 | return convert_error(zdev, reply); | ||
| 280 | case TYPE80_RSP_CODE: | ||
| 281 | return convert_type80(zdev, reply, | ||
| 282 | outputdata, outputdatalength); | ||
| 283 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 284 | zdev->online = 0; | ||
| 285 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | /** | ||
| 290 | * This function is called from the AP bus code after a crypto request | ||
| 291 | * "msg" has finished with the reply message "reply". | ||
| 292 | * It is called from tasklet context. | ||
| 293 | * @ap_dev: pointer to the AP device | ||
| 294 | * @msg: pointer to the AP message | ||
| 295 | * @reply: pointer to the AP reply message | ||
| 296 | */ | ||
| 297 | static void zcrypt_cex2a_receive(struct ap_device *ap_dev, | ||
| 298 | struct ap_message *msg, | ||
| 299 | struct ap_message *reply) | ||
| 300 | { | ||
| 301 | static struct error_hdr error_reply = { | ||
| 302 | .type = TYPE82_RSP_CODE, | ||
| 303 | .reply_code = REP82_ERROR_MACHINE_FAILURE, | ||
| 304 | }; | ||
| 305 | struct type80_hdr *t80h; | ||
| 306 | int length; | ||
| 307 | |||
| 308 | /* Copy the reply message to the request message buffer. */ | ||
| 309 | if (IS_ERR(reply)) { | ||
| 310 | memcpy(msg->message, &error_reply, sizeof(error_reply)); | ||
| 311 | goto out; | ||
| 312 | } | ||
| 313 | t80h = reply->message; | ||
| 314 | if (t80h->type == TYPE80_RSP_CODE) { | ||
| 315 | if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A) | ||
| 316 | length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len); | ||
| 317 | else | ||
| 318 | length = min(CEX3A_MAX_RESPONSE_SIZE, (int) t80h->len); | ||
| 319 | memcpy(msg->message, reply->message, length); | ||
| 320 | } else | ||
| 321 | memcpy(msg->message, reply->message, sizeof error_reply); | ||
| 322 | out: | ||
| 323 | complete((struct completion *) msg->private); | ||
| 324 | } | ||
| 325 | |||
| 326 | static atomic_t zcrypt_step = ATOMIC_INIT(0); | ||
| 327 | |||
| 328 | /** | ||
| 329 | * The request distributor calls this function if it picked the CEX2A | ||
| 330 | * device to handle a modexpo request. | ||
| 331 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 332 | * CEX2A device to the request distributor | ||
| 333 | * @mex: pointer to the modexpo request buffer | ||
| 334 | */ | ||
| 335 | static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, | ||
| 336 | struct ica_rsa_modexpo *mex) | ||
| 337 | { | ||
| 338 | struct ap_message ap_msg; | ||
| 339 | struct completion work; | ||
| 340 | int rc; | ||
| 341 | |||
| 342 | ap_init_message(&ap_msg); | ||
| 343 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 344 | ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL); | ||
| 345 | else | ||
| 346 | ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL); | ||
| 347 | if (!ap_msg.message) | ||
| 348 | return -ENOMEM; | ||
| 349 | ap_msg.receive = zcrypt_cex2a_receive; | ||
| 350 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 351 | atomic_inc_return(&zcrypt_step); | ||
| 352 | ap_msg.private = &work; | ||
| 353 | rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex); | ||
| 354 | if (rc) | ||
| 355 | goto out_free; | ||
| 356 | init_completion(&work); | ||
| 357 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 358 | rc = wait_for_completion_interruptible(&work); | ||
| 359 | if (rc == 0) | ||
| 360 | rc = convert_response(zdev, &ap_msg, mex->outputdata, | ||
| 361 | mex->outputdatalength); | ||
| 362 | else | ||
| 363 | /* Signal pending. */ | ||
| 364 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 365 | out_free: | ||
| 366 | kfree(ap_msg.message); | ||
| 367 | return rc; | ||
| 368 | } | ||
| 369 | |||
| 370 | /** | ||
| 371 | * The request distributor calls this function if it picked the CEX2A | ||
| 372 | * device to handle a modexpo_crt request. | ||
| 373 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 374 | * CEX2A device to the request distributor | ||
| 375 | * @crt: pointer to the modexpoc_crt request buffer | ||
| 376 | */ | ||
| 377 | static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, | ||
| 378 | struct ica_rsa_modexpo_crt *crt) | ||
| 379 | { | ||
| 380 | struct ap_message ap_msg; | ||
| 381 | struct completion work; | ||
| 382 | int rc; | ||
| 383 | |||
| 384 | ap_init_message(&ap_msg); | ||
| 385 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 386 | ap_msg.message = kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL); | ||
| 387 | else | ||
| 388 | ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL); | ||
| 389 | if (!ap_msg.message) | ||
| 390 | return -ENOMEM; | ||
| 391 | ap_msg.receive = zcrypt_cex2a_receive; | ||
| 392 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 393 | atomic_inc_return(&zcrypt_step); | ||
| 394 | ap_msg.private = &work; | ||
| 395 | rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt); | ||
| 396 | if (rc) | ||
| 397 | goto out_free; | ||
| 398 | init_completion(&work); | ||
| 399 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 400 | rc = wait_for_completion_interruptible(&work); | ||
| 401 | if (rc == 0) | ||
| 402 | rc = convert_response(zdev, &ap_msg, crt->outputdata, | ||
| 403 | crt->outputdatalength); | ||
| 404 | else | ||
| 405 | /* Signal pending. */ | ||
| 406 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 407 | out_free: | ||
| 408 | kfree(ap_msg.message); | ||
| 409 | return rc; | ||
| 410 | } | ||
| 411 | |||
| 412 | /** | ||
| 413 | * The crypto operations for a CEX2A card. | ||
| 414 | */ | ||
| 415 | static struct zcrypt_ops zcrypt_cex2a_ops = { | ||
| 416 | .rsa_modexpo = zcrypt_cex2a_modexpo, | ||
| 417 | .rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt, | ||
| 418 | }; | ||
| 419 | |||
| 420 | /** | ||
| 421 | * Probe function for CEX2A cards. It always accepts the AP device | 83 | * Probe function for CEX2A cards. It always accepts the AP device |
| 422 | * since the bus_match already checked the hardware type. | 84 | * since the bus_match already checked the hardware type. |
| 423 | * @ap_dev: pointer to the AP device. | 85 | * @ap_dev: pointer to the AP device. |
| @@ -449,7 +111,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) | |||
| 449 | zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; | 111 | zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; |
| 450 | zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; | 112 | zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; |
| 451 | zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; | 113 | zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; |
| 452 | if (ap_4096_commands_available(ap_dev->qid)) { | 114 | if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) && |
| 115 | ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) { | ||
| 453 | zdev->max_mod_size = CEX3A_MAX_MOD_SIZE; | 116 | zdev->max_mod_size = CEX3A_MAX_MOD_SIZE; |
| 454 | zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; | 117 | zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; |
| 455 | } | 118 | } |
| @@ -457,16 +120,18 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) | |||
| 457 | zdev->speed_rating = CEX3A_SPEED_RATING; | 120 | zdev->speed_rating = CEX3A_SPEED_RATING; |
| 458 | break; | 121 | break; |
| 459 | } | 122 | } |
| 460 | if (zdev != NULL) { | 123 | if (!zdev) |
| 461 | zdev->ap_dev = ap_dev; | 124 | return -ENODEV; |
| 462 | zdev->ops = &zcrypt_cex2a_ops; | 125 | zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME, |
| 463 | zdev->online = 1; | 126 | MSGTYPE50_VARIANT_DEFAULT); |
| 464 | ap_dev->reply = &zdev->reply; | 127 | zdev->ap_dev = ap_dev; |
| 465 | ap_dev->private = zdev; | 128 | zdev->online = 1; |
| 466 | rc = zcrypt_device_register(zdev); | 129 | ap_dev->reply = &zdev->reply; |
| 467 | } | 130 | ap_dev->private = zdev; |
| 131 | rc = zcrypt_device_register(zdev); | ||
| 468 | if (rc) { | 132 | if (rc) { |
| 469 | ap_dev->private = NULL; | 133 | ap_dev->private = NULL; |
| 134 | zcrypt_msgtype_release(zdev->ops); | ||
| 470 | zcrypt_device_free(zdev); | 135 | zcrypt_device_free(zdev); |
| 471 | } | 136 | } |
| 472 | return rc; | 137 | return rc; |
| @@ -479,8 +144,10 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) | |||
| 479 | static void zcrypt_cex2a_remove(struct ap_device *ap_dev) | 144 | static void zcrypt_cex2a_remove(struct ap_device *ap_dev) |
| 480 | { | 145 | { |
| 481 | struct zcrypt_device *zdev = ap_dev->private; | 146 | struct zcrypt_device *zdev = ap_dev->private; |
| 147 | struct zcrypt_ops *zops = zdev->ops; | ||
| 482 | 148 | ||
| 483 | zcrypt_device_unregister(zdev); | 149 | zcrypt_device_unregister(zdev); |
| 150 | zcrypt_msgtype_release(zops); | ||
| 484 | } | 151 | } |
| 485 | 152 | ||
| 486 | int __init zcrypt_cex2a_init(void) | 153 | int __init zcrypt_cex2a_init(void) |
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c new file mode 100644 index 000000000000..ce1226398ac9 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_cex4.c | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | /* | ||
| 2 | * Copyright IBM Corp. 2012 | ||
| 3 | * Author(s): Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/module.h> | ||
| 7 | #include <linux/slab.h> | ||
| 8 | #include <linux/init.h> | ||
| 9 | #include <linux/err.h> | ||
| 10 | #include <linux/atomic.h> | ||
| 11 | #include <linux/uaccess.h> | ||
| 12 | |||
| 13 | #include "ap_bus.h" | ||
| 14 | #include "zcrypt_api.h" | ||
| 15 | #include "zcrypt_msgtype6.h" | ||
| 16 | #include "zcrypt_msgtype50.h" | ||
| 17 | #include "zcrypt_error.h" | ||
| 18 | #include "zcrypt_cex4.h" | ||
| 19 | |||
| 20 | #define CEX4A_MIN_MOD_SIZE 1 /* 8 bits */ | ||
| 21 | #define CEX4A_MAX_MOD_SIZE_2K 256 /* 2048 bits */ | ||
| 22 | #define CEX4A_MAX_MOD_SIZE_4K 512 /* 4096 bits */ | ||
| 23 | |||
| 24 | #define CEX4C_MIN_MOD_SIZE 16 /* 256 bits */ | ||
| 25 | #define CEX4C_MAX_MOD_SIZE 512 /* 4096 bits */ | ||
| 26 | |||
| 27 | #define CEX4A_SPEED_RATING 900 /* TODO new card, new speed rating */ | ||
| 28 | #define CEX4C_SPEED_RATING 6500 /* TODO new card, new speed rating */ | ||
| 29 | |||
| 30 | #define CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE | ||
| 31 | #define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE | ||
| 32 | |||
| 33 | #define CEX4_CLEANUP_TIME (15*HZ) | ||
| 34 | |||
| 35 | static struct ap_device_id zcrypt_cex4_ids[] = { | ||
| 36 | { AP_DEVICE(AP_DEVICE_TYPE_CEX4) }, | ||
| 37 | { /* end of list */ }, | ||
| 38 | }; | ||
| 39 | |||
| 40 | MODULE_DEVICE_TABLE(ap, zcrypt_cex4_ids); | ||
| 41 | MODULE_AUTHOR("IBM Corporation"); | ||
| 42 | MODULE_DESCRIPTION("CEX4 Cryptographic Card device driver, " \ | ||
| 43 | "Copyright IBM Corp. 2012"); | ||
| 44 | MODULE_LICENSE("GPL"); | ||
| 45 | |||
| 46 | static int zcrypt_cex4_probe(struct ap_device *ap_dev); | ||
| 47 | static void zcrypt_cex4_remove(struct ap_device *ap_dev); | ||
| 48 | |||
| 49 | static struct ap_driver zcrypt_cex4_driver = { | ||
| 50 | .probe = zcrypt_cex4_probe, | ||
| 51 | .remove = zcrypt_cex4_remove, | ||
| 52 | .ids = zcrypt_cex4_ids, | ||
| 53 | .request_timeout = CEX4_CLEANUP_TIME, | ||
| 54 | }; | ||
| 55 | |||
| 56 | /** | ||
| 57 | * Probe function for CEX4 cards. It always accepts the AP device | ||
| 58 | * since the bus_match already checked the hardware type. | ||
| 59 | * @ap_dev: pointer to the AP device. | ||
| 60 | */ | ||
| 61 | static int zcrypt_cex4_probe(struct ap_device *ap_dev) | ||
| 62 | { | ||
| 63 | struct zcrypt_device *zdev = NULL; | ||
| 64 | int rc = 0; | ||
| 65 | |||
| 66 | switch (ap_dev->device_type) { | ||
| 67 | case AP_DEVICE_TYPE_CEX4: | ||
| 68 | if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) { | ||
| 69 | zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE); | ||
| 70 | if (!zdev) | ||
| 71 | return -ENOMEM; | ||
| 72 | zdev->type_string = "CEX4A"; | ||
| 73 | zdev->user_space_type = ZCRYPT_CEX3A; | ||
| 74 | zdev->min_mod_size = CEX4A_MIN_MOD_SIZE; | ||
| 75 | if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) && | ||
| 76 | ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) { | ||
| 77 | zdev->max_mod_size = | ||
| 78 | CEX4A_MAX_MOD_SIZE_4K; | ||
| 79 | zdev->max_exp_bit_length = | ||
| 80 | CEX4A_MAX_MOD_SIZE_4K; | ||
| 81 | } else { | ||
| 82 | zdev->max_mod_size = | ||
| 83 | CEX4A_MAX_MOD_SIZE_2K; | ||
| 84 | zdev->max_exp_bit_length = | ||
| 85 | CEX4A_MAX_MOD_SIZE_2K; | ||
| 86 | } | ||
| 87 | zdev->short_crt = 1; | ||
| 88 | zdev->speed_rating = CEX4A_SPEED_RATING; | ||
| 89 | zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME, | ||
| 90 | MSGTYPE50_VARIANT_DEFAULT); | ||
| 91 | } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) { | ||
| 92 | zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE); | ||
| 93 | if (!zdev) | ||
| 94 | return -ENOMEM; | ||
| 95 | zdev->type_string = "CEX4C"; | ||
| 96 | zdev->user_space_type = ZCRYPT_CEX3C; | ||
| 97 | zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; | ||
| 98 | zdev->max_mod_size = CEX4C_MAX_MOD_SIZE; | ||
| 99 | zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; | ||
| 100 | zdev->short_crt = 0; | ||
| 101 | zdev->speed_rating = CEX4C_SPEED_RATING; | ||
| 102 | zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, | ||
| 103 | MSGTYPE06_VARIANT_DEFAULT); | ||
| 104 | } | ||
| 105 | break; | ||
| 106 | } | ||
| 107 | if (!zdev) | ||
| 108 | return -ENODEV; | ||
| 109 | zdev->ap_dev = ap_dev; | ||
| 110 | zdev->online = 1; | ||
| 111 | ap_dev->reply = &zdev->reply; | ||
| 112 | ap_dev->private = zdev; | ||
| 113 | rc = zcrypt_device_register(zdev); | ||
| 114 | if (rc) { | ||
| 115 | zcrypt_msgtype_release(zdev->ops); | ||
| 116 | ap_dev->private = NULL; | ||
| 117 | zcrypt_device_free(zdev); | ||
| 118 | } | ||
| 119 | return rc; | ||
| 120 | } | ||
| 121 | |||
| 122 | /** | ||
| 123 | * This is called to remove the extended CEX4 driver information | ||
| 124 | * if an AP device is removed. | ||
| 125 | */ | ||
| 126 | static void zcrypt_cex4_remove(struct ap_device *ap_dev) | ||
| 127 | { | ||
| 128 | struct zcrypt_device *zdev = ap_dev->private; | ||
| 129 | struct zcrypt_ops *zops; | ||
| 130 | |||
| 131 | if (zdev) { | ||
| 132 | zops = zdev->ops; | ||
| 133 | zcrypt_device_unregister(zdev); | ||
| 134 | zcrypt_msgtype_release(zops); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | int __init zcrypt_cex4_init(void) | ||
| 139 | { | ||
| 140 | return ap_driver_register(&zcrypt_cex4_driver, THIS_MODULE, "cex4"); | ||
| 141 | } | ||
| 142 | |||
| 143 | void __exit zcrypt_cex4_exit(void) | ||
| 144 | { | ||
| 145 | ap_driver_unregister(&zcrypt_cex4_driver); | ||
| 146 | } | ||
| 147 | |||
| 148 | module_init(zcrypt_cex4_init); | ||
| 149 | module_exit(zcrypt_cex4_exit); | ||
diff --git a/drivers/s390/crypto/zcrypt_cex4.h b/drivers/s390/crypto/zcrypt_cex4.h new file mode 100644 index 000000000000..719571375ccc --- /dev/null +++ b/drivers/s390/crypto/zcrypt_cex4.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | /* | ||
| 2 | * Copyright IBM Corp. 2012 | ||
| 3 | * Author(s): Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef _ZCRYPT_CEX4_H_ | ||
| 7 | #define _ZCRYPT_CEX4_H_ | ||
| 8 | |||
| 9 | int zcrypt_cex4_init(void); | ||
| 10 | void zcrypt_cex4_exit(void); | ||
| 11 | |||
| 12 | #endif /* _ZCRYPT_CEX4_H_ */ | ||
diff --git a/drivers/s390/crypto/zcrypt_debug.h b/drivers/s390/crypto/zcrypt_debug.h new file mode 100644 index 000000000000..841ea72e4a4e --- /dev/null +++ b/drivers/s390/crypto/zcrypt_debug.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | /* | ||
| 2 | * Copyright IBM Corp. 2012 | ||
| 3 | * Author(s): Holger Dengler (hd@linux.vnet.ibm.com) | ||
| 4 | */ | ||
| 5 | #ifndef ZCRYPT_DEBUG_H | ||
| 6 | #define ZCRYPT_DEBUG_H | ||
| 7 | |||
| 8 | #include <asm/debug.h> | ||
| 9 | #include "zcrypt_api.h" | ||
| 10 | |||
| 11 | /* that gives us 15 characters in the text event views */ | ||
| 12 | #define ZCRYPT_DBF_LEN 16 | ||
| 13 | |||
| 14 | /* sort out low debug levels early to avoid wasted sprints */ | ||
| 15 | static inline int zcrypt_dbf_passes(debug_info_t *dbf_grp, int level) | ||
| 16 | { | ||
| 17 | return (level <= dbf_grp->level); | ||
| 18 | } | ||
| 19 | |||
| 20 | #define DBF_ERR 3 /* error conditions */ | ||
| 21 | #define DBF_WARN 4 /* warning conditions */ | ||
| 22 | #define DBF_INFO 6 /* informational */ | ||
| 23 | |||
| 24 | #define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO) | ||
| 25 | |||
| 26 | #define ZCRYPT_DBF_COMMON(level, text...) \ | ||
| 27 | do { \ | ||
| 28 | if (zcrypt_dbf_passes(zcrypt_dbf_common, level)) { \ | ||
| 29 | char debug_buffer[ZCRYPT_DBF_LEN]; \ | ||
| 30 | snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ | ||
| 31 | debug_text_event(zcrypt_dbf_common, level, \ | ||
| 32 | debug_buffer); \ | ||
| 33 | } \ | ||
| 34 | } while (0) | ||
| 35 | |||
| 36 | #define ZCRYPT_DBF_DEVICES(level, text...) \ | ||
| 37 | do { \ | ||
| 38 | if (zcrypt_dbf_passes(zcrypt_dbf_devices, level)) { \ | ||
| 39 | char debug_buffer[ZCRYPT_DBF_LEN]; \ | ||
| 40 | snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ | ||
| 41 | debug_text_event(zcrypt_dbf_devices, level, \ | ||
| 42 | debug_buffer); \ | ||
| 43 | } \ | ||
| 44 | } while (0) | ||
| 45 | |||
| 46 | #define ZCRYPT_DBF_DEV(level, device, text...) \ | ||
| 47 | do { \ | ||
| 48 | if (zcrypt_dbf_passes(device->dbf_area, level)) { \ | ||
| 49 | char debug_buffer[ZCRYPT_DBF_LEN]; \ | ||
| 50 | snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ | ||
| 51 | debug_text_event(device->dbf_area, level, \ | ||
| 52 | debug_buffer); \ | ||
| 53 | } \ | ||
| 54 | } while (0) | ||
| 55 | |||
| 56 | int zcrypt_debug_init(void); | ||
| 57 | void zcrypt_debug_exit(void); | ||
| 58 | |||
| 59 | #endif /* ZCRYPT_DEBUG_H */ | ||
diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index 0965e2626d18..0079b6617211 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h | |||
| @@ -26,6 +26,8 @@ | |||
| 26 | #ifndef _ZCRYPT_ERROR_H_ | 26 | #ifndef _ZCRYPT_ERROR_H_ |
| 27 | #define _ZCRYPT_ERROR_H_ | 27 | #define _ZCRYPT_ERROR_H_ |
| 28 | 28 | ||
| 29 | #include <linux/atomic.h> | ||
| 30 | #include "zcrypt_debug.h" | ||
| 29 | #include "zcrypt_api.h" | 31 | #include "zcrypt_api.h" |
| 30 | 32 | ||
| 31 | /** | 33 | /** |
| @@ -108,16 +110,27 @@ static inline int convert_error(struct zcrypt_device *zdev, | |||
| 108 | * and then repeat the request. | 110 | * and then repeat the request. |
| 109 | */ | 111 | */ |
| 110 | WARN_ON(1); | 112 | WARN_ON(1); |
| 113 | atomic_set(&zcrypt_rescan_req, 1); | ||
| 111 | zdev->online = 0; | 114 | zdev->online = 0; |
| 115 | ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", | ||
| 116 | zdev->ap_dev->qid, | ||
| 117 | zdev->online, ehdr->reply_code); | ||
| 112 | return -EAGAIN; | 118 | return -EAGAIN; |
| 113 | case REP82_ERROR_TRANSPORT_FAIL: | 119 | case REP82_ERROR_TRANSPORT_FAIL: |
| 114 | case REP82_ERROR_MACHINE_FAILURE: | 120 | case REP82_ERROR_MACHINE_FAILURE: |
| 115 | // REP88_ERROR_MODULE_FAILURE // '10' CEX2A | 121 | // REP88_ERROR_MODULE_FAILURE // '10' CEX2A |
| 116 | /* If a card fails disable it and repeat the request. */ | 122 | /* If a card fails disable it and repeat the request. */ |
| 123 | atomic_set(&zcrypt_rescan_req, 1); | ||
| 117 | zdev->online = 0; | 124 | zdev->online = 0; |
| 125 | ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", | ||
| 126 | zdev->ap_dev->qid, | ||
| 127 | zdev->online, ehdr->reply_code); | ||
| 118 | return -EAGAIN; | 128 | return -EAGAIN; |
| 119 | default: | 129 | default: |
| 120 | zdev->online = 0; | 130 | zdev->online = 0; |
| 131 | ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", | ||
| 132 | zdev->ap_dev->qid, | ||
| 133 | zdev->online, ehdr->reply_code); | ||
| 121 | return -EAGAIN; /* repeat the request on a different device. */ | 134 | return -EAGAIN; /* repeat the request on a different device. */ |
| 122 | } | 135 | } |
| 123 | } | 136 | } |
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c new file mode 100644 index 000000000000..035b6dc31b71 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_msgtype50.c | |||
| @@ -0,0 +1,531 @@ | |||
| 1 | /* | ||
| 2 | * zcrypt 2.1.0 | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2001, 2012 | ||
| 5 | * Author(s): Robert Burroughs | ||
| 6 | * Eric Rossman (edrossma@us.ibm.com) | ||
| 7 | * | ||
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | ||
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | ||
| 11 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License as published by | ||
| 15 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 16 | * any later version. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | * | ||
| 23 | * You should have received a copy of the GNU General Public License | ||
| 24 | * along with this program; if not, write to the Free Software | ||
| 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/slab.h> | ||
| 30 | #include <linux/init.h> | ||
| 31 | #include <linux/err.h> | ||
| 32 | #include <linux/atomic.h> | ||
| 33 | #include <linux/uaccess.h> | ||
| 34 | |||
| 35 | #include "ap_bus.h" | ||
| 36 | #include "zcrypt_api.h" | ||
| 37 | #include "zcrypt_error.h" | ||
| 38 | #include "zcrypt_msgtype50.h" | ||
| 39 | |||
| 40 | #define CEX3A_MAX_MOD_SIZE 512 /* 4096 bits */ | ||
| 41 | |||
| 42 | #define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */ | ||
| 43 | |||
| 44 | #define CEX3A_MAX_RESPONSE_SIZE 0x210 /* 512 bit modulus | ||
| 45 | * (max outputdatalength) + | ||
| 46 | * type80_hdr*/ | ||
| 47 | |||
| 48 | MODULE_AUTHOR("IBM Corporation"); | ||
| 49 | MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \ | ||
| 50 | "Copyright IBM Corp. 2001, 2012"); | ||
| 51 | MODULE_LICENSE("GPL"); | ||
| 52 | |||
| 53 | static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *, | ||
| 54 | struct ap_message *); | ||
| 55 | |||
| 56 | /** | ||
| 57 | * The type 50 message family is associated with a CEX2A card. | ||
| 58 | * | ||
| 59 | * The four members of the family are described below. | ||
| 60 | * | ||
| 61 | * Note that all unsigned char arrays are right-justified and left-padded | ||
| 62 | * with zeroes. | ||
| 63 | * | ||
| 64 | * Note that all reserved fields must be zeroes. | ||
| 65 | */ | ||
| 66 | struct type50_hdr { | ||
| 67 | unsigned char reserved1; | ||
| 68 | unsigned char msg_type_code; /* 0x50 */ | ||
| 69 | unsigned short msg_len; | ||
| 70 | unsigned char reserved2; | ||
| 71 | unsigned char ignored; | ||
| 72 | unsigned short reserved3; | ||
| 73 | } __packed; | ||
| 74 | |||
| 75 | #define TYPE50_TYPE_CODE 0x50 | ||
| 76 | |||
| 77 | #define TYPE50_MEB1_FMT 0x0001 | ||
| 78 | #define TYPE50_MEB2_FMT 0x0002 | ||
| 79 | #define TYPE50_MEB3_FMT 0x0003 | ||
| 80 | #define TYPE50_CRB1_FMT 0x0011 | ||
| 81 | #define TYPE50_CRB2_FMT 0x0012 | ||
| 82 | #define TYPE50_CRB3_FMT 0x0013 | ||
| 83 | |||
| 84 | /* Mod-Exp, with a small modulus */ | ||
| 85 | struct type50_meb1_msg { | ||
| 86 | struct type50_hdr header; | ||
| 87 | unsigned short keyblock_type; /* 0x0001 */ | ||
| 88 | unsigned char reserved[6]; | ||
| 89 | unsigned char exponent[128]; | ||
| 90 | unsigned char modulus[128]; | ||
| 91 | unsigned char message[128]; | ||
| 92 | } __packed; | ||
| 93 | |||
| 94 | /* Mod-Exp, with a large modulus */ | ||
| 95 | struct type50_meb2_msg { | ||
| 96 | struct type50_hdr header; | ||
| 97 | unsigned short keyblock_type; /* 0x0002 */ | ||
| 98 | unsigned char reserved[6]; | ||
| 99 | unsigned char exponent[256]; | ||
| 100 | unsigned char modulus[256]; | ||
| 101 | unsigned char message[256]; | ||
| 102 | } __packed; | ||
| 103 | |||
| 104 | /* Mod-Exp, with a larger modulus */ | ||
| 105 | struct type50_meb3_msg { | ||
| 106 | struct type50_hdr header; | ||
| 107 | unsigned short keyblock_type; /* 0x0003 */ | ||
| 108 | unsigned char reserved[6]; | ||
| 109 | unsigned char exponent[512]; | ||
| 110 | unsigned char modulus[512]; | ||
| 111 | unsigned char message[512]; | ||
| 112 | } __packed; | ||
| 113 | |||
| 114 | /* CRT, with a small modulus */ | ||
| 115 | struct type50_crb1_msg { | ||
| 116 | struct type50_hdr header; | ||
| 117 | unsigned short keyblock_type; /* 0x0011 */ | ||
| 118 | unsigned char reserved[6]; | ||
| 119 | unsigned char p[64]; | ||
| 120 | unsigned char q[64]; | ||
| 121 | unsigned char dp[64]; | ||
| 122 | unsigned char dq[64]; | ||
| 123 | unsigned char u[64]; | ||
| 124 | unsigned char message[128]; | ||
| 125 | } __packed; | ||
| 126 | |||
| 127 | /* CRT, with a large modulus */ | ||
| 128 | struct type50_crb2_msg { | ||
| 129 | struct type50_hdr header; | ||
| 130 | unsigned short keyblock_type; /* 0x0012 */ | ||
| 131 | unsigned char reserved[6]; | ||
| 132 | unsigned char p[128]; | ||
| 133 | unsigned char q[128]; | ||
| 134 | unsigned char dp[128]; | ||
| 135 | unsigned char dq[128]; | ||
| 136 | unsigned char u[128]; | ||
| 137 | unsigned char message[256]; | ||
| 138 | } __packed; | ||
| 139 | |||
| 140 | /* CRT, with a larger modulus */ | ||
| 141 | struct type50_crb3_msg { | ||
| 142 | struct type50_hdr header; | ||
| 143 | unsigned short keyblock_type; /* 0x0013 */ | ||
| 144 | unsigned char reserved[6]; | ||
| 145 | unsigned char p[256]; | ||
| 146 | unsigned char q[256]; | ||
| 147 | unsigned char dp[256]; | ||
| 148 | unsigned char dq[256]; | ||
| 149 | unsigned char u[256]; | ||
| 150 | unsigned char message[512]; | ||
| 151 | } __packed; | ||
| 152 | |||
| 153 | /** | ||
| 154 | * The type 80 response family is associated with a CEX2A card. | ||
| 155 | * | ||
| 156 | * Note that all unsigned char arrays are right-justified and left-padded | ||
| 157 | * with zeroes. | ||
| 158 | * | ||
| 159 | * Note that all reserved fields must be zeroes. | ||
| 160 | */ | ||
| 161 | |||
| 162 | #define TYPE80_RSP_CODE 0x80 | ||
| 163 | |||
| 164 | struct type80_hdr { | ||
| 165 | unsigned char reserved1; | ||
| 166 | unsigned char type; /* 0x80 */ | ||
| 167 | unsigned short len; | ||
| 168 | unsigned char code; /* 0x00 */ | ||
| 169 | unsigned char reserved2[3]; | ||
| 170 | unsigned char reserved3[8]; | ||
| 171 | } __packed; | ||
| 172 | |||
| 173 | /** | ||
| 174 | * Convert a ICAMEX message to a type50 MEX message. | ||
| 175 | * | ||
| 176 | * @zdev: crypto device pointer | ||
| 177 | * @zreq: crypto request pointer | ||
| 178 | * @mex: pointer to user input data | ||
| 179 | * | ||
| 180 | * Returns 0 on success or -EFAULT. | ||
| 181 | */ | ||
| 182 | static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev, | ||
| 183 | struct ap_message *ap_msg, | ||
| 184 | struct ica_rsa_modexpo *mex) | ||
| 185 | { | ||
| 186 | unsigned char *mod, *exp, *inp; | ||
| 187 | int mod_len; | ||
| 188 | |||
| 189 | mod_len = mex->inputdatalength; | ||
| 190 | |||
| 191 | if (mod_len <= 128) { | ||
| 192 | struct type50_meb1_msg *meb1 = ap_msg->message; | ||
| 193 | memset(meb1, 0, sizeof(*meb1)); | ||
| 194 | ap_msg->length = sizeof(*meb1); | ||
| 195 | meb1->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 196 | meb1->header.msg_len = sizeof(*meb1); | ||
| 197 | meb1->keyblock_type = TYPE50_MEB1_FMT; | ||
| 198 | mod = meb1->modulus + sizeof(meb1->modulus) - mod_len; | ||
| 199 | exp = meb1->exponent + sizeof(meb1->exponent) - mod_len; | ||
| 200 | inp = meb1->message + sizeof(meb1->message) - mod_len; | ||
| 201 | } else if (mod_len <= 256) { | ||
| 202 | struct type50_meb2_msg *meb2 = ap_msg->message; | ||
| 203 | memset(meb2, 0, sizeof(*meb2)); | ||
| 204 | ap_msg->length = sizeof(*meb2); | ||
| 205 | meb2->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 206 | meb2->header.msg_len = sizeof(*meb2); | ||
| 207 | meb2->keyblock_type = TYPE50_MEB2_FMT; | ||
| 208 | mod = meb2->modulus + sizeof(meb2->modulus) - mod_len; | ||
| 209 | exp = meb2->exponent + sizeof(meb2->exponent) - mod_len; | ||
| 210 | inp = meb2->message + sizeof(meb2->message) - mod_len; | ||
| 211 | } else { | ||
| 212 | /* mod_len > 256 = 4096 bit RSA Key */ | ||
| 213 | struct type50_meb3_msg *meb3 = ap_msg->message; | ||
| 214 | memset(meb3, 0, sizeof(*meb3)); | ||
| 215 | ap_msg->length = sizeof(*meb3); | ||
| 216 | meb3->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 217 | meb3->header.msg_len = sizeof(*meb3); | ||
| 218 | meb3->keyblock_type = TYPE50_MEB3_FMT; | ||
| 219 | mod = meb3->modulus + sizeof(meb3->modulus) - mod_len; | ||
| 220 | exp = meb3->exponent + sizeof(meb3->exponent) - mod_len; | ||
| 221 | inp = meb3->message + sizeof(meb3->message) - mod_len; | ||
| 222 | } | ||
| 223 | |||
| 224 | if (copy_from_user(mod, mex->n_modulus, mod_len) || | ||
| 225 | copy_from_user(exp, mex->b_key, mod_len) || | ||
| 226 | copy_from_user(inp, mex->inputdata, mod_len)) | ||
| 227 | return -EFAULT; | ||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | /** | ||
| 232 | * Convert a ICACRT message to a type50 CRT message. | ||
| 233 | * | ||
| 234 | * @zdev: crypto device pointer | ||
| 235 | * @zreq: crypto request pointer | ||
| 236 | * @crt: pointer to user input data | ||
| 237 | * | ||
| 238 | * Returns 0 on success or -EFAULT. | ||
| 239 | */ | ||
| 240 | static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, | ||
| 241 | struct ap_message *ap_msg, | ||
| 242 | struct ica_rsa_modexpo_crt *crt) | ||
| 243 | { | ||
| 244 | int mod_len, short_len, long_len, long_offset, limit; | ||
| 245 | unsigned char *p, *q, *dp, *dq, *u, *inp; | ||
| 246 | |||
| 247 | mod_len = crt->inputdatalength; | ||
| 248 | short_len = mod_len / 2; | ||
| 249 | long_len = mod_len / 2 + 8; | ||
| 250 | |||
| 251 | /* | ||
| 252 | * CEX2A cannot handle p, dp, or U > 128 bytes. | ||
| 253 | * If we have one of these, we need to do extra checking. | ||
| 254 | * For CEX3A the limit is 256 bytes. | ||
| 255 | */ | ||
| 256 | if (zdev->max_mod_size == CEX3A_MAX_MOD_SIZE) | ||
| 257 | limit = 256; | ||
| 258 | else | ||
| 259 | limit = 128; | ||
| 260 | |||
| 261 | if (long_len > limit) { | ||
| 262 | /* | ||
| 263 | * zcrypt_rsa_crt already checked for the leading | ||
| 264 | * zeroes of np_prime, bp_key and u_mult_inc. | ||
| 265 | */ | ||
| 266 | long_offset = long_len - limit; | ||
| 267 | long_len = limit; | ||
| 268 | } else | ||
| 269 | long_offset = 0; | ||
| 270 | |||
| 271 | /* | ||
| 272 | * Instead of doing extra work for p, dp, U > 64 bytes, we'll just use | ||
| 273 | * the larger message structure. | ||
| 274 | */ | ||
| 275 | if (long_len <= 64) { | ||
| 276 | struct type50_crb1_msg *crb1 = ap_msg->message; | ||
| 277 | memset(crb1, 0, sizeof(*crb1)); | ||
| 278 | ap_msg->length = sizeof(*crb1); | ||
| 279 | crb1->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 280 | crb1->header.msg_len = sizeof(*crb1); | ||
| 281 | crb1->keyblock_type = TYPE50_CRB1_FMT; | ||
| 282 | p = crb1->p + sizeof(crb1->p) - long_len; | ||
| 283 | q = crb1->q + sizeof(crb1->q) - short_len; | ||
| 284 | dp = crb1->dp + sizeof(crb1->dp) - long_len; | ||
| 285 | dq = crb1->dq + sizeof(crb1->dq) - short_len; | ||
| 286 | u = crb1->u + sizeof(crb1->u) - long_len; | ||
| 287 | inp = crb1->message + sizeof(crb1->message) - mod_len; | ||
| 288 | } else if (long_len <= 128) { | ||
| 289 | struct type50_crb2_msg *crb2 = ap_msg->message; | ||
| 290 | memset(crb2, 0, sizeof(*crb2)); | ||
| 291 | ap_msg->length = sizeof(*crb2); | ||
| 292 | crb2->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 293 | crb2->header.msg_len = sizeof(*crb2); | ||
| 294 | crb2->keyblock_type = TYPE50_CRB2_FMT; | ||
| 295 | p = crb2->p + sizeof(crb2->p) - long_len; | ||
| 296 | q = crb2->q + sizeof(crb2->q) - short_len; | ||
| 297 | dp = crb2->dp + sizeof(crb2->dp) - long_len; | ||
| 298 | dq = crb2->dq + sizeof(crb2->dq) - short_len; | ||
| 299 | u = crb2->u + sizeof(crb2->u) - long_len; | ||
| 300 | inp = crb2->message + sizeof(crb2->message) - mod_len; | ||
| 301 | } else { | ||
| 302 | /* long_len >= 256 */ | ||
| 303 | struct type50_crb3_msg *crb3 = ap_msg->message; | ||
| 304 | memset(crb3, 0, sizeof(*crb3)); | ||
| 305 | ap_msg->length = sizeof(*crb3); | ||
| 306 | crb3->header.msg_type_code = TYPE50_TYPE_CODE; | ||
| 307 | crb3->header.msg_len = sizeof(*crb3); | ||
| 308 | crb3->keyblock_type = TYPE50_CRB3_FMT; | ||
| 309 | p = crb3->p + sizeof(crb3->p) - long_len; | ||
| 310 | q = crb3->q + sizeof(crb3->q) - short_len; | ||
| 311 | dp = crb3->dp + sizeof(crb3->dp) - long_len; | ||
| 312 | dq = crb3->dq + sizeof(crb3->dq) - short_len; | ||
| 313 | u = crb3->u + sizeof(crb3->u) - long_len; | ||
| 314 | inp = crb3->message + sizeof(crb3->message) - mod_len; | ||
| 315 | } | ||
| 316 | |||
| 317 | if (copy_from_user(p, crt->np_prime + long_offset, long_len) || | ||
| 318 | copy_from_user(q, crt->nq_prime, short_len) || | ||
| 319 | copy_from_user(dp, crt->bp_key + long_offset, long_len) || | ||
| 320 | copy_from_user(dq, crt->bq_key, short_len) || | ||
| 321 | copy_from_user(u, crt->u_mult_inv + long_offset, long_len) || | ||
| 322 | copy_from_user(inp, crt->inputdata, mod_len)) | ||
| 323 | return -EFAULT; | ||
| 324 | |||
| 325 | return 0; | ||
| 326 | } | ||
| 327 | |||
| 328 | /** | ||
| 329 | * Copy results from a type 80 reply message back to user space. | ||
| 330 | * | ||
| 331 | * @zdev: crypto device pointer | ||
| 332 | * @reply: reply AP message. | ||
| 333 | * @data: pointer to user output data | ||
| 334 | * @length: size of user output data | ||
| 335 | * | ||
| 336 | * Returns 0 on success or -EFAULT. | ||
| 337 | */ | ||
| 338 | static int convert_type80(struct zcrypt_device *zdev, | ||
| 339 | struct ap_message *reply, | ||
| 340 | char __user *outputdata, | ||
| 341 | unsigned int outputdatalength) | ||
| 342 | { | ||
| 343 | struct type80_hdr *t80h = reply->message; | ||
| 344 | unsigned char *data; | ||
| 345 | |||
| 346 | if (t80h->len < sizeof(*t80h) + outputdatalength) { | ||
| 347 | /* The result is too short, the CEX2A card may not do that.. */ | ||
| 348 | zdev->online = 0; | ||
| 349 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 350 | } | ||
| 351 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 352 | BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE); | ||
| 353 | else | ||
| 354 | BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE); | ||
| 355 | data = reply->message + t80h->len - outputdatalength; | ||
| 356 | if (copy_to_user(outputdata, data, outputdatalength)) | ||
| 357 | return -EFAULT; | ||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | |||
| 361 | static int convert_response(struct zcrypt_device *zdev, | ||
| 362 | struct ap_message *reply, | ||
| 363 | char __user *outputdata, | ||
| 364 | unsigned int outputdatalength) | ||
| 365 | { | ||
| 366 | /* Response type byte is the second byte in the response. */ | ||
| 367 | switch (((unsigned char *) reply->message)[1]) { | ||
| 368 | case TYPE82_RSP_CODE: | ||
| 369 | case TYPE88_RSP_CODE: | ||
| 370 | return convert_error(zdev, reply); | ||
| 371 | case TYPE80_RSP_CODE: | ||
| 372 | return convert_type80(zdev, reply, | ||
| 373 | outputdata, outputdatalength); | ||
| 374 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 375 | zdev->online = 0; | ||
| 376 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | /** | ||
| 381 | * This function is called from the AP bus code after a crypto request | ||
| 382 | * "msg" has finished with the reply message "reply". | ||
| 383 | * It is called from tasklet context. | ||
| 384 | * @ap_dev: pointer to the AP device | ||
| 385 | * @msg: pointer to the AP message | ||
| 386 | * @reply: pointer to the AP reply message | ||
| 387 | */ | ||
| 388 | static void zcrypt_cex2a_receive(struct ap_device *ap_dev, | ||
| 389 | struct ap_message *msg, | ||
| 390 | struct ap_message *reply) | ||
| 391 | { | ||
| 392 | static struct error_hdr error_reply = { | ||
| 393 | .type = TYPE82_RSP_CODE, | ||
| 394 | .reply_code = REP82_ERROR_MACHINE_FAILURE, | ||
| 395 | }; | ||
| 396 | struct type80_hdr *t80h; | ||
| 397 | int length; | ||
| 398 | |||
| 399 | /* Copy the reply message to the request message buffer. */ | ||
| 400 | if (IS_ERR(reply)) { | ||
| 401 | memcpy(msg->message, &error_reply, sizeof(error_reply)); | ||
| 402 | goto out; | ||
| 403 | } | ||
| 404 | t80h = reply->message; | ||
| 405 | if (t80h->type == TYPE80_RSP_CODE) { | ||
| 406 | if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A) | ||
| 407 | length = min_t(int, | ||
| 408 | CEX2A_MAX_RESPONSE_SIZE, t80h->len); | ||
| 409 | else | ||
| 410 | length = min_t(int, | ||
| 411 | CEX3A_MAX_RESPONSE_SIZE, t80h->len); | ||
| 412 | memcpy(msg->message, reply->message, length); | ||
| 413 | } else | ||
| 414 | memcpy(msg->message, reply->message, sizeof(error_reply)); | ||
| 415 | out: | ||
| 416 | complete((struct completion *) msg->private); | ||
| 417 | } | ||
| 418 | |||
| 419 | static atomic_t zcrypt_step = ATOMIC_INIT(0); | ||
| 420 | |||
| 421 | /** | ||
| 422 | * The request distributor calls this function if it picked the CEX2A | ||
| 423 | * device to handle a modexpo request. | ||
| 424 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 425 | * CEX2A device to the request distributor | ||
| 426 | * @mex: pointer to the modexpo request buffer | ||
| 427 | */ | ||
| 428 | static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, | ||
| 429 | struct ica_rsa_modexpo *mex) | ||
| 430 | { | ||
| 431 | struct ap_message ap_msg; | ||
| 432 | struct completion work; | ||
| 433 | int rc; | ||
| 434 | |||
| 435 | ap_init_message(&ap_msg); | ||
| 436 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 437 | ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, | ||
| 438 | GFP_KERNEL); | ||
| 439 | else | ||
| 440 | ap_msg.message = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, | ||
| 441 | GFP_KERNEL); | ||
| 442 | if (!ap_msg.message) | ||
| 443 | return -ENOMEM; | ||
| 444 | ap_msg.receive = zcrypt_cex2a_receive; | ||
| 445 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 446 | atomic_inc_return(&zcrypt_step); | ||
| 447 | ap_msg.private = &work; | ||
| 448 | rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex); | ||
| 449 | if (rc) | ||
| 450 | goto out_free; | ||
| 451 | init_completion(&work); | ||
| 452 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 453 | rc = wait_for_completion_interruptible(&work); | ||
| 454 | if (rc == 0) | ||
| 455 | rc = convert_response(zdev, &ap_msg, mex->outputdata, | ||
| 456 | mex->outputdatalength); | ||
| 457 | else | ||
| 458 | /* Signal pending. */ | ||
| 459 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 460 | out_free: | ||
| 461 | kfree(ap_msg.message); | ||
| 462 | return rc; | ||
| 463 | } | ||
| 464 | |||
| 465 | /** | ||
| 466 | * The request distributor calls this function if it picked the CEX2A | ||
| 467 | * device to handle a modexpo_crt request. | ||
| 468 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 469 | * CEX2A device to the request distributor | ||
| 470 | * @crt: pointer to the modexpoc_crt request buffer | ||
| 471 | */ | ||
| 472 | static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, | ||
| 473 | struct ica_rsa_modexpo_crt *crt) | ||
| 474 | { | ||
| 475 | struct ap_message ap_msg; | ||
| 476 | struct completion work; | ||
| 477 | int rc; | ||
| 478 | |||
| 479 | ap_init_message(&ap_msg); | ||
| 480 | if (zdev->user_space_type == ZCRYPT_CEX2A) | ||
| 481 | ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, | ||
| 482 | GFP_KERNEL); | ||
| 483 | else | ||
| 484 | ap_msg.message = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, | ||
| 485 | GFP_KERNEL); | ||
| 486 | if (!ap_msg.message) | ||
| 487 | return -ENOMEM; | ||
| 488 | ap_msg.receive = zcrypt_cex2a_receive; | ||
| 489 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 490 | atomic_inc_return(&zcrypt_step); | ||
| 491 | ap_msg.private = &work; | ||
| 492 | rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt); | ||
| 493 | if (rc) | ||
| 494 | goto out_free; | ||
| 495 | init_completion(&work); | ||
| 496 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 497 | rc = wait_for_completion_interruptible(&work); | ||
| 498 | if (rc == 0) | ||
| 499 | rc = convert_response(zdev, &ap_msg, crt->outputdata, | ||
| 500 | crt->outputdatalength); | ||
| 501 | else | ||
| 502 | /* Signal pending. */ | ||
| 503 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 504 | out_free: | ||
| 505 | kfree(ap_msg.message); | ||
| 506 | return rc; | ||
| 507 | } | ||
| 508 | |||
| 509 | /** | ||
| 510 | * The crypto operations for message type 50. | ||
| 511 | */ | ||
| 512 | static struct zcrypt_ops zcrypt_msgtype50_ops = { | ||
| 513 | .rsa_modexpo = zcrypt_cex2a_modexpo, | ||
| 514 | .rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt, | ||
| 515 | .owner = THIS_MODULE, | ||
| 516 | .variant = MSGTYPE50_VARIANT_DEFAULT, | ||
| 517 | }; | ||
| 518 | |||
| 519 | int __init zcrypt_msgtype50_init(void) | ||
| 520 | { | ||
| 521 | zcrypt_msgtype_register(&zcrypt_msgtype50_ops); | ||
| 522 | return 0; | ||
| 523 | } | ||
| 524 | |||
| 525 | void __exit zcrypt_msgtype50_exit(void) | ||
| 526 | { | ||
| 527 | zcrypt_msgtype_unregister(&zcrypt_msgtype50_ops); | ||
| 528 | } | ||
| 529 | |||
| 530 | module_init(zcrypt_msgtype50_init); | ||
| 531 | module_exit(zcrypt_msgtype50_exit); | ||
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h new file mode 100644 index 000000000000..e56dc72c7733 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_msgtype50.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* | ||
| 2 | * zcrypt 2.1.0 | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2001, 2012 | ||
| 5 | * Author(s): Robert Burroughs | ||
| 6 | * Eric Rossman (edrossma@us.ibm.com) | ||
| 7 | * | ||
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | ||
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 10 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 15 | * any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef _ZCRYPT_MSGTYPE50_H_ | ||
| 28 | #define _ZCRYPT_MSGTYPE50_H_ | ||
| 29 | |||
| 30 | #define MSGTYPE50_NAME "zcrypt_msgtype50" | ||
| 31 | #define MSGTYPE50_VARIANT_DEFAULT 0 | ||
| 32 | |||
| 33 | #define MSGTYPE50_CRB2_MAX_MSG_SIZE 0x390 /*sizeof(struct type50_crb2_msg)*/ | ||
| 34 | #define MSGTYPE50_CRB3_MAX_MSG_SIZE 0x710 /*sizeof(struct type50_crb3_msg)*/ | ||
| 35 | |||
| 36 | int zcrypt_msgtype50_init(void); | ||
| 37 | void zcrypt_msgtype50_exit(void); | ||
| 38 | |||
| 39 | #endif /* _ZCRYPT_MSGTYPE50_H_ */ | ||
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c new file mode 100644 index 000000000000..7d97fa5a26d0 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_msgtype6.c | |||
| @@ -0,0 +1,856 @@ | |||
| 1 | /* | ||
| 2 | * zcrypt 2.1.0 | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2001, 2012 | ||
| 5 | * Author(s): Robert Burroughs | ||
| 6 | * Eric Rossman (edrossma@us.ibm.com) | ||
| 7 | * | ||
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | ||
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | ||
| 11 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License as published by | ||
| 15 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 16 | * any later version. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | * | ||
| 23 | * You should have received a copy of the GNU General Public License | ||
| 24 | * along with this program; if not, write to the Free Software | ||
| 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/init.h> | ||
| 30 | #include <linux/err.h> | ||
| 31 | #include <linux/delay.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/atomic.h> | ||
| 34 | #include <linux/uaccess.h> | ||
| 35 | |||
| 36 | #include "ap_bus.h" | ||
| 37 | #include "zcrypt_api.h" | ||
| 38 | #include "zcrypt_error.h" | ||
| 39 | #include "zcrypt_msgtype6.h" | ||
| 40 | #include "zcrypt_cca_key.h" | ||
| 41 | |||
| 42 | #define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */ | ||
| 43 | #define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */ | ||
| 44 | |||
| 45 | #define CEIL4(x) ((((x)+3)/4)*4) | ||
| 46 | |||
| 47 | struct response_type { | ||
| 48 | struct completion work; | ||
| 49 | int type; | ||
| 50 | }; | ||
| 51 | #define PCIXCC_RESPONSE_TYPE_ICA 0 | ||
| 52 | #define PCIXCC_RESPONSE_TYPE_XCRB 1 | ||
| 53 | |||
| 54 | MODULE_AUTHOR("IBM Corporation"); | ||
| 55 | MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \ | ||
| 56 | "Copyright IBM Corp. 2001, 2012"); | ||
| 57 | MODULE_LICENSE("GPL"); | ||
| 58 | |||
| 59 | static void zcrypt_msgtype6_receive(struct ap_device *, struct ap_message *, | ||
| 60 | struct ap_message *); | ||
| 61 | |||
| 62 | /** | ||
| 63 | * CPRB | ||
| 64 | * Note that all shorts, ints and longs are little-endian. | ||
| 65 | * All pointer fields are 32-bits long, and mean nothing | ||
| 66 | * | ||
| 67 | * A request CPRB is followed by a request_parameter_block. | ||
| 68 | * | ||
| 69 | * The request (or reply) parameter block is organized thus: | ||
| 70 | * function code | ||
| 71 | * VUD block | ||
| 72 | * key block | ||
| 73 | */ | ||
| 74 | struct CPRB { | ||
| 75 | unsigned short cprb_len; /* CPRB length */ | ||
| 76 | unsigned char cprb_ver_id; /* CPRB version id. */ | ||
| 77 | unsigned char pad_000; /* Alignment pad byte. */ | ||
| 78 | unsigned char srpi_rtcode[4]; /* SRPI return code LELONG */ | ||
| 79 | unsigned char srpi_verb; /* SRPI verb type */ | ||
| 80 | unsigned char flags; /* flags */ | ||
| 81 | unsigned char func_id[2]; /* function id */ | ||
| 82 | unsigned char checkpoint_flag; /* */ | ||
| 83 | unsigned char resv2; /* reserved */ | ||
| 84 | unsigned short req_parml; /* request parameter buffer */ | ||
| 85 | /* length 16-bit little endian */ | ||
| 86 | unsigned char req_parmp[4]; /* request parameter buffer * | ||
| 87 | * pointer (means nothing: the * | ||
| 88 | * parameter buffer follows * | ||
| 89 | * the CPRB). */ | ||
| 90 | unsigned char req_datal[4]; /* request data buffer */ | ||
| 91 | /* length ULELONG */ | ||
| 92 | unsigned char req_datap[4]; /* request data buffer */ | ||
| 93 | /* pointer */ | ||
| 94 | unsigned short rpl_parml; /* reply parameter buffer */ | ||
| 95 | /* length 16-bit little endian */ | ||
| 96 | unsigned char pad_001[2]; /* Alignment pad bytes. ULESHORT */ | ||
| 97 | unsigned char rpl_parmp[4]; /* reply parameter buffer * | ||
| 98 | * pointer (means nothing: the * | ||
| 99 | * parameter buffer follows * | ||
| 100 | * the CPRB). */ | ||
| 101 | unsigned char rpl_datal[4]; /* reply data buffer len ULELONG */ | ||
| 102 | unsigned char rpl_datap[4]; /* reply data buffer */ | ||
| 103 | /* pointer */ | ||
| 104 | unsigned short ccp_rscode; /* server reason code ULESHORT */ | ||
| 105 | unsigned short ccp_rtcode; /* server return code ULESHORT */ | ||
| 106 | unsigned char repd_parml[2]; /* replied parameter len ULESHORT*/ | ||
| 107 | unsigned char mac_data_len[2]; /* Mac Data Length ULESHORT */ | ||
| 108 | unsigned char repd_datal[4]; /* replied data length ULELONG */ | ||
| 109 | unsigned char req_pc[2]; /* PC identifier */ | ||
| 110 | unsigned char res_origin[8]; /* resource origin */ | ||
| 111 | unsigned char mac_value[8]; /* Mac Value */ | ||
| 112 | unsigned char logon_id[8]; /* Logon Identifier */ | ||
| 113 | unsigned char usage_domain[2]; /* cdx */ | ||
| 114 | unsigned char resv3[18]; /* reserved for requestor */ | ||
| 115 | unsigned short svr_namel; /* server name length ULESHORT */ | ||
| 116 | unsigned char svr_name[8]; /* server name */ | ||
| 117 | } __packed; | ||
| 118 | |||
| 119 | struct function_and_rules_block { | ||
| 120 | unsigned char function_code[2]; | ||
| 121 | unsigned short ulen; | ||
| 122 | unsigned char only_rule[8]; | ||
| 123 | } __packed; | ||
| 124 | |||
| 125 | /** | ||
| 126 | * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C | ||
| 127 | * card in a type6 message. The 3 fields that must be filled in at execution | ||
| 128 | * time are req_parml, rpl_parml and usage_domain. | ||
| 129 | * Everything about this interface is ascii/big-endian, since the | ||
| 130 | * device does *not* have 'Intel inside'. | ||
| 131 | * | ||
| 132 | * The CPRBX is followed immediately by the parm block. | ||
| 133 | * The parm block contains: | ||
| 134 | * - function code ('PD' 0x5044 or 'PK' 0x504B) | ||
| 135 | * - rule block (one of:) | ||
| 136 | * + 0x000A 'PKCS-1.2' (MCL2 'PD') | ||
| 137 | * + 0x000A 'ZERO-PAD' (MCL2 'PK') | ||
| 138 | * + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD') | ||
| 139 | * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK') | ||
| 140 | * - VUD block | ||
| 141 | */ | ||
| 142 | static struct CPRBX static_cprbx = { | ||
| 143 | .cprb_len = 0x00DC, | ||
| 144 | .cprb_ver_id = 0x02, | ||
| 145 | .func_id = {0x54, 0x32}, | ||
| 146 | }; | ||
| 147 | |||
| 148 | /** | ||
| 149 | * Convert a ICAMEX message to a type6 MEX message. | ||
| 150 | * | ||
| 151 | * @zdev: crypto device pointer | ||
| 152 | * @ap_msg: pointer to AP message | ||
| 153 | * @mex: pointer to user input data | ||
| 154 | * | ||
| 155 | * Returns 0 on success or -EFAULT. | ||
| 156 | */ | ||
| 157 | static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, | ||
| 158 | struct ap_message *ap_msg, | ||
| 159 | struct ica_rsa_modexpo *mex) | ||
| 160 | { | ||
| 161 | static struct type6_hdr static_type6_hdrX = { | ||
| 162 | .type = 0x06, | ||
| 163 | .offset1 = 0x00000058, | ||
| 164 | .agent_id = {'C', 'A',}, | ||
| 165 | .function_code = {'P', 'K'}, | ||
| 166 | }; | ||
| 167 | static struct function_and_rules_block static_pke_fnr = { | ||
| 168 | .function_code = {'P', 'K'}, | ||
| 169 | .ulen = 10, | ||
| 170 | .only_rule = {'M', 'R', 'P', ' ', ' ', ' ', ' ', ' '} | ||
| 171 | }; | ||
| 172 | static struct function_and_rules_block static_pke_fnr_MCL2 = { | ||
| 173 | .function_code = {'P', 'K'}, | ||
| 174 | .ulen = 10, | ||
| 175 | .only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'} | ||
| 176 | }; | ||
| 177 | struct { | ||
| 178 | struct type6_hdr hdr; | ||
| 179 | struct CPRBX cprbx; | ||
| 180 | struct function_and_rules_block fr; | ||
| 181 | unsigned short length; | ||
| 182 | char text[0]; | ||
| 183 | } __packed * msg = ap_msg->message; | ||
| 184 | int size; | ||
| 185 | |||
| 186 | /* VUD.ciphertext */ | ||
| 187 | msg->length = mex->inputdatalength + 2; | ||
| 188 | if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength)) | ||
| 189 | return -EFAULT; | ||
| 190 | |||
| 191 | /* Set up key which is located after the variable length text. */ | ||
| 192 | size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1); | ||
| 193 | if (size < 0) | ||
| 194 | return size; | ||
| 195 | size += sizeof(*msg) + mex->inputdatalength; | ||
| 196 | |||
| 197 | /* message header, cprbx and f&r */ | ||
| 198 | msg->hdr = static_type6_hdrX; | ||
| 199 | msg->hdr.ToCardLen1 = size - sizeof(msg->hdr); | ||
| 200 | msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); | ||
| 201 | |||
| 202 | msg->cprbx = static_cprbx; | ||
| 203 | msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); | ||
| 204 | msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1; | ||
| 205 | |||
| 206 | msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? | ||
| 207 | static_pke_fnr_MCL2 : static_pke_fnr; | ||
| 208 | |||
| 209 | msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx); | ||
| 210 | |||
| 211 | ap_msg->length = size; | ||
| 212 | return 0; | ||
| 213 | } | ||
| 214 | |||
| 215 | /** | ||
| 216 | * Convert a ICACRT message to a type6 CRT message. | ||
| 217 | * | ||
| 218 | * @zdev: crypto device pointer | ||
| 219 | * @ap_msg: pointer to AP message | ||
| 220 | * @crt: pointer to user input data | ||
| 221 | * | ||
| 222 | * Returns 0 on success or -EFAULT. | ||
| 223 | */ | ||
| 224 | static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, | ||
| 225 | struct ap_message *ap_msg, | ||
| 226 | struct ica_rsa_modexpo_crt *crt) | ||
| 227 | { | ||
| 228 | static struct type6_hdr static_type6_hdrX = { | ||
| 229 | .type = 0x06, | ||
| 230 | .offset1 = 0x00000058, | ||
| 231 | .agent_id = {'C', 'A',}, | ||
| 232 | .function_code = {'P', 'D'}, | ||
| 233 | }; | ||
| 234 | static struct function_and_rules_block static_pkd_fnr = { | ||
| 235 | .function_code = {'P', 'D'}, | ||
| 236 | .ulen = 10, | ||
| 237 | .only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'} | ||
| 238 | }; | ||
| 239 | |||
| 240 | static struct function_and_rules_block static_pkd_fnr_MCL2 = { | ||
| 241 | .function_code = {'P', 'D'}, | ||
| 242 | .ulen = 10, | ||
| 243 | .only_rule = {'P', 'K', 'C', 'S', '-', '1', '.', '2'} | ||
| 244 | }; | ||
| 245 | struct { | ||
| 246 | struct type6_hdr hdr; | ||
| 247 | struct CPRBX cprbx; | ||
| 248 | struct function_and_rules_block fr; | ||
| 249 | unsigned short length; | ||
| 250 | char text[0]; | ||
| 251 | } __packed * msg = ap_msg->message; | ||
| 252 | int size; | ||
| 253 | |||
| 254 | /* VUD.ciphertext */ | ||
| 255 | msg->length = crt->inputdatalength + 2; | ||
| 256 | if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength)) | ||
| 257 | return -EFAULT; | ||
| 258 | |||
| 259 | /* Set up key which is located after the variable length text. */ | ||
| 260 | size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1); | ||
| 261 | if (size < 0) | ||
| 262 | return size; | ||
| 263 | size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */ | ||
| 264 | |||
| 265 | /* message header, cprbx and f&r */ | ||
| 266 | msg->hdr = static_type6_hdrX; | ||
| 267 | msg->hdr.ToCardLen1 = size - sizeof(msg->hdr); | ||
| 268 | msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); | ||
| 269 | |||
| 270 | msg->cprbx = static_cprbx; | ||
| 271 | msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); | ||
| 272 | msg->cprbx.req_parml = msg->cprbx.rpl_msgbl = | ||
| 273 | size - sizeof(msg->hdr) - sizeof(msg->cprbx); | ||
| 274 | |||
| 275 | msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? | ||
| 276 | static_pkd_fnr_MCL2 : static_pkd_fnr; | ||
| 277 | |||
| 278 | ap_msg->length = size; | ||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | /** | ||
| 283 | * Convert a XCRB message to a type6 CPRB message. | ||
| 284 | * | ||
| 285 | * @zdev: crypto device pointer | ||
| 286 | * @ap_msg: pointer to AP message | ||
| 287 | * @xcRB: pointer to user input data | ||
| 288 | * | ||
| 289 | * Returns 0 on success or -EFAULT, -EINVAL. | ||
| 290 | */ | ||
| 291 | struct type86_fmt2_msg { | ||
| 292 | struct type86_hdr hdr; | ||
| 293 | struct type86_fmt2_ext fmt2; | ||
| 294 | } __packed; | ||
| 295 | |||
| 296 | static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, | ||
| 297 | struct ap_message *ap_msg, | ||
| 298 | struct ica_xcRB *xcRB) | ||
| 299 | { | ||
| 300 | static struct type6_hdr static_type6_hdrX = { | ||
| 301 | .type = 0x06, | ||
| 302 | .offset1 = 0x00000058, | ||
| 303 | }; | ||
| 304 | struct { | ||
| 305 | struct type6_hdr hdr; | ||
| 306 | struct CPRBX cprbx; | ||
| 307 | } __packed * msg = ap_msg->message; | ||
| 308 | |||
| 309 | int rcblen = CEIL4(xcRB->request_control_blk_length); | ||
| 310 | int replylen; | ||
| 311 | char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen; | ||
| 312 | char *function_code; | ||
| 313 | |||
| 314 | /* length checks */ | ||
| 315 | ap_msg->length = sizeof(struct type6_hdr) + | ||
| 316 | CEIL4(xcRB->request_control_blk_length) + | ||
| 317 | xcRB->request_data_length; | ||
| 318 | if (ap_msg->length > MSGTYPE06_MAX_MSG_SIZE) | ||
| 319 | return -EINVAL; | ||
| 320 | replylen = sizeof(struct type86_fmt2_msg) + | ||
| 321 | CEIL4(xcRB->reply_control_blk_length) + | ||
| 322 | xcRB->reply_data_length; | ||
| 323 | if (replylen > MSGTYPE06_MAX_MSG_SIZE) | ||
| 324 | return -EINVAL; | ||
| 325 | |||
| 326 | /* prepare type6 header */ | ||
| 327 | msg->hdr = static_type6_hdrX; | ||
| 328 | memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID)); | ||
| 329 | msg->hdr.ToCardLen1 = xcRB->request_control_blk_length; | ||
| 330 | if (xcRB->request_data_length) { | ||
| 331 | msg->hdr.offset2 = msg->hdr.offset1 + rcblen; | ||
| 332 | msg->hdr.ToCardLen2 = xcRB->request_data_length; | ||
| 333 | } | ||
| 334 | msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length; | ||
| 335 | msg->hdr.FromCardLen2 = xcRB->reply_data_length; | ||
| 336 | |||
| 337 | /* prepare CPRB */ | ||
| 338 | if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr, | ||
| 339 | xcRB->request_control_blk_length)) | ||
| 340 | return -EFAULT; | ||
| 341 | if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) > | ||
| 342 | xcRB->request_control_blk_length) | ||
| 343 | return -EINVAL; | ||
| 344 | function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len; | ||
| 345 | memcpy(msg->hdr.function_code, function_code, | ||
| 346 | sizeof(msg->hdr.function_code)); | ||
| 347 | |||
| 348 | if (memcmp(function_code, "US", 2) == 0) | ||
| 349 | ap_msg->special = 1; | ||
| 350 | else | ||
| 351 | ap_msg->special = 0; | ||
| 352 | |||
| 353 | /* copy data block */ | ||
| 354 | if (xcRB->request_data_length && | ||
| 355 | copy_from_user(req_data, xcRB->request_data_address, | ||
| 356 | xcRB->request_data_length)) | ||
| 357 | return -EFAULT; | ||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * Copy results from a type 86 ICA reply message back to user space. | ||
| 363 | * | ||
| 364 | * @zdev: crypto device pointer | ||
| 365 | * @reply: reply AP message. | ||
| 366 | * @data: pointer to user output data | ||
| 367 | * @length: size of user output data | ||
| 368 | * | ||
| 369 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. | ||
| 370 | */ | ||
| 371 | struct type86x_reply { | ||
| 372 | struct type86_hdr hdr; | ||
| 373 | struct type86_fmt2_ext fmt2; | ||
| 374 | struct CPRBX cprbx; | ||
| 375 | unsigned char pad[4]; /* 4 byte function code/rules block ? */ | ||
| 376 | unsigned short length; | ||
| 377 | char text[0]; | ||
| 378 | } __packed; | ||
| 379 | |||
| 380 | static int convert_type86_ica(struct zcrypt_device *zdev, | ||
| 381 | struct ap_message *reply, | ||
| 382 | char __user *outputdata, | ||
| 383 | unsigned int outputdatalength) | ||
| 384 | { | ||
| 385 | static unsigned char static_pad[] = { | ||
| 386 | 0x00, 0x02, | ||
| 387 | 0x1B, 0x7B, 0x5D, 0xB5, 0x75, 0x01, 0x3D, 0xFD, | ||
| 388 | 0x8D, 0xD1, 0xC7, 0x03, 0x2D, 0x09, 0x23, 0x57, | ||
| 389 | 0x89, 0x49, 0xB9, 0x3F, 0xBB, 0x99, 0x41, 0x5B, | ||
| 390 | 0x75, 0x21, 0x7B, 0x9D, 0x3B, 0x6B, 0x51, 0x39, | ||
| 391 | 0xBB, 0x0D, 0x35, 0xB9, 0x89, 0x0F, 0x93, 0xA5, | ||
| 392 | 0x0B, 0x47, 0xF1, 0xD3, 0xBB, 0xCB, 0xF1, 0x9D, | ||
| 393 | 0x23, 0x73, 0x71, 0xFF, 0xF3, 0xF5, 0x45, 0xFB, | ||
| 394 | 0x61, 0x29, 0x23, 0xFD, 0xF1, 0x29, 0x3F, 0x7F, | ||
| 395 | 0x17, 0xB7, 0x1B, 0xA9, 0x19, 0xBD, 0x57, 0xA9, | ||
| 396 | 0xD7, 0x95, 0xA3, 0xCB, 0xED, 0x1D, 0xDB, 0x45, | ||
| 397 | 0x7D, 0x11, 0xD1, 0x51, 0x1B, 0xED, 0x71, 0xE9, | ||
| 398 | 0xB1, 0xD1, 0xAB, 0xAB, 0x21, 0x2B, 0x1B, 0x9F, | ||
| 399 | 0x3B, 0x9F, 0xF7, 0xF7, 0xBD, 0x63, 0xEB, 0xAD, | ||
| 400 | 0xDF, 0xB3, 0x6F, 0x5B, 0xDB, 0x8D, 0xA9, 0x5D, | ||
| 401 | 0xE3, 0x7D, 0x77, 0x49, 0x47, 0xF5, 0xA7, 0xFD, | ||
| 402 | 0xAB, 0x2F, 0x27, 0x35, 0x77, 0xD3, 0x49, 0xC9, | ||
| 403 | 0x09, 0xEB, 0xB1, 0xF9, 0xBF, 0x4B, 0xCB, 0x2B, | ||
| 404 | 0xEB, 0xEB, 0x05, 0xFF, 0x7D, 0xC7, 0x91, 0x8B, | ||
| 405 | 0x09, 0x83, 0xB9, 0xB9, 0x69, 0x33, 0x39, 0x6B, | ||
| 406 | 0x79, 0x75, 0x19, 0xBF, 0xBB, 0x07, 0x1D, 0xBD, | ||
| 407 | 0x29, 0xBF, 0x39, 0x95, 0x93, 0x1D, 0x35, 0xC7, | ||
| 408 | 0xC9, 0x4D, 0xE5, 0x97, 0x0B, 0x43, 0x9B, 0xF1, | ||
| 409 | 0x16, 0x93, 0x03, 0x1F, 0xA5, 0xFB, 0xDB, 0xF3, | ||
| 410 | 0x27, 0x4F, 0x27, 0x61, 0x05, 0x1F, 0xB9, 0x23, | ||
| 411 | 0x2F, 0xC3, 0x81, 0xA9, 0x23, 0x71, 0x55, 0x55, | ||
| 412 | 0xEB, 0xED, 0x41, 0xE5, 0xF3, 0x11, 0xF1, 0x43, | ||
| 413 | 0x69, 0x03, 0xBD, 0x0B, 0x37, 0x0F, 0x51, 0x8F, | ||
| 414 | 0x0B, 0xB5, 0x89, 0x5B, 0x67, 0xA9, 0xD9, 0x4F, | ||
| 415 | 0x01, 0xF9, 0x21, 0x77, 0x37, 0x73, 0x79, 0xC5, | ||
| 416 | 0x7F, 0x51, 0xC1, 0xCF, 0x97, 0xA1, 0x75, 0xAD, | ||
| 417 | 0x35, 0x9D, 0xD3, 0xD3, 0xA7, 0x9D, 0x5D, 0x41, | ||
| 418 | 0x6F, 0x65, 0x1B, 0xCF, 0xA9, 0x87, 0x91, 0x09 | ||
| 419 | }; | ||
| 420 | struct type86x_reply *msg = reply->message; | ||
| 421 | unsigned short service_rc, service_rs; | ||
| 422 | unsigned int reply_len, pad_len; | ||
| 423 | char *data; | ||
| 424 | |||
| 425 | service_rc = msg->cprbx.ccp_rtcode; | ||
| 426 | if (unlikely(service_rc != 0)) { | ||
| 427 | service_rs = msg->cprbx.ccp_rscode; | ||
| 428 | if (service_rc == 8 && service_rs == 66) | ||
| 429 | return -EINVAL; | ||
| 430 | if (service_rc == 8 && service_rs == 65) | ||
| 431 | return -EINVAL; | ||
| 432 | if (service_rc == 8 && service_rs == 770) | ||
| 433 | return -EINVAL; | ||
| 434 | if (service_rc == 8 && service_rs == 783) { | ||
| 435 | zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; | ||
| 436 | return -EAGAIN; | ||
| 437 | } | ||
| 438 | if (service_rc == 12 && service_rs == 769) | ||
| 439 | return -EINVAL; | ||
| 440 | if (service_rc == 8 && service_rs == 72) | ||
| 441 | return -EINVAL; | ||
| 442 | zdev->online = 0; | ||
| 443 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 444 | } | ||
| 445 | data = msg->text; | ||
| 446 | reply_len = msg->length - 2; | ||
| 447 | if (reply_len > outputdatalength) | ||
| 448 | return -EINVAL; | ||
| 449 | /* | ||
| 450 | * For all encipher requests, the length of the ciphertext (reply_len) | ||
| 451 | * will always equal the modulus length. For MEX decipher requests | ||
| 452 | * the output needs to get padded. Minimum pad size is 10. | ||
| 453 | * | ||
| 454 | * Currently, the cases where padding will be added is for: | ||
| 455 | * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support | ||
| 456 | * ZERO-PAD and CRT is only supported for PKD requests) | ||
| 457 | * - PCICC, always | ||
| 458 | */ | ||
| 459 | pad_len = outputdatalength - reply_len; | ||
| 460 | if (pad_len > 0) { | ||
| 461 | if (pad_len < 10) | ||
| 462 | return -EINVAL; | ||
| 463 | /* 'restore' padding left in the PCICC/PCIXCC card. */ | ||
| 464 | if (copy_to_user(outputdata, static_pad, pad_len - 1)) | ||
| 465 | return -EFAULT; | ||
| 466 | if (put_user(0, outputdata + pad_len - 1)) | ||
| 467 | return -EFAULT; | ||
| 468 | } | ||
| 469 | /* Copy the crypto response to user space. */ | ||
| 470 | if (copy_to_user(outputdata + pad_len, data, reply_len)) | ||
| 471 | return -EFAULT; | ||
| 472 | return 0; | ||
| 473 | } | ||
| 474 | |||
| 475 | /** | ||
| 476 | * Copy results from a type 86 XCRB reply message back to user space. | ||
| 477 | * | ||
| 478 | * @zdev: crypto device pointer | ||
| 479 | * @reply: reply AP message. | ||
| 480 | * @xcRB: pointer to XCRB | ||
| 481 | * | ||
| 482 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. | ||
| 483 | */ | ||
| 484 | static int convert_type86_xcrb(struct zcrypt_device *zdev, | ||
| 485 | struct ap_message *reply, | ||
| 486 | struct ica_xcRB *xcRB) | ||
| 487 | { | ||
| 488 | struct type86_fmt2_msg *msg = reply->message; | ||
| 489 | char *data = reply->message; | ||
| 490 | |||
| 491 | /* Copy CPRB to user */ | ||
| 492 | if (copy_to_user(xcRB->reply_control_blk_addr, | ||
| 493 | data + msg->fmt2.offset1, msg->fmt2.count1)) | ||
| 494 | return -EFAULT; | ||
| 495 | xcRB->reply_control_blk_length = msg->fmt2.count1; | ||
| 496 | |||
| 497 | /* Copy data buffer to user */ | ||
| 498 | if (msg->fmt2.count2) | ||
| 499 | if (copy_to_user(xcRB->reply_data_addr, | ||
| 500 | data + msg->fmt2.offset2, msg->fmt2.count2)) | ||
| 501 | return -EFAULT; | ||
| 502 | xcRB->reply_data_length = msg->fmt2.count2; | ||
| 503 | return 0; | ||
| 504 | } | ||
| 505 | |||
| 506 | static int convert_type86_rng(struct zcrypt_device *zdev, | ||
| 507 | struct ap_message *reply, | ||
| 508 | char *buffer) | ||
| 509 | { | ||
| 510 | struct { | ||
| 511 | struct type86_hdr hdr; | ||
| 512 | struct type86_fmt2_ext fmt2; | ||
| 513 | struct CPRBX cprbx; | ||
| 514 | } __packed * msg = reply->message; | ||
| 515 | char *data = reply->message; | ||
| 516 | |||
| 517 | if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) | ||
| 518 | return -EINVAL; | ||
| 519 | memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2); | ||
| 520 | return msg->fmt2.count2; | ||
| 521 | } | ||
| 522 | |||
| 523 | static int convert_response_ica(struct zcrypt_device *zdev, | ||
| 524 | struct ap_message *reply, | ||
| 525 | char __user *outputdata, | ||
| 526 | unsigned int outputdatalength) | ||
| 527 | { | ||
| 528 | struct type86x_reply *msg = reply->message; | ||
| 529 | |||
| 530 | /* Response type byte is the second byte in the response. */ | ||
| 531 | switch (((unsigned char *) reply->message)[1]) { | ||
| 532 | case TYPE82_RSP_CODE: | ||
| 533 | case TYPE88_RSP_CODE: | ||
| 534 | return convert_error(zdev, reply); | ||
| 535 | case TYPE86_RSP_CODE: | ||
| 536 | if (msg->cprbx.ccp_rtcode && | ||
| 537 | (msg->cprbx.ccp_rscode == 0x14f) && | ||
| 538 | (outputdatalength > 256)) { | ||
| 539 | if (zdev->max_exp_bit_length <= 17) { | ||
| 540 | zdev->max_exp_bit_length = 17; | ||
| 541 | return -EAGAIN; | ||
| 542 | } else | ||
| 543 | return -EINVAL; | ||
| 544 | } | ||
| 545 | if (msg->hdr.reply_code) | ||
| 546 | return convert_error(zdev, reply); | ||
| 547 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 548 | return convert_type86_ica(zdev, reply, | ||
| 549 | outputdata, outputdatalength); | ||
| 550 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 551 | * response */ | ||
| 552 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 553 | zdev->online = 0; | ||
| 554 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 558 | static int convert_response_xcrb(struct zcrypt_device *zdev, | ||
| 559 | struct ap_message *reply, | ||
| 560 | struct ica_xcRB *xcRB) | ||
| 561 | { | ||
| 562 | struct type86x_reply *msg = reply->message; | ||
| 563 | |||
| 564 | /* Response type byte is the second byte in the response. */ | ||
| 565 | switch (((unsigned char *) reply->message)[1]) { | ||
| 566 | case TYPE82_RSP_CODE: | ||
| 567 | case TYPE88_RSP_CODE: | ||
| 568 | xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ | ||
| 569 | return convert_error(zdev, reply); | ||
| 570 | case TYPE86_RSP_CODE: | ||
| 571 | if (msg->hdr.reply_code) { | ||
| 572 | memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32)); | ||
| 573 | return convert_error(zdev, reply); | ||
| 574 | } | ||
| 575 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 576 | return convert_type86_xcrb(zdev, reply, xcRB); | ||
| 577 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 578 | * response */ | ||
| 579 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 580 | xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ | ||
| 581 | zdev->online = 0; | ||
| 582 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 583 | } | ||
| 584 | } | ||
| 585 | |||
| 586 | static int convert_response_rng(struct zcrypt_device *zdev, | ||
| 587 | struct ap_message *reply, | ||
| 588 | char *data) | ||
| 589 | { | ||
| 590 | struct type86x_reply *msg = reply->message; | ||
| 591 | |||
| 592 | switch (msg->hdr.type) { | ||
| 593 | case TYPE82_RSP_CODE: | ||
| 594 | case TYPE88_RSP_CODE: | ||
| 595 | return -EINVAL; | ||
| 596 | case TYPE86_RSP_CODE: | ||
| 597 | if (msg->hdr.reply_code) | ||
| 598 | return -EINVAL; | ||
| 599 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 600 | return convert_type86_rng(zdev, reply, data); | ||
| 601 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 602 | * response */ | ||
| 603 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 604 | zdev->online = 0; | ||
| 605 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | /** | ||
| 610 | * This function is called from the AP bus code after a crypto request | ||
| 611 | * "msg" has finished with the reply message "reply". | ||
| 612 | * It is called from tasklet context. | ||
| 613 | * @ap_dev: pointer to the AP device | ||
| 614 | * @msg: pointer to the AP message | ||
| 615 | * @reply: pointer to the AP reply message | ||
| 616 | */ | ||
| 617 | static void zcrypt_msgtype6_receive(struct ap_device *ap_dev, | ||
| 618 | struct ap_message *msg, | ||
| 619 | struct ap_message *reply) | ||
| 620 | { | ||
| 621 | static struct error_hdr error_reply = { | ||
| 622 | .type = TYPE82_RSP_CODE, | ||
| 623 | .reply_code = REP82_ERROR_MACHINE_FAILURE, | ||
| 624 | }; | ||
| 625 | struct response_type *resp_type = | ||
| 626 | (struct response_type *) msg->private; | ||
| 627 | struct type86x_reply *t86r; | ||
| 628 | int length; | ||
| 629 | |||
| 630 | /* Copy the reply message to the request message buffer. */ | ||
| 631 | if (IS_ERR(reply)) { | ||
| 632 | memcpy(msg->message, &error_reply, sizeof(error_reply)); | ||
| 633 | goto out; | ||
| 634 | } | ||
| 635 | t86r = reply->message; | ||
| 636 | if (t86r->hdr.type == TYPE86_RSP_CODE && | ||
| 637 | t86r->cprbx.cprb_ver_id == 0x02) { | ||
| 638 | switch (resp_type->type) { | ||
| 639 | case PCIXCC_RESPONSE_TYPE_ICA: | ||
| 640 | length = sizeof(struct type86x_reply) | ||
| 641 | + t86r->length - 2; | ||
| 642 | length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length); | ||
| 643 | memcpy(msg->message, reply->message, length); | ||
| 644 | break; | ||
| 645 | case PCIXCC_RESPONSE_TYPE_XCRB: | ||
| 646 | length = t86r->fmt2.offset2 + t86r->fmt2.count2; | ||
| 647 | length = min(MSGTYPE06_MAX_MSG_SIZE, length); | ||
| 648 | memcpy(msg->message, reply->message, length); | ||
| 649 | break; | ||
| 650 | default: | ||
| 651 | memcpy(msg->message, &error_reply, | ||
| 652 | sizeof(error_reply)); | ||
| 653 | } | ||
| 654 | } else | ||
| 655 | memcpy(msg->message, reply->message, sizeof(error_reply)); | ||
| 656 | out: | ||
| 657 | complete(&(resp_type->work)); | ||
| 658 | } | ||
| 659 | |||
| 660 | static atomic_t zcrypt_step = ATOMIC_INIT(0); | ||
| 661 | |||
| 662 | /** | ||
| 663 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 664 | * device to handle a modexpo request. | ||
| 665 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 666 | * PCIXCC/CEX2C device to the request distributor | ||
| 667 | * @mex: pointer to the modexpo request buffer | ||
| 668 | */ | ||
| 669 | static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev, | ||
| 670 | struct ica_rsa_modexpo *mex) | ||
| 671 | { | ||
| 672 | struct ap_message ap_msg; | ||
| 673 | struct response_type resp_type = { | ||
| 674 | .type = PCIXCC_RESPONSE_TYPE_ICA, | ||
| 675 | }; | ||
| 676 | int rc; | ||
| 677 | |||
| 678 | ap_init_message(&ap_msg); | ||
| 679 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); | ||
| 680 | if (!ap_msg.message) | ||
| 681 | return -ENOMEM; | ||
| 682 | ap_msg.receive = zcrypt_msgtype6_receive; | ||
| 683 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 684 | atomic_inc_return(&zcrypt_step); | ||
| 685 | ap_msg.private = &resp_type; | ||
| 686 | rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex); | ||
| 687 | if (rc) | ||
| 688 | goto out_free; | ||
| 689 | init_completion(&resp_type.work); | ||
| 690 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 691 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 692 | if (rc == 0) | ||
| 693 | rc = convert_response_ica(zdev, &ap_msg, mex->outputdata, | ||
| 694 | mex->outputdatalength); | ||
| 695 | else | ||
| 696 | /* Signal pending. */ | ||
| 697 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 698 | out_free: | ||
| 699 | free_page((unsigned long) ap_msg.message); | ||
| 700 | return rc; | ||
| 701 | } | ||
| 702 | |||
| 703 | /** | ||
| 704 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 705 | * device to handle a modexpo_crt request. | ||
| 706 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 707 | * PCIXCC/CEX2C device to the request distributor | ||
| 708 | * @crt: pointer to the modexpoc_crt request buffer | ||
| 709 | */ | ||
| 710 | static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev, | ||
| 711 | struct ica_rsa_modexpo_crt *crt) | ||
| 712 | { | ||
| 713 | struct ap_message ap_msg; | ||
| 714 | struct response_type resp_type = { | ||
| 715 | .type = PCIXCC_RESPONSE_TYPE_ICA, | ||
| 716 | }; | ||
| 717 | int rc; | ||
| 718 | |||
| 719 | ap_init_message(&ap_msg); | ||
| 720 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); | ||
| 721 | if (!ap_msg.message) | ||
| 722 | return -ENOMEM; | ||
| 723 | ap_msg.receive = zcrypt_msgtype6_receive; | ||
| 724 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 725 | atomic_inc_return(&zcrypt_step); | ||
| 726 | ap_msg.private = &resp_type; | ||
| 727 | rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt); | ||
| 728 | if (rc) | ||
| 729 | goto out_free; | ||
| 730 | init_completion(&resp_type.work); | ||
| 731 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 732 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 733 | if (rc == 0) | ||
| 734 | rc = convert_response_ica(zdev, &ap_msg, crt->outputdata, | ||
| 735 | crt->outputdatalength); | ||
| 736 | else | ||
| 737 | /* Signal pending. */ | ||
| 738 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 739 | out_free: | ||
| 740 | free_page((unsigned long) ap_msg.message); | ||
| 741 | return rc; | ||
| 742 | } | ||
| 743 | |||
| 744 | /** | ||
| 745 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 746 | * device to handle a send_cprb request. | ||
| 747 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 748 | * PCIXCC/CEX2C device to the request distributor | ||
| 749 | * @xcRB: pointer to the send_cprb request buffer | ||
| 750 | */ | ||
| 751 | static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, | ||
| 752 | struct ica_xcRB *xcRB) | ||
| 753 | { | ||
| 754 | struct ap_message ap_msg; | ||
| 755 | struct response_type resp_type = { | ||
| 756 | .type = PCIXCC_RESPONSE_TYPE_XCRB, | ||
| 757 | }; | ||
| 758 | int rc; | ||
| 759 | |||
| 760 | ap_init_message(&ap_msg); | ||
| 761 | ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); | ||
| 762 | if (!ap_msg.message) | ||
| 763 | return -ENOMEM; | ||
| 764 | ap_msg.receive = zcrypt_msgtype6_receive; | ||
| 765 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 766 | atomic_inc_return(&zcrypt_step); | ||
| 767 | ap_msg.private = &resp_type; | ||
| 768 | rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB); | ||
| 769 | if (rc) | ||
| 770 | goto out_free; | ||
| 771 | init_completion(&resp_type.work); | ||
| 772 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 773 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 774 | if (rc == 0) | ||
| 775 | rc = convert_response_xcrb(zdev, &ap_msg, xcRB); | ||
| 776 | else | ||
| 777 | /* Signal pending. */ | ||
| 778 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 779 | out_free: | ||
| 780 | kzfree(ap_msg.message); | ||
| 781 | return rc; | ||
| 782 | } | ||
| 783 | |||
| 784 | /** | ||
| 785 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 786 | * device to generate random data. | ||
| 787 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 788 | * PCIXCC/CEX2C device to the request distributor | ||
| 789 | * @buffer: pointer to a memory page to return random data | ||
| 790 | */ | ||
| 791 | |||
| 792 | static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev, | ||
| 793 | char *buffer) | ||
| 794 | { | ||
| 795 | struct ap_message ap_msg; | ||
| 796 | struct response_type resp_type = { | ||
| 797 | .type = PCIXCC_RESPONSE_TYPE_XCRB, | ||
| 798 | }; | ||
| 799 | int rc; | ||
| 800 | |||
| 801 | ap_init_message(&ap_msg); | ||
| 802 | ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); | ||
| 803 | if (!ap_msg.message) | ||
| 804 | return -ENOMEM; | ||
| 805 | ap_msg.receive = zcrypt_msgtype6_receive; | ||
| 806 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 807 | atomic_inc_return(&zcrypt_step); | ||
| 808 | ap_msg.private = &resp_type; | ||
| 809 | rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE); | ||
| 810 | init_completion(&resp_type.work); | ||
| 811 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 812 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 813 | if (rc == 0) | ||
| 814 | rc = convert_response_rng(zdev, &ap_msg, buffer); | ||
| 815 | else | ||
| 816 | /* Signal pending. */ | ||
| 817 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 818 | kfree(ap_msg.message); | ||
| 819 | return rc; | ||
| 820 | } | ||
| 821 | |||
| 822 | /** | ||
| 823 | * The crypto operations for a PCIXCC/CEX2C card. | ||
| 824 | */ | ||
| 825 | static struct zcrypt_ops zcrypt_msgtype6_norng_ops = { | ||
| 826 | .owner = THIS_MODULE, | ||
| 827 | .variant = MSGTYPE06_VARIANT_NORNG, | ||
| 828 | .rsa_modexpo = zcrypt_msgtype6_modexpo, | ||
| 829 | .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt, | ||
| 830 | .send_cprb = zcrypt_msgtype6_send_cprb, | ||
| 831 | }; | ||
| 832 | |||
| 833 | static struct zcrypt_ops zcrypt_msgtype6_ops = { | ||
| 834 | .owner = THIS_MODULE, | ||
| 835 | .variant = MSGTYPE06_VARIANT_DEFAULT, | ||
| 836 | .rsa_modexpo = zcrypt_msgtype6_modexpo, | ||
| 837 | .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt, | ||
| 838 | .send_cprb = zcrypt_msgtype6_send_cprb, | ||
| 839 | .rng = zcrypt_msgtype6_rng, | ||
| 840 | }; | ||
| 841 | |||
| 842 | int __init zcrypt_msgtype6_init(void) | ||
| 843 | { | ||
| 844 | zcrypt_msgtype_register(&zcrypt_msgtype6_norng_ops); | ||
| 845 | zcrypt_msgtype_register(&zcrypt_msgtype6_ops); | ||
| 846 | return 0; | ||
| 847 | } | ||
| 848 | |||
| 849 | void __exit zcrypt_msgtype6_exit(void) | ||
| 850 | { | ||
| 851 | zcrypt_msgtype_unregister(&zcrypt_msgtype6_norng_ops); | ||
| 852 | zcrypt_msgtype_unregister(&zcrypt_msgtype6_ops); | ||
| 853 | } | ||
| 854 | |||
| 855 | module_init(zcrypt_msgtype6_init); | ||
| 856 | module_exit(zcrypt_msgtype6_exit); | ||
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h new file mode 100644 index 000000000000..1e500d3c0735 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_msgtype6.h | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* | ||
| 2 | * zcrypt 2.1.0 | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2001, 2012 | ||
| 5 | * Author(s): Robert Burroughs | ||
| 6 | * Eric Rossman (edrossma@us.ibm.com) | ||
| 7 | * | ||
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | ||
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
| 10 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 15 | * any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef _ZCRYPT_MSGTYPE6_H_ | ||
| 28 | #define _ZCRYPT_MSGTYPE6_H_ | ||
| 29 | |||
| 30 | #include <asm/zcrypt.h> | ||
| 31 | |||
| 32 | #define MSGTYPE06_NAME "zcrypt_msgtype6" | ||
| 33 | #define MSGTYPE06_VARIANT_DEFAULT 0 | ||
| 34 | #define MSGTYPE06_VARIANT_NORNG 1 | ||
| 35 | |||
| 36 | #define MSGTYPE06_MAX_MSG_SIZE (12*1024) | ||
| 37 | |||
| 38 | /** | ||
| 39 | * The type 6 message family is associated with PCICC or PCIXCC cards. | ||
| 40 | * | ||
| 41 | * It contains a message header followed by a CPRB, both of which | ||
| 42 | * are described below. | ||
| 43 | * | ||
| 44 | * Note that all reserved fields must be zeroes. | ||
| 45 | */ | ||
| 46 | struct type6_hdr { | ||
| 47 | unsigned char reserved1; /* 0x00 */ | ||
| 48 | unsigned char type; /* 0x06 */ | ||
| 49 | unsigned char reserved2[2]; /* 0x0000 */ | ||
| 50 | unsigned char right[4]; /* 0x00000000 */ | ||
| 51 | unsigned char reserved3[2]; /* 0x0000 */ | ||
| 52 | unsigned char reserved4[2]; /* 0x0000 */ | ||
| 53 | unsigned char apfs[4]; /* 0x00000000 */ | ||
| 54 | unsigned int offset1; /* 0x00000058 (offset to CPRB) */ | ||
| 55 | unsigned int offset2; /* 0x00000000 */ | ||
| 56 | unsigned int offset3; /* 0x00000000 */ | ||
| 57 | unsigned int offset4; /* 0x00000000 */ | ||
| 58 | unsigned char agent_id[16]; /* PCICC: */ | ||
| 59 | /* 0x0100 */ | ||
| 60 | /* 0x4343412d4150504c202020 */ | ||
| 61 | /* 0x010101 */ | ||
| 62 | /* PCIXCC: */ | ||
| 63 | /* 0x4341000000000000 */ | ||
| 64 | /* 0x0000000000000000 */ | ||
| 65 | unsigned char rqid[2]; /* rqid. internal to 603 */ | ||
| 66 | unsigned char reserved5[2]; /* 0x0000 */ | ||
| 67 | unsigned char function_code[2]; /* for PKD, 0x5044 (ascii 'PD') */ | ||
| 68 | unsigned char reserved6[2]; /* 0x0000 */ | ||
| 69 | unsigned int ToCardLen1; /* (request CPRB len + 3) & -4 */ | ||
| 70 | unsigned int ToCardLen2; /* db len 0x00000000 for PKD */ | ||
| 71 | unsigned int ToCardLen3; /* 0x00000000 */ | ||
| 72 | unsigned int ToCardLen4; /* 0x00000000 */ | ||
| 73 | unsigned int FromCardLen1; /* response buffer length */ | ||
| 74 | unsigned int FromCardLen2; /* db len 0x00000000 for PKD */ | ||
| 75 | unsigned int FromCardLen3; /* 0x00000000 */ | ||
| 76 | unsigned int FromCardLen4; /* 0x00000000 */ | ||
| 77 | } __packed; | ||
| 78 | |||
| 79 | /** | ||
| 80 | * The type 86 message family is associated with PCICC and PCIXCC cards. | ||
| 81 | * | ||
| 82 | * It contains a message header followed by a CPRB. The CPRB is | ||
| 83 | * the same as the request CPRB, which is described above. | ||
| 84 | * | ||
| 85 | * If format is 1, an error condition exists and no data beyond | ||
| 86 | * the 8-byte message header is of interest. | ||
| 87 | * | ||
| 88 | * The non-error message is shown below. | ||
| 89 | * | ||
| 90 | * Note that all reserved fields must be zeroes. | ||
| 91 | */ | ||
| 92 | struct type86_hdr { | ||
| 93 | unsigned char reserved1; /* 0x00 */ | ||
| 94 | unsigned char type; /* 0x86 */ | ||
| 95 | unsigned char format; /* 0x01 (error) or 0x02 (ok) */ | ||
| 96 | unsigned char reserved2; /* 0x00 */ | ||
| 97 | unsigned char reply_code; /* reply code (see above) */ | ||
| 98 | unsigned char reserved3[3]; /* 0x000000 */ | ||
| 99 | } __packed; | ||
| 100 | |||
| 101 | #define TYPE86_RSP_CODE 0x86 | ||
| 102 | #define TYPE86_FMT2 0x02 | ||
| 103 | |||
| 104 | struct type86_fmt2_ext { | ||
| 105 | unsigned char reserved[4]; /* 0x00000000 */ | ||
| 106 | unsigned char apfs[4]; /* final status */ | ||
| 107 | unsigned int count1; /* length of CPRB + parameters */ | ||
| 108 | unsigned int offset1; /* offset to CPRB */ | ||
| 109 | unsigned int count2; /* 0x00000000 */ | ||
| 110 | unsigned int offset2; /* db offset 0x00000000 for PKD */ | ||
| 111 | unsigned int count3; /* 0x00000000 */ | ||
| 112 | unsigned int offset3; /* 0x00000000 */ | ||
| 113 | unsigned int count4; /* 0x00000000 */ | ||
| 114 | unsigned int offset4; /* 0x00000000 */ | ||
| 115 | } __packed; | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Prepare a type6 CPRB message for random number generation | ||
| 119 | * | ||
| 120 | * @ap_dev: AP device pointer | ||
| 121 | * @ap_msg: pointer to AP message | ||
| 122 | */ | ||
| 123 | static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev, | ||
| 124 | struct ap_message *ap_msg, | ||
| 125 | unsigned random_number_length) | ||
| 126 | { | ||
| 127 | struct { | ||
| 128 | struct type6_hdr hdr; | ||
| 129 | struct CPRBX cprbx; | ||
| 130 | char function_code[2]; | ||
| 131 | short int rule_length; | ||
| 132 | char rule[8]; | ||
| 133 | short int verb_length; | ||
| 134 | short int key_length; | ||
| 135 | } __packed * msg = ap_msg->message; | ||
| 136 | static struct type6_hdr static_type6_hdrX = { | ||
| 137 | .type = 0x06, | ||
| 138 | .offset1 = 0x00000058, | ||
| 139 | .agent_id = {'C', 'A'}, | ||
| 140 | .function_code = {'R', 'L'}, | ||
| 141 | .ToCardLen1 = sizeof(*msg) - sizeof(msg->hdr), | ||
| 142 | .FromCardLen1 = sizeof(*msg) - sizeof(msg->hdr), | ||
| 143 | }; | ||
| 144 | static struct CPRBX local_cprbx = { | ||
| 145 | .cprb_len = 0x00dc, | ||
| 146 | .cprb_ver_id = 0x02, | ||
| 147 | .func_id = {0x54, 0x32}, | ||
| 148 | .req_parml = sizeof(*msg) - sizeof(msg->hdr) - | ||
| 149 | sizeof(msg->cprbx), | ||
| 150 | .rpl_msgbl = sizeof(*msg) - sizeof(msg->hdr), | ||
| 151 | }; | ||
| 152 | |||
| 153 | msg->hdr = static_type6_hdrX; | ||
| 154 | msg->hdr.FromCardLen2 = random_number_length, | ||
| 155 | msg->cprbx = local_cprbx; | ||
| 156 | msg->cprbx.rpl_datal = random_number_length, | ||
| 157 | msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); | ||
| 158 | memcpy(msg->function_code, msg->hdr.function_code, 0x02); | ||
| 159 | msg->rule_length = 0x0a; | ||
| 160 | memcpy(msg->rule, "RANDOM ", 8); | ||
| 161 | msg->verb_length = 0x02; | ||
| 162 | msg->key_length = 0x02; | ||
| 163 | ap_msg->length = sizeof(*msg); | ||
| 164 | } | ||
| 165 | |||
| 166 | int zcrypt_msgtype6_init(void); | ||
| 167 | void zcrypt_msgtype6_exit(void); | ||
| 168 | |||
| 169 | #endif /* _ZCRYPT_MSGTYPE6_H_ */ | ||
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index ccb4f8b60c75..c7275e303a0d 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * zcrypt 2.1.0 | 2 | * zcrypt 2.1.0 |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2001, 2006 | 4 | * Copyright IBM Corp. 2001, 2012 |
| 5 | * Author(s): Robert Burroughs | 5 | * Author(s): Robert Burroughs |
| 6 | * Eric Rossman (edrossma@us.ibm.com) | 6 | * Eric Rossman (edrossma@us.ibm.com) |
| 7 | * | 7 | * |
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | 10 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
| 11 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 11 | * | 12 | * |
| 12 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
| @@ -35,9 +36,10 @@ | |||
| 35 | #include "ap_bus.h" | 36 | #include "ap_bus.h" |
| 36 | #include "zcrypt_api.h" | 37 | #include "zcrypt_api.h" |
| 37 | #include "zcrypt_error.h" | 38 | #include "zcrypt_error.h" |
| 38 | #include "zcrypt_pcicc.h" | 39 | #include "zcrypt_msgtype6.h" |
| 39 | #include "zcrypt_pcixcc.h" | 40 | #include "zcrypt_pcixcc.h" |
| 40 | #include "zcrypt_cca_key.h" | 41 | #include "zcrypt_cca_key.h" |
| 42 | #include "zcrypt_msgtype6.h" | ||
| 41 | 43 | ||
| 42 | #define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */ | 44 | #define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */ |
| 43 | #define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */ | 45 | #define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */ |
| @@ -75,14 +77,12 @@ static struct ap_device_id zcrypt_pcixcc_ids[] = { | |||
| 75 | 77 | ||
| 76 | MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids); | 78 | MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids); |
| 77 | MODULE_AUTHOR("IBM Corporation"); | 79 | MODULE_AUTHOR("IBM Corporation"); |
| 78 | MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " | 80 | MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \ |
| 79 | "Copyright IBM Corp. 2001, 2006"); | 81 | "Copyright IBM Corp. 2001, 2012"); |
| 80 | MODULE_LICENSE("GPL"); | 82 | MODULE_LICENSE("GPL"); |
| 81 | 83 | ||
| 82 | static int zcrypt_pcixcc_probe(struct ap_device *ap_dev); | 84 | static int zcrypt_pcixcc_probe(struct ap_device *ap_dev); |
| 83 | static void zcrypt_pcixcc_remove(struct ap_device *ap_dev); | 85 | static void zcrypt_pcixcc_remove(struct ap_device *ap_dev); |
| 84 | static void zcrypt_pcixcc_receive(struct ap_device *, struct ap_message *, | ||
| 85 | struct ap_message *); | ||
| 86 | 86 | ||
| 87 | static struct ap_driver zcrypt_pcixcc_driver = { | 87 | static struct ap_driver zcrypt_pcixcc_driver = { |
| 88 | .probe = zcrypt_pcixcc_probe, | 88 | .probe = zcrypt_pcixcc_probe, |
| @@ -92,766 +92,6 @@ static struct ap_driver zcrypt_pcixcc_driver = { | |||
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | /** | 94 | /** |
| 95 | * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C | ||
| 96 | * card in a type6 message. The 3 fields that must be filled in at execution | ||
| 97 | * time are req_parml, rpl_parml and usage_domain. | ||
| 98 | * Everything about this interface is ascii/big-endian, since the | ||
| 99 | * device does *not* have 'Intel inside'. | ||
| 100 | * | ||
| 101 | * The CPRBX is followed immediately by the parm block. | ||
| 102 | * The parm block contains: | ||
| 103 | * - function code ('PD' 0x5044 or 'PK' 0x504B) | ||
| 104 | * - rule block (one of:) | ||
| 105 | * + 0x000A 'PKCS-1.2' (MCL2 'PD') | ||
| 106 | * + 0x000A 'ZERO-PAD' (MCL2 'PK') | ||
| 107 | * + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD') | ||
| 108 | * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK') | ||
| 109 | * - VUD block | ||
| 110 | */ | ||
| 111 | static struct CPRBX static_cprbx = { | ||
| 112 | .cprb_len = 0x00DC, | ||
| 113 | .cprb_ver_id = 0x02, | ||
| 114 | .func_id = {0x54,0x32}, | ||
| 115 | }; | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Convert a ICAMEX message to a type6 MEX message. | ||
| 119 | * | ||
| 120 | * @zdev: crypto device pointer | ||
| 121 | * @ap_msg: pointer to AP message | ||
| 122 | * @mex: pointer to user input data | ||
| 123 | * | ||
| 124 | * Returns 0 on success or -EFAULT. | ||
| 125 | */ | ||
| 126 | static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, | ||
| 127 | struct ap_message *ap_msg, | ||
| 128 | struct ica_rsa_modexpo *mex) | ||
| 129 | { | ||
| 130 | static struct type6_hdr static_type6_hdrX = { | ||
| 131 | .type = 0x06, | ||
| 132 | .offset1 = 0x00000058, | ||
| 133 | .agent_id = {'C','A',}, | ||
| 134 | .function_code = {'P','K'}, | ||
| 135 | }; | ||
| 136 | static struct function_and_rules_block static_pke_fnr = { | ||
| 137 | .function_code = {'P','K'}, | ||
| 138 | .ulen = 10, | ||
| 139 | .only_rule = {'M','R','P',' ',' ',' ',' ',' '} | ||
| 140 | }; | ||
| 141 | static struct function_and_rules_block static_pke_fnr_MCL2 = { | ||
| 142 | .function_code = {'P','K'}, | ||
| 143 | .ulen = 10, | ||
| 144 | .only_rule = {'Z','E','R','O','-','P','A','D'} | ||
| 145 | }; | ||
| 146 | struct { | ||
| 147 | struct type6_hdr hdr; | ||
| 148 | struct CPRBX cprbx; | ||
| 149 | struct function_and_rules_block fr; | ||
| 150 | unsigned short length; | ||
| 151 | char text[0]; | ||
| 152 | } __attribute__((packed)) *msg = ap_msg->message; | ||
| 153 | int size; | ||
| 154 | |||
| 155 | /* VUD.ciphertext */ | ||
| 156 | msg->length = mex->inputdatalength + 2; | ||
| 157 | if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength)) | ||
| 158 | return -EFAULT; | ||
| 159 | |||
| 160 | /* Set up key which is located after the variable length text. */ | ||
| 161 | size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1); | ||
| 162 | if (size < 0) | ||
| 163 | return size; | ||
| 164 | size += sizeof(*msg) + mex->inputdatalength; | ||
| 165 | |||
| 166 | /* message header, cprbx and f&r */ | ||
| 167 | msg->hdr = static_type6_hdrX; | ||
| 168 | msg->hdr.ToCardLen1 = size - sizeof(msg->hdr); | ||
| 169 | msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); | ||
| 170 | |||
| 171 | msg->cprbx = static_cprbx; | ||
| 172 | msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); | ||
| 173 | msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1; | ||
| 174 | |||
| 175 | msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? | ||
| 176 | static_pke_fnr_MCL2 : static_pke_fnr; | ||
| 177 | |||
| 178 | msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx); | ||
| 179 | |||
| 180 | ap_msg->length = size; | ||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 185 | * Convert a ICACRT message to a type6 CRT message. | ||
| 186 | * | ||
| 187 | * @zdev: crypto device pointer | ||
| 188 | * @ap_msg: pointer to AP message | ||
| 189 | * @crt: pointer to user input data | ||
| 190 | * | ||
| 191 | * Returns 0 on success or -EFAULT. | ||
| 192 | */ | ||
| 193 | static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, | ||
| 194 | struct ap_message *ap_msg, | ||
| 195 | struct ica_rsa_modexpo_crt *crt) | ||
| 196 | { | ||
| 197 | static struct type6_hdr static_type6_hdrX = { | ||
| 198 | .type = 0x06, | ||
| 199 | .offset1 = 0x00000058, | ||
| 200 | .agent_id = {'C','A',}, | ||
| 201 | .function_code = {'P','D'}, | ||
| 202 | }; | ||
| 203 | static struct function_and_rules_block static_pkd_fnr = { | ||
| 204 | .function_code = {'P','D'}, | ||
| 205 | .ulen = 10, | ||
| 206 | .only_rule = {'Z','E','R','O','-','P','A','D'} | ||
| 207 | }; | ||
| 208 | |||
| 209 | static struct function_and_rules_block static_pkd_fnr_MCL2 = { | ||
| 210 | .function_code = {'P','D'}, | ||
| 211 | .ulen = 10, | ||
| 212 | .only_rule = {'P','K','C','S','-','1','.','2'} | ||
| 213 | }; | ||
| 214 | struct { | ||
| 215 | struct type6_hdr hdr; | ||
| 216 | struct CPRBX cprbx; | ||
| 217 | struct function_and_rules_block fr; | ||
| 218 | unsigned short length; | ||
| 219 | char text[0]; | ||
| 220 | } __attribute__((packed)) *msg = ap_msg->message; | ||
| 221 | int size; | ||
| 222 | |||
| 223 | /* VUD.ciphertext */ | ||
| 224 | msg->length = crt->inputdatalength + 2; | ||
| 225 | if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength)) | ||
| 226 | return -EFAULT; | ||
| 227 | |||
| 228 | /* Set up key which is located after the variable length text. */ | ||
| 229 | size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1); | ||
| 230 | if (size < 0) | ||
| 231 | return size; | ||
| 232 | size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */ | ||
| 233 | |||
| 234 | /* message header, cprbx and f&r */ | ||
| 235 | msg->hdr = static_type6_hdrX; | ||
| 236 | msg->hdr.ToCardLen1 = size - sizeof(msg->hdr); | ||
| 237 | msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); | ||
| 238 | |||
| 239 | msg->cprbx = static_cprbx; | ||
| 240 | msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); | ||
| 241 | msg->cprbx.req_parml = msg->cprbx.rpl_msgbl = | ||
| 242 | size - sizeof(msg->hdr) - sizeof(msg->cprbx); | ||
| 243 | |||
| 244 | msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? | ||
| 245 | static_pkd_fnr_MCL2 : static_pkd_fnr; | ||
| 246 | |||
| 247 | ap_msg->length = size; | ||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | /** | ||
| 252 | * Convert a XCRB message to a type6 CPRB message. | ||
| 253 | * | ||
| 254 | * @zdev: crypto device pointer | ||
| 255 | * @ap_msg: pointer to AP message | ||
| 256 | * @xcRB: pointer to user input data | ||
| 257 | * | ||
| 258 | * Returns 0 on success or -EFAULT, -EINVAL. | ||
| 259 | */ | ||
| 260 | struct type86_fmt2_msg { | ||
| 261 | struct type86_hdr hdr; | ||
| 262 | struct type86_fmt2_ext fmt2; | ||
| 263 | } __attribute__((packed)); | ||
| 264 | |||
| 265 | static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, | ||
| 266 | struct ap_message *ap_msg, | ||
| 267 | struct ica_xcRB *xcRB) | ||
| 268 | { | ||
| 269 | static struct type6_hdr static_type6_hdrX = { | ||
| 270 | .type = 0x06, | ||
| 271 | .offset1 = 0x00000058, | ||
| 272 | }; | ||
| 273 | struct { | ||
| 274 | struct type6_hdr hdr; | ||
| 275 | struct CPRBX cprbx; | ||
| 276 | } __attribute__((packed)) *msg = ap_msg->message; | ||
| 277 | |||
| 278 | int rcblen = CEIL4(xcRB->request_control_blk_length); | ||
| 279 | int replylen; | ||
| 280 | char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen; | ||
| 281 | char *function_code; | ||
| 282 | |||
| 283 | /* length checks */ | ||
| 284 | ap_msg->length = sizeof(struct type6_hdr) + | ||
| 285 | CEIL4(xcRB->request_control_blk_length) + | ||
| 286 | xcRB->request_data_length; | ||
| 287 | if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) | ||
| 288 | return -EINVAL; | ||
| 289 | replylen = sizeof(struct type86_fmt2_msg) + | ||
| 290 | CEIL4(xcRB->reply_control_blk_length) + | ||
| 291 | xcRB->reply_data_length; | ||
| 292 | if (replylen > PCIXCC_MAX_XCRB_MESSAGE_SIZE) | ||
| 293 | return -EINVAL; | ||
| 294 | |||
| 295 | /* prepare type6 header */ | ||
| 296 | msg->hdr = static_type6_hdrX; | ||
| 297 | memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID)); | ||
| 298 | msg->hdr.ToCardLen1 = xcRB->request_control_blk_length; | ||
| 299 | if (xcRB->request_data_length) { | ||
| 300 | msg->hdr.offset2 = msg->hdr.offset1 + rcblen; | ||
| 301 | msg->hdr.ToCardLen2 = xcRB->request_data_length; | ||
| 302 | } | ||
| 303 | msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length; | ||
| 304 | msg->hdr.FromCardLen2 = xcRB->reply_data_length; | ||
| 305 | |||
| 306 | /* prepare CPRB */ | ||
| 307 | if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr, | ||
| 308 | xcRB->request_control_blk_length)) | ||
| 309 | return -EFAULT; | ||
| 310 | if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) > | ||
| 311 | xcRB->request_control_blk_length) | ||
| 312 | return -EINVAL; | ||
| 313 | function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len; | ||
| 314 | memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code)); | ||
| 315 | |||
| 316 | if (memcmp(function_code, "US", 2) == 0) | ||
| 317 | ap_msg->special = 1; | ||
| 318 | else | ||
| 319 | ap_msg->special = 0; | ||
| 320 | |||
| 321 | /* copy data block */ | ||
| 322 | if (xcRB->request_data_length && | ||
| 323 | copy_from_user(req_data, xcRB->request_data_address, | ||
| 324 | xcRB->request_data_length)) | ||
| 325 | return -EFAULT; | ||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | |||
| 329 | /** | ||
| 330 | * Prepare a type6 CPRB message for random number generation | ||
| 331 | * | ||
| 332 | * @ap_dev: AP device pointer | ||
| 333 | * @ap_msg: pointer to AP message | ||
| 334 | */ | ||
| 335 | static void rng_type6CPRB_msgX(struct ap_device *ap_dev, | ||
| 336 | struct ap_message *ap_msg, | ||
| 337 | unsigned random_number_length) | ||
| 338 | { | ||
| 339 | struct { | ||
| 340 | struct type6_hdr hdr; | ||
| 341 | struct CPRBX cprbx; | ||
| 342 | char function_code[2]; | ||
| 343 | short int rule_length; | ||
| 344 | char rule[8]; | ||
| 345 | short int verb_length; | ||
| 346 | short int key_length; | ||
| 347 | } __attribute__((packed)) *msg = ap_msg->message; | ||
| 348 | static struct type6_hdr static_type6_hdrX = { | ||
| 349 | .type = 0x06, | ||
| 350 | .offset1 = 0x00000058, | ||
| 351 | .agent_id = {'C', 'A'}, | ||
| 352 | .function_code = {'R', 'L'}, | ||
| 353 | .ToCardLen1 = sizeof *msg - sizeof(msg->hdr), | ||
| 354 | .FromCardLen1 = sizeof *msg - sizeof(msg->hdr), | ||
| 355 | }; | ||
| 356 | static struct CPRBX local_cprbx = { | ||
| 357 | .cprb_len = 0x00dc, | ||
| 358 | .cprb_ver_id = 0x02, | ||
| 359 | .func_id = {0x54, 0x32}, | ||
| 360 | .req_parml = sizeof *msg - sizeof(msg->hdr) - | ||
| 361 | sizeof(msg->cprbx), | ||
| 362 | .rpl_msgbl = sizeof *msg - sizeof(msg->hdr), | ||
| 363 | }; | ||
| 364 | |||
| 365 | msg->hdr = static_type6_hdrX; | ||
| 366 | msg->hdr.FromCardLen2 = random_number_length, | ||
| 367 | msg->cprbx = local_cprbx; | ||
| 368 | msg->cprbx.rpl_datal = random_number_length, | ||
| 369 | msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); | ||
| 370 | memcpy(msg->function_code, msg->hdr.function_code, 0x02); | ||
| 371 | msg->rule_length = 0x0a; | ||
| 372 | memcpy(msg->rule, "RANDOM ", 8); | ||
| 373 | msg->verb_length = 0x02; | ||
| 374 | msg->key_length = 0x02; | ||
| 375 | ap_msg->length = sizeof *msg; | ||
| 376 | } | ||
| 377 | |||
| 378 | /** | ||
| 379 | * Copy results from a type 86 ICA reply message back to user space. | ||
| 380 | * | ||
| 381 | * @zdev: crypto device pointer | ||
| 382 | * @reply: reply AP message. | ||
| 383 | * @data: pointer to user output data | ||
| 384 | * @length: size of user output data | ||
| 385 | * | ||
| 386 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. | ||
| 387 | */ | ||
| 388 | struct type86x_reply { | ||
| 389 | struct type86_hdr hdr; | ||
| 390 | struct type86_fmt2_ext fmt2; | ||
| 391 | struct CPRBX cprbx; | ||
| 392 | unsigned char pad[4]; /* 4 byte function code/rules block ? */ | ||
| 393 | unsigned short length; | ||
| 394 | char text[0]; | ||
| 395 | } __attribute__((packed)); | ||
| 396 | |||
| 397 | static int convert_type86_ica(struct zcrypt_device *zdev, | ||
| 398 | struct ap_message *reply, | ||
| 399 | char __user *outputdata, | ||
| 400 | unsigned int outputdatalength) | ||
| 401 | { | ||
| 402 | static unsigned char static_pad[] = { | ||
| 403 | 0x00,0x02, | ||
| 404 | 0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD, | ||
| 405 | 0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57, | ||
| 406 | 0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B, | ||
| 407 | 0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39, | ||
| 408 | 0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5, | ||
| 409 | 0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D, | ||
| 410 | 0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB, | ||
| 411 | 0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F, | ||
| 412 | 0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9, | ||
| 413 | 0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45, | ||
| 414 | 0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9, | ||
| 415 | 0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F, | ||
| 416 | 0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD, | ||
| 417 | 0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D, | ||
| 418 | 0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD, | ||
| 419 | 0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9, | ||
| 420 | 0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B, | ||
| 421 | 0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B, | ||
| 422 | 0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B, | ||
| 423 | 0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD, | ||
| 424 | 0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7, | ||
| 425 | 0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1, | ||
| 426 | 0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3, | ||
| 427 | 0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23, | ||
| 428 | 0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55, | ||
| 429 | 0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43, | ||
| 430 | 0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F, | ||
| 431 | 0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F, | ||
| 432 | 0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5, | ||
| 433 | 0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD, | ||
| 434 | 0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41, | ||
| 435 | 0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09 | ||
| 436 | }; | ||
| 437 | struct type86x_reply *msg = reply->message; | ||
| 438 | unsigned short service_rc, service_rs; | ||
| 439 | unsigned int reply_len, pad_len; | ||
| 440 | char *data; | ||
| 441 | |||
| 442 | service_rc = msg->cprbx.ccp_rtcode; | ||
| 443 | if (unlikely(service_rc != 0)) { | ||
| 444 | service_rs = msg->cprbx.ccp_rscode; | ||
| 445 | if (service_rc == 8 && service_rs == 66) | ||
| 446 | return -EINVAL; | ||
| 447 | if (service_rc == 8 && service_rs == 65) | ||
| 448 | return -EINVAL; | ||
| 449 | if (service_rc == 8 && service_rs == 770) | ||
| 450 | return -EINVAL; | ||
| 451 | if (service_rc == 8 && service_rs == 783) { | ||
| 452 | zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; | ||
| 453 | return -EAGAIN; | ||
| 454 | } | ||
| 455 | if (service_rc == 12 && service_rs == 769) | ||
| 456 | return -EINVAL; | ||
| 457 | if (service_rc == 8 && service_rs == 72) | ||
| 458 | return -EINVAL; | ||
| 459 | zdev->online = 0; | ||
| 460 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 461 | } | ||
| 462 | data = msg->text; | ||
| 463 | reply_len = msg->length - 2; | ||
| 464 | if (reply_len > outputdatalength) | ||
| 465 | return -EINVAL; | ||
| 466 | /* | ||
| 467 | * For all encipher requests, the length of the ciphertext (reply_len) | ||
| 468 | * will always equal the modulus length. For MEX decipher requests | ||
| 469 | * the output needs to get padded. Minimum pad size is 10. | ||
| 470 | * | ||
| 471 | * Currently, the cases where padding will be added is for: | ||
| 472 | * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support | ||
| 473 | * ZERO-PAD and CRT is only supported for PKD requests) | ||
| 474 | * - PCICC, always | ||
| 475 | */ | ||
| 476 | pad_len = outputdatalength - reply_len; | ||
| 477 | if (pad_len > 0) { | ||
| 478 | if (pad_len < 10) | ||
| 479 | return -EINVAL; | ||
| 480 | /* 'restore' padding left in the PCICC/PCIXCC card. */ | ||
| 481 | if (copy_to_user(outputdata, static_pad, pad_len - 1)) | ||
| 482 | return -EFAULT; | ||
| 483 | if (put_user(0, outputdata + pad_len - 1)) | ||
| 484 | return -EFAULT; | ||
| 485 | } | ||
| 486 | /* Copy the crypto response to user space. */ | ||
| 487 | if (copy_to_user(outputdata + pad_len, data, reply_len)) | ||
| 488 | return -EFAULT; | ||
| 489 | return 0; | ||
| 490 | } | ||
| 491 | |||
| 492 | /** | ||
| 493 | * Copy results from a type 86 XCRB reply message back to user space. | ||
| 494 | * | ||
| 495 | * @zdev: crypto device pointer | ||
| 496 | * @reply: reply AP message. | ||
| 497 | * @xcRB: pointer to XCRB | ||
| 498 | * | ||
| 499 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. | ||
| 500 | */ | ||
| 501 | static int convert_type86_xcrb(struct zcrypt_device *zdev, | ||
| 502 | struct ap_message *reply, | ||
| 503 | struct ica_xcRB *xcRB) | ||
| 504 | { | ||
| 505 | struct type86_fmt2_msg *msg = reply->message; | ||
| 506 | char *data = reply->message; | ||
| 507 | |||
| 508 | /* Copy CPRB to user */ | ||
| 509 | if (copy_to_user(xcRB->reply_control_blk_addr, | ||
| 510 | data + msg->fmt2.offset1, msg->fmt2.count1)) | ||
| 511 | return -EFAULT; | ||
| 512 | xcRB->reply_control_blk_length = msg->fmt2.count1; | ||
| 513 | |||
| 514 | /* Copy data buffer to user */ | ||
| 515 | if (msg->fmt2.count2) | ||
| 516 | if (copy_to_user(xcRB->reply_data_addr, | ||
| 517 | data + msg->fmt2.offset2, msg->fmt2.count2)) | ||
| 518 | return -EFAULT; | ||
| 519 | xcRB->reply_data_length = msg->fmt2.count2; | ||
| 520 | return 0; | ||
| 521 | } | ||
| 522 | |||
| 523 | static int convert_type86_rng(struct zcrypt_device *zdev, | ||
| 524 | struct ap_message *reply, | ||
| 525 | char *buffer) | ||
| 526 | { | ||
| 527 | struct { | ||
| 528 | struct type86_hdr hdr; | ||
| 529 | struct type86_fmt2_ext fmt2; | ||
| 530 | struct CPRBX cprbx; | ||
| 531 | } __attribute__((packed)) *msg = reply->message; | ||
| 532 | char *data = reply->message; | ||
| 533 | |||
| 534 | if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) | ||
| 535 | return -EINVAL; | ||
| 536 | memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2); | ||
| 537 | return msg->fmt2.count2; | ||
| 538 | } | ||
| 539 | |||
| 540 | static int convert_response_ica(struct zcrypt_device *zdev, | ||
| 541 | struct ap_message *reply, | ||
| 542 | char __user *outputdata, | ||
| 543 | unsigned int outputdatalength) | ||
| 544 | { | ||
| 545 | struct type86x_reply *msg = reply->message; | ||
| 546 | |||
| 547 | /* Response type byte is the second byte in the response. */ | ||
| 548 | switch (((unsigned char *) reply->message)[1]) { | ||
| 549 | case TYPE82_RSP_CODE: | ||
| 550 | case TYPE88_RSP_CODE: | ||
| 551 | return convert_error(zdev, reply); | ||
| 552 | case TYPE86_RSP_CODE: | ||
| 553 | if (msg->cprbx.ccp_rtcode && | ||
| 554 | (msg->cprbx.ccp_rscode == 0x14f) && | ||
| 555 | (outputdatalength > 256)) { | ||
| 556 | if (zdev->max_exp_bit_length <= 17) { | ||
| 557 | zdev->max_exp_bit_length = 17; | ||
| 558 | return -EAGAIN; | ||
| 559 | } else | ||
| 560 | return -EINVAL; | ||
| 561 | } | ||
| 562 | if (msg->hdr.reply_code) | ||
| 563 | return convert_error(zdev, reply); | ||
| 564 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 565 | return convert_type86_ica(zdev, reply, | ||
| 566 | outputdata, outputdatalength); | ||
| 567 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 568 | * response */ | ||
| 569 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 570 | zdev->online = 0; | ||
| 571 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 572 | } | ||
| 573 | } | ||
| 574 | |||
| 575 | static int convert_response_xcrb(struct zcrypt_device *zdev, | ||
| 576 | struct ap_message *reply, | ||
| 577 | struct ica_xcRB *xcRB) | ||
| 578 | { | ||
| 579 | struct type86x_reply *msg = reply->message; | ||
| 580 | |||
| 581 | /* Response type byte is the second byte in the response. */ | ||
| 582 | switch (((unsigned char *) reply->message)[1]) { | ||
| 583 | case TYPE82_RSP_CODE: | ||
| 584 | case TYPE88_RSP_CODE: | ||
| 585 | xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ | ||
| 586 | return convert_error(zdev, reply); | ||
| 587 | case TYPE86_RSP_CODE: | ||
| 588 | if (msg->hdr.reply_code) { | ||
| 589 | memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32)); | ||
| 590 | return convert_error(zdev, reply); | ||
| 591 | } | ||
| 592 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 593 | return convert_type86_xcrb(zdev, reply, xcRB); | ||
| 594 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 595 | * response */ | ||
| 596 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 597 | xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ | ||
| 598 | zdev->online = 0; | ||
| 599 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 600 | } | ||
| 601 | } | ||
| 602 | |||
| 603 | static int convert_response_rng(struct zcrypt_device *zdev, | ||
| 604 | struct ap_message *reply, | ||
| 605 | char *data) | ||
| 606 | { | ||
| 607 | struct type86x_reply *msg = reply->message; | ||
| 608 | |||
| 609 | switch (msg->hdr.type) { | ||
| 610 | case TYPE82_RSP_CODE: | ||
| 611 | case TYPE88_RSP_CODE: | ||
| 612 | return -EINVAL; | ||
| 613 | case TYPE86_RSP_CODE: | ||
| 614 | if (msg->hdr.reply_code) | ||
| 615 | return -EINVAL; | ||
| 616 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
| 617 | return convert_type86_rng(zdev, reply, data); | ||
| 618 | /* Fall through, no break, incorrect cprb version is an unknown | ||
| 619 | * response */ | ||
| 620 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
| 621 | zdev->online = 0; | ||
| 622 | return -EAGAIN; /* repeat the request on a different device. */ | ||
| 623 | } | ||
| 624 | } | ||
| 625 | |||
| 626 | /** | ||
| 627 | * This function is called from the AP bus code after a crypto request | ||
| 628 | * "msg" has finished with the reply message "reply". | ||
| 629 | * It is called from tasklet context. | ||
| 630 | * @ap_dev: pointer to the AP device | ||
| 631 | * @msg: pointer to the AP message | ||
| 632 | * @reply: pointer to the AP reply message | ||
| 633 | */ | ||
| 634 | static void zcrypt_pcixcc_receive(struct ap_device *ap_dev, | ||
| 635 | struct ap_message *msg, | ||
| 636 | struct ap_message *reply) | ||
| 637 | { | ||
| 638 | static struct error_hdr error_reply = { | ||
| 639 | .type = TYPE82_RSP_CODE, | ||
| 640 | .reply_code = REP82_ERROR_MACHINE_FAILURE, | ||
| 641 | }; | ||
| 642 | struct response_type *resp_type = | ||
| 643 | (struct response_type *) msg->private; | ||
| 644 | struct type86x_reply *t86r; | ||
| 645 | int length; | ||
| 646 | |||
| 647 | /* Copy the reply message to the request message buffer. */ | ||
| 648 | if (IS_ERR(reply)) { | ||
| 649 | memcpy(msg->message, &error_reply, sizeof(error_reply)); | ||
| 650 | goto out; | ||
| 651 | } | ||
| 652 | t86r = reply->message; | ||
| 653 | if (t86r->hdr.type == TYPE86_RSP_CODE && | ||
| 654 | t86r->cprbx.cprb_ver_id == 0x02) { | ||
| 655 | switch (resp_type->type) { | ||
| 656 | case PCIXCC_RESPONSE_TYPE_ICA: | ||
| 657 | length = sizeof(struct type86x_reply) | ||
| 658 | + t86r->length - 2; | ||
| 659 | length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length); | ||
| 660 | memcpy(msg->message, reply->message, length); | ||
| 661 | break; | ||
| 662 | case PCIXCC_RESPONSE_TYPE_XCRB: | ||
| 663 | length = t86r->fmt2.offset2 + t86r->fmt2.count2; | ||
| 664 | length = min(PCIXCC_MAX_XCRB_MESSAGE_SIZE, length); | ||
| 665 | memcpy(msg->message, reply->message, length); | ||
| 666 | break; | ||
| 667 | default: | ||
| 668 | memcpy(msg->message, &error_reply, sizeof error_reply); | ||
| 669 | } | ||
| 670 | } else | ||
| 671 | memcpy(msg->message, reply->message, sizeof error_reply); | ||
| 672 | out: | ||
| 673 | complete(&(resp_type->work)); | ||
| 674 | } | ||
| 675 | |||
| 676 | static atomic_t zcrypt_step = ATOMIC_INIT(0); | ||
| 677 | |||
| 678 | /** | ||
| 679 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 680 | * device to handle a modexpo request. | ||
| 681 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 682 | * PCIXCC/CEX2C device to the request distributor | ||
| 683 | * @mex: pointer to the modexpo request buffer | ||
| 684 | */ | ||
| 685 | static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev, | ||
| 686 | struct ica_rsa_modexpo *mex) | ||
| 687 | { | ||
| 688 | struct ap_message ap_msg; | ||
| 689 | struct response_type resp_type = { | ||
| 690 | .type = PCIXCC_RESPONSE_TYPE_ICA, | ||
| 691 | }; | ||
| 692 | int rc; | ||
| 693 | |||
| 694 | ap_init_message(&ap_msg); | ||
| 695 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); | ||
| 696 | if (!ap_msg.message) | ||
| 697 | return -ENOMEM; | ||
| 698 | ap_msg.receive = zcrypt_pcixcc_receive; | ||
| 699 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 700 | atomic_inc_return(&zcrypt_step); | ||
| 701 | ap_msg.private = &resp_type; | ||
| 702 | rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex); | ||
| 703 | if (rc) | ||
| 704 | goto out_free; | ||
| 705 | init_completion(&resp_type.work); | ||
| 706 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 707 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 708 | if (rc == 0) | ||
| 709 | rc = convert_response_ica(zdev, &ap_msg, mex->outputdata, | ||
| 710 | mex->outputdatalength); | ||
| 711 | else | ||
| 712 | /* Signal pending. */ | ||
| 713 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 714 | out_free: | ||
| 715 | free_page((unsigned long) ap_msg.message); | ||
| 716 | return rc; | ||
| 717 | } | ||
| 718 | |||
| 719 | /** | ||
| 720 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 721 | * device to handle a modexpo_crt request. | ||
| 722 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 723 | * PCIXCC/CEX2C device to the request distributor | ||
| 724 | * @crt: pointer to the modexpoc_crt request buffer | ||
| 725 | */ | ||
| 726 | static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev, | ||
| 727 | struct ica_rsa_modexpo_crt *crt) | ||
| 728 | { | ||
| 729 | struct ap_message ap_msg; | ||
| 730 | struct response_type resp_type = { | ||
| 731 | .type = PCIXCC_RESPONSE_TYPE_ICA, | ||
| 732 | }; | ||
| 733 | int rc; | ||
| 734 | |||
| 735 | ap_init_message(&ap_msg); | ||
| 736 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); | ||
| 737 | if (!ap_msg.message) | ||
| 738 | return -ENOMEM; | ||
| 739 | ap_msg.receive = zcrypt_pcixcc_receive; | ||
| 740 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 741 | atomic_inc_return(&zcrypt_step); | ||
| 742 | ap_msg.private = &resp_type; | ||
| 743 | rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt); | ||
| 744 | if (rc) | ||
| 745 | goto out_free; | ||
| 746 | init_completion(&resp_type.work); | ||
| 747 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 748 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 749 | if (rc == 0) | ||
| 750 | rc = convert_response_ica(zdev, &ap_msg, crt->outputdata, | ||
| 751 | crt->outputdatalength); | ||
| 752 | else | ||
| 753 | /* Signal pending. */ | ||
| 754 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 755 | out_free: | ||
| 756 | free_page((unsigned long) ap_msg.message); | ||
| 757 | return rc; | ||
| 758 | } | ||
| 759 | |||
| 760 | /** | ||
| 761 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 762 | * device to handle a send_cprb request. | ||
| 763 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 764 | * PCIXCC/CEX2C device to the request distributor | ||
| 765 | * @xcRB: pointer to the send_cprb request buffer | ||
| 766 | */ | ||
| 767 | static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, | ||
| 768 | struct ica_xcRB *xcRB) | ||
| 769 | { | ||
| 770 | struct ap_message ap_msg; | ||
| 771 | struct response_type resp_type = { | ||
| 772 | .type = PCIXCC_RESPONSE_TYPE_XCRB, | ||
| 773 | }; | ||
| 774 | int rc; | ||
| 775 | |||
| 776 | ap_init_message(&ap_msg); | ||
| 777 | ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL); | ||
| 778 | if (!ap_msg.message) | ||
| 779 | return -ENOMEM; | ||
| 780 | ap_msg.receive = zcrypt_pcixcc_receive; | ||
| 781 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 782 | atomic_inc_return(&zcrypt_step); | ||
| 783 | ap_msg.private = &resp_type; | ||
| 784 | rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB); | ||
| 785 | if (rc) | ||
| 786 | goto out_free; | ||
| 787 | init_completion(&resp_type.work); | ||
| 788 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 789 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 790 | if (rc == 0) | ||
| 791 | rc = convert_response_xcrb(zdev, &ap_msg, xcRB); | ||
| 792 | else | ||
| 793 | /* Signal pending. */ | ||
| 794 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 795 | out_free: | ||
| 796 | kzfree(ap_msg.message); | ||
| 797 | return rc; | ||
| 798 | } | ||
| 799 | |||
| 800 | /** | ||
| 801 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
| 802 | * device to generate random data. | ||
| 803 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
| 804 | * PCIXCC/CEX2C device to the request distributor | ||
| 805 | * @buffer: pointer to a memory page to return random data | ||
| 806 | */ | ||
| 807 | |||
| 808 | static long zcrypt_pcixcc_rng(struct zcrypt_device *zdev, | ||
| 809 | char *buffer) | ||
| 810 | { | ||
| 811 | struct ap_message ap_msg; | ||
| 812 | struct response_type resp_type = { | ||
| 813 | .type = PCIXCC_RESPONSE_TYPE_XCRB, | ||
| 814 | }; | ||
| 815 | int rc; | ||
| 816 | |||
| 817 | ap_init_message(&ap_msg); | ||
| 818 | ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL); | ||
| 819 | if (!ap_msg.message) | ||
| 820 | return -ENOMEM; | ||
| 821 | ap_msg.receive = zcrypt_pcixcc_receive; | ||
| 822 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
| 823 | atomic_inc_return(&zcrypt_step); | ||
| 824 | ap_msg.private = &resp_type; | ||
| 825 | rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE); | ||
| 826 | init_completion(&resp_type.work); | ||
| 827 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
| 828 | rc = wait_for_completion_interruptible(&resp_type.work); | ||
| 829 | if (rc == 0) | ||
| 830 | rc = convert_response_rng(zdev, &ap_msg, buffer); | ||
| 831 | else | ||
| 832 | /* Signal pending. */ | ||
| 833 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
| 834 | kfree(ap_msg.message); | ||
| 835 | return rc; | ||
| 836 | } | ||
| 837 | |||
| 838 | /** | ||
| 839 | * The crypto operations for a PCIXCC/CEX2C card. | ||
| 840 | */ | ||
| 841 | static struct zcrypt_ops zcrypt_pcixcc_ops = { | ||
| 842 | .rsa_modexpo = zcrypt_pcixcc_modexpo, | ||
| 843 | .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt, | ||
| 844 | .send_cprb = zcrypt_pcixcc_send_cprb, | ||
| 845 | }; | ||
| 846 | |||
| 847 | static struct zcrypt_ops zcrypt_pcixcc_with_rng_ops = { | ||
| 848 | .rsa_modexpo = zcrypt_pcixcc_modexpo, | ||
| 849 | .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt, | ||
| 850 | .send_cprb = zcrypt_pcixcc_send_cprb, | ||
| 851 | .rng = zcrypt_pcixcc_rng, | ||
| 852 | }; | ||
| 853 | |||
| 854 | /** | ||
| 855 | * Micro-code detection function. Its sends a message to a pcixcc card | 95 | * Micro-code detection function. Its sends a message to a pcixcc card |
| 856 | * to find out the microcode level. | 96 | * to find out the microcode level. |
| 857 | * @ap_dev: pointer to the AP device. | 97 | * @ap_dev: pointer to the AP device. |
| @@ -1083,9 +323,11 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) | |||
| 1083 | return rc; | 323 | return rc; |
| 1084 | } | 324 | } |
| 1085 | if (rc) | 325 | if (rc) |
| 1086 | zdev->ops = &zcrypt_pcixcc_with_rng_ops; | 326 | zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, |
| 327 | MSGTYPE06_VARIANT_DEFAULT); | ||
| 1087 | else | 328 | else |
| 1088 | zdev->ops = &zcrypt_pcixcc_ops; | 329 | zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, |
| 330 | MSGTYPE06_VARIANT_NORNG); | ||
| 1089 | ap_dev->reply = &zdev->reply; | 331 | ap_dev->reply = &zdev->reply; |
| 1090 | ap_dev->private = zdev; | 332 | ap_dev->private = zdev; |
| 1091 | rc = zcrypt_device_register(zdev); | 333 | rc = zcrypt_device_register(zdev); |
| @@ -1095,6 +337,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) | |||
| 1095 | 337 | ||
| 1096 | out_free: | 338 | out_free: |
| 1097 | ap_dev->private = NULL; | 339 | ap_dev->private = NULL; |
| 340 | zcrypt_msgtype_release(zdev->ops); | ||
| 1098 | zcrypt_device_free(zdev); | 341 | zcrypt_device_free(zdev); |
| 1099 | return rc; | 342 | return rc; |
| 1100 | } | 343 | } |
| @@ -1106,8 +349,10 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) | |||
| 1106 | static void zcrypt_pcixcc_remove(struct ap_device *ap_dev) | 349 | static void zcrypt_pcixcc_remove(struct ap_device *ap_dev) |
| 1107 | { | 350 | { |
| 1108 | struct zcrypt_device *zdev = ap_dev->private; | 351 | struct zcrypt_device *zdev = ap_dev->private; |
| 352 | struct zcrypt_ops *zops = zdev->ops; | ||
| 1109 | 353 | ||
| 1110 | zcrypt_device_unregister(zdev); | 354 | zcrypt_device_unregister(zdev); |
| 355 | zcrypt_msgtype_release(zops); | ||
| 1111 | } | 356 | } |
| 1112 | 357 | ||
| 1113 | int __init zcrypt_pcixcc_init(void) | 358 | int __init zcrypt_pcixcc_init(void) |
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h index c7cdf599e46b..eacafc8962f2 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.h +++ b/drivers/s390/crypto/zcrypt_pcixcc.h | |||
| @@ -1,12 +1,13 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * zcrypt 2.1.0 | 2 | * zcrypt 2.1.0 |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2001, 2006 | 4 | * Copyright IBM Corp. 2001, 2012 |
| 5 | * Author(s): Robert Burroughs | 5 | * Author(s): Robert Burroughs |
| 6 | * Eric Rossman (edrossma@us.ibm.com) | 6 | * Eric Rossman (edrossma@us.ibm.com) |
| 7 | * | 7 | * |
| 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | 8 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
| 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | 9 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 10 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> | ||
| 10 | * | 11 | * |
| 11 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 7a8b09612c41..cf6da7fafe54 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
| @@ -2993,7 +2993,7 @@ static void qeth_get_trap_id(struct qeth_card *card, struct qeth_trap_id *tid) | |||
| 2993 | struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info; | 2993 | struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info; |
| 2994 | struct sysinfo_3_2_2 *info322 = (struct sysinfo_3_2_2 *)info; | 2994 | struct sysinfo_3_2_2 *info322 = (struct sysinfo_3_2_2 *)info; |
| 2995 | struct ccw_dev_id ccwid; | 2995 | struct ccw_dev_id ccwid; |
| 2996 | int level, rc; | 2996 | int level; |
| 2997 | 2997 | ||
| 2998 | tid->chpid = card->info.chpid; | 2998 | tid->chpid = card->info.chpid; |
| 2999 | ccw_device_get_id(CARD_RDEV(card), &ccwid); | 2999 | ccw_device_get_id(CARD_RDEV(card), &ccwid); |
| @@ -3001,17 +3001,10 @@ static void qeth_get_trap_id(struct qeth_card *card, struct qeth_trap_id *tid) | |||
| 3001 | tid->devno = ccwid.devno; | 3001 | tid->devno = ccwid.devno; |
| 3002 | if (!info) | 3002 | if (!info) |
| 3003 | return; | 3003 | return; |
| 3004 | 3004 | level = stsi(NULL, 0, 0, 0); | |
| 3005 | rc = stsi(NULL, 0, 0, 0); | 3005 | if ((level >= 2) && (stsi(info222, 2, 2, 2) == 0)) |
| 3006 | if (rc == -ENOSYS) | ||
| 3007 | level = rc; | ||
| 3008 | else | ||
| 3009 | level = (((unsigned int) rc) >> 28); | ||
| 3010 | |||
| 3011 | if ((level >= 2) && (stsi(info222, 2, 2, 2) != -ENOSYS)) | ||
| 3012 | tid->lparnr = info222->lpar_number; | 3006 | tid->lparnr = info222->lpar_number; |
| 3013 | 3007 | if ((level >= 3) && (stsi(info322, 3, 2, 2) == 0)) { | |
| 3014 | if ((level >= 3) && (stsi(info322, 3, 2, 2) != -ENOSYS)) { | ||
| 3015 | EBCASC(info322->vm[0].name, sizeof(info322->vm[0].name)); | 3008 | EBCASC(info322->vm[0].name, sizeof(info322->vm[0].name)); |
| 3016 | memcpy(tid->vmname, info322->vm[0].name, sizeof(tid->vmname)); | 3009 | memcpy(tid->vmname, info322->vm[0].name, sizeof(tid->vmname)); |
| 3017 | } | 3010 | } |
diff --git a/include/linux/elf.h b/include/linux/elf.h index 999b4f52e8e5..f930b1a390ab 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h | |||
| @@ -387,6 +387,7 @@ typedef struct elf64_shdr { | |||
| 387 | #define NT_S390_PREFIX 0x305 /* s390 prefix register */ | 387 | #define NT_S390_PREFIX 0x305 /* s390 prefix register */ |
| 388 | #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ | 388 | #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ |
| 389 | #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ | 389 | #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ |
| 390 | #define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ | ||
| 390 | #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ | 391 | #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ |
| 391 | 392 | ||
| 392 | 393 | ||
diff --git a/scripts/sortextable.c b/scripts/sortextable.c index 6acf83449105..f19ddc47304c 100644 --- a/scripts/sortextable.c +++ b/scripts/sortextable.c | |||
| @@ -161,7 +161,7 @@ typedef void (*table_sort_t)(char *, int); | |||
| 161 | #define SORTEXTABLE_64 | 161 | #define SORTEXTABLE_64 |
| 162 | #include "sortextable.h" | 162 | #include "sortextable.h" |
| 163 | 163 | ||
| 164 | static int compare_x86_table(const void *a, const void *b) | 164 | static int compare_relative_table(const void *a, const void *b) |
| 165 | { | 165 | { |
| 166 | int32_t av = (int32_t)r(a); | 166 | int32_t av = (int32_t)r(a); |
| 167 | int32_t bv = (int32_t)r(b); | 167 | int32_t bv = (int32_t)r(b); |
| @@ -173,7 +173,7 @@ static int compare_x86_table(const void *a, const void *b) | |||
| 173 | return 0; | 173 | return 0; |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | static void sort_x86_table(char *extab_image, int image_size) | 176 | static void sort_relative_table(char *extab_image, int image_size) |
| 177 | { | 177 | { |
| 178 | int i; | 178 | int i; |
| 179 | 179 | ||
| @@ -188,7 +188,7 @@ static void sort_x86_table(char *extab_image, int image_size) | |||
| 188 | i += 4; | 188 | i += 4; |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | qsort(extab_image, image_size / 8, 8, compare_x86_table); | 191 | qsort(extab_image, image_size / 8, 8, compare_relative_table); |
| 192 | 192 | ||
| 193 | /* Now denormalize. */ | 193 | /* Now denormalize. */ |
| 194 | i = 0; | 194 | i = 0; |
| @@ -245,9 +245,9 @@ do_file(char const *const fname) | |||
| 245 | break; | 245 | break; |
| 246 | case EM_386: | 246 | case EM_386: |
| 247 | case EM_X86_64: | 247 | case EM_X86_64: |
| 248 | custom_sort = sort_x86_table; | ||
| 249 | break; | ||
| 250 | case EM_S390: | 248 | case EM_S390: |
| 249 | custom_sort = sort_relative_table; | ||
| 250 | break; | ||
| 251 | case EM_MIPS: | 251 | case EM_MIPS: |
| 252 | break; | 252 | break; |
| 253 | } /* end switch */ | 253 | } /* end switch */ |
