提交 ff47d8c0 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Martin Schwidefsky:

 - New entropy generation for the pseudo random number generator.

 - Early boot printk output via sclp to help debug crashes on boot. This
   needs to be enabled with a kernel parameter.

 - Add proper no-execute support with a bit in the page table entry.

 - Bug fixes and cleanups.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (65 commits)
  s390/syscall: fix single stepped system calls
  s390/zcrypt: make ap_bus explicitly non-modular
  s390/zcrypt: Removed unneeded debug feature directory creation.
  s390: add missing "do {} while (0)" loop constructs to multiline macros
  s390/mm: add cond_resched call to kernel page table dumper
  s390: get rid of MACHINE_HAS_PFMF and MACHINE_HAS_HPAGE
  s390/mm: make memory_block_size_bytes available for !MEMORY_HOTPLUG
  s390: replace ACCESS_ONCE with READ_ONCE
  s390: Audit and remove any remaining unnecessary uses of module.h
  s390: mm: Audit and remove any unnecessary uses of module.h
  s390: kernel: Audit and remove any unnecessary uses of module.h
  s390/kdump: Use "LINUX" ELF note name instead of "CORE"
  s390: add no-execute support
  s390: report new vector facilities
  s390: use correct input data address for setup_randomness
  s390/sclp: get rid of common response code handling
  s390/sclp: don't add new lines to each printed string
  s390/sclp: make early sclp code readable
  s390/sclp: disable early sclp code as soon as the base sclp driver is active
  s390/sclp: move early printk code to drivers
  ...
...@@ -970,9 +970,10 @@ ...@@ -970,9 +970,10 @@
address. The serial port must already be setup address. The serial port must already be setup
and configured. Options are not yet supported. and configured. Options are not yet supported.
earlyprintk= [X86,SH,BLACKFIN,ARM,M68k] earlyprintk= [X86,SH,BLACKFIN,ARM,M68k,S390]
earlyprintk=vga earlyprintk=vga
earlyprintk=efi earlyprintk=efi
earlyprintk=sclp
earlyprintk=xen earlyprintk=xen
earlyprintk=serial[,ttySn[,baudrate]] earlyprintk=serial[,ttySn[,baudrate]]
earlyprintk=serial[,0x...[,baudrate]] earlyprintk=serial[,0x...[,baudrate]]
...@@ -1007,6 +1008,8 @@ ...@@ -1007,6 +1008,8 @@
The xen output can only be used by Xen PV guests. The xen output can only be used by Xen PV guests.
The sclp output can only be used on s390.
edac_report= [HW,EDAC] Control how to report EDAC event edac_report= [HW,EDAC] Control how to report EDAC event
Format: {"on" | "off" | "force"} Format: {"on" | "off" | "force"}
on: enable EDAC to report H/W event. May be overridden on: enable EDAC to report H/W event. May be overridden
......
...@@ -17,4 +17,7 @@ config S390_PTDUMP ...@@ -17,4 +17,7 @@ config S390_PTDUMP
kernel. kernel.
If in doubt, say "N" If in doubt, say "N"
config EARLY_PRINTK
def_bool y
endmenu endmenu
...@@ -19,7 +19,8 @@ KBUILD_CFLAGS += $(call cc-option,-ffreestanding) ...@@ -19,7 +19,8 @@ KBUILD_CFLAGS += $(call cc-option,-ffreestanding)
GCOV_PROFILE := n GCOV_PROFILE := n
UBSAN_SANITIZE := n UBSAN_SANITIZE := n
OBJECTS := $(addprefix $(objtree)/arch/s390/kernel/, head.o sclp.o ebcdic.o als.o) OBJECTS := $(addprefix $(objtree)/arch/s390/kernel/, head.o ebcdic.o als.o)
OBJECTS += $(objtree)/drivers/s390/char/sclp_early_core.o
OBJECTS += $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o OBJECTS += $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o
LDFLAGS_vmlinux := --oformat $(LD_BFD) -e startup -T LDFLAGS_vmlinux := --oformat $(LD_BFD) -e startup -T
......
...@@ -66,7 +66,7 @@ static unsigned long free_mem_end_ptr; ...@@ -66,7 +66,7 @@ static unsigned long free_mem_end_ptr;
static int puts(const char *s) static int puts(const char *s)
{ {
_sclp_print_early(s); sclp_early_printk(s);
return 0; return 0;
} }
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/cpufeature.h> #include <linux/cpufeature.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/fips.h>
#include <crypto/xts.h> #include <crypto/xts.h>
#include <asm/cpacf.h> #include <asm/cpacf.h>
...@@ -501,6 +502,12 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, ...@@ -501,6 +502,12 @@ static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
if (err) if (err)
return err; return err;
/* In fips mode only 128 bit or 256 bit keys are valid */
if (fips_enabled && key_len != 32 && key_len != 64) {
tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
/* Pick the correct function code based on the key length */ /* Pick the correct function code based on the key length */
fc = (key_len == 32) ? CPACF_KM_XTS_128 : fc = (key_len == 32) ? CPACF_KM_XTS_128 :
(key_len == 64) ? CPACF_KM_XTS_256 : 0; (key_len == 64) ? CPACF_KM_XTS_256 : 0;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/cpufeature.h> #include <linux/cpufeature.h>
#include <linux/crypto.h> #include <linux/crypto.h>
#include <linux/fips.h>
#include <crypto/algapi.h> #include <crypto/algapi.h>
#include <crypto/des.h> #include <crypto/des.h>
#include <asm/cpacf.h> #include <asm/cpacf.h>
...@@ -221,6 +222,8 @@ static struct crypto_alg cbc_des_alg = { ...@@ -221,6 +222,8 @@ static struct crypto_alg cbc_des_alg = {
* same as DES. Implementers MUST reject keys that exhibit this * same as DES. Implementers MUST reject keys that exhibit this
* property. * property.
* *
* In fips mode additinally check for all 3 keys are unique.
*
*/ */
static int des3_setkey(struct crypto_tfm *tfm, const u8 *key, static int des3_setkey(struct crypto_tfm *tfm, const u8 *key,
unsigned int key_len) unsigned int key_len)
...@@ -234,6 +237,17 @@ static int des3_setkey(struct crypto_tfm *tfm, const u8 *key, ...@@ -234,6 +237,17 @@ static int des3_setkey(struct crypto_tfm *tfm, const u8 *key,
tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
return -EINVAL; return -EINVAL;
} }
/* in fips mode, ensure k1 != k2 and k2 != k3 and k1 != k3 */
if (fips_enabled &&
!(crypto_memneq(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
crypto_memneq(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
DES_KEY_SIZE) &&
crypto_memneq(key, &key[DES_KEY_SIZE * 2], DES_KEY_SIZE))) {
tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
return -EINVAL;
}
memcpy(ctx->key, key, key_len); memcpy(ctx->key, key, key_len);
return 0; return 0;
} }
......
...@@ -110,22 +110,30 @@ static const u8 initial_parm_block[32] __initconst = { ...@@ -110,22 +110,30 @@ static const u8 initial_parm_block[32] __initconst = {
/*** helper functions ***/ /*** helper functions ***/
/*
* generate_entropy:
* This algorithm produces 64 bytes of entropy data based on 1024
* individual stckf() invocations assuming that each stckf() value
* contributes 0.25 bits of entropy. So the caller gets 256 bit
* entropy per 64 byte or 4 bits entropy per byte.
*/
static int generate_entropy(u8 *ebuf, size_t nbytes) static int generate_entropy(u8 *ebuf, size_t nbytes)
{ {
int n, ret = 0; int n, ret = 0;
u8 *pg, *h, hash[32]; u8 *pg, *h, hash[64];
pg = (u8 *) __get_free_page(GFP_KERNEL); /* allocate 2 pages */
pg = (u8 *) __get_free_pages(GFP_KERNEL, 1);
if (!pg) { if (!pg) {
prng_errorflag = PRNG_GEN_ENTROPY_FAILED; prng_errorflag = PRNG_GEN_ENTROPY_FAILED;
return -ENOMEM; return -ENOMEM;
} }
while (nbytes) { while (nbytes) {
/* fill page with urandom bytes */ /* fill pages with urandom bytes */
get_random_bytes(pg, PAGE_SIZE); get_random_bytes(pg, 2*PAGE_SIZE);
/* exor page with stckf values */ /* exor pages with 1024 stckf values */
for (n = 0; n < PAGE_SIZE / sizeof(u64); n++) { for (n = 0; n < 2 * PAGE_SIZE / sizeof(u64); n++) {
u64 *p = ((u64 *)pg) + n; u64 *p = ((u64 *)pg) + n;
*p ^= get_tod_clock_fast(); *p ^= get_tod_clock_fast();
} }
...@@ -134,8 +142,8 @@ static int generate_entropy(u8 *ebuf, size_t nbytes) ...@@ -134,8 +142,8 @@ static int generate_entropy(u8 *ebuf, size_t nbytes)
h = hash; h = hash;
else else
h = ebuf; h = ebuf;
/* generate sha256 from this page */ /* hash over the filled pages */
cpacf_kimd(CPACF_KIMD_SHA_256, h, pg, PAGE_SIZE); cpacf_kimd(CPACF_KIMD_SHA_512, h, pg, 2*PAGE_SIZE);
if (n < sizeof(hash)) if (n < sizeof(hash))
memcpy(ebuf, hash, n); memcpy(ebuf, hash, n);
ret += n; ret += n;
...@@ -143,7 +151,7 @@ static int generate_entropy(u8 *ebuf, size_t nbytes) ...@@ -143,7 +151,7 @@ static int generate_entropy(u8 *ebuf, size_t nbytes)
nbytes -= n; nbytes -= n;
} }
free_page((unsigned long)pg); free_pages((unsigned long)pg, 1);
return ret; return ret;
} }
...@@ -334,7 +342,7 @@ static int __init prng_sha512_selftest(void) ...@@ -334,7 +342,7 @@ static int __init prng_sha512_selftest(void)
static int __init prng_sha512_instantiate(void) static int __init prng_sha512_instantiate(void)
{ {
int ret, datalen; int ret, datalen;
u8 seed[64]; u8 seed[64 + 32 + 16];
pr_debug("prng runs in SHA-512 mode " pr_debug("prng runs in SHA-512 mode "
"with chunksize=%d and reseed_limit=%u\n", "with chunksize=%d and reseed_limit=%u\n",
...@@ -357,12 +365,12 @@ static int __init prng_sha512_instantiate(void) ...@@ -357,12 +365,12 @@ static int __init prng_sha512_instantiate(void)
if (ret) if (ret)
goto outfree; goto outfree;
/* generate initial seed bytestring, first 48 bytes of entropy */ /* generate initial seed bytestring, with 256 + 128 bits entropy */
ret = generate_entropy(seed, 48); ret = generate_entropy(seed, 64 + 32);
if (ret != 48) if (ret != 64 + 32)
goto outfree; goto outfree;
/* followed by 16 bytes of unique nonce */ /* followed by 16 bytes of unique nonce */
get_tod_clock_ext(seed + 48); get_tod_clock_ext(seed + 64 + 32);
/* initial seed of the ppno drng */ /* initial seed of the ppno drng */
cpacf_ppno(CPACF_PPNO_SHA512_DRNG_SEED, cpacf_ppno(CPACF_PPNO_SHA512_DRNG_SEED,
...@@ -395,9 +403,9 @@ static void prng_sha512_deinstantiate(void) ...@@ -395,9 +403,9 @@ static void prng_sha512_deinstantiate(void)
static int prng_sha512_reseed(void) static int prng_sha512_reseed(void)
{ {
int ret; int ret;
u8 seed[32]; u8 seed[64];
/* generate 32 bytes of fresh entropy */ /* fetch 256 bits of fresh entropy */
ret = generate_entropy(seed, sizeof(seed)); ret = generate_entropy(seed, sizeof(seed));
if (ret != sizeof(seed)) if (ret != sizeof(seed))
return ret; return ret;
......
...@@ -4,9 +4,31 @@ ...@@ -4,9 +4,31 @@
/* Caches aren't brain-dead on the s390. */ /* Caches aren't brain-dead on the s390. */
#include <asm-generic/cacheflush.h> #include <asm-generic/cacheflush.h>
int set_memory_ro(unsigned long addr, int numpages); #define SET_MEMORY_RO 1UL
int set_memory_rw(unsigned long addr, int numpages); #define SET_MEMORY_RW 2UL
int set_memory_nx(unsigned long addr, int numpages); #define SET_MEMORY_NX 4UL
int set_memory_x(unsigned long addr, int numpages); #define SET_MEMORY_X 8UL
int __set_memory(unsigned long addr, int numpages, unsigned long flags);
static inline int set_memory_ro(unsigned long addr, int numpages)
{
return __set_memory(addr, numpages, SET_MEMORY_RO);
}
static inline int set_memory_rw(unsigned long addr, int numpages)
{
return __set_memory(addr, numpages, SET_MEMORY_RW);
}
static inline int set_memory_nx(unsigned long addr, int numpages)
{
return __set_memory(addr, numpages, SET_MEMORY_NX);
}
static inline int set_memory_x(unsigned long addr, int numpages)
{
return __set_memory(addr, numpages, SET_MEMORY_X);
}
#endif /* _S390_CACHEFLUSH_H */ #endif /* _S390_CACHEFLUSH_H */
...@@ -199,14 +199,15 @@ static inline int ecctr(u64 ctr, u64 *val) ...@@ -199,14 +199,15 @@ static inline int ecctr(u64 ctr, u64 *val)
/* Store CPU counter multiple for the MT utilization counter set */ /* Store CPU counter multiple for the MT utilization counter set */
static inline int stcctm5(u64 num, u64 *val) static inline int stcctm5(u64 num, u64 *val)
{ {
typedef struct { u64 _[num]; } addrtype;
int cc; int cc;
asm volatile ( asm volatile (
" .insn rsy,0xeb0000000017,%2,5,%1\n" " .insn rsy,0xeb0000000017,%2,5,%1\n"
" ipm %0\n" " ipm %0\n"
" srl %0,28\n" " srl %0,28\n"
: "=d" (cc), "=Q" (*(addrtype *) val) : "d" (num) : "cc"); : "=d" (cc)
: "Q" (*val), "d" (num)
: "cc", "memory");
return cc; return cc;
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <linux/bug.h> #include <linux/bug.h>
#define __ctl_load(array, low, high) { \ #define __ctl_load(array, low, high) do { \
typedef struct { char _[sizeof(array)]; } addrtype; \ typedef struct { char _[sizeof(array)]; } addrtype; \
\ \
BUILD_BUG_ON(sizeof(addrtype) != (high - low + 1) * sizeof(long));\ BUILD_BUG_ON(sizeof(addrtype) != (high - low + 1) * sizeof(long));\
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
: \ : \
: "Q" (*(addrtype *)(&array)), "i" (low), "i" (high) \ : "Q" (*(addrtype *)(&array)), "i" (low), "i" (high) \
: "memory"); \ : "memory"); \
} } while (0)
#define __ctl_store(array, low, high) { \ #define __ctl_store(array, low, high) do { \
typedef struct { char _[sizeof(array)]; } addrtype; \ typedef struct { char _[sizeof(array)]; } addrtype; \
\ \
BUILD_BUG_ON(sizeof(addrtype) != (high - low + 1) * sizeof(long));\ BUILD_BUG_ON(sizeof(addrtype) != (high - low + 1) * sizeof(long));\
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
" stctg %1,%2,%0\n" \ " stctg %1,%2,%0\n" \
: "=Q" (*(addrtype *)(&array)) \ : "=Q" (*(addrtype *)(&array)) \
: "i" (low), "i" (high)); \ : "i" (low), "i" (high)); \
} } while (0)
static inline void __ctl_set_bit(unsigned int cr, unsigned int bit) static inline void __ctl_set_bit(unsigned int cr, unsigned int bit)
{ {
...@@ -62,7 +62,9 @@ union ctlreg0 { ...@@ -62,7 +62,9 @@ union ctlreg0 {
unsigned long : 4; unsigned long : 4;
unsigned long afp : 1; /* AFP-register control */ unsigned long afp : 1; /* AFP-register control */
unsigned long vx : 1; /* Vector enablement control */ unsigned long vx : 1; /* Vector enablement control */
unsigned long : 17; unsigned long : 7;
unsigned long sssm : 1; /* Service signal subclass mask */
unsigned long : 9;
}; };
}; };
......
...@@ -103,6 +103,8 @@ ...@@ -103,6 +103,8 @@
#define HWCAP_S390_HIGH_GPRS 512 #define HWCAP_S390_HIGH_GPRS 512
#define HWCAP_S390_TE 1024 #define HWCAP_S390_TE 1024
#define HWCAP_S390_VXRS 2048 #define HWCAP_S390_VXRS 2048
#define HWCAP_S390_VXRS_BCD 4096
#define HWCAP_S390_VXRS_EXT 8192
/* Internal bits, not exposed via elf */ /* Internal bits, not exposed via elf */
#define HWCAP_INT_SIE 1UL #define HWCAP_INT_SIE 1UL
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#define is_hugepage_only_range(mm, addr, len) 0 #define is_hugepage_only_range(mm, addr, len) 0
#define hugetlb_free_pgd_range free_pgd_range #define hugetlb_free_pgd_range free_pgd_range
#define hugepages_supported() (MACHINE_HAS_HPAGE) #define hugepages_supported() (MACHINE_HAS_EDAT1)
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte); pte_t *ptep, pte_t pte);
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#ifndef ASM_LIVEPATCH_H #ifndef ASM_LIVEPATCH_H
#define ASM_LIVEPATCH_H #define ASM_LIVEPATCH_H
#include <linux/module.h> #include <asm/ptrace.h>
static inline int klp_check_compiler_support(void) static inline int klp_check_compiler_support(void)
{ {
......
...@@ -85,7 +85,7 @@ struct clp_rsp_query_pci { ...@@ -85,7 +85,7 @@ struct clp_rsp_query_pci {
u32 fid; /* pci function id */ u32 fid; /* pci function id */
u8 bar_size[PCI_BAR_COUNT]; u8 bar_size[PCI_BAR_COUNT];
u16 pchid; u16 pchid;
u32 bar[PCI_BAR_COUNT]; __le32 bar[PCI_BAR_COUNT];
u8 pfip[CLP_PFIP_NR_SEGMENTS]; /* pci function internal path */ u8 pfip[CLP_PFIP_NR_SEGMENTS]; /* pci function internal path */
u32 : 16; u32 : 16;
u8 fmb_len; u8 fmb_len;
......
...@@ -200,6 +200,7 @@ static inline int is_module_addr(void *addr) ...@@ -200,6 +200,7 @@ static inline int is_module_addr(void *addr)
*/ */
/* Hardware bits in the page table entry */ /* Hardware bits in the page table entry */
#define _PAGE_NOEXEC 0x100 /* HW no-execute bit */
#define _PAGE_PROTECT 0x200 /* HW read-only bit */ #define _PAGE_PROTECT 0x200 /* HW read-only bit */
#define _PAGE_INVALID 0x400 /* HW invalid bit */ #define _PAGE_INVALID 0x400 /* HW invalid bit */
#define _PAGE_LARGE 0x800 /* Bit to mark a large pte */ #define _PAGE_LARGE 0x800 /* Bit to mark a large pte */
...@@ -277,6 +278,7 @@ static inline int is_module_addr(void *addr) ...@@ -277,6 +278,7 @@ static inline int is_module_addr(void *addr)
/* Bits in the region table entry */ /* Bits in the region table entry */
#define _REGION_ENTRY_ORIGIN ~0xfffUL/* region/segment table origin */ #define _REGION_ENTRY_ORIGIN ~0xfffUL/* region/segment table origin */
#define _REGION_ENTRY_PROTECT 0x200 /* region protection bit */ #define _REGION_ENTRY_PROTECT 0x200 /* region protection bit */
#define _REGION_ENTRY_NOEXEC 0x100 /* region no-execute bit */
#define _REGION_ENTRY_OFFSET 0xc0 /* region table offset */ #define _REGION_ENTRY_OFFSET 0xc0 /* region table offset */
#define _REGION_ENTRY_INVALID 0x20 /* invalid region table entry */ #define _REGION_ENTRY_INVALID 0x20 /* invalid region table entry */
#define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */ #define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */
...@@ -316,6 +318,7 @@ static inline int is_module_addr(void *addr) ...@@ -316,6 +318,7 @@ static inline int is_module_addr(void *addr)
#define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address */ #define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address */
#define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */ #define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */
#define _SEGMENT_ENTRY_PROTECT 0x200 /* page protection bit */ #define _SEGMENT_ENTRY_PROTECT 0x200 /* page protection bit */
#define _SEGMENT_ENTRY_NOEXEC 0x100 /* region no-execute bit */
#define _SEGMENT_ENTRY_INVALID 0x20 /* invalid segment table entry */ #define _SEGMENT_ENTRY_INVALID 0x20 /* invalid segment table entry */
#define _SEGMENT_ENTRY (0) #define _SEGMENT_ENTRY (0)
...@@ -385,17 +388,23 @@ static inline int is_module_addr(void *addr) ...@@ -385,17 +388,23 @@ static inline int is_module_addr(void *addr)
* Page protection definitions. * Page protection definitions.
*/ */
#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_INVALID | _PAGE_PROTECT) #define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_INVALID | _PAGE_PROTECT)
#define PAGE_READ __pgprot(_PAGE_PRESENT | _PAGE_READ | \ #define PAGE_RO __pgprot(_PAGE_PRESENT | _PAGE_READ | \
_PAGE_NOEXEC | _PAGE_INVALID | _PAGE_PROTECT)
#define PAGE_RX __pgprot(_PAGE_PRESENT | _PAGE_READ | \
_PAGE_INVALID | _PAGE_PROTECT) _PAGE_INVALID | _PAGE_PROTECT)
#define PAGE_WRITE __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ #define PAGE_RW __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
_PAGE_NOEXEC | _PAGE_INVALID | _PAGE_PROTECT)
#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
_PAGE_INVALID | _PAGE_PROTECT) _PAGE_INVALID | _PAGE_PROTECT)
#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
_PAGE_YOUNG | _PAGE_DIRTY) _PAGE_YOUNG | _PAGE_DIRTY | _PAGE_NOEXEC)
#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
_PAGE_YOUNG | _PAGE_DIRTY) _PAGE_YOUNG | _PAGE_DIRTY | _PAGE_NOEXEC)
#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_YOUNG | \ #define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_YOUNG | \
_PAGE_PROTECT) _PAGE_PROTECT | _PAGE_NOEXEC)
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
_PAGE_YOUNG | _PAGE_DIRTY)
/* /*
* On s390 the page table entry has an invalid bit and a read-only bit. * On s390 the page table entry has an invalid bit and a read-only bit.
...@@ -404,43 +413,51 @@ static inline int is_module_addr(void *addr) ...@@ -404,43 +413,51 @@ static inline int is_module_addr(void *addr)
*/ */
/*xwr*/ /*xwr*/
#define __P000 PAGE_NONE #define __P000 PAGE_NONE
#define __P001 PAGE_READ #define __P001 PAGE_RO
#define __P010 PAGE_READ #define __P010 PAGE_RO
#define __P011 PAGE_READ #define __P011 PAGE_RO
#define __P100 PAGE_READ #define __P100 PAGE_RX
#define __P101 PAGE_READ #define __P101 PAGE_RX
#define __P110 PAGE_READ #define __P110 PAGE_RX
#define __P111 PAGE_READ #define __P111 PAGE_RX
#define __S000 PAGE_NONE #define __S000 PAGE_NONE
#define __S001 PAGE_READ #define __S001 PAGE_RO
#define __S010 PAGE_WRITE #define __S010 PAGE_RW
#define __S011 PAGE_WRITE #define __S011 PAGE_RW
#define __S100 PAGE_READ #define __S100 PAGE_RX
#define __S101 PAGE_READ #define __S101 PAGE_RX
#define __S110 PAGE_WRITE #define __S110 PAGE_RWX
#define __S111 PAGE_WRITE #define __S111 PAGE_RWX
/* /*
* Segment entry (large page) protection definitions. * Segment entry (large page) protection definitions.
*/ */
#define SEGMENT_NONE __pgprot(_SEGMENT_ENTRY_INVALID | \ #define SEGMENT_NONE __pgprot(_SEGMENT_ENTRY_INVALID | \
_SEGMENT_ENTRY_PROTECT) _SEGMENT_ENTRY_PROTECT)
#define SEGMENT_READ __pgprot(_SEGMENT_ENTRY_PROTECT | \ #define SEGMENT_RO __pgprot(_SEGMENT_ENTRY_PROTECT | \
_SEGMENT_ENTRY_READ | \
_SEGMENT_ENTRY_NOEXEC)
#define SEGMENT_RX __pgprot(_SEGMENT_ENTRY_PROTECT | \
_SEGMENT_ENTRY_READ) _SEGMENT_ENTRY_READ)
#define SEGMENT_WRITE __pgprot(_SEGMENT_ENTRY_READ | \ #define SEGMENT_RW __pgprot(_SEGMENT_ENTRY_READ | \
_SEGMENT_ENTRY_WRITE | \
_SEGMENT_ENTRY_NOEXEC)
#define SEGMENT_RWX __pgprot(_SEGMENT_ENTRY_READ | \
_SEGMENT_ENTRY_WRITE) _SEGMENT_ENTRY_WRITE)
#define SEGMENT_KERNEL __pgprot(_SEGMENT_ENTRY | \ #define SEGMENT_KERNEL __pgprot(_SEGMENT_ENTRY | \
_SEGMENT_ENTRY_LARGE | \ _SEGMENT_ENTRY_LARGE | \
_SEGMENT_ENTRY_READ | \ _SEGMENT_ENTRY_READ | \
_SEGMENT_ENTRY_WRITE | \ _SEGMENT_ENTRY_WRITE | \
_SEGMENT_ENTRY_YOUNG | \ _SEGMENT_ENTRY_YOUNG | \
_SEGMENT_ENTRY_DIRTY) _SEGMENT_ENTRY_DIRTY | \
_SEGMENT_ENTRY_NOEXEC)
#define SEGMENT_KERNEL_RO __pgprot(_SEGMENT_ENTRY | \ #define SEGMENT_KERNEL_RO __pgprot(_SEGMENT_ENTRY | \
_SEGMENT_ENTRY_LARGE | \ _SEGMENT_ENTRY_LARGE | \
_SEGMENT_ENTRY_READ | \ _SEGMENT_ENTRY_READ | \
_SEGMENT_ENTRY_YOUNG | \ _SEGMENT_ENTRY_YOUNG | \
_SEGMENT_ENTRY_PROTECT) _SEGMENT_ENTRY_PROTECT | \
_SEGMENT_ENTRY_NOEXEC)
/* /*
* Region3 entry (large page) protection definitions. * Region3 entry (large page) protection definitions.
...@@ -451,12 +468,14 @@ static inline int is_module_addr(void *addr) ...@@ -451,12 +468,14 @@ static inline int is_module_addr(void *addr)
_REGION3_ENTRY_READ | \ _REGION3_ENTRY_READ | \
_REGION3_ENTRY_WRITE | \ _REGION3_ENTRY_WRITE | \
_REGION3_ENTRY_YOUNG | \ _REGION3_ENTRY_YOUNG | \
_REGION3_ENTRY_DIRTY) _REGION3_ENTRY_DIRTY | \
_REGION_ENTRY_NOEXEC)
#define REGION3_KERNEL_RO __pgprot(_REGION_ENTRY_TYPE_R3 | \ #define REGION3_KERNEL_RO __pgprot(_REGION_ENTRY_TYPE_R3 | \
_REGION3_ENTRY_LARGE | \ _REGION3_ENTRY_LARGE | \
_REGION3_ENTRY_READ | \ _REGION3_ENTRY_READ | \
_REGION3_ENTRY_YOUNG | \ _REGION3_ENTRY_YOUNG | \
_REGION_ENTRY_PROTECT) _REGION_ENTRY_PROTECT | \
_REGION_ENTRY_NOEXEC)
static inline int mm_has_pgste(struct mm_struct *mm) static inline int mm_has_pgste(struct mm_struct *mm)
{ {
...@@ -801,14 +820,14 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) ...@@ -801,14 +820,14 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
pte_val(pte) &= _PAGE_CHG_MASK; pte_val(pte) &= _PAGE_CHG_MASK;
pte_val(pte) |= pgprot_val(newprot); pte_val(pte) |= pgprot_val(newprot);
/* /*
* newprot for PAGE_NONE, PAGE_READ and PAGE_WRITE has the * newprot for PAGE_NONE, PAGE_RO, PAGE_RX, PAGE_RW and PAGE_RWX
* invalid bit set, clear it again for readable, young pages * has the invalid bit set, clear it again for readable, young pages
*/ */
if ((pte_val(pte) & _PAGE_YOUNG) && (pte_val(pte) & _PAGE_READ)) if ((pte_val(pte) & _PAGE_YOUNG) && (pte_val(pte) & _PAGE_READ))
pte_val(pte) &= ~_PAGE_INVALID; pte_val(pte) &= ~_PAGE_INVALID;
/* /*
* newprot for PAGE_READ and PAGE_WRITE has the page protection * newprot for PAGE_RO, PAGE_RX, PAGE_RW and PAGE_RWX has the page
* bit set, clear it again for writable, dirty pages * protection bit set, clear it again for writable, dirty pages
*/ */
if ((pte_val(pte) & _PAGE_DIRTY) && (pte_val(pte) & _PAGE_WRITE)) if ((pte_val(pte) & _PAGE_DIRTY) && (pte_val(pte) & _PAGE_WRITE))
pte_val(pte) &= ~_PAGE_PROTECT; pte_val(pte) &= ~_PAGE_PROTECT;
...@@ -1029,6 +1048,8 @@ int get_guest_storage_key(struct mm_struct *mm, unsigned long addr, ...@@ -1029,6 +1048,8 @@ int get_guest_storage_key(struct mm_struct *mm, unsigned long addr,
static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t entry) pte_t *ptep, pte_t entry)
{ {
if (!MACHINE_HAS_NX)
pte_val(entry) &= ~_PAGE_NOEXEC;
if (mm_has_pgste(mm)) if (mm_has_pgste(mm))
ptep_set_pte_at(mm, addr, ptep, entry); ptep_set_pte_at(mm, addr, ptep, entry);
else else
...@@ -1173,14 +1194,18 @@ static inline pud_t pud_mkdirty(pud_t pud) ...@@ -1173,14 +1194,18 @@ static inline pud_t pud_mkdirty(pud_t pud)
static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot) static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot)
{ {
/* /*
* pgprot is PAGE_NONE, PAGE_READ, or PAGE_WRITE (see __Pxxx / __Sxxx) * pgprot is PAGE_NONE, PAGE_RO, PAGE_RX, PAGE_RW or PAGE_RWX
* Convert to segment table entry format. * (see __Pxxx / __Sxxx). Convert to segment table entry format.
*/ */
if (pgprot_val(pgprot) == pgprot_val(PAGE_NONE)) if (pgprot_val(pgprot) == pgprot_val(PAGE_NONE))
return pgprot_val(SEGMENT_NONE); return pgprot_val(SEGMENT_NONE);
if (pgprot_val(pgprot) == pgprot_val(PAGE_READ)) if (pgprot_val(pgprot) == pgprot_val(PAGE_RO))
return pgprot_val(SEGMENT_READ); return pgprot_val(SEGMENT_RO);
return pgprot_val(SEGMENT_WRITE); if (pgprot_val(pgprot) == pgprot_val(PAGE_RX))
return pgprot_val(SEGMENT_RX);
if (pgprot_val(pgprot) == pgprot_val(PAGE_RW))
return pgprot_val(SEGMENT_RW);
return pgprot_val(SEGMENT_RWX);
} }
static inline pmd_t pmd_mkyoung(pmd_t pmd) static inline pmd_t pmd_mkyoung(pmd_t pmd)
...@@ -1315,6 +1340,8 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma, ...@@ -1315,6 +1340,8 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma,
static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, pmd_t entry) pmd_t *pmdp, pmd_t entry)
{ {
if (!MACHINE_HAS_NX)
pmd_val(entry) &= ~_SEGMENT_ENTRY_NOEXEC;
*pmdp = entry; *pmdp = entry;
} }
...@@ -1389,7 +1416,7 @@ static inline int pmd_trans_huge(pmd_t pmd) ...@@ -1389,7 +1416,7 @@ static inline int pmd_trans_huge(pmd_t pmd)
#define has_transparent_hugepage has_transparent_hugepage #define has_transparent_hugepage has_transparent_hugepage
static inline int has_transparent_hugepage(void) static inline int has_transparent_hugepage(void)
{ {
return MACHINE_HAS_HPAGE ? 1 : 0; return MACHINE_HAS_EDAT1 ? 1 : 0;
} }
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
......
...@@ -361,12 +361,12 @@ extern void (*s390_base_ext_handler_fn)(void); ...@@ -361,12 +361,12 @@ extern void (*s390_base_ext_handler_fn)(void);
extern int memcpy_real(void *, void *, size_t); extern int memcpy_real(void *, void *, size_t);
extern void memcpy_absolute(void *, void *, size_t); extern void memcpy_absolute(void *, void *, size_t);
#define mem_assign_absolute(dest, val) { \ #define mem_assign_absolute(dest, val) do { \
__typeof__(dest) __tmp = (val); \ __typeof__(dest) __tmp = (val); \
\ \
BUILD_BUG_ON(sizeof(__tmp) != sizeof(val)); \ BUILD_BUG_ON(sizeof(__tmp) != sizeof(val)); \
memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \ memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \
} } while (0)
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
......
...@@ -101,7 +101,12 @@ struct zpci_report_error_header { ...@@ -101,7 +101,12 @@ struct zpci_report_error_header {
u8 data[0]; /* Subsequent Data passed verbatim to SCLP ET 24 */ u8 data[0]; /* Subsequent Data passed verbatim to SCLP ET 24 */
} __packed; } __packed;
int _sclp_get_core_info_early(struct sclp_core_info *info); int sclp_early_get_core_info(struct sclp_core_info *info);
void sclp_early_get_ipl_info(struct sclp_ipl_info *info);
void sclp_early_detect(void);
void sclp_early_printk(const char *s);
void __sclp_early_printk(const char *s, unsigned int len);
int _sclp_get_core_info(struct sclp_core_info *info); int _sclp_get_core_info(struct sclp_core_info *info);
int sclp_core_configure(u8 core); int sclp_core_configure(u8 core);
int sclp_core_deconfigure(u8 core); int sclp_core_deconfigure(u8 core);
...@@ -110,20 +115,17 @@ int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); ...@@ -110,20 +115,17 @@ int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
int sclp_chp_configure(struct chp_id chpid); int sclp_chp_configure(struct chp_id chpid);
int sclp_chp_deconfigure(struct chp_id chpid); int sclp_chp_deconfigure(struct chp_id chpid);
int sclp_chp_read_info(struct sclp_chp_info *info); int sclp_chp_read_info(struct sclp_chp_info *info);
void sclp_get_ipl_info(struct sclp_ipl_info *info);
int sclp_pci_configure(u32 fid); int sclp_pci_configure(u32 fid);
int sclp_pci_deconfigure(u32 fid); int sclp_pci_deconfigure(u32 fid);
int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid); int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid);
int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count); int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count);
int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count); int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count);
void sclp_early_detect(void);
void _sclp_print_early(const char *);
void sclp_ocf_cpc_name_copy(char *dst); void sclp_ocf_cpc_name_copy(char *dst);
static inline int sclp_get_core_info(struct sclp_core_info *info, int early) static inline int sclp_get_core_info(struct sclp_core_info *info, int early)
{ {
if (early) if (early)
return _sclp_get_core_info_early(info); return sclp_early_get_core_info(info);
return _sclp_get_core_info(info); return _sclp_get_core_info(info);
} }
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#define MACHINE_FLAG_TLB_LC _BITUL(12) #define MACHINE_FLAG_TLB_LC _BITUL(12)
#define MACHINE_FLAG_VX _BITUL(13) #define MACHINE_FLAG_VX _BITUL(13)
#define MACHINE_FLAG_CAD _BITUL(14) #define MACHINE_FLAG_CAD _BITUL(14)
#define MACHINE_FLAG_NX _BITUL(15)
#define LPP_MAGIC _BITUL(31) #define LPP_MAGIC _BITUL(31)
#define LPP_PFAULT_PID_MASK _AC(0xffffffff, UL) #define LPP_PFAULT_PID_MASK _AC(0xffffffff, UL)
...@@ -58,9 +59,6 @@ extern void detect_memory_memblock(void); ...@@ -58,9 +59,6 @@ extern void detect_memory_memblock(void);
#define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C) #define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C)
#define MACHINE_HAS_ESOP (S390_lowcore.machine_flags & MACHINE_FLAG_ESOP) #define MACHINE_HAS_ESOP (S390_lowcore.machine_flags & MACHINE_FLAG_ESOP)
#define MACHINE_HAS_PFMF MACHINE_HAS_EDAT1
#define MACHINE_HAS_HPAGE MACHINE_HAS_EDAT1
#define MACHINE_HAS_IDTE (S390_lowcore.machine_flags & MACHINE_FLAG_IDTE) #define MACHINE_HAS_IDTE (S390_lowcore.machine_flags & MACHINE_FLAG_IDTE)
#define MACHINE_HAS_DIAG44 (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44) #define MACHINE_HAS_DIAG44 (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44)
#define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1) #define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1)
...@@ -71,6 +69,7 @@ extern void detect_memory_memblock(void); ...@@ -71,6 +69,7 @@ extern void detect_memory_memblock(void);
#define MACHINE_HAS_TLB_LC (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC) #define MACHINE_HAS_TLB_LC (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC)
#define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX) #define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX)
#define MACHINE_HAS_CAD (S390_lowcore.machine_flags & MACHINE_FLAG_CAD) #define MACHINE_HAS_CAD (S390_lowcore.machine_flags & MACHINE_FLAG_CAD)
#define MACHINE_HAS_NX (S390_lowcore.machine_flags & MACHINE_FLAG_NX)
/* /*
* Console mode. Override with conmode= * Console mode. Override with conmode=
......
...@@ -63,7 +63,7 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock) ...@@ -63,7 +63,7 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
static inline int arch_spin_is_locked(arch_spinlock_t *lp) static inline int arch_spin_is_locked(arch_spinlock_t *lp)
{ {
return ACCESS_ONCE(lp->lock) != 0; return READ_ONCE(lp->lock) != 0;
} }
static inline int arch_spin_trylock_once(arch_spinlock_t *lp) static inline int arch_spin_trylock_once(arch_spinlock_t *lp)
......
...@@ -178,14 +178,6 @@ int get_phys_clock(unsigned long long *clock); ...@@ -178,14 +178,6 @@ int get_phys_clock(unsigned long long *clock);
void init_cpu_timer(void); void init_cpu_timer(void);
unsigned long long monotonic_clock(void); unsigned long long monotonic_clock(void);
void tod_to_timeval(__u64 todval, struct timespec64 *xt);
static inline
void stck_to_timespec64(unsigned long long stck, struct timespec64 *ts)
{
tod_to_timeval(stck - TOD_UNIX_EPOCH, ts);
}
extern u64 sched_clock_base_cc; extern u64 sched_clock_base_cc;
/** /**
......
...@@ -38,13 +38,13 @@ ...@@ -38,13 +38,13 @@
#define get_fs() (current->thread.mm_segment) #define get_fs() (current->thread.mm_segment)
#define set_fs(x) \ #define set_fs(x) \
{ \ do { \
unsigned long __pto; \ unsigned long __pto; \
current->thread.mm_segment = (x); \ current->thread.mm_segment = (x); \
__pto = current->thread.mm_segment.ar4 ? \ __pto = current->thread.mm_segment.ar4 ? \
S390_lowcore.user_asce : S390_lowcore.kernel_asce; \ S390_lowcore.user_asce : S390_lowcore.kernel_asce; \
__ctl_load(__pto, 7, 7); \ __ctl_load(__pto, 7, 7); \
} } while (0)
#define segment_eq(a,b) ((a).ar4 == (b).ar4) #define segment_eq(a,b) ((a).ar4 == (b).ar4)
...@@ -177,7 +177,7 @@ static inline int __put_user_fn(void *x, void __user *ptr, unsigned long size) ...@@ -177,7 +177,7 @@ static inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
(unsigned long *)x, (unsigned long *)x,
size, spec); size, spec);
break; break;
}; }
return rc; return rc;
} }
...@@ -207,7 +207,7 @@ static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long s ...@@ -207,7 +207,7 @@ static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long s
(unsigned long __user *)ptr, (unsigned long __user *)ptr,
size, spec); size, spec);
break; break;
}; }
return rc; return rc;
} }
......
...@@ -10,31 +10,25 @@ CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) ...@@ -10,31 +10,25 @@ CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
# Do not trace early setup code # Do not trace early setup code
CFLAGS_REMOVE_als.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_als.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_sclp.o = $(CC_FLAGS_FTRACE)
endif endif
GCOV_PROFILE_als.o := n GCOV_PROFILE_als.o := n
GCOV_PROFILE_early.o := n GCOV_PROFILE_early.o := n
GCOV_PROFILE_sclp.o := n
KCOV_INSTRUMENT_als.o := n KCOV_INSTRUMENT_als.o := n
KCOV_INSTRUMENT_early.o := n KCOV_INSTRUMENT_early.o := n
KCOV_INSTRUMENT_sclp.o := n
UBSAN_SANITIZE_als.o := n UBSAN_SANITIZE_als.o := n
UBSAN_SANITIZE_early.o := n UBSAN_SANITIZE_early.o := n
UBSAN_SANITIZE_sclp.o := n
# #
# Use -march=z900 for sclp.c and als.c to be able to print an error # Use -march=z900 for als.c to be able to print an error
# message if the kernel is started on a machine which is too old # message if the kernel is started on a machine which is too old
# #
ifneq ($(CC_FLAGS_MARCH),-march=z900) ifneq ($(CC_FLAGS_MARCH),-march=z900)
CFLAGS_REMOVE_als.o += $(CC_FLAGS_MARCH) CFLAGS_REMOVE_als.o += $(CC_FLAGS_MARCH)
CFLAGS_als.o += -march=z900 CFLAGS_als.o += -march=z900
CFLAGS_REMOVE_sclp.o += $(CC_FLAGS_MARCH)
CFLAGS_sclp.o += -march=z900
AFLAGS_REMOVE_head.o += $(CC_FLAGS_MARCH) AFLAGS_REMOVE_head.o += $(CC_FLAGS_MARCH)
AFLAGS_head.o += -march=z900 AFLAGS_head.o += -march=z900
endif endif
...@@ -61,7 +55,7 @@ CFLAGS_sysinfo.o += -w ...@@ -61,7 +55,7 @@ CFLAGS_sysinfo.o += -w
obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o
obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
obj-y += debug.o irq.o ipl.o dis.o diag.o sclp.o vdso.o als.o obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o
obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
obj-y += runtime_instr.o cache.o fpu.o dumpstack.o obj-y += runtime_instr.o cache.o fpu.o dumpstack.o
obj-y += entry.o reipl.o relocate_kernel.o obj-y += entry.o reipl.o relocate_kernel.o
...@@ -76,7 +70,7 @@ obj-$(CONFIG_AUDIT) += audit.o ...@@ -76,7 +70,7 @@ obj-$(CONFIG_AUDIT) += audit.o
compat-obj-$(CONFIG_AUDIT) += compat_audit.o compat-obj-$(CONFIG_AUDIT) += compat_audit.o
obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o
obj-$(CONFIG_COMPAT) += compat_wrapper.o $(compat-obj-y) obj-$(CONFIG_COMPAT) += compat_wrapper.o $(compat-obj-y)
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
......
...@@ -41,7 +41,8 @@ static void __init print_machine_type(void) ...@@ -41,7 +41,8 @@ static void __init print_machine_type(void)
get_cpu_id(&id); get_cpu_id(&id);
u16_to_hex(type_str, id.machine); u16_to_hex(type_str, id.machine);
strcat(mach_str, type_str); strcat(mach_str, type_str);
_sclp_print_early(mach_str); strcat(mach_str, "\n");
sclp_early_printk(mach_str);
} }
static void __init u16_to_decimal(char *str, u16 val) static void __init u16_to_decimal(char *str, u16 val)
...@@ -79,7 +80,8 @@ static void __init print_missing_facilities(void) ...@@ -79,7 +80,8 @@ static void __init print_missing_facilities(void)
* z/VM adds a four character prefix. * z/VM adds a four character prefix.
*/ */
if (strlen(als_str) > 70) { if (strlen(als_str) > 70) {
_sclp_print_early(als_str); strcat(als_str, "\n");
sclp_early_printk(als_str);
*als_str = '\0'; *als_str = '\0';
} }
u16_to_decimal(val_str, i * BITS_PER_LONG + j); u16_to_decimal(val_str, i * BITS_PER_LONG + j);
...@@ -87,13 +89,14 @@ static void __init print_missing_facilities(void) ...@@ -87,13 +89,14 @@ static void __init print_missing_facilities(void)
first = 0; first = 0;
} }
} }
_sclp_print_early(als_str); strcat(als_str, "\n");
_sclp_print_early("See Principles of Operations for facility bits"); sclp_early_printk(als_str);
sclp_early_printk("See Principles of Operations for facility bits\n");
} }
static void __init facility_mismatch(void) static void __init facility_mismatch(void)
{ {
_sclp_print_early("The Linux kernel requires more recent processor hardware"); sclp_early_printk("The Linux kernel requires more recent processor hardware\n");
print_machine_type(); print_machine_type();
print_missing_facilities(); print_missing_facilities();
disabled_wait(0x8badcccc); disabled_wait(0x8badcccc);
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <linux/shm.h> #include <linux/shm.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/quota.h> #include <linux/quota.h>
#include <linux/module.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/personality.h> #include <linux/personality.h>
#include <linux/stat.h> #include <linux/stat.h>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/stddef.h> #include <linux/stddef.h>
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
#include <linux/crash_dump.h> #include <linux/crash_dump.h>
#include <asm/lowcore.h> #include <asm/lowcore.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/init.h>
#include <linux/mm.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
...@@ -329,7 +330,11 @@ static void *nt_init_name(void *buf, Elf64_Word type, void *desc, int d_len, ...@@ -329,7 +330,11 @@ static void *nt_init_name(void *buf, Elf64_Word type, void *desc, int d_len,
static inline void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len) static inline void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len)
{ {
return nt_init_name(buf, type, desc, d_len, KEXEC_CORE_NOTE_NAME); const char *note_name = "LINUX";
if (type == NT_PRPSINFO || type == NT_PRSTATUS || type == NT_PRFPREG)
note_name = KEXEC_CORE_NOTE_NAME;
return nt_init_name(buf, type, desc, d_len, note_name);
} }
/* /*
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
...@@ -866,7 +866,7 @@ static inline void ...@@ -866,7 +866,7 @@ static inline void
debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level, debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
int exception) int exception)
{ {
active->id.stck = get_tod_clock_fast(); active->id.stck = get_tod_clock_fast() - sched_clock_base_cc;
active->id.fields.cpuid = smp_processor_id(); active->id.fields.cpuid = smp_processor_id();
active->caller = __builtin_return_address(0); active->caller = __builtin_return_address(0);
active->id.fields.exception = exception; active->id.fields.exception = exception;
...@@ -1455,23 +1455,24 @@ int ...@@ -1455,23 +1455,24 @@ int
debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
int area, debug_entry_t * entry, char *out_buf) int area, debug_entry_t * entry, char *out_buf)
{ {
struct timespec64 time_spec; unsigned long sec, usec;
char *except_str; char *except_str;
unsigned long caller; unsigned long caller;
int rc = 0; int rc = 0;
unsigned int level; unsigned int level;
level = entry->id.fields.level; level = entry->id.fields.level;
stck_to_timespec64(entry->id.stck, &time_spec); sec = (entry->id.stck >> 12) + (sched_clock_base_cc >> 12);
sec = sec - (TOD_UNIX_EPOCH >> 12);
usec = do_div(sec, USEC_PER_SEC);
if (entry->id.fields.exception) if (entry->id.fields.exception)
except_str = "*"; except_str = "*";
else else
except_str = "-"; except_str = "-";
caller = (unsigned long) entry->caller; caller = (unsigned long) entry->caller;
rc += sprintf(out_buf, "%02i %011lld:%06lu %1u %1s %02i %p ", rc += sprintf(out_buf, "%02i %011ld:%06lu %1u %1s %02i %p ",
area, (long long)time_spec.tv_sec, area, sec, usec, level, except_str,
time_spec.tv_nsec / 1000, level, except_str,
entry->id.fields.cpuid, (void *)caller); entry->id.fields.cpuid, (void *)caller);
return rc; return rc;
} }
......
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
* Author(s): Michael Holzheu <holzheu@de.ibm.com> * Author(s): Michael Holzheu <holzheu@de.ibm.com>
*/ */
#include <linux/module.h> #include <linux/export.h>
#include <linux/init.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
......
...@@ -354,6 +354,10 @@ static __init void detect_machine_facilities(void) ...@@ -354,6 +354,10 @@ static __init void detect_machine_facilities(void)
S390_lowcore.machine_flags |= MACHINE_FLAG_VX; S390_lowcore.machine_flags |= MACHINE_FLAG_VX;
__ctl_set_bit(0, 17); __ctl_set_bit(0, 17);
} }
if (test_facility(130)) {
S390_lowcore.machine_flags |= MACHINE_FLAG_NX;
__ctl_set_bit(0, 20);
}
} }
static inline void save_vector_registers(void) static inline void save_vector_registers(void)
...@@ -364,6 +368,18 @@ static inline void save_vector_registers(void) ...@@ -364,6 +368,18 @@ static inline void save_vector_registers(void)
#endif #endif
} }
static int __init topology_setup(char *str)
{
bool enabled;
int rc;
rc = kstrtobool(str, &enabled);
if (!rc && !enabled)
S390_lowcore.machine_flags &= ~MACHINE_HAS_TOPOLOGY;
return rc;
}
early_param("topology", topology_setup);
static int __init disable_vector_extension(char *str) static int __init disable_vector_extension(char *str)
{ {
S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX;
...@@ -372,6 +388,21 @@ static int __init disable_vector_extension(char *str) ...@@ -372,6 +388,21 @@ static int __init disable_vector_extension(char *str)
} }
early_param("novx", disable_vector_extension); early_param("novx", disable_vector_extension);
static int __init noexec_setup(char *str)
{
bool enabled;
int rc;
rc = kstrtobool(str, &enabled);
if (!rc && !enabled) {
/* Disable no-execute support */
S390_lowcore.machine_flags &= ~MACHINE_FLAG_NX;
__ctl_clear_bit(0, 20);
}
return rc;
}
early_param("noexec", noexec_setup);
static int __init cad_setup(char *str) static int __init cad_setup(char *str)
{ {
int val; int val;
......
/*
* Copyright IBM Corp. 2017
*/
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/sclp.h>
static void sclp_early_write(struct console *con, const char *s, unsigned int len)
{
__sclp_early_printk(s, len);
}
static struct console sclp_early_console = {
.name = "earlysclp",
.write = sclp_early_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
static int __init setup_early_printk(char *buf)
{
if (early_console)
return 0;
/* Accept only "earlyprintk" and "earlyprintk=sclp" */
if (buf && strncmp(buf, "sclp", 4))
return 0;
if (!sclp.has_linemode && !sclp.has_vt220)
return 0;
early_console = &sclp_early_console;
register_console(early_console);
return 0;
}
early_param("earlyprintk", setup_early_printk);
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
* Martin Peschke <peschke@fh-brandenburg.de> * Martin Peschke <peschke@fh-brandenburg.de>
*/ */
#include <linux/module.h> #include <linux/types.h>
#include <asm/types.h> #include <linux/export.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
/* /*
......
...@@ -103,8 +103,7 @@ _PIF_WORK = (_PIF_PER_TRAP) ...@@ -103,8 +103,7 @@ _PIF_WORK = (_PIF_PER_TRAP)
CHECK_STACK 1<<STACK_SHIFT,\savearea CHECK_STACK 1<<STACK_SHIFT,\savearea
aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
j 3f j 3f
1: LAST_BREAK %r14 1: UPDATE_VTIME %r14,%r15,\timer
UPDATE_VTIME %r14,%r15,\timer
2: lg %r15,__LC_ASYNC_STACK # load async stack 2: lg %r15,__LC_ASYNC_STACK # load async stack
3: la %r11,STACK_FRAME_OVERHEAD(%r15) 3: la %r11,STACK_FRAME_OVERHEAD(%r15)
.endm .endm
...@@ -121,18 +120,6 @@ _PIF_WORK = (_PIF_PER_TRAP) ...@@ -121,18 +120,6 @@ _PIF_WORK = (_PIF_PER_TRAP)
mvc __LC_LAST_UPDATE_TIMER(8),\enter_timer mvc __LC_LAST_UPDATE_TIMER(8),\enter_timer
.endm .endm
.macro LAST_BREAK scratch
srag \scratch,%r10,23
#ifdef CONFIG_HAVE_MARCH_Z990_FEATURES
jz .+10
stg %r10,__TASK_thread+__THREAD_last_break(%r12)
#else
jz .+14
lghi \scratch,__TASK_thread
stg %r10,__THREAD_last_break(\scratch,%r12)
#endif
.endm
.macro REENABLE_IRQS .macro REENABLE_IRQS
stg %r8,__LC_RETURN_PSW stg %r8,__LC_RETURN_PSW
ni __LC_RETURN_PSW,0xbf ni __LC_RETURN_PSW,0xbf
...@@ -278,15 +265,14 @@ ENTRY(system_call) ...@@ -278,15 +265,14 @@ ENTRY(system_call)
stpt __LC_SYNC_ENTER_TIMER stpt __LC_SYNC_ENTER_TIMER
.Lsysc_stmg: .Lsysc_stmg:
stmg %r8,%r15,__LC_SAVE_AREA_SYNC stmg %r8,%r15,__LC_SAVE_AREA_SYNC
lg %r10,__LC_LAST_BREAK
lg %r12,__LC_CURRENT lg %r12,__LC_CURRENT
lghi %r13,__TASK_thread
lghi %r14,_PIF_SYSCALL lghi %r14,_PIF_SYSCALL
.Lsysc_per: .Lsysc_per:
lg %r15,__LC_KERNEL_STACK lg %r15,__LC_KERNEL_STACK
la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
LAST_BREAK %r13
.Lsysc_vtime: .Lsysc_vtime:
UPDATE_VTIME %r10,%r13,__LC_SYNC_ENTER_TIMER UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER
stmg %r0,%r7,__PT_R0(%r11) stmg %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW
...@@ -294,12 +280,7 @@ ENTRY(system_call) ...@@ -294,12 +280,7 @@ ENTRY(system_call)
stg %r14,__PT_FLAGS(%r11) stg %r14,__PT_FLAGS(%r11)
.Lsysc_do_svc: .Lsysc_do_svc:
# load address of system call table # load address of system call table
#ifdef CONFIG_HAVE_MARCH_Z990_FEATURES
lg %r10,__TASK_thread+__THREAD_sysc_table(%r12)
#else
lghi %r13,__TASK_thread
lg %r10,__THREAD_sysc_table(%r13,%r12) lg %r10,__THREAD_sysc_table(%r13,%r12)
#endif
llgh %r8,__PT_INT_CODE+2(%r11) llgh %r8,__PT_INT_CODE+2(%r11)
slag %r8,%r8,2 # shift and test for svc 0 slag %r8,%r8,2 # shift and test for svc 0
jnz .Lsysc_nr_ok jnz .Lsysc_nr_ok
...@@ -399,13 +380,11 @@ ENTRY(system_call) ...@@ -399,13 +380,11 @@ ENTRY(system_call)
brasl %r14,do_signal brasl %r14,do_signal
TSTMSK __PT_FLAGS(%r11),_PIF_SYSCALL TSTMSK __PT_FLAGS(%r11),_PIF_SYSCALL
jno .Lsysc_return jno .Lsysc_return
.Lsysc_do_syscall:
lghi %r13,__TASK_thread
lmg %r2,%r7,__PT_R2(%r11) # load svc arguments lmg %r2,%r7,__PT_R2(%r11) # load svc arguments
lghi %r8,0 # svc 0 returns -ENOSYS lghi %r1,0 # svc 0 returns -ENOSYS
llgh %r1,__PT_INT_CODE+2(%r11) # load new svc number j .Lsysc_do_svc
cghi %r1,NR_syscalls
jnl .Lsysc_nr_ok # invalid svc number -> do svc 0
slag %r8,%r1,2
j .Lsysc_nr_ok # restart svc
# #
# _TIF_NOTIFY_RESUME is set, call do_notify_resume # _TIF_NOTIFY_RESUME is set, call do_notify_resume
...@@ -508,8 +487,7 @@ ENTRY(pgm_check_handler) ...@@ -508,8 +487,7 @@ ENTRY(pgm_check_handler)
1: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC 1: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC
aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
j 3f j 3f
2: LAST_BREAK %r14 2: UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
lg %r15,__LC_KERNEL_STACK lg %r15,__LC_KERNEL_STACK
lgr %r14,%r12 lgr %r14,%r12
aghi %r14,__TASK_thread # pointer to thread_struct aghi %r14,__TASK_thread # pointer to thread_struct
...@@ -518,6 +496,7 @@ ENTRY(pgm_check_handler) ...@@ -518,6 +496,7 @@ ENTRY(pgm_check_handler)
jz 3f jz 3f
mvc __THREAD_trap_tdb(256,%r14),0(%r13) mvc __THREAD_trap_tdb(256,%r14),0(%r13)
3: la %r11,STACK_FRAME_OVERHEAD(%r15) 3: la %r11,STACK_FRAME_OVERHEAD(%r15)
stg %r10,__THREAD_last_break(%r14)
stmg %r0,%r7,__PT_R0(%r11) stmg %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
stmg %r8,%r9,__PT_PSW(%r11) stmg %r8,%r9,__PT_PSW(%r11)
...@@ -547,6 +526,8 @@ ENTRY(pgm_check_handler) ...@@ -547,6 +526,8 @@ ENTRY(pgm_check_handler)
LOCKDEP_SYS_EXIT LOCKDEP_SYS_EXIT
tm __PT_PSW+1(%r11),0x01 # returning to user ? tm __PT_PSW+1(%r11),0x01 # returning to user ?
jno .Lsysc_restore jno .Lsysc_restore
TSTMSK __PT_FLAGS(%r11),_PIF_SYSCALL
jo .Lsysc_do_syscall
j .Lsysc_tif j .Lsysc_tif
# #
...@@ -564,6 +545,7 @@ ENTRY(pgm_check_handler) ...@@ -564,6 +545,7 @@ ENTRY(pgm_check_handler)
# #
.Lpgm_svcper: .Lpgm_svcper:
mvc __LC_RETURN_PSW(8),__LC_SVC_NEW_PSW mvc __LC_RETURN_PSW(8),__LC_SVC_NEW_PSW
lghi %r13,__TASK_thread
larl %r14,.Lsysc_per larl %r14,.Lsysc_per
stg %r14,__LC_RETURN_PSW+8 stg %r14,__LC_RETURN_PSW+8
lghi %r14,_PIF_SYSCALL | _PIF_PER_TRAP lghi %r14,_PIF_SYSCALL | _PIF_PER_TRAP
...@@ -576,7 +558,6 @@ ENTRY(io_int_handler) ...@@ -576,7 +558,6 @@ ENTRY(io_int_handler)
STCK __LC_INT_CLOCK STCK __LC_INT_CLOCK
stpt __LC_ASYNC_ENTER_TIMER stpt __LC_ASYNC_ENTER_TIMER
stmg %r8,%r15,__LC_SAVE_AREA_ASYNC stmg %r8,%r15,__LC_SAVE_AREA_ASYNC
lg %r10,__LC_LAST_BREAK
lg %r12,__LC_CURRENT lg %r12,__LC_CURRENT
larl %r13,cleanup_critical larl %r13,cleanup_critical
lmg %r8,%r9,__LC_IO_OLD_PSW lmg %r8,%r9,__LC_IO_OLD_PSW
...@@ -750,7 +731,6 @@ ENTRY(ext_int_handler) ...@@ -750,7 +731,6 @@ ENTRY(ext_int_handler)
STCK __LC_INT_CLOCK STCK __LC_INT_CLOCK
stpt __LC_ASYNC_ENTER_TIMER stpt __LC_ASYNC_ENTER_TIMER
stmg %r8,%r15,__LC_SAVE_AREA_ASYNC stmg %r8,%r15,__LC_SAVE_AREA_ASYNC
lg %r10,__LC_LAST_BREAK
lg %r12,__LC_CURRENT lg %r12,__LC_CURRENT
larl %r13,cleanup_critical larl %r13,cleanup_critical
lmg %r8,%r9,__LC_EXT_OLD_PSW lmg %r8,%r9,__LC_EXT_OLD_PSW
...@@ -893,7 +873,6 @@ ENTRY(mcck_int_handler) ...@@ -893,7 +873,6 @@ ENTRY(mcck_int_handler)
la %r1,4095 # revalidate r1 la %r1,4095 # revalidate r1
spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer
lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
lg %r10,__LC_LAST_BREAK
lg %r12,__LC_CURRENT lg %r12,__LC_CURRENT
larl %r13,cleanup_critical larl %r13,cleanup_critical
lmg %r8,%r9,__LC_MCK_OLD_PSW lmg %r8,%r9,__LC_MCK_OLD_PSW
...@@ -1088,9 +1067,10 @@ cleanup_critical: ...@@ -1088,9 +1067,10 @@ cleanup_critical:
0: # check if base register setup + TIF bit load has been done 0: # check if base register setup + TIF bit load has been done
clg %r9,BASED(.Lcleanup_system_call_insn+16) clg %r9,BASED(.Lcleanup_system_call_insn+16)
jhe 0f jhe 0f
# set up saved registers r10 and r12 # set up saved register r12 task struct pointer
stg %r10,16(%r11) # r10 last break stg %r12,32(%r11)
stg %r12,32(%r11) # r12 task struct pointer # set up saved register r13 __TASK_thread offset
mvc 40(8,%r11),BASED(.Lcleanup_system_call_const)
0: # check if the user time update has been done 0: # check if the user time update has been done
clg %r9,BASED(.Lcleanup_system_call_insn+24) clg %r9,BASED(.Lcleanup_system_call_insn+24)
jh 0f jh 0f
...@@ -1107,14 +1087,7 @@ cleanup_critical: ...@@ -1107,14 +1087,7 @@ cleanup_critical:
stg %r15,__LC_SYSTEM_TIMER stg %r15,__LC_SYSTEM_TIMER
0: # update accounting time stamp 0: # update accounting time stamp
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
# do LAST_BREAK # set up saved register r11
lg %r9,16(%r11)
srag %r9,%r9,23
jz 0f
lgr %r9,%r12
aghi %r9,__TASK_thread
mvc __THREAD_last_break(8,%r9),16(%r11)
0: # set up saved register r11
lg %r15,__LC_KERNEL_STACK lg %r15,__LC_KERNEL_STACK
la %r9,STACK_FRAME_OVERHEAD(%r15) la %r9,STACK_FRAME_OVERHEAD(%r15)
stg %r9,24(%r11) # r11 pt_regs pointer stg %r9,24(%r11) # r11 pt_regs pointer
...@@ -1136,6 +1109,8 @@ cleanup_critical: ...@@ -1136,6 +1109,8 @@ cleanup_critical:
.quad .Lsysc_per .quad .Lsysc_per
.quad .Lsysc_vtime+36 .quad .Lsysc_vtime+36
.quad .Lsysc_vtime+42 .quad .Lsysc_vtime+42
.Lcleanup_system_call_const:
.quad __TASK_thread
.Lcleanup_sysc_tif: .Lcleanup_sysc_tif:
larl %r9,.Lsysc_tif larl %r9,.Lsysc_tif
......
...@@ -57,8 +57,8 @@ static ssize_t show_idle_count(struct device *dev, ...@@ -57,8 +57,8 @@ static ssize_t show_idle_count(struct device *dev,
do { do {
seq = read_seqcount_begin(&idle->seqcount); seq = read_seqcount_begin(&idle->seqcount);
idle_count = ACCESS_ONCE(idle->idle_count); idle_count = READ_ONCE(idle->idle_count);
if (ACCESS_ONCE(idle->clock_idle_enter)) if (READ_ONCE(idle->clock_idle_enter))
idle_count++; idle_count++;
} while (read_seqcount_retry(&idle->seqcount, seq)); } while (read_seqcount_retry(&idle->seqcount, seq));
return sprintf(buf, "%llu\n", idle_count); return sprintf(buf, "%llu\n", idle_count);
...@@ -75,9 +75,9 @@ static ssize_t show_idle_time(struct device *dev, ...@@ -75,9 +75,9 @@ static ssize_t show_idle_time(struct device *dev,
do { do {
now = get_tod_clock(); now = get_tod_clock();
seq = read_seqcount_begin(&idle->seqcount); seq = read_seqcount_begin(&idle->seqcount);
idle_time = ACCESS_ONCE(idle->idle_time); idle_time = READ_ONCE(idle->idle_time);
idle_enter = ACCESS_ONCE(idle->clock_idle_enter); idle_enter = READ_ONCE(idle->clock_idle_enter);
idle_exit = ACCESS_ONCE(idle->clock_idle_exit); idle_exit = READ_ONCE(idle->clock_idle_exit);
} while (read_seqcount_retry(&idle->seqcount, seq)); } while (read_seqcount_retry(&idle->seqcount, seq));
idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0; idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0;
return sprintf(buf, "%llu\n", idle_time >> 12); return sprintf(buf, "%llu\n", idle_time >> 12);
...@@ -93,8 +93,8 @@ u64 arch_cpu_idle_time(int cpu) ...@@ -93,8 +93,8 @@ u64 arch_cpu_idle_time(int cpu)
do { do {
now = get_tod_clock(); now = get_tod_clock();
seq = read_seqcount_begin(&idle->seqcount); seq = read_seqcount_begin(&idle->seqcount);
idle_enter = ACCESS_ONCE(idle->clock_idle_enter); idle_enter = READ_ONCE(idle->clock_idle_enter);
idle_exit = ACCESS_ONCE(idle->clock_idle_exit); idle_exit = READ_ONCE(idle->clock_idle_exit);
} while (read_seqcount_retry(&idle->seqcount, seq)); } while (read_seqcount_retry(&idle->seqcount, seq));
return cputime_to_nsecs(idle_enter ? ((idle_exit ?: now) - idle_enter) : 0); return cputime_to_nsecs(idle_enter ? ((idle_exit ?: now) - idle_enter) : 0);
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/reboot.h> #include <linux/reboot.h>
...@@ -1546,7 +1547,8 @@ static void dump_reipl_run(struct shutdown_trigger *trigger) ...@@ -1546,7 +1547,8 @@ static void dump_reipl_run(struct shutdown_trigger *trigger)
unsigned long ipib = (unsigned long) reipl_block_actual; unsigned long ipib = (unsigned long) reipl_block_actual;
unsigned int csum; unsigned int csum;
csum = csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0); csum = (__force unsigned int)
csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0);
mem_assign_absolute(S390_lowcore.ipib, ipib); mem_assign_absolute(S390_lowcore.ipib, ipib);
mem_assign_absolute(S390_lowcore.ipib_checksum, csum); mem_assign_absolute(S390_lowcore.ipib_checksum, csum);
dump_run(trigger); dump_run(trigger);
...@@ -1863,7 +1865,7 @@ static int __init s390_ipl_init(void) ...@@ -1863,7 +1865,7 @@ static int __init s390_ipl_init(void)
{ {
char str[8] = {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40}; char str[8] = {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40};
sclp_get_ipl_info(&sclp_ipl_info); sclp_early_get_ipl_info(&sclp_ipl_info);
/* /*
* Fix loadparm: There are systems where the (SCSI) LOADPARM * Fix loadparm: There are systems where the (SCSI) LOADPARM
* returned by read SCP info is invalid (contains EBCDIC blanks) * returned by read SCP info is invalid (contains EBCDIC blanks)
......
...@@ -12,11 +12,12 @@ ...@@ -12,11 +12,12 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/profile.h> #include <linux/profile.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <asm/irq_regs.h> #include <asm/irq_regs.h>
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
* Copyright IBM Corp. 2011 * Copyright IBM Corp. 2011
* Author(s): Jan Glauber <jang@linux.vnet.ibm.com> * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
*/ */
#include <linux/module.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/stop_machine.h> #include <linux/stop_machine.h>
#include <linux/jump_label.h> #include <linux/jump_label.h>
......
...@@ -45,11 +45,17 @@ DEFINE_INSN_CACHE_OPS(dmainsn); ...@@ -45,11 +45,17 @@ DEFINE_INSN_CACHE_OPS(dmainsn);
static void *alloc_dmainsn_page(void) static void *alloc_dmainsn_page(void)
{ {
return (void *)__get_free_page(GFP_KERNEL | GFP_DMA); void *page;
page = (void *) __get_free_page(GFP_KERNEL | GFP_DMA);
if (page)
set_memory_x((unsigned long) page, 1);
return page;
} }
static void free_dmainsn_page(void *page) static void free_dmainsn_page(void *page)
{ {
set_memory_nx((unsigned long) page, 1);
free_page((unsigned long)page); free_page((unsigned long)page);
} }
......
...@@ -45,7 +45,8 @@ void *module_alloc(unsigned long size) ...@@ -45,7 +45,8 @@ void *module_alloc(unsigned long size)
if (PAGE_ALIGN(size) > MODULES_LEN) if (PAGE_ALIGN(size) > MODULES_LEN)
return NULL; return NULL;
return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, GFP_KERNEL, PAGE_KERNEL_EXEC,
0, NUMA_NO_NODE,
__builtin_return_address(0)); __builtin_return_address(0));
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/module.h> #include <linux/export.h>
#include <asm/lowcore.h> #include <asm/lowcore.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/stp.h> #include <asm/stp.h>
......
...@@ -26,7 +26,7 @@ static struct os_info os_info __page_aligned_data; ...@@ -26,7 +26,7 @@ static struct os_info os_info __page_aligned_data;
u32 os_info_csum(struct os_info *os_info) u32 os_info_csum(struct os_info *os_info)
{ {
int size = sizeof(*os_info) - offsetof(struct os_info, version_major); int size = sizeof(*os_info) - offsetof(struct os_info, version_major);
return csum_partial(&os_info->version_major, size, 0); return (__force u32)csum_partial(&os_info->version_major, size, 0);
} }
/* /*
...@@ -46,7 +46,7 @@ void os_info_entry_add(int nr, void *ptr, u64 size) ...@@ -46,7 +46,7 @@ void os_info_entry_add(int nr, void *ptr, u64 size)
{ {
os_info.entry[nr].addr = (u64)(unsigned long)ptr; os_info.entry[nr].addr = (u64)(unsigned long)ptr;
os_info.entry[nr].size = size; os_info.entry[nr].size = size;
os_info.entry[nr].csum = csum_partial(ptr, size, 0); os_info.entry[nr].csum = (__force u32)csum_partial(ptr, size, 0);
os_info.csum = os_info_csum(&os_info); os_info.csum = os_info_csum(&os_info);
} }
...@@ -93,7 +93,7 @@ static void os_info_old_alloc(int nr, int align) ...@@ -93,7 +93,7 @@ static void os_info_old_alloc(int nr, int align)
msg = "copy failed"; msg = "copy failed";
goto fail_free; goto fail_free;
} }
csum = csum_partial(buf_align, size, 0); csum = (__force u32)csum_partial(buf_align, size, 0);
if (csum != os_info_old->entry[nr].csum) { if (csum != os_info_old->entry[nr].csum) {
msg = "checksum failed"; msg = "checksum failed";
goto fail_free; goto fail_free;
......
...@@ -309,7 +309,7 @@ __init const struct attribute_group **cpumf_cf_event_group(void) ...@@ -309,7 +309,7 @@ __init const struct attribute_group **cpumf_cf_event_group(void)
default: default:
model = NULL; model = NULL;
break; break;
}; }
if (!model) if (!model)
goto out; goto out;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/init_task.h> #include <linux/init_task.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/processor.h> #include <asm/processor.h>
......
...@@ -32,7 +32,7 @@ static bool machine_has_cpu_mhz; ...@@ -32,7 +32,7 @@ static bool machine_has_cpu_mhz;
void __init cpu_detect_mhz_feature(void) void __init cpu_detect_mhz_feature(void)
{ {
if (test_facility(34) && __ecag(ECAG_CPU_ATTRIBUTE, 0) != -1UL) if (test_facility(34) && __ecag(ECAG_CPU_ATTRIBUTE, 0) != -1UL)
machine_has_cpu_mhz = 1; machine_has_cpu_mhz = true;
} }
static void update_cpu_mhz(void *arg) static void update_cpu_mhz(void *arg)
...@@ -92,7 +92,7 @@ static void show_cpu_summary(struct seq_file *m, void *v) ...@@ -92,7 +92,7 @@ static void show_cpu_summary(struct seq_file *m, void *v)
{ {
static const char *hwcap_str[] = { static const char *hwcap_str[] = {
"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
"edat", "etf3eh", "highgprs", "te", "vx" "edat", "etf3eh", "highgprs", "te", "vx", "vxd", "vxe"
}; };
static const char * const int_hwcap_str[] = { static const char * const int_hwcap_str[] = {
"sie" "sie"
......
/*
* Copyright IBM Corp. 2015
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#include <linux/kernel.h>
#include <asm/ebcdic.h>
#include <asm/irq.h>
#include <asm/lowcore.h>
#include <asm/processor.h>
#include <asm/sclp.h>
#define EVTYP_VT220MSG_MASK 0x00000040
#define EVTYP_MSG_MASK 0x40000000
static char _sclp_work_area[4096] __aligned(PAGE_SIZE) __section(data);
static bool have_vt220 __section(data);
static bool have_linemode __section(data);
static void _sclp_wait_int(void)
{
unsigned long cr0, cr0_new, psw_mask, addr;
psw_t psw_ext_save, psw_wait;
__ctl_store(cr0, 0, 0);
cr0_new = cr0 | 0x200;
__ctl_load(cr0_new, 0, 0);
psw_ext_save = S390_lowcore.external_new_psw;
psw_mask = __extract_psw();
S390_lowcore.external_new_psw.mask = psw_mask;
psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT;
S390_lowcore.ext_int_code = 0;
do {
asm volatile(
" larl %[addr],0f\n"
" stg %[addr],%[psw_wait_addr]\n"
" stg %[addr],%[psw_ext_addr]\n"
" lpswe %[psw_wait]\n"
"0:\n"
: [addr] "=&d" (addr),
[psw_wait_addr] "=Q" (psw_wait.addr),
[psw_ext_addr] "=Q" (S390_lowcore.external_new_psw.addr)
: [psw_wait] "Q" (psw_wait)
: "cc", "memory");
} while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG);
__ctl_load(cr0, 0, 0);
S390_lowcore.external_new_psw = psw_ext_save;
}
static int _sclp_servc(unsigned int cmd, char *sccb)
{
unsigned int cc;
do {
asm volatile(
" .insn rre,0xb2200000,%1,%2\n"
" ipm %0\n"
: "=d" (cc) : "d" (cmd), "a" (sccb)
: "cc", "memory");
cc >>= 28;
if (cc == 3)
return -EINVAL;
_sclp_wait_int();
} while (cc != 0);
return (*(unsigned short *)(sccb + 6) == 0x20) ? 0 : -EIO;
}
static int _sclp_setup(int disable)
{
static unsigned char init_sccb[] = {
0x00, 0x1c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04,
0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int *masks;
int rc;
memcpy(_sclp_work_area, init_sccb, 28);
masks = (unsigned int *)(_sclp_work_area + 12);
if (disable)
memset(masks, 0, 16);
/* SCLP write mask */
rc = _sclp_servc(0x00780005, _sclp_work_area);
if (rc)
return rc;
have_vt220 = masks[2] & EVTYP_VT220MSG_MASK;
have_linemode = masks[2] & EVTYP_MSG_MASK;
return 0;
}
/* Output multi-line text using SCLP Message interface. */
static void _sclp_print_lm(const char *str)
{
static unsigned char write_head[] = {
/* sccb header */
0x00, 0x52, /* 0 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */
/* evbuf */
0x00, 0x4a, /* 8 */
0x02, 0x00, 0x00, 0x00, /* 10 */
/* mdb */
0x00, 0x44, /* 14 */
0x00, 0x01, /* 16 */
0xd4, 0xc4, 0xc2, 0x40, /* 18 */
0x00, 0x00, 0x00, 0x01, /* 22 */
/* go */
0x00, 0x38, /* 26 */
0x00, 0x01, /* 28 */
0x00, 0x00, 0x00, 0x00, /* 30 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 34 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 */
0x00, 0x00, 0x00, 0x00, /* 50 */
0x00, 0x00, /* 54 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 64 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 72 */
0x00, 0x00, /* 80 */
};
static unsigned char write_mto[] = {
/* mto */
0x00, 0x0a, /* 0 */
0x00, 0x04, /* 2 */
0x10, 0x00, /* 4 */
0x00, 0x00, 0x00, 0x00 /* 6 */
};
unsigned char *ptr, ch;
unsigned int count;
memcpy(_sclp_work_area, write_head, sizeof(write_head));
ptr = _sclp_work_area + sizeof(write_head);
do {
memcpy(ptr, write_mto, sizeof(write_mto));
for (count = sizeof(write_mto); (ch = *str++) != 0; count++) {
if (ch == 0x0a)
break;
ptr[count] = _ascebc[ch];
}
/* Update length fields in mto, mdb, evbuf and sccb */
*(unsigned short *) ptr = count;
*(unsigned short *)(_sclp_work_area + 14) += count;
*(unsigned short *)(_sclp_work_area + 8) += count;
*(unsigned short *)(_sclp_work_area + 0) += count;
ptr += count;
} while (ch != 0);
/* SCLP write data */
_sclp_servc(0x00760005, _sclp_work_area);
}
/* Output multi-line text (plus a newline) using SCLP VT220
* interface.
*/
static void _sclp_print_vt220(const char *str)
{
static unsigned char const write_head[] = {
/* sccb header */
0x00, 0x0e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* evbuf header */
0x00, 0x06,
0x1a, 0x00, 0x00, 0x00,
};
size_t len = strlen(str);
if (sizeof(write_head) + len >= sizeof(_sclp_work_area))
len = sizeof(_sclp_work_area) - sizeof(write_head) - 1;
memcpy(_sclp_work_area, write_head, sizeof(write_head));
memcpy(_sclp_work_area + sizeof(write_head), str, len);
_sclp_work_area[sizeof(write_head) + len] = '\n';
/* Update length fields in evbuf and sccb headers */
*(unsigned short *)(_sclp_work_area + 8) += len + 1;
*(unsigned short *)(_sclp_work_area + 0) += len + 1;
/* SCLP write data */
(void)_sclp_servc(0x00760005, _sclp_work_area);
}
/* Output one or more lines of text on the SCLP console (VT220 and /
* or line-mode). All lines get terminated; no need for a trailing LF.
*/
void _sclp_print_early(const char *str)
{
if (_sclp_setup(0) != 0)
return;
if (have_linemode)
_sclp_print_lm(str);
if (have_vt220)
_sclp_print_vt220(str);
_sclp_setup(1);
}
...@@ -636,6 +636,8 @@ static void __init reserve_crashkernel(void) ...@@ -636,6 +636,8 @@ static void __init reserve_crashkernel(void)
static void __init reserve_initrd(void) static void __init reserve_initrd(void)
{ {
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
if (!INITRD_START || !INITRD_SIZE)
return;
initrd_start = INITRD_START; initrd_start = INITRD_START;
initrd_end = initrd_start + INITRD_SIZE; initrd_end = initrd_start + INITRD_SIZE;
memblock_reserve(INITRD_START, INITRD_SIZE); memblock_reserve(INITRD_START, INITRD_SIZE);
...@@ -747,7 +749,7 @@ static int __init setup_hwcaps(void) ...@@ -747,7 +749,7 @@ static int __init setup_hwcaps(void)
/* /*
* Huge page support HWCAP_S390_HPAGE is bit 7. * Huge page support HWCAP_S390_HPAGE is bit 7.
*/ */
if (MACHINE_HAS_HPAGE) if (MACHINE_HAS_EDAT1)
elf_hwcap |= HWCAP_S390_HPAGE; elf_hwcap |= HWCAP_S390_HPAGE;
/* /*
...@@ -767,8 +769,14 @@ static int __init setup_hwcaps(void) ...@@ -767,8 +769,14 @@ static int __init setup_hwcaps(void)
* can be disabled with the "novx" parameter. Use MACHINE_HAS_VX * can be disabled with the "novx" parameter. Use MACHINE_HAS_VX
* instead of facility bit 129. * instead of facility bit 129.
*/ */
if (MACHINE_HAS_VX) if (MACHINE_HAS_VX) {
elf_hwcap |= HWCAP_S390_VXRS; elf_hwcap |= HWCAP_S390_VXRS;
if (test_facility(134))
elf_hwcap |= HWCAP_S390_VXRS_EXT;
if (test_facility(135))
elf_hwcap |= HWCAP_S390_VXRS_BCD;
}
get_cpu_id(&cpu_id); get_cpu_id(&cpu_id);
add_device_randomness(&cpu_id, sizeof(cpu_id)); add_device_randomness(&cpu_id, sizeof(cpu_id));
switch (cpu_id.machine) { switch (cpu_id.machine) {
...@@ -820,10 +828,10 @@ static void __init setup_randomness(void) ...@@ -820,10 +828,10 @@ static void __init setup_randomness(void)
{ {
struct sysinfo_3_2_2 *vmms; struct sysinfo_3_2_2 *vmms;
vmms = (struct sysinfo_3_2_2 *) alloc_page(GFP_KERNEL); vmms = (struct sysinfo_3_2_2 *) memblock_alloc(PAGE_SIZE, PAGE_SIZE);
if (vmms && stsi(vmms, 3, 2, 2) == 0 && vmms->count) if (stsi(vmms, 3, 2, 2) == 0 && vmms->count)
add_device_randomness(&vmms, vmms->count); add_device_randomness(&vmms->vm, sizeof(vmms->vm[0]) * vmms->count);
free_page((unsigned long) vmms); memblock_free((unsigned long) vmms, PAGE_SIZE);
} }
/* /*
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/err.h> #include <linux/err.h>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/stacktrace.h> #include <linux/stacktrace.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/module.h> #include <linux/export.h>
static int __save_address(void *data, unsigned long address, int nosched) static int __save_address(void *data, unsigned long address, int nosched)
{ {
......
...@@ -196,7 +196,7 @@ pgm_check_entry: ...@@ -196,7 +196,7 @@ pgm_check_entry:
larl %r15,init_thread_union larl %r15,init_thread_union
ahi %r15,1<<(PAGE_SHIFT+THREAD_SIZE_ORDER) ahi %r15,1<<(PAGE_SHIFT+THREAD_SIZE_ORDER)
larl %r2,.Lpanic_string larl %r2,.Lpanic_string
larl %r3,_sclp_print_early larl %r3,sclp_early_printk
lghi %r1,0 lghi %r1,0
sam31 sam31
sigp %r1,%r0,SIGP_SET_ARCHITECTURE sigp %r1,%r0,SIGP_SET_ARCHITECTURE
...@@ -273,7 +273,7 @@ restore_registers: ...@@ -273,7 +273,7 @@ restore_registers:
.Ldisabled_wait_31: .Ldisabled_wait_31:
.long 0x000a0000,0x00000000 .long 0x000a0000,0x00000000
.Lpanic_string: .Lpanic_string:
.asciz "Resume not possible because suspend CPU is no longer available" .asciz "Resume not possible because suspend CPU is no longer available\n"
.align 8 .align 8
.Lrestart_diag308_psw: .Lrestart_diag308_psw:
.long 0x00080000,0x80000000 .long 0x00080000,0x80000000
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <asm/sysinfo.h> #include <asm/sysinfo.h>
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/param.h> #include <linux/param.h>
...@@ -110,7 +110,7 @@ unsigned long long monotonic_clock(void) ...@@ -110,7 +110,7 @@ unsigned long long monotonic_clock(void)
} }
EXPORT_SYMBOL(monotonic_clock); EXPORT_SYMBOL(monotonic_clock);
void tod_to_timeval(__u64 todval, struct timespec64 *xt) static void tod_to_timeval(__u64 todval, struct timespec64 *xt)
{ {
unsigned long long sec; unsigned long long sec;
...@@ -120,7 +120,6 @@ void tod_to_timeval(__u64 todval, struct timespec64 *xt) ...@@ -120,7 +120,6 @@ void tod_to_timeval(__u64 todval, struct timespec64 *xt)
todval -= (sec * 1000000) << 12; todval -= (sec * 1000000) << 12;
xt->tv_nsec = ((todval * 1000) >> 12); xt->tv_nsec = ((todval * 1000) >> 12);
} }
EXPORT_SYMBOL(tod_to_timeval);
void clock_comparator_work(void) void clock_comparator_work(void)
{ {
...@@ -492,7 +491,7 @@ static void __init stp_reset(void) ...@@ -492,7 +491,7 @@ static void __init stp_reset(void)
pr_warn("The real or virtual hardware system does not provide an STP interface\n"); pr_warn("The real or virtual hardware system does not provide an STP interface\n");
free_page((unsigned long) stp_page); free_page((unsigned long) stp_page);
stp_page = NULL; stp_page = NULL;
stp_online = 0; stp_online = false;
} }
} }
......
...@@ -38,7 +38,6 @@ static void set_topology_timer(void); ...@@ -38,7 +38,6 @@ static void set_topology_timer(void);
static void topology_work_fn(struct work_struct *work); static void topology_work_fn(struct work_struct *work);
static struct sysinfo_15_1_x *tl_info; static struct sysinfo_15_1_x *tl_info;
static bool topology_enabled = true;
static DECLARE_WORK(topology_work, topology_work_fn); static DECLARE_WORK(topology_work, topology_work_fn);
/* /*
...@@ -59,7 +58,7 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) ...@@ -59,7 +58,7 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
cpumask_t mask; cpumask_t mask;
cpumask_copy(&mask, cpumask_of(cpu)); cpumask_copy(&mask, cpumask_of(cpu));
if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) if (!MACHINE_HAS_TOPOLOGY)
return mask; return mask;
for (; info; info = info->next) { for (; info; info = info->next) {
if (cpumask_test_cpu(cpu, &info->mask)) if (cpumask_test_cpu(cpu, &info->mask))
...@@ -74,7 +73,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu) ...@@ -74,7 +73,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu)
int i; int i;
cpumask_copy(&mask, cpumask_of(cpu)); cpumask_copy(&mask, cpumask_of(cpu));
if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) if (!MACHINE_HAS_TOPOLOGY)
return mask; return mask;
cpu -= cpu % (smp_cpu_mtid + 1); cpu -= cpu % (smp_cpu_mtid + 1);
for (i = 0; i <= smp_cpu_mtid; i++) for (i = 0; i <= smp_cpu_mtid; i++)
...@@ -428,12 +427,6 @@ static const struct cpumask *cpu_drawer_mask(int cpu) ...@@ -428,12 +427,6 @@ static const struct cpumask *cpu_drawer_mask(int cpu)
return &cpu_topology[cpu].drawer_mask; return &cpu_topology[cpu].drawer_mask;
} }
static int __init early_parse_topology(char *p)
{
return kstrtobool(p, &topology_enabled);
}
early_param("topology", early_parse_topology);
static struct sched_domain_topology_level s390_topology[] = { static struct sched_domain_topology_level s390_topology[] = {
{ cpu_thread_mask, cpu_smt_flags, SD_INIT_NAME(SMT) }, { cpu_thread_mask, cpu_smt_flags, SD_INIT_NAME(SMT) },
{ cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
...@@ -461,18 +454,16 @@ static void __init alloc_masks(struct sysinfo_15_1_x *info, ...@@ -461,18 +454,16 @@ static void __init alloc_masks(struct sysinfo_15_1_x *info,
void __init topology_init_early(void) void __init topology_init_early(void)
{ {
struct sysinfo_15_1_x *info; struct sysinfo_15_1_x *info;
int i;
set_sched_topology(s390_topology); set_sched_topology(s390_topology);
if (!MACHINE_HAS_TOPOLOGY) if (!MACHINE_HAS_TOPOLOGY)
goto out; goto out;
tl_info = memblock_virt_alloc(sizeof(*tl_info), PAGE_SIZE); tl_info = memblock_virt_alloc(PAGE_SIZE, PAGE_SIZE);
info = tl_info; info = tl_info;
store_topology(info); store_topology(info);
pr_info("The CPU configuration topology of the machine is:"); pr_info("The CPU configuration topology of the machine is: %d %d %d %d %d %d / %d\n",
for (i = 0; i < TOPOLOGY_NR_MAG; i++) info->mag[0], info->mag[1], info->mag[2], info->mag[3],
printk(KERN_CONT " %d", info->mag[i]); info->mag[4], info->mag[5], info->mnest);
printk(KERN_CONT " / %d\n", info->mnest);
alloc_masks(info, &socket_info, 1); alloc_masks(info, &socket_info, 1);
alloc_masks(info, &book_info, 2); alloc_masks(info, &book_info, 2);
alloc_masks(info, &drawer_info, 3); alloc_masks(info, &drawer_info, 3);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
*/ */
#include <linux/module.h> #include <linux/init.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kernel.h> #include <linux/kernel.h>
......
...@@ -44,6 +44,7 @@ SECTIONS ...@@ -44,6 +44,7 @@ SECTIONS
*(.gnu.warning) *(.gnu.warning)
} :text = 0x0700 } :text = 0x0700
. = ALIGN(PAGE_SIZE);
_etext = .; /* End of text section */ _etext = .; /* End of text section */
NOTES :text :note NOTES :text :note
...@@ -79,7 +80,13 @@ SECTIONS ...@@ -79,7 +80,13 @@ SECTIONS
. = ALIGN(PAGE_SIZE); /* Init code and data */ . = ALIGN(PAGE_SIZE); /* Init code and data */
__init_begin = .; __init_begin = .;
INIT_TEXT_SECTION(PAGE_SIZE) . = ALIGN(PAGE_SIZE);
.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
VMLINUX_SYMBOL(_sinittext) = . ;
INIT_TEXT
. = ALIGN(PAGE_SIZE);
VMLINUX_SYMBOL(_einittext) = . ;
}
/* /*
* .exit.text is discarded at runtime, not link time, * .exit.text is discarded at runtime, not link time,
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/kvm_host.h> #include <linux/kvm_host.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/timer.h> #include <linux/timer.h>
......
...@@ -311,7 +311,7 @@ static int handle_sske(struct kvm_vcpu *vcpu) ...@@ -311,7 +311,7 @@ static int handle_sske(struct kvm_vcpu *vcpu)
if (rc < 0) if (rc < 0)
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
start += PAGE_SIZE; start += PAGE_SIZE;
}; }
if (m3 & (SSKE_MC | SSKE_MR)) { if (m3 & (SSKE_MC | SSKE_MR)) {
if (m3 & SSKE_MB) { if (m3 & SSKE_MB) {
......
...@@ -899,7 +899,7 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -899,7 +899,7 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
if (rc || scb_s->icptcode || signal_pending(current) || if (rc || scb_s->icptcode || signal_pending(current) ||
kvm_s390_vcpu_has_irq(vcpu, 0)) kvm_s390_vcpu_has_irq(vcpu, 0))
break; break;
}; }
if (rc == -EFAULT) { if (rc == -EFAULT) {
/* /*
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/irqflags.h> #include <linux/irqflags.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
......
...@@ -14,31 +14,29 @@ ENTRY(memmove) ...@@ -14,31 +14,29 @@ ENTRY(memmove)
ltgr %r4,%r4 ltgr %r4,%r4
lgr %r1,%r2 lgr %r1,%r2
bzr %r14 bzr %r14
aghi %r4,-1
clgr %r2,%r3 clgr %r2,%r3
jnh .Lmemmove_forward jnh .Lmemmove_forward
la %r5,0(%r4,%r3) la %r5,1(%r4,%r3)
clgr %r2,%r5 clgr %r2,%r5
jl .Lmemmove_reverse jl .Lmemmove_reverse
.Lmemmove_forward: .Lmemmove_forward:
aghi %r4,-1
srlg %r0,%r4,8 srlg %r0,%r4,8
ltgr %r0,%r0 ltgr %r0,%r0
jz .Lmemmove_rest jz .Lmemmove_forward_remainder
.Lmemmove_loop: .Lmemmove_forward_loop:
mvc 0(256,%r1),0(%r3) mvc 0(256,%r1),0(%r3)
la %r1,256(%r1) la %r1,256(%r1)
la %r3,256(%r3) la %r3,256(%r3)
brctg %r0,.Lmemmove_loop brctg %r0,.Lmemmove_forward_loop
.Lmemmove_rest: .Lmemmove_forward_remainder:
larl %r5,.Lmemmove_mvc larl %r5,.Lmemmove_mvc
ex %r4,0(%r5) ex %r4,0(%r5)
br %r14 br %r14
.Lmemmove_reverse: .Lmemmove_reverse:
aghi %r4,-1
.Lmemmove_reverse_loop:
ic %r0,0(%r4,%r3) ic %r0,0(%r4,%r3)
stc %r0,0(%r4,%r1) stc %r0,0(%r4,%r1)
brctg %r4,.Lmemmove_reverse_loop brctg %r4,.Lmemmove_reverse
ic %r0,0(%r4,%r3) ic %r0,0(%r4,%r3)
stc %r0,0(%r4,%r1) stc %r0,0(%r4,%r1)
br %r14 br %r14
...@@ -70,12 +68,12 @@ ENTRY(memset) ...@@ -70,12 +68,12 @@ ENTRY(memset)
srlg %r3,%r4,8 srlg %r3,%r4,8
ltgr %r3,%r3 ltgr %r3,%r3
lgr %r1,%r2 lgr %r1,%r2
jz .Lmemset_clear_rest jz .Lmemset_clear_remainder
.Lmemset_clear_loop: .Lmemset_clear_loop:
xc 0(256,%r1),0(%r1) xc 0(256,%r1),0(%r1)
la %r1,256(%r1) la %r1,256(%r1)
brctg %r3,.Lmemset_clear_loop brctg %r3,.Lmemset_clear_loop
.Lmemset_clear_rest: .Lmemset_clear_remainder:
larl %r3,.Lmemset_xc larl %r3,.Lmemset_xc
ex %r4,0(%r3) ex %r4,0(%r3)
br %r14 br %r14
...@@ -87,12 +85,12 @@ ENTRY(memset) ...@@ -87,12 +85,12 @@ ENTRY(memset)
aghi %r4,-2 aghi %r4,-2
srlg %r3,%r4,8 srlg %r3,%r4,8
ltgr %r3,%r3 ltgr %r3,%r3
jz .Lmemset_fill_rest jz .Lmemset_fill_remainder
.Lmemset_fill_loop: .Lmemset_fill_loop:
mvc 1(256,%r1),0(%r1) mvc 1(256,%r1),0(%r1)
la %r1,256(%r1) la %r1,256(%r1)
brctg %r3,.Lmemset_fill_loop brctg %r3,.Lmemset_fill_loop
.Lmemset_fill_rest: .Lmemset_fill_remainder:
larl %r3,.Lmemset_mvc larl %r3,.Lmemset_mvc
ex %r4,0(%r3) ex %r4,0(%r3)
br %r14 br %r14
...@@ -115,7 +113,7 @@ ENTRY(memcpy) ...@@ -115,7 +113,7 @@ ENTRY(memcpy)
ltgr %r5,%r5 ltgr %r5,%r5
lgr %r1,%r2 lgr %r1,%r2
jnz .Lmemcpy_loop jnz .Lmemcpy_loop
.Lmemcpy_rest: .Lmemcpy_remainder:
larl %r5,.Lmemcpy_mvc larl %r5,.Lmemcpy_mvc
ex %r4,0(%r5) ex %r4,0(%r5)
br %r14 br %r14
...@@ -124,7 +122,7 @@ ENTRY(memcpy) ...@@ -124,7 +122,7 @@ ENTRY(memcpy)
la %r1,256(%r1) la %r1,256(%r1)
la %r3,256(%r3) la %r3,256(%r3)
brctg %r5,.Lmemcpy_loop brctg %r5,.Lmemcpy_loop
j .Lmemcpy_rest j .Lmemcpy_remainder
.Lmemcpy_mvc: .Lmemcpy_mvc:
mvc 0(1,%r1),0(%r3) mvc 0(1,%r1),0(%r3)
EXPORT_SYMBOL(memcpy) EXPORT_SYMBOL(memcpy)
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/smp.h> #include <linux/smp.h>
...@@ -133,7 +133,7 @@ int arch_spin_trylock_retry(arch_spinlock_t *lp) ...@@ -133,7 +133,7 @@ int arch_spin_trylock_retry(arch_spinlock_t *lp)
int count; int count;
for (count = spin_retry; count > 0; count--) { for (count = spin_retry; count > 0; count--) {
owner = ACCESS_ONCE(lp->lock); owner = READ_ONCE(lp->lock);
/* Try to get the lock if it is free. */ /* Try to get the lock if it is free. */
if (!owner) { if (!owner) {
if (_raw_compare_and_swap(&lp->lock, 0, cpu)) if (_raw_compare_and_swap(&lp->lock, 0, cpu))
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
#define IN_ARCH_STRING_C 1 #define IN_ARCH_STRING_C 1
#include <linux/types.h> #include <linux/types.h>
#include <linux/module.h> #include <linux/string.h>
#include <linux/export.h>
/* /*
* Helper functions to find the end of a string * Helper functions to find the end of a string
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/raid/xor.h> #include <linux/raid/xor.h>
static void xor_xc_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) static void xor_xc_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
......
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/module.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -49,8 +49,8 @@ static void print_prot(struct seq_file *m, unsigned int pr, int level) ...@@ -49,8 +49,8 @@ static void print_prot(struct seq_file *m, unsigned int pr, int level)
seq_printf(m, "I\n"); seq_printf(m, "I\n");
return; return;
} }
seq_printf(m, "%s", pr & _PAGE_PROTECT ? "RO " : "RW "); seq_puts(m, (pr & _PAGE_PROTECT) ? "RO " : "RW ");
seq_putc(m, '\n'); seq_puts(m, (pr & _PAGE_NOEXEC) ? "NX\n" : "X\n");
} }
static void note_page(struct seq_file *m, struct pg_state *st, static void note_page(struct seq_file *m, struct pg_state *st,
...@@ -117,7 +117,8 @@ static void walk_pte_level(struct seq_file *m, struct pg_state *st, ...@@ -117,7 +117,8 @@ static void walk_pte_level(struct seq_file *m, struct pg_state *st,
for (i = 0; i < PTRS_PER_PTE && addr < max_addr; i++) { for (i = 0; i < PTRS_PER_PTE && addr < max_addr; i++) {
st->current_address = addr; st->current_address = addr;
pte = pte_offset_kernel(pmd, addr); pte = pte_offset_kernel(pmd, addr);
prot = pte_val(*pte) & (_PAGE_PROTECT | _PAGE_INVALID); prot = pte_val(*pte) &
(_PAGE_PROTECT | _PAGE_INVALID | _PAGE_NOEXEC);
note_page(m, st, prot, 4); note_page(m, st, prot, 4);
addr += PAGE_SIZE; addr += PAGE_SIZE;
} }
...@@ -135,7 +136,9 @@ static void walk_pmd_level(struct seq_file *m, struct pg_state *st, ...@@ -135,7 +136,9 @@ static void walk_pmd_level(struct seq_file *m, struct pg_state *st,
pmd = pmd_offset(pud, addr); pmd = pmd_offset(pud, addr);
if (!pmd_none(*pmd)) { if (!pmd_none(*pmd)) {
if (pmd_large(*pmd)) { if (pmd_large(*pmd)) {
prot = pmd_val(*pmd) & _SEGMENT_ENTRY_PROTECT; prot = pmd_val(*pmd) &
(_SEGMENT_ENTRY_PROTECT |
_SEGMENT_ENTRY_NOEXEC);
note_page(m, st, prot, 3); note_page(m, st, prot, 3);
} else } else
walk_pte_level(m, st, pmd, addr); walk_pte_level(m, st, pmd, addr);
...@@ -157,7 +160,9 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, ...@@ -157,7 +160,9 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st,
pud = pud_offset(pgd, addr); pud = pud_offset(pgd, addr);
if (!pud_none(*pud)) if (!pud_none(*pud))
if (pud_large(*pud)) { if (pud_large(*pud)) {
prot = pud_val(*pud) & _REGION_ENTRY_PROTECT; prot = pud_val(*pud) &
(_REGION_ENTRY_PROTECT |
_REGION_ENTRY_NOEXEC);
note_page(m, st, prot, 2); note_page(m, st, prot, 2);
} else } else
walk_pmd_level(m, st, pud, addr); walk_pmd_level(m, st, pud, addr);
...@@ -183,6 +188,7 @@ static void walk_pgd_level(struct seq_file *m) ...@@ -183,6 +188,7 @@ static void walk_pgd_level(struct seq_file *m)
else else
note_page(m, &st, _PAGE_INVALID, 1); note_page(m, &st, _PAGE_INVALID, 1);
addr += PGDIR_SIZE; addr += PGDIR_SIZE;
cond_resched();
} }
/* Flush out the last page */ /* Flush out the last page */
st.current_address = max_addr; st.current_address = max_addr;
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/export.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/ioport.h> #include <linux/ioport.h>
...@@ -154,7 +154,7 @@ dcss_mkname(char *name, char *dcss_name) ...@@ -154,7 +154,7 @@ dcss_mkname(char *name, char *dcss_name)
if (name[i] == '\0') if (name[i] == '\0')
break; break;
dcss_name[i] = toupper(name[i]); dcss_name[i] = toupper(name[i]);
}; }
for (; i < 8; i++) for (; i < 8; i++)
dcss_name[i] = ' '; dcss_name[i] = ' ';
ASCEBC(dcss_name, 8); ASCEBC(dcss_name, 8);
......
...@@ -311,12 +311,34 @@ static noinline void do_sigbus(struct pt_regs *regs) ...@@ -311,12 +311,34 @@ static noinline void do_sigbus(struct pt_regs *regs)
force_sig_info(SIGBUS, &si, tsk); force_sig_info(SIGBUS, &si, tsk);
} }
static noinline void do_fault_error(struct pt_regs *regs, int fault) static noinline int signal_return(struct pt_regs *regs)
{
u16 instruction;
int rc;
rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
if (rc)
return rc;
if (instruction == 0x0a77) {
set_pt_regs_flag(regs, PIF_SYSCALL);
regs->int_code = 0x00040077;
return 0;
} else if (instruction == 0x0aad) {
set_pt_regs_flag(regs, PIF_SYSCALL);
regs->int_code = 0x000400ad;
return 0;
}
return -EACCES;
}
static noinline void do_fault_error(struct pt_regs *regs, int access, int fault)
{ {
int si_code; int si_code;
switch (fault) { switch (fault) {
case VM_FAULT_BADACCESS: case VM_FAULT_BADACCESS:
if (access == VM_EXEC && signal_return(regs) == 0)
break;
case VM_FAULT_BADMAP: case VM_FAULT_BADMAP:
/* Bad memory access. Check if it is kernel or user space. */ /* Bad memory access. Check if it is kernel or user space. */
if (user_mode(regs)) { if (user_mode(regs)) {
...@@ -324,7 +346,7 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault) ...@@ -324,7 +346,7 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault)
si_code = (fault == VM_FAULT_BADMAP) ? si_code = (fault == VM_FAULT_BADMAP) ?
SEGV_MAPERR : SEGV_ACCERR; SEGV_MAPERR : SEGV_ACCERR;
do_sigsegv(regs, si_code); do_sigsegv(regs, si_code);
return; break;
} }
case VM_FAULT_BADCONTEXT: case VM_FAULT_BADCONTEXT:
case VM_FAULT_PFAULT: case VM_FAULT_PFAULT:
...@@ -525,7 +547,7 @@ static inline int do_exception(struct pt_regs *regs, int access) ...@@ -525,7 +547,7 @@ static inline int do_exception(struct pt_regs *regs, int access)
void do_protection_exception(struct pt_regs *regs) void do_protection_exception(struct pt_regs *regs)
{ {
unsigned long trans_exc_code; unsigned long trans_exc_code;
int fault; int access, fault;
trans_exc_code = regs->int_parm_long; trans_exc_code = regs->int_parm_long;
/* /*
...@@ -544,9 +566,17 @@ void do_protection_exception(struct pt_regs *regs) ...@@ -544,9 +566,17 @@ void do_protection_exception(struct pt_regs *regs)
do_low_address(regs); do_low_address(regs);
return; return;
} }
fault = do_exception(regs, VM_WRITE); if (unlikely(MACHINE_HAS_NX && (trans_exc_code & 0x80))) {
regs->int_parm_long = (trans_exc_code & ~PAGE_MASK) |
(regs->psw.addr & PAGE_MASK);
access = VM_EXEC;
fault = VM_FAULT_BADACCESS;
} else {
access = VM_WRITE;
fault = do_exception(regs, access);
}
if (unlikely(fault)) if (unlikely(fault))
do_fault_error(regs, fault); do_fault_error(regs, access, fault);
} }
NOKPROBE_SYMBOL(do_protection_exception); NOKPROBE_SYMBOL(do_protection_exception);
...@@ -557,7 +587,7 @@ void do_dat_exception(struct pt_regs *regs) ...@@ -557,7 +587,7 @@ void do_dat_exception(struct pt_regs *regs)
access = VM_READ | VM_EXEC | VM_WRITE; access = VM_READ | VM_EXEC | VM_WRITE;
fault = do_exception(regs, access); fault = do_exception(regs, access);
if (unlikely(fault)) if (unlikely(fault))
do_fault_error(regs, fault); do_fault_error(regs, access, fault);
} }
NOKPROBE_SYMBOL(do_dat_exception); NOKPROBE_SYMBOL(do_dat_exception);
......
...@@ -59,6 +59,8 @@ static inline unsigned long __pte_to_rste(pte_t pte) ...@@ -59,6 +59,8 @@ static inline unsigned long __pte_to_rste(pte_t pte)
rste |= move_set_bit(pte_val(pte), _PAGE_SOFT_DIRTY, rste |= move_set_bit(pte_val(pte), _PAGE_SOFT_DIRTY,
_SEGMENT_ENTRY_SOFT_DIRTY); _SEGMENT_ENTRY_SOFT_DIRTY);
#endif #endif
rste |= move_set_bit(pte_val(pte), _PAGE_NOEXEC,
_SEGMENT_ENTRY_NOEXEC);
} else } else
rste = _SEGMENT_ENTRY_INVALID; rste = _SEGMENT_ENTRY_INVALID;
return rste; return rste;
...@@ -113,6 +115,8 @@ static inline pte_t __rste_to_pte(unsigned long rste) ...@@ -113,6 +115,8 @@ static inline pte_t __rste_to_pte(unsigned long rste)
pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_SOFT_DIRTY, pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_SOFT_DIRTY,
_PAGE_DIRTY); _PAGE_DIRTY);
#endif #endif
pte_val(pte) |= move_set_bit(rste, _SEGMENT_ENTRY_NOEXEC,
_PAGE_NOEXEC);
} else } else
pte_val(pte) = _PAGE_INVALID; pte_val(pte) = _PAGE_INVALID;
return pte; return pte;
...@@ -121,7 +125,11 @@ static inline pte_t __rste_to_pte(unsigned long rste) ...@@ -121,7 +125,11 @@ static inline pte_t __rste_to_pte(unsigned long rste)
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte) pte_t *ptep, pte_t pte)
{ {
unsigned long rste = __pte_to_rste(pte); unsigned long rste;
rste = __pte_to_rste(pte);
if (!MACHINE_HAS_NX)
rste &= ~_SEGMENT_ENTRY_NOEXEC;
/* Set correct table type for 2G hugepages */ /* Set correct table type for 2G hugepages */
if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
......
...@@ -137,6 +137,9 @@ void __init mem_init(void) ...@@ -137,6 +137,9 @@ void __init mem_init(void)
void free_initmem(void) void free_initmem(void)
{ {
__set_memory((unsigned long) _sinittext,
(_einittext - _sinittext) >> PAGE_SHIFT,
SET_MEMORY_RW | SET_MEMORY_NX);
free_initmem_default(POISON_FREE_INITMEM); free_initmem_default(POISON_FREE_INITMEM);
} }
...@@ -148,6 +151,15 @@ void __init free_initrd_mem(unsigned long start, unsigned long end) ...@@ -148,6 +151,15 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
} }
#endif #endif
unsigned long memory_block_size_bytes(void)
{
/*
* Make sure the memory block size is always greater
* or equal than the memory increment size.
*/
return max_t(unsigned long, MIN_MEMORY_BLOCK_SIZE, sclp.rzm);
}
#ifdef CONFIG_MEMORY_HOTPLUG #ifdef CONFIG_MEMORY_HOTPLUG
int arch_add_memory(int nid, u64 start, u64 size, bool for_device) int arch_add_memory(int nid, u64 start, u64 size, bool for_device)
{ {
...@@ -191,15 +203,6 @@ int arch_add_memory(int nid, u64 start, u64 size, bool for_device) ...@@ -191,15 +203,6 @@ int arch_add_memory(int nid, u64 start, u64 size, bool for_device)
return rc; return rc;
} }
unsigned long memory_block_size_bytes(void)
{
/*
* Make sure the memory block size is always greater
* or equal than the memory increment size.
*/
return max_t(unsigned long, MIN_MEMORY_BLOCK_SIZE, sclp.rzm);
}
#ifdef CONFIG_MEMORY_HOTREMOVE #ifdef CONFIG_MEMORY_HOTREMOVE
int arch_remove_memory(u64 start, u64 size) int arch_remove_memory(u64 start, u64 size)
{ {
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
...@@ -19,6 +18,8 @@ ...@@ -19,6 +18,8 @@
static inline void memblock_physmem_add(phys_addr_t start, phys_addr_t size) static inline void memblock_physmem_add(phys_addr_t start, phys_addr_t size)
{ {
memblock_dbg("memblock_physmem_add: [%#016llx-%#016llx]\n",
start, start + size - 1);
memblock_add_range(&memblock.memory, start, size, 0, 0); memblock_add_range(&memblock.memory, start, size, 0, 0);
memblock_add_range(&memblock.physmem, start, size, 0, 0); memblock_add_range(&memblock.physmem, start, size, 0, 0);
} }
...@@ -39,7 +40,8 @@ void __init detect_memory_memblock(void) ...@@ -39,7 +40,8 @@ void __init detect_memory_memblock(void)
memblock_set_bottom_up(true); memblock_set_bottom_up(true);
do { do {
size = 0; size = 0;
type = tprot(addr); /* assume lowcore is writable */
type = addr ? tprot(addr) : CHUNK_READ_WRITE;
do { do {
size += rzm; size += rzm;
if (max_physmem_end && addr + size >= max_physmem_end) if (max_physmem_end && addr + size >= max_physmem_end)
...@@ -55,4 +57,5 @@ void __init detect_memory_memblock(void) ...@@ -55,4 +57,5 @@ void __init detect_memory_memblock(void)
memblock_set_bottom_up(false); memblock_set_bottom_up(false);
if (!max_physmem_end) if (!max_physmem_end)
max_physmem_end = memblock_end_of_DRAM(); max_physmem_end = memblock_end_of_DRAM();
memblock_dump_all();
} }
...@@ -26,11 +26,11 @@ ...@@ -26,11 +26,11 @@
#include <linux/personality.h> #include <linux/personality.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/module.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/security.h> #include <linux/security.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/elf.h>
static unsigned long stack_maxrandom_size(void) static unsigned long stack_maxrandom_size(void)
{ {
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
* Author(s): Jan Glauber <jang@linux.vnet.ibm.com> * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
*/ */
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/module.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/facility.h> #include <asm/facility.h>
...@@ -81,24 +80,24 @@ static void pgt_set(unsigned long *old, unsigned long new, unsigned long addr, ...@@ -81,24 +80,24 @@ static void pgt_set(unsigned long *old, unsigned long new, unsigned long addr,
} }
} }
struct cpa {
unsigned int set_ro : 1;
unsigned int clear_ro : 1;
};
static int walk_pte_level(pmd_t *pmdp, unsigned long addr, unsigned long end, static int walk_pte_level(pmd_t *pmdp, unsigned long addr, unsigned long end,
struct cpa cpa) unsigned long flags)
{ {
pte_t *ptep, new; pte_t *ptep, new;
ptep = pte_offset(pmdp, addr); ptep = pte_offset(pmdp, addr);
do { do {
if (pte_none(*ptep)) new = *ptep;
if (pte_none(new))
return -EINVAL; return -EINVAL;
if (cpa.set_ro) if (flags & SET_MEMORY_RO)
new = pte_wrprotect(*ptep); new = pte_wrprotect(new);
else if (cpa.clear_ro) else if (flags & SET_MEMORY_RW)
new = pte_mkwrite(pte_mkdirty(*ptep)); new = pte_mkwrite(pte_mkdirty(new));
if ((flags & SET_MEMORY_NX) && MACHINE_HAS_NX)
pte_val(new) |= _PAGE_NOEXEC;
else if (flags & SET_MEMORY_X)
pte_val(new) &= ~_PAGE_NOEXEC;
pgt_set((unsigned long *)ptep, pte_val(new), addr, CRDTE_DTT_PAGE); pgt_set((unsigned long *)ptep, pte_val(new), addr, CRDTE_DTT_PAGE);
ptep++; ptep++;
addr += PAGE_SIZE; addr += PAGE_SIZE;
...@@ -112,14 +111,17 @@ static int split_pmd_page(pmd_t *pmdp, unsigned long addr) ...@@ -112,14 +111,17 @@ static int split_pmd_page(pmd_t *pmdp, unsigned long addr)
unsigned long pte_addr, prot; unsigned long pte_addr, prot;
pte_t *pt_dir, *ptep; pte_t *pt_dir, *ptep;
pmd_t new; pmd_t new;
int i, ro; int i, ro, nx;
pt_dir = vmem_pte_alloc(); pt_dir = vmem_pte_alloc();
if (!pt_dir) if (!pt_dir)
return -ENOMEM; return -ENOMEM;
pte_addr = pmd_pfn(*pmdp) << PAGE_SHIFT; pte_addr = pmd_pfn(*pmdp) << PAGE_SHIFT;
ro = !!(pmd_val(*pmdp) & _SEGMENT_ENTRY_PROTECT); ro = !!(pmd_val(*pmdp) & _SEGMENT_ENTRY_PROTECT);
nx = !!(pmd_val(*pmdp) & _SEGMENT_ENTRY_NOEXEC);
prot = pgprot_val(ro ? PAGE_KERNEL_RO : PAGE_KERNEL); prot = pgprot_val(ro ? PAGE_KERNEL_RO : PAGE_KERNEL);
if (!nx)
prot &= ~_PAGE_NOEXEC;
ptep = pt_dir; ptep = pt_dir;
for (i = 0; i < PTRS_PER_PTE; i++) { for (i = 0; i < PTRS_PER_PTE; i++) {
pte_val(*ptep) = pte_addr | prot; pte_val(*ptep) = pte_addr | prot;
...@@ -133,19 +135,24 @@ static int split_pmd_page(pmd_t *pmdp, unsigned long addr) ...@@ -133,19 +135,24 @@ static int split_pmd_page(pmd_t *pmdp, unsigned long addr)
return 0; return 0;
} }
static void modify_pmd_page(pmd_t *pmdp, unsigned long addr, struct cpa cpa) static void modify_pmd_page(pmd_t *pmdp, unsigned long addr,
unsigned long flags)
{ {
pmd_t new; pmd_t new = *pmdp;
if (cpa.set_ro) if (flags & SET_MEMORY_RO)
new = pmd_wrprotect(*pmdp); new = pmd_wrprotect(new);
else if (cpa.clear_ro) else if (flags & SET_MEMORY_RW)
new = pmd_mkwrite(pmd_mkdirty(*pmdp)); new = pmd_mkwrite(pmd_mkdirty(new));
if ((flags & SET_MEMORY_NX) && MACHINE_HAS_NX)
pmd_val(new) |= _SEGMENT_ENTRY_NOEXEC;
else if (flags & SET_MEMORY_X)
pmd_val(new) &= ~_SEGMENT_ENTRY_NOEXEC;
pgt_set((unsigned long *)pmdp, pmd_val(new), addr, CRDTE_DTT_SEGMENT); pgt_set((unsigned long *)pmdp, pmd_val(new), addr, CRDTE_DTT_SEGMENT);
} }
static int walk_pmd_level(pud_t *pudp, unsigned long addr, unsigned long end, static int walk_pmd_level(pud_t *pudp, unsigned long addr, unsigned long end,
struct cpa cpa) unsigned long flags)
{ {
unsigned long next; unsigned long next;
pmd_t *pmdp; pmd_t *pmdp;
...@@ -163,9 +170,9 @@ static int walk_pmd_level(pud_t *pudp, unsigned long addr, unsigned long end, ...@@ -163,9 +170,9 @@ static int walk_pmd_level(pud_t *pudp, unsigned long addr, unsigned long end,
return rc; return rc;
continue; continue;
} }
modify_pmd_page(pmdp, addr, cpa); modify_pmd_page(pmdp, addr, flags);
} else { } else {
rc = walk_pte_level(pmdp, addr, next, cpa); rc = walk_pte_level(pmdp, addr, next, flags);
if (rc) if (rc)
return rc; return rc;
} }
...@@ -181,14 +188,17 @@ static int split_pud_page(pud_t *pudp, unsigned long addr) ...@@ -181,14 +188,17 @@ static int split_pud_page(pud_t *pudp, unsigned long addr)
unsigned long pmd_addr, prot; unsigned long pmd_addr, prot;
pmd_t *pm_dir, *pmdp; pmd_t *pm_dir, *pmdp;
pud_t new; pud_t new;
int i, ro; int i, ro, nx;
pm_dir = vmem_pmd_alloc(); pm_dir = vmem_pmd_alloc();
if (!pm_dir) if (!pm_dir)
return -ENOMEM; return -ENOMEM;
pmd_addr = pud_pfn(*pudp) << PAGE_SHIFT; pmd_addr = pud_pfn(*pudp) << PAGE_SHIFT;
ro = !!(pud_val(*pudp) & _REGION_ENTRY_PROTECT); ro = !!(pud_val(*pudp) & _REGION_ENTRY_PROTECT);
nx = !!(pud_val(*pudp) & _REGION_ENTRY_NOEXEC);
prot = pgprot_val(ro ? SEGMENT_KERNEL_RO : SEGMENT_KERNEL); prot = pgprot_val(ro ? SEGMENT_KERNEL_RO : SEGMENT_KERNEL);
if (!nx)
prot &= ~_SEGMENT_ENTRY_NOEXEC;
pmdp = pm_dir; pmdp = pm_dir;
for (i = 0; i < PTRS_PER_PMD; i++) { for (i = 0; i < PTRS_PER_PMD; i++) {
pmd_val(*pmdp) = pmd_addr | prot; pmd_val(*pmdp) = pmd_addr | prot;
...@@ -202,19 +212,24 @@ static int split_pud_page(pud_t *pudp, unsigned long addr) ...@@ -202,19 +212,24 @@ static int split_pud_page(pud_t *pudp, unsigned long addr)
return 0; return 0;
} }
static void modify_pud_page(pud_t *pudp, unsigned long addr, struct cpa cpa) static void modify_pud_page(pud_t *pudp, unsigned long addr,
unsigned long flags)
{ {
pud_t new; pud_t new = *pudp;
if (cpa.set_ro) if (flags & SET_MEMORY_RO)
new = pud_wrprotect(*pudp); new = pud_wrprotect(new);
else if (cpa.clear_ro) else if (flags & SET_MEMORY_RW)
new = pud_mkwrite(pud_mkdirty(*pudp)); new = pud_mkwrite(pud_mkdirty(new));
if ((flags & SET_MEMORY_NX) && MACHINE_HAS_NX)
pud_val(new) |= _REGION_ENTRY_NOEXEC;
else if (flags & SET_MEMORY_X)
pud_val(new) &= ~_REGION_ENTRY_NOEXEC;
pgt_set((unsigned long *)pudp, pud_val(new), addr, CRDTE_DTT_REGION3); pgt_set((unsigned long *)pudp, pud_val(new), addr, CRDTE_DTT_REGION3);
} }
static int walk_pud_level(pgd_t *pgd, unsigned long addr, unsigned long end, static int walk_pud_level(pgd_t *pgd, unsigned long addr, unsigned long end,
struct cpa cpa) unsigned long flags)
{ {
unsigned long next; unsigned long next;
pud_t *pudp; pud_t *pudp;
...@@ -232,9 +247,9 @@ static int walk_pud_level(pgd_t *pgd, unsigned long addr, unsigned long end, ...@@ -232,9 +247,9 @@ static int walk_pud_level(pgd_t *pgd, unsigned long addr, unsigned long end,
break; break;
continue; continue;
} }
modify_pud_page(pudp, addr, cpa); modify_pud_page(pudp, addr, flags);
} else { } else {
rc = walk_pmd_level(pudp, addr, next, cpa); rc = walk_pmd_level(pudp, addr, next, flags);
} }
pudp++; pudp++;
addr = next; addr = next;
...@@ -246,7 +261,7 @@ static int walk_pud_level(pgd_t *pgd, unsigned long addr, unsigned long end, ...@@ -246,7 +261,7 @@ static int walk_pud_level(pgd_t *pgd, unsigned long addr, unsigned long end,
static DEFINE_MUTEX(cpa_mutex); static DEFINE_MUTEX(cpa_mutex);
static int change_page_attr(unsigned long addr, unsigned long end, static int change_page_attr(unsigned long addr, unsigned long end,
struct cpa cpa) unsigned long flags)
{ {
unsigned long next; unsigned long next;
int rc = -EINVAL; int rc = -EINVAL;
...@@ -262,7 +277,7 @@ static int change_page_attr(unsigned long addr, unsigned long end, ...@@ -262,7 +277,7 @@ static int change_page_attr(unsigned long addr, unsigned long end,
if (pgd_none(*pgdp)) if (pgd_none(*pgdp))
break; break;
next = pgd_addr_end(addr, end); next = pgd_addr_end(addr, end);
rc = walk_pud_level(pgdp, addr, next, cpa); rc = walk_pud_level(pgdp, addr, next, flags);
if (rc) if (rc)
break; break;
cond_resched(); cond_resched();
...@@ -271,35 +286,10 @@ static int change_page_attr(unsigned long addr, unsigned long end, ...@@ -271,35 +286,10 @@ static int change_page_attr(unsigned long addr, unsigned long end,
return rc; return rc;
} }
int set_memory_ro(unsigned long addr, int numpages) int __set_memory(unsigned long addr, int numpages, unsigned long flags)
{ {
struct cpa cpa = {
.set_ro = 1,
};
addr &= PAGE_MASK; addr &= PAGE_MASK;
return change_page_attr(addr, addr + numpages * PAGE_SIZE, cpa); return change_page_attr(addr, addr + numpages * PAGE_SIZE, flags);
}
int set_memory_rw(unsigned long addr, int numpages)
{
struct cpa cpa = {
.clear_ro = 1,
};
addr &= PAGE_MASK;
return change_page_attr(addr, addr + numpages * PAGE_SIZE, cpa);
}
/* not possible */
int set_memory_nx(unsigned long addr, int numpages)
{
return 0;
}
int set_memory_x(unsigned long addr, int numpages)
{
return 0;
} }
#ifdef CONFIG_DEBUG_PAGEALLOC #ifdef CONFIG_DEBUG_PAGEALLOC
...@@ -339,7 +329,7 @@ void __kernel_map_pages(struct page *page, int numpages, int enable) ...@@ -339,7 +329,7 @@ void __kernel_map_pages(struct page *page, int numpages, int enable)
nr = min(numpages - i, nr); nr = min(numpages - i, nr);
if (enable) { if (enable) {
for (j = 0; j < nr; j++) { for (j = 0; j < nr; j++) {
pte_val(*pte) = address | pgprot_val(PAGE_KERNEL); pte_val(*pte) &= ~_PAGE_INVALID;
address += PAGE_SIZE; address += PAGE_SIZE;
pte++; pte++;
} }
......
...@@ -275,6 +275,8 @@ void ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, ...@@ -275,6 +275,8 @@ void ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
{ {
pgste_t pgste; pgste_t pgste;
if (!MACHINE_HAS_NX)
pte_val(pte) &= ~_PAGE_NOEXEC;
if (mm_has_pgste(mm)) { if (mm_has_pgste(mm)) {
pgste = pgste_get(ptep); pgste = pgste_get(ptep);
pgste_set_key(ptep, pgste, pte, mm); pgste_set_key(ptep, pgste, pte, mm);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/pfn.h> #include <linux/pfn.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/init.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -79,6 +79,7 @@ pte_t __ref *vmem_pte_alloc(void) ...@@ -79,6 +79,7 @@ pte_t __ref *vmem_pte_alloc(void)
*/ */
static int vmem_add_mem(unsigned long start, unsigned long size) static int vmem_add_mem(unsigned long start, unsigned long size)
{ {
unsigned long pgt_prot, sgt_prot, r3_prot;
unsigned long pages4k, pages1m, pages2g; unsigned long pages4k, pages1m, pages2g;
unsigned long end = start + size; unsigned long end = start + size;
unsigned long address = start; unsigned long address = start;
...@@ -88,6 +89,14 @@ static int vmem_add_mem(unsigned long start, unsigned long size) ...@@ -88,6 +89,14 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
pte_t *pt_dir; pte_t *pt_dir;
int ret = -ENOMEM; int ret = -ENOMEM;
pgt_prot = pgprot_val(PAGE_KERNEL);
sgt_prot = pgprot_val(SEGMENT_KERNEL);
r3_prot = pgprot_val(REGION3_KERNEL);
if (!MACHINE_HAS_NX) {
pgt_prot &= ~_PAGE_NOEXEC;
sgt_prot &= ~_SEGMENT_ENTRY_NOEXEC;
r3_prot &= ~_REGION_ENTRY_NOEXEC;
}
pages4k = pages1m = pages2g = 0; pages4k = pages1m = pages2g = 0;
while (address < end) { while (address < end) {
pg_dir = pgd_offset_k(address); pg_dir = pgd_offset_k(address);
...@@ -101,7 +110,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size) ...@@ -101,7 +110,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
if (MACHINE_HAS_EDAT2 && pud_none(*pu_dir) && address && if (MACHINE_HAS_EDAT2 && pud_none(*pu_dir) && address &&
!(address & ~PUD_MASK) && (address + PUD_SIZE <= end) && !(address & ~PUD_MASK) && (address + PUD_SIZE <= end) &&
!debug_pagealloc_enabled()) { !debug_pagealloc_enabled()) {
pud_val(*pu_dir) = address | pgprot_val(REGION3_KERNEL); pud_val(*pu_dir) = address | r3_prot;
address += PUD_SIZE; address += PUD_SIZE;
pages2g++; pages2g++;
continue; continue;
...@@ -116,7 +125,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size) ...@@ -116,7 +125,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address && if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address &&
!(address & ~PMD_MASK) && (address + PMD_SIZE <= end) && !(address & ~PMD_MASK) && (address + PMD_SIZE <= end) &&
!debug_pagealloc_enabled()) { !debug_pagealloc_enabled()) {
pmd_val(*pm_dir) = address | pgprot_val(SEGMENT_KERNEL); pmd_val(*pm_dir) = address | sgt_prot;
address += PMD_SIZE; address += PMD_SIZE;
pages1m++; pages1m++;
continue; continue;
...@@ -129,7 +138,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size) ...@@ -129,7 +138,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size)
} }
pt_dir = pte_offset_kernel(pm_dir, address); pt_dir = pte_offset_kernel(pm_dir, address);
pte_val(*pt_dir) = address | pgprot_val(PAGE_KERNEL); pte_val(*pt_dir) = address | pgt_prot;
address += PAGE_SIZE; address += PAGE_SIZE;
pages4k++; pages4k++;
} }
...@@ -200,6 +209,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size) ...@@ -200,6 +209,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
*/ */
int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
{ {
unsigned long pgt_prot, sgt_prot;
unsigned long address = start; unsigned long address = start;
pgd_t *pg_dir; pgd_t *pg_dir;
pud_t *pu_dir; pud_t *pu_dir;
...@@ -207,6 +217,12 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) ...@@ -207,6 +217,12 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
pte_t *pt_dir; pte_t *pt_dir;
int ret = -ENOMEM; int ret = -ENOMEM;
pgt_prot = pgprot_val(PAGE_KERNEL);
sgt_prot = pgprot_val(SEGMENT_KERNEL);
if (!MACHINE_HAS_NX) {
pgt_prot &= ~_PAGE_NOEXEC;
sgt_prot &= ~_SEGMENT_ENTRY_NOEXEC;
}
for (address = start; address < end;) { for (address = start; address < end;) {
pg_dir = pgd_offset_k(address); pg_dir = pgd_offset_k(address);
if (pgd_none(*pg_dir)) { if (pgd_none(*pg_dir)) {
...@@ -238,8 +254,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) ...@@ -238,8 +254,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
new_page = vmemmap_alloc_block(PMD_SIZE, node); new_page = vmemmap_alloc_block(PMD_SIZE, node);
if (!new_page) if (!new_page)
goto out; goto out;
pmd_val(*pm_dir) = __pa(new_page) | pmd_val(*pm_dir) = __pa(new_page) | sgt_prot;
_SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE;
address = (address + PMD_SIZE) & PMD_MASK; address = (address + PMD_SIZE) & PMD_MASK;
continue; continue;
} }
...@@ -259,8 +274,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) ...@@ -259,8 +274,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
new_page = vmemmap_alloc_block(PAGE_SIZE, node); new_page = vmemmap_alloc_block(PAGE_SIZE, node);
if (!new_page) if (!new_page)
goto out; goto out;
pte_val(*pt_dir) = pte_val(*pt_dir) = __pa(new_page) | pgt_prot;
__pa(new_page) | pgprot_val(PAGE_KERNEL);
} }
address += PAGE_SIZE; address += PAGE_SIZE;
} }
...@@ -372,13 +386,21 @@ int vmem_add_mapping(unsigned long start, unsigned long size) ...@@ -372,13 +386,21 @@ int vmem_add_mapping(unsigned long start, unsigned long size)
*/ */
void __init vmem_map_init(void) void __init vmem_map_init(void)
{ {
unsigned long size = _eshared - _stext;
struct memblock_region *reg; struct memblock_region *reg;
for_each_memblock(memory, reg) for_each_memblock(memory, reg)
vmem_add_mem(reg->base, reg->size); vmem_add_mem(reg->base, reg->size);
set_memory_ro((unsigned long)_stext, size >> PAGE_SHIFT); __set_memory((unsigned long) _stext,
pr_info("Write protected kernel read-only data: %luk\n", size >> 10); (_etext - _stext) >> PAGE_SHIFT,
SET_MEMORY_RO | SET_MEMORY_X);
__set_memory((unsigned long) _etext,
(_eshared - _etext) >> PAGE_SHIFT,
SET_MEMORY_RO);
__set_memory((unsigned long) _sinittext,
(_einittext - _sinittext) >> PAGE_SHIFT,
SET_MEMORY_RO | SET_MEMORY_X);
pr_info("Write protected kernel read-only data: %luk\n",
(_eshared - _stext) >> 10);
} }
/* /*
......
...@@ -1323,14 +1323,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) ...@@ -1323,14 +1323,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
} }
if (bpf_jit_enable > 1) { if (bpf_jit_enable > 1) {
bpf_jit_dump(fp->len, jit.size, pass, jit.prg_buf); bpf_jit_dump(fp->len, jit.size, pass, jit.prg_buf);
if (jit.prg_buf) print_fn_code(jit.prg_buf, jit.size_prg);
print_fn_code(jit.prg_buf, jit.size_prg);
}
if (jit.prg_buf) {
bpf_jit_binary_lock_ro(header);
fp->bpf_func = (void *) jit.prg_buf;
fp->jited = 1;
} }
bpf_jit_binary_lock_ro(header);
fp->bpf_func = (void *) jit.prg_buf;
fp->jited = 1;
free_addrs: free_addrs:
kfree(jit.addrs); kfree(jit.addrs);
out: out:
......
...@@ -224,8 +224,8 @@ static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len) ...@@ -224,8 +224,8 @@ static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
rc = zpci_load(&data, req, offset); rc = zpci_load(&data, req, offset);
if (!rc) { if (!rc) {
data = data << ((8 - len) * 8); data = le64_to_cpu((__force __le64) data);
data = le64_to_cpu(data); data >>= (8 - len) * 8;
*val = (u32) data; *val = (u32) data;
} else } else
*val = 0xffffffff; *val = 0xffffffff;
...@@ -238,8 +238,8 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len) ...@@ -238,8 +238,8 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)
u64 data = val; u64 data = val;
int rc; int rc;
data = cpu_to_le64(data); data <<= (8 - len) * 8;
data = data >> ((8 - len) * 8); data = (__force u64) cpu_to_le64(data);
rc = zpci_store(data, req, offset); rc = zpci_store(data, req, offset);
return rc; return rc;
} }
......
...@@ -1712,8 +1712,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, ...@@ -1712,8 +1712,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
/* check for for attention message */ /* check for for attention message */
if (scsw_dstat(&irb->scsw) & DEV_STAT_ATTENTION) { if (scsw_dstat(&irb->scsw) & DEV_STAT_ATTENTION) {
device = dasd_device_from_cdev_locked(cdev); device = dasd_device_from_cdev_locked(cdev);
device->discipline->check_attention(device, irb->esw.esw1.lpum); if (!IS_ERR(device)) {
dasd_put_device(device); device->discipline->check_attention(device,
irb->esw.esw1.lpum);
dasd_put_device(device);
}
} }
if (!cqr) if (!cqr)
...@@ -3598,10 +3601,11 @@ int dasd_generic_set_offline(struct ccw_device *cdev) ...@@ -3598,10 +3601,11 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
* empty * empty
*/ */
/* sync blockdev and partitions */ /* sync blockdev and partitions */
rc = fsync_bdev(device->block->bdev); if (device->block) {
if (rc != 0) rc = fsync_bdev(device->block->bdev);
goto interrupted; if (rc != 0)
goto interrupted;
}
/* schedule device tasklet and wait for completion */ /* schedule device tasklet and wait for completion */
dasd_schedule_device_bh(device); dasd_schedule_device_bh(device);
rc = wait_event_interruptible(shutdown_waitq, rc = wait_event_interruptible(shutdown_waitq,
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
/* This is ugly... */ /* This is ugly... */
#define PRINTK_HEADER "dasd_devmap:" #define PRINTK_HEADER "dasd_devmap:"
#define DASD_BUS_ID_SIZE 20 #define DASD_BUS_ID_SIZE 20
#define DASD_MAX_PARAMS 256
#include "dasd_int.h" #include "dasd_int.h"
...@@ -76,7 +77,7 @@ EXPORT_SYMBOL_GPL(dasd_nofcx); ...@@ -76,7 +77,7 @@ EXPORT_SYMBOL_GPL(dasd_nofcx);
* it is named 'dasd' to directly be filled by insmod with the comma separated * it is named 'dasd' to directly be filled by insmod with the comma separated
* strings when running as a module. * strings when running as a module.
*/ */
static char *dasd[256]; static char *dasd[DASD_MAX_PARAMS];
module_param_array(dasd, charp, NULL, S_IRUGO); module_param_array(dasd, charp, NULL, S_IRUGO);
/* /*
...@@ -104,18 +105,19 @@ dasd_hash_busid(const char *bus_id) ...@@ -104,18 +105,19 @@ dasd_hash_busid(const char *bus_id)
} }
#ifndef MODULE #ifndef MODULE
/* static int __init dasd_call_setup(char *opt)
* The parameter parsing functions for builtin-drivers are called
* before kmalloc works. Store the pointers to the parameters strings
* into dasd[] for later processing.
*/
static int __init
dasd_call_setup(char *str)
{ {
static int count = 0; static int i __initdata;
char *tmp;
while (i < DASD_MAX_PARAMS) {
tmp = strsep(&opt, ",");
if (!tmp)
break;
dasd[i++] = tmp;
}
if (count < 256)
dasd[count++] = str;
return 1; return 1;
} }
...@@ -127,14 +129,13 @@ __setup ("dasd=", dasd_call_setup); ...@@ -127,14 +129,13 @@ __setup ("dasd=", dasd_call_setup);
/* /*
* Read a device busid/devno from a string. * Read a device busid/devno from a string.
*/ */
static int static int __init dasd_busid(char *str, int *id0, int *id1, int *devno)
dasd_busid(char **str, int *id0, int *id1, int *devno)
{ {
int val, old_style; unsigned int val;
char *tok;
/* Interpret ipldev busid */ /* Interpret ipldev busid */
if (strncmp(DASD_IPLDEV, *str, strlen(DASD_IPLDEV)) == 0) { if (strncmp(DASD_IPLDEV, str, strlen(DASD_IPLDEV)) == 0) {
if (ipl_info.type != IPL_TYPE_CCW) { if (ipl_info.type != IPL_TYPE_CCW) {
pr_err("The IPL device is not a CCW device\n"); pr_err("The IPL device is not a CCW device\n");
return -EINVAL; return -EINVAL;
...@@ -142,63 +143,50 @@ dasd_busid(char **str, int *id0, int *id1, int *devno) ...@@ -142,63 +143,50 @@ dasd_busid(char **str, int *id0, int *id1, int *devno)
*id0 = 0; *id0 = 0;
*id1 = ipl_info.data.ccw.dev_id.ssid; *id1 = ipl_info.data.ccw.dev_id.ssid;
*devno = ipl_info.data.ccw.dev_id.devno; *devno = ipl_info.data.ccw.dev_id.devno;
*str += strlen(DASD_IPLDEV);
return 0; return 0;
} }
/* check for leading '0x' */
old_style = 0; /* Old style 0xXXXX or XXXX */
if ((*str)[0] == '0' && (*str)[1] == 'x') { if (!kstrtouint(str, 16, &val)) {
*str += 2;
old_style = 1;
}
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
return -EINVAL;
val = simple_strtoul(*str, str, 16);
if (old_style || (*str)[0] != '.') {
*id0 = *id1 = 0; *id0 = *id1 = 0;
if (val < 0 || val > 0xffff) if (val < 0 || val > 0xffff)
return -EINVAL; return -EINVAL;
*devno = val; *devno = val;
return 0; return 0;
} }
/* New style x.y.z busid */ /* New style x.y.z busid */
if (val < 0 || val > 0xff) tok = strsep(&str, ".");
if (kstrtouint(tok, 16, &val) || val > 0xff)
return -EINVAL; return -EINVAL;
*id0 = val; *id0 = val;
(*str)++;
if (!isxdigit((*str)[0])) /* We require at least one hex digit */ tok = strsep(&str, ".");
return -EINVAL; if (kstrtouint(tok, 16, &val) || val > 0xff)
val = simple_strtoul(*str, str, 16);
if (val < 0 || val > 0xff || (*str)++[0] != '.')
return -EINVAL; return -EINVAL;
*id1 = val; *id1 = val;
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
return -EINVAL; tok = strsep(&str, ".");
val = simple_strtoul(*str, str, 16); if (kstrtouint(tok, 16, &val) || val > 0xffff)
if (val < 0 || val > 0xffff)
return -EINVAL; return -EINVAL;
*devno = val; *devno = val;
return 0; return 0;
} }
/* /*
* Read colon separated list of dasd features. Currently there is * Read colon separated list of dasd features.
* only one: "ro" for read-only devices. The default feature set
* is empty (value 0).
*/ */
static int static int __init dasd_feature_list(char *str)
dasd_feature_list(char *str, char **endp)
{ {
int features, len, rc; int features, len, rc;
features = 0;
rc = 0; rc = 0;
if (*str != '(') {
*endp = str; if (!str)
return DASD_FEATURE_DEFAULT; return DASD_FEATURE_DEFAULT;
}
str++;
features = 0;
while (1) { while (1) {
for (len = 0; for (len = 0;
...@@ -223,15 +211,8 @@ dasd_feature_list(char *str, char **endp) ...@@ -223,15 +211,8 @@ dasd_feature_list(char *str, char **endp)
break; break;
str++; str++;
} }
if (*str != ')') {
pr_warn("A closing parenthesis ')' is missing in the dasd= parameter\n"); return rc ? : features;
rc = -EINVAL;
} else
str++;
*endp = str;
if (rc != 0)
return rc;
return features;
} }
/* /*
...@@ -240,48 +221,38 @@ dasd_feature_list(char *str, char **endp) ...@@ -240,48 +221,38 @@ dasd_feature_list(char *str, char **endp)
* action and return a pointer to the residual string. If the first element * action and return a pointer to the residual string. If the first element
* could not be matched to any keyword then return an error code. * could not be matched to any keyword then return an error code.
*/ */
static char * static int __init dasd_parse_keyword(char *keyword)
dasd_parse_keyword( char *parsestring ) { {
int length = strlen(keyword);
char *nextcomma, *residual_str;
int length;
nextcomma = strchr(parsestring,','); if (strncmp("autodetect", keyword, length) == 0) {
if (nextcomma) {
length = nextcomma - parsestring;
residual_str = nextcomma + 1;
} else {
length = strlen(parsestring);
residual_str = parsestring + length;
}
if (strncmp("autodetect", parsestring, length) == 0) {
dasd_autodetect = 1; dasd_autodetect = 1;
pr_info("The autodetection mode has been activated\n"); pr_info("The autodetection mode has been activated\n");
return residual_str; return 0;
} }
if (strncmp("probeonly", parsestring, length) == 0) { if (strncmp("probeonly", keyword, length) == 0) {
dasd_probeonly = 1; dasd_probeonly = 1;
pr_info("The probeonly mode has been activated\n"); pr_info("The probeonly mode has been activated\n");
return residual_str; return 0;
} }
if (strncmp("nopav", parsestring, length) == 0) { if (strncmp("nopav", keyword, length) == 0) {
if (MACHINE_IS_VM) if (MACHINE_IS_VM)
pr_info("'nopav' is not supported on z/VM\n"); pr_info("'nopav' is not supported on z/VM\n");
else { else {
dasd_nopav = 1; dasd_nopav = 1;
pr_info("PAV support has be deactivated\n"); pr_info("PAV support has be deactivated\n");
} }
return residual_str; return 0;
} }
if (strncmp("nofcx", parsestring, length) == 0) { if (strncmp("nofcx", keyword, length) == 0) {
dasd_nofcx = 1; dasd_nofcx = 1;
pr_info("High Performance FICON support has been " pr_info("High Performance FICON support has been "
"deactivated\n"); "deactivated\n");
return residual_str; return 0;
} }
if (strncmp("fixedbuffers", parsestring, length) == 0) { if (strncmp("fixedbuffers", keyword, length) == 0) {
if (dasd_page_cache) if (dasd_page_cache)
return residual_str; return 0;
dasd_page_cache = dasd_page_cache =
kmem_cache_create("dasd_page_cache", PAGE_SIZE, kmem_cache_create("dasd_page_cache", PAGE_SIZE,
PAGE_SIZE, SLAB_CACHE_DMA, PAGE_SIZE, SLAB_CACHE_DMA,
...@@ -292,107 +263,126 @@ dasd_parse_keyword( char *parsestring ) { ...@@ -292,107 +263,126 @@ dasd_parse_keyword( char *parsestring ) {
else else
DBF_EVENT(DBF_INFO, "%s", DBF_EVENT(DBF_INFO, "%s",
"turning on fixed buffer mode"); "turning on fixed buffer mode");
return residual_str; return 0;
} }
return ERR_PTR(-EINVAL);
return -EINVAL;
} }
/* /*
* Try to interprete the first element on the comma separated parse string * Split a string of a device range into its pieces and return the from, to, and
* as a device number or a range of devices. If the interpretation is * feature parts separately.
* successful, create the matching dasd_devmap entries and return a pointer * e.g.:
* to the residual string. * 0.0.1234-0.0.5678(ro:erplog) -> from: 0.0.1234 to: 0.0.5678 features: ro:erplog
* If interpretation fails or in case of an error, return an error code. * 0.0.8765(raw) -> from: 0.0.8765 to: null features: raw
* 0x4321 -> from: 0x4321 to: null features: null
*/ */
static char * static int __init dasd_evaluate_range_param(char *range, char **from_str,
dasd_parse_range( char *parsestring ) { char **to_str, char **features_str)
{
int rc = 0;
/* Do we have a range or a single device? */
if (strchr(range, '-')) {
*from_str = strsep(&range, "-");
*to_str = strsep(&range, "(");
*features_str = strsep(&range, ")");
} else {
*from_str = strsep(&range, "(");
*features_str = strsep(&range, ")");
}
if (*features_str && !range) {
pr_warn("A closing parenthesis ')' is missing in the dasd= parameter\n");
rc = -EINVAL;
}
return rc;
}
/*
* Try to interprete the range string as a device number or a range of devices.
* If the interpretation is successful, create the matching dasd_devmap entries.
* If interpretation fails or in case of an error, return an error code.
*/
static int __init dasd_parse_range(const char *range)
{
struct dasd_devmap *devmap; struct dasd_devmap *devmap;
int from, from_id0, from_id1; int from, from_id0, from_id1;
int to, to_id0, to_id1; int to, to_id0, to_id1;
int features, rc; int features;
char bus_id[DASD_BUS_ID_SIZE+1], *str; char bus_id[DASD_BUS_ID_SIZE + 1];
char *features_str = NULL;
str = parsestring; char *from_str = NULL;
rc = dasd_busid(&str, &from_id0, &from_id1, &from); char *to_str = NULL;
if (rc == 0) { size_t len = strlen(range) + 1;
to = from; char tmp[len];
to_id0 = from_id0;
to_id1 = from_id1; strlcpy(tmp, range, len);
if (*str == '-') {
str++; if (dasd_evaluate_range_param(tmp, &from_str, &to_str, &features_str))
rc = dasd_busid(&str, &to_id0, &to_id1, &to); goto out_err;
if (dasd_busid(from_str, &from_id0, &from_id1, &from))
goto out_err;
to = from;
to_id0 = from_id0;
to_id1 = from_id1;
if (to_str) {
if (dasd_busid(to_str, &to_id0, &to_id1, &to))
goto out_err;
if (from_id0 != to_id0 || from_id1 != to_id1 || from > to) {
pr_err("%s is not a valid device range\n", range);
goto out_err;
} }
} }
if (rc == 0 &&
(from_id0 != to_id0 || from_id1 != to_id1 || from > to)) features = dasd_feature_list(features_str);
rc = -EINVAL;
if (rc) {
pr_err("%s is not a valid device range\n", parsestring);
return ERR_PTR(rc);
}
features = dasd_feature_list(str, &str);
if (features < 0) if (features < 0)
return ERR_PTR(-EINVAL); goto out_err;
/* each device in dasd= parameter should be set initially online */ /* each device in dasd= parameter should be set initially online */
features |= DASD_FEATURE_INITIAL_ONLINE; features |= DASD_FEATURE_INITIAL_ONLINE;
while (from <= to) { while (from <= to) {
sprintf(bus_id, "%01x.%01x.%04x", sprintf(bus_id, "%01x.%01x.%04x", from_id0, from_id1, from++);
from_id0, from_id1, from++);
devmap = dasd_add_busid(bus_id, features); devmap = dasd_add_busid(bus_id, features);
if (IS_ERR(devmap)) if (IS_ERR(devmap))
return (char *)devmap; return PTR_ERR(devmap);
} }
if (*str == ',')
return str + 1;
if (*str == '\0')
return str;
pr_warn("The dasd= parameter value %s has an invalid ending\n", str);
return ERR_PTR(-EINVAL);
}
static char * return 0;
dasd_parse_next_element( char *parsestring ) {
char * residual_str; out_err:
residual_str = dasd_parse_keyword(parsestring); return -EINVAL;
if (!IS_ERR(residual_str))
return residual_str;
residual_str = dasd_parse_range(parsestring);
return residual_str;
} }
/* /*
* Parse parameters stored in dasd[] * Parse parameters stored in dasd[]
* The 'dasd=...' parameter allows to specify a comma separated list of * The 'dasd=...' parameter allows to specify a comma separated list of
* keywords and device ranges. When the dasd driver is build into the kernel, * keywords and device ranges. The parameters in that list will be stored as
* the complete list will be stored as one element of the dasd[] array. * separate elementes in dasd[].
* When the dasd driver is build as a module, then the list is broken into
* it's elements and each dasd[] entry contains one element.
*/ */
int int __init dasd_parse(void)
dasd_parse(void)
{ {
int rc, i; int rc, i;
char *parsestring; char *cur;
rc = 0; rc = 0;
for (i = 0; i < 256; i++) { for (i = 0; i < DASD_MAX_PARAMS; i++) {
if (dasd[i] == NULL) cur = dasd[i];
if (!cur)
break; break;
parsestring = dasd[i]; if (*cur == '\0')
/* loop over the comma separated list in the parsestring */ continue;
while (*parsestring) {
parsestring = dasd_parse_next_element(parsestring); rc = dasd_parse_keyword(cur);
if(IS_ERR(parsestring)) { if (rc)
rc = PTR_ERR(parsestring); rc = dasd_parse_range(cur);
break;
} if (rc)
}
if (rc) {
DBF_EVENT(DBF_ALERT, "%s", "invalid range found");
break; break;
}
} }
return rc; return rc;
} }
...@@ -1528,14 +1518,12 @@ dasd_path_threshold_store(struct device *dev, struct device_attribute *attr, ...@@ -1528,14 +1518,12 @@ dasd_path_threshold_store(struct device *dev, struct device_attribute *attr,
if (IS_ERR(device)) if (IS_ERR(device))
return -ENODEV; return -ENODEV;
if ((kstrtoul(buf, 10, &val) != 0) || if (kstrtoul(buf, 10, &val) != 0 || val > DASD_THRHLD_MAX) {
(val > DASD_THRHLD_MAX) || val == 0) {
dasd_put_device(device); dasd_put_device(device);
return -EINVAL; return -EINVAL;
} }
spin_lock_irqsave(get_ccwdev_lock(to_ccwdev(dev)), flags); spin_lock_irqsave(get_ccwdev_lock(to_ccwdev(dev)), flags);
if (val) device->path_thrhld = val;
device->path_thrhld = val;
spin_unlock_irqrestore(get_ccwdev_lock(to_ccwdev(dev)), flags); spin_unlock_irqrestore(get_ccwdev_lock(to_ccwdev(dev)), flags);
dasd_put_device(device); dasd_put_device(device);
return count; return count;
......
...@@ -2543,8 +2543,8 @@ dasd_eckd_build_format(struct dasd_device *base, ...@@ -2543,8 +2543,8 @@ dasd_eckd_build_format(struct dasd_device *base,
DASD_ECKD_CCW_WRITE_CKD_MT; DASD_ECKD_CCW_WRITE_CKD_MT;
ccw->flags = CCW_FLAG_SLI; ccw->flags = CCW_FLAG_SLI;
ccw->count = 8; ccw->count = 8;
ccw->cda = (__u32)(addr_t) ect; ccw->cda = (__u32)(addr_t) ect;
ccw++; ccw++;
} }
} }
} }
......
...@@ -805,7 +805,7 @@ struct dasd_device *dasd_device_from_devindex(int); ...@@ -805,7 +805,7 @@ struct dasd_device *dasd_device_from_devindex(int);
void dasd_add_link_to_gendisk(struct gendisk *, struct dasd_device *); void dasd_add_link_to_gendisk(struct gendisk *, struct dasd_device *);
struct dasd_device *dasd_device_from_gendisk(struct gendisk *); struct dasd_device *dasd_device_from_gendisk(struct gendisk *);
int dasd_parse(void); int dasd_parse(void) __init;
int dasd_busid_known(const char *); int dasd_busid_known(const char *);
/* externals in dasd_gendisk.c */ /* externals in dasd_gendisk.c */
......
...@@ -892,7 +892,7 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum, ...@@ -892,7 +892,7 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
dev_info = bdev->bd_disk->private_data; dev_info = bdev->bd_disk->private_data;
if (!dev_info) if (!dev_info)
return -ENODEV; return -ENODEV;
dev_sz = dev_info->end - dev_info->start; dev_sz = dev_info->end - dev_info->start + 1;
offset = secnum * 512; offset = secnum * 512;
*kaddr = (void *) dev_info->start + offset; *kaddr = (void *) dev_info->start + offset;
*pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), PFN_DEV); *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), PFN_DEV);
......
...@@ -2,9 +2,23 @@ ...@@ -2,9 +2,23 @@
# S/390 character devices # S/390 character devices
# #
ifdef CONFIG_FUNCTION_TRACER
# Do not trace early setup code
CFLAGS_REMOVE_sclp_early_core.o = $(CC_FLAGS_FTRACE)
endif
GCOV_PROFILE_sclp_early_core.o := n
KCOV_INSTRUMENT_sclp_early_core.o := n
UBSAN_SANITIZE_sclp_early_core.o := n
ifneq ($(CC_FLAGS_MARCH),-march=z900)
CFLAGS_REMOVE_sclp_early_core.o += $(CC_FLAGS_MARCH)
CFLAGS_sclp_early_core.o += -march=z900
endif
obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \ sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \
sclp_early.o sclp_early.o sclp_early_core.o
obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270) += raw3270.o
obj-$(CONFIG_TN3270_CONSOLE) += con3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
static struct raw3270_fn con3270_fn; static struct raw3270_fn con3270_fn;
static bool auto_update = 1; static bool auto_update = true;
module_param(auto_update, bool, 0); module_param(auto_update, bool, 0);
/* /*
......
...@@ -82,7 +82,7 @@ static LIST_HEAD(raw3270_devices); ...@@ -82,7 +82,7 @@ static LIST_HEAD(raw3270_devices);
static int raw3270_registered; static int raw3270_registered;
/* Module parameters */ /* Module parameters */
static bool tubxcorrect = 0; static bool tubxcorrect;
module_param(tubxcorrect, bool, 0); module_param(tubxcorrect, bool, 0);
/* /*
......
...@@ -94,13 +94,6 @@ static struct timer_list sclp_request_timer; ...@@ -94,13 +94,6 @@ static struct timer_list sclp_request_timer;
/* Timer for queued requests. */ /* Timer for queued requests. */
static struct timer_list sclp_queue_timer; static struct timer_list sclp_queue_timer;
/* Internal state: is the driver initialized? */
static volatile enum sclp_init_state_t {
sclp_init_state_uninitialized,
sclp_init_state_initializing,
sclp_init_state_initialized
} sclp_init_state = sclp_init_state_uninitialized;
/* Internal state: is a request active at the sclp? */ /* Internal state: is a request active at the sclp? */
static volatile enum sclp_running_state_t { static volatile enum sclp_running_state_t {
sclp_running_state_idle, sclp_running_state_idle,
...@@ -147,31 +140,6 @@ static void __sclp_make_read_req(void); ...@@ -147,31 +140,6 @@ static void __sclp_make_read_req(void);
static int sclp_init_mask(int calculate); static int sclp_init_mask(int calculate);
static int sclp_init(void); static int sclp_init(void);
/* Perform service call. Return 0 on success, non-zero otherwise. */
int
sclp_service_call(sclp_cmdw_t command, void *sccb)
{
int cc = 4; /* Initialize for program check handling */
asm volatile(
"0: .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */
"1: ipm %0\n"
" srl %0,28\n"
"2:\n"
EX_TABLE(0b, 2b)
EX_TABLE(1b, 2b)
: "+&d" (cc) : "d" (command), "a" (__pa(sccb))
: "cc", "memory");
if (cc == 4)
return -EINVAL;
if (cc == 3)
return -EIO;
if (cc == 2)
return -EBUSY;
return 0;
}
static void static void
__sclp_queue_read_req(void) __sclp_queue_read_req(void)
{ {
......
...@@ -204,19 +204,57 @@ void sclp_unregister(struct sclp_register *reg); ...@@ -204,19 +204,57 @@ void sclp_unregister(struct sclp_register *reg);
int sclp_remove_processed(struct sccb_header *sccb); int sclp_remove_processed(struct sccb_header *sccb);
int sclp_deactivate(void); int sclp_deactivate(void);
int sclp_reactivate(void); int sclp_reactivate(void);
int sclp_service_call(sclp_cmdw_t command, void *sccb);
int sclp_sync_request(sclp_cmdw_t command, void *sccb); int sclp_sync_request(sclp_cmdw_t command, void *sccb);
int sclp_sync_request_timeout(sclp_cmdw_t command, void *sccb, int timeout); int sclp_sync_request_timeout(sclp_cmdw_t command, void *sccb, int timeout);
int sclp_sdias_init(void); int sclp_sdias_init(void);
void sclp_sdias_exit(void); void sclp_sdias_exit(void);
enum {
sclp_init_state_uninitialized,
sclp_init_state_initializing,
sclp_init_state_initialized
};
extern int sclp_init_state;
extern int sclp_console_pages; extern int sclp_console_pages;
extern int sclp_console_drop; extern int sclp_console_drop;
extern unsigned long sclp_console_full; extern unsigned long sclp_console_full;
extern char sclp_early_sccb[PAGE_SIZE];
void sclp_early_wait_irq(void);
int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb);
unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb);
int sclp_early_set_event_mask(struct init_sccb *sccb,
unsigned long receive_mask,
unsigned long send_mask);
/* useful inlines */ /* useful inlines */
/* Perform service call. Return 0 on success, non-zero otherwise. */
static inline int sclp_service_call(sclp_cmdw_t command, void *sccb)
{
int cc = 4; /* Initialize for program check handling */
asm volatile(
"0: .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */
"1: ipm %0\n"
" srl %0,28\n"
"2:\n"
EX_TABLE(0b, 2b)
EX_TABLE(1b, 2b)
: "+&d" (cc) : "d" (command), "a" ((unsigned long)sccb)
: "cc", "memory");
if (cc == 4)
return -EINVAL;
if (cc == 3)
return -EIO;
if (cc == 2)
return -EBUSY;
return 0;
}
/* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */ /* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */
/* translate single character from ASCII to EBCDIC */ /* translate single character from ASCII to EBCDIC */
static inline unsigned char static inline unsigned char
......
...@@ -55,46 +55,23 @@ struct read_info_sccb { ...@@ -55,46 +55,23 @@ struct read_info_sccb {
u8 _pad_128[4096 - 128]; /* 128-4095 */ u8 _pad_128[4096 - 128]; /* 128-4095 */
} __packed __aligned(PAGE_SIZE); } __packed __aligned(PAGE_SIZE);
static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata;
static struct sclp_ipl_info sclp_ipl_info; static struct sclp_ipl_info sclp_ipl_info;
struct sclp_info sclp; struct sclp_info sclp;
EXPORT_SYMBOL(sclp); EXPORT_SYMBOL(sclp);
static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb) static int __init sclp_early_read_info(struct read_info_sccb *sccb)
{ {
int rc; int i;
__ctl_set_bit(0, 9);
rc = sclp_service_call(cmd, sccb);
if (rc)
goto out;
__load_psw_mask(PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA |
PSW_MASK_BA | PSW_MASK_EXT | PSW_MASK_WAIT);
local_irq_disable();
out:
/* Contents of the sccb might have changed. */
barrier();
__ctl_clear_bit(0, 9);
return rc;
}
static int __init sclp_read_info_early(struct read_info_sccb *sccb)
{
int rc, i;
sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
SCLP_CMDW_READ_SCP_INFO}; SCLP_CMDW_READ_SCP_INFO};
for (i = 0; i < ARRAY_SIZE(commands); i++) { for (i = 0; i < ARRAY_SIZE(commands); i++) {
do { memset(sccb, 0, sizeof(*sccb));
memset(sccb, 0, sizeof(*sccb)); sccb->header.length = sizeof(*sccb);
sccb->header.length = sizeof(*sccb); sccb->header.function_code = 0x80;
sccb->header.function_code = 0x80; sccb->header.control_mask[2] = 0x80;
sccb->header.control_mask[2] = 0x80; if (sclp_early_cmd(commands[i], sccb))
rc = sclp_cmd_sync_early(commands[i], sccb);
} while (rc == -EBUSY);
if (rc)
break; break;
if (sccb->header.response_code == 0x10) if (sccb->header.response_code == 0x10)
return 0; return 0;
...@@ -104,12 +81,12 @@ static int __init sclp_read_info_early(struct read_info_sccb *sccb) ...@@ -104,12 +81,12 @@ static int __init sclp_read_info_early(struct read_info_sccb *sccb)
return -EIO; return -EIO;
} }
static void __init sclp_facilities_detect(struct read_info_sccb *sccb) static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
{ {
struct sclp_core_entry *cpue; struct sclp_core_entry *cpue;
u16 boot_cpu_address, cpu; u16 boot_cpu_address, cpu;
if (sclp_read_info_early(sccb)) if (sclp_early_read_info(sccb))
return; return;
sclp.facilities = sccb->facilities; sclp.facilities = sccb->facilities;
...@@ -172,141 +149,96 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb) ...@@ -172,141 +149,96 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
} }
/* /*
* This function will be called after sclp_facilities_detect(), which gets * This function will be called after sclp_early_facilities_detect(), which gets
* called from early.c code. The sclp_facilities_detect() function retrieves * called from early.c code. The sclp_early_facilities_detect() function retrieves
* and saves the IPL information. * and saves the IPL information.
*/ */
void __init sclp_get_ipl_info(struct sclp_ipl_info *info) void __init sclp_early_get_ipl_info(struct sclp_ipl_info *info)
{ {
*info = sclp_ipl_info; *info = sclp_ipl_info;
} }
static int __init sclp_cmd_early(sclp_cmdw_t cmd, void *sccb) static struct sclp_core_info sclp_early_core_info __initdata;
{ static int sclp_early_core_info_valid __initdata;
int rc;
do {
rc = sclp_cmd_sync_early(cmd, sccb);
} while (rc == -EBUSY);
if (rc)
return -EIO;
if (((struct sccb_header *) sccb)->response_code != 0x0020)
return -EIO;
return 0;
}
static void __init sccb_init_eq_size(struct sdias_sccb *sccb)
{
memset(sccb, 0, sizeof(*sccb));
sccb->hdr.length = sizeof(*sccb);
sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
sccb->evbuf.hdr.type = EVTYP_SDIAS;
sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
sccb->evbuf.event_id = 4712;
sccb->evbuf.dbs = 1;
}
static int __init sclp_set_event_mask(struct init_sccb *sccb, static void __init sclp_early_init_core_info(struct read_cpu_info_sccb *sccb)
unsigned long receive_mask,
unsigned long send_mask)
{ {
memset(sccb, 0, sizeof(*sccb));
sccb->header.length = sizeof(*sccb);
sccb->mask_length = sizeof(sccb_mask_t);
sccb->receive_mask = receive_mask;
sccb->send_mask = send_mask;
return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb);
}
static struct sclp_core_info sclp_core_info_early __initdata;
static int sclp_core_info_early_valid __initdata;
static void __init sclp_init_core_info_early(struct read_cpu_info_sccb *sccb)
{
int rc;
if (!SCLP_HAS_CPU_INFO) if (!SCLP_HAS_CPU_INFO)
return; return;
memset(sccb, 0, sizeof(*sccb)); memset(sccb, 0, sizeof(*sccb));
sccb->header.length = sizeof(*sccb); sccb->header.length = sizeof(*sccb);
do { if (sclp_early_cmd(SCLP_CMDW_READ_CPU_INFO, sccb))
rc = sclp_cmd_sync_early(SCLP_CMDW_READ_CPU_INFO, sccb);
} while (rc == -EBUSY);
if (rc)
return; return;
if (sccb->header.response_code != 0x0010) if (sccb->header.response_code != 0x0010)
return; return;
sclp_fill_core_info(&sclp_core_info_early, sccb); sclp_fill_core_info(&sclp_early_core_info, sccb);
sclp_core_info_early_valid = 1; sclp_early_core_info_valid = 1;
} }
int __init _sclp_get_core_info_early(struct sclp_core_info *info) int __init sclp_early_get_core_info(struct sclp_core_info *info)
{ {
if (!sclp_core_info_early_valid) if (!sclp_early_core_info_valid)
return -EIO; return -EIO;
*info = sclp_core_info_early; *info = sclp_early_core_info;
return 0; return 0;
} }
static long __init sclp_hsa_size_init(struct sdias_sccb *sccb) static long __init sclp_early_hsa_size_init(struct sdias_sccb *sccb)
{ {
sccb_init_eq_size(sccb); memset(sccb, 0, sizeof(*sccb));
if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb)) sccb->hdr.length = sizeof(*sccb);
sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
sccb->evbuf.hdr.type = EVTYP_SDIAS;
sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
sccb->evbuf.event_id = 4712;
sccb->evbuf.dbs = 1;
if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
return -EIO;
if (sccb->hdr.response_code != 0x20)
return -EIO; return -EIO;
if (sccb->evbuf.blk_cnt == 0) if (sccb->evbuf.blk_cnt == 0)
return 0; return 0;
return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE; return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
} }
static long __init sclp_hsa_copy_wait(struct sccb_header *sccb) static long __init sclp_early_hsa_copy_wait(struct sdias_sccb *sccb)
{ {
memset(sccb, 0, PAGE_SIZE); memset(sccb, 0, PAGE_SIZE);
sccb->length = PAGE_SIZE; sccb->hdr.length = PAGE_SIZE;
if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb)) if (sclp_early_cmd(SCLP_CMDW_READ_EVENT_DATA, sccb))
return -EIO; return -EIO;
if (((struct sdias_sccb *) sccb)->evbuf.blk_cnt == 0) if ((sccb->hdr.response_code != 0x20) && (sccb->hdr.response_code != 0x220))
return -EIO;
if (sccb->evbuf.blk_cnt == 0)
return 0; return 0;
return (((struct sdias_sccb *) sccb)->evbuf.blk_cnt - 1) * PAGE_SIZE; return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
} }
static void __init sclp_hsa_size_detect(void *sccb) static void __init sclp_early_hsa_size_detect(void *sccb)
{ {
long size; unsigned long flags;
long size = -EIO;
/* First try synchronous interface (LPAR) */ raw_local_irq_save(flags);
if (sclp_set_event_mask(sccb, 0, 0x40000010)) if (sclp_early_set_event_mask(sccb, EVTYP_SDIAS_MASK, EVTYP_SDIAS_MASK))
return;
size = sclp_hsa_size_init(sccb);
if (size < 0)
return;
if (size != 0)
goto out; goto out;
/* Then try asynchronous interface (z/VM) */ size = sclp_early_hsa_size_init(sccb);
if (sclp_set_event_mask(sccb, 0x00000010, 0x40000010)) /* First check for synchronous response (LPAR) */
return; if (size)
size = sclp_hsa_size_init(sccb); goto out_mask;
if (size < 0) if (!(S390_lowcore.ext_params & 1))
return; sclp_early_wait_irq();
size = sclp_hsa_copy_wait(sccb); size = sclp_early_hsa_copy_wait(sccb);
if (size < 0) out_mask:
return; sclp_early_set_event_mask(sccb, 0, 0);
out: out:
sclp.hsa_size = size; raw_local_irq_restore(flags);
} if (size > 0)
sclp.hsa_size = size;
static unsigned int __init sclp_con_check_linemode(struct init_sccb *sccb)
{
if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK))
return 0;
if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
return 0;
return 1;
} }
static void __init sclp_console_detect(struct init_sccb *sccb) static void __init sclp_early_console_detect(struct init_sccb *sccb)
{ {
if (sccb->header.response_code != 0x20) if (sccb->header.response_code != 0x20)
return; return;
...@@ -314,21 +246,22 @@ static void __init sclp_console_detect(struct init_sccb *sccb) ...@@ -314,21 +246,22 @@ static void __init sclp_console_detect(struct init_sccb *sccb)
if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK) if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK)
sclp.has_vt220 = 1; sclp.has_vt220 = 1;
if (sclp_con_check_linemode(sccb)) if (sclp_early_con_check_linemode(sccb))
sclp.has_linemode = 1; sclp.has_linemode = 1;
} }
void __init sclp_early_detect(void) void __init sclp_early_detect(void)
{ {
void *sccb = &sccb_early; void *sccb = &sclp_early_sccb;
sclp_facilities_detect(sccb); sclp_early_facilities_detect(sccb);
sclp_init_core_info_early(sccb); sclp_early_init_core_info(sccb);
sclp_hsa_size_detect(sccb); sclp_early_hsa_size_detect(sccb);
/* Turn off SCLP event notifications. Also save remote masks in the /*
* Turn off SCLP event notifications. Also save remote masks in the
* sccb. These are sufficient to detect sclp console capabilities. * sccb. These are sufficient to detect sclp console capabilities.
*/ */
sclp_set_event_mask(sccb, 0, 0); sclp_early_set_event_mask(sccb, 0, 0);
sclp_console_detect(sccb); sclp_early_console_detect(sccb);
} }
/*
* Copyright IBM Corp. 2015
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
#include <linux/kernel.h>
#include <asm/processor.h>
#include <asm/lowcore.h>
#include <asm/ebcdic.h>
#include <asm/irq.h>
#include "sclp.h"
#include "sclp_rw.h"
char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(data);
int sclp_init_state __section(data) = sclp_init_state_uninitialized;
void sclp_early_wait_irq(void)
{
unsigned long psw_mask, addr;
psw_t psw_ext_save, psw_wait;
union ctlreg0 cr0, cr0_new;
__ctl_store(cr0.val, 0, 0);
cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK;
cr0_new.lap = 0;
cr0_new.sssm = 1;
__ctl_load(cr0_new.val, 0, 0);
psw_ext_save = S390_lowcore.external_new_psw;
psw_mask = __extract_psw();
S390_lowcore.external_new_psw.mask = psw_mask;
psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT;
S390_lowcore.ext_int_code = 0;
do {
asm volatile(
" larl %[addr],0f\n"
" stg %[addr],%[psw_wait_addr]\n"
" stg %[addr],%[psw_ext_addr]\n"
" lpswe %[psw_wait]\n"
"0:\n"
: [addr] "=&d" (addr),
[psw_wait_addr] "=Q" (psw_wait.addr),
[psw_ext_addr] "=Q" (S390_lowcore.external_new_psw.addr)
: [psw_wait] "Q" (psw_wait)
: "cc", "memory");
} while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG);
S390_lowcore.external_new_psw = psw_ext_save;
__ctl_load(cr0.val, 0, 0);
}
int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb)
{
unsigned long flags;
int rc;
raw_local_irq_save(flags);
rc = sclp_service_call(cmd, sccb);
if (rc)
goto out;
sclp_early_wait_irq();
out:
raw_local_irq_restore(flags);
return rc;
}
struct write_sccb {
struct sccb_header header;
struct msg_buf msg;
} __packed;
/* Output multi-line text using SCLP Message interface. */
static void sclp_early_print_lm(const char *str, unsigned int len)
{
unsigned char *ptr, *end, ch;
unsigned int count, offset;
struct write_sccb *sccb;
struct msg_buf *msg;
struct mdb *mdb;
struct mto *mto;
struct go *go;
sccb = (struct write_sccb *) &sclp_early_sccb;
end = (unsigned char *) sccb + sizeof(sclp_early_sccb) - 1;
memset(sccb, 0, sizeof(*sccb));
ptr = (unsigned char *) &sccb->msg.mdb.mto;
offset = 0;
do {
for (count = sizeof(*mto); offset < len; count++) {
ch = str[offset++];
if ((ch == 0x0a) || (ptr + count > end))
break;
ptr[count] = _ascebc[ch];
}
mto = (struct mto *) ptr;
memset(mto, 0, sizeof(*mto));
mto->length = count;
mto->type = 4;
mto->line_type_flags = LNTPFLGS_ENDTEXT;
ptr += count;
} while ((offset < len) && (ptr + sizeof(*mto) <= end));
len = ptr - (unsigned char *) sccb;
sccb->header.length = len - offsetof(struct write_sccb, header);
msg = &sccb->msg;
msg->header.type = EVTYP_MSG;
msg->header.length = len - offsetof(struct write_sccb, msg.header);
mdb = &msg->mdb;
mdb->header.type = 1;
mdb->header.tag = 0xD4C4C240;
mdb->header.revision_code = 1;
mdb->header.length = len - offsetof(struct write_sccb, msg.mdb.header);
go = &mdb->go;
go->length = sizeof(*go);
go->type = 1;
sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
}
struct vt220_sccb {
struct sccb_header header;
struct {
struct evbuf_header header;
char data[];
} msg;
} __packed;
/* Output multi-line text using SCLP VT220 interface. */
static void sclp_early_print_vt220(const char *str, unsigned int len)
{
struct vt220_sccb *sccb;
sccb = (struct vt220_sccb *) &sclp_early_sccb;
if (sizeof(*sccb) + len >= sizeof(sclp_early_sccb))
len = sizeof(sclp_early_sccb) - sizeof(*sccb);
memset(sccb, 0, sizeof(*sccb));
memcpy(&sccb->msg.data, str, len);
sccb->header.length = sizeof(*sccb) + len;
sccb->msg.header.length = sizeof(sccb->msg) + len;
sccb->msg.header.type = EVTYP_VT220MSG;
sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
}
int sclp_early_set_event_mask(struct init_sccb *sccb,
unsigned long receive_mask,
unsigned long send_mask)
{
memset(sccb, 0, sizeof(*sccb));
sccb->header.length = sizeof(*sccb);
sccb->mask_length = sizeof(sccb_mask_t);
sccb->receive_mask = receive_mask;
sccb->send_mask = send_mask;
if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb))
return -EIO;
if (sccb->header.response_code != 0x20)
return -EIO;
return 0;
}
unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb)
{
if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK))
return 0;
if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
return 0;
return 1;
}
static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220)
{
unsigned long receive_mask, send_mask;
struct init_sccb *sccb;
int rc;
*have_linemode = *have_vt220 = 0;
sccb = (struct init_sccb *) &sclp_early_sccb;
receive_mask = disable ? 0 : EVTYP_OPCMD_MASK;
send_mask = disable ? 0 : EVTYP_VT220MSG_MASK | EVTYP_MSG_MASK;
rc = sclp_early_set_event_mask(sccb, receive_mask, send_mask);
if (rc)
return rc;
*have_linemode = sclp_early_con_check_linemode(sccb);
*have_vt220 = sccb->send_mask & EVTYP_VT220MSG_MASK;
return rc;
}
/*
* Output one or more lines of text on the SCLP console (VT220 and /
* or line-mode).
*/
void __sclp_early_printk(const char *str, unsigned int len)
{
int have_linemode, have_vt220;
if (sclp_init_state != sclp_init_state_uninitialized)
return;
if (sclp_early_setup(0, &have_linemode, &have_vt220) != 0)
return;
if (have_linemode)
sclp_early_print_lm(str, len);
if (have_vt220)
sclp_early_print_vt220(str, len);
sclp_early_setup(1, &have_linemode, &have_vt220);
}
void sclp_early_printk(const char *str)
{
__sclp_early_printk(str, strlen(str));
}
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/memblock.h> #include <linux/memblock.h>
...@@ -273,7 +272,7 @@ static int __init zcore_reipl_init(void) ...@@ -273,7 +272,7 @@ static int __init zcore_reipl_init(void)
rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE); rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE);
else else
rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE); rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE);
if (rc || csum_partial(ipl_block, ipl_block->hdr.len, 0) != if (rc || (__force u32)csum_partial(ipl_block, ipl_block->hdr.len, 0) !=
ipib_info.checksum) { ipib_info.checksum) {
TRACE("Checksum does not match\n"); TRACE("Checksum does not match\n");
free_page((unsigned long) ipl_block); free_page((unsigned long) ipl_block);
......
...@@ -444,6 +444,7 @@ int chp_update_desc(struct channel_path *chp) ...@@ -444,6 +444,7 @@ int chp_update_desc(struct channel_path *chp)
*/ */
int chp_new(struct chp_id chpid) int chp_new(struct chp_id chpid)
{ {
struct channel_subsystem *css = css_by_id(chpid.cssid);
struct channel_path *chp; struct channel_path *chp;
int ret; int ret;
...@@ -456,7 +457,7 @@ int chp_new(struct chp_id chpid) ...@@ -456,7 +457,7 @@ int chp_new(struct chp_id chpid)
/* fill in status, etc. */ /* fill in status, etc. */
chp->chpid = chpid; chp->chpid = chpid;
chp->state = 1; chp->state = 1;
chp->dev.parent = &channel_subsystems[chpid.cssid]->device; chp->dev.parent = &css->device;
chp->dev.groups = chp_attr_groups; chp->dev.groups = chp_attr_groups;
chp->dev.release = chp_release; chp->dev.release = chp_release;
mutex_init(&chp->lock); mutex_init(&chp->lock);
...@@ -479,17 +480,17 @@ int chp_new(struct chp_id chpid) ...@@ -479,17 +480,17 @@ int chp_new(struct chp_id chpid)
put_device(&chp->dev); put_device(&chp->dev);
goto out; goto out;
} }
mutex_lock(&channel_subsystems[chpid.cssid]->mutex); mutex_lock(&css->mutex);
if (channel_subsystems[chpid.cssid]->cm_enabled) { if (css->cm_enabled) {
ret = chp_add_cmg_attr(chp); ret = chp_add_cmg_attr(chp);
if (ret) { if (ret) {
device_unregister(&chp->dev); device_unregister(&chp->dev);
mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); mutex_unlock(&css->mutex);
goto out; goto out;
} }
} }
channel_subsystems[chpid.cssid]->chps[chpid.id] = chp; css->chps[chpid.id] = chp;
mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); mutex_unlock(&css->mutex);
goto out; goto out;
out_free: out_free:
kfree(chp); kfree(chp);
......
...@@ -54,7 +54,7 @@ struct channel_path { ...@@ -54,7 +54,7 @@ struct channel_path {
/* Return channel_path struct for given chpid. */ /* Return channel_path struct for given chpid. */
static inline struct channel_path *chpid_to_chp(struct chp_id chpid) static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
{ {
return channel_subsystems[chpid.cssid]->chps[chpid.id]; return css_by_id(chpid.cssid)->chps[chpid.id];
} }
int chp_get_status(struct chp_id chpid); int chp_get_status(struct chp_id chpid);
......
...@@ -1131,6 +1131,52 @@ int chsc_enable_facility(int operation_code) ...@@ -1131,6 +1131,52 @@ int chsc_enable_facility(int operation_code)
return ret; return ret;
} }
int __init chsc_get_cssid(int idx)
{
struct {
struct chsc_header request;
u8 atype;
u32 : 24;
u32 reserved1[6];
struct chsc_header response;
u32 reserved2[3];
struct {
u8 cssid;
u32 : 24;
} list[0];
} __packed *sdcal_area;
int ret;
spin_lock_irq(&chsc_page_lock);
memset(chsc_page, 0, PAGE_SIZE);
sdcal_area = chsc_page;
sdcal_area->request.length = 0x0020;
sdcal_area->request.code = 0x0034;
sdcal_area->atype = 4;
ret = chsc(sdcal_area);
if (ret) {
ret = (ret == 3) ? -ENODEV : -EBUSY;
goto exit;
}
ret = chsc_error_from_response(sdcal_area->response.code);
if (ret) {
CIO_CRW_EVENT(2, "chsc: sdcal failed (rc=%04x)\n",
sdcal_area->response.code);
goto exit;
}
if ((addr_t) &sdcal_area->list[idx] <
(addr_t) &sdcal_area->response + sdcal_area->response.length)
ret = sdcal_area->list[idx].cssid;
else
ret = -ENODEV;
exit:
spin_unlock_irq(&chsc_page_lock);
return ret;
}
struct css_general_char css_general_characteristics; struct css_general_char css_general_characteristics;
struct css_chsc_char css_chsc_characteristics; struct css_chsc_char css_chsc_characteristics;
...@@ -1216,7 +1262,7 @@ int chsc_sstpi(void *page, void *result, size_t size) ...@@ -1216,7 +1262,7 @@ int chsc_sstpi(void *page, void *result, size_t size)
struct chsc_header request; struct chsc_header request;
unsigned int rsvd0[3]; unsigned int rsvd0[3];
struct chsc_header response; struct chsc_header response;
char data[size]; char data[];
} __attribute__ ((packed)) *rr; } __attribute__ ((packed)) *rr;
int rc; int rc;
......
...@@ -242,6 +242,8 @@ int chsc_pnso_brinfo(struct subchannel_id schid, ...@@ -242,6 +242,8 @@ int chsc_pnso_brinfo(struct subchannel_id schid,
struct chsc_brinfo_resume_token resume_token, struct chsc_brinfo_resume_token resume_token,
int cnc); int cnc);
int __init chsc_get_cssid(int idx);
#ifdef CONFIG_SCM_BUS #ifdef CONFIG_SCM_BUS
int scm_update_information(void); int scm_update_information(void);
int scm_process_availability_information(void); int scm_process_availability_information(void);
......
...@@ -1085,15 +1085,9 @@ static ssize_t cmb_show_avg_utilization(struct device *dev, ...@@ -1085,15 +1085,9 @@ static ssize_t cmb_show_avg_utilization(struct device *dev,
data.function_pending_time + data.function_pending_time +
data.device_disconnect_time; data.device_disconnect_time;
/* shift to avoid long long division */
while (-1ul < (data.elapsed_time | utilization)) {
utilization >>= 8;
data.elapsed_time >>= 8;
}
/* calculate value in 0.1 percent units */ /* calculate value in 0.1 percent units */
t = (unsigned long) data.elapsed_time / 1000; t = data.elapsed_time / 1000;
u = (unsigned long) utilization / t; u = utilization / t;
return sprintf(buf, "%02ld.%01ld%%\n", u/ 10, u - (u/ 10) * 10); return sprintf(buf, "%02ld.%01ld%%\n", u/ 10, u - (u/ 10) * 10);
} }
......
...@@ -36,7 +36,8 @@ ...@@ -36,7 +36,8 @@
int css_init_done = 0; int css_init_done = 0;
int max_ssid; int max_ssid;
struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; #define MAX_CSS_IDX 0
struct channel_subsystem *channel_subsystems[MAX_CSS_IDX + 1];
static struct bus_type css_bus_type; static struct bus_type css_bus_type;
int int
...@@ -702,7 +703,8 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) ...@@ -702,7 +703,8 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
if (css_general_characteristics.mcss) { if (css_general_characteristics.mcss) {
css->global_pgid.pgid_high.ext_cssid.version = 0x80; css->global_pgid.pgid_high.ext_cssid.version = 0x80;
css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; css->global_pgid.pgid_high.ext_cssid.cssid =
(css->cssid < 0) ? 0 : css->cssid;
} else { } else {
css->global_pgid.pgid_high.cpu_addr = stap(); css->global_pgid.pgid_high.cpu_addr = stap();
} }
...@@ -712,43 +714,44 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) ...@@ -712,43 +714,44 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
css->global_pgid.tod_high = tod_high; css->global_pgid.tod_high = tod_high;
} }
static void static void channel_subsystem_release(struct device *dev)
channel_subsystem_release(struct device *dev)
{ {
struct channel_subsystem *css; struct channel_subsystem *css = to_css(dev);
css = to_css(dev);
mutex_destroy(&css->mutex); mutex_destroy(&css->mutex);
if (css->pseudo_subchannel) {
/* Implies that it has been generated but never registered. */
css_subchannel_release(&css->pseudo_subchannel->dev);
css->pseudo_subchannel = NULL;
}
kfree(css); kfree(css);
} }
static ssize_t static ssize_t real_cssid_show(struct device *dev, struct device_attribute *a,
css_cm_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
char *buf) {
struct channel_subsystem *css = to_css(dev);
if (css->cssid < 0)
return -EINVAL;
return sprintf(buf, "%x\n", css->cssid);
}
static DEVICE_ATTR_RO(real_cssid);
static ssize_t cm_enable_show(struct device *dev, struct device_attribute *a,
char *buf)
{ {
struct channel_subsystem *css = to_css(dev); struct channel_subsystem *css = to_css(dev);
int ret; int ret;
if (!css)
return 0;
mutex_lock(&css->mutex); mutex_lock(&css->mutex);
ret = sprintf(buf, "%x\n", css->cm_enabled); ret = sprintf(buf, "%x\n", css->cm_enabled);
mutex_unlock(&css->mutex); mutex_unlock(&css->mutex);
return ret; return ret;
} }
static ssize_t static ssize_t cm_enable_store(struct device *dev, struct device_attribute *a,
css_cm_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
const char *buf, size_t count)
{ {
struct channel_subsystem *css = to_css(dev); struct channel_subsystem *css = to_css(dev);
int ret;
unsigned long val; unsigned long val;
int ret;
ret = kstrtoul(buf, 16, &val); ret = kstrtoul(buf, 16, &val);
if (ret) if (ret)
...@@ -767,51 +770,104 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, ...@@ -767,51 +770,104 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr,
mutex_unlock(&css->mutex); mutex_unlock(&css->mutex);
return ret < 0 ? ret : count; return ret < 0 ? ret : count;
} }
static DEVICE_ATTR_RW(cm_enable);
static umode_t cm_enable_mode(struct kobject *kobj, struct attribute *attr,
int index)
{
return css_chsc_characteristics.secm ? attr->mode : 0;
}
static struct attribute *cssdev_attrs[] = {
&dev_attr_real_cssid.attr,
NULL,
};
static struct attribute_group cssdev_attr_group = {
.attrs = cssdev_attrs,
};
static struct attribute *cssdev_cm_attrs[] = {
&dev_attr_cm_enable.attr,
NULL,
};
static struct attribute_group cssdev_cm_attr_group = {
.attrs = cssdev_cm_attrs,
.is_visible = cm_enable_mode,
};
static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store); static const struct attribute_group *cssdev_attr_groups[] = {
&cssdev_attr_group,
&cssdev_cm_attr_group,
NULL,
};
static int __init setup_css(int nr) static int __init setup_css(int nr)
{ {
u32 tod_high;
int ret;
struct channel_subsystem *css; struct channel_subsystem *css;
int ret;
css = channel_subsystems[nr]; css = kzalloc(sizeof(*css), GFP_KERNEL);
memset(css, 0, sizeof(struct channel_subsystem)); if (!css)
css->pseudo_subchannel =
kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL);
if (!css->pseudo_subchannel)
return -ENOMEM; return -ENOMEM;
channel_subsystems[nr] = css;
dev_set_name(&css->device, "css%x", nr);
css->device.groups = cssdev_attr_groups;
css->device.release = channel_subsystem_release;
mutex_init(&css->mutex);
css->cssid = chsc_get_cssid(nr);
css_generate_pgid(css, (u32) (get_tod_clock() >> 32));
ret = device_register(&css->device);
if (ret) {
put_device(&css->device);
goto out_err;
}
css->pseudo_subchannel = kzalloc(sizeof(*css->pseudo_subchannel),
GFP_KERNEL);
if (!css->pseudo_subchannel) {
device_unregister(&css->device);
ret = -ENOMEM;
goto out_err;
}
css->pseudo_subchannel->dev.parent = &css->device; css->pseudo_subchannel->dev.parent = &css->device;
css->pseudo_subchannel->dev.release = css_subchannel_release; css->pseudo_subchannel->dev.release = css_subchannel_release;
dev_set_name(&css->pseudo_subchannel->dev, "defunct");
mutex_init(&css->pseudo_subchannel->reg_mutex); mutex_init(&css->pseudo_subchannel->reg_mutex);
ret = css_sch_create_locks(css->pseudo_subchannel); ret = css_sch_create_locks(css->pseudo_subchannel);
if (ret) { if (ret) {
kfree(css->pseudo_subchannel); kfree(css->pseudo_subchannel);
return ret; device_unregister(&css->device);
goto out_err;
} }
mutex_init(&css->mutex);
css->valid = 1; dev_set_name(&css->pseudo_subchannel->dev, "defunct");
css->cssid = nr; ret = device_register(&css->pseudo_subchannel->dev);
dev_set_name(&css->device, "css%x", nr); if (ret) {
css->device.release = channel_subsystem_release; put_device(&css->pseudo_subchannel->dev);
tod_high = (u32) (get_tod_clock() >> 32); device_unregister(&css->device);
css_generate_pgid(css, tod_high); goto out_err;
return 0; }
return ret;
out_err:
channel_subsystems[nr] = NULL;
return ret;
} }
static int css_reboot_event(struct notifier_block *this, static int css_reboot_event(struct notifier_block *this,
unsigned long event, unsigned long event,
void *ptr) void *ptr)
{ {
int ret, i; struct channel_subsystem *css;
int ret;
ret = NOTIFY_DONE; ret = NOTIFY_DONE;
for (i = 0; i <= __MAX_CSSID; i++) { for_each_css(css) {
struct channel_subsystem *css;
css = channel_subsystems[i];
mutex_lock(&css->mutex); mutex_lock(&css->mutex);
if (css->cm_enabled) if (css->cm_enabled)
if (chsc_secm(css, 0)) if (chsc_secm(css, 0))
...@@ -835,16 +891,14 @@ static struct notifier_block css_reboot_notifier = { ...@@ -835,16 +891,14 @@ static struct notifier_block css_reboot_notifier = {
static int css_power_event(struct notifier_block *this, unsigned long event, static int css_power_event(struct notifier_block *this, unsigned long event,
void *ptr) void *ptr)
{ {
int ret, i; struct channel_subsystem *css;
int ret;
switch (event) { switch (event) {
case PM_HIBERNATION_PREPARE: case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE: case PM_SUSPEND_PREPARE:
ret = NOTIFY_DONE; ret = NOTIFY_DONE;
for (i = 0; i <= __MAX_CSSID; i++) { for_each_css(css) {
struct channel_subsystem *css;
css = channel_subsystems[i];
mutex_lock(&css->mutex); mutex_lock(&css->mutex);
if (!css->cm_enabled) { if (!css->cm_enabled) {
mutex_unlock(&css->mutex); mutex_unlock(&css->mutex);
...@@ -858,10 +912,7 @@ static int css_power_event(struct notifier_block *this, unsigned long event, ...@@ -858,10 +912,7 @@ static int css_power_event(struct notifier_block *this, unsigned long event,
case PM_POST_HIBERNATION: case PM_POST_HIBERNATION:
case PM_POST_SUSPEND: case PM_POST_SUSPEND:
ret = NOTIFY_DONE; ret = NOTIFY_DONE;
for (i = 0; i <= __MAX_CSSID; i++) { for_each_css(css) {
struct channel_subsystem *css;
css = channel_subsystems[i];
mutex_lock(&css->mutex); mutex_lock(&css->mutex);
if (!css->cm_enabled) { if (!css->cm_enabled) {
mutex_unlock(&css->mutex); mutex_unlock(&css->mutex);
...@@ -916,36 +967,10 @@ static int __init css_bus_init(void) ...@@ -916,36 +967,10 @@ static int __init css_bus_init(void)
goto out; goto out;
/* Setup css structure. */ /* Setup css structure. */
for (i = 0; i <= __MAX_CSSID; i++) { for (i = 0; i <= MAX_CSS_IDX; i++) {
struct channel_subsystem *css;
css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
if (!css) {
ret = -ENOMEM;
goto out_unregister;
}
channel_subsystems[i] = css;
ret = setup_css(i); ret = setup_css(i);
if (ret) { if (ret)
kfree(channel_subsystems[i]);
goto out_unregister;
}
ret = device_register(&css->device);
if (ret) {
put_device(&css->device);
goto out_unregister; goto out_unregister;
}
if (css_chsc_characteristics.secm) {
ret = device_create_file(&css->device,
&dev_attr_cm_enable);
if (ret)
goto out_device;
}
ret = device_register(&css->pseudo_subchannel->dev);
if (ret) {
put_device(&css->pseudo_subchannel->dev);
goto out_file;
}
} }
ret = register_reboot_notifier(&css_reboot_notifier); ret = register_reboot_notifier(&css_reboot_notifier);
if (ret) if (ret)
...@@ -961,23 +986,10 @@ static int __init css_bus_init(void) ...@@ -961,23 +986,10 @@ static int __init css_bus_init(void)
isc_register(IO_SCH_ISC); isc_register(IO_SCH_ISC);
return 0; return 0;
out_file:
if (css_chsc_characteristics.secm)
device_remove_file(&channel_subsystems[i]->device,
&dev_attr_cm_enable);
out_device:
device_unregister(&channel_subsystems[i]->device);
out_unregister: out_unregister:
while (i > 0) { while (i-- > 0) {
struct channel_subsystem *css; struct channel_subsystem *css = channel_subsystems[i];
i--;
css = channel_subsystems[i];
device_unregister(&css->pseudo_subchannel->dev); device_unregister(&css->pseudo_subchannel->dev);
css->pseudo_subchannel = NULL;
if (css_chsc_characteristics.secm)
device_remove_file(&css->device,
&dev_attr_cm_enable);
device_unregister(&css->device); device_unregister(&css->device);
} }
bus_unregister(&css_bus_type); bus_unregister(&css_bus_type);
...@@ -993,14 +1005,9 @@ static int __init css_bus_init(void) ...@@ -993,14 +1005,9 @@ static int __init css_bus_init(void)
static void __init css_bus_cleanup(void) static void __init css_bus_cleanup(void)
{ {
struct channel_subsystem *css; struct channel_subsystem *css;
int i;
for (i = 0; i <= __MAX_CSSID; i++) { for_each_css(css) {
css = channel_subsystems[i];
device_unregister(&css->pseudo_subchannel->dev); device_unregister(&css->pseudo_subchannel->dev);
css->pseudo_subchannel = NULL;
if (css_chsc_characteristics.secm)
device_remove_file(&css->device, &dev_attr_cm_enable);
device_unregister(&css->device); device_unregister(&css->device);
} }
bus_unregister(&css_bus_type); bus_unregister(&css_bus_type);
......
...@@ -113,8 +113,7 @@ extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); ...@@ -113,8 +113,7 @@ extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
void css_update_ssd_info(struct subchannel *sch); void css_update_ssd_info(struct subchannel *sch);
struct channel_subsystem { struct channel_subsystem {
u8 cssid; int cssid;
int valid;
struct channel_path *chps[__MAX_CHPID + 1]; struct channel_path *chps[__MAX_CHPID + 1];
struct device device; struct device device;
struct pgid global_pgid; struct pgid global_pgid;
...@@ -130,6 +129,16 @@ struct channel_subsystem { ...@@ -130,6 +129,16 @@ struct channel_subsystem {
extern struct channel_subsystem *channel_subsystems[]; extern struct channel_subsystem *channel_subsystems[];
/* Dummy helper which needs to change once we support more than one css. */
static inline struct channel_subsystem *css_by_id(u8 cssid)
{
return channel_subsystems[0];
}
/* Dummy iterator which needs to change once we support more than one css. */
#define for_each_css(css) \
for ((css) = channel_subsystems[0]; (css); (css) = NULL)
/* Helper functions to build lists for the slow path. */ /* Helper functions to build lists for the slow path. */
void css_schedule_eval(struct subchannel_id schid); void css_schedule_eval(struct subchannel_id schid);
void css_schedule_eval_all(void); void css_schedule_eval_all(void);
......
...@@ -457,7 +457,7 @@ static inline void inbound_primed(struct qdio_q *q, int count) ...@@ -457,7 +457,7 @@ static inline void inbound_primed(struct qdio_q *q, int count)
{ {
int new; int new;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %02x", count); DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim:%1d %02x", q->nr, count);
/* for QEBSM the ACK was already set by EQBS */ /* for QEBSM the ACK was already set by EQBS */
if (is_qebsm(q)) { if (is_qebsm(q)) {
...@@ -544,7 +544,8 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) ...@@ -544,7 +544,8 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
case SLSB_P_INPUT_ACK: case SLSB_P_INPUT_ACK:
if (q->irq_ptr->perf_stat_enabled) if (q->irq_ptr->perf_stat_enabled)
q->q_stats.nr_sbal_nop++; q->q_stats.nr_sbal_nop++;
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in nop"); DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in nop:%1d %#02x",
q->nr, q->first_to_check);
break; break;
default: default:
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
......
...@@ -147,11 +147,11 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) ...@@ -147,11 +147,11 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
struct qdio_q *q; struct qdio_q *q;
int i; int i;
for_each_input_queue(irq, q, i) { if (!references_shared_dsci(irq) &&
if (!references_shared_dsci(irq) && has_multiple_inq_on_dsci(irq))
has_multiple_inq_on_dsci(irq)) xchg(irq->dsci, 0);
xchg(q->irq_ptr->dsci, 0);
for_each_input_queue(irq, q, i) {
if (q->u.in.queue_start_poll) { if (q->u.in.queue_start_poll) {
/* skip if polling is enabled or already in work */ /* skip if polling is enabled or already in work */
if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
...@@ -161,11 +161,11 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) ...@@ -161,11 +161,11 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
} }
/* avoid dsci clear here, done after processing */ /* avoid dsci clear here, done after processing */
q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr, q->u.in.queue_start_poll(irq->cdev, q->nr,
q->irq_ptr->int_parm); irq->int_parm);
} else { } else {
if (!shared_ind(q->irq_ptr)) if (!shared_ind(irq))
xchg(q->irq_ptr->dsci, 0); xchg(irq->dsci, 0);
/* /*
* Call inbound processing but not directly * Call inbound processing but not directly
...@@ -178,8 +178,7 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) ...@@ -178,8 +178,7 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
/** /**
* tiqdio_thinint_handler - thin interrupt handler for qdio * tiqdio_thinint_handler - thin interrupt handler for qdio
* @alsi: pointer to adapter local summary indicator * @airq: pointer to adapter interrupt descriptor
* @data: NULL
*/ */
static void tiqdio_thinint_handler(struct airq_struct *airq) static void tiqdio_thinint_handler(struct airq_struct *airq)
{ {
......
...@@ -129,7 +129,6 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, ...@@ -129,7 +129,6 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
unsigned long long psmid, unsigned long long psmid,
void *msg, size_t length) void *msg, size_t length)
{ {
struct msgblock { char _[length]; };
register unsigned long reg0 asm ("0") = qid | 0x40000000UL; register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
register struct ap_queue_status reg1 asm ("1"); register struct ap_queue_status reg1 asm ("1");
register unsigned long reg2 asm ("2") = (unsigned long) msg; register unsigned long reg2 asm ("2") = (unsigned long) msg;
...@@ -141,8 +140,8 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, ...@@ -141,8 +140,8 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
"0: .long 0xb2ad0042\n" /* NQAP */ "0: .long 0xb2ad0042\n" /* NQAP */
" brc 2,0b" " brc 2,0b"
: "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3)
: "d" (reg4), "d" (reg5), "m" (*(struct msgblock *) msg) : "d" (reg4), "d" (reg5)
: "cc"); : "cc", "memory");
return reg1; return reg1;
} }
...@@ -168,7 +167,6 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, ...@@ -168,7 +167,6 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
unsigned long long *psmid, unsigned long long *psmid,
void *msg, size_t length) void *msg, size_t length)
{ {
struct msgblock { char _[length]; };
register unsigned long reg0 asm("0") = qid | 0x80000000UL; register unsigned long reg0 asm("0") = qid | 0x80000000UL;
register struct ap_queue_status reg1 asm ("1"); register struct ap_queue_status reg1 asm ("1");
register unsigned long reg2 asm("2") = 0UL; register unsigned long reg2 asm("2") = 0UL;
...@@ -182,8 +180,8 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, ...@@ -182,8 +180,8 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
"0: .long 0xb2ae0064\n" /* DQAP */ "0: .long 0xb2ae0064\n" /* DQAP */
" brc 6,0b\n" " brc 6,0b\n"
: "+d" (reg0), "=d" (reg1), "+d" (reg2), : "+d" (reg0), "=d" (reg1), "+d" (reg2),
"+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7), "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7)
"=m" (*(struct msgblock *) msg) : : "cc"); : : "cc", "memory");
*psmid = (((unsigned long long) reg6) << 32) + reg7; *psmid = (((unsigned long long) reg6) << 32) + reg7;
return reg1; return reg1;
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/module.h> #include <linux/moduleparam.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -54,16 +54,7 @@ ...@@ -54,16 +54,7 @@
#include "ap_debug.h" #include "ap_debug.h"
/* /*
* Module description. * Module parameters; note though this file itself isn't modular.
*/
MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("Adjunct Processor Bus driver, " \
"Copyright IBM Corp. 2006, 2012");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CRYPTO("z90crypt");
/*
* Module parameter
*/ */
int ap_domain_index = -1; /* Adjunct Processor Domain Index */ int ap_domain_index = -1; /* Adjunct Processor Domain Index */
static DEFINE_SPINLOCK(ap_domain_lock); static DEFINE_SPINLOCK(ap_domain_lock);
...@@ -86,7 +77,6 @@ static bool initialised; ...@@ -86,7 +77,6 @@ static bool initialised;
/* /*
* AP bus related debug feature things. * AP bus related debug feature things.
*/ */
static struct dentry *ap_dbf_root;
debug_info_t *ap_dbf_info; debug_info_t *ap_dbf_info;
/* /*
...@@ -1148,7 +1138,6 @@ static struct reset_call ap_reset_call = { ...@@ -1148,7 +1138,6 @@ static struct reset_call ap_reset_call = {
int __init ap_debug_init(void) int __init ap_debug_init(void)
{ {
ap_dbf_root = debugfs_create_dir("ap", NULL);
ap_dbf_info = debug_register("ap", 1, 1, ap_dbf_info = debug_register("ap", 1, 1,
DBF_MAX_SPRINTF_ARGS * sizeof(long)); DBF_MAX_SPRINTF_ARGS * sizeof(long));
debug_register_view(ap_dbf_info, &debug_sprintf_view); debug_register_view(ap_dbf_info, &debug_sprintf_view);
...@@ -1159,7 +1148,6 @@ int __init ap_debug_init(void) ...@@ -1159,7 +1148,6 @@ int __init ap_debug_init(void)
void ap_debug_exit(void) void ap_debug_exit(void)
{ {
debugfs_remove(ap_dbf_root);
debug_unregister(ap_dbf_info); debug_unregister(ap_dbf_info);
} }
...@@ -1270,43 +1258,4 @@ int __init ap_module_init(void) ...@@ -1270,43 +1258,4 @@ int __init ap_module_init(void)
kfree(ap_configuration); kfree(ap_configuration);
return rc; return rc;
} }
device_initcall(ap_module_init);
/**
* ap_modules_exit(): The module termination code
*
* Terminates the module.
*/
void ap_module_exit(void)
{
int i;
initialised = false;
ap_reset_domain();
ap_poll_thread_stop();
del_timer_sync(&ap_config_timer);
hrtimer_cancel(&ap_poll_timer);
tasklet_kill(&ap_tasklet);
/* first remove queue devices */
bus_for_each_dev(&ap_bus_type, NULL, NULL,
__ap_queue_devices_unregister);
/* now remove the card devices */
bus_for_each_dev(&ap_bus_type, NULL, NULL,
__ap_card_devices_unregister);
/* remove bus attributes */
for (i = 0; ap_bus_attrs[i]; i++)
bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
unregister_pm_notifier(&ap_power_notifier);
root_device_unregister(ap_root_device);
bus_unregister(&ap_bus_type);
kfree(ap_configuration);
unregister_reset_call(&ap_reset_call);
if (ap_using_interrupts())
unregister_adapter_interrupt(&ap_airq);
ap_debug_exit();
}
module_init(ap_module_init);
module_exit(ap_module_exit);
...@@ -137,7 +137,7 @@ static const struct attribute_group *ap_card_dev_attr_groups[] = { ...@@ -137,7 +137,7 @@ static const struct attribute_group *ap_card_dev_attr_groups[] = {
NULL NULL
}; };
struct device_type ap_card_type = { static struct device_type ap_card_type = {
.name = "ap_card", .name = "ap_card",
.groups = ap_card_dev_attr_groups, .groups = ap_card_dev_attr_groups,
}; };
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册