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

Pull s390 update from Martin Schwidefsky:
 "The most prominent change in this patch set is the software dirty bit
  patch for s390.  It removes __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY and
  the page_test_and_clear_dirty primitive which makes the common memory
  management code a bit less obscure.

  Heiko fixed most of the PCI related fallout, more often than not
  missing GENERIC_HARDIRQS dependencies.  Notable is one of the 3270
  patches which adds an export to tty_io to be able to resize a tty.

  The rest is the usual bunch of cleanups and bug fixes."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (42 commits)
  s390/module: Add missing R_390_NONE relocation type
  drivers/gpio: add missing GENERIC_HARDIRQ dependency
  drivers/input: add couple of missing GENERIC_HARDIRQS dependencies
  s390/cleanup: rename SPP to LPP
  s390/mm: implement software dirty bits
  s390/mm: Fix crst upgrade of mmap with MAP_FIXED
  s390/linker skript: discard exit.data at runtime
  drivers/media: add missing GENERIC_HARDIRQS dependency
  s390/bpf,jit: add vlan tag support
  drivers/net,AT91RM9200: add missing GENERIC_HARDIRQS dependency
  iucv: fix kernel panic at reboot
  s390/Kconfig: sort list of arch selected config options
  phylib: remove !S390 dependeny from Kconfig
  uio: remove !S390 dependency from Kconfig
  dasd: fix sysfs cleanup in dasd_generic_remove
  s390/pci: fix hotplug module init
  s390/pci: cleanup clp page allocation
  s390/pci: cleanup clp inline assembly
  s390/perf: cpum_cf: fallback to software sampling events
  s390/mm: provide PAGE_SHARED define
  ...
This commit is contained in:
Linus Torvalds 2013-02-21 17:54:03 -08:00
Родитель 48a732dfaa e80cfc31d8
Коммит 81ec44a6c6
82 изменённых файлов: 1216 добавлений и 930 удалений

Просмотреть файл

@ -6519,7 +6519,7 @@ S: Supported
F: drivers/s390/net/ F: drivers/s390/net/
S390 ZCRYPT DRIVER S390 ZCRYPT DRIVER
M: Holger Dengler <hd@linux.vnet.ibm.com> M: Ingo Tuchscherer <ingo.tuchscherer@de.ibm.com>
M: linux390@de.ibm.com M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/ W: http://www.ibm.com/developerworks/linux/linux390/

Просмотреть файл

@ -60,85 +60,86 @@ config PCI_QUIRKS
config S390 config S390
def_bool y def_bool y
select USE_GENERIC_SMP_HELPERS if SMP
select GENERIC_CPU_DEVICES if !SMP
select HAVE_SYSCALL_WRAPPERS
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_C_RECORDMCOUNT
select HAVE_SYSCALL_TRACEPOINTS
select SYSCTL_EXCEPTION_TRACE
select HAVE_DYNAMIC_FTRACE
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_OPROFILE
select HAVE_KPROBES
select HAVE_KRETPROBES
select HAVE_KVM if 64BIT
select HAVE_ARCH_TRACEHOOK
select INIT_ALL_POSSIBLE
select HAVE_PERF_EVENTS
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select HAVE_DEBUG_KMEMLEAK
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_LZO
select HAVE_KERNEL_XZ
select HAVE_ARCH_MUTEX_CPU_RELAX
select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
select HAVE_BPF_JIT if 64BIT && PACK_STACK
select ARCH_SAVE_PAGE_KEYS if HIBERNATION
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select HAVE_MEMBLOCK
select HAVE_MEMBLOCK_NODE_MAP
select HAVE_CMPXCHG_LOCAL
select HAVE_CMPXCHG_DOUBLE
select HAVE_ALIGNED_STRUCT_PAGE if SLUB
select HAVE_VIRT_CPU_ACCOUNTING
select VIRT_CPU_ACCOUNTING
select ARCH_DISCARD_MEMBLOCK select ARCH_DISCARD_MEMBLOCK
select BUILDTIME_EXTABLE_SORT select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_INLINE_SPIN_TRYLOCK select ARCH_HAVE_NMI_SAFE_CMPXCHG
select ARCH_INLINE_SPIN_TRYLOCK_BH
select ARCH_INLINE_SPIN_LOCK
select ARCH_INLINE_SPIN_LOCK_BH
select ARCH_INLINE_SPIN_LOCK_IRQ
select ARCH_INLINE_SPIN_LOCK_IRQSAVE
select ARCH_INLINE_SPIN_UNLOCK
select ARCH_INLINE_SPIN_UNLOCK_BH
select ARCH_INLINE_SPIN_UNLOCK_IRQ
select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE
select ARCH_INLINE_READ_TRYLOCK
select ARCH_INLINE_READ_LOCK select ARCH_INLINE_READ_LOCK
select ARCH_INLINE_READ_LOCK_BH select ARCH_INLINE_READ_LOCK_BH
select ARCH_INLINE_READ_LOCK_IRQ select ARCH_INLINE_READ_LOCK_IRQ
select ARCH_INLINE_READ_LOCK_IRQSAVE select ARCH_INLINE_READ_LOCK_IRQSAVE
select ARCH_INLINE_READ_TRYLOCK
select ARCH_INLINE_READ_UNLOCK select ARCH_INLINE_READ_UNLOCK
select ARCH_INLINE_READ_UNLOCK_BH select ARCH_INLINE_READ_UNLOCK_BH
select ARCH_INLINE_READ_UNLOCK_IRQ select ARCH_INLINE_READ_UNLOCK_IRQ
select ARCH_INLINE_READ_UNLOCK_IRQRESTORE select ARCH_INLINE_READ_UNLOCK_IRQRESTORE
select ARCH_INLINE_WRITE_TRYLOCK select ARCH_INLINE_SPIN_LOCK
select ARCH_INLINE_SPIN_LOCK_BH
select ARCH_INLINE_SPIN_LOCK_IRQ
select ARCH_INLINE_SPIN_LOCK_IRQSAVE
select ARCH_INLINE_SPIN_TRYLOCK
select ARCH_INLINE_SPIN_TRYLOCK_BH
select ARCH_INLINE_SPIN_UNLOCK
select ARCH_INLINE_SPIN_UNLOCK_BH
select ARCH_INLINE_SPIN_UNLOCK_IRQ
select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE
select ARCH_INLINE_WRITE_LOCK select ARCH_INLINE_WRITE_LOCK
select ARCH_INLINE_WRITE_LOCK_BH select ARCH_INLINE_WRITE_LOCK_BH
select ARCH_INLINE_WRITE_LOCK_IRQ select ARCH_INLINE_WRITE_LOCK_IRQ
select ARCH_INLINE_WRITE_LOCK_IRQSAVE select ARCH_INLINE_WRITE_LOCK_IRQSAVE
select ARCH_INLINE_WRITE_TRYLOCK
select ARCH_INLINE_WRITE_UNLOCK select ARCH_INLINE_WRITE_UNLOCK
select ARCH_INLINE_WRITE_UNLOCK_BH select ARCH_INLINE_WRITE_UNLOCK_BH
select ARCH_INLINE_WRITE_UNLOCK_IRQ select ARCH_INLINE_WRITE_UNLOCK_IRQ
select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
select HAVE_UID16 if 32BIT select ARCH_SAVE_PAGE_KEYS if HIBERNATION
select ARCH_WANT_IPC_PARSE_VERSION select ARCH_WANT_IPC_PARSE_VERSION
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if 64BIT select BUILDTIME_EXTABLE_SORT
select CLONE_BACKWARDS2
select GENERIC_CLOCKEVENTS
select GENERIC_CPU_DEVICES if !SMP
select GENERIC_KERNEL_THREAD
select GENERIC_SMP_IDLE_THREAD select GENERIC_SMP_IDLE_THREAD
select GENERIC_TIME_VSYSCALL_OLD select GENERIC_TIME_VSYSCALL_OLD
select GENERIC_CLOCKEVENTS select HAVE_ALIGNED_STRUCT_PAGE if SLUB
select KTIME_SCALAR if 32BIT select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
select HAVE_ARCH_MUTEX_CPU_RELAX
select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if 64BIT
select HAVE_BPF_JIT if 64BIT && PACK_STACK
select HAVE_CMPXCHG_DOUBLE
select HAVE_CMPXCHG_LOCAL
select HAVE_C_RECORDMCOUNT
select HAVE_DEBUG_KMEMLEAK
select HAVE_DYNAMIC_FTRACE
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_LZO
select HAVE_KERNEL_XZ
select HAVE_KPROBES
select HAVE_KRETPROBES
select HAVE_KVM if 64BIT
select HAVE_MEMBLOCK
select HAVE_MEMBLOCK_NODE_MAP
select HAVE_MOD_ARCH_SPECIFIC select HAVE_MOD_ARCH_SPECIFIC
select HAVE_OPROFILE
select HAVE_PERF_EVENTS
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_SYSCALL_WRAPPERS
select HAVE_UID16 if 32BIT
select HAVE_VIRT_CPU_ACCOUNTING
select INIT_ALL_POSSIBLE
select KTIME_SCALAR if 32BIT
select MODULES_USE_ELF_RELA select MODULES_USE_ELF_RELA
select CLONE_BACKWARDS2 select SYSCTL_EXCEPTION_TRACE
select USE_GENERIC_SMP_HELPERS if SMP
select VIRT_CPU_ACCOUNTING
config SCHED_OMIT_FRAME_POINTER config SCHED_OMIT_FRAME_POINTER
def_bool y def_bool y

Просмотреть файл

@ -108,7 +108,7 @@ static void appldata_get_mem_data(void *data)
mem_data->totalswap = P2K(val.totalswap); mem_data->totalswap = P2K(val.totalswap);
mem_data->freeswap = P2K(val.freeswap); mem_data->freeswap = P2K(val.freeswap);
mem_data->timestamp = get_clock(); mem_data->timestamp = get_tod_clock();
mem_data->sync_count_2++; mem_data->sync_count_2++;
} }

Просмотреть файл

@ -111,7 +111,7 @@ static void appldata_get_net_sum_data(void *data)
net_data->tx_dropped = tx_dropped; net_data->tx_dropped = tx_dropped;
net_data->collisions = collisions; net_data->collisions = collisions;
net_data->timestamp = get_clock(); net_data->timestamp = get_tod_clock();
net_data->sync_count_2++; net_data->sync_count_2++;
} }

Просмотреть файл

@ -156,7 +156,7 @@ static void appldata_get_os_data(void *data)
} }
ops.size = new_size; ops.size = new_size;
} }
os_data->timestamp = get_clock(); os_data->timestamp = get_tod_clock();
os_data->sync_count_2++; os_data->sync_count_2++;
} }

Просмотреть файл

@ -245,7 +245,7 @@ static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size)
d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr)); d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr));
if (IS_ERR(d2fc)) if (IS_ERR(d2fc))
return PTR_ERR(d2fc); return PTR_ERR(d2fc);
get_clock_ext(d2fc->hdr.tod_ext); get_tod_clock_ext(d2fc->hdr.tod_ext);
d2fc->hdr.len = count * sizeof(struct diag2fc_data); d2fc->hdr.len = count * sizeof(struct diag2fc_data);
d2fc->hdr.version = DBFS_D2FC_HDR_VERSION; d2fc->hdr.version = DBFS_D2FC_HDR_VERSION;
d2fc->hdr.count = count; d2fc->hdr.count = count;

Просмотреть файл

@ -13,15 +13,12 @@
* to devices. * to devices.
*/ */
static inline void mb(void)
{
#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
/* Fast-BCR without checkpoint synchronization */ /* Fast-BCR without checkpoint synchronization */
asm volatile("bcr 14,0" : : : "memory"); #define mb() do { asm volatile("bcr 14,0" : : : "memory"); } while (0)
#else #else
asm volatile("bcr 15,0" : : : "memory"); #define mb() do { asm volatile("bcr 15,0" : : : "memory"); } while (0)
#endif #endif
}
#define rmb() mb() #define rmb() mb()
#define wmb() mb() #define wmb() mb()

Просмотреть файл

@ -2,7 +2,7 @@
#define _ASM_S390_CLP_H #define _ASM_S390_CLP_H
/* CLP common request & response block size */ /* CLP common request & response block size */
#define CLP_BLK_SIZE (PAGE_SIZE * 2) #define CLP_BLK_SIZE PAGE_SIZE
struct clp_req_hdr { struct clp_req_hdr {
u16 len; u16 len;

Просмотреть файл

@ -34,12 +34,12 @@
/* CPU measurement facility support */ /* CPU measurement facility support */
static inline int cpum_cf_avail(void) static inline int cpum_cf_avail(void)
{ {
return MACHINE_HAS_SPP && test_facility(67); return MACHINE_HAS_LPP && test_facility(67);
} }
static inline int cpum_sf_avail(void) static inline int cpum_sf_avail(void)
{ {
return MACHINE_HAS_SPP && test_facility(68); return MACHINE_HAS_LPP && test_facility(68);
} }

Просмотреть файл

@ -19,9 +19,11 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
} }
extern int dma_set_mask(struct device *dev, u64 mask); extern int dma_set_mask(struct device *dev, u64 mask);
extern int dma_is_consistent(struct device *dev, dma_addr_t dma_handle);
extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction); enum dma_data_direction direction)
{
}
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)

Просмотреть файл

@ -9,7 +9,7 @@
#include <uapi/asm/mman.h> #include <uapi/asm/mman.h>
#if !defined(__ASSEMBLY__) && defined(CONFIG_64BIT) #if !defined(__ASSEMBLY__) && defined(CONFIG_64BIT)
int s390_mmap_check(unsigned long addr, unsigned long len); int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags);
#define arch_mmap_check(addr,len,flags) s390_mmap_check(addr,len) #define arch_mmap_check(addr, len, flags) s390_mmap_check(addr, len, flags)
#endif #endif
#endif /* __S390_MMAN_H__ */ #endif /* __S390_MMAN_H__ */

Просмотреть файл

@ -154,28 +154,6 @@ static inline int page_reset_referenced(unsigned long addr)
#define _PAGE_FP_BIT 0x08 /* HW fetch protection bit */ #define _PAGE_FP_BIT 0x08 /* HW fetch protection bit */
#define _PAGE_ACC_BITS 0xf0 /* HW access control bits */ #define _PAGE_ACC_BITS 0xf0 /* HW access control bits */
/*
* Test and clear dirty bit in storage key.
* We can't clear the changed bit atomically. This is a potential
* race against modification of the referenced bit. This function
* should therefore only be called if it is not mapped in any
* address space.
*
* Note that the bit gets set whenever page content is changed. That means
* also when the page is modified by DMA or from inside the kernel.
*/
#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
static inline int page_test_and_clear_dirty(unsigned long pfn, int mapped)
{
unsigned char skey;
skey = page_get_storage_key(pfn << PAGE_SHIFT);
if (!(skey & _PAGE_CHANGED))
return 0;
page_set_storage_key(pfn << PAGE_SHIFT, skey & ~_PAGE_CHANGED, mapped);
return 1;
}
/* /*
* Test and clear referenced bit in storage key. * Test and clear referenced bit in storage key.
*/ */

Просмотреть файл

@ -160,9 +160,14 @@ void zpci_teardown_msi_irq(struct zpci_dev *, struct msi_desc *);
int zpci_msihash_init(void); int zpci_msihash_init(void);
void zpci_msihash_exit(void); void zpci_msihash_exit(void);
#ifdef CONFIG_PCI
/* Error handling and recovery */ /* Error handling and recovery */
void zpci_event_error(void *); void zpci_event_error(void *);
void zpci_event_availability(void *); void zpci_event_availability(void *);
#else /* CONFIG_PCI */
static inline void zpci_event_error(void *e) {}
static inline void zpci_event_availability(void *e) {}
#endif /* CONFIG_PCI */
/* Helpers */ /* Helpers */
struct zpci_dev *get_zdev(struct pci_dev *); struct zpci_dev *get_zdev(struct pci_dev *);
@ -180,8 +185,10 @@ void zpci_dma_exit(void);
/* Hotplug */ /* Hotplug */
extern struct mutex zpci_list_lock; extern struct mutex zpci_list_lock;
extern struct list_head zpci_list; extern struct list_head zpci_list;
extern struct pci_hp_callback_ops hotplug_ops; extern unsigned int s390_pci_probe;
extern unsigned int pci_probe;
void zpci_register_hp_ops(struct pci_hp_callback_ops *);
void zpci_deregister_hp_ops(void);
/* FMB */ /* FMB */
int zpci_fmb_enable_device(struct zpci_dev *); int zpci_fmb_enable_device(struct zpci_dev *);

Просмотреть файл

@ -29,6 +29,7 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm_types.h> #include <linux/mm_types.h>
#include <linux/page-flags.h>
#include <asm/bug.h> #include <asm/bug.h>
#include <asm/page.h> #include <asm/page.h>
@ -221,13 +222,15 @@ extern unsigned long MODULES_END;
/* Software bits in the page table entry */ /* Software bits in the page table entry */
#define _PAGE_SWT 0x001 /* SW pte type bit t */ #define _PAGE_SWT 0x001 /* SW pte type bit t */
#define _PAGE_SWX 0x002 /* SW pte type bit x */ #define _PAGE_SWX 0x002 /* SW pte type bit x */
#define _PAGE_SWC 0x004 /* SW pte changed bit (for KVM) */ #define _PAGE_SWC 0x004 /* SW pte changed bit */
#define _PAGE_SWR 0x008 /* SW pte referenced bit (for KVM) */ #define _PAGE_SWR 0x008 /* SW pte referenced bit */
#define _PAGE_SPECIAL 0x010 /* SW associated with special page */ #define _PAGE_SWW 0x010 /* SW pte write bit */
#define _PAGE_SPECIAL 0x020 /* SW associated with special page */
#define __HAVE_ARCH_PTE_SPECIAL #define __HAVE_ARCH_PTE_SPECIAL
/* Set of bits not changed in pte_modify */ /* Set of bits not changed in pte_modify */
#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL | _PAGE_SWC | _PAGE_SWR) #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL | _PAGE_CO | \
_PAGE_SWC | _PAGE_SWR)
/* Six different types of pages. */ /* Six different types of pages. */
#define _PAGE_TYPE_EMPTY 0x400 #define _PAGE_TYPE_EMPTY 0x400
@ -321,6 +324,7 @@ extern unsigned long MODULES_END;
/* 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_RO 0x200 /* region protection bit */
#define _REGION_ENTRY_INV 0x20 /* invalid region table entry */ #define _REGION_ENTRY_INV 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 */
#define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */ #define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */
@ -382,9 +386,11 @@ extern unsigned long MODULES_END;
*/ */
#define PAGE_NONE __pgprot(_PAGE_TYPE_NONE) #define PAGE_NONE __pgprot(_PAGE_TYPE_NONE)
#define PAGE_RO __pgprot(_PAGE_TYPE_RO) #define PAGE_RO __pgprot(_PAGE_TYPE_RO)
#define PAGE_RW __pgprot(_PAGE_TYPE_RW) #define PAGE_RW __pgprot(_PAGE_TYPE_RO | _PAGE_SWW)
#define PAGE_RWC __pgprot(_PAGE_TYPE_RW | _PAGE_SWW | _PAGE_SWC)
#define PAGE_KERNEL PAGE_RW #define PAGE_KERNEL PAGE_RWC
#define PAGE_SHARED PAGE_KERNEL
#define PAGE_COPY PAGE_RO #define PAGE_COPY PAGE_RO
/* /*
@ -631,23 +637,23 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
/* Clear page changed & referenced bit in the storage key */ /* Clear page changed & referenced bit in the storage key */
if (bits & _PAGE_CHANGED) if (bits & _PAGE_CHANGED)
page_set_storage_key(address, skey ^ bits, 1); page_set_storage_key(address, skey ^ bits, 0);
else if (bits) else if (bits)
page_reset_referenced(address); page_reset_referenced(address);
/* Transfer page changed & referenced bit to guest bits in pgste */ /* Transfer page changed & referenced bit to guest bits in pgste */
pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */ pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */
/* Get host changed & referenced bits from pgste */ /* Get host changed & referenced bits from pgste */
bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52; bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52;
/* Clear host bits in pgste. */ /* Transfer page changed & referenced bit to kvm user bits */
pgste_val(pgste) |= bits << 45; /* KVM_UR_BIT & KVM_UC_BIT */
/* Clear relevant host bits in pgste. */
pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT); pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT);
pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT); pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT);
/* Copy page access key and fetch protection bit to pgste */ /* Copy page access key and fetch protection bit to pgste */
pgste_val(pgste) |= pgste_val(pgste) |=
(unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; (unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
/* Transfer changed and referenced to kvm user bits */ /* Transfer referenced bit to pte */
pgste_val(pgste) |= bits << 45; /* KVM_UR_BIT & KVM_UC_BIT */ pte_val(*ptep) |= (bits & _PAGE_REFERENCED) << 1;
/* Transfer changed & referenced to pte sofware bits */
pte_val(*ptep) |= bits << 1; /* _PAGE_SWR & _PAGE_SWC */
#endif #endif
return pgste; return pgste;
@ -660,20 +666,25 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
if (!pte_present(*ptep)) if (!pte_present(*ptep))
return pgste; return pgste;
/* Get referenced bit from storage key */
young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK); young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
/* Transfer page referenced bit to pte software bit (host view) */ if (young)
if (young || (pgste_val(pgste) & RCP_HR_BIT)) pgste_val(pgste) |= RCP_GR_BIT;
/* Get host referenced bit from pgste */
if (pgste_val(pgste) & RCP_HR_BIT) {
pgste_val(pgste) &= ~RCP_HR_BIT;
young = 1;
}
/* Transfer referenced bit to kvm user bits and pte */
if (young) {
pgste_val(pgste) |= KVM_UR_BIT;
pte_val(*ptep) |= _PAGE_SWR; pte_val(*ptep) |= _PAGE_SWR;
/* Clear host referenced bit in pgste. */ }
pgste_val(pgste) &= ~RCP_HR_BIT;
/* Transfer page referenced bit to guest bit in pgste */
pgste_val(pgste) |= (unsigned long) young << 50; /* set RCP_GR_BIT */
#endif #endif
return pgste; return pgste;
} }
static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry) static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry)
{ {
#ifdef CONFIG_PGSTE #ifdef CONFIG_PGSTE
unsigned long address; unsigned long address;
@ -687,10 +698,23 @@ static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry)
/* Set page access key and fetch protection bit from pgste */ /* Set page access key and fetch protection bit from pgste */
nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56; nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56;
if (okey != nkey) if (okey != nkey)
page_set_storage_key(address, nkey, 1); page_set_storage_key(address, nkey, 0);
#endif #endif
} }
static inline void pgste_set_pte(pte_t *ptep, pte_t entry)
{
if (!MACHINE_HAS_ESOP && (pte_val(entry) & _PAGE_SWW)) {
/*
* Without enhanced suppression-on-protection force
* the dirty bit on for all writable ptes.
*/
pte_val(entry) |= _PAGE_SWC;
pte_val(entry) &= ~_PAGE_RO;
}
*ptep = entry;
}
/** /**
* struct gmap_struct - guest address space * struct gmap_struct - guest address space
* @mm: pointer to the parent mm_struct * @mm: pointer to the parent mm_struct
@ -749,11 +773,14 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
if (mm_has_pgste(mm)) { if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep); pgste = pgste_get_lock(ptep);
pgste_set_pte(ptep, pgste, entry); pgste_set_key(ptep, pgste, entry);
*ptep = entry; pgste_set_pte(ptep, entry);
pgste_set_unlock(ptep, pgste); pgste_set_unlock(ptep, pgste);
} else } else {
if (!(pte_val(entry) & _PAGE_INVALID) && MACHINE_HAS_EDAT1)
pte_val(entry) |= _PAGE_CO;
*ptep = entry; *ptep = entry;
}
} }
/* /*
@ -762,16 +789,12 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
*/ */
static inline int pte_write(pte_t pte) static inline int pte_write(pte_t pte)
{ {
return (pte_val(pte) & _PAGE_RO) == 0; return (pte_val(pte) & _PAGE_SWW) != 0;
} }
static inline int pte_dirty(pte_t pte) static inline int pte_dirty(pte_t pte)
{ {
#ifdef CONFIG_PGSTE return (pte_val(pte) & _PAGE_SWC) != 0;
if (pte_val(pte) & _PAGE_SWC)
return 1;
#endif
return 0;
} }
static inline int pte_young(pte_t pte) static inline int pte_young(pte_t pte)
@ -821,11 +844,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);
if ((pte_val(pte) & _PAGE_SWC) && (pte_val(pte) & _PAGE_SWW))
pte_val(pte) &= ~_PAGE_RO;
return pte; return pte;
} }
static inline pte_t pte_wrprotect(pte_t pte) static inline pte_t pte_wrprotect(pte_t pte)
{ {
pte_val(pte) &= ~_PAGE_SWW;
/* Do not clobber _PAGE_TYPE_NONE pages! */ /* Do not clobber _PAGE_TYPE_NONE pages! */
if (!(pte_val(pte) & _PAGE_INVALID)) if (!(pte_val(pte) & _PAGE_INVALID))
pte_val(pte) |= _PAGE_RO; pte_val(pte) |= _PAGE_RO;
@ -834,20 +860,26 @@ static inline pte_t pte_wrprotect(pte_t pte)
static inline pte_t pte_mkwrite(pte_t pte) static inline pte_t pte_mkwrite(pte_t pte)
{ {
pte_val(pte) &= ~_PAGE_RO; pte_val(pte) |= _PAGE_SWW;
if (pte_val(pte) & _PAGE_SWC)
pte_val(pte) &= ~_PAGE_RO;
return pte; return pte;
} }
static inline pte_t pte_mkclean(pte_t pte) static inline pte_t pte_mkclean(pte_t pte)
{ {
#ifdef CONFIG_PGSTE
pte_val(pte) &= ~_PAGE_SWC; pte_val(pte) &= ~_PAGE_SWC;
#endif /* Do not clobber _PAGE_TYPE_NONE pages! */
if (!(pte_val(pte) & _PAGE_INVALID))
pte_val(pte) |= _PAGE_RO;
return pte; return pte;
} }
static inline pte_t pte_mkdirty(pte_t pte) static inline pte_t pte_mkdirty(pte_t pte)
{ {
pte_val(pte) |= _PAGE_SWC;
if (pte_val(pte) & _PAGE_SWW)
pte_val(pte) &= ~_PAGE_RO;
return pte; return pte;
} }
@ -885,10 +917,10 @@ static inline pte_t pte_mkhuge(pte_t pte)
pte_val(pte) |= _SEGMENT_ENTRY_INV; pte_val(pte) |= _SEGMENT_ENTRY_INV;
} }
/* /*
* Clear SW pte bits SWT and SWX, there are no SW bits in a segment * Clear SW pte bits, there are no SW bits in a segment table entry.
* table entry.
*/ */
pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX); pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX | _PAGE_SWC |
_PAGE_SWR | _PAGE_SWW);
/* /*
* Also set the change-override bit because we don't need dirty bit * Also set the change-override bit because we don't need dirty bit
* tracking for hugetlbfs pages. * tracking for hugetlbfs pages.
@ -1040,9 +1072,11 @@ static inline void ptep_modify_prot_commit(struct mm_struct *mm,
unsigned long address, unsigned long address,
pte_t *ptep, pte_t pte) pte_t *ptep, pte_t pte)
{ {
*ptep = pte; if (mm_has_pgste(mm)) {
if (mm_has_pgste(mm)) pgste_set_pte(ptep, pte);
pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE)); pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE));
} else
*ptep = pte;
} }
#define __HAVE_ARCH_PTEP_CLEAR_FLUSH #define __HAVE_ARCH_PTEP_CLEAR_FLUSH
@ -1110,10 +1144,13 @@ static inline pte_t ptep_set_wrprotect(struct mm_struct *mm,
if (!mm_exclusive(mm)) if (!mm_exclusive(mm))
__ptep_ipte(address, ptep); __ptep_ipte(address, ptep);
*ptep = pte_wrprotect(pte); pte = pte_wrprotect(pte);
if (mm_has_pgste(mm)) if (mm_has_pgste(mm)) {
pgste_set_pte(ptep, pte);
pgste_set_unlock(ptep, pgste); pgste_set_unlock(ptep, pgste);
} else
*ptep = pte;
} }
return pte; return pte;
} }
@ -1131,10 +1168,12 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma,
pgste = pgste_get_lock(ptep); pgste = pgste_get_lock(ptep);
__ptep_ipte(address, ptep); __ptep_ipte(address, ptep);
*ptep = entry;
if (mm_has_pgste(vma->vm_mm)) if (mm_has_pgste(vma->vm_mm)) {
pgste_set_pte(ptep, entry);
pgste_set_unlock(ptep, pgste); pgste_set_unlock(ptep, pgste);
} else
*ptep = entry;
return 1; return 1;
} }
@ -1152,8 +1191,13 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) static inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
{ {
unsigned long physpage = page_to_phys(page); unsigned long physpage = page_to_phys(page);
pte_t __pte = mk_pte_phys(physpage, pgprot);
return mk_pte_phys(physpage, pgprot); if ((pte_val(__pte) & _PAGE_SWW) && PageDirty(page)) {
pte_val(__pte) |= _PAGE_SWC;
pte_val(__pte) &= ~_PAGE_RO;
}
return __pte;
} }
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
@ -1245,6 +1289,8 @@ static inline int pmd_trans_splitting(pmd_t pmd)
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 (!(pmd_val(entry) & _SEGMENT_ENTRY_INV) && MACHINE_HAS_EDAT1)
pmd_val(entry) |= _SEGMENT_ENTRY_CO;
*pmdp = entry; *pmdp = entry;
} }

Просмотреть файл

@ -46,7 +46,6 @@ int sclp_cpu_deconfigure(u8 cpu);
void sclp_facilities_detect(void); void sclp_facilities_detect(void);
unsigned long long sclp_get_rnmax(void); unsigned long long sclp_get_rnmax(void);
unsigned long long sclp_get_rzm(void); unsigned long long sclp_get_rzm(void);
u8 sclp_get_fac85(void);
int sclp_sdias_blk_count(void); int sclp_sdias_blk_count(void);
int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); 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);

Просмотреть файл

@ -64,17 +64,18 @@ extern unsigned int s390_user_mode;
#define MACHINE_FLAG_VM (1UL << 0) #define MACHINE_FLAG_VM (1UL << 0)
#define MACHINE_FLAG_IEEE (1UL << 1) #define MACHINE_FLAG_IEEE (1UL << 1)
#define MACHINE_FLAG_CSP (1UL << 3) #define MACHINE_FLAG_CSP (1UL << 2)
#define MACHINE_FLAG_MVPG (1UL << 4) #define MACHINE_FLAG_MVPG (1UL << 3)
#define MACHINE_FLAG_DIAG44 (1UL << 5) #define MACHINE_FLAG_DIAG44 (1UL << 4)
#define MACHINE_FLAG_IDTE (1UL << 6) #define MACHINE_FLAG_IDTE (1UL << 5)
#define MACHINE_FLAG_DIAG9C (1UL << 7) #define MACHINE_FLAG_DIAG9C (1UL << 6)
#define MACHINE_FLAG_MVCOS (1UL << 8) #define MACHINE_FLAG_MVCOS (1UL << 7)
#define MACHINE_FLAG_KVM (1UL << 9) #define MACHINE_FLAG_KVM (1UL << 8)
#define MACHINE_FLAG_ESOP (1UL << 9)
#define MACHINE_FLAG_EDAT1 (1UL << 10) #define MACHINE_FLAG_EDAT1 (1UL << 10)
#define MACHINE_FLAG_EDAT2 (1UL << 11) #define MACHINE_FLAG_EDAT2 (1UL << 11)
#define MACHINE_FLAG_LPAR (1UL << 12) #define MACHINE_FLAG_LPAR (1UL << 12)
#define MACHINE_FLAG_SPP (1UL << 13) #define MACHINE_FLAG_LPP (1UL << 13)
#define MACHINE_FLAG_TOPOLOGY (1UL << 14) #define MACHINE_FLAG_TOPOLOGY (1UL << 14)
#define MACHINE_FLAG_TE (1UL << 15) #define MACHINE_FLAG_TE (1UL << 15)
#define MACHINE_FLAG_RRBM (1UL << 16) #define MACHINE_FLAG_RRBM (1UL << 16)
@ -84,6 +85,7 @@ extern unsigned int s390_user_mode;
#define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR) #define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR)
#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_PFMF MACHINE_HAS_EDAT1 #define MACHINE_HAS_PFMF MACHINE_HAS_EDAT1
#define MACHINE_HAS_HPAGE MACHINE_HAS_EDAT1 #define MACHINE_HAS_HPAGE MACHINE_HAS_EDAT1
@ -96,7 +98,7 @@ extern unsigned int s390_user_mode;
#define MACHINE_HAS_MVCOS (0) #define MACHINE_HAS_MVCOS (0)
#define MACHINE_HAS_EDAT1 (0) #define MACHINE_HAS_EDAT1 (0)
#define MACHINE_HAS_EDAT2 (0) #define MACHINE_HAS_EDAT2 (0)
#define MACHINE_HAS_SPP (0) #define MACHINE_HAS_LPP (0)
#define MACHINE_HAS_TOPOLOGY (0) #define MACHINE_HAS_TOPOLOGY (0)
#define MACHINE_HAS_TE (0) #define MACHINE_HAS_TE (0)
#define MACHINE_HAS_RRBM (0) #define MACHINE_HAS_RRBM (0)
@ -109,7 +111,7 @@ extern unsigned int s390_user_mode;
#define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS) #define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS)
#define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1) #define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1)
#define MACHINE_HAS_EDAT2 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT2) #define MACHINE_HAS_EDAT2 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT2)
#define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP) #define MACHINE_HAS_LPP (S390_lowcore.machine_flags & MACHINE_FLAG_LPP)
#define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
#define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE) #define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE)
#define MACHINE_HAS_RRBM (S390_lowcore.machine_flags & MACHINE_FLAG_RRBM) #define MACHINE_HAS_RRBM (S390_lowcore.machine_flags & MACHINE_FLAG_RRBM)

Просмотреть файл

@ -15,7 +15,7 @@
#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL #define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
/* Inline functions for clock register access. */ /* Inline functions for clock register access. */
static inline int set_clock(__u64 time) static inline int set_tod_clock(__u64 time)
{ {
int cc; int cc;
@ -27,7 +27,7 @@ static inline int set_clock(__u64 time)
return cc; return cc;
} }
static inline int store_clock(__u64 *time) static inline int store_tod_clock(__u64 *time)
{ {
int cc; int cc;
@ -71,7 +71,7 @@ static inline void local_tick_enable(unsigned long long comp)
typedef unsigned long long cycles_t; typedef unsigned long long cycles_t;
static inline unsigned long long get_clock(void) static inline unsigned long long get_tod_clock(void)
{ {
unsigned long long clk; unsigned long long clk;
@ -83,21 +83,21 @@ static inline unsigned long long get_clock(void)
return clk; return clk;
} }
static inline void get_clock_ext(char *clk) static inline void get_tod_clock_ext(char *clk)
{ {
asm volatile("stcke %0" : "=Q" (*clk) : : "cc"); asm volatile("stcke %0" : "=Q" (*clk) : : "cc");
} }
static inline unsigned long long get_clock_xt(void) static inline unsigned long long get_tod_clock_xt(void)
{ {
unsigned char clk[16]; unsigned char clk[16];
get_clock_ext(clk); get_tod_clock_ext(clk);
return *((unsigned long long *)&clk[1]); return *((unsigned long long *)&clk[1]);
} }
static inline cycles_t get_cycles(void) static inline cycles_t get_cycles(void)
{ {
return (cycles_t) get_clock() >> 2; return (cycles_t) get_tod_clock() >> 2;
} }
int get_sync_clock(unsigned long long *clock); int get_sync_clock(unsigned long long *clock);
@ -123,9 +123,9 @@ extern u64 sched_clock_base_cc;
* function, otherwise the returned value is not guaranteed to * function, otherwise the returned value is not guaranteed to
* be monotonic. * be monotonic.
*/ */
static inline unsigned long long get_clock_monotonic(void) static inline unsigned long long get_tod_clock_monotonic(void)
{ {
return get_clock_xt() - sched_clock_base_cc; return get_tod_clock_xt() - sched_clock_base_cc;
} }
/** /**

Просмотреть файл

@ -867,7 +867,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_clock(); active->id.stck = get_tod_clock();
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;

Просмотреть файл

@ -840,7 +840,6 @@ static struct insn opcode_b2[] = {
{ "stcke", 0x78, INSTR_S_RD }, { "stcke", 0x78, INSTR_S_RD },
{ "sacf", 0x79, INSTR_S_RD }, { "sacf", 0x79, INSTR_S_RD },
{ "stsi", 0x7d, INSTR_S_RD }, { "stsi", 0x7d, INSTR_S_RD },
{ "spp", 0x80, INSTR_S_RD },
{ "srnm", 0x99, INSTR_S_RD }, { "srnm", 0x99, INSTR_S_RD },
{ "stfpc", 0x9c, INSTR_S_RD }, { "stfpc", 0x9c, INSTR_S_RD },
{ "lfpc", 0x9d, INSTR_S_RD }, { "lfpc", 0x9d, INSTR_S_RD },

Просмотреть файл

@ -47,10 +47,10 @@ static void __init reset_tod_clock(void)
{ {
u64 time; u64 time;
if (store_clock(&time) == 0) if (store_tod_clock(&time) == 0)
return; return;
/* TOD clock not running. Set the clock to Unix Epoch. */ /* TOD clock not running. Set the clock to Unix Epoch. */
if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0) if (set_tod_clock(TOD_UNIX_EPOCH) != 0 || store_tod_clock(&time) != 0)
disabled_wait(0); disabled_wait(0);
sched_clock_base_cc = TOD_UNIX_EPOCH; sched_clock_base_cc = TOD_UNIX_EPOCH;
@ -173,7 +173,7 @@ static noinline __init void create_kernel_nss(void)
} }
/* re-initialize cputime accounting. */ /* re-initialize cputime accounting. */
sched_clock_base_cc = get_clock(); sched_clock_base_cc = get_tod_clock();
S390_lowcore.last_update_clock = sched_clock_base_cc; S390_lowcore.last_update_clock = sched_clock_base_cc;
S390_lowcore.last_update_timer = 0x7fffffffffffffffULL; S390_lowcore.last_update_timer = 0x7fffffffffffffffULL;
S390_lowcore.user_timer = 0; S390_lowcore.user_timer = 0;
@ -381,7 +381,7 @@ static __init void detect_machine_facilities(void)
if (test_facility(27)) if (test_facility(27))
S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
if (test_facility(40)) if (test_facility(40))
S390_lowcore.machine_flags |= MACHINE_FLAG_SPP; S390_lowcore.machine_flags |= MACHINE_FLAG_LPP;
if (test_facility(50) && test_facility(73)) if (test_facility(50) && test_facility(73))
S390_lowcore.machine_flags |= MACHINE_FLAG_TE; S390_lowcore.machine_flags |= MACHINE_FLAG_TE;
if (test_facility(66)) if (test_facility(66))

Просмотреть файл

@ -72,9 +72,9 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
#endif #endif
.endm .endm
.macro SPP newpp .macro LPP newpp
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_LPP
jz .+8 jz .+8
.insn s,0xb2800000,\newpp .insn s,0xb2800000,\newpp
#endif #endif
@ -96,7 +96,7 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
jhe .+22 jhe .+22
.endif .endif
lg %r9,BASED(.Lsie_loop) lg %r9,BASED(.Lsie_loop)
SPP BASED(.Lhost_id) # set host id LPP BASED(.Lhost_id) # set host id
#endif #endif
.endm .endm
@ -967,10 +967,10 @@ sie_loop:
lctlg %c1,%c1,__GMAP_ASCE(%r14) # load primary asce lctlg %c1,%c1,__GMAP_ASCE(%r14) # load primary asce
sie_gmap: sie_gmap:
lg %r14,__SF_EMPTY(%r15) # get control block pointer lg %r14,__SF_EMPTY(%r15) # get control block pointer
SPP __SF_EMPTY(%r15) # set guest id LPP __SF_EMPTY(%r15) # set guest id
sie 0(%r14) sie 0(%r14)
sie_done: sie_done:
SPP __SF_EMPTY+16(%r15) # set host id LPP __SF_EMPTY+16(%r15) # set host id
lg %r14,__LC_THREAD_INFO # pointer thread_info struct lg %r14,__LC_THREAD_INFO # pointer thread_info struct
sie_exit: sie_exit:
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce lctlg %c1,%c1,__LC_USER_ASCE # load primary asce

Просмотреть файл

@ -1414,6 +1414,16 @@ static struct kobj_attribute dump_type_attr =
static struct kset *dump_kset; static struct kset *dump_kset;
static void diag308_dump(void *dump_block)
{
diag308(DIAG308_SET, dump_block);
while (1) {
if (diag308(DIAG308_DUMP, NULL) != 0x302)
break;
udelay_simple(USEC_PER_SEC);
}
}
static void __dump_run(void *unused) static void __dump_run(void *unused)
{ {
struct ccw_dev_id devid; struct ccw_dev_id devid;
@ -1432,12 +1442,10 @@ static void __dump_run(void *unused)
__cpcmd(buf, NULL, 0, NULL); __cpcmd(buf, NULL, 0, NULL);
break; break;
case DUMP_METHOD_CCW_DIAG: case DUMP_METHOD_CCW_DIAG:
diag308(DIAG308_SET, dump_block_ccw); diag308_dump(dump_block_ccw);
diag308(DIAG308_DUMP, NULL);
break; break;
case DUMP_METHOD_FCP_DIAG: case DUMP_METHOD_FCP_DIAG:
diag308(DIAG308_SET, dump_block_fcp); diag308_dump(dump_block_fcp);
diag308(DIAG308_DUMP, NULL);
break; break;
default: default:
break; break;

Просмотреть файл

@ -65,8 +65,7 @@ void module_free(struct module *mod, void *module_region)
vfree(module_region); vfree(module_region);
} }
static void static void check_rela(Elf_Rela *rela, struct module *me)
check_rela(Elf_Rela *rela, struct module *me)
{ {
struct mod_arch_syminfo *info; struct mod_arch_syminfo *info;
@ -115,9 +114,8 @@ check_rela(Elf_Rela *rela, struct module *me)
* Account for GOT and PLT relocations. We can't add sections for * Account for GOT and PLT relocations. We can't add sections for
* got and plt but we can increase the core module size. * got and plt but we can increase the core module size.
*/ */
int int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, char *secstrings, struct module *me)
char *secstrings, struct module *me)
{ {
Elf_Shdr *symtab; Elf_Shdr *symtab;
Elf_Sym *symbols; Elf_Sym *symbols;
@ -179,13 +177,52 @@ module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
return 0; return 0;
} }
static int static int apply_rela_bits(Elf_Addr loc, Elf_Addr val,
apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, int sign, int bits, int shift)
struct module *me) {
unsigned long umax;
long min, max;
if (val & ((1UL << shift) - 1))
return -ENOEXEC;
if (sign) {
val = (Elf_Addr)(((long) val) >> shift);
min = -(1L << (bits - 1));
max = (1L << (bits - 1)) - 1;
if ((long) val < min || (long) val > max)
return -ENOEXEC;
} else {
val >>= shift;
umax = ((1UL << (bits - 1)) << 1) - 1;
if ((unsigned long) val > umax)
return -ENOEXEC;
}
if (bits == 8)
*(unsigned char *) loc = val;
else if (bits == 12)
*(unsigned short *) loc = (val & 0xfff) |
(*(unsigned short *) loc & 0xf000);
else if (bits == 16)
*(unsigned short *) loc = val;
else if (bits == 20)
*(unsigned int *) loc = (val & 0xfff) << 16 |
(val & 0xff000) >> 4 |
(*(unsigned int *) loc & 0xf00000ff);
else if (bits == 32)
*(unsigned int *) loc = val;
else if (bits == 64)
*(unsigned long *) loc = val;
return 0;
}
static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
const char *strtab, struct module *me)
{ {
struct mod_arch_syminfo *info; struct mod_arch_syminfo *info;
Elf_Addr loc, val; Elf_Addr loc, val;
int r_type, r_sym; int r_type, r_sym;
int rc;
/* This is where to make the change */ /* This is where to make the change */
loc = base + rela->r_offset; loc = base + rela->r_offset;
@ -197,6 +234,9 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
val = symtab[r_sym].st_value; val = symtab[r_sym].st_value;
switch (r_type) { switch (r_type) {
case R_390_NONE: /* No relocation. */
rc = 0;
break;
case R_390_8: /* Direct 8 bit. */ case R_390_8: /* Direct 8 bit. */
case R_390_12: /* Direct 12 bit. */ case R_390_12: /* Direct 12 bit. */
case R_390_16: /* Direct 16 bit. */ case R_390_16: /* Direct 16 bit. */
@ -205,20 +245,17 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
case R_390_64: /* Direct 64 bit. */ case R_390_64: /* Direct 64 bit. */
val += rela->r_addend; val += rela->r_addend;
if (r_type == R_390_8) if (r_type == R_390_8)
*(unsigned char *) loc = val; rc = apply_rela_bits(loc, val, 0, 8, 0);
else if (r_type == R_390_12) else if (r_type == R_390_12)
*(unsigned short *) loc = (val & 0xfff) | rc = apply_rela_bits(loc, val, 0, 12, 0);
(*(unsigned short *) loc & 0xf000);
else if (r_type == R_390_16) else if (r_type == R_390_16)
*(unsigned short *) loc = val; rc = apply_rela_bits(loc, val, 0, 16, 0);
else if (r_type == R_390_20) else if (r_type == R_390_20)
*(unsigned int *) loc = rc = apply_rela_bits(loc, val, 1, 20, 0);
(*(unsigned int *) loc & 0xf00000ff) |
(val & 0xfff) << 16 | (val & 0xff000) >> 4;
else if (r_type == R_390_32) else if (r_type == R_390_32)
*(unsigned int *) loc = val; rc = apply_rela_bits(loc, val, 0, 32, 0);
else if (r_type == R_390_64) else if (r_type == R_390_64)
*(unsigned long *) loc = val; rc = apply_rela_bits(loc, val, 0, 64, 0);
break; break;
case R_390_PC16: /* PC relative 16 bit. */ case R_390_PC16: /* PC relative 16 bit. */
case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */ case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */
@ -227,15 +264,15 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
case R_390_PC64: /* PC relative 64 bit. */ case R_390_PC64: /* PC relative 64 bit. */
val += rela->r_addend - loc; val += rela->r_addend - loc;
if (r_type == R_390_PC16) if (r_type == R_390_PC16)
*(unsigned short *) loc = val; rc = apply_rela_bits(loc, val, 1, 16, 0);
else if (r_type == R_390_PC16DBL) else if (r_type == R_390_PC16DBL)
*(unsigned short *) loc = val >> 1; rc = apply_rela_bits(loc, val, 1, 16, 1);
else if (r_type == R_390_PC32DBL) else if (r_type == R_390_PC32DBL)
*(unsigned int *) loc = val >> 1; rc = apply_rela_bits(loc, val, 1, 32, 1);
else if (r_type == R_390_PC32) else if (r_type == R_390_PC32)
*(unsigned int *) loc = val; rc = apply_rela_bits(loc, val, 1, 32, 0);
else if (r_type == R_390_PC64) else if (r_type == R_390_PC64)
*(unsigned long *) loc = val; rc = apply_rela_bits(loc, val, 1, 64, 0);
break; break;
case R_390_GOT12: /* 12 bit GOT offset. */ case R_390_GOT12: /* 12 bit GOT offset. */
case R_390_GOT16: /* 16 bit GOT offset. */ case R_390_GOT16: /* 16 bit GOT offset. */
@ -260,26 +297,24 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
val = info->got_offset + rela->r_addend; val = info->got_offset + rela->r_addend;
if (r_type == R_390_GOT12 || if (r_type == R_390_GOT12 ||
r_type == R_390_GOTPLT12) r_type == R_390_GOTPLT12)
*(unsigned short *) loc = (val & 0xfff) | rc = apply_rela_bits(loc, val, 0, 12, 0);
(*(unsigned short *) loc & 0xf000);
else if (r_type == R_390_GOT16 || else if (r_type == R_390_GOT16 ||
r_type == R_390_GOTPLT16) r_type == R_390_GOTPLT16)
*(unsigned short *) loc = val; rc = apply_rela_bits(loc, val, 0, 16, 0);
else if (r_type == R_390_GOT20 || else if (r_type == R_390_GOT20 ||
r_type == R_390_GOTPLT20) r_type == R_390_GOTPLT20)
*(unsigned int *) loc = rc = apply_rela_bits(loc, val, 1, 20, 0);
(*(unsigned int *) loc & 0xf00000ff) |
(val & 0xfff) << 16 | (val & 0xff000) >> 4;
else if (r_type == R_390_GOT32 || else if (r_type == R_390_GOT32 ||
r_type == R_390_GOTPLT32) r_type == R_390_GOTPLT32)
*(unsigned int *) loc = val; rc = apply_rela_bits(loc, val, 0, 32, 0);
else if (r_type == R_390_GOTENT ||
r_type == R_390_GOTPLTENT)
*(unsigned int *) loc =
(val + (Elf_Addr) me->module_core - loc) >> 1;
else if (r_type == R_390_GOT64 || else if (r_type == R_390_GOT64 ||
r_type == R_390_GOTPLT64) r_type == R_390_GOTPLT64)
*(unsigned long *) loc = val; rc = apply_rela_bits(loc, val, 0, 64, 0);
else if (r_type == R_390_GOTENT ||
r_type == R_390_GOTPLTENT) {
val += (Elf_Addr) me->module_core - loc;
rc = apply_rela_bits(loc, val, 1, 32, 1);
}
break; break;
case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */ case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */
case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */ case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */
@ -321,17 +356,17 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
val += rela->r_addend - loc; val += rela->r_addend - loc;
} }
if (r_type == R_390_PLT16DBL) if (r_type == R_390_PLT16DBL)
*(unsigned short *) loc = val >> 1; rc = apply_rela_bits(loc, val, 1, 16, 1);
else if (r_type == R_390_PLTOFF16) else if (r_type == R_390_PLTOFF16)
*(unsigned short *) loc = val; rc = apply_rela_bits(loc, val, 0, 16, 0);
else if (r_type == R_390_PLT32DBL) else if (r_type == R_390_PLT32DBL)
*(unsigned int *) loc = val >> 1; rc = apply_rela_bits(loc, val, 1, 32, 1);
else if (r_type == R_390_PLT32 || else if (r_type == R_390_PLT32 ||
r_type == R_390_PLTOFF32) r_type == R_390_PLTOFF32)
*(unsigned int *) loc = val; rc = apply_rela_bits(loc, val, 0, 32, 0);
else if (r_type == R_390_PLT64 || else if (r_type == R_390_PLT64 ||
r_type == R_390_PLTOFF64) r_type == R_390_PLTOFF64)
*(unsigned long *) loc = val; rc = apply_rela_bits(loc, val, 0, 64, 0);
break; break;
case R_390_GOTOFF16: /* 16 bit offset to GOT. */ case R_390_GOTOFF16: /* 16 bit offset to GOT. */
case R_390_GOTOFF32: /* 32 bit offset to GOT. */ case R_390_GOTOFF32: /* 32 bit offset to GOT. */
@ -339,20 +374,20 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
val = val + rela->r_addend - val = val + rela->r_addend -
((Elf_Addr) me->module_core + me->arch.got_offset); ((Elf_Addr) me->module_core + me->arch.got_offset);
if (r_type == R_390_GOTOFF16) if (r_type == R_390_GOTOFF16)
*(unsigned short *) loc = val; rc = apply_rela_bits(loc, val, 0, 16, 0);
else if (r_type == R_390_GOTOFF32) else if (r_type == R_390_GOTOFF32)
*(unsigned int *) loc = val; rc = apply_rela_bits(loc, val, 0, 32, 0);
else if (r_type == R_390_GOTOFF64) else if (r_type == R_390_GOTOFF64)
*(unsigned long *) loc = val; rc = apply_rela_bits(loc, val, 0, 64, 0);
break; break;
case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */ case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */ case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */
val = (Elf_Addr) me->module_core + me->arch.got_offset + val = (Elf_Addr) me->module_core + me->arch.got_offset +
rela->r_addend - loc; rela->r_addend - loc;
if (r_type == R_390_GOTPC) if (r_type == R_390_GOTPC)
*(unsigned int *) loc = val; rc = apply_rela_bits(loc, val, 1, 32, 0);
else if (r_type == R_390_GOTPCDBL) else if (r_type == R_390_GOTPCDBL)
*(unsigned int *) loc = val >> 1; rc = apply_rela_bits(loc, val, 1, 32, 1);
break; break;
case R_390_COPY: case R_390_COPY:
case R_390_GLOB_DAT: /* Create GOT entry. */ case R_390_GLOB_DAT: /* Create GOT entry. */
@ -360,19 +395,25 @@ apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
case R_390_RELATIVE: /* Adjust by program base. */ case R_390_RELATIVE: /* Adjust by program base. */
/* Only needed if we want to support loading of /* Only needed if we want to support loading of
modules linked with -shared. */ modules linked with -shared. */
break; return -ENOEXEC;
default: default:
printk(KERN_ERR "module %s: Unknown relocation: %u\n", printk(KERN_ERR "module %s: unknown relocation: %u\n",
me->name, r_type); me->name, r_type);
return -ENOEXEC; return -ENOEXEC;
} }
if (rc) {
printk(KERN_ERR "module %s: relocation error for symbol %s "
"(r_type %i, value 0x%lx)\n",
me->name, strtab + symtab[r_sym].st_name,
r_type, (unsigned long) val);
return rc;
}
return 0; return 0;
} }
int int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec,
unsigned int symindex, unsigned int relsec, struct module *me)
struct module *me)
{ {
Elf_Addr base; Elf_Addr base;
Elf_Sym *symtab; Elf_Sym *symtab;
@ -388,7 +429,7 @@ apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
n = sechdrs[relsec].sh_size / sizeof(Elf_Rela); n = sechdrs[relsec].sh_size / sizeof(Elf_Rela);
for (i = 0; i < n; i++, rela++) { for (i = 0; i < n; i++, rela++) {
rc = apply_rela(rela, base, symtab, me); rc = apply_rela(rela, base, symtab, strtab, me);
if (rc) if (rc)
return rc; return rc;
} }

Просмотреть файл

@ -293,7 +293,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
* retry this instruction. * retry this instruction.
*/ */
spin_lock(&ipd_lock); spin_lock(&ipd_lock);
tmp = get_clock(); tmp = get_tod_clock();
if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME) if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME)
ipd_count++; ipd_count++;
else else

Просмотреть файл

@ -367,13 +367,6 @@ static int __hw_perf_event_init(struct perf_event *event)
if (ev >= PERF_CPUM_CF_MAX_CTR) if (ev >= PERF_CPUM_CF_MAX_CTR)
return -EINVAL; return -EINVAL;
/* The CPU measurement counter facility does not have any interrupts
* to do sampling. Sampling must be provided by external means,
* for example, by timers.
*/
if (hwc->sample_period)
return -EINVAL;
/* Use the hardware perf event structure to store the counter number /* Use the hardware perf event structure to store the counter number
* in 'config' member and the counter set to which the counter belongs * in 'config' member and the counter set to which the counter belongs
* in the 'config_base'. The counter set (config_base) is then used * in the 'config_base'. The counter set (config_base) is then used
@ -418,6 +411,12 @@ static int cpumf_pmu_event_init(struct perf_event *event)
case PERF_TYPE_HARDWARE: case PERF_TYPE_HARDWARE:
case PERF_TYPE_HW_CACHE: case PERF_TYPE_HW_CACHE:
case PERF_TYPE_RAW: case PERF_TYPE_RAW:
/* The CPU measurement counter facility does not have overflow
* interrupts to do sampling. Sampling must be provided by
* external means, for example, by timers.
*/
if (is_sampling_event(event))
return -ENOENT;
err = __hw_perf_event_init(event); err = __hw_perf_event_init(event);
break; break;
default: default:

Просмотреть файл

@ -365,16 +365,16 @@ void smp_emergency_stop(cpumask_t *cpumask)
u64 end; u64 end;
int cpu; int cpu;
end = get_clock() + (1000000UL << 12); end = get_tod_clock() + (1000000UL << 12);
for_each_cpu(cpu, cpumask) { for_each_cpu(cpu, cpumask) {
struct pcpu *pcpu = pcpu_devices + cpu; struct pcpu *pcpu = pcpu_devices + cpu;
set_bit(ec_stop_cpu, &pcpu->ec_mask); set_bit(ec_stop_cpu, &pcpu->ec_mask);
while (__pcpu_sigp(pcpu->address, SIGP_EMERGENCY_SIGNAL, while (__pcpu_sigp(pcpu->address, SIGP_EMERGENCY_SIGNAL,
0, NULL) == SIGP_CC_BUSY && 0, NULL) == SIGP_CC_BUSY &&
get_clock() < end) get_tod_clock() < end)
cpu_relax(); cpu_relax();
} }
while (get_clock() < end) { while (get_tod_clock() < end) {
for_each_cpu(cpu, cpumask) for_each_cpu(cpu, cpumask)
if (pcpu_stopped(pcpu_devices + cpu)) if (pcpu_stopped(pcpu_devices + cpu))
cpumask_clear_cpu(cpu, cpumask); cpumask_clear_cpu(cpu, cpumask);
@ -694,7 +694,7 @@ static void __init smp_detect_cpus(void)
*/ */
static void __cpuinit smp_start_secondary(void *cpuvoid) static void __cpuinit smp_start_secondary(void *cpuvoid)
{ {
S390_lowcore.last_update_clock = get_clock(); S390_lowcore.last_update_clock = get_tod_clock();
S390_lowcore.restart_stack = (unsigned long) restart_stack; S390_lowcore.restart_stack = (unsigned long) restart_stack;
S390_lowcore.restart_fn = (unsigned long) do_restart; S390_lowcore.restart_fn = (unsigned long) do_restart;
S390_lowcore.restart_data = 0; S390_lowcore.restart_data = 0;
@ -947,7 +947,7 @@ static ssize_t show_idle_time(struct device *dev,
unsigned int sequence; unsigned int sequence;
do { do {
now = get_clock(); now = get_tod_clock();
sequence = ACCESS_ONCE(idle->sequence); sequence = ACCESS_ONCE(idle->sequence);
idle_time = ACCESS_ONCE(idle->idle_time); idle_time = ACCESS_ONCE(idle->idle_time);
idle_enter = ACCESS_ONCE(idle->clock_idle_enter); idle_enter = ACCESS_ONCE(idle->clock_idle_enter);

Просмотреть файл

@ -63,7 +63,7 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators);
*/ */
unsigned long long notrace __kprobes sched_clock(void) unsigned long long notrace __kprobes sched_clock(void)
{ {
return tod_to_ns(get_clock_monotonic()); return tod_to_ns(get_tod_clock_monotonic());
} }
/* /*
@ -194,7 +194,7 @@ static void stp_reset(void);
void read_persistent_clock(struct timespec *ts) void read_persistent_clock(struct timespec *ts)
{ {
tod_to_timeval(get_clock() - TOD_UNIX_EPOCH, ts); tod_to_timeval(get_tod_clock() - TOD_UNIX_EPOCH, ts);
} }
void read_boot_clock(struct timespec *ts) void read_boot_clock(struct timespec *ts)
@ -204,7 +204,7 @@ void read_boot_clock(struct timespec *ts)
static cycle_t read_tod_clock(struct clocksource *cs) static cycle_t read_tod_clock(struct clocksource *cs)
{ {
return get_clock(); return get_tod_clock();
} }
static struct clocksource clocksource_tod = { static struct clocksource clocksource_tod = {
@ -342,7 +342,7 @@ int get_sync_clock(unsigned long long *clock)
sw_ptr = &get_cpu_var(clock_sync_word); sw_ptr = &get_cpu_var(clock_sync_word);
sw0 = atomic_read(sw_ptr); sw0 = atomic_read(sw_ptr);
*clock = get_clock(); *clock = get_tod_clock();
sw1 = atomic_read(sw_ptr); sw1 = atomic_read(sw_ptr);
put_cpu_var(clock_sync_word); put_cpu_var(clock_sync_word);
if (sw0 == sw1 && (sw0 & 0x80000000U)) if (sw0 == sw1 && (sw0 & 0x80000000U))
@ -486,7 +486,7 @@ static void etr_reset(void)
.p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0, .p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0,
.es = 0, .sl = 0 }; .es = 0, .sl = 0 };
if (etr_setr(&etr_eacr) == 0) { if (etr_setr(&etr_eacr) == 0) {
etr_tolec = get_clock(); etr_tolec = get_tod_clock();
set_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags); set_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags);
if (etr_port0_online && etr_port1_online) if (etr_port0_online && etr_port1_online)
set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); set_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
@ -768,8 +768,8 @@ static int etr_sync_clock(void *data)
__ctl_set_bit(14, 21); __ctl_set_bit(14, 21);
__ctl_set_bit(0, 29); __ctl_set_bit(0, 29);
clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32; clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32;
old_clock = get_clock(); old_clock = get_tod_clock();
if (set_clock(clock) == 0) { if (set_tod_clock(clock) == 0) {
__udelay(1); /* Wait for the clock to start. */ __udelay(1); /* Wait for the clock to start. */
__ctl_clear_bit(0, 29); __ctl_clear_bit(0, 29);
__ctl_clear_bit(14, 21); __ctl_clear_bit(14, 21);
@ -845,7 +845,7 @@ static struct etr_eacr etr_handle_events(struct etr_eacr eacr)
* assume that this can have caused an stepping * assume that this can have caused an stepping
* port switch. * port switch.
*/ */
etr_tolec = get_clock(); etr_tolec = get_tod_clock();
eacr.p0 = etr_port0_online; eacr.p0 = etr_port0_online;
if (!eacr.p0) if (!eacr.p0)
eacr.e0 = 0; eacr.e0 = 0;
@ -858,7 +858,7 @@ static struct etr_eacr etr_handle_events(struct etr_eacr eacr)
* assume that this can have caused an stepping * assume that this can have caused an stepping
* port switch. * port switch.
*/ */
etr_tolec = get_clock(); etr_tolec = get_tod_clock();
eacr.p1 = etr_port1_online; eacr.p1 = etr_port1_online;
if (!eacr.p1) if (!eacr.p1)
eacr.e1 = 0; eacr.e1 = 0;
@ -974,7 +974,7 @@ static void etr_update_eacr(struct etr_eacr eacr)
etr_eacr = eacr; etr_eacr = eacr;
etr_setr(&etr_eacr); etr_setr(&etr_eacr);
if (dp_changed) if (dp_changed)
etr_tolec = get_clock(); etr_tolec = get_tod_clock();
} }
/* /*
@ -1012,7 +1012,7 @@ static void etr_work_fn(struct work_struct *work)
/* Store aib to get the current ETR status word. */ /* Store aib to get the current ETR status word. */
BUG_ON(etr_stetr(&aib) != 0); BUG_ON(etr_stetr(&aib) != 0);
etr_port0.esw = etr_port1.esw = aib.esw; /* Copy status word. */ etr_port0.esw = etr_port1.esw = aib.esw; /* Copy status word. */
now = get_clock(); now = get_tod_clock();
/* /*
* Update the port information if the last stepping port change * Update the port information if the last stepping port change
@ -1537,10 +1537,10 @@ static int stp_sync_clock(void *data)
if (stp_info.todoff[0] || stp_info.todoff[1] || if (stp_info.todoff[0] || stp_info.todoff[1] ||
stp_info.todoff[2] || stp_info.todoff[3] || stp_info.todoff[2] || stp_info.todoff[3] ||
stp_info.tmd != 2) { stp_info.tmd != 2) {
old_clock = get_clock(); old_clock = get_tod_clock();
rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0); rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0);
if (rc == 0) { if (rc == 0) {
delta = adjust_time(old_clock, get_clock(), 0); delta = adjust_time(old_clock, get_tod_clock(), 0);
fixup_clock_comparator(delta); fixup_clock_comparator(delta);
rc = chsc_sstpi(stp_page, &stp_info, rc = chsc_sstpi(stp_page, &stp_info,
sizeof(struct stp_sstpi)); sizeof(struct stp_sstpi));

Просмотреть файл

@ -75,6 +75,10 @@ SECTIONS
EXIT_TEXT EXIT_TEXT
} }
.exit.data : {
EXIT_DATA
}
/* early.c uses stsi, which requires page aligned data. */ /* early.c uses stsi, which requires page aligned data. */
. = ALIGN(PAGE_SIZE); . = ALIGN(PAGE_SIZE);
INIT_DATA_SECTION(0x100) INIT_DATA_SECTION(0x100)

Просмотреть файл

@ -191,7 +191,7 @@ cputime64_t s390_get_idle_time(int cpu)
unsigned int sequence; unsigned int sequence;
do { do {
now = get_clock(); now = get_tod_clock();
sequence = ACCESS_ONCE(idle->sequence); sequence = ACCESS_ONCE(idle->sequence);
idle_enter = ACCESS_ONCE(idle->clock_idle_enter); idle_enter = ACCESS_ONCE(idle->clock_idle_enter);
idle_exit = ACCESS_ONCE(idle->clock_idle_exit); idle_exit = ACCESS_ONCE(idle->clock_idle_exit);

Просмотреть файл

@ -362,7 +362,7 @@ static int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
} }
if ((!rc) && (vcpu->arch.sie_block->ckc < if ((!rc) && (vcpu->arch.sie_block->ckc <
get_clock() + vcpu->arch.sie_block->epoch)) { get_tod_clock() + vcpu->arch.sie_block->epoch)) {
if ((!psw_extint_disabled(vcpu)) && if ((!psw_extint_disabled(vcpu)) &&
(vcpu->arch.sie_block->gcr[0] & 0x800ul)) (vcpu->arch.sie_block->gcr[0] & 0x800ul))
rc = 1; rc = 1;
@ -402,7 +402,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
goto no_timer; goto no_timer;
} }
now = get_clock() + vcpu->arch.sie_block->epoch; now = get_tod_clock() + vcpu->arch.sie_block->epoch;
if (vcpu->arch.sie_block->ckc < now) { if (vcpu->arch.sie_block->ckc < now) {
__unset_cpu_idle(vcpu); __unset_cpu_idle(vcpu);
return 0; return 0;
@ -492,7 +492,7 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
} }
if ((vcpu->arch.sie_block->ckc < if ((vcpu->arch.sie_block->ckc <
get_clock() + vcpu->arch.sie_block->epoch)) get_tod_clock() + vcpu->arch.sie_block->epoch))
__try_deliver_ckc_interrupt(vcpu); __try_deliver_ckc_interrupt(vcpu);
if (atomic_read(&fi->active)) { if (atomic_read(&fi->active)) {

Просмотреть файл

@ -147,7 +147,7 @@ int kvm_dev_ioctl_check_extension(long ext)
r = KVM_MAX_VCPUS; r = KVM_MAX_VCPUS;
break; break;
case KVM_CAP_S390_COW: case KVM_CAP_S390_COW:
r = sclp_get_fac85() & 0x2; r = MACHINE_HAS_ESOP;
break; break;
default: default:
r = 0; r = 0;

Просмотреть файл

@ -32,7 +32,7 @@ static void __udelay_disabled(unsigned long long usecs)
unsigned long cr0, cr6, new; unsigned long cr0, cr6, new;
u64 clock_saved, end; u64 clock_saved, end;
end = get_clock() + (usecs << 12); end = get_tod_clock() + (usecs << 12);
clock_saved = local_tick_disable(); clock_saved = local_tick_disable();
__ctl_store(cr0, 0, 0); __ctl_store(cr0, 0, 0);
__ctl_store(cr6, 6, 6); __ctl_store(cr6, 6, 6);
@ -45,7 +45,7 @@ static void __udelay_disabled(unsigned long long usecs)
set_clock_comparator(end); set_clock_comparator(end);
vtime_stop_cpu(); vtime_stop_cpu();
local_irq_disable(); local_irq_disable();
} while (get_clock() < end); } while (get_tod_clock() < end);
lockdep_on(); lockdep_on();
__ctl_load(cr0, 0, 0); __ctl_load(cr0, 0, 0);
__ctl_load(cr6, 6, 6); __ctl_load(cr6, 6, 6);
@ -56,7 +56,7 @@ static void __udelay_enabled(unsigned long long usecs)
{ {
u64 clock_saved, end; u64 clock_saved, end;
end = get_clock() + (usecs << 12); end = get_tod_clock() + (usecs << 12);
do { do {
clock_saved = 0; clock_saved = 0;
if (end < S390_lowcore.clock_comparator) { if (end < S390_lowcore.clock_comparator) {
@ -67,7 +67,7 @@ static void __udelay_enabled(unsigned long long usecs)
local_irq_disable(); local_irq_disable();
if (clock_saved) if (clock_saved)
local_tick_enable(clock_saved); local_tick_enable(clock_saved);
} while (get_clock() < end); } while (get_tod_clock() < end);
} }
/* /*
@ -111,8 +111,8 @@ void udelay_simple(unsigned long long usecs)
{ {
u64 end; u64 end;
end = get_clock() + (usecs << 12); end = get_tod_clock() + (usecs << 12);
while (get_clock() < end) while (get_tod_clock() < end)
cpu_relax(); cpu_relax();
} }
@ -122,10 +122,10 @@ void __ndelay(unsigned long long nsecs)
nsecs <<= 9; nsecs <<= 9;
do_div(nsecs, 125); do_div(nsecs, 125);
end = get_clock() + nsecs; end = get_tod_clock() + nsecs;
if (nsecs & ~0xfffUL) if (nsecs & ~0xfffUL)
__udelay(nsecs >> 12); __udelay(nsecs >> 12);
while (get_clock() < end) while (get_tod_clock() < end)
barrier(); barrier();
} }
EXPORT_SYMBOL(__ndelay); EXPORT_SYMBOL(__ndelay);

Просмотреть файл

@ -50,7 +50,7 @@ static __always_inline unsigned long follow_table(struct mm_struct *mm,
ptep = pte_offset_map(pmd, addr); ptep = pte_offset_map(pmd, addr);
if (!pte_present(*ptep)) if (!pte_present(*ptep))
return -0x11UL; return -0x11UL;
if (write && !pte_write(*ptep)) if (write && (!pte_write(*ptep) || !pte_dirty(*ptep)))
return -0x04UL; return -0x04UL;
return (pte_val(*ptep) & PAGE_MASK) + (addr & ~PAGE_MASK); return (pte_val(*ptep) & PAGE_MASK) + (addr & ~PAGE_MASK);

Просмотреть файл

@ -101,12 +101,15 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
#else #else
int s390_mmap_check(unsigned long addr, unsigned long len) int s390_mmap_check(unsigned long addr, unsigned long len, unsigned long flags)
{ {
int rc; int rc;
if (!is_compat_task() && if (is_compat_task() || (TASK_SIZE >= (1UL << 53)))
len >= TASK_SIZE && TASK_SIZE < (1UL << 53)) { return 0;
if (!(flags & MAP_FIXED))
addr = 0;
if ((addr + len) >= TASK_SIZE) {
rc = crst_table_upgrade(current->mm, 1UL << 53); rc = crst_table_upgrade(current->mm, 1UL << 53);
if (rc) if (rc)
return rc; return rc;

Просмотреть файл

@ -127,7 +127,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
pte_val(*pte) = _PAGE_TYPE_EMPTY; pte_val(*pte) = _PAGE_TYPE_EMPTY;
continue; continue;
} }
*pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW)); pte_val(*pte) = __pa(address);
} }
} }

Просмотреть файл

@ -85,11 +85,9 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
pud_t *pu_dir; pud_t *pu_dir;
pmd_t *pm_dir; pmd_t *pm_dir;
pte_t *pt_dir; pte_t *pt_dir;
pte_t pte;
int ret = -ENOMEM; int ret = -ENOMEM;
while (address < end) { while (address < end) {
pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0));
pg_dir = pgd_offset_k(address); pg_dir = pgd_offset_k(address);
if (pgd_none(*pg_dir)) { if (pgd_none(*pg_dir)) {
pu_dir = vmem_pud_alloc(); pu_dir = vmem_pud_alloc();
@ -101,9 +99,9 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
#if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC)
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)) {
pte_val(pte) |= _REGION3_ENTRY_LARGE; pud_val(*pu_dir) = __pa(address) |
pte_val(pte) |= _REGION_ENTRY_TYPE_R3; _REGION_ENTRY_TYPE_R3 | _REGION3_ENTRY_LARGE |
pud_val(*pu_dir) = pte_val(pte); (ro ? _REGION_ENTRY_RO : 0);
address += PUD_SIZE; address += PUD_SIZE;
continue; continue;
} }
@ -118,8 +116,9 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
#if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC)
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)) {
pte_val(pte) |= _SEGMENT_ENTRY_LARGE; pmd_val(*pm_dir) = __pa(address) |
pmd_val(*pm_dir) = pte_val(pte); _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE |
(ro ? _SEGMENT_ENTRY_RO : 0);
address += PMD_SIZE; address += PMD_SIZE;
continue; continue;
} }
@ -132,7 +131,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
} }
pt_dir = pte_offset_kernel(pm_dir, address); pt_dir = pte_offset_kernel(pm_dir, address);
*pt_dir = pte; pte_val(*pt_dir) = __pa(address) | (ro ? _PAGE_RO : 0);
address += PAGE_SIZE; address += PAGE_SIZE;
} }
ret = 0; ret = 0;
@ -199,7 +198,6 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
pud_t *pu_dir; pud_t *pu_dir;
pmd_t *pm_dir; pmd_t *pm_dir;
pte_t *pt_dir; pte_t *pt_dir;
pte_t pte;
int ret = -ENOMEM; int ret = -ENOMEM;
start_addr = (unsigned long) start; start_addr = (unsigned long) start;
@ -237,9 +235,8 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, 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;
pte = mk_pte_phys(__pa(new_page), PAGE_RW); pmd_val(*pm_dir) = __pa(new_page) |
pte_val(pte) |= _SEGMENT_ENTRY_LARGE; _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE;
pmd_val(*pm_dir) = pte_val(pte);
address = (address + PMD_SIZE) & PMD_MASK; address = (address + PMD_SIZE) & PMD_MASK;
continue; continue;
} }
@ -260,8 +257,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
new_page =__pa(vmem_alloc_pages(0)); new_page =__pa(vmem_alloc_pages(0));
if (!new_page) if (!new_page)
goto out; goto out;
pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL); pte_val(*pt_dir) = __pa(new_page);
*pt_dir = pte;
} }
address += PAGE_SIZE; address += PAGE_SIZE;
} }

Просмотреть файл

@ -7,6 +7,7 @@
*/ */
#include <linux/moduleloader.h> #include <linux/moduleloader.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <linux/filter.h> #include <linux/filter.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/processor.h> #include <asm/processor.h>
@ -254,6 +255,8 @@ static void bpf_jit_noleaks(struct bpf_jit *jit, struct sock_filter *filter)
case BPF_S_ANC_HATYPE: case BPF_S_ANC_HATYPE:
case BPF_S_ANC_RXHASH: case BPF_S_ANC_RXHASH:
case BPF_S_ANC_CPU: case BPF_S_ANC_CPU:
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
case BPF_S_RET_K: case BPF_S_RET_K:
/* first instruction sets A register */ /* first instruction sets A register */
break; break;
@ -699,6 +702,24 @@ call_fn: /* lg %r1,<d(function)>(%r13) */
/* l %r5,<d(rxhash)>(%r2) */ /* l %r5,<d(rxhash)>(%r2) */
EMIT4_DISP(0x58502000, offsetof(struct sk_buff, rxhash)); EMIT4_DISP(0x58502000, offsetof(struct sk_buff, rxhash));
break; break;
case BPF_S_ANC_VLAN_TAG:
case BPF_S_ANC_VLAN_TAG_PRESENT:
BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2);
BUILD_BUG_ON(VLAN_TAG_PRESENT != 0x1000);
/* lhi %r5,0 */
EMIT4(0xa7580000);
/* icm %r5,3,<d(vlan_tci)>(%r2) */
EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, vlan_tci));
if (filter->code == BPF_S_ANC_VLAN_TAG) {
/* nill %r5,0xefff */
EMIT4_IMM(0xa5570000, ~VLAN_TAG_PRESENT);
} else {
/* nill %r5,0x1000 */
EMIT4_IMM(0xa5570000, VLAN_TAG_PRESENT);
/* srl %r5,12 */
EMIT4_DISP(0x88500000, 12);
}
break;
case BPF_S_ANC_CPU: /* A = smp_processor_id() */ case BPF_S_ANC_CPU: /* A = smp_processor_id() */
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* l %r5,<d(cpu_nr)> */ /* l %r5,<d(cpu_nr)> */

Просмотреть файл

@ -51,8 +51,7 @@ EXPORT_SYMBOL_GPL(zpci_list);
DEFINE_MUTEX(zpci_list_lock); DEFINE_MUTEX(zpci_list_lock);
EXPORT_SYMBOL_GPL(zpci_list_lock); EXPORT_SYMBOL_GPL(zpci_list_lock);
struct pci_hp_callback_ops hotplug_ops; static struct pci_hp_callback_ops *hotplug_ops;
EXPORT_SYMBOL_GPL(hotplug_ops);
static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES); static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES);
static DEFINE_SPINLOCK(zpci_domain_lock); static DEFINE_SPINLOCK(zpci_domain_lock);
@ -974,8 +973,8 @@ int zpci_create_device(struct zpci_dev *zdev)
mutex_lock(&zpci_list_lock); mutex_lock(&zpci_list_lock);
list_add_tail(&zdev->entry, &zpci_list); list_add_tail(&zdev->entry, &zpci_list);
if (hotplug_ops.create_slot) if (hotplug_ops)
hotplug_ops.create_slot(zdev); hotplug_ops->create_slot(zdev);
mutex_unlock(&zpci_list_lock); mutex_unlock(&zpci_list_lock);
if (zdev->state == ZPCI_FN_STATE_STANDBY) if (zdev->state == ZPCI_FN_STATE_STANDBY)
@ -989,8 +988,8 @@ int zpci_create_device(struct zpci_dev *zdev)
out_start: out_start:
mutex_lock(&zpci_list_lock); mutex_lock(&zpci_list_lock);
list_del(&zdev->entry); list_del(&zdev->entry);
if (hotplug_ops.remove_slot) if (hotplug_ops)
hotplug_ops.remove_slot(zdev); hotplug_ops->remove_slot(zdev);
mutex_unlock(&zpci_list_lock); mutex_unlock(&zpci_list_lock);
out_bus: out_bus:
zpci_free_domain(zdev); zpci_free_domain(zdev);
@ -1072,13 +1071,29 @@ static void zpci_mem_exit(void)
kmem_cache_destroy(zdev_fmb_cache); kmem_cache_destroy(zdev_fmb_cache);
} }
unsigned int pci_probe = 1; void zpci_register_hp_ops(struct pci_hp_callback_ops *ops)
EXPORT_SYMBOL_GPL(pci_probe); {
mutex_lock(&zpci_list_lock);
hotplug_ops = ops;
mutex_unlock(&zpci_list_lock);
}
EXPORT_SYMBOL_GPL(zpci_register_hp_ops);
void zpci_deregister_hp_ops(void)
{
mutex_lock(&zpci_list_lock);
hotplug_ops = NULL;
mutex_unlock(&zpci_list_lock);
}
EXPORT_SYMBOL_GPL(zpci_deregister_hp_ops);
unsigned int s390_pci_probe = 1;
EXPORT_SYMBOL_GPL(s390_pci_probe);
char * __init pcibios_setup(char *str) char * __init pcibios_setup(char *str)
{ {
if (!strcmp(str, "off")) { if (!strcmp(str, "off")) {
pci_probe = 0; s390_pci_probe = 0;
return NULL; return NULL;
} }
return str; return str;
@ -1088,7 +1103,7 @@ static int __init pci_base_init(void)
{ {
int rc; int rc;
if (!pci_probe) if (!s390_pci_probe)
return 0; return 0;
if (!test_facility(2) || !test_facility(69) if (!test_facility(2) || !test_facility(69)

Просмотреть файл

@ -19,25 +19,25 @@
* Call Logical Processor * Call Logical Processor
* Retry logic is handled by the caller. * Retry logic is handled by the caller.
*/ */
static inline u8 clp_instr(void *req) static inline u8 clp_instr(void *data)
{ {
u64 ilpm; struct { u8 _[CLP_BLK_SIZE]; } *req = data;
u64 ignored;
u8 cc; u8 cc;
asm volatile ( asm volatile (
" .insn rrf,0xb9a00000,%[ilpm],%[req],0x0,0x2\n" " .insn rrf,0xb9a00000,%[ign],%[req],0x0,0x2\n"
" ipm %[cc]\n" " ipm %[cc]\n"
" srl %[cc],28\n" " srl %[cc],28\n"
: [cc] "=d" (cc), [ilpm] "=d" (ilpm) : [cc] "=d" (cc), [ign] "=d" (ignored), "+m" (*req)
: [req] "a" (req) : [req] "a" (req)
: "cc", "memory"); : "cc");
return cc; return cc;
} }
static void *clp_alloc_block(void) static void *clp_alloc_block(void)
{ {
struct page *page = alloc_pages(GFP_KERNEL, get_order(CLP_BLK_SIZE)); return (void *) __get_free_pages(GFP_KERNEL, get_order(CLP_BLK_SIZE));
return (page) ? page_address(page) : NULL;
} }
static void clp_free_block(void *ptr) static void clp_free_block(void *ptr)

Просмотреть файл

@ -14,7 +14,7 @@ menuconfig ATA
tristate "Serial ATA and Parallel ATA drivers" tristate "Serial ATA and Parallel ATA drivers"
depends on HAS_IOMEM depends on HAS_IOMEM
depends on BLOCK depends on BLOCK
depends on !(M32R || M68K) || BROKEN depends on !(M32R || M68K || S390) || BROKEN
select SCSI select SCSI
---help--- ---help---
If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or

Просмотреть файл

@ -277,7 +277,7 @@ config GPIO_ICH
config GPIO_VX855 config GPIO_VX855
tristate "VIA VX855/VX875 GPIO" tristate "VIA VX855/VX875 GPIO"
depends on PCI depends on PCI && GENERIC_HARDIRQS
select MFD_CORE select MFD_CORE
select MFD_VX855 select MFD_VX855
help help
@ -599,7 +599,7 @@ config GPIO_TIMBERDALE
config GPIO_RDC321X config GPIO_RDC321X
tristate "RDC R-321x GPIO support" tristate "RDC R-321x GPIO support"
depends on PCI depends on PCI && GENERIC_HARDIRQS
select MFD_CORE select MFD_CORE
select MFD_RDC321X select MFD_RDC321X
help help

Просмотреть файл

@ -180,7 +180,7 @@ config RADIO_TIMBERDALE
config RADIO_WL1273 config RADIO_WL1273
tristate "Texas Instruments WL1273 I2C FM Radio" tristate "Texas Instruments WL1273 I2C FM Radio"
depends on I2C && VIDEO_V4L2 depends on I2C && VIDEO_V4L2 && GENERIC_HARDIRQS
select MFD_CORE select MFD_CORE
select MFD_WL1273_CORE select MFD_WL1273_CORE
select FW_LOADER select FW_LOADER

Просмотреть файл

@ -22,6 +22,7 @@ if NET_CADENCE
config ARM_AT91_ETHER config ARM_AT91_ETHER
tristate "AT91RM9200 Ethernet support" tristate "AT91RM9200 Ethernet support"
depends on GENERIC_HARDIRQS
select NET_CORE select NET_CORE
select MACB select MACB
---help--- ---help---

Просмотреть файл

@ -4,7 +4,6 @@
menuconfig PHYLIB menuconfig PHYLIB
tristate "PHY Device support and infrastructure" tristate "PHY Device support and infrastructure"
depends on !S390
depends on NETDEVICES depends on NETDEVICES
help help
Ethernet controllers are usually attached to PHY Ethernet controllers are usually attached to PHY

Просмотреть файл

@ -35,7 +35,7 @@ if PARPORT
config PARPORT_PC config PARPORT_PC
tristate "PC-style hardware" tristate "PC-style hardware"
depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && \ depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && !S390 && \
(!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && !XTENSA (!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && !XTENSA
---help--- ---help---
You should say Y here if you have a PC-style parallel port. All You should say Y here if you have a PC-style parallel port. All

Просмотреть файл

@ -172,25 +172,6 @@ error:
return -ENOMEM; return -ENOMEM;
} }
static int __init init_pci_slots(void)
{
struct zpci_dev *zdev;
int device = 0;
/*
* Create a structure for each slot, and register that slot
* with the pci_hotplug subsystem.
*/
mutex_lock(&zpci_list_lock);
list_for_each_entry(zdev, &zpci_list, entry) {
init_pci_slot(zdev);
device++;
}
mutex_unlock(&zpci_list_lock);
return (device) ? 0 : -ENODEV;
}
static void exit_pci_slot(struct zpci_dev *zdev) static void exit_pci_slot(struct zpci_dev *zdev)
{ {
struct list_head *tmp, *n; struct list_head *tmp, *n;
@ -205,6 +186,26 @@ static void exit_pci_slot(struct zpci_dev *zdev)
} }
} }
static struct pci_hp_callback_ops hp_ops = {
.create_slot = init_pci_slot,
.remove_slot = exit_pci_slot,
};
static void __init init_pci_slots(void)
{
struct zpci_dev *zdev;
/*
* Create a structure for each slot, and register that slot
* with the pci_hotplug subsystem.
*/
mutex_lock(&zpci_list_lock);
list_for_each_entry(zdev, &zpci_list, entry) {
init_pci_slot(zdev);
}
mutex_unlock(&zpci_list_lock);
}
static void __exit exit_pci_slots(void) static void __exit exit_pci_slots(void)
{ {
struct list_head *tmp, *n; struct list_head *tmp, *n;
@ -224,28 +225,19 @@ static void __exit exit_pci_slots(void)
static int __init pci_hotplug_s390_init(void) static int __init pci_hotplug_s390_init(void)
{ {
/* if (!s390_pci_probe)
* Do specific initialization stuff for your driver here
* like initializing your controller hardware (if any) and
* determining the number of slots you have in the system
* right now.
*/
if (!pci_probe)
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* register callbacks for slot handling from arch code */ zpci_register_hp_ops(&hp_ops);
mutex_lock(&zpci_list_lock); init_pci_slots();
hotplug_ops.create_slot = init_pci_slot;
hotplug_ops.remove_slot = exit_pci_slot; return 0;
mutex_unlock(&zpci_list_lock);
pr_info("registered hotplug slot callbacks\n");
return init_pci_slots();
} }
static void __exit pci_hotplug_s390_exit(void) static void __exit pci_hotplug_s390_exit(void)
{ {
exit_pci_slots(); exit_pci_slots();
zpci_deregister_hp_ops();
} }
module_init(pci_hotplug_s390_init); module_init(pci_hotplug_s390_init);

Просмотреть файл

@ -1352,7 +1352,7 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)
switch (rc) { switch (rc) {
case 0: /* termination successful */ case 0: /* termination successful */
cqr->status = DASD_CQR_CLEAR_PENDING; cqr->status = DASD_CQR_CLEAR_PENDING;
cqr->stopclk = get_clock(); cqr->stopclk = get_tod_clock();
cqr->starttime = 0; cqr->starttime = 0;
DBF_DEV_EVENT(DBF_DEBUG, device, DBF_DEV_EVENT(DBF_DEBUG, device,
"terminate cqr %p successful", "terminate cqr %p successful",
@ -1420,7 +1420,7 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
cqr->status = DASD_CQR_ERROR; cqr->status = DASD_CQR_ERROR;
return -EIO; return -EIO;
} }
cqr->startclk = get_clock(); cqr->startclk = get_tod_clock();
cqr->starttime = jiffies; cqr->starttime = jiffies;
cqr->retries--; cqr->retries--;
if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) { if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) {
@ -1623,7 +1623,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
return; return;
} }
now = get_clock(); now = get_tod_clock();
cqr = (struct dasd_ccw_req *) intparm; cqr = (struct dasd_ccw_req *) intparm;
/* check for conditions that should be handled immediately */ /* check for conditions that should be handled immediately */
if (!cqr || if (!cqr ||
@ -1963,7 +1963,7 @@ int dasd_flush_device_queue(struct dasd_device *device)
} }
break; break;
case DASD_CQR_QUEUED: case DASD_CQR_QUEUED:
cqr->stopclk = get_clock(); cqr->stopclk = get_tod_clock();
cqr->status = DASD_CQR_CLEARED; cqr->status = DASD_CQR_CLEARED;
break; break;
default: /* no need to modify the others */ default: /* no need to modify the others */
@ -2210,7 +2210,7 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
wait_event(generic_waitq, _wait_for_wakeup(cqr)); wait_event(generic_waitq, _wait_for_wakeup(cqr));
} }
maincqr->endclk = get_clock(); maincqr->endclk = get_tod_clock();
if ((maincqr->status != DASD_CQR_DONE) && if ((maincqr->status != DASD_CQR_DONE) &&
(maincqr->intrc != -ERESTARTSYS)) (maincqr->intrc != -ERESTARTSYS))
dasd_log_sense(maincqr, &maincqr->irb); dasd_log_sense(maincqr, &maincqr->irb);
@ -2340,7 +2340,7 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr)
"Cancelling request %p failed with rc=%d\n", "Cancelling request %p failed with rc=%d\n",
cqr, rc); cqr, rc);
} else { } else {
cqr->stopclk = get_clock(); cqr->stopclk = get_tod_clock();
} }
break; break;
default: /* already finished or clear pending - do nothing */ default: /* already finished or clear pending - do nothing */
@ -2568,7 +2568,7 @@ restart:
} }
/* Rechain finished requests to final queue */ /* Rechain finished requests to final queue */
cqr->endclk = get_clock(); cqr->endclk = get_tod_clock();
list_move_tail(&cqr->blocklist, final_queue); list_move_tail(&cqr->blocklist, final_queue);
} }
} }
@ -2711,7 +2711,7 @@ restart_cb:
} }
/* call the callback function */ /* call the callback function */
spin_lock_irq(&block->request_queue_lock); spin_lock_irq(&block->request_queue_lock);
cqr->endclk = get_clock(); cqr->endclk = get_tod_clock();
list_del_init(&cqr->blocklist); list_del_init(&cqr->blocklist);
__dasd_cleanup_cqr(cqr); __dasd_cleanup_cqr(cqr);
spin_unlock_irq(&block->request_queue_lock); spin_unlock_irq(&block->request_queue_lock);
@ -3042,12 +3042,15 @@ void dasd_generic_remove(struct ccw_device *cdev)
cdev->handler = NULL; cdev->handler = NULL;
device = dasd_device_from_cdev(cdev); device = dasd_device_from_cdev(cdev);
if (IS_ERR(device)) if (IS_ERR(device)) {
dasd_remove_sysfs_files(cdev);
return; return;
}
if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags) && if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags) &&
!test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) { !test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
/* Already doing offline processing */ /* Already doing offline processing */
dasd_put_device(device); dasd_put_device(device);
dasd_remove_sysfs_files(cdev);
return; return;
} }
/* /*
@ -3504,7 +3507,7 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
cqr->memdev = device; cqr->memdev = device;
cqr->expires = 10*HZ; cqr->expires = 10*HZ;
cqr->retries = 256; cqr->retries = 256;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
return cqr; return cqr;
} }

Просмотреть файл

@ -229,7 +229,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
dctl_cqr->expires = 5 * 60 * HZ; dctl_cqr->expires = 5 * 60 * HZ;
dctl_cqr->retries = 2; dctl_cqr->retries = 2;
dctl_cqr->buildclk = get_clock(); dctl_cqr->buildclk = get_tod_clock();
dctl_cqr->status = DASD_CQR_FILLED; dctl_cqr->status = DASD_CQR_FILLED;
@ -1719,7 +1719,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
erp->magic = default_erp->magic; erp->magic = default_erp->magic;
erp->expires = default_erp->expires; erp->expires = default_erp->expires;
erp->retries = 256; erp->retries = 256;
erp->buildclk = get_clock(); erp->buildclk = get_tod_clock();
erp->status = DASD_CQR_FILLED; erp->status = DASD_CQR_FILLED;
/* remove the default erp */ /* remove the default erp */
@ -2322,7 +2322,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
DBF_DEV_EVENT(DBF_ERR, device, "%s", DBF_DEV_EVENT(DBF_ERR, device, "%s",
"Unable to allocate ERP request"); "Unable to allocate ERP request");
cqr->status = DASD_CQR_FAILED; cqr->status = DASD_CQR_FAILED;
cqr->stopclk = get_clock (); cqr->stopclk = get_tod_clock();
} else { } else {
DBF_DEV_EVENT(DBF_ERR, device, DBF_DEV_EVENT(DBF_ERR, device,
"Unable to allocate ERP request " "Unable to allocate ERP request "
@ -2364,7 +2364,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
erp->magic = cqr->magic; erp->magic = cqr->magic;
erp->expires = cqr->expires; erp->expires = cqr->expires;
erp->retries = 256; erp->retries = 256;
erp->buildclk = get_clock(); erp->buildclk = get_tod_clock();
erp->status = DASD_CQR_FILLED; erp->status = DASD_CQR_FILLED;
return erp; return erp;

Просмотреть файл

@ -448,7 +448,7 @@ static int read_unit_address_configuration(struct dasd_device *device,
ccw->count = sizeof(*(lcu->uac)); ccw->count = sizeof(*(lcu->uac));
ccw->cda = (__u32)(addr_t) lcu->uac; ccw->cda = (__u32)(addr_t) lcu->uac;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
/* need to unset flag here to detect race with summary unit check */ /* need to unset flag here to detect race with summary unit check */
@ -733,7 +733,7 @@ static int reset_summary_unit_check(struct alias_lcu *lcu,
cqr->memdev = device; cqr->memdev = device;
cqr->block = NULL; cqr->block = NULL;
cqr->expires = 5 * HZ; cqr->expires = 5 * HZ;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr); rc = dasd_sleep_on_immediatly(cqr);

Просмотреть файл

@ -184,14 +184,14 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
private->iob.bio_list = dreq->bio; private->iob.bio_list = dreq->bio;
private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT; private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
cqr->startclk = get_clock(); cqr->startclk = get_tod_clock();
cqr->starttime = jiffies; cqr->starttime = jiffies;
cqr->retries--; cqr->retries--;
rc = dia250(&private->iob, RW_BIO); rc = dia250(&private->iob, RW_BIO);
switch (rc) { switch (rc) {
case 0: /* Synchronous I/O finished successfully */ case 0: /* Synchronous I/O finished successfully */
cqr->stopclk = get_clock(); cqr->stopclk = get_tod_clock();
cqr->status = DASD_CQR_SUCCESS; cqr->status = DASD_CQR_SUCCESS;
/* Indicate to calling function that only a dasd_schedule_bh() /* Indicate to calling function that only a dasd_schedule_bh()
and no timer is needed */ and no timer is needed */
@ -222,7 +222,7 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
mdsk_term_io(device); mdsk_term_io(device);
mdsk_init_io(device, device->block->bp_block, 0, NULL); mdsk_init_io(device, device->block->bp_block, 0, NULL);
cqr->status = DASD_CQR_CLEAR_PENDING; cqr->status = DASD_CQR_CLEAR_PENDING;
cqr->stopclk = get_clock(); cqr->stopclk = get_tod_clock();
dasd_schedule_device_bh(device); dasd_schedule_device_bh(device);
return 0; return 0;
} }
@ -276,7 +276,7 @@ static void dasd_ext_handler(struct ext_code ext_code,
return; return;
} }
cqr->stopclk = get_clock(); cqr->stopclk = get_tod_clock();
expires = 0; expires = 0;
if ((ext_code.subcode & 0xff) == 0) { if ((ext_code.subcode & 0xff) == 0) {
@ -556,7 +556,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
} }
} }
cqr->retries = DIAG_MAX_RETRIES; cqr->retries = DIAG_MAX_RETRIES;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
if (blk_noretry_request(req) || if (blk_noretry_request(req) ||
block->base->features & DASD_FEATURE_FAILFAST) block->base->features & DASD_FEATURE_FAILFAST)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);

Просмотреть файл

@ -862,7 +862,7 @@ static void dasd_eckd_fill_rcd_cqr(struct dasd_device *device,
cqr->expires = 10*HZ; cqr->expires = 10*HZ;
cqr->lpm = lpm; cqr->lpm = lpm;
cqr->retries = 256; cqr->retries = 256;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags); set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags);
} }
@ -1449,7 +1449,7 @@ static int dasd_eckd_read_features(struct dasd_device *device)
ccw->count = sizeof(struct dasd_rssd_features); ccw->count = sizeof(struct dasd_rssd_features);
ccw->cda = (__u32)(addr_t) features; ccw->cda = (__u32)(addr_t) features;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on(cqr); rc = dasd_sleep_on(cqr);
if (rc == 0) { if (rc == 0) {
@ -1501,7 +1501,7 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device,
cqr->block = NULL; cqr->block = NULL;
cqr->retries = 256; cqr->retries = 256;
cqr->expires = 10*HZ; cqr->expires = 10*HZ;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
return cqr; return cqr;
} }
@ -1841,7 +1841,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
cqr->startdev = device; cqr->startdev = device;
cqr->memdev = device; cqr->memdev = device;
cqr->retries = 255; cqr->retries = 255;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
return cqr; return cqr;
} }
@ -2241,7 +2241,7 @@ dasd_eckd_format_device(struct dasd_device * device,
fcp->startdev = device; fcp->startdev = device;
fcp->memdev = device; fcp->memdev = device;
fcp->retries = 256; fcp->retries = 256;
fcp->buildclk = get_clock(); fcp->buildclk = get_tod_clock();
fcp->status = DASD_CQR_FILLED; fcp->status = DASD_CQR_FILLED;
return fcp; return fcp;
} }
@ -2530,7 +2530,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */
cqr->lpm = startdev->path_data.ppm; cqr->lpm = startdev->path_data.ppm;
cqr->retries = 256; cqr->retries = 256;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
return cqr; return cqr;
} }
@ -2705,7 +2705,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */
cqr->lpm = startdev->path_data.ppm; cqr->lpm = startdev->path_data.ppm;
cqr->retries = 256; cqr->retries = 256;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
return cqr; return cqr;
} }
@ -2998,7 +2998,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */
cqr->lpm = startdev->path_data.ppm; cqr->lpm = startdev->path_data.ppm;
cqr->retries = 256; cqr->retries = 256;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
return cqr; return cqr;
out_error: out_error:
@ -3201,7 +3201,7 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
cqr->expires = startdev->default_expires * HZ; cqr->expires = startdev->default_expires * HZ;
cqr->lpm = startdev->path_data.ppm; cqr->lpm = startdev->path_data.ppm;
cqr->retries = 256; cqr->retries = 256;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN)
@ -3402,7 +3402,7 @@ dasd_eckd_release(struct dasd_device *device)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ; cqr->expires = 2 * HZ;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr); rc = dasd_sleep_on_immediatly(cqr);
@ -3457,7 +3457,7 @@ dasd_eckd_reserve(struct dasd_device *device)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ; cqr->expires = 2 * HZ;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr); rc = dasd_sleep_on_immediatly(cqr);
@ -3511,7 +3511,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ; cqr->expires = 2 * HZ;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr); rc = dasd_sleep_on_immediatly(cqr);
@ -3572,7 +3572,7 @@ static int dasd_eckd_snid(struct dasd_device *device,
set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags);
cqr->retries = 5; cqr->retries = 5;
cqr->expires = 10 * HZ; cqr->expires = 10 * HZ;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
cqr->lpm = usrparm.path_mask; cqr->lpm = usrparm.path_mask;
@ -3642,7 +3642,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
ccw->count = sizeof(struct dasd_rssd_perf_stats_t); ccw->count = sizeof(struct dasd_rssd_perf_stats_t);
ccw->cda = (__u32)(addr_t) stats; ccw->cda = (__u32)(addr_t) stats;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on(cqr); rc = dasd_sleep_on(cqr);
if (rc == 0) { if (rc == 0) {
@ -3768,7 +3768,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
cqr->memdev = device; cqr->memdev = device;
cqr->retries = 3; cqr->retries = 3;
cqr->expires = 10 * HZ; cqr->expires = 10 * HZ;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
/* Build the ccws */ /* Build the ccws */

Просмотреть файл

@ -481,7 +481,7 @@ int dasd_eer_enable(struct dasd_device *device)
ccw->flags = 0; ccw->flags = 0;
ccw->cda = (__u32)(addr_t) cqr->data; ccw->cda = (__u32)(addr_t) cqr->data;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
cqr->callback = dasd_eer_snss_cb; cqr->callback = dasd_eer_snss_cb;

Просмотреть файл

@ -102,7 +102,7 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr)
pr_err("%s: default ERP has run out of retries and failed\n", pr_err("%s: default ERP has run out of retries and failed\n",
dev_name(&device->cdev->dev)); dev_name(&device->cdev->dev));
cqr->status = DASD_CQR_FAILED; cqr->status = DASD_CQR_FAILED;
cqr->stopclk = get_clock(); cqr->stopclk = get_tod_clock();
} }
return cqr; return cqr;
} /* end dasd_default_erp_action */ } /* end dasd_default_erp_action */
@ -146,7 +146,7 @@ struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
cqr->status = DASD_CQR_DONE; cqr->status = DASD_CQR_DONE;
else { else {
cqr->status = DASD_CQR_FAILED; cqr->status = DASD_CQR_FAILED;
cqr->stopclk = get_clock(); cqr->stopclk = get_tod_clock();
} }
return cqr; return cqr;

Просмотреть файл

@ -370,7 +370,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
cqr->block = block; cqr->block = block;
cqr->expires = memdev->default_expires * HZ; /* default 5 minutes */ cqr->expires = memdev->default_expires * HZ; /* default 5 minutes */
cqr->retries = 32; cqr->retries = 32;
cqr->buildclk = get_clock(); cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
return cqr; return cqr;
} }

Просмотреть файл

@ -68,19 +68,34 @@ void scm_initiate_cluster_request(struct scm_request *);
void scm_cluster_request_irq(struct scm_request *); void scm_cluster_request_irq(struct scm_request *);
bool scm_test_cluster_request(struct scm_request *); bool scm_test_cluster_request(struct scm_request *);
bool scm_cluster_size_valid(void); bool scm_cluster_size_valid(void);
#else #else /* CONFIG_SCM_BLOCK_CLUSTER_WRITE */
#define __scm_free_rq_cluster(scmrq) {} static inline void __scm_free_rq_cluster(struct scm_request *scmrq) {}
#define __scm_alloc_rq_cluster(scmrq) 0 static inline int __scm_alloc_rq_cluster(struct scm_request *scmrq)
#define scm_request_cluster_init(scmrq) {} {
#define scm_reserve_cluster(scmrq) true return 0;
#define scm_release_cluster(scmrq) {} }
#define scm_blk_dev_cluster_setup(bdev) {} static inline void scm_request_cluster_init(struct scm_request *scmrq) {}
#define scm_need_cluster_request(scmrq) false static inline bool scm_reserve_cluster(struct scm_request *scmrq)
#define scm_initiate_cluster_request(scmrq) {} {
#define scm_cluster_request_irq(scmrq) {} return true;
#define scm_test_cluster_request(scmrq) false }
#define scm_cluster_size_valid() true static inline void scm_release_cluster(struct scm_request *scmrq) {}
#endif static inline void scm_blk_dev_cluster_setup(struct scm_blk_dev *bdev) {}
static inline bool scm_need_cluster_request(struct scm_request *scmrq)
{
return false;
}
static inline void scm_initiate_cluster_request(struct scm_request *scmrq) {}
static inline void scm_cluster_request_irq(struct scm_request *scmrq) {}
static inline bool scm_test_cluster_request(struct scm_request *scmrq)
{
return false;
}
static inline bool scm_cluster_size_valid(void)
{
return true;
}
#endif /* CONFIG_SCM_BLOCK_CLUSTER_WRITE */
extern debug_info_t *scm_debug; extern debug_info_t *scm_debug;

Просмотреть файл

@ -443,7 +443,7 @@ fs3270_open(struct inode *inode, struct file *filp)
tty_kref_put(tty); tty_kref_put(tty);
return -ENODEV; return -ENODEV;
} }
minor = tty->index + RAW3270_FIRSTMINOR; minor = tty->index;
tty_kref_put(tty); tty_kref_put(tty);
} }
mutex_lock(&fs3270_mutex); mutex_lock(&fs3270_mutex);
@ -524,6 +524,25 @@ static const struct file_operations fs3270_fops = {
.llseek = no_llseek, .llseek = no_llseek,
}; };
void fs3270_create_cb(int minor)
{
__register_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub", &fs3270_fops);
device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, minor),
NULL, "3270/tub%d", minor);
}
void fs3270_destroy_cb(int minor)
{
device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, minor));
__unregister_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub");
}
struct raw3270_notifier fs3270_notifier =
{
.create = fs3270_create_cb,
.destroy = fs3270_destroy_cb,
};
/* /*
* 3270 fullscreen driver initialization. * 3270 fullscreen driver initialization.
*/ */
@ -532,16 +551,20 @@ fs3270_init(void)
{ {
int rc; int rc;
rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops); rc = __register_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270", &fs3270_fops);
if (rc) if (rc)
return rc; return rc;
device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, 0),
NULL, "3270/tub");
raw3270_register_notifier(&fs3270_notifier);
return 0; return 0;
} }
static void __exit static void __exit
fs3270_exit(void) fs3270_exit(void)
{ {
unregister_chrdev(IBM_FS3270_MAJOR, "fs3270"); raw3270_unregister_notifier(&fs3270_notifier);
__unregister_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270");
} }
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

Просмотреть файл

@ -28,7 +28,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/mutex.h> #include <linux/mutex.h>
static struct class *class3270; struct class *class3270;
/* The main 3270 data structure. */ /* The main 3270 data structure. */
struct raw3270 { struct raw3270 {
@ -37,6 +37,7 @@ struct raw3270 {
int minor; int minor;
short model, rows, cols; short model, rows, cols;
unsigned int state;
unsigned long flags; unsigned long flags;
struct list_head req_queue; /* Request queue. */ struct list_head req_queue; /* Request queue. */
@ -46,20 +47,26 @@ struct raw3270 {
struct timer_list timer; /* Device timer. */ struct timer_list timer; /* Device timer. */
unsigned char *ascebc; /* ascii -> ebcdic table */ unsigned char *ascebc; /* ascii -> ebcdic table */
struct device *clttydev; /* 3270-class tty device ptr */
struct device *cltubdev; /* 3270-class tub device ptr */
struct raw3270_request init_request; struct raw3270_view init_view;
struct raw3270_request init_reset;
struct raw3270_request init_readpart;
struct raw3270_request init_readmod;
unsigned char init_data[256]; unsigned char init_data[256];
}; };
/* raw3270->state */
#define RAW3270_STATE_INIT 0 /* Initial state */
#define RAW3270_STATE_RESET 1 /* Reset command is pending */
#define RAW3270_STATE_W4ATTN 2 /* Wait for attention interrupt */
#define RAW3270_STATE_READMOD 3 /* Read partition is pending */
#define RAW3270_STATE_READY 4 /* Device is usable by views */
/* raw3270->flags */ /* raw3270->flags */
#define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */ #define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */
#define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */ #define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */
#define RAW3270_FLAGS_ATTN 2 /* Device sent an ATTN interrupt */ #define RAW3270_FLAGS_CONSOLE 2 /* Device is the console. */
#define RAW3270_FLAGS_READY 4 /* Device is useable by views */ #define RAW3270_FLAGS_FROZEN 3 /* set if 3270 is frozen for suspend */
#define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */
#define RAW3270_FLAGS_FROZEN 16 /* set if 3270 is frozen for suspend */
/* Semaphore to protect global data of raw3270 (devices, views, etc). */ /* Semaphore to protect global data of raw3270 (devices, views, etc). */
static DEFINE_MUTEX(raw3270_mutex); static DEFINE_MUTEX(raw3270_mutex);
@ -97,6 +104,17 @@ static unsigned char raw3270_ebcgraf[64] = {
0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
}; };
static inline int raw3270_state_ready(struct raw3270 *rp)
{
return rp->state == RAW3270_STATE_READY;
}
static inline int raw3270_state_final(struct raw3270 *rp)
{
return rp->state == RAW3270_STATE_INIT ||
rp->state == RAW3270_STATE_READY;
}
void void
raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr) raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr)
{ {
@ -214,7 +232,7 @@ raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
* Stop running ccw. * Stop running ccw.
*/ */
static int static int
raw3270_halt_io_nolock(struct raw3270 *rp, struct raw3270_request *rq) __raw3270_halt_io(struct raw3270 *rp, struct raw3270_request *rq)
{ {
int retries; int retries;
int rc; int rc;
@ -233,18 +251,6 @@ raw3270_halt_io_nolock(struct raw3270 *rp, struct raw3270_request *rq)
return rc; return rc;
} }
static int
raw3270_halt_io(struct raw3270 *rp, struct raw3270_request *rq)
{
unsigned long flags;
int rc;
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
rc = raw3270_halt_io_nolock(rp, rq);
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
return rc;
}
/* /*
* Add the request to the request queue, try to start it if the * Add the request to the request queue, try to start it if the
* 3270 device is idle. Return without waiting for end of i/o. * 3270 device is idle. Return without waiting for end of i/o.
@ -281,8 +287,8 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
if (!rp || rp->view != view || if (!rp || rp->view != view ||
test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
rc = -EACCES; rc = -EACCES;
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) else if (!raw3270_state_ready(rp))
rc = -ENODEV; rc = -EBUSY;
else else
rc = __raw3270_start(rp, view, rq); rc = __raw3270_start(rp, view, rq);
spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
@ -299,8 +305,8 @@ raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
if (!rp || rp->view != view || if (!rp || rp->view != view ||
test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
rc = -EACCES; rc = -EACCES;
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) else if (!raw3270_state_ready(rp))
rc = -ENODEV; rc = -EBUSY;
else else
rc = __raw3270_start(rp, view, rq); rc = __raw3270_start(rp, view, rq);
return rc; return rc;
@ -378,7 +384,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
case RAW3270_IO_STOP: case RAW3270_IO_STOP:
if (!rq) if (!rq)
break; break;
raw3270_halt_io_nolock(rp, rq); __raw3270_halt_io(rp, rq);
rq->rc = -EIO; rq->rc = -EIO;
break; break;
default: default:
@ -413,9 +419,14 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
} }
/* /*
* Size sensing. * To determine the size of the 3270 device we need to do:
* 1) send a 'read partition' data stream to the device
* 2) wait for the attn interrupt that precedes the query reply
* 3) do a read modified to get the query reply
* To make things worse we have to cope with intervention
* required (3270 device switched to 'stand-by') and command
* rejects (old devices that can't do 'read partition').
*/ */
struct raw3270_ua { /* Query Reply structure for Usable Area */ struct raw3270_ua { /* Query Reply structure for Usable Area */
struct { /* Usable Area Query Reply Base */ struct { /* Usable Area Query Reply Base */
short l; /* Length of this structured field */ short l; /* Length of this structured field */
@ -451,117 +462,21 @@ struct raw3270_ua { /* Query Reply structure for Usable Area */
} __attribute__ ((packed)) aua; } __attribute__ ((packed)) aua;
} __attribute__ ((packed)); } __attribute__ ((packed));
static struct diag210 raw3270_init_diag210;
static DEFINE_MUTEX(raw3270_init_mutex);
static int
raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
struct irb *irb)
{
/*
* Unit-Check Processing:
* Expect Command Reject or Intervention Required.
*/
if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
/* Request finished abnormally. */
if (irb->ecw[0] & SNS0_INTERVENTION_REQ) {
set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags);
return RAW3270_IO_BUSY;
}
}
if (rq) {
if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
if (irb->ecw[0] & SNS0_CMD_REJECT)
rq->rc = -EOPNOTSUPP;
else
rq->rc = -EIO;
} else
/* Request finished normally. Copy residual count. */
rq->rescnt = irb->scsw.cmd.count;
}
if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
set_bit(RAW3270_FLAGS_ATTN, &view->dev->flags);
wake_up(&raw3270_wait_queue);
}
return RAW3270_IO_DONE;
}
static struct raw3270_fn raw3270_init_fn = {
.intv = raw3270_init_irq
};
static struct raw3270_view raw3270_init_view = {
.fn = &raw3270_init_fn
};
/*
* raw3270_wait/raw3270_wait_interruptible/__raw3270_wakeup
* Wait for end of request. The request must have been started
* with raw3270_start, rc = 0. The device lock may NOT have been
* released between calling raw3270_start and raw3270_wait.
*/
static void static void
raw3270_wake_init(struct raw3270_request *rq, void *data) raw3270_size_device_vm(struct raw3270 *rp)
{
wake_up((wait_queue_head_t *) data);
}
/*
* Special wait function that can cope with console initialization.
*/
static int
raw3270_start_init(struct raw3270 *rp, struct raw3270_view *view,
struct raw3270_request *rq)
{
unsigned long flags;
int rc;
#ifdef CONFIG_TN3270_CONSOLE
if (raw3270_registered == 0) {
spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
rq->callback = NULL;
rc = __raw3270_start(rp, view, rq);
if (rc == 0)
while (!raw3270_request_final(rq)) {
wait_cons_dev();
barrier();
}
spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
return rq->rc;
}
#endif
rq->callback = raw3270_wake_init;
rq->callback_data = &raw3270_wait_queue;
spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
rc = __raw3270_start(rp, view, rq);
spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
if (rc)
return rc;
/* Now wait for the completion. */
rc = wait_event_interruptible(raw3270_wait_queue,
raw3270_request_final(rq));
if (rc == -ERESTARTSYS) { /* Interrupted by a signal. */
raw3270_halt_io(view->dev, rq);
/* No wait for the halt to complete. */
wait_event(raw3270_wait_queue, raw3270_request_final(rq));
return -ERESTARTSYS;
}
return rq->rc;
}
static int
__raw3270_size_device_vm(struct raw3270 *rp)
{ {
int rc, model; int rc, model;
struct ccw_dev_id dev_id; struct ccw_dev_id dev_id;
struct diag210 diag_data;
ccw_device_get_id(rp->cdev, &dev_id); ccw_device_get_id(rp->cdev, &dev_id);
raw3270_init_diag210.vrdcdvno = dev_id.devno; diag_data.vrdcdvno = dev_id.devno;
raw3270_init_diag210.vrdclen = sizeof(struct diag210); diag_data.vrdclen = sizeof(struct diag210);
rc = diag210(&raw3270_init_diag210); rc = diag210(&diag_data);
if (rc) model = diag_data.vrdccrmd;
return rc; /* Use default model 2 if the size could not be detected */
model = raw3270_init_diag210.vrdccrmd; if (rc || model < 2 || model > 5)
model = 2;
switch (model) { switch (model) {
case 2: case 2:
rp->model = model; rp->model = model;
@ -583,77 +498,25 @@ __raw3270_size_device_vm(struct raw3270 *rp)
rp->rows = 27; rp->rows = 27;
rp->cols = 132; rp->cols = 132;
break; break;
default:
rc = -EOPNOTSUPP;
break;
} }
return rc;
} }
static int static void
__raw3270_size_device(struct raw3270 *rp) raw3270_size_device(struct raw3270 *rp)
{ {
static const unsigned char wbuf[] =
{ 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
struct raw3270_ua *uap; struct raw3270_ua *uap;
int rc;
/*
* To determine the size of the 3270 device we need to do:
* 1) send a 'read partition' data stream to the device
* 2) wait for the attn interrupt that precedes the query reply
* 3) do a read modified to get the query reply
* To make things worse we have to cope with intervention
* required (3270 device switched to 'stand-by') and command
* rejects (old devices that can't do 'read partition').
*/
memset(&rp->init_request, 0, sizeof(rp->init_request));
memset(&rp->init_data, 0, 256);
/* Store 'read partition' data stream to init_data */
memcpy(&rp->init_data, wbuf, sizeof(wbuf));
INIT_LIST_HEAD(&rp->init_request.list);
rp->init_request.ccw.cmd_code = TC_WRITESF;
rp->init_request.ccw.flags = CCW_FLAG_SLI;
rp->init_request.ccw.count = sizeof(wbuf);
rp->init_request.ccw.cda = (__u32) __pa(&rp->init_data);
rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
if (rc)
/* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
return rc;
/* Wait for attention interrupt. */
#ifdef CONFIG_TN3270_CONSOLE
if (raw3270_registered == 0) {
unsigned long flags;
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
while (!test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags))
wait_cons_dev();
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
} else
#endif
rc = wait_event_interruptible(raw3270_wait_queue,
test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags));
if (rc)
return rc;
/*
* The device accepted the 'read partition' command. Now
* set up a read ccw and issue it.
*/
rp->init_request.ccw.cmd_code = TC_READMOD;
rp->init_request.ccw.flags = CCW_FLAG_SLI;
rp->init_request.ccw.count = sizeof(rp->init_data);
rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
if (rc)
return rc;
/* Got a Query Reply */ /* Got a Query Reply */
uap = (struct raw3270_ua *) (rp->init_data + 1); uap = (struct raw3270_ua *) (rp->init_data + 1);
/* Paranoia check. */ /* Paranoia check. */
if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81) if (rp->init_readmod.rc || rp->init_data[0] != 0x88 ||
return -EOPNOTSUPP; uap->uab.qcode != 0x81) {
/* Couldn't detect size. Use default model 2. */
rp->model = 2;
rp->rows = 24;
rp->cols = 80;
return;
}
/* Copy rows/columns of default Usable Area */ /* Copy rows/columns of default Usable Area */
rp->rows = uap->uab.h; rp->rows = uap->uab.h;
rp->cols = uap->uab.w; rp->cols = uap->uab.w;
@ -666,66 +529,131 @@ __raw3270_size_device(struct raw3270 *rp)
rp->rows = uap->aua.hauai; rp->rows = uap->aua.hauai;
rp->cols = uap->aua.wauai; rp->cols = uap->aua.wauai;
} }
return 0; /* Try to find a model. */
rp->model = 0;
if (rp->rows == 24 && rp->cols == 80)
rp->model = 2;
if (rp->rows == 32 && rp->cols == 80)
rp->model = 3;
if (rp->rows == 43 && rp->cols == 80)
rp->model = 4;
if (rp->rows == 27 && rp->cols == 132)
rp->model = 5;
}
static void
raw3270_size_device_done(struct raw3270 *rp)
{
struct raw3270_view *view;
rp->view = NULL;
rp->state = RAW3270_STATE_READY;
/* Notify views about new size */
list_for_each_entry(view, &rp->view_list, list)
if (view->fn->resize)
view->fn->resize(view, rp->model, rp->rows, rp->cols);
/* Setup processing done, now activate a view */
list_for_each_entry(view, &rp->view_list, list) {
rp->view = view;
if (view->fn->activate(view) == 0)
break;
rp->view = NULL;
}
}
static void
raw3270_read_modified_cb(struct raw3270_request *rq, void *data)
{
struct raw3270 *rp = rq->view->dev;
raw3270_size_device(rp);
raw3270_size_device_done(rp);
}
static void
raw3270_read_modified(struct raw3270 *rp)
{
if (rp->state != RAW3270_STATE_W4ATTN)
return;
/* Use 'read modified' to get the result of a read partition. */
memset(&rp->init_readmod, 0, sizeof(rp->init_readmod));
memset(&rp->init_data, 0, sizeof(rp->init_data));
rp->init_readmod.ccw.cmd_code = TC_READMOD;
rp->init_readmod.ccw.flags = CCW_FLAG_SLI;
rp->init_readmod.ccw.count = sizeof(rp->init_data);
rp->init_readmod.ccw.cda = (__u32) __pa(rp->init_data);
rp->init_readmod.callback = raw3270_read_modified_cb;
rp->state = RAW3270_STATE_READMOD;
raw3270_start_irq(&rp->init_view, &rp->init_readmod);
}
static void
raw3270_writesf_readpart(struct raw3270 *rp)
{
static const unsigned char wbuf[] =
{ 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
/* Store 'read partition' data stream to init_data */
memset(&rp->init_readpart, 0, sizeof(rp->init_readpart));
memset(&rp->init_data, 0, sizeof(rp->init_data));
memcpy(&rp->init_data, wbuf, sizeof(wbuf));
rp->init_readpart.ccw.cmd_code = TC_WRITESF;
rp->init_readpart.ccw.flags = CCW_FLAG_SLI;
rp->init_readpart.ccw.count = sizeof(wbuf);
rp->init_readpart.ccw.cda = (__u32) __pa(&rp->init_data);
rp->state = RAW3270_STATE_W4ATTN;
raw3270_start_irq(&rp->init_view, &rp->init_readpart);
}
/*
* Device reset
*/
static void
raw3270_reset_device_cb(struct raw3270_request *rq, void *data)
{
struct raw3270 *rp = rq->view->dev;
if (rp->state != RAW3270_STATE_RESET)
return;
if (rq && rq->rc) {
/* Reset command failed. */
rp->state = RAW3270_STATE_INIT;
} else if (0 && MACHINE_IS_VM) {
raw3270_size_device_vm(rp);
raw3270_size_device_done(rp);
} else
raw3270_writesf_readpart(rp);
} }
static int static int
raw3270_size_device(struct raw3270 *rp) __raw3270_reset_device(struct raw3270 *rp)
{ {
int rc; int rc;
mutex_lock(&raw3270_init_mutex); /* Store reset data stream to init_data/init_reset */
rp->view = &raw3270_init_view; memset(&rp->init_reset, 0, sizeof(rp->init_reset));
raw3270_init_view.dev = rp; memset(&rp->init_data, 0, sizeof(rp->init_data));
if (MACHINE_IS_VM) rp->init_data[0] = TW_KR;
rc = __raw3270_size_device_vm(rp); rp->init_reset.ccw.cmd_code = TC_EWRITEA;
else rp->init_reset.ccw.flags = CCW_FLAG_SLI;
rc = __raw3270_size_device(rp); rp->init_reset.ccw.count = 1;
raw3270_init_view.dev = NULL; rp->init_reset.ccw.cda = (__u32) __pa(rp->init_data);
rp->view = NULL; rp->init_reset.callback = raw3270_reset_device_cb;
mutex_unlock(&raw3270_init_mutex); rc = __raw3270_start(rp, &rp->init_view, &rp->init_reset);
if (rc == 0) { /* Found something. */ if (rc == 0 && rp->state == RAW3270_STATE_INIT)
/* Try to find a model. */ rp->state = RAW3270_STATE_RESET;
rp->model = 0;
if (rp->rows == 24 && rp->cols == 80)
rp->model = 2;
if (rp->rows == 32 && rp->cols == 80)
rp->model = 3;
if (rp->rows == 43 && rp->cols == 80)
rp->model = 4;
if (rp->rows == 27 && rp->cols == 132)
rp->model = 5;
} else {
/* Couldn't detect size. Use default model 2. */
rp->model = 2;
rp->rows = 24;
rp->cols = 80;
return 0;
}
return rc; return rc;
} }
static int static int
raw3270_reset_device(struct raw3270 *rp) raw3270_reset_device(struct raw3270 *rp)
{ {
unsigned long flags;
int rc; int rc;
mutex_lock(&raw3270_init_mutex); spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
memset(&rp->init_request, 0, sizeof(rp->init_request)); rc = __raw3270_reset_device(rp);
memset(&rp->init_data, 0, sizeof(rp->init_data)); spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
/* Store reset data stream to init_data/init_request */
rp->init_data[0] = TW_KR;
INIT_LIST_HEAD(&rp->init_request.list);
rp->init_request.ccw.cmd_code = TC_EWRITEA;
rp->init_request.ccw.flags = CCW_FLAG_SLI;
rp->init_request.ccw.count = 1;
rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
rp->view = &raw3270_init_view;
raw3270_init_view.dev = rp;
rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
raw3270_init_view.dev = NULL;
rp->view = NULL;
mutex_unlock(&raw3270_init_mutex);
return rc; return rc;
} }
@ -739,13 +667,50 @@ raw3270_reset(struct raw3270_view *view)
if (!rp || rp->view != view || if (!rp || rp->view != view ||
test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
rc = -EACCES; rc = -EACCES;
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) else if (!raw3270_state_ready(rp))
rc = -ENODEV; rc = -EBUSY;
else else
rc = raw3270_reset_device(view->dev); rc = raw3270_reset_device(view->dev);
return rc; return rc;
} }
static int
raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
struct irb *irb)
{
struct raw3270 *rp;
/*
* Unit-Check Processing:
* Expect Command Reject or Intervention Required.
*/
if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
/* Request finished abnormally. */
if (irb->ecw[0] & SNS0_INTERVENTION_REQ) {
set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags);
return RAW3270_IO_BUSY;
}
}
if (rq) {
if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
if (irb->ecw[0] & SNS0_CMD_REJECT)
rq->rc = -EOPNOTSUPP;
else
rq->rc = -EIO;
}
}
if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
/* Queue read modified after attention interrupt */
rp = view->dev;
raw3270_read_modified(rp);
}
return RAW3270_IO_DONE;
}
static struct raw3270_fn raw3270_init_fn = {
.intv = raw3270_init_irq
};
/* /*
* Setup new 3270 device. * Setup new 3270 device.
*/ */
@ -774,6 +739,10 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
INIT_LIST_HEAD(&rp->req_queue); INIT_LIST_HEAD(&rp->req_queue);
INIT_LIST_HEAD(&rp->view_list); INIT_LIST_HEAD(&rp->view_list);
rp->init_view.dev = rp;
rp->init_view.fn = &raw3270_init_fn;
rp->view = &rp->init_view;
/* /*
* Add device to list and find the smallest unused minor * Add device to list and find the smallest unused minor
* number for it. Note: there is no device with minor 0, * number for it. Note: there is no device with minor 0,
@ -812,6 +781,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
*/ */
struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev) struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
{ {
unsigned long flags;
struct raw3270 *rp; struct raw3270 *rp;
char *ascebc; char *ascebc;
int rc; int rc;
@ -822,16 +792,15 @@ struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
if (rc) if (rc)
return ERR_PTR(rc); return ERR_PTR(rc);
set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags); set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
rc = raw3270_reset_device(rp); spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
if (rc) do {
return ERR_PTR(rc); __raw3270_reset_device(rp);
rc = raw3270_size_device(rp); while (!raw3270_state_final(rp)) {
if (rc) wait_cons_dev();
return ERR_PTR(rc); barrier();
rc = raw3270_reset_device(rp); }
if (rc) } while (rp->state != RAW3270_STATE_READY);
return ERR_PTR(rc); spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
set_bit(RAW3270_FLAGS_READY, &rp->flags);
return rp; return rp;
} }
@ -893,13 +862,13 @@ raw3270_activate_view(struct raw3270_view *view)
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
if (rp->view == view) if (rp->view == view)
rc = 0; rc = 0;
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) else if (!raw3270_state_ready(rp))
rc = -ENODEV; rc = -EBUSY;
else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
rc = -EACCES; rc = -EACCES;
else { else {
oldview = NULL; oldview = NULL;
if (rp->view) { if (rp->view && rp->view->fn->deactivate) {
oldview = rp->view; oldview = rp->view;
oldview->fn->deactivate(oldview); oldview->fn->deactivate(oldview);
} }
@ -944,7 +913,7 @@ raw3270_deactivate_view(struct raw3270_view *view)
list_del_init(&view->list); list_del_init(&view->list);
list_add_tail(&view->list, &rp->view_list); list_add_tail(&view->list, &rp->view_list);
/* Try to activate another view. */ /* Try to activate another view. */
if (test_bit(RAW3270_FLAGS_READY, &rp->flags) && if (raw3270_state_ready(rp) &&
!test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
list_for_each_entry(view, &rp->view_list, list) { list_for_each_entry(view, &rp->view_list, list) {
rp->view = view; rp->view = view;
@ -975,18 +944,16 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
if (rp->minor != minor) if (rp->minor != minor)
continue; continue;
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { atomic_set(&view->ref_count, 2);
atomic_set(&view->ref_count, 2); view->dev = rp;
view->dev = rp; view->fn = fn;
view->fn = fn; view->model = rp->model;
view->model = rp->model; view->rows = rp->rows;
view->rows = rp->rows; view->cols = rp->cols;
view->cols = rp->cols; view->ascebc = rp->ascebc;
view->ascebc = rp->ascebc; spin_lock_init(&view->lock);
spin_lock_init(&view->lock); list_add(&view->list, &rp->view_list);
list_add(&view->list, &rp->view_list); rc = 0;
rc = 0;
}
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
break; break;
} }
@ -1010,14 +977,11 @@ raw3270_find_view(struct raw3270_fn *fn, int minor)
if (rp->minor != minor) if (rp->minor != minor)
continue; continue;
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { list_for_each_entry(tmp, &rp->view_list, list) {
view = ERR_PTR(-ENOENT); if (tmp->fn == fn) {
list_for_each_entry(tmp, &rp->view_list, list) { raw3270_get_view(tmp);
if (tmp->fn == fn) { view = tmp;
raw3270_get_view(tmp); break;
view = tmp;
break;
}
} }
} }
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
@ -1044,7 +1008,7 @@ raw3270_del_view(struct raw3270_view *view)
rp->view = NULL; rp->view = NULL;
} }
list_del_init(&view->list); list_del_init(&view->list);
if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags) && if (!rp->view && raw3270_state_ready(rp) &&
!test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
/* Try to activate another view. */ /* Try to activate another view. */
list_for_each_entry(nv, &rp->view_list, list) { list_for_each_entry(nv, &rp->view_list, list) {
@ -1072,10 +1036,6 @@ raw3270_delete_device(struct raw3270 *rp)
/* Remove from device chain. */ /* Remove from device chain. */
mutex_lock(&raw3270_mutex); mutex_lock(&raw3270_mutex);
if (rp->clttydev && !IS_ERR(rp->clttydev))
device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
if (rp->cltubdev && !IS_ERR(rp->cltubdev))
device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, rp->minor));
list_del_init(&rp->list); list_del_init(&rp->list);
mutex_unlock(&raw3270_mutex); mutex_unlock(&raw3270_mutex);
@ -1139,75 +1099,34 @@ static struct attribute_group raw3270_attr_group = {
static int raw3270_create_attributes(struct raw3270 *rp) static int raw3270_create_attributes(struct raw3270 *rp)
{ {
int rc; return sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
rc = sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
if (rc)
goto out;
rp->clttydev = device_create(class3270, &rp->cdev->dev,
MKDEV(IBM_TTY3270_MAJOR, rp->minor), NULL,
"tty%s", dev_name(&rp->cdev->dev));
if (IS_ERR(rp->clttydev)) {
rc = PTR_ERR(rp->clttydev);
goto out_ttydev;
}
rp->cltubdev = device_create(class3270, &rp->cdev->dev,
MKDEV(IBM_FS3270_MAJOR, rp->minor), NULL,
"tub%s", dev_name(&rp->cdev->dev));
if (!IS_ERR(rp->cltubdev))
goto out;
rc = PTR_ERR(rp->cltubdev);
device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
out_ttydev:
sysfs_remove_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
out:
return rc;
} }
/* /*
* Notifier for device addition/removal * Notifier for device addition/removal
*/ */
struct raw3270_notifier {
struct list_head list;
void (*notifier)(int, int);
};
static LIST_HEAD(raw3270_notifier); static LIST_HEAD(raw3270_notifier);
int raw3270_register_notifier(void (*notifier)(int, int)) int raw3270_register_notifier(struct raw3270_notifier *notifier)
{ {
struct raw3270_notifier *np;
struct raw3270 *rp; struct raw3270 *rp;
np = kmalloc(sizeof(struct raw3270_notifier), GFP_KERNEL);
if (!np)
return -ENOMEM;
np->notifier = notifier;
mutex_lock(&raw3270_mutex); mutex_lock(&raw3270_mutex);
list_add_tail(&np->list, &raw3270_notifier); list_add_tail(&notifier->list, &raw3270_notifier);
list_for_each_entry(rp, &raw3270_devices, list) { list_for_each_entry(rp, &raw3270_devices, list)
get_device(&rp->cdev->dev); notifier->create(rp->minor);
notifier(rp->minor, 1);
}
mutex_unlock(&raw3270_mutex); mutex_unlock(&raw3270_mutex);
return 0; return 0;
} }
void raw3270_unregister_notifier(void (*notifier)(int, int)) void raw3270_unregister_notifier(struct raw3270_notifier *notifier)
{ {
struct raw3270_notifier *np; struct raw3270 *rp;
mutex_lock(&raw3270_mutex); mutex_lock(&raw3270_mutex);
list_for_each_entry(np, &raw3270_notifier, list) list_for_each_entry(rp, &raw3270_devices, list)
if (np->notifier == notifier) { notifier->destroy(rp->minor);
list_del(&np->list); list_del(&notifier->list);
kfree(np);
break;
}
mutex_unlock(&raw3270_mutex); mutex_unlock(&raw3270_mutex);
} }
@ -1217,29 +1136,20 @@ void raw3270_unregister_notifier(void (*notifier)(int, int))
static int static int
raw3270_set_online (struct ccw_device *cdev) raw3270_set_online (struct ccw_device *cdev)
{ {
struct raw3270 *rp;
struct raw3270_notifier *np; struct raw3270_notifier *np;
struct raw3270 *rp;
int rc; int rc;
rp = raw3270_create_device(cdev); rp = raw3270_create_device(cdev);
if (IS_ERR(rp)) if (IS_ERR(rp))
return PTR_ERR(rp); return PTR_ERR(rp);
rc = raw3270_reset_device(rp);
if (rc)
goto failure;
rc = raw3270_size_device(rp);
if (rc)
goto failure;
rc = raw3270_reset_device(rp);
if (rc)
goto failure;
rc = raw3270_create_attributes(rp); rc = raw3270_create_attributes(rp);
if (rc) if (rc)
goto failure; goto failure;
set_bit(RAW3270_FLAGS_READY, &rp->flags); raw3270_reset_device(rp);
mutex_lock(&raw3270_mutex); mutex_lock(&raw3270_mutex);
list_for_each_entry(np, &raw3270_notifier, list) list_for_each_entry(np, &raw3270_notifier, list)
np->notifier(rp->minor, 1); np->create(rp->minor);
mutex_unlock(&raw3270_mutex); mutex_unlock(&raw3270_mutex);
return 0; return 0;
@ -1268,14 +1178,14 @@ raw3270_remove (struct ccw_device *cdev)
*/ */
if (rp == NULL) if (rp == NULL)
return; return;
clear_bit(RAW3270_FLAGS_READY, &rp->flags);
sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group); sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
/* Deactivate current view and remove all views. */ /* Deactivate current view and remove all views. */
spin_lock_irqsave(get_ccwdev_lock(cdev), flags); spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
if (rp->view) { if (rp->view) {
rp->view->fn->deactivate(rp->view); if (rp->view->fn->deactivate)
rp->view->fn->deactivate(rp->view);
rp->view = NULL; rp->view = NULL;
} }
while (!list_empty(&rp->view_list)) { while (!list_empty(&rp->view_list)) {
@ -1290,7 +1200,7 @@ raw3270_remove (struct ccw_device *cdev)
mutex_lock(&raw3270_mutex); mutex_lock(&raw3270_mutex);
list_for_each_entry(np, &raw3270_notifier, list) list_for_each_entry(np, &raw3270_notifier, list)
np->notifier(rp->minor, 0); np->destroy(rp->minor);
mutex_unlock(&raw3270_mutex); mutex_unlock(&raw3270_mutex);
/* Reset 3270 device. */ /* Reset 3270 device. */
@ -1324,7 +1234,7 @@ static int raw3270_pm_stop(struct ccw_device *cdev)
if (!rp) if (!rp)
return 0; return 0;
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
if (rp->view) if (rp->view && rp->view->fn->deactivate)
rp->view->fn->deactivate(rp->view); rp->view->fn->deactivate(rp->view);
if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) { if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) {
/* /*
@ -1351,7 +1261,7 @@ static int raw3270_pm_start(struct ccw_device *cdev)
return 0; return 0;
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags); clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
if (rp->view) if (rp->view && rp->view->fn->activate)
rp->view->fn->activate(rp->view); rp->view->fn->activate(rp->view);
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
return 0; return 0;
@ -1434,6 +1344,7 @@ MODULE_LICENSE("GPL");
module_init(raw3270_init); module_init(raw3270_init);
module_exit(raw3270_exit); module_exit(raw3270_exit);
EXPORT_SYMBOL(class3270);
EXPORT_SYMBOL(raw3270_request_alloc); EXPORT_SYMBOL(raw3270_request_alloc);
EXPORT_SYMBOL(raw3270_request_free); EXPORT_SYMBOL(raw3270_request_free);
EXPORT_SYMBOL(raw3270_request_reset); EXPORT_SYMBOL(raw3270_request_reset);

Просмотреть файл

@ -91,6 +91,7 @@ struct raw3270_iocb {
struct raw3270; struct raw3270;
struct raw3270_view; struct raw3270_view;
extern struct class *class3270;
/* 3270 CCW request */ /* 3270 CCW request */
struct raw3270_request { struct raw3270_request {
@ -140,6 +141,7 @@ struct raw3270_fn {
struct raw3270_request *, struct irb *); struct raw3270_request *, struct irb *);
void (*release)(struct raw3270_view *); void (*release)(struct raw3270_view *);
void (*free)(struct raw3270_view *); void (*free)(struct raw3270_view *);
void (*resize)(struct raw3270_view *, int, int, int);
}; };
/* /*
@ -192,8 +194,14 @@ struct raw3270 *raw3270_setup_console(struct ccw_device *cdev);
void raw3270_wait_cons_dev(struct raw3270 *); void raw3270_wait_cons_dev(struct raw3270 *);
/* Notifier for device addition/removal */ /* Notifier for device addition/removal */
int raw3270_register_notifier(void (*notifier)(int, int)); struct raw3270_notifier {
void raw3270_unregister_notifier(void (*notifier)(int, int)); struct list_head list;
void (*create)(int minor);
void (*destroy)(int minor);
};
int raw3270_register_notifier(struct raw3270_notifier *);
void raw3270_unregister_notifier(struct raw3270_notifier *);
void raw3270_pm_unfreeze(struct raw3270_view *); void raw3270_pm_unfreeze(struct raw3270_view *);
/* /*

Просмотреть файл

@ -450,7 +450,7 @@ sclp_sync_wait(void)
timeout = 0; timeout = 0;
if (timer_pending(&sclp_request_timer)) { if (timer_pending(&sclp_request_timer)) {
/* Get timeout TOD value */ /* Get timeout TOD value */
timeout = get_clock() + timeout = get_tod_clock() +
sclp_tod_from_jiffies(sclp_request_timer.expires - sclp_tod_from_jiffies(sclp_request_timer.expires -
jiffies); jiffies);
} }
@ -472,7 +472,7 @@ sclp_sync_wait(void)
while (sclp_running_state != sclp_running_state_idle) { while (sclp_running_state != sclp_running_state_idle) {
/* Check for expired request timer */ /* Check for expired request timer */
if (timer_pending(&sclp_request_timer) && if (timer_pending(&sclp_request_timer) &&
get_clock() > timeout && get_tod_clock() > timeout &&
del_timer(&sclp_request_timer)) del_timer(&sclp_request_timer))
sclp_request_timer.function(sclp_request_timer.data); sclp_request_timer.function(sclp_request_timer.data);
cpu_relax(); cpu_relax();

Просмотреть файл

@ -56,7 +56,6 @@ static int __initdata early_read_info_sccb_valid;
u64 sclp_facilities; u64 sclp_facilities;
static u8 sclp_fac84; static u8 sclp_fac84;
static u8 sclp_fac85;
static unsigned long long rzm; static unsigned long long rzm;
static unsigned long long rnmax; static unsigned long long rnmax;
@ -131,7 +130,8 @@ void __init sclp_facilities_detect(void)
sccb = &early_read_info_sccb; sccb = &early_read_info_sccb;
sclp_facilities = sccb->facilities; sclp_facilities = sccb->facilities;
sclp_fac84 = sccb->fac84; sclp_fac84 = sccb->fac84;
sclp_fac85 = sccb->fac85; if (sccb->fac85 & 0x02)
S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
rzm <<= 20; rzm <<= 20;
@ -171,12 +171,6 @@ unsigned long long sclp_get_rzm(void)
return rzm; return rzm;
} }
u8 sclp_get_fac85(void)
{
return sclp_fac85;
}
EXPORT_SYMBOL_GPL(sclp_get_fac85);
/* /*
* This function will be called after sclp_facilities_detect(), which gets * This function will be called after sclp_facilities_detect(), which gets
* called from early.c code. Therefore the sccb should have valid contents. * called from early.c code. Therefore the sccb should have valid contents.

Просмотреть файл

@ -15,6 +15,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
@ -80,6 +81,8 @@ struct tty3270 {
unsigned int highlight; /* Blink/reverse/underscore */ unsigned int highlight; /* Blink/reverse/underscore */
unsigned int f_color; /* Foreground color */ unsigned int f_color; /* Foreground color */
struct tty3270_line *screen; struct tty3270_line *screen;
unsigned int n_model, n_cols, n_rows; /* New model & size */
struct work_struct resize_work;
/* Input stuff. */ /* Input stuff. */
struct string *prompt; /* Output string for input area. */ struct string *prompt; /* Output string for input area. */
@ -115,6 +118,7 @@ struct tty3270 {
#define TTY_UPDATE_ALL 16 /* Recreate screen. */ #define TTY_UPDATE_ALL 16 /* Recreate screen. */
static void tty3270_update(struct tty3270 *); static void tty3270_update(struct tty3270 *);
static void tty3270_resize_work(struct work_struct *work);
/* /*
* Setup timeout for a device. On timeout trigger an update. * Setup timeout for a device. On timeout trigger an update.
@ -683,12 +687,6 @@ tty3270_alloc_view(void)
INIT_LIST_HEAD(&tp->update); INIT_LIST_HEAD(&tp->update);
INIT_LIST_HEAD(&tp->rcl_lines); INIT_LIST_HEAD(&tp->rcl_lines);
tp->rcl_max = 20; tp->rcl_max = 20;
tty_port_init(&tp->port);
setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
(unsigned long) tp);
tasklet_init(&tp->readlet,
(void (*)(unsigned long)) tty3270_read_tasklet,
(unsigned long) tp->read);
for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) { for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
tp->freemem_pages[pages] = (void *) tp->freemem_pages[pages] = (void *)
@ -710,6 +708,15 @@ tty3270_alloc_view(void)
tp->kbd = kbd_alloc(); tp->kbd = kbd_alloc();
if (!tp->kbd) if (!tp->kbd)
goto out_reset; goto out_reset;
tty_port_init(&tp->port);
setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
(unsigned long) tp);
tasklet_init(&tp->readlet,
(void (*)(unsigned long)) tty3270_read_tasklet,
(unsigned long) tp->read);
INIT_WORK(&tp->resize_work, tty3270_resize_work);
return tp; return tp;
out_reset: out_reset:
@ -752,42 +759,96 @@ tty3270_free_view(struct tty3270 *tp)
/* /*
* Allocate tty3270 screen. * Allocate tty3270 screen.
*/ */
static int static struct tty3270_line *
tty3270_alloc_screen(struct tty3270 *tp) tty3270_alloc_screen(unsigned int rows, unsigned int cols)
{ {
struct tty3270_line *screen;
unsigned long size; unsigned long size;
int lines; int lines;
size = sizeof(struct tty3270_line) * (tp->view.rows - 2); size = sizeof(struct tty3270_line) * (rows - 2);
tp->screen = kzalloc(size, GFP_KERNEL); screen = kzalloc(size, GFP_KERNEL);
if (!tp->screen) if (!screen)
goto out_err; goto out_err;
for (lines = 0; lines < tp->view.rows - 2; lines++) { for (lines = 0; lines < rows - 2; lines++) {
size = sizeof(struct tty3270_cell) * tp->view.cols; size = sizeof(struct tty3270_cell) * cols;
tp->screen[lines].cells = kzalloc(size, GFP_KERNEL); screen[lines].cells = kzalloc(size, GFP_KERNEL);
if (!tp->screen[lines].cells) if (!screen[lines].cells)
goto out_screen; goto out_screen;
} }
return 0; return screen;
out_screen: out_screen:
while (lines--) while (lines--)
kfree(tp->screen[lines].cells); kfree(screen[lines].cells);
kfree(tp->screen); kfree(screen);
out_err: out_err:
return -ENOMEM; return ERR_PTR(-ENOMEM);
} }
/* /*
* Free tty3270 screen. * Free tty3270 screen.
*/ */
static void static void
tty3270_free_screen(struct tty3270 *tp) tty3270_free_screen(struct tty3270_line *screen, unsigned int rows)
{ {
int lines; int lines;
for (lines = 0; lines < tp->view.rows - 2; lines++) for (lines = 0; lines < rows - 2; lines++)
kfree(tp->screen[lines].cells); kfree(screen[lines].cells);
kfree(tp->screen); kfree(screen);
}
/*
* Resize tty3270 screen
*/
static void tty3270_resize_work(struct work_struct *work)
{
struct tty3270 *tp = container_of(work, struct tty3270, resize_work);
struct tty3270_line *screen, *oscreen;
struct tty_struct *tty;
unsigned int orows;
struct winsize ws;
screen = tty3270_alloc_screen(tp->n_rows, tp->n_cols);
if (!screen)
return;
/* Switch to new output size */
spin_lock_bh(&tp->view.lock);
oscreen = tp->screen;
orows = tp->view.rows;
tp->view.model = tp->n_model;
tp->view.rows = tp->n_rows;
tp->view.cols = tp->n_cols;
tp->screen = screen;
free_string(&tp->freemem, tp->prompt);
free_string(&tp->freemem, tp->status);
tty3270_create_prompt(tp);
tty3270_create_status(tp);
tp->nr_up = 0;
while (tp->nr_lines < tp->view.rows - 2)
tty3270_blank_line(tp);
tp->update_flags = TTY_UPDATE_ALL;
spin_unlock_bh(&tp->view.lock);
tty3270_free_screen(oscreen, orows);
tty3270_set_timer(tp, 1);
/* Informat tty layer about new size */
tty = tty_port_tty_get(&tp->port);
if (!tty)
return;
ws.ws_row = tp->view.rows - 2;
ws.ws_col = tp->view.cols;
tty_do_resize(tty, &ws);
}
static void
tty3270_resize(struct raw3270_view *view, int model, int rows, int cols)
{
struct tty3270 *tp = container_of(view, struct tty3270, view);
tp->n_model = model;
tp->n_rows = rows;
tp->n_cols = cols;
schedule_work(&tp->resize_work);
} }
/* /*
@ -815,7 +876,8 @@ static void
tty3270_free(struct raw3270_view *view) tty3270_free(struct raw3270_view *view)
{ {
struct tty3270 *tp = container_of(view, struct tty3270, view); struct tty3270 *tp = container_of(view, struct tty3270, view);
tty3270_free_screen(tp);
tty3270_free_screen(tp->screen, tp->view.rows);
tty3270_free_view(tp); tty3270_free_view(tp);
} }
@ -827,9 +889,8 @@ tty3270_del_views(void)
{ {
int i; int i;
for (i = 0; i < tty3270_max_index; i++) { for (i = RAW3270_FIRSTMINOR; i <= tty3270_max_index; i++) {
struct raw3270_view *view = struct raw3270_view *view = raw3270_find_view(&tty3270_fn, i);
raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
if (!IS_ERR(view)) if (!IS_ERR(view))
raw3270_del_view(view); raw3270_del_view(view);
} }
@ -840,7 +901,8 @@ static struct raw3270_fn tty3270_fn = {
.deactivate = tty3270_deactivate, .deactivate = tty3270_deactivate,
.intv = (void *) tty3270_irq, .intv = (void *) tty3270_irq,
.release = tty3270_release, .release = tty3270_release,
.free = tty3270_free .free = tty3270_free,
.resize = tty3270_resize
}; };
/* /*
@ -853,8 +915,7 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
int i, rc; int i, rc;
/* Check if the tty3270 is already there. */ /* Check if the tty3270 is already there. */
view = raw3270_find_view(&tty3270_fn, view = raw3270_find_view(&tty3270_fn, tty->index);
tty->index + RAW3270_FIRSTMINOR);
if (!IS_ERR(view)) { if (!IS_ERR(view)) {
tp = container_of(view, struct tty3270, view); tp = container_of(view, struct tty3270, view);
tty->driver_data = tp; tty->driver_data = tp;
@ -866,29 +927,26 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
tp->inattr = TF_INPUT; tp->inattr = TF_INPUT;
return tty_port_install(&tp->port, driver, tty); return tty_port_install(&tp->port, driver, tty);
} }
if (tty3270_max_index < tty->index + 1) if (tty3270_max_index < tty->index)
tty3270_max_index = tty->index + 1; tty3270_max_index = tty->index;
/* Quick exit if there is no device for tty->index. */
if (PTR_ERR(view) == -ENODEV)
return -ENODEV;
/* Allocate tty3270 structure on first open. */ /* Allocate tty3270 structure on first open. */
tp = tty3270_alloc_view(); tp = tty3270_alloc_view();
if (IS_ERR(tp)) if (IS_ERR(tp))
return PTR_ERR(tp); return PTR_ERR(tp);
rc = raw3270_add_view(&tp->view, &tty3270_fn, rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index);
tty->index + RAW3270_FIRSTMINOR);
if (rc) { if (rc) {
tty3270_free_view(tp); tty3270_free_view(tp);
return rc; return rc;
} }
rc = tty3270_alloc_screen(tp); tp->screen = tty3270_alloc_screen(tp->view.cols, tp->view.rows);
if (rc) { if (IS_ERR(tp->screen)) {
rc = PTR_ERR(tp->screen);
raw3270_put_view(&tp->view); raw3270_put_view(&tp->view);
raw3270_del_view(&tp->view); raw3270_del_view(&tp->view);
tty3270_free_view(tp);
return rc; return rc;
} }
@ -925,6 +983,20 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
return 0; return 0;
} }
/*
* This routine is called whenever a 3270 tty is opened.
*/
static int
tty3270_open(struct tty_struct *tty, struct file *filp)
{
struct tty3270 *tp = tty->driver_data;
struct tty_port *port = &tp->port;
port->count++;
tty_port_tty_set(port, tty);
return 0;
}
/* /*
* This routine is called when the 3270 tty is closed. We wait * This routine is called when the 3270 tty is closed. We wait
* for the remaining request to be completed. Then we clean up. * for the remaining request to be completed. Then we clean up.
@ -1753,6 +1825,7 @@ static long tty3270_compat_ioctl(struct tty_struct *tty,
static const struct tty_operations tty3270_ops = { static const struct tty_operations tty3270_ops = {
.install = tty3270_install, .install = tty3270_install,
.cleanup = tty3270_cleanup, .cleanup = tty3270_cleanup,
.open = tty3270_open,
.close = tty3270_close, .close = tty3270_close,
.write = tty3270_write, .write = tty3270_write,
.put_char = tty3270_put_char, .put_char = tty3270_put_char,
@ -1771,6 +1844,22 @@ static const struct tty_operations tty3270_ops = {
.set_termios = tty3270_set_termios .set_termios = tty3270_set_termios
}; };
void tty3270_create_cb(int minor)
{
tty_register_device(tty3270_driver, minor, NULL);
}
void tty3270_destroy_cb(int minor)
{
tty_unregister_device(tty3270_driver, minor);
}
struct raw3270_notifier tty3270_notifier =
{
.create = tty3270_create_cb,
.destroy = tty3270_destroy_cb,
};
/* /*
* 3270 tty registration code called from tty_init(). * 3270 tty registration code called from tty_init().
* Most kernel services (incl. kmalloc) are available at this poimt. * Most kernel services (incl. kmalloc) are available at this poimt.
@ -1780,23 +1869,25 @@ static int __init tty3270_init(void)
struct tty_driver *driver; struct tty_driver *driver;
int ret; int ret;
driver = alloc_tty_driver(RAW3270_MAXDEVS); driver = tty_alloc_driver(RAW3270_MAXDEVS,
if (!driver) TTY_DRIVER_REAL_RAW |
return -ENOMEM; TTY_DRIVER_DYNAMIC_DEV |
TTY_DRIVER_RESET_TERMIOS);
if (IS_ERR(driver))
return PTR_ERR(driver);
/* /*
* Initialize the tty_driver structure * Initialize the tty_driver structure
* Entries in tty3270_driver that are NOT initialized: * Entries in tty3270_driver that are NOT initialized:
* proc_entry, set_termios, flush_buffer, set_ldisc, write_proc * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
*/ */
driver->driver_name = "ttyTUB"; driver->driver_name = "tty3270";
driver->name = "ttyTUB"; driver->name = "3270/tty";
driver->major = IBM_TTY3270_MAJOR; driver->major = IBM_TTY3270_MAJOR;
driver->minor_start = RAW3270_FIRSTMINOR; driver->minor_start = 0;
driver->type = TTY_DRIVER_TYPE_SYSTEM; driver->type = TTY_DRIVER_TYPE_SYSTEM;
driver->subtype = SYSTEM_TYPE_TTY; driver->subtype = SYSTEM_TYPE_TTY;
driver->init_termios = tty_std_termios; driver->init_termios = tty_std_termios;
driver->flags = TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(driver, &tty3270_ops); tty_set_operations(driver, &tty3270_ops);
ret = tty_register_driver(driver); ret = tty_register_driver(driver);
if (ret) { if (ret) {
@ -1804,6 +1895,7 @@ static int __init tty3270_init(void)
return ret; return ret;
} }
tty3270_driver = driver; tty3270_driver = driver;
raw3270_register_notifier(&tty3270_notifier);
return 0; return 0;
} }
@ -1812,6 +1904,7 @@ tty3270_exit(void)
{ {
struct tty_driver *driver; struct tty_driver *driver;
raw3270_unregister_notifier(&tty3270_notifier);
driver = tty3270_driver; driver = tty3270_driver;
tty3270_driver = NULL; tty3270_driver = NULL;
tty_unregister_driver(driver); tty_unregister_driver(driver);

Просмотреть файл

@ -62,6 +62,7 @@ static struct dentry *zcore_dir;
static struct dentry *zcore_file; static struct dentry *zcore_file;
static struct dentry *zcore_memmap_file; static struct dentry *zcore_memmap_file;
static struct dentry *zcore_reipl_file; static struct dentry *zcore_reipl_file;
static struct dentry *zcore_hsa_file;
static struct ipl_parameter_block *ipl_block; static struct ipl_parameter_block *ipl_block;
/* /*
@ -77,6 +78,8 @@ static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
int offs, blk_num; int offs, blk_num;
static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
if (!hsa_available)
return -ENODATA;
if (count == 0) if (count == 0)
return 0; return 0;
@ -277,6 +280,15 @@ next:
return 0; return 0;
} }
/*
* Release the HSA
*/
static void release_hsa(void)
{
diag308(DIAG308_REL_HSA, NULL);
hsa_available = 0;
}
/* /*
* Read routine for zcore character device * Read routine for zcore character device
* First 4K are dump header * First 4K are dump header
@ -363,8 +375,8 @@ static int zcore_open(struct inode *inode, struct file *filp)
static int zcore_release(struct inode *inode, struct file *filep) static int zcore_release(struct inode *inode, struct file *filep)
{ {
diag308(DIAG308_REL_HSA, NULL); if (hsa_available)
hsa_available = 0; release_hsa();
return 0; return 0;
} }
@ -474,6 +486,41 @@ static const struct file_operations zcore_reipl_fops = {
.llseek = no_llseek, .llseek = no_llseek,
}; };
static ssize_t zcore_hsa_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
static char str[18];
if (hsa_available)
snprintf(str, sizeof(str), "%lx\n", ZFCPDUMP_HSA_SIZE);
else
snprintf(str, sizeof(str), "0\n");
return simple_read_from_buffer(buf, count, ppos, str, strlen(str));
}
static ssize_t zcore_hsa_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
char value;
if (*ppos != 0)
return -EPIPE;
if (copy_from_user(&value, buf, 1))
return -EFAULT;
if (value != '0')
return -EINVAL;
release_hsa();
return count;
}
static const struct file_operations zcore_hsa_fops = {
.owner = THIS_MODULE,
.write = zcore_hsa_write,
.read = zcore_hsa_read,
.open = nonseekable_open,
.llseek = no_llseek,
};
#ifdef CONFIG_32BIT #ifdef CONFIG_32BIT
static void __init set_lc_mask(struct save_area *map) static void __init set_lc_mask(struct save_area *map)
@ -590,7 +637,7 @@ static int __init zcore_header_init(int arch, struct zcore_header *hdr)
hdr->rmem_size = memory; hdr->rmem_size = memory;
hdr->mem_end = sys_info.mem_size; hdr->mem_end = sys_info.mem_size;
hdr->num_pages = memory / PAGE_SIZE; hdr->num_pages = memory / PAGE_SIZE;
hdr->tod = get_clock(); hdr->tod = get_tod_clock();
get_cpu_id(&hdr->cpu_id); get_cpu_id(&hdr->cpu_id);
for (i = 0; zfcpdump_save_areas[i]; i++) { for (i = 0; zfcpdump_save_areas[i]; i++) {
prefix = zfcpdump_save_areas[i]->pref_reg; prefix = zfcpdump_save_areas[i]->pref_reg;
@ -658,6 +705,7 @@ static int __init zcore_init(void)
rc = check_sdias(); rc = check_sdias();
if (rc) if (rc)
goto fail; goto fail;
hsa_available = 1;
rc = memcpy_hsa_kernel(&arch, __LC_AR_MODE_ID, 1); rc = memcpy_hsa_kernel(&arch, __LC_AR_MODE_ID, 1);
if (rc) if (rc)
@ -714,9 +762,16 @@ static int __init zcore_init(void)
rc = -ENOMEM; rc = -ENOMEM;
goto fail_memmap_file; goto fail_memmap_file;
} }
hsa_available = 1; zcore_hsa_file = debugfs_create_file("hsa", S_IRUSR|S_IWUSR, zcore_dir,
NULL, &zcore_hsa_fops);
if (!zcore_hsa_file) {
rc = -ENOMEM;
goto fail_reipl_file;
}
return 0; return 0;
fail_reipl_file:
debugfs_remove(zcore_reipl_file);
fail_memmap_file: fail_memmap_file:
debugfs_remove(zcore_memmap_file); debugfs_remove(zcore_memmap_file);
fail_file: fail_file:
@ -733,6 +788,7 @@ static void __exit zcore_exit(void)
debug_unregister(zcore_dbf); debug_unregister(zcore_dbf);
sclp_sdias_exit(); sclp_sdias_exit();
free_page((unsigned long) ipl_block); free_page((unsigned long) ipl_block);
debugfs_remove(zcore_hsa_file);
debugfs_remove(zcore_reipl_file); debugfs_remove(zcore_reipl_file);
debugfs_remove(zcore_memmap_file); debugfs_remove(zcore_memmap_file);
debugfs_remove(zcore_file); debugfs_remove(zcore_file);

Просмотреть файл

@ -435,7 +435,6 @@ static void chsc_process_sei_scm_change(struct chsc_sei_nt0_area *sei_area)
static void chsc_process_sei_nt2(struct chsc_sei_nt2_area *sei_area) static void chsc_process_sei_nt2(struct chsc_sei_nt2_area *sei_area)
{ {
#ifdef CONFIG_PCI
switch (sei_area->cc) { switch (sei_area->cc) {
case 1: case 1:
zpci_event_error(sei_area->ccdf); zpci_event_error(sei_area->ccdf);
@ -444,11 +443,10 @@ static void chsc_process_sei_nt2(struct chsc_sei_nt2_area *sei_area)
zpci_event_availability(sei_area->ccdf); zpci_event_availability(sei_area->ccdf);
break; break;
default: default:
CIO_CRW_EVENT(2, "chsc: unhandled sei content code %d\n", CIO_CRW_EVENT(2, "chsc: sei nt2 unhandled cc=%d\n",
sei_area->cc); sei_area->cc);
break; break;
} }
#endif
} }
static void chsc_process_sei_nt0(struct chsc_sei_nt0_area *sei_area) static void chsc_process_sei_nt0(struct chsc_sei_nt0_area *sei_area)
@ -471,13 +469,19 @@ static void chsc_process_sei_nt0(struct chsc_sei_nt0_area *sei_area)
chsc_process_sei_scm_change(sei_area); chsc_process_sei_scm_change(sei_area);
break; break;
default: /* other stuff */ default: /* other stuff */
CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", CIO_CRW_EVENT(2, "chsc: sei nt0 unhandled cc=%d\n",
sei_area->cc); sei_area->cc);
break; break;
} }
/* Check if we might have lost some information. */
if (sei_area->flags & 0x40) {
CIO_CRW_EVENT(2, "chsc: event overflow\n");
css_schedule_eval_all();
}
} }
static int __chsc_process_crw(struct chsc_sei *sei, u64 ntsm) static void chsc_process_event_information(struct chsc_sei *sei, u64 ntsm)
{ {
do { do {
memset(sei, 0, sizeof(*sei)); memset(sei, 0, sizeof(*sei));
@ -488,40 +492,37 @@ static int __chsc_process_crw(struct chsc_sei *sei, u64 ntsm)
if (chsc(sei)) if (chsc(sei))
break; break;
if (sei->response.code == 0x0001) { if (sei->response.code != 0x0001) {
CIO_CRW_EVENT(2, "chsc: sei successful\n");
/* Check if we might have lost some information. */
if (sei->u.nt0_area.flags & 0x40) {
CIO_CRW_EVENT(2, "chsc: event overflow\n");
css_schedule_eval_all();
}
switch (sei->nt) {
case 0:
chsc_process_sei_nt0(&sei->u.nt0_area);
break;
case 2:
chsc_process_sei_nt2(&sei->u.nt2_area);
break;
default:
CIO_CRW_EVENT(2, "chsc: unhandled nt=%d\n",
sei->nt);
break;
}
} else {
CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
sei->response.code); sei->response.code);
break; break;
} }
} while (sei->u.nt0_area.flags & 0x80);
return 0; CIO_CRW_EVENT(2, "chsc: sei successful (nt=%d)\n", sei->nt);
switch (sei->nt) {
case 0:
chsc_process_sei_nt0(&sei->u.nt0_area);
break;
case 2:
chsc_process_sei_nt2(&sei->u.nt2_area);
break;
default:
CIO_CRW_EVENT(2, "chsc: unhandled nt: %d\n", sei->nt);
break;
}
} while (sei->u.nt0_area.flags & 0x80);
} }
/*
* Handle channel subsystem related CRWs.
* Use store event information to find out what's going on.
*
* Note: Access to sei_page is serialized through machine check handler
* thread, so no need for locking.
*/
static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow) static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
{ {
struct chsc_sei *sei; struct chsc_sei *sei = sei_page;
if (overflow) { if (overflow) {
css_schedule_eval_all(); css_schedule_eval_all();
@ -531,14 +532,9 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
"chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc, crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,
crw0->erc, crw0->rsid); crw0->erc, crw0->rsid);
if (!sei_page)
return;
/* Access to sei_page is serialized through machine check handler
* thread, so no need for locking. */
sei = sei_page;
CIO_TRACE_EVENT(2, "prcss"); CIO_TRACE_EVENT(2, "prcss");
__chsc_process_crw(sei, CHSC_SEI_NT0 | CHSC_SEI_NT2); chsc_process_event_information(sei, CHSC_SEI_NT0 | CHSC_SEI_NT2);
} }
void chsc_chp_online(struct chp_id chpid) void chsc_chp_online(struct chp_id chpid)

Просмотреть файл

@ -157,7 +157,7 @@ int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token);
#ifdef CONFIG_SCM_BUS #ifdef CONFIG_SCM_BUS
int scm_update_information(void); int scm_update_information(void);
#else /* CONFIG_SCM_BUS */ #else /* CONFIG_SCM_BUS */
#define scm_update_information() 0 static inline int scm_update_information(void) { return 0; }
#endif /* CONFIG_SCM_BUS */ #endif /* CONFIG_SCM_BUS */

Просмотреть файл

@ -962,9 +962,9 @@ static void css_reset(void)
atomic_inc(&chpid_reset_count); atomic_inc(&chpid_reset_count);
} }
/* Wait for machine check for all channel paths. */ /* Wait for machine check for all channel paths. */
timeout = get_clock() + (RCHP_TIMEOUT << 12); timeout = get_tod_clock() + (RCHP_TIMEOUT << 12);
while (atomic_read(&chpid_reset_count) != 0) { while (atomic_read(&chpid_reset_count) != 0) {
if (get_clock() > timeout) if (get_tod_clock() > timeout)
break; break;
cpu_relax(); cpu_relax();
} }

Просмотреть файл

@ -33,7 +33,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/timex.h> /* get_clock() */ #include <linux/timex.h> /* get_tod_clock() */
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#include <asm/cio.h> #include <asm/cio.h>
@ -326,7 +326,7 @@ static int cmf_copy_block(struct ccw_device *cdev)
memcpy(cmb_data->last_block, hw_block, cmb_data->size); memcpy(cmb_data->last_block, hw_block, cmb_data->size);
memcpy(reference_buf, hw_block, cmb_data->size); memcpy(reference_buf, hw_block, cmb_data->size);
} while (memcmp(cmb_data->last_block, reference_buf, cmb_data->size)); } while (memcmp(cmb_data->last_block, reference_buf, cmb_data->size));
cmb_data->last_update = get_clock(); cmb_data->last_update = get_tod_clock();
kfree(reference_buf); kfree(reference_buf);
return 0; return 0;
} }
@ -428,7 +428,7 @@ static void cmf_generic_reset(struct ccw_device *cdev)
memset(cmbops->align(cmb_data->hw_block), 0, cmb_data->size); memset(cmbops->align(cmb_data->hw_block), 0, cmb_data->size);
cmb_data->last_update = 0; cmb_data->last_update = 0;
} }
cdev->private->cmb_start_time = get_clock(); cdev->private->cmb_start_time = get_tod_clock();
spin_unlock_irq(cdev->ccwlock); spin_unlock_irq(cdev->ccwlock);
} }

Просмотреть файл

@ -780,7 +780,7 @@ static int __init setup_css(int nr)
css->cssid = nr; css->cssid = nr;
dev_set_name(&css->device, "css%x", nr); dev_set_name(&css->device, "css%x", nr);
css->device.release = channel_subsystem_release; css->device.release = channel_subsystem_release;
tod_high = (u32) (get_clock() >> 32); tod_high = (u32) (get_tod_clock() >> 32);
css_generate_pgid(css, tod_high); css_generate_pgid(css, tod_high);
return 0; return 0;
} }

Просмотреть файл

@ -632,6 +632,14 @@ initiate_logging(struct device *dev, struct device_attribute *attr,
return count; return count;
} }
static ssize_t vpm_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct subchannel *sch = to_subchannel(dev);
return sprintf(buf, "%02x\n", sch->vpm);
}
static DEVICE_ATTR(chpids, 0444, chpids_show, NULL); static DEVICE_ATTR(chpids, 0444, chpids_show, NULL);
static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL); static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL);
static DEVICE_ATTR(devtype, 0444, devtype_show, NULL); static DEVICE_ATTR(devtype, 0444, devtype_show, NULL);
@ -640,11 +648,13 @@ static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
static DEVICE_ATTR(online, 0644, online_show, online_store); static DEVICE_ATTR(online, 0644, online_show, online_store);
static DEVICE_ATTR(availability, 0444, available_show, NULL); static DEVICE_ATTR(availability, 0444, available_show, NULL);
static DEVICE_ATTR(logging, 0200, NULL, initiate_logging); static DEVICE_ATTR(logging, 0200, NULL, initiate_logging);
static DEVICE_ATTR(vpm, 0444, vpm_show, NULL);
static struct attribute *io_subchannel_attrs[] = { static struct attribute *io_subchannel_attrs[] = {
&dev_attr_chpids.attr, &dev_attr_chpids.attr,
&dev_attr_pimpampom.attr, &dev_attr_pimpampom.attr,
&dev_attr_logging.attr, &dev_attr_logging.attr,
&dev_attr_vpm.attr,
NULL, NULL,
}; };

Просмотреть файл

@ -47,7 +47,7 @@ static void ccw_timeout_log(struct ccw_device *cdev)
cc = stsch_err(sch->schid, &schib); cc = stsch_err(sch->schid, &schib);
printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, " printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
"device information:\n", get_clock()); "device information:\n", get_tod_clock());
printk(KERN_WARNING "cio: orb:\n"); printk(KERN_WARNING "cio: orb:\n");
print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1,
orb, sizeof(*orb), 0); orb, sizeof(*orb), 0);

Просмотреть файл

@ -23,6 +23,8 @@
#define PGID_RETRIES 256 #define PGID_RETRIES 256
#define PGID_TIMEOUT (10 * HZ) #define PGID_TIMEOUT (10 * HZ)
static void verify_start(struct ccw_device *cdev);
/* /*
* Process path verification data and report result. * Process path verification data and report result.
*/ */
@ -70,8 +72,8 @@ static void nop_do(struct ccw_device *cdev)
struct subchannel *sch = to_subchannel(cdev->dev.parent); struct subchannel *sch = to_subchannel(cdev->dev.parent);
struct ccw_request *req = &cdev->private->req; struct ccw_request *req = &cdev->private->req;
/* Adjust lpm. */ req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam & sch->opm &
req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam & sch->opm); ~cdev->private->path_noirq_mask);
if (!req->lpm) if (!req->lpm)
goto out_nopath; goto out_nopath;
nop_build_cp(cdev); nop_build_cp(cdev);
@ -102,10 +104,20 @@ static void nop_callback(struct ccw_device *cdev, void *data, int rc)
struct subchannel *sch = to_subchannel(cdev->dev.parent); struct subchannel *sch = to_subchannel(cdev->dev.parent);
struct ccw_request *req = &cdev->private->req; struct ccw_request *req = &cdev->private->req;
if (rc == 0) switch (rc) {
case 0:
sch->vpm |= req->lpm; sch->vpm |= req->lpm;
else if (rc != -EACCES) break;
case -ETIME:
cdev->private->path_noirq_mask |= req->lpm;
break;
case -EACCES:
cdev->private->path_notoper_mask |= req->lpm;
break;
default:
goto err; goto err;
}
/* Continue on the next path. */
req->lpm >>= 1; req->lpm >>= 1;
nop_do(cdev); nop_do(cdev);
return; return;
@ -132,6 +144,48 @@ static void spid_build_cp(struct ccw_device *cdev, u8 fn)
req->cp = cp; req->cp = cp;
} }
static void pgid_wipeout_callback(struct ccw_device *cdev, void *data, int rc)
{
if (rc) {
/* We don't know the path groups' state. Abort. */
verify_done(cdev, rc);
return;
}
/*
* Path groups have been reset. Restart path verification but
* leave paths in path_noirq_mask out.
*/
cdev->private->flags.pgid_unknown = 0;
verify_start(cdev);
}
/*
* Reset pathgroups and restart path verification, leave unusable paths out.
*/
static void pgid_wipeout_start(struct ccw_device *cdev)
{
struct subchannel *sch = to_subchannel(cdev->dev.parent);
struct ccw_dev_id *id = &cdev->private->dev_id;
struct ccw_request *req = &cdev->private->req;
u8 fn;
CIO_MSG_EVENT(2, "wipe: device 0.%x.%04x: pvm=%02x nim=%02x\n",
id->ssid, id->devno, cdev->private->pgid_valid_mask,
cdev->private->path_noirq_mask);
/* Initialize request data. */
memset(req, 0, sizeof(*req));
req->timeout = PGID_TIMEOUT;
req->maxretries = PGID_RETRIES;
req->lpm = sch->schib.pmcw.pam;
req->callback = pgid_wipeout_callback;
fn = SPID_FUNC_DISBAND;
if (cdev->private->flags.mpath)
fn |= SPID_FUNC_MULTI_PATH;
spid_build_cp(cdev, fn);
ccw_request_start(cdev);
}
/* /*
* Perform establish/resign SET PGID on a single path. * Perform establish/resign SET PGID on a single path.
*/ */
@ -157,11 +211,14 @@ static void spid_do(struct ccw_device *cdev)
return; return;
out_nopath: out_nopath:
if (cdev->private->flags.pgid_unknown) {
/* At least one SPID could be partially done. */
pgid_wipeout_start(cdev);
return;
}
verify_done(cdev, sch->vpm ? 0 : -EACCES); verify_done(cdev, sch->vpm ? 0 : -EACCES);
} }
static void verify_start(struct ccw_device *cdev);
/* /*
* Process SET PGID request result for a single path. * Process SET PGID request result for a single path.
*/ */
@ -174,7 +231,12 @@ static void spid_callback(struct ccw_device *cdev, void *data, int rc)
case 0: case 0:
sch->vpm |= req->lpm & sch->opm; sch->vpm |= req->lpm & sch->opm;
break; break;
case -ETIME:
cdev->private->flags.pgid_unknown = 1;
cdev->private->path_noirq_mask |= req->lpm;
break;
case -EACCES: case -EACCES:
cdev->private->path_notoper_mask |= req->lpm;
break; break;
case -EOPNOTSUPP: case -EOPNOTSUPP:
if (cdev->private->flags.mpath) { if (cdev->private->flags.mpath) {
@ -330,8 +392,9 @@ static void snid_done(struct ccw_device *cdev, int rc)
else { else {
donepm = pgid_to_donepm(cdev); donepm = pgid_to_donepm(cdev);
sch->vpm = donepm & sch->opm; sch->vpm = donepm & sch->opm;
cdev->private->pgid_todo_mask &= ~donepm;
cdev->private->pgid_reset_mask |= reset; cdev->private->pgid_reset_mask |= reset;
cdev->private->pgid_todo_mask &=
~(donepm | cdev->private->path_noirq_mask);
pgid_fill(cdev, pgid); pgid_fill(cdev, pgid);
} }
out: out:
@ -341,6 +404,10 @@ out:
cdev->private->pgid_todo_mask, mismatch, reserved, reset); cdev->private->pgid_todo_mask, mismatch, reserved, reset);
switch (rc) { switch (rc) {
case 0: case 0:
if (cdev->private->flags.pgid_unknown) {
pgid_wipeout_start(cdev);
return;
}
/* Anything left to do? */ /* Anything left to do? */
if (cdev->private->pgid_todo_mask == 0) { if (cdev->private->pgid_todo_mask == 0) {
verify_done(cdev, sch->vpm == 0 ? -EACCES : 0); verify_done(cdev, sch->vpm == 0 ? -EACCES : 0);
@ -384,9 +451,10 @@ static void snid_do(struct ccw_device *cdev)
{ {
struct subchannel *sch = to_subchannel(cdev->dev.parent); struct subchannel *sch = to_subchannel(cdev->dev.parent);
struct ccw_request *req = &cdev->private->req; struct ccw_request *req = &cdev->private->req;
int ret;
/* Adjust lpm if paths are not set in pam. */ req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam &
req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam); ~cdev->private->path_noirq_mask);
if (!req->lpm) if (!req->lpm)
goto out_nopath; goto out_nopath;
snid_build_cp(cdev); snid_build_cp(cdev);
@ -394,7 +462,13 @@ static void snid_do(struct ccw_device *cdev)
return; return;
out_nopath: out_nopath:
snid_done(cdev, cdev->private->pgid_valid_mask ? 0 : -EACCES); if (cdev->private->pgid_valid_mask)
ret = 0;
else if (cdev->private->path_noirq_mask)
ret = -ETIME;
else
ret = -EACCES;
snid_done(cdev, ret);
} }
/* /*
@ -404,10 +478,21 @@ static void snid_callback(struct ccw_device *cdev, void *data, int rc)
{ {
struct ccw_request *req = &cdev->private->req; struct ccw_request *req = &cdev->private->req;
if (rc == 0) switch (rc) {
case 0:
cdev->private->pgid_valid_mask |= req->lpm; cdev->private->pgid_valid_mask |= req->lpm;
else if (rc != -EACCES) break;
case -ETIME:
cdev->private->flags.pgid_unknown = 1;
cdev->private->path_noirq_mask |= req->lpm;
break;
case -EACCES:
cdev->private->path_notoper_mask |= req->lpm;
break;
default:
goto err; goto err;
}
/* Continue on the next path. */
req->lpm >>= 1; req->lpm >>= 1;
snid_do(cdev); snid_do(cdev);
return; return;
@ -427,6 +512,13 @@ static void verify_start(struct ccw_device *cdev)
sch->vpm = 0; sch->vpm = 0;
sch->lpm = sch->schib.pmcw.pam; sch->lpm = sch->schib.pmcw.pam;
/* Initialize PGID data. */
memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
cdev->private->pgid_valid_mask = 0;
cdev->private->pgid_todo_mask = sch->schib.pmcw.pam;
cdev->private->path_notoper_mask = 0;
/* Initialize request data. */ /* Initialize request data. */
memset(req, 0, sizeof(*req)); memset(req, 0, sizeof(*req));
req->timeout = PGID_TIMEOUT; req->timeout = PGID_TIMEOUT;
@ -459,14 +551,8 @@ static void verify_start(struct ccw_device *cdev)
*/ */
void ccw_device_verify_start(struct ccw_device *cdev) void ccw_device_verify_start(struct ccw_device *cdev)
{ {
struct subchannel *sch = to_subchannel(cdev->dev.parent);
CIO_TRACE_EVENT(4, "vrfy"); CIO_TRACE_EVENT(4, "vrfy");
CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
/* Initialize PGID data. */
memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
cdev->private->pgid_valid_mask = 0;
cdev->private->pgid_todo_mask = sch->schib.pmcw.pam;
/* /*
* Initialize pathgroup and multipath state with target values. * Initialize pathgroup and multipath state with target values.
* They may change in the course of path verification. * They may change in the course of path verification.
@ -474,6 +560,7 @@ void ccw_device_verify_start(struct ccw_device *cdev)
cdev->private->flags.pgroup = cdev->private->options.pgroup; cdev->private->flags.pgroup = cdev->private->options.pgroup;
cdev->private->flags.mpath = cdev->private->options.mpath; cdev->private->flags.mpath = cdev->private->options.mpath;
cdev->private->flags.doverify = 0; cdev->private->flags.doverify = 0;
cdev->private->path_noirq_mask = 0;
verify_start(cdev); verify_start(cdev);
} }

Просмотреть файл

@ -126,6 +126,10 @@ struct ccw_device_private {
u8 pgid_valid_mask; /* mask of valid PGIDs */ u8 pgid_valid_mask; /* mask of valid PGIDs */
u8 pgid_todo_mask; /* mask of PGIDs to be adjusted */ u8 pgid_todo_mask; /* mask of PGIDs to be adjusted */
u8 pgid_reset_mask; /* mask of PGIDs which were reset */ u8 pgid_reset_mask; /* mask of PGIDs which were reset */
u8 path_noirq_mask; /* mask of paths for which no irq was
received */
u8 path_notoper_mask; /* mask of paths which were found
not operable */
u8 path_gone_mask; /* mask of paths, that became unavailable */ u8 path_gone_mask; /* mask of paths, that became unavailable */
u8 path_new_mask; /* mask of paths, that became available */ u8 path_new_mask; /* mask of paths, that became available */
struct { struct {
@ -145,6 +149,7 @@ struct ccw_device_private {
unsigned int resuming:1; /* recognition while resume */ unsigned int resuming:1; /* recognition while resume */
unsigned int pgroup:1; /* pathgroup is set up */ unsigned int pgroup:1; /* pathgroup is set up */
unsigned int mpath:1; /* multipathing is set up */ unsigned int mpath:1; /* multipathing is set up */
unsigned int pgid_unknown:1;/* unknown pgid state */
unsigned int initialized:1; /* set if initial reference held */ unsigned int initialized:1; /* set if initial reference held */
} __attribute__((packed)) flags; } __attribute__((packed)) flags;
unsigned long intparm; /* user interruption parameter */ unsigned long intparm; /* user interruption parameter */

Просмотреть файл

@ -338,10 +338,10 @@ again:
retries++; retries++;
if (!start_time) { if (!start_time) {
start_time = get_clock(); start_time = get_tod_clock();
goto again; goto again;
} }
if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE) if ((get_tod_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE)
goto again; goto again;
} }
if (retries) { if (retries) {
@ -504,7 +504,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
int count, stop; int count, stop;
unsigned char state = 0; unsigned char state = 0;
q->timestamp = get_clock(); q->timestamp = get_tod_clock();
/* /*
* Don't check 128 buffers, as otherwise qdio_inbound_q_moved * Don't check 128 buffers, as otherwise qdio_inbound_q_moved
@ -563,7 +563,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q)
if (bufnr != q->last_move) { if (bufnr != q->last_move) {
q->last_move = bufnr; q->last_move = bufnr;
if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR)
q->u.in.timestamp = get_clock(); q->u.in.timestamp = get_tod_clock();
return 1; return 1;
} else } else
return 0; return 0;
@ -595,7 +595,7 @@ static inline int qdio_inbound_q_done(struct qdio_q *q)
* At this point we know, that inbound first_to_check * At this point we know, that inbound first_to_check
* has (probably) not moved (see qdio_inbound_processing). * has (probably) not moved (see qdio_inbound_processing).
*/ */
if (get_clock() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { if (get_tod_clock() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) {
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x", DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x",
q->first_to_check); q->first_to_check);
return 1; return 1;
@ -772,7 +772,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
int count, stop; int count, stop;
unsigned char state = 0; unsigned char state = 0;
q->timestamp = get_clock(); q->timestamp = get_tod_clock();
if (need_siga_sync(q)) if (need_siga_sync(q))
if (((queue_type(q) != QDIO_IQDIO_QFMT) && if (((queue_type(q) != QDIO_IQDIO_QFMT) &&

Просмотреть файл

@ -818,7 +818,7 @@ static inline struct qeth_card *CARD_FROM_CDEV(struct ccw_device *cdev)
static inline int qeth_get_micros(void) static inline int qeth_get_micros(void)
{ {
return (int) (get_clock() >> 12); return (int) (get_tod_clock() >> 12);
} }
static inline int qeth_get_ip_version(struct sk_buff *skb) static inline int qeth_get_ip_version(struct sk_buff *skb)

Просмотреть файл

@ -727,7 +727,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
zfcp_reqlist_add(adapter->req_list, req); zfcp_reqlist_add(adapter->req_list, req);
req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free); req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free);
req->issued = get_clock(); req->issued = get_tod_clock();
if (zfcp_qdio_send(qdio, &req->qdio_req)) { if (zfcp_qdio_send(qdio, &req->qdio_req)) {
del_timer(&req->timer); del_timer(&req->timer);
/* lookup request again, list might have changed */ /* lookup request again, list might have changed */

Просмотреть файл

@ -68,7 +68,7 @@ static inline void zfcp_qdio_account(struct zfcp_qdio *qdio)
unsigned long long now, span; unsigned long long now, span;
int used; int used;
now = get_clock_monotonic(); now = get_tod_clock_monotonic();
span = (now - qdio->req_q_time) >> 12; span = (now - qdio->req_q_time) >> 12;
used = QDIO_MAX_BUFFERS_PER_Q - atomic_read(&qdio->req_q_free); used = QDIO_MAX_BUFFERS_PER_Q - atomic_read(&qdio->req_q_free);
qdio->req_q_util += used * span; qdio->req_q_util += used * span;

Просмотреть файл

@ -2199,6 +2199,7 @@ done:
mutex_unlock(&tty->termios_mutex); mutex_unlock(&tty->termios_mutex);
return 0; return 0;
} }
EXPORT_SYMBOL(tty_do_resize);
/** /**
* tiocswinsz - implement window size set ioctl * tiocswinsz - implement window size set ioctl

Просмотреть файл

@ -1,6 +1,5 @@
menuconfig UIO menuconfig UIO
tristate "Userspace I/O drivers" tristate "Userspace I/O drivers"
depends on !S390
help help
Enable this to allow the userspace driver core code to be Enable this to allow the userspace driver core code to be
built. This code allows userspace programs easy access to built. This code allows userspace programs easy access to

Просмотреть файл

@ -53,8 +53,18 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
#endif #endif
#define readb __raw_readb #define readb __raw_readb
#define readw(addr) __le16_to_cpu(__raw_readw(addr))
#define readl(addr) __le32_to_cpu(__raw_readl(addr)) #define readw readw
static inline u16 readw(const volatile void __iomem *addr)
{
return __le16_to_cpu(__raw_readw(addr));
}
#define readl readl
static inline u32 readl(const volatile void __iomem *addr)
{
return __le32_to_cpu(__raw_readl(addr));
}
#ifndef __raw_writeb #ifndef __raw_writeb
static inline void __raw_writeb(u8 b, volatile void __iomem *addr) static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
@ -89,7 +99,11 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
} }
#endif #endif
#define readq(addr) __le64_to_cpu(__raw_readq(addr)) #define readq readq
static inline u64 readq(const volatile void __iomem *addr)
{
return __le64_to_cpu(__raw_readq(addr));
}
#ifndef __raw_writeq #ifndef __raw_writeq
static inline void __raw_writeq(u64 b, volatile void __iomem *addr) static inline void __raw_writeq(u64 b, volatile void __iomem *addr)

Просмотреть файл

@ -197,16 +197,6 @@ static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#endif #endif
#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
#define page_test_and_clear_dirty(pfn, mapped) (0)
#endif
#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
#define pte_maybe_dirty(pte) pte_dirty(pte)
#else
#define pte_maybe_dirty(pte) (1)
#endif
#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
#define page_test_and_clear_young(pfn) (0) #define page_test_and_clear_young(pfn) (0)
#endif #endif

Просмотреть файл

@ -303,21 +303,13 @@ static inline void __SetPageUptodate(struct page *page)
static inline void SetPageUptodate(struct page *page) static inline void SetPageUptodate(struct page *page)
{ {
#ifdef CONFIG_S390
if (!test_and_set_bit(PG_uptodate, &page->flags))
page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, 0);
#else
/* /*
* Memory barrier must be issued before setting the PG_uptodate bit, * Memory barrier must be issued before setting the PG_uptodate bit,
* so that all previous stores issued in order to bring the page * so that all previous stores issued in order to bring the page
* uptodate are actually visible before PageUptodate becomes true. * uptodate are actually visible before PageUptodate becomes true.
*
* s390 doesn't need an explicit smp_wmb here because the test and
* set bit already provides full barriers.
*/ */
smp_wmb(); smp_wmb();
set_bit(PG_uptodate, &(page)->flags); set_bit(PG_uptodate, &(page)->flags);
#endif
} }
CLEARPAGEFLAG(Uptodate, uptodate) CLEARPAGEFLAG(Uptodate, uptodate)

Просмотреть файл

@ -1126,7 +1126,6 @@ void page_add_file_rmap(struct page *page)
*/ */
void page_remove_rmap(struct page *page) void page_remove_rmap(struct page *page)
{ {
struct address_space *mapping = page_mapping(page);
bool anon = PageAnon(page); bool anon = PageAnon(page);
bool locked; bool locked;
unsigned long flags; unsigned long flags;
@ -1143,29 +1142,6 @@ void page_remove_rmap(struct page *page)
if (!atomic_add_negative(-1, &page->_mapcount)) if (!atomic_add_negative(-1, &page->_mapcount))
goto out; goto out;
/*
* Now that the last pte has gone, s390 must transfer dirty
* flag from storage key to struct page. We can usually skip
* this if the page is anon, so about to be freed; but perhaps
* not if it's in swapcache - there might be another pte slot
* containing the swap entry, but page not yet written to swap.
*
* And we can skip it on file pages, so long as the filesystem
* participates in dirty tracking (note that this is not only an
* optimization but also solves problems caused by dirty flag in
* storage key getting set by a write from inside kernel); but need to
* catch shm and tmpfs and ramfs pages which have been modified since
* creation by read fault.
*
* Note that mapping must be decided above, before decrementing
* mapcount (which luckily provides a barrier): once page is unmapped,
* it could be truncated and page->mapping reset to NULL at any moment.
* Note also that we are relying on page_mapping(page) to set mapping
* to &swapper_space when PageSwapCache(page).
*/
if (mapping && !mapping_cap_account_dirty(mapping) &&
page_test_and_clear_dirty(page_to_pfn(page), 1))
set_page_dirty(page);
/* /*
* Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED
* and not charged by memcg for now. * and not charged by memcg for now.

Просмотреть файл

@ -831,8 +831,11 @@ static int iucv_reboot_event(struct notifier_block *this,
{ {
int i; int i;
if (cpumask_empty(&iucv_irq_cpumask))
return NOTIFY_DONE;
get_online_cpus(); get_online_cpus();
on_each_cpu(iucv_block_cpu, NULL, 1); on_each_cpu_mask(&iucv_irq_cpumask, iucv_block_cpu, NULL, 1);
preempt_disable(); preempt_disable();
for (i = 0; i < iucv_max_pathid; i++) { for (i = 0; i < iucv_max_pathid; i++) {
if (iucv_path_table[i]) if (iucv_path_table[i])