s390 patches for 2.6.22
Subsystems (14)
cover s390 patches for 2.6.22
This is the s390 patchset for the merge window of 2.6.22. Most of it is cleanup and bug-fixes, but there are some new features as well:
- Channel path configure function.
- Improved oops output with an in-kernel disassembler
- Make use of generic bug.
- zfcpdump support.
- Processor degradation notification.
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 1/38 memory detection: stop at first memory hole.
From: Heiko Carstens <[email protected]>
If both sclp and diag memory detection don't work stop at the first memory hole. Otherwise the code might loop forever...
---
arch/s390/kernel/early.c | 7 +++---- 1 files changed, 3 insertions(+), 4 deletions(-)
arch/s390/kernel/early.c +3 -4
@@ -253,11 +253,10 @@break ;#endif /* -* Finish memory detection at the first hole, unless -* - we reached the hsa -> skip it. -* - we know there must be more. +* Finish memory detection at the first hole +* if storage size is unknown. */ -if (cc ==-1UL && !memsize && old_addr !=ADDR2G ) +if (cc ==-1UL && !memsize)break ;if (memsize && addr >= memsize)break ;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 2/38 cio/ipl: Clean interface between cio and ipl code.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
Clean interface between cio and ipl code, so Peter stops complaining.
---
arch/s390/kernel/ipl.c | 23 ++++++++++++++++++++++- drivers/s390/cio/cio.c | 38 ++++++++++---------------------------- include/asm-s390/cio.h | 7 +++++++ include/asm-s390/ipl.h | 3 +-- 4 files changed, 40 insertions(+), 31 deletions(-)
arch/s390/kernel/ipl.c +22 -1
@@ -47,7 +47,7 @@* Must be in data section since the bss section * is not cleared when these are accessed. */ -u16 ipl_devno __attribute__((__section__(".data"))) = 0; +static u16 ipl_devno __attribute__((__section__(".data"))) = 0; u32 ipl_flags __attribute__((__section__(".data"))) = 0;static char *ipl_type_str (enum ipl_type type)
@@ -1038,6 +1038,27 @@__initcall (s390_ipl_init); +void __init ipl_save_parameters (void ) +{ +struct cio_iplinfo iplinfo; +unsigned int *ipl_ptr; +void *src, *dst; + +if (cio_get_iplinfo (&iplinfo)) +return ; + + ipl_devno = iplinfo.devno; + ipl_flags |=IPL_DEVNO_VALID ; +if (!iplinfo.is_qdio) +return ; + ipl_flags |=IPL_PARMBLOCK_VALID ; + ipl_ptr = (unsigned int *)__LC_IPL_PARMBLOCK_PTR; + src = (void *)(unsigned long )*ipl_ptr; + dst = (void *)IPL_PARMBLOCK_ORIGIN ; +memmove (dst, src,PAGE_SIZE ); + *ipl_ptr =IPL_PARMBLOCK_ORIGIN ; +} +static LIST_HEAD (rcall);static DEFINE_MUTEX (rcall_mutex);
drivers/s390/cio/cio.c +10 -28
@@ -1048,37 +1048,19 @@do_reipl_asm (*((__u32 *)&schid)); } -static struct schib __initdata ipl_schib; - -/* -* ipl_save_parameters gets called very early. It is not allowed to access -* anything in the bss section at all. The bss section is not cleared yet, -* but may contain some ipl parameters written by the firmware. -* These parameters (if present) are copied to 0x2000. -* To avoid corruption of the ipl parameters, all variables used by this -* function must reside on the stack or in the data section. -*/ -void ipl_save_parameters (void ) +int __init cio_get_iplinfo (struct cio_iplinfo *iplinfo) {struct subchannel_id schid; -unsigned int *ipl_ptr; -void *src, *dst; +struct schib schib; schid = *(struct subchannel_id *)__LC_SUBCHANNEL_ID;if (!schid.one) -return ; -if (stsch (schid, &ipl_schib)) -return ; -if (!ipl_schib.pmcw.dnv) -return ; - ipl_devno = ipl_schib.pmcw.dev; - ipl_flags |=IPL_DEVNO_VALID ; -if (!ipl_schib.pmcw.qf) -return ; - ipl_flags |=IPL_PARMBLOCK_VALID ; - ipl_ptr = (unsigned int *)__LC_IPL_PARMBLOCK_PTR; - src = (void *)(unsigned long )*ipl_ptr; - dst = (void *)IPL_PARMBLOCK_ORIGIN ; -memmove (dst, src,PAGE_SIZE ); - *ipl_ptr =IPL_PARMBLOCK_ORIGIN ; +return -ENODEV ; +if (stsch (schid, &schib)) +return -ENODEV ; +if (!schib.pmcw.dnv) +return -ENODEV ; + iplinfo->devno = schib.pmcw.dev; + iplinfo->is_qdio = schib.pmcw.qf; +return 0 ; }
include/asm-s390/cio.h +7 -0
@@ -292,6 +292,13 @@extern void reipl_ccw_dev (struct ccw_dev_id *id); +struct cio_iplinfo { +u16 devno; +int is_qdio; +}; + +extern int cio_get_iplinfo (struct cio_iplinfo *iplinfo); +#endif #endif
include/asm-s390/ipl.h +1 -2
@@ -74,10 +74,9 @@ } __attribute__((packed));/* -* IPL validity flags and parameters as detected in head.S +* IPL validity flags */ extern u32 ipl_flags; -extern u16 ipl_devno;extern u32 dump_prefix_page;extern void do_reipl (void );
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 3/38 cio: Introduce struct chp_id.
In reply to Martin SchwidefskyFrom: Peter Oberparleiter <[email protected]>
Introduce data type for channel-path IDs.
---
drivers/s390/cio/chpid.h | 51 ++++++++++++ drivers/s390/cio/chsc.c | 178 +++++++++++++++++++++++------------------- drivers/s390/cio/chsc.h | 8 + drivers/s390/cio/cio.c | 5 - drivers/s390/cio/device_fsm.c | 6 + drivers/s390/cio/ioasm.h | 5 - 6 files changed, 167 insertions(+), 86 deletions(-)
drivers/s390/cio/chpid.h new file +51 -0
@@ -0,0 +1,51 @@ +/* +* drivers/s390/cio/chpid.h +* +* Copyright IBM Corp. 2007 +* Author(s): Peter Oberparleiter <[email protected]> +*/ + +#ifndef S390_CHP_ID_H +#define S390_CHP_ID_H S390_CHP_ID_H + +#include <linux/string.h> +#include <asm/types.h> +#include "css.h" + +struct chp_id { +u8 reserved1; +u8 cssid; +u8 reserved2; +u8 id; +} __attribute__((packed)); + +static inline void chp_id_init (struct chp_id *chpid) +{ +memset (chpid,0 ,sizeof (struct chp_id )); +} + +static inline int chp_id_is_equal (struct chp_id *a,struct chp_id *b) +{ +return (a->id == b->id) && (a->cssid == b->cssid); +} + +static inline void chp_id_next (struct chp_id *chpid) +{ +if (chpid->id < __MAX_CHPID) + chpid->id++; +else { + chpid->id =0 ; + chpid->cssid++; + } +} + +static inline int chp_id_is_valid (struct chp_id *chpid) +{ +return (chpid->cssid <= __MAX_CSSID); +} + + +#define chp_id_for_each (c) \ + for (chp_id_init(c); chp_id_is_valid(c); chp_id_next(c)) + +#endif /* S390_CHP_ID_H */
drivers/s390/cio/chsc.c +98 -80
442 lines not on this page · raw message
drivers/s390/cio/chsc.h +6 -2
@@ -1,6 +1,10 @@#ifndef S390_CHSC_H #define S390_CHSC_H +#include <linux/types.h> +#include <linux/device.h> +#include "chpid.h" +#define CHSC_SEI_ACC_CHPID 1#define CHSC_SEI_ACC_LINKADDR 2#define CHSC_SEI_ACC_FULLLINKADDR 3
@@ -34,7 +38,7 @@ } __attribute__ ((packed));struct channel_path { -int id; +struct chp_id chpid;int state;struct channel_path_desc desc;/* Channel-measurement related stuff: */
@@ -46,7 +50,7 @@extern void s390_process_css (void );extern void chsc_validate_chpids (struct subchannel *); -extern void chpid_is_actually_online (int ); +extern void chpid_is_actually_online (struct chp_id );extern int css_get_ssd_info (struct subchannel *);extern int chsc_process_crw (void );extern int chp_process_crw (int ,int );
drivers/s390/cio/cio.c +4 -1
@@ -954,6 +954,7 @@ {int i, ret;unsigned long long timeout; +struct chp_id chpid;/* Reset subchannels. */ for_each_subchannel (__shutdown_subchannel_easy,NULL );
@@ -963,8 +964,10 @@__ctl_set_bit (14 ,28 );/* Temporarily reenable machine checks. */ local_mcck_enable (); +chp_id_init (&chpid);for (i =0 ; i <= __MAX_CHPID; i++) { - ret =rchp (i); + chpid.id = i; + ret =rchp (chpid);if ((ret ==0 ) || (ret ==2 ))/* * rchp either succeeded, or another rchp is already
drivers/s390/cio/device_fsm.c +5 -1
@@ -22,6 +22,7 @@#include "device.h" #include "chsc.h" #include "ioasm.h" +#include "chpid.h" int device_is_online (struct subchannel *sch)
@@ -210,14 +211,17 @@ __recover_lost_chpids(struct subchannel *sch, int old_lpm) { int mask, i; +struct chp_id chpid; +chp_id_init (&chpid);for (i =0 ; i<8 ; i++) { mask =0x80 >> i;if (!(sch->lpm & mask))continue ;if (old_lpm & mask)continue ; -chpid_is_actually_online (sch->schib.pmcw.chpid[i]); + chpid.id = sch->schib.pmcw.chpid[i]; +chpid_is_actually_online (chpid); } }
drivers/s390/cio/ioasm.h +3 -2
@@ -2,6 +2,7 @@#define S390_CIO_IOASM_H #include "schid.h" +#include "chpid.h" /* * TPI info structure
@@ -189,9 +190,9 @@return cc; } -static inline int rchp (int chpid) +static inline int rchp (struct chp_id chpid) { - register unsigned int reg1 asm ("1") = chpid; + register struct chp_id reg1 asm ("1") = chpid;int ccode; asm volatile(
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 4/38 cio: Allow 0 and 1 as input for channel path status attribute.
In reply to Martin SchwidefskyFrom: Peter Oberparleiter <[email protected]>
Channel path status can now be modified by writing '0' and '1' to the sysfs status attribute in addition to 'offline' and 'online' respectively.
---
drivers/s390/cio/chsc.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/s390/cio/chsc.c +2 -2
@@ -1169,9 +1169,9 @@if (!num_args)return count; -if (!strnicmp (cmd,"on" ,2 )) +if (!strnicmp (cmd,"on" ,2 ) || !strcmp (cmd,"1" )) error =s390_vary_chpid (cp->chpid,1 ); -else if (!strnicmp (cmd,"off" ,3 )) +else if (!strnicmp (cmd,"off" ,3 ) || !strcmp (cmd,"0" )) error =s390_vary_chpid (cp->chpid,0 );else error = -EINVAL ;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 5/38 cio: Introduce separate files for channel-path related code.
In reply to Martin SchwidefskyFrom: Peter Oberparleiter <[email protected]>
---
drivers/s390/cio/Makefile | 2 drivers/s390/cio/chp.c | 433 ++++++++++++++++++++++++++++++++++++++ drivers/s390/cio/chp.h | 37 +++ drivers/s390/cio/chsc.c | 473 +++--------------------------------------- drivers/s390/cio/chsc.h | 30 -- drivers/s390/cio/cio.c | 8 drivers/s390/cio/css.h | 1 drivers/s390/cio/device_fsm.c | 6 drivers/s390/cio/device_ops.c | 7 drivers/s390/s390mach.c | 1 10 files changed, 535 insertions(+), 463 deletions(-)
drivers/s390/cio/chp.c new file +433 -0
@@ -0,0 +1,433 @@ +/* +* drivers/s390/cio/chp.c +* +* Copyright IBM Corp. 1999,2007 +* Author(s): Cornelia Huck ([email protected]) +* Arnd Bergmann ([email protected]) +* Peter Oberparleiter <[email protected]> +*/ + +#include <linux/bug.h> +#include <linux/workqueue.h> +#include <linux/spinlock.h> +#include <asm/errno.h> + +#include "chpid.h" +#include "cio.h" +#include "css.h" +#include "ioasm.h" +#include "cio_debug.h" +#include "chp.h" + +#define to_channelpath (device) container_of(device, struct channel_path, dev) + +/* Return channel_path struct for given chpid. */ +static inline struct channel_path *chpid_to_chp (struct chp_id chpid) +{ +return css[chpid.cssid]->chps[chpid.id]; +} + +/* Set vary state for given chpid. */ +static void set_chp_logically_online (struct chp_id chpid,int onoff) +{ +chpid_to_chp (chpid)->state = onoff; +} + +/* On succes return 0 if channel-path is varied offline, 1 if it is varied +* online. Return -ENODEV if channel-path is not registered. */ +int chp_get_status (struct chp_id chpid) +{ +return (chpid_to_chp (chpid) ?chpid_to_chp (chpid)->state : -ENODEV ); +} + +/** +* chp_get_sch_opm - return opm for subchannel +* @sch: subchannel +* +* Calculate and return the operational path mask (opm) based on the chpids +* used by the subchannel and the status of the associated channel-paths. +*/ +u8 chp_get_sch_opm (struct subchannel *sch) +{ +struct chp_id chpid; +int opm; +int i; + + opm =0 ; +chp_id_init (&chpid); +for (i=0 ; i <8 ; i++) { + opm <<=1 ; + chpid.id = sch->schib.pmcw.chpid[i]; +if (chp_get_status (chpid) !=0 ) + opm |=1 ; + } +return opm; +} + +/** +* chp_is_registered - check if a channel-path is registered +* @chpid: channel-path ID +* +* Return non-zero if a channel-path with the given chpid is registered, +* zero otherwise. +*/ +int chp_is_registered (struct chp_id chpid) +{ +return chpid_to_chp (chpid) !=NULL ; +} + +/* +* Function: s390_vary_chpid +* Varies the specified chpid online or offline +*/ +static int s390_vary_chpid (struct chp_id chpid,int on) +{ +char dbf_text[15 ]; +int status; + +sprintf (dbf_text, on?"varyon%x.%02x" :"varyoff%x.%02x" , chpid.cssid, + chpid.id); +CIO_TRACE_EVENT (2 , dbf_text); + + status =chp_get_status (chpid); +if (status <0 ) { +printk (KERN_ERR "Can't vary unknown chpid %x.%02x\n" , + chpid.cssid, chpid.id); +return -EINVAL ; + } + +if (!on && !status) { +printk (KERN_ERR "chpid %x.%02x is already offline\n" , + chpid.cssid, chpid.id); +return -EINVAL ; + } + +set_chp_logically_online (chpid, on); +chsc_chp_vary (chpid, on); +return 0 ; +} + +/* +* Channel measurement related functions +*/ +static ssize_t chp_measurement_chars_read (struct kobject *kobj,char *buf, +loff_t off,size_t count) +{ +struct channel_path *chp; +unsigned int size; + + chp = to_channelpath(container_of(kobj, struct device, kobj)); +if (!chp->cmg_chars) +return 0 ; + + size =sizeof (struct cmg_chars ); + +if (off > size) +return 0 ; +if (off + count > size) + count = size - off; +memcpy (buf, chp->cmg_chars + off, count); +return count; +} + +static struct bin_attribute chp_measurement_chars_attr = { + .attr = { + .name ="measurement_chars" , + .mode =S_IRUSR , + .owner =THIS_MODULE , + }, + .size =sizeof (struct cmg_chars ), + .read = chp_measurement_chars_read, +}; + +static void chp_measurement_copy_block (struct cmg_entry *buf, +struct channel_subsystem *css, +struct chp_id chpid) +{ +void *area; +struct cmg_entry *entry, reference_buf; +int idx; + +if (chpid.id <128 ) { + area = css->cub_addr1; + idx = chpid.id; + }else { + area = css->cub_addr2; + idx = chpid.id -128 ; + } + entry = area + (idx *sizeof (struct cmg_entry )); +do { +memcpy (buf, entry,sizeof (*entry)); +memcpy (&reference_buf, entry,sizeof (*entry)); + }while (reference_buf.values[0 ] != buf->values[0 ]); +} + +static ssize_t chp_measurement_read (struct kobject *kobj,char *buf, +loff_t off,size_t count) +{ +struct channel_path *chp; +struct channel_subsystem *css; +unsigned int size; + + chp = to_channelpath(container_of(kobj, struct device, kobj)); + css =to_css (chp->dev.parent); + + size =sizeof (struct cmg_entry ); + +/* Only allow single reads. */ +if (off || count < size) +return 0 ; +chp_measurement_copy_block ((struct cmg_entry *)buf, css, chp->chpid); + count = size; +return count; +} + +static struct bin_attribute chp_measurement_attr = { + .attr = { + .name ="measurement" , + .mode =S_IRUSR , + .owner =THIS_MODULE , + }, + .size =sizeof (struct cmg_entry ), + .read = chp_measurement_read, +}; + +void chp_remove_cmg_attr (struct channel_path *chp) +{ +device_remove_bin_file (&chp->dev, &chp_measurement_chars_attr); +device_remove_bin_file (&chp->dev, &chp_measurement_attr); +} + +int chp_add_cmg_attr (struct channel_path *chp) +{ +int ret; + + ret =device_create_bin_file (&chp->dev, &chp_measurement_chars_attr); +if (ret) +return ret; + ret =device_create_bin_file (&chp->dev, &chp_measurement_attr); +if (ret) +device_remove_bin_file (&chp->dev, &chp_measurement_chars_attr); +return ret; +} + +/* +* Files for the channel path entries. +*/ +static ssize_t chp_status_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ + struct channel_path *chp = container_of(dev, struct channel_path, dev); + +if (!chp) +return 0 ; +return (chp_get_status (chp->chpid) ?sprintf (buf,"online\n" ) : +sprintf (buf,"offline\n" )); +} + +static ssize_t chp_status_write (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ + struct channel_path *cp = container_of(dev, struct channel_path, dev); +char cmd[10 ]; +int num_args; +int error; + + num_args =sscanf (buf,"%5s" , cmd); +if (!num_args) +return count; + +if (!strnicmp (cmd,"on" ,2 ) || !strcmp (cmd,"1" )) + error =s390_vary_chpid (cp->chpid,1 ); +else if (!strnicmp (cmd,"off" ,3 ) || !strcmp (cmd,"0" )) + error =s390_vary_chpid (cp->chpid,0 ); +else + error = -EINVAL ; + +return error <0 ? error : count; + +} + +static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write); + +static ssize_t chp_type_show (struct device *dev,struct device_attribute *attr, +char *buf) +{ + struct channel_path *chp = container_of(dev, struct channel_path, dev); + +if (!chp) +return 0 ; +return sprintf (buf,"%x\n" , chp->desc.desc); +} + +static DEVICE_ATTR(type, 0444, chp_type_show, NULL); + +static ssize_t chp_cmg_show (struct device *dev,struct device_attribute *attr, +char *buf) +{ +struct channel_path *chp =to_channelpath (dev); + +if (!chp) +return 0 ; +if (chp->cmg ==-1 )/* channel measurements not available */ +return sprintf (buf,"unknown\n" ); +return sprintf (buf,"%x\n" , chp->cmg); +} + +static DEVICE_ATTR(cmg, 0444, chp_cmg_show, NULL); + +static ssize_t chp_shared_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +struct channel_path *chp =to_channelpath (dev); + +if (!chp) +return 0 ; +if (chp->shared ==-1 )/* channel measurements not available */ +return sprintf (buf,"unknown\n" ); +return sprintf (buf,"%x\n" , chp->shared); +} + +static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL); + +static struct attribute * chp_attrs[] = { + &dev_attr_status.attr, + &dev_attr_type.attr, + &dev_attr_cmg.attr, + &dev_attr_shared.attr, +NULL , +}; + +static struct attribute_group chp_attr_group = { + .attrs = chp_attrs, +}; + +static void chp_release (struct device *dev) +{ +struct channel_path *cp; + + cp = container_of(dev, struct channel_path, dev); +kfree (cp); +} + +/** +* chp_new - register a new channel-path +* @chpid - channel-path ID +* +* Create and register data structure representing new channel-path. Return +* zero on success, non-zero otherwise. +*/ +int chp_new (struct chp_id chpid) +{ +struct channel_path *chp; +int ret; + + chp =kzalloc (sizeof (struct channel_path ),GFP_KERNEL ); +if (!chp) +return -ENOMEM ; + +/* fill in status, etc. */ + chp->chpid = chpid; + chp->state =1 ; + chp->dev.parent = &css[chpid.cssid]->device; + chp->dev.release = chp_release; +snprintf (chp->dev.bus_id,BUS_ID_SIZE ,"chp%x.%02x" , chpid.cssid, + chpid.id); + +/* Obtain channel path description and fill it in. */ + ret =chsc_determine_channel_path_description (chpid, &chp->desc); +if (ret) + goto out_free; +/* Get channel-measurement characteristics. */ +if (css_characteristics_avail && css_chsc_characteristics.scmc + && css_chsc_characteristics.secm) { + ret =chsc_get_channel_measurement_chars (chp); +if (ret) + goto out_free; + }else { +static int msg_done; + +if (!msg_done) { +printk (KERN_WARNING "cio: Channel measurements not " +"available, continuing.\n" ); + msg_done =1 ; + } + chp->cmg =-1 ; + } + +/* make it known to the system */ + ret =device_register (&chp->dev); +if (ret) { +printk (KERN_WARNING "%s: could not register %x.%02x\n" , + __func__, chpid.cssid, chpid.id); + goto out_free; + } + ret =sysfs_create_group (&chp->dev.kobj, &chp_attr_group); +if (ret) { +device_unregister (&chp->dev); + goto out_free; + } +mutex_lock (&css[chpid.cssid]->mutex); +if (css[chpid.cssid]->cm_enabled) { + ret =chp_add_cmg_attr (chp); +if (ret) { +sysfs_remove_group (&chp->dev.kobj, &chp_attr_group); +device_unregister (&chp->dev); +mutex_unlock (&css[chpid.cssid]->mutex); + goto out_free; + } + } + css[chpid.cssid]->chps[chpid.id] = chp; +mutex_unlock (&css[chpid.cssid]->mutex); +return ret; +out_free: +kfree (chp); +return ret; +} + +/** +* chp_get_chp_desc - return newly allocated channel-path description +* @chpid: channel-path ID +* +* On success return a newly allocated copy of the channel-path description +* data associated with the given channel-path ID. Return %NULL on error. +*/ +void *chp_get_chp_desc (struct chp_id chpid) +{ +struct channel_path *chp; +struct channel_path_desc *desc; + + chp =chpid_to_chp (chpid); +if (!chp) +return NULL ; + desc =kmalloc (sizeof (struct channel_path_desc ),GFP_KERNEL ); +if (!desc) +return NULL ; +memcpy (desc, &chp->desc,sizeof (struct channel_path_desc )); +return desc; +} + +/** +* chp_process_crw - process channel-path status change +* @id: channel-path ID number +* @status: non-zero if channel-path has become available, zero otherwise +* +* Handle channel-report-words indicating that the status of a channel-path +* has changed. +*/ +int chp_process_crw (int id,int status) +{ +struct chp_id chpid; + +chp_id_init (&chpid); + chpid.id = id; +if (status) { +if (!chp_is_registered (chpid)) +chp_new (chpid); +return chsc_chp_online (chpid); + }else { +chsc_chp_offline (chpid); +return 0 ; + } +}
drivers/s390/cio/chp.h new file +37 -0
@@ -0,0 +1,37 @@ +/* +* drivers/s390/cio/chp.h +* +* Copyright IBM Corp. 2007 +* Author(s): Peter Oberparleiter <[email protected]> +*/ + +#ifndef S390_CHP_H +#define S390_CHP_H S390_CHP_H + +#include <linux/types.h> +#include <linux/device.h> + +#include "chpid.h" +#include "chsc.h" + +struct channel_path { +struct chp_id chpid; +int state; +struct channel_path_desc desc; +/* Channel-measurement related stuff: */ +int cmg; +int shared; +void *cmg_chars; +struct device dev; +}; + +int chp_get_status (struct chp_id chpid); +u8 chp_get_sch_opm (struct subchannel *sch); +int chp_is_registered (struct chp_id chpid); +void *chp_get_chp_desc (struct chp_id chpid); +int chp_process_crw (int id,int available); +void chp_remove_cmg_attr (struct channel_path *chp); +int chp_add_cmg_attr (struct channel_path *chp); +int chp_new (struct chp_id chpid); + +#endif /* S390_CHP_H */
drivers/s390/cio/chsc.c +38 -435
662 lines not on this page · raw message
drivers/s390/cio/chsc.h +8 -22
@@ -5,10 +5,6 @@#include <linux/device.h> #include "chpid.h" -#define CHSC_SEI_ACC_CHPID 1 -#define CHSC_SEI_ACC_LINKADDR 2 -#define CHSC_SEI_ACC_FULLLINKADDR 3 -#define CHSC_SDA_OC_MSS 0x2struct chsc_header {
@@ -37,23 +33,10 @@u8 chpp; } __attribute__ ((packed)); -struct channel_path { -struct chp_id chpid; -int state; -struct channel_path_desc desc; -/* Channel-measurement related stuff: */ -int cmg; -int shared; -void *cmg_chars; -struct device dev; -}; - -extern void s390_process_css (void ); -extern void chsc_validate_chpids (struct subchannel *); -extern void chpid_is_actually_online (struct chp_id ); +struct channel_path ; +extern int css_get_ssd_info (struct subchannel *);extern int chsc_process_crw (void ); -extern int chp_process_crw (int ,int );struct css_general_char { u64 : 41;
@@ -89,12 +72,15 @@extern int chsc_determine_css_characteristics (void );extern int css_characteristics_avail; -extern void *chsc_get_chp_desc (struct subchannel *,int ); -extern int chsc_enable_facility (int );struct channel_subsystem ;extern int chsc_secm (struct channel_subsystem *,int ); -#define to_channelpath (device) container_of(device, struct channel_path, dev) +int chsc_chp_vary (struct chp_id chpid,int on); +int chsc_determine_channel_path_description (struct chp_id chpid, +struct channel_path_desc *desc); +int chsc_chp_online (struct chp_id chpid); +void chsc_chp_offline (struct chp_id chpid); +int chsc_get_channel_measurement_chars (struct channel_path *chp);#endif
drivers/s390/cio/cio.c +5 -3
@@ -29,6 +29,7 @@#include "ioasm.h" #include "blacklist.h" #include "cio_debug.h" +#include "chp.h" #include "../s390mach.h" debug_info_t *cio_debug_msg_id;
@@ -592,9 +593,10 @@ err = -ENODEV ; goto out; } - sch->opm =0xff ; -if (!cio_is_console (sch->schid)) -chsc_validate_chpids (sch); +if (cio_is_console (sch->schid)) + sch->opm =0xff ; +else + sch->opm =chp_get_sch_opm (sch); sch->lpm = sch->schib.pmcw.pam & sch->opm; CIO_DEBUG(KERN_INFO, 0,
drivers/s390/cio/css.h +1 -0
@@ -4,6 +4,7 @@#include <linux/mutex.h> #include <linux/wait.h> #include <linux/workqueue.h> +#include <linux/device.h> #include <asm/cio.h>
drivers/s390/cio/device_fsm.c +5 -1
@@ -23,6 +23,7 @@#include "chsc.h" #include "ioasm.h" #include "chpid.h" +#include "chp.h" int device_is_online (struct subchannel *sch)
@@ -221,7 +222,10 @@if (old_lpm & mask)continue ; chpid.id = sch->schib.pmcw.chpid[i]; -chpid_is_actually_online (chpid); +if (!chp_is_registered (chpid)) { + need_rescan =1 ; +queue_work (slow_path_wq, &slow_path_work); + } } }
drivers/s390/cio/device_ops.c +6 -1
@@ -22,6 +22,8 @@#include "css.h" #include "chsc.h" #include "device.h" +#include "chpid.h" +#include "chp.h" int ccw_device_set_options_mask (struct ccw_device *cdev,unsigned long flags) {
@@ -606,9 +608,12 @@ ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) {struct subchannel *sch; +struct chp_id chpid; sch =to_subchannel (cdev->dev.parent); -return chsc_get_chp_desc (sch, chp_no); +chp_id_init (&chpid); + chpid.id = sch->schib.pmcw.chpid[chp_no]; +return chp_get_chp_desc (chpid); }// FIXME: these have to go:
drivers/s390/cio/Makefile +1 -1
@@ -2,7 +2,7 @@ # Makefile for the S/390 common i/o drivers # -obj-y += airq.o blacklist.o chsc.o cio.o css.o +obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o ccw_device-objs += device.o device_fsm.o device_ops.o ccw_device-objs += device_id.o device_pgid.o device_status.o obj-y += ccw_device.o cmf.o
drivers/s390/s390mach.c +1 -0
@@ -21,6 +21,7 @@#include "cio/cio.h" #include "cio/chsc.h" #include "cio/css.h" +#include "cio/chp.h" #include "s390mach.h" static struct semaphore m_sem;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 6/38 cio: observe chpid valid flag
In reply to Martin SchwidefskyFrom: Peter Oberparleiter <[email protected]>
Check validity flag of CHPID description data before continuing with channel-path initialization.
---
drivers/s390/cio/chp.c | 4 ++++ 1 files changed, 4 insertions(+)
drivers/s390/cio/chp.c +4 -0
@@ -339,6 +339,10 @@ ret =chsc_determine_channel_path_description (chpid, &chp->desc);if (ret) goto out_free; +if ((chp->desc.flags &0x80 ) ==0 ) { + ret = -ENODEV ; + goto out_free; + }/* Get channel-measurement characteristics. */ if (css_characteristics_avail && css_chsc_characteristics.scmc && css_chsc_characteristics.secm) {
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 7/38 cio: Clean up online_store.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
Detangle the online_store code and make it more readable.
---
drivers/s390/cio/device.c | 109 ++++++++++++++++++++++++++-------------------- 1 files changed, 62 insertions(+), 47 deletions(-)
drivers/s390/cio/device.c +62 -47
@@ -413,11 +413,60 @@return (ret ==0 ) ? -ENODEV : ret; } -static ssize_t -online_store (struct device *dev,struct device_attribute *attr,const char *buf,size_t count) +static void online_store_handle_offline (struct ccw_device *cdev) +{ +if (cdev->private->state ==DEV_STATE_DISCONNECTED ) +ccw_device_remove_disconnected (cdev); +else if (cdev->drv && cdev->drv->set_offline) +ccw_device_set_offline (cdev); +} + +static int online_store_recog_and_online (struct ccw_device *cdev) +{ +int ret; + +/* Do device recognition, if needed. */ +if (cdev->id.cu_type ==0 ) { + ret =ccw_device_recognition (cdev); +if (ret) { +printk (KERN_WARNING "Couldn't start recognition " +"for device %s (ret=%d)\n" , + cdev->dev.bus_id, ret); +return ret; + } +wait_event (cdev->private->wait_q, + cdev->private->flags.recog_done); + } +if (cdev->drv && cdev->drv->set_online) +ccw_device_set_online (cdev); +return 0 ; +} +static void online_store_handle_online (struct ccw_device *cdev,int force) +{ +int ret; + + ret =online_store_recog_and_online (cdev); +if (ret) +return ; +if (force && cdev->private->state ==DEV_STATE_BOXED ) { + ret =ccw_device_stlck (cdev); +if (ret) { +printk (KERN_WARNING "ccw_device_stlck for device %s " +"returned %d!\n" , cdev->dev.bus_id, ret); +return ; + } +if (cdev->id.cu_type ==0 ) + cdev->private->state =DEV_STATE_NOT_OPER ; +online_store_recog_and_online (cdev); + } + +} + +static ssize_t online_store (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) {struct ccw_device *cdev =to_ccwdev (dev); -int i, force, ret; +int i, force;char *tmp;if (atomic_cmpxchg (&cdev->private->onoff,0 ,1 ) !=0 )
@@ -434,51 +483,17 @@ force =0 ; i =simple_strtoul (buf, &tmp,16 ); } -if (i ==1 ) { -/* Do device recognition, if needed. */ -if (cdev->id.cu_type ==0 ) { - ret =ccw_device_recognition (cdev); -if (ret) { -printk (KERN_WARNING "Couldn't start recognition " -"for device %s (ret=%d)\n" , - cdev->dev.bus_id, ret); - goto out; - } -wait_event (cdev->private->wait_q, - cdev->private->flags.recog_done); - } -if (cdev->drv && cdev->drv->set_online) -ccw_device_set_online (cdev); - }else if (i ==0 ) { -if (cdev->private->state ==DEV_STATE_DISCONNECTED ) -ccw_device_remove_disconnected (cdev); -else if (cdev->drv && cdev->drv->set_offline) -ccw_device_set_offline (cdev); - } -if (force && cdev->private->state ==DEV_STATE_BOXED ) { - ret =ccw_device_stlck (cdev); -if (ret) { -printk (KERN_WARNING "ccw_device_stlck for device %s " -"returned %d!\n" , cdev->dev.bus_id, ret); - goto out; - } -/* Do device recognition, if needed. */ -if (cdev->id.cu_type ==0 ) { - cdev->private->state =DEV_STATE_NOT_OPER ; - ret =ccw_device_recognition (cdev); -if (ret) { -printk (KERN_WARNING "Couldn't start recognition " -"for device %s (ret=%d)\n" , - cdev->dev.bus_id, ret); - goto out; - } -wait_event (cdev->private->wait_q, - cdev->private->flags.recog_done); - } -if (cdev->drv && cdev->drv->set_online) -ccw_device_set_online (cdev); + +switch (i) { +case 0 : +online_store_handle_offline (cdev); +break ; +case 1 : +online_store_handle_online (cdev, force); +break ; +default : + count = -EINVAL ; } - out:if (cdev->drv)module_put (cdev->drv->owner);atomic_set (&cdev->private->onoff,0 );
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 8/38 cio: Channel-path configure function.
In reply to Martin SchwidefskyFrom: Peter Oberparleiter <[email protected]>
Add a new attribute to the channel-path sysfs directory through which channel-path configure operations can be triggered. Also listen for hardware events requesting channel-path configure operations and process them accordingly.
---
drivers/s390/char/Makefile | 2 drivers/s390/char/sclp_chp.c | 196 ++++++++++++++++++++++++++++++++ drivers/s390/cio/chp.c | 250 +++++++++++++++++++++++++++++++++++++++++- drivers/s390/cio/chp.h | 20 +++ drivers/s390/cio/chpid.h | 51 -------- drivers/s390/cio/chsc.c | 44 +++++++ drivers/s390/cio/chsc.h | 2 drivers/s390/cio/cio.c | 1 drivers/s390/cio/cio.h | 1 drivers/s390/cio/css.h | 4 drivers/s390/cio/device_fsm.c | 2 drivers/s390/cio/device_ops.c | 2 drivers/s390/cio/ioasm.h | 2 include/asm-s390/chpid.h | 53 ++++++++ include/asm-s390/cio.h | 1 include/asm-s390/sclp.h | 12 ++ 16 files changed, 581 insertions(+), 62 deletions(-)
drivers/s390/char/Makefile +1 -1
@@ -3,7 +3,7 @@ # obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ - sclp_info.o + sclp_info.o sclp_chp.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
drivers/s390/char/sclp_chp.c new file +196 -0
196 lines not on this page · raw message
drivers/s390/cio/chp.c +249 -1
285 lines not on this page · raw message
drivers/s390/cio/chp.h +18 -2
@@ -10,10 +10,23 @@#include <linux/types.h> #include <linux/device.h> - -#include "chpid.h" +#include <asm/chpid.h> #include "chsc.h" +#define CHP_STATUS_STANDBY 0 +#define CHP_STATUS_CONFIGURED 1 +#define CHP_STATUS_RESERVED 2 +#define CHP_STATUS_NOT_RECOGNIZED 3 + +static inline int chp_test_bit (u8 *bitmap,int num) +{ +int byte = num >>3 ; +int mask =128 >> (num &7 ); + +return (bitmap[byte] & mask) ?1 :0 ; +} + +struct channel_path {struct chp_id chpid;int state;
@@ -33,5 +46,8 @@void chp_remove_cmg_attr (struct channel_path *chp);int chp_add_cmg_attr (struct channel_path *chp);int chp_new (struct chp_id chpid); +void chp_cfg_schedule (struct chp_id chpid,int configure); +void chp_cfg_cancel_deconfigure (struct chp_id chpid); +int chp_info_get_status (struct chp_id chpid);#endif /* S390_CHP_H */
drivers/s390/cio/chpid.h deleted +0 -51
51 lines not on this page · raw message
drivers/s390/cio/chsc.c +43 -1
67 lines not on this page · raw message
drivers/s390/cio/chsc.h +1 -1
@@ -3,7 +3,7 @@#include <linux/types.h> #include <linux/device.h> -#include "chpid.h" +#include <asm/chpid.h> #define CHSC_SDA_OC_MSS 0x2
drivers/s390/cio/cio.c +1 -0
@@ -22,6 +22,7 @@#include <asm/setup.h> #include <asm/reset.h> #include <asm/ipl.h> +#include <asm/chpid.h> #include "airq.h" #include "cio.h" #include "css.h"
drivers/s390/cio/cio.h +1 -0
@@ -3,6 +3,7 @@#include "schid.h" #include <linux/mutex.h> +#include <linux/device.h> /* * where we put the ssd info
drivers/s390/cio/css.h +2 -2
@@ -5,8 +5,10 @@#include <linux/wait.h> #include <linux/workqueue.h> #include <linux/device.h> +#include <linux/types.h> #include <asm/cio.h> +#include <asm/chpid.h> #include "schid.h"
@@ -149,8 +151,6 @@#define __MAX_SUBCHANNEL 65535#define __MAX_SSID 3 -#define __MAX_CHPID 255 -#define __MAX_CSSID 0struct channel_subsystem {u8 cssid;
drivers/s390/cio/device_fsm.c +1 -1
@@ -15,6 +15,7 @@#include <asm/ccwdev.h> #include <asm/cio.h> +#include <asm/chpid.h> #include "cio.h" #include "cio_debug.h"
@@ -22,7 +23,6 @@#include "device.h" #include "chsc.h" #include "ioasm.h" -#include "chpid.h" #include "chp.h" int
drivers/s390/cio/device_ops.c +1 -1
@@ -16,13 +16,13 @@#include <asm/ccwdev.h> #include <asm/idals.h> +#include <asm/chpid.h> #include "cio.h" #include "cio_debug.h" #include "css.h" #include "chsc.h" #include "device.h" -#include "chpid.h" #include "chp.h" int ccw_device_set_options_mask (struct ccw_device *cdev,unsigned long flags)
drivers/s390/cio/ioasm.h +1 -1
@@ -1,8 +1,8 @@#ifndef S390_CIO_IOASM_H #define S390_CIO_IOASM_H +#include <asm/chpid.h> #include "schid.h" -#include "chpid.h" /* * TPI info structure
include/asm-s390/chpid.h new file +53 -0
53 lines not on this page · raw message
include/asm-s390/cio.h +1 -0
@@ -13,6 +13,7 @@#ifdef __KERNEL__#define LPM_ANYPATH 0xff +#define __MAX_CSSID 0/* * subchannel status word
include/asm-s390/sclp.h +12 -0
@@ -9,6 +9,7 @@#define _ASM_S390_SCLP_H#include <linux/types.h> +#include <asm/chpid.h> struct sccb_header {u16 length;
@@ -33,7 +34,18 @@u8 _reserved3[4096 -112 ];/* 112-4095 */ } __attribute__((packed, aligned(4096))); +#define SCLP_CHP_INFO_MASK_SIZE 32 + +struct sclp_chp_info { +u8 recognized[SCLP_CHP_INFO_MASK_SIZE ]; +u8 standby[SCLP_CHP_INFO_MASK_SIZE ]; +u8 configured[SCLP_CHP_INFO_MASK_SIZE ]; +}; +extern struct sclp_readinfo_sccb s390_readinfo_sccb;extern void sclp_readinfo_early (void ); +extern int sclp_chp_configure (struct chp_id chpid); +extern int sclp_chp_deconfigure (struct chp_id chpid); +extern int sclp_chp_read_info (struct sclp_chp_info *info);#endif /* _ASM_S390_SCLP_H */
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 9/38 cio: Use add_uevent_var.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
Convert ccw_uevent to use add_uevent_var and adapt snprint_alias.
---
drivers/s390/cio/device.c | 66 ++++++++++++++++++---------------------------- 1 files changed, 26 insertions(+), 40 deletions(-)
drivers/s390/cio/device.c +26 -40
@@ -56,13 +56,12 @@/* Store modalias string delimited by prefix/suffix string into buffer with * specified size. Return length of resulting string (excluding trailing '\0') * even if string doesn't fit buffer (snprintf semantics). */ -static int snprint_alias (char *buf,size_t size,const char *prefix, +static int snprint_alias (char *buf,size_t size,struct ccw_device_id *id,const char *suffix) {int len; - len =snprintf (buf, size,"%sccw:t%04Xm%02X" , prefix, id->cu_type, - id->cu_model); + len =snprintf (buf, size,"ccw:t%04Xm%02X" , id->cu_type, id->cu_model);if (len > size)return len; buf += len;
@@ -85,53 +84,40 @@struct ccw_device *cdev =to_ccwdev (dev);struct ccw_device_id *id = &(cdev->id);int i =0 ; -int len; +int len =0 ; +int ret; +char modalias_buf[30 ];/* CU_TYPE= */ - len =snprintf (buffer, buffer_size,"CU_TYPE=%04X" , id->cu_type) +1 ; -if (len > buffer_size || i >= num_envp) -return -ENOMEM ; - envp[i++] = buffer; - buffer += len; - buffer_size -= len; + ret =add_uevent_var (envp, num_envp, &i, buffer, buffer_size, &len, +"CU_TYPE=%04X" , id->cu_type); +if (ret) +return ret;/* CU_MODEL= */ - len =snprintf (buffer, buffer_size,"CU_MODEL=%02X" , id->cu_model) +1 ; -if (len > buffer_size || i >= num_envp) -return -ENOMEM ; - envp[i++] = buffer; - buffer += len; - buffer_size -= len; + ret =add_uevent_var (envp, num_envp, &i, buffer, buffer_size, &len, +"CU_MODEL=%02X" , id->cu_model); +if (ret) +return ret;/* The next two can be zero, that's ok for us */ /* DEV_TYPE= */ - len =snprintf (buffer, buffer_size,"DEV_TYPE=%04X" , id->dev_type) +1 ; -if (len > buffer_size || i >= num_envp) -return -ENOMEM ; - envp[i++] = buffer; - buffer += len; - buffer_size -= len; + ret =add_uevent_var (envp, num_envp, &i, buffer, buffer_size, &len, +"DEV_TYPE=%04X" , id->dev_type); +if (ret) +return ret;/* DEV_MODEL= */ - len =snprintf (buffer, buffer_size,"DEV_MODEL=%02X" , - (unsigned char ) id->dev_model) +1 ; -if (len > buffer_size || i >= num_envp) -return -ENOMEM ; - envp[i++] = buffer; - buffer += len; - buffer_size -= len; + ret =add_uevent_var (envp, num_envp, &i, buffer, buffer_size, &len, +"DEV_MODEL=%02X" , id->dev_model); +if (ret) +return ret;/* MODALIAS= */ - len =snprint_alias (buffer, buffer_size,"MODALIAS=" , id,"" ) +1 ; -if (len > buffer_size || i >= num_envp) -return -ENOMEM ; - envp[i++] = buffer; - buffer += len; - buffer_size -= len; - - envp[i] =NULL ; - -return 0 ; +snprint_alias (modalias_buf,sizeof (modalias_buf), id,"" ); + ret =add_uevent_var (envp, num_envp, &i, buffer, buffer_size, &len, +"MODALIAS=%s" , modalias_buf); +return ret; }struct bus_type ccw_bus_type;
@@ -280,7 +266,7 @@struct ccw_device_id *id = &(cdev->id);int len; - len =snprint_alias (buf,PAGE_SIZE ,"" , id,"\n" ) +1 ; + len =snprint_alias (buf,PAGE_SIZE , id,"\n" ) +1 ;return len >PAGE_SIZE ?PAGE_SIZE : len; }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 10/38 cio: Re-start path verification after aborting internal I/O.
In reply to Martin SchwidefskyFrom: Stefan Bader <[email protected]>
Path verification triggered by changes to the available CHPIDs will be interrupted by another change but not re-started. This results in an invalid path mask.
To solve this make sure to completely re-start path verification when changing the available paths.
---
drivers/s390/cio/chsc.c | 108 ++++++++++++++++++++++++------------------------ 1 files changed, 54 insertions(+), 54 deletions(-)
drivers/s390/cio/chsc.c +54 -54
@@ -178,6 +178,38 @@return ret; } +static int check_for_io_on_path (struct subchannel *sch,int mask) +{ +int cc; + + cc =stsch (sch->schid, &sch->schib); +if (cc) +return 0 ; +if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == mask) +return 1 ; +return 0 ; +} + +static void terminate_internal_io (struct subchannel *sch) +{ +if (cio_clear (sch)) { +/* Recheck device in case clear failed. */ + sch->lpm =0 ; +if (device_trigger_verify (sch) !=0 ) { +if (css_enqueue_subchannel_slow (sch->schid)) { +css_clear_subchannel_slow_list (); + need_rescan =1 ; + } + } +return ; + } +/* Request retry of internal operation. */ +device_set_intretry (sch); +/* Call handler. */ +if (sch->driver && sch->driver->termination) + sch->driver->termination (&sch->dev); +} +static int s390_subchannel_remove_chpid (struct device *dev,void *data) {
@@ -208,37 +240,33 @@if (sch->schib.pmcw.pim ==0x80 ) goto out_unreg; -if ((sch->schib.scsw.actl &SCSW_ACTL_DEVACT ) && - (sch->schib.scsw.actl &SCSW_ACTL_SCHACT ) && - (sch->schib.pmcw.lpum == mask)) { -int cc; - - cc =cio_clear (sch); -if (cc == -ENODEV ) +if (check_for_io_on_path (sch, mask)) { +if (device_is_online (sch)) +device_kill_io (sch); +else { +terminate_internal_io (sch); +/* Re-start path verification. */ +if (sch->driver && sch->driver->verify) + sch->driver->verify (&sch->dev); + } + }else { +/* trigger path verification. */ +if (sch->driver && sch->driver->verify) + sch->driver->verify (&sch->dev); +else if (sch->lpm == mask) goto out_unreg; -/* Request retry of internal operation. */ -device_set_intretry (sch); -/* Call handler. */ -if (sch->driver && sch->driver->termination) - sch->driver->termination (&sch->dev); - goto out_unlock; } -/* trigger path verification. */ -if (sch->driver && sch->driver->verify) - sch->driver->verify (&sch->dev); -else if (sch->lpm == mask) - goto out_unreg; -out_unlock:spin_unlock_irq (sch->lock);return 0 ; + out_unreg: -spin_unlock_irq (sch->lock); sch->lpm =0 ;if (css_enqueue_subchannel_slow (sch->schid)) {css_clear_subchannel_slow_list (); need_rescan =1 ; } +spin_unlock_irq (sch->lock);return 0 ; }
@@ -683,38 +711,6 @@return rc; } -static int check_for_io_on_path (struct subchannel *sch,int index) -{ -int cc; - - cc =stsch (sch->schid, &sch->schib); -if (cc) -return 0 ; -if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) -return 1 ; -return 0 ; -} - -static void terminate_internal_io (struct subchannel *sch) -{ -if (cio_clear (sch)) { -/* Recheck device in case clear failed. */ - sch->lpm =0 ; -if (device_trigger_verify (sch) !=0 ) { -if (css_enqueue_subchannel_slow (sch->schid)) { -css_clear_subchannel_slow_list (); - need_rescan =1 ; - } - } -return ; - } -/* Request retry of internal operation. */ -device_set_intretry (sch); -/* Call handler. */ -if (sch->driver && sch->driver->termination) - sch->driver->termination (&sch->dev); -} -static void __s390_subchannel_vary_chpid (struct subchannel *sch,struct chp_id chpid,int on) {
@@ -741,13 +737,17 @@ } sch->opm &= ~(0x80 >> chp); sch->lpm &= ~(0x80 >> chp); -if (check_for_io_on_path (sch, chp)) { +if (check_for_io_on_path (sch, (0x80 >> chp))) {if (device_is_online (sch))/* Path verification is done after killing. */ device_kill_io (sch); -else +else {/* Kill and retry internal I/O. */ terminate_internal_io (sch); +/* Re-start path verification. */ +if (sch->driver && sch->driver->verify) + sch->driver->verify (&sch->dev); + } }else if (!sch->lpm) {if (device_trigger_verify (sch) !=0 ) {if (css_enqueue_subchannel_slow (sch->schid)) {
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 11/38 cio: replace subchannel evaluation queue with bitmap
In reply to Martin SchwidefskyFrom: Peter Oberparleiter <[email protected]>
Use a bitmap for indicating which subchannels require evaluation instead of allocating memory for each evaluation request. This approach reduces memory consumption during recovery in case of massive evaluation request occurrence and removes the need for memory allocation failure handling.
---
drivers/s390/cio/Makefile | 2 drivers/s390/cio/chp.c | 8 -- drivers/s390/cio/chp.h | 2 drivers/s390/cio/chsc.c | 130 +++++++++--------------------------- drivers/s390/cio/chsc.h | 4 - drivers/s390/cio/css.c | 148 +++++++++++++----------------------------- drivers/s390/cio/css.h | 10 -- drivers/s390/cio/device_fsm.c | 6 - drivers/s390/cio/idset.c | 112 +++++++++++++++++++++++++++++++ drivers/s390/cio/idset.h | 25 +++++++ drivers/s390/s390mach.c | 24 +----- 11 files changed, 235 insertions(+), 236 deletions(-)
drivers/s390/cio/chp.c +3 -5
@@ -491,7 +491,7 @@* Handle channel-report-words indicating that the status of a channel-path * has changed. */ -int chp_process_crw (int id,int status) +void chp_process_crw (int id,int status) {struct chp_id chpid;
@@ -500,11 +500,9 @@if (status) {if (!chp_is_registered (chpid))chp_new (chpid); -return chsc_chp_online (chpid); - }else { +chsc_chp_online (chpid); + }else chsc_chp_offline (chpid); -return 0 ; - } }static inline int info_bit_num (struct chp_id id)
drivers/s390/cio/chp.h +1 -1
@@ -42,7 +42,7 @@u8 chp_get_sch_opm (struct subchannel *sch);int chp_is_registered (struct chp_id chpid);void *chp_get_chp_desc (struct chp_id chpid); -int chp_process_crw (int id,int available); +void chp_process_crw (int id,int available);void chp_remove_cmg_attr (struct channel_path *chp);int chp_add_cmg_attr (struct channel_path *chp);int chp_new (struct chp_id chpid);
drivers/s390/cio/chsc.c +33 -97
316 lines not on this page · raw message
drivers/s390/cio/chsc.h +2 -2
@@ -36,7 +36,7 @@struct channel_path ;extern int css_get_ssd_info (struct subchannel *); -extern int chsc_process_crw (void ); +extern void chsc_process_crw (void );struct css_general_char { u64 : 41;
@@ -79,7 +79,7 @@int chsc_chp_vary (struct chp_id chpid,int on);int chsc_determine_channel_path_description (struct chp_id chpid,struct channel_path_desc *desc); -int chsc_chp_online (struct chp_id chpid); +void chsc_chp_online (struct chp_id chpid);void chsc_chp_offline (struct chp_id chpid);int chsc_get_channel_measurement_chars (struct channel_path *chp);
drivers/s390/cio/css.c +47 -101
209 lines not on this page · raw message
drivers/s390/cio/css.h +3 -7
@@ -146,7 +146,7 @@extern struct subchannel *get_subchannel_by_schid (struct subchannel_id );extern int css_init_done;extern int for_each_subchannel (int (*fn)(struct subchannel_id ,void *),void *); -extern int css_process_crw (int ,int ); +extern void css_process_crw (int ,int );extern void css_reiterate_subchannels (void );#define __MAX_SUBCHANNEL 65535
@@ -186,16 +186,12 @@void device_kill_pending_timer (struct subchannel *);/* Helper functions to build lists for the slow path. */ -extern int css_enqueue_subchannel_slow (struct subchannel_id schid); -void css_walk_subchannel_slow_list (void (*fn)(unsigned long )); -void css_clear_subchannel_slow_list (void ); -int css_slow_subchannels_exist (void ); -extern int need_rescan; +void css_schedule_eval (struct subchannel_id schid); +void css_schedule_eval_all (void );int sch_is_pseudo_sch (struct subchannel *);extern struct workqueue_struct *slow_path_wq; -extern struct work_struct slow_path_work;int subchannel_add_files (struct device *);extern struct attribute_group *subch_attr_groups[];
drivers/s390/cio/device_fsm.c +2 -4
@@ -222,10 +222,8 @@if (old_lpm & mask)continue ; chpid.id = sch->schib.pmcw.chpid[i]; -if (!chp_is_registered (chpid)) { - need_rescan =1 ; -queue_work (slow_path_wq, &slow_path_work); - } +if (!chp_is_registered (chpid)) +css_schedule_eval_all (); } }
drivers/s390/cio/idset.c new file +112 -0
112 lines not on this page · raw message
drivers/s390/cio/idset.h new file +25 -0
@@ -0,0 +1,25 @@ +/* +* drivers/s390/cio/idset.h +* +* Copyright IBM Corp. 2007 +* Author(s): Peter Oberparleiter <[email protected]> +*/ + +#ifndef S390_IDSET_H +#define S390_IDSET_H S390_IDSET_H + +#include "schid.h" + +struct idset ; + +void idset_free (struct idset *set); +void idset_clear (struct idset *set); +void idset_fill (struct idset *set); + +struct idset *idset_sch_new (void ); +void idset_sch_add (struct idset *set,struct subchannel_id id); +void idset_sch_del (struct idset *set,struct subchannel_id id); +int idset_sch_contains (struct idset *set,struct subchannel_id id); +int idset_sch_get_first (struct idset *set,struct subchannel_id *id); + +#endif /* S390_IDSET_H */
drivers/s390/cio/Makefile +1 -1
@@ -2,7 +2,7 @@ # Makefile for the S/390 common i/o drivers # -obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o +obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o ccw_device-objs += device.o device_fsm.o device_ops.o ccw_device-objs += device_id.o device_pgid.o device_status.o obj-y += ccw_device.o cmf.o
drivers/s390/s390mach.c +6 -18
@@ -45,14 +45,13 @@ s390_collect_crw_info(void *param) {struct crw crw[2 ]; -int ccode, ret, slow; +int ccode;struct semaphore *sem;unsigned int chain; sem = (struct semaphore *)param; repeat:down_interruptible (sem); - slow =0 ; chain =0 ;while (1 ) {if (unlikely (chain >1 )) {
@@ -85,9 +84,8 @@/* Check for overflows. */ if (crw[chain].oflw) {pr_debug ("%s: crw overflow detected!\n" , __FUNCTION__); -css_reiterate_subchannels (); +css_schedule_eval_all (); chain =0 ; - slow =1 ;continue ; }switch (crw[chain].rsc) {
@@ -95,10 +93,7 @@if (crw[0 ].chn && !chain)break ;pr_debug ("source is subchannel %04X\n" , crw[0 ].rsid); - ret =css_process_crw (crw[0 ].rsid, - chain ? crw[1 ].rsid :0 ); -if (ret == -EAGAIN ) - slow =1 ; +css_process_crw (crw[0 ].rsid, chain ? crw[1 ].rsid :0 );break ;case CRW_RSC_MONITOR :pr_debug ("source is monitoring facility\n" );
@@ -117,28 +112,23 @@ }switch (crw[0 ].erc) {case CRW_ERC_IPARM :/* Path has come. */ - ret =chp_process_crw (crw[0 ].rsid,1 ); +chp_process_crw (crw[0 ].rsid,1 );break ;case CRW_ERC_PERRI :/* Path has gone. */ case CRW_ERC_PERRN : - ret =chp_process_crw (crw[0 ].rsid,0 ); +chp_process_crw (crw[0 ].rsid,0 );break ;default :pr_debug ("Don't know how to handle erc=%x\n" , crw[0 ].erc); - ret =0 ; } -if (ret == -EAGAIN ) - slow =1 ;break ;case CRW_RSC_CONFIG :pr_debug ("source is configuration-alert facility\n" );break ;case CRW_RSC_CSS :pr_debug ("source is channel subsystem\n" ); - ret =chsc_process_crw (); -if (ret == -EAGAIN ) - slow =1 ; +chsc_process_crw ();break ;default :pr_debug ("unknown source\n" );
@@ -147,8 +137,6 @@/* chain is always 0 or 1 here. */ chain = crw[chain].chn ? chain +1 :0 ; } -if (slow) -queue_work (slow_path_wq, &slow_path_work); goto repeat;return 0 ; }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 12/38 cio: fix subchannel channel-path data usage
In reply to Martin SchwidefskyFrom: Peter Oberparleiter <[email protected]>
Ensure that channel-path related subchannel data is only retrieved and used when it is valid and that it is updated when it may have changed.
---
drivers/s390/cio/chsc.c | 303 ++++++++++++++---------------------------- drivers/s390/cio/chsc.h | 10 + drivers/s390/cio/cio.h | 16 -- drivers/s390/cio/css.c | 53 ++++++- drivers/s390/cio/css.h | 1 drivers/s390/cio/device.c | 12 + drivers/s390/cio/device_fsm.c | 1 7 files changed, 179 insertions(+), 217 deletions(-)
drivers/s390/cio/chsc.c +107 -196
@@ -26,155 +26,84 @@static void *sei_page; -/* FIXME: this is _always_ called for every subchannel. shouldn't we -* process more than one at a time? */ -static int -chsc_get_sch_desc_irq (struct subchannel *sch,void *page) -{ -int ccode, j; - -struct { -struct chsc_header request; -u16 reserved1a:10 ; -u16 ssid:2 ; -u16 reserved1b:4 ; -u16 f_sch;/* first subchannel */ -u16 reserved2; -u16 l_sch;/* last subchannel */ -u32 reserved3; -struct chsc_header response; -u32 reserved4; -u8 sch_valid :1 ; -u8 dev_valid :1 ; -u8 st :3 ;/* subchannel type */ -u8 zeroes :3 ; -u8 unit_addr;/* unit address */ -u16 devno;/* device number */ -u8 path_mask; -u8 fla_valid_mask; -u16 sch;/* subchannel */ -u8 chpid[8 ];/* chpids 0-7 */ -u16 fla[8 ];/* full link addresses 0-7 */ - } __attribute__ ((packed)) *ssd_area; +struct chsc_ssd_area { +struct chsc_header request; + u16 :10; +u16 ssid:2 ; + u16 :4; +u16 f_sch;/* first subchannel */ + u16 :16; +u16 l_sch;/* last subchannel */ + u32 :32; +struct chsc_header response; + u32 :32; +u8 sch_valid :1 ; +u8 dev_valid :1 ; +u8 st :3 ;/* subchannel type */ +u8 zeroes :3 ; +u8 unit_addr;/* unit address */ +u16 devno;/* device number */ +u8 path_mask; +u8 fla_valid_mask; +u16 sch;/* subchannel */ +u8 chpid[8 ];/* chpids 0-7 */ +u16 fla[8 ];/* full link addresses 0-7 */ +} __attribute__ ((packed)); - ssd_area = page; +int chsc_get_ssd_info (struct subchannel_id schid,struct chsc_ssd_info *ssd) +{ +unsigned long page; +struct chsc_ssd_area *ssd_area; +int ccode; +int ret; +int i; +int mask; + page =get_zeroed_page (GFP_KERNEL |GFP_DMA ); +if (!page) +return -ENOMEM ; + ssd_area = (struct chsc_ssd_area *) page; ssd_area->request.length =0x0010 ; ssd_area->request.code =0x0004 ; - - ssd_area->ssid = sch->schid.ssid; - ssd_area->f_sch = sch->schid.sch_no; - ssd_area->l_sch = sch->schid.sch_no; + ssd_area->ssid = schid.ssid; + ssd_area->f_sch = schid.sch_no; + ssd_area->l_sch = schid.sch_no; ccode =chsc (ssd_area); +/* Check response. */ if (ccode >0 ) { -pr_debug ("chsc returned with ccode = %d\n" , ccode); -return (ccode ==3 ) ? -ENODEV : -EBUSY ; + ret = (ccode ==3 ) ? -ENODEV : -EBUSY ; + goto out_free; } - -switch (ssd_area->response.code) { -case 0x0001 :/* everything ok */ -break ; -case 0x0002 : -CIO_CRW_EVENT (2 ,"Invalid command!\n" ); -return -EINVAL ; -case 0x0003 : -CIO_CRW_EVENT (2 ,"Error in chsc request block!\n" ); -return -EINVAL ; -case 0x0004 : -CIO_CRW_EVENT (2 ,"Model does not provide ssd\n" ); -return -EOPNOTSUPP ; -default : -CIO_CRW_EVENT (2 ,"Unknown CHSC response %d\n" , +if (ssd_area->response.code !=0x0001 ) { +CIO_MSG_EVENT (2 ,"chsc: ssd failed for 0.%x.%04x (rc=%04x)\n" , + schid.ssid, schid.sch_no, ssd_area->response.code); -return -EIO ; + ret = -EIO ; + goto out_free; } - -/* -* ssd_area->st stores the type of the detected -* subchannel, with the following definitions: -* -* 0: I/O subchannel: All fields have meaning -* 1: CHSC subchannel: Only sch_val, st and sch -* have meaning -* 2: Message subchannel: All fields except unit_addr -* have meaning -* 3: ADM subchannel: Only sch_val, st and sch -* have meaning -* -* Other types are currently undefined. -*/ -if (ssd_area->st >3 ) {/* uhm, that looks strange... */ -CIO_CRW_EVENT (0 ,"Strange subchannel type %d" -" for sch 0.%x.%04x\n" , ssd_area->st, - sch->schid.ssid, sch->schid.sch_no); -/* -* There may have been a new subchannel type defined in the -* time since this code was written; since we don't know which -* fields have meaning and what to do with it we just jump out -*/ -return 0 ; - }else { -const char *type[4 ] = {"I/O" ,"chsc" ,"message" ,"ADM" }; -CIO_CRW_EVENT (6 ,"ssd: sch 0.%x.%04x is %s subchannel\n" , - sch->schid.ssid, sch->schid.sch_no, - type[ssd_area->st]); - - sch->ssd_info.valid =1 ; - sch->ssd_info.type = ssd_area->st; - } - -if (ssd_area->st ==0 || ssd_area->st ==2 ) { -for (j =0 ; j <8 ; j++) { -if (!((0x80 >> j) & ssd_area->path_mask & - ssd_area->fla_valid_mask)) -continue ; - sch->ssd_info.chpid[j] = ssd_area->chpid[j]; - sch->ssd_info.fla[j] = ssd_area->fla[j]; - } +if (!ssd_area->sch_valid) { + ret = -ENODEV ; + goto out_free; } -return 0 ; -} - -int -css_get_ssd_info (struct subchannel *sch) -{ -int ret; -void *page; - - page = (void *)get_zeroed_page (GFP_KERNEL |GFP_DMA ); -if (!page) -return -ENOMEM ; -spin_lock_irq (sch->lock); - ret =chsc_get_sch_desc_irq (sch, page); -if (ret) { -static int cio_chsc_err_msg; - -if (!cio_chsc_err_msg) { -printk (KERN_ERR -"chsc_get_sch_descriptions:" -" Error %d while doing chsc; " -"processing some machine checks may " -"not work\n" , ret); - cio_chsc_err_msg =1 ; - } - } -spin_unlock_irq (sch->lock); -free_page ((unsigned long )page); -if (!ret) { -int j, mask; -struct chp_id chpid; - -chp_id_init (&chpid); -/* Allocate channel path structures, if needed. */ -for (j =0 ; j <8 ; j++) { - mask =0x80 >> j; - chpid.id = sch->ssd_info.chpid[j]; -if ((sch->schib.pmcw.pim & mask) && - !chp_is_registered (chpid)) -chp_new (chpid); +/* Copy data */ + ret =0 ; +memset (ssd,0 ,sizeof (struct chsc_ssd_info )); +if ((ssd_area->st !=0 ) && (ssd_area->st !=2 )) + goto out_free; + ssd->path_mask = ssd_area->path_mask; + ssd->fla_valid_mask = ssd_area->fla_valid_mask; +for (i =0 ; i <8 ; i++) { + mask =0x80 >> i; +if (ssd_area->path_mask & mask) { +chp_id_init (&ssd->chpid[i]); + ssd->chpid[i].id = ssd_area->chpid[i]; } +if (ssd_area->fla_valid_mask & mask) + ssd->fla[i] = ssd_area->fla[i]; } +out_free: +free_page (page);return ret; }
@@ -276,47 +205,6 @@ s390_subchannel_remove_chpid); } -struct res_acc_data { -struct chp_id chpid; -u32 fla_mask; -u16 fla; -}; - -static int s390_process_res_acc_sch (struct res_acc_data *res_data, -struct subchannel *sch) -{ -int found; -int chp; -int ccode; - - found =0 ; -for (chp =0 ; chp <=7 ; chp++) -/* -* check if chpid is in information updated by ssd -*/ -if (sch->ssd_info.valid && - sch->ssd_info.chpid[chp] == res_data->chpid.id && - (sch->ssd_info.fla[chp] & res_data->fla_mask) - == res_data->fla) { - found =1 ; -break ; - } - -if (found ==0 ) -return 0 ; - -/* -* Do a stsch to update our subchannel structure with the -* new path information and eventually check for logically -* offline chpids. -*/ - ccode =stsch (sch->schid, &sch->schib); -if (ccode >0 ) -return 0 ; - -return 0x80 >> chp; -} -static int s390_process_res_acc_new_sch (struct subchannel_id schid) {
@@ -338,6 +226,32 @@return 0 ; } +struct res_acc_data { +struct chp_id chpid; +u32 fla_mask; +u16 fla; +}; + +static int get_res_chpid_mask (struct chsc_ssd_info *ssd, +struct res_acc_data *data) +{ +int i; +int mask; + +for (i =0 ; i <8 ; i++) { + mask =0x80 >> i; +if (!(ssd->path_mask & mask)) +continue ; +if (!chp_id_is_equal (&ssd->chpid[i], &data->chpid)) +continue ; +if ((ssd->fla_valid_mask & mask) && + ((ssd->fla[i] & data->fla_mask) != data->fla)) +continue ; +return mask; + } +return 0 ; +} +static int __s390_process_res_acc (struct subchannel_id schid,void *data) {
@@ -352,14 +266,11 @@return s390_process_res_acc_new_sch (schid);spin_lock_irq (sch->lock); - - chp_mask =s390_process_res_acc_sch (res_data, sch); - -if (chp_mask ==0 ) { -spin_unlock_irq (sch->lock); -put_device (&sch->dev); -return 0 ; - } + chp_mask =get_res_chpid_mask (&sch->ssd_info, res_data); +if (chp_mask ==0 ) + goto out; +if (stsch (sch->schid, &sch->schib)) + goto out; old_lpm = sch->lpm; sch->lpm = ((sch->schib.pmcw.pim & sch->schib.pmcw.pam &
@@ -369,13 +280,12 @@device_trigger_reprobe (sch); else if (sch->driver && sch->driver->verify) sch->driver->verify(&sch->dev); - +out:spin_unlock_irq (sch->lock);put_device (&sch->dev);return 0 ; } -static void s390_process_res_acc (struct res_acc_data *res_data) {char dbf_txt[15 ];
@@ -661,29 +571,30 @@ struct chp_id chpid, int on) { int chp, old_lpm; +int mask;unsigned long flags; -if (!sch->ssd_info.valid) -return ; -spin_lock_irqsave (sch->lock, flags); old_lpm = sch->lpm;for (chp =0 ; chp <8 ; chp++) { -if (sch->ssd_info.chpid[chp] != chpid.id) + mask =0x80 >> chp; +if (!(sch->ssd_info.path_mask & mask)) +continue ; +if (!chp_id_is_equal (&sch->ssd_info.chpid[chp], &chpid))continue ;if (on) { - sch->opm |= (0x80 >> chp); - sch->lpm |= (0x80 >> chp); + sch->opm |= mask; + sch->lpm |= mask;if (!old_lpm)device_trigger_reprobe (sch);else if (sch->driver && sch->driver->verify) sch->driver->verify (&sch->dev);break ; } - sch->opm &= ~(0x80 >> chp); - sch->lpm &= ~(0x80 >> chp); -if (check_for_io_on_path (sch, (0x80 >> chp))) { + sch->opm &= ~mask; + sch->lpm &= ~mask; +if (check_for_io_on_path (sch, mask)) {if (device_is_online (sch))/* Path verification is done after killing. */ device_kill_io (sch);
drivers/s390/cio/chsc.h +9 -1
@@ -4,6 +4,7 @@#include <linux/types.h> #include <linux/device.h> #include <asm/chpid.h> +#include "schid.h" #define CHSC_SDA_OC_MSS 0x2
@@ -35,7 +36,6 @@struct channel_path ; -extern int css_get_ssd_info (struct subchannel *);extern void chsc_process_crw (void );struct css_general_char {
@@ -69,6 +69,14 @@extern struct css_general_char css_general_characteristics;extern struct css_chsc_char css_chsc_characteristics; +struct chsc_ssd_info { +u8 path_mask; +u8 fla_valid_mask; +struct chp_id chpid[8 ]; +u16 fla[8 ]; +}; +extern int chsc_get_ssd_info (struct subchannel_id schid, +struct chsc_ssd_info *ssd);extern int chsc_determine_css_characteristics (void );extern int css_characteristics_avail;
drivers/s390/cio/cio.h +4 -12
@@ -1,19 +1,11 @@#ifndef S390_CIO_H #define S390_CIO_H -#include "schid.h" #include <linux/mutex.h> #include <linux/device.h> - -/* -* where we put the ssd info -*/ -struct ssd_info { -__u8 valid:1 ; -__u8 type:7 ;/* subchannel type */ -__u8 chpid[8 ];/* chpids */ -__u16 fla[8 ];/* full link addresses */ -} __attribute__ ((packed)); +#include <asm/chpid.h> +#include "chsc.h" +#include "schid.h" /* * path management control word
@@ -109,7 +101,7 @@struct schib schib;/* subchannel information block */ struct orb orb;/* operation request block */ struct ccw1 sense_ccw;/* static ccw for sense command */ -struct ssd_info ssd_info;/* subchannel description */ +struct chsc_ssd_info ssd_info;/* subchannel description */ struct device dev;/* entry in device tree */ struct css_driver *driver; } __attribute__ ((aligned(8)));
drivers/s390/cio/css.c +48 -5
71 lines not on this page · raw message
drivers/s390/cio/css.h +1 -0
@@ -148,6 +148,7 @@extern int for_each_subchannel (int (*fn)(struct subchannel_id ,void *),void *);extern void css_process_crw (int ,int );extern void css_reiterate_subchannels (void ); +void css_update_ssd_info (struct subchannel *sch);#define __MAX_SUBCHANNEL 65535#define __MAX_SSID 3
drivers/s390/cio/device.c +9 -3
@@ -216,12 +216,18 @@ chpids_show (struct device * dev, struct device_attribute *attr, char * buf) { struct subchannel *sch = to_subchannel(dev); -struct ssd_info *ssd = &sch->ssd_info; +struct chsc_ssd_info *ssd = &sch->ssd_info;ssize_t ret =0 ;int chp; +int mask; -for (chp =0 ; chp <8 ; chp++) - ret +=sprintf (buf+ret,"%02x " , ssd->chpid[chp]); +for (chp =0 ; chp <8 ; chp++) { + mask =0x80 >> chp; +if (ssd->path_mask & mask) + ret +=sprintf (buf + ret,"%02x " , ssd->chpid[chp].id); +else + ret +=sprintf (buf + ret,"00 " ); + } ret +=sprintf (buf+ret,"\n" );return min ((ssize_t )PAGE_SIZE , ret); }
drivers/s390/cio/device_fsm.c +1 -0
@@ -246,6 +246,7 @@*/ old_lpm = sch->lpm;stsch (sch->schid, &sch->schib); +css_update_ssd_info (sch); sch->lpm = sch->schib.pmcw.pam & sch->opm;/* Check since device may again have become not operational. */ if (!sch->schib.pmcw.dnv)
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 13/38 cio: Dont call css_update_ssd_info from interrupt context.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
---
drivers/s390/cio/device.c | 3 ++- drivers/s390/cio/device_fsm.c | 1 - 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/s390/cio/device.c +2 -1
@@ -743,6 +743,7 @@static void sch_attach_device (struct subchannel *sch,struct ccw_device *cdev) { +css_update_ssd_info (sch);spin_lock_irq (sch->lock); sch->dev.driver_data = cdev; cdev->private->schid = sch->schid;
@@ -878,7 +879,7 @@ priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; sch =to_subchannel (cdev->dev.parent); - +css_update_ssd_info (sch);/* * io_subchannel_register() will also be called after device * recognition has been done for a boxed device (which will already
drivers/s390/cio/device_fsm.c +0 -1
@@ -246,7 +246,6 @@*/ old_lpm = sch->lpm;stsch (sch->schid, &sch->schib); -css_update_ssd_info (sch); sch->lpm = sch->schib.pmcw.pam & sch->opm;/* Check since device may again have become not operational. */ if (!sch->schib.pmcw.dnv)
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 14/38 cio: ccwgroup register vs. unregister.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
Introduce a mutex for struct ccwgroup to prevent simuntaneous register/unregister on the same ccwgroup device.
---
drivers/s390/cio/ccwgroup.c | 33 ++++++++++++++++++--------------- include/asm-s390/ccwgroup.h | 1 + 2 files changed, 19 insertions(+), 15 deletions(-)
drivers/s390/cio/ccwgroup.c +18 -15
@@ -75,8 +75,10 @@ {struct ccwgroup_device *gdev =to_ccwgroupdev (dev); +mutex_lock (&gdev->reg_mutex);__ccwgroup_remove_symlinks (gdev);device_unregister (dev); +mutex_unlock (&gdev->reg_mutex); } static ssize_t
@@ -173,7 +175,8 @@return -ENOMEM ;atomic_set (&gdev->onoff,0 ); - +mutex_init (&gdev->reg_mutex); +mutex_lock (&gdev->reg_mutex);for (i =0 ; i < argc; i++) { gdev->cdev[i] =get_ccwdev_by_busid (cdrv, argv[i]);
@@ -183,12 +186,12 @@ || gdev->cdev[i]->id.driver_info != gdev->cdev[0]->id.driver_info) { rc = -EINVAL ; - goto free_dev; + goto error; }/* Don't allow a device to belong to more than one group. */ if (gdev->cdev[i]->dev.driver_data) { rc = -EINVAL ; - goto free_dev; + goto error; } gdev->cdev[i]->dev.driver_data = gdev; }
@@ -203,9 +206,8 @@ gdev->cdev[0]->dev.bus_id); rc =device_register (&gdev->dev); -if (rc) - goto free_dev; + goto error;get_device (&gdev->dev); rc =device_create_file (&gdev->dev, &dev_attr_ungroup);
@@ -216,6 +218,7 @@ rc =__ccwgroup_create_symlinks (gdev);if (!rc) { +mutex_unlock (&gdev->reg_mutex);put_device (&gdev->dev);return 0 ; }
@@ -224,19 +227,12 @@ error:for (i =0 ; i < argc; i++)if (gdev->cdev[i]) { -put_device (&gdev->cdev[i]->dev); - gdev->cdev[i]->dev.driver_data =NULL ; - } -put_device (&gdev->dev); -return rc; -free_dev: -for (i =0 ; i < argc; i++) -if (gdev->cdev[i]) {if (gdev->cdev[i]->dev.driver_data == gdev) gdev->cdev[i]->dev.driver_data =NULL ;put_device (&gdev->cdev[i]->dev); } -kfree (gdev); +mutex_unlock (&gdev->reg_mutex); +put_device (&gdev->dev);return rc; }
@@ -422,8 +418,12 @@get_driver (&cdriver->driver);while ((dev =driver_find_device (&cdriver->driver,NULL ,NULL , __ccwgroup_match_all))) { -__ccwgroup_remove_symlinks (to_ccwgroupdev (dev)); +struct ccwgroup_device *gdev =to_ccwgroupdev (dev); + +mutex_lock (&gdev->reg_mutex); +__ccwgroup_remove_symlinks (gdev);device_unregister (dev); +mutex_unlock (&gdev->reg_mutex);put_device (dev); }put_driver (&cdriver->driver);
@@ -444,8 +444,10 @@if (cdev->dev.driver_data) { gdev = (struct ccwgroup_device *)cdev->dev.driver_data;if (get_device (&gdev->dev)) { +mutex_lock (&gdev->reg_mutex);if (device_is_registered (&gdev->dev))return gdev; +mutex_unlock (&gdev->reg_mutex);put_device (&gdev->dev); }return NULL ;
@@ -465,6 +467,7 @@if (gdev) {__ccwgroup_remove_symlinks (gdev);device_unregister (&gdev->dev); +mutex_unlock (&gdev->reg_mutex);put_device (&gdev->dev); } }
include/asm-s390/ccwgroup.h +1 -0
@@ -11,6 +11,7 @@CCWGROUP_ONLINE , } state;atomic_t onoff; +struct mutex reg_mutex;unsigned int count;/* number of attached slave devices */ struct device dev;/* master device */ struct ccw_device *cdev[0 ];/* variable number, allocate as needed */
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 15/38 cio: cm_enable memory leak.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
We allocage two pages when channel path measurements are enabled via cm_enable. We must not forget to free them again when channel path measurements are disabled again.
---
drivers/s390/cio/chsc.c | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-)
drivers/s390/cio/chsc.c +1 -1
@@ -818,7 +818,7 @@ }else chsc_remove_cmg_attr (css); } -if (enable && !css->cm_enabled) { +if (!css->cm_enabled) {free_page ((unsigned long )css->cub_addr1);free_page ((unsigned long )css->cub_addr2); }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 16/38 cio: Unregister ccw devices directly.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
We used to unregister ccw devices not directly from the I/O subchannel remove function in order to avoid lifelocks on the css bus semaphore. This semaphore is gone, and there is no reason to not unregister the ccw device directly (it is even better since it is more in keeping with the goal of immediate disconnect).
---
drivers/s390/cio/device.c | 56 +++++++++------------------------------------- 1 files changed, 12 insertions(+), 44 deletions(-)
drivers/s390/cio/device.c +12 -44
@@ -290,16 +290,10 @@return sch_is_pseudo_sch (to_subchannel (cdev->dev.parent)); } -static void ccw_device_unregister (struct work_struct *work) +static void ccw_device_unregister (struct ccw_device *cdev) { -struct ccw_device_private *priv; -struct ccw_device *cdev; - - priv = container_of(work, struct ccw_device_private, kick_work); - cdev = priv->cdev;if (test_and_clear_bit (1 , &cdev->private->registered)) -device_unregister (&cdev->dev); -put_device (&cdev->dev); +device_del (&cdev->dev); } static void
@@ -316,11 +310,8 @@spin_lock_irqsave (cdev->ccwlock, flags); cdev->private->state =DEV_STATE_NOT_OPER ;spin_unlock_irqrestore (cdev->ccwlock, flags); -if (get_device (&cdev->dev)) { -PREPARE_WORK (&cdev->private->kick_work, - ccw_device_unregister); -queue_work (ccw_device_work, &cdev->private->kick_work); - } +ccw_device_unregister (cdev); +put_device (&cdev->dev);return ; } sch =to_subchannel (cdev->dev.parent);
@@ -555,17 +546,10 @@ .attrs = ccwdev_attrs, }; -static int -device_add_files (struct device *dev) -{ -return sysfs_create_group (&dev->kobj, &ccwdev_attr_group); -} - -static void -device_remove_files (struct device *dev) -{ -sysfs_remove_group (&dev->kobj, &ccwdev_attr_group); -} +struct attribute_group *ccwdev_attr_groups[] = { + &ccwdev_attr_group, +NULL , +};/* this is a simple abstraction for device_register that sets the * correct bus type and adds the bus specific files */
@@ -580,10 +564,6 @@return ret;set_bit (1 , &cdev->private->registered); -if ((ret =device_add_files (dev))) { -if (test_and_clear_bit (1 , &cdev->private->registered)) -device_del (dev); - }return ret; }
@@ -655,10 +635,6 @@return ; }set_bit (1 , &cdev->private->registered); -if (device_add_files (&cdev->dev)) { -if (test_and_clear_bit (1 , &cdev->private->registered)) -device_unregister (&cdev->dev); - } }void ccw_device_do_unreg_rereg (struct work_struct *work)
@@ -671,9 +647,7 @@ cdev = priv->cdev; sch =to_subchannel (cdev->dev.parent); -device_remove_files (&cdev->dev); -if (test_and_clear_bit (1 , &cdev->private->registered)) -device_del (&cdev->dev); +ccw_device_unregister (cdev);PREPARE_WORK (&cdev->private->kick_work, ccw_device_add_changed);queue_work (ccw_device_work, &cdev->private->kick_work);
@@ -712,6 +686,7 @@ cdev->dev.parent = &sch->dev; cdev->dev.release = ccw_device_release;INIT_LIST_HEAD (&cdev->private->kick_work.entry); + cdev->dev.groups = ccwdev_attr_groups;/* Do first half of device_register. */ device_initialize (&cdev->dev);if (!get_device (&sch->dev)) {
@@ -1141,15 +1116,8 @@ sch->dev.driver_data =NULL ; cdev->private->state =DEV_STATE_NOT_OPER ;spin_unlock_irqrestore (cdev->ccwlock, flags); -/* -* Put unregistration on workqueue to avoid livelocks on the css bus -* semaphore. -*/ -if (get_device (&cdev->dev)) { -PREPARE_WORK (&cdev->private->kick_work, - ccw_device_unregister); -queue_work (ccw_device_work, &cdev->private->kick_work); - } +ccw_device_unregister (cdev); +put_device (&cdev->dev);return 0 ; }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 17/38 System call cleanup.
In reply to Martin SchwidefskyFrom: Martin Schwidefsky <[email protected]>
Remove system call glue for sys_clone, sys_fork, sys_vfork, sys_execve, sys_sigreturn, sys_rt_sigreturn and sys_sigaltstack. Call do_execve from kernel_execve directly, move pt_regs to the right place and branch to sysc_return to start the user space program. This removes the last in-kernel system call.
---
arch/s390/kernel/compat_linux.c | 62 +++++++++++++----------- arch/s390/kernel/compat_signal.c | 14 +++-- arch/s390/kernel/entry.S | 87 ++++++++++++--------------------- arch/s390/kernel/entry64.S | 100 ++++++++++----------------------------- arch/s390/kernel/process.c | 82 ++++++++++++++++++------------- arch/s390/kernel/signal.c | 10 ++- arch/s390/kernel/sys_s390.c | 20 ------- arch/s390/kernel/syscalls.S | 14 ++--- 8 files changed, 163 insertions(+), 226 deletions(-)
arch/s390/kernel/compat_linux.c +34 -28
@@ -495,29 +495,34 @@* sys32_execve() executes a new program after the asm stub has set * things up for us. This should basically do what I want it to. */ -asmlinkage long -sys32_execve (struct pt_regs regs) +asmlinkage long sys32_execve (void ) { -int error; -char * filename; - - filename =getname (compat_ptr (regs.orig_gpr2)); - error =PTR_ERR (filename); -if (IS_ERR (filename)) +struct pt_regs *regs =task_pt_regs (current); +char *filename; +unsigned long result; +int rc; + + filename =getname (compat_ptr (regs->orig_gpr2)); +if (IS_ERR (filename)) { + result =PTR_ERR (filename); goto out; - error =compat_do_execve (filename,compat_ptr (regs.gprs[3 ]), -compat_ptr (regs.gprs[4 ]), ®s); -if (error ==0 ) - { -task_lock (current); - current->ptrace &= ~PT_DTRACE ; -task_unlock (current); - current->thread.fp_regs.fpc=0 ; - asmvolatile ("sfpc %0,0" : :"d" (0 )); } + rc =compat_do_execve (filename,compat_ptr (regs->gprs[3 ]), +compat_ptr (regs->gprs[4 ]), regs); +if (rc) { + result = rc; + goto out_putname; + } +task_lock (current); + current->ptrace &= ~PT_DTRACE ; +task_unlock (current); + current->thread.fp_regs.fpc=0 ; + asmvolatile ("sfpc %0,0" : :"d" (0 )); + result = regs->gprs[2 ]; +out_putname:putname (filename); out: -return error; +return result; }
@@ -918,19 +923,20 @@return sys_write (fd, buf, count); } -asmlinkage long sys32_clone (struct pt_regs regs) +asmlinkage long sys32_clone (void ) { -unsigned long clone_flags; -unsigned long newsp; +struct pt_regs *regs =task_pt_regs (current); +unsigned long clone_flags; +unsigned long newsp;int __user *parent_tidptr, *child_tidptr; - clone_flags = regs.gprs[3 ] &0xffffffffUL ; - newsp = regs.orig_gpr2 &0x7fffffffUL ; - parent_tidptr =compat_ptr (regs.gprs[4 ]); - child_tidptr =compat_ptr (regs.gprs[5 ]); -if (!newsp) - newsp = regs.gprs[15 ]; -return do_fork (clone_flags, newsp, ®s,0 , + clone_flags = regs->gprs[3 ] &0xffffffffUL ; + newsp = regs->orig_gpr2 &0x7fffffffUL ; + parent_tidptr =compat_ptr (regs->gprs[4 ]); + child_tidptr =compat_ptr (regs->gprs[5 ]); +if (!newsp) + newsp = regs->gprs[15 ]; +return do_fork (clone_flags, newsp, regs,0 , parent_tidptr, child_tidptr); }
arch/s390/kernel/compat_signal.c +8 -6
@@ -255,9 +255,9 @@ }asmlinkage long -sys32_sigaltstack (const stack_t32 __user *uss,stack_t32 __user *uoss, -struct pt_regs *regs) +sys32_sigaltstack (const stack_t32 __user *uss,stack_t32 __user *uoss) { +struct pt_regs *regs =task_pt_regs (current);stack_t kss, koss;unsigned long ss_sp;int ret, err =0 ;
@@ -344,8 +344,9 @@return 0 ; } -asmlinkage long sys32_sigreturn (struct pt_regs *regs) +asmlinkage long sys32_sigreturn (void ) { +struct pt_regs *regs =task_pt_regs (current);sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15 ];sigset_t set;
@@ -370,8 +371,9 @@return 0 ; } -asmlinkage long sys32_rt_sigreturn (struct pt_regs *regs) +asmlinkage long sys32_rt_sigreturn (void ) { +struct pt_regs *regs =task_pt_regs (current);rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15 ];sigset_t set;stack_t st;
@@ -407,8 +409,8 @@return regs->gprs[2 ]; badframe: -force_sig (SIGSEGV , current); -return 0 ; +force_sig (SIGSEGV , current); +return 0 ; }/*
arch/s390/kernel/entry64.S +28 -72
113 lines not on this page · raw message
arch/s390/kernel/entry.S +32 -55
109 lines not on this page · raw message
arch/s390/kernel/process.c +48 -34
112 lines not on this page · raw message
arch/s390/kernel/signal.c +6 -4
@@ -102,9 +102,9 @@ }asmlinkage long -sys_sigaltstack (const stack_t __user *uss,stack_t __user *uoss, -struct pt_regs *regs) +sys_sigaltstack (const stack_t __user *uss,stack_t __user *uoss) { +struct pt_regs *regs =task_pt_regs (current);return do_sigaltstack (uss, uoss, regs->gprs[15 ]); }
@@ -163,8 +163,9 @@return 0 ; } -asmlinkage long sys_sigreturn (struct pt_regs *regs) +asmlinkage long sys_sigreturn (void ) { +struct pt_regs *regs =task_pt_regs (current);sigframe __user *frame = (sigframe __user *)regs->gprs[15 ];sigset_t set;
@@ -189,8 +190,9 @@return 0 ; } -asmlinkage long sys_rt_sigreturn (struct pt_regs *regs) +asmlinkage long sys_rt_sigreturn (void ) { +struct pt_regs *regs =task_pt_regs (current);rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15 ];sigset_t set;
arch/s390/kernel/syscalls.S +7 -7
@@ -10,7 +10,7 @@ NI_SYSCALL /* 0 */ SYSCALL(sys_exit,sys_exit,sys32_exit_wrapper) -SYSCALL(sys_fork_glue,sys_fork_glue,sys_fork_glue) +SYSCALL(sys_fork,sys_fork,sys_fork) SYSCALL(sys_read,sys_read,sys32_read_wrapper) SYSCALL(sys_write,sys_write,sys32_write_wrapper) SYSCALL(sys_open,sys_open,sys32_open_wrapper) /* 5 */
@@ -19,7 +19,7 @@ SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper) SYSCALL(sys_link,sys_link,sys32_link_wrapper) SYSCALL(sys_unlink,sys_unlink,sys32_unlink_wrapper) /* 10 */ -SYSCALL(sys_execve_glue,sys_execve_glue,sys32_execve_glue) +SYSCALL(sys_execve,sys_execve,sys32_execve) SYSCALL(sys_chdir,sys_chdir,sys32_chdir_wrapper) SYSCALL(sys_time,sys_ni_syscall,sys32_time_wrapper) /* old time syscall */ SYSCALL(sys_mknod,sys_mknod,sys32_mknod_wrapper)
@@ -127,8 +127,8 @@ SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper) SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper) SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper) -SYSCALL(sys_sigreturn_glue,sys_sigreturn_glue,sys32_sigreturn_glue) -SYSCALL(sys_clone_glue,sys_clone_glue,sys32_clone_glue) /* 120 */ +SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn) +SYSCALL(sys_clone,sys_clone,sys32_clone) /* 120 */ SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper) SYSCALL(sys_newuname,s390x_newuname,sys32_newuname_wrapper) NI_SYSCALL /* modify_ldt for i386 */
@@ -181,7 +181,7 @@ SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper) /* 170 old setresgid16 syscall */ SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper) /* old getresgid16 syscall */ SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper) -SYSCALL(sys_rt_sigreturn_glue,sys_rt_sigreturn_glue,sys32_rt_sigreturn_glue) +SYSCALL(sys_rt_sigreturn,sys_rt_sigreturn,sys32_rt_sigreturn) SYSCALL(sys_rt_sigaction,sys_rt_sigaction,sys32_rt_sigaction_wrapper) SYSCALL(sys_rt_sigprocmask,sys_rt_sigprocmask,sys32_rt_sigprocmask_wrapper) /* 175 */ SYSCALL(sys_rt_sigpending,sys_rt_sigpending,sys32_rt_sigpending_wrapper)
@@ -194,11 +194,11 @@ SYSCALL(sys_getcwd,sys_getcwd,sys32_getcwd_wrapper) SYSCALL(sys_capget,sys_capget,sys32_capget_wrapper) SYSCALL(sys_capset,sys_capset,sys32_capset_wrapper) /* 185 */ -SYSCALL(sys_sigaltstack_glue,sys_sigaltstack_glue,sys32_sigaltstack_glue) +SYSCALL(sys_sigaltstack,sys_sigaltstack,sys32_sigaltstack) SYSCALL(sys_sendfile,sys_sendfile64,sys32_sendfile_wrapper) NI_SYSCALL /* streams1 */ NI_SYSCALL /* streams2 */ -SYSCALL(sys_vfork_glue,sys_vfork_glue,sys_vfork_glue) /* 190 */ +SYSCALL(sys_vfork,sys_vfork,sys_vfork) /* 190 */ SYSCALL(sys_getrlimit,sys_getrlimit,compat_sys_getrlimit_wrapper) SYSCALL(sys_mmap2,sys_mmap2,sys32_mmap2_wrapper) SYSCALL(sys_truncate64,sys_ni_syscall,sys32_truncate64_wrapper)
arch/s390/kernel/sys_s390.c +0 -20
@@ -266,23 +266,3 @@return -EFAULT ;return sys_fadvise64_64 (a.fd, a.offset, a.len, a.advice); } - -/* -* Do a system call from kernel instead of calling sys_execve so we -* end up with proper pt_regs. -*/ -int kernel_execve (const char *filename,char *const argv[],char *const envp[]) -{ - register const char *__arg1 asm("2") = filename; - register char *const*__arg2 asm("3") = argv; - register char *const*__arg3 asm("4") = envp; - registerlong __svcres asm("2" ); - asmvolatile ( -"svc %b1" - :"=d" (__svcres) - :"i" (__NR_execve), -"0" (__arg1), -"d" (__arg2), -"d" (__arg3) :"memory" ); -return __svcres; -}
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 18/38 Improved oops output.
In reply to Martin SchwidefskyFrom: Martin Schwidefsky <[email protected]>
This patch adds two improvements to the oops output. First it adds an additional line after the PSW which decodes the different fields of it. Second a disassembler is added that decodes the instructions surrounding the faulting PSW. The output of a test oops now looks like this:
kernel BUG at init/main.c:419
illegal operation: 0001 [#1]
CPU: 0 Not tainted
Process swapper (pid: 0, task: 0000000000464968, ksp: 00000000004be000) Krnl PSW : 0700000180000000 00000000000120b6 (rest_init+0x36/0x38)
R:0 T:1 IO:1 EX:1 Key:0 M:0 W:0 P:0 AS:0 CC:0 PM:0 EA:3
Krnl GPRS: 0000000000000003 00000000004ba017 0000000000000022 0000000000000001
000000000003a5f6 0000000000000000 00000000004be6a8 0000000000000000
0000000000000000 00000000004b8200 0000000000003a50 0000000000008000
0000000000516368 000000000033d008 00000000000120b2 00000000004bdee0
Krnl Code: 00000000000120a6: e3e0f0980024 stg %r14,152(%r15)
00000000000120ac: c0e500014296 brasl %r14,3a5d8
00000000000120b2: a7f40001 brc 15,120b4
>00000000000120b6: 0707 bcr 0,%r7
00000000000120b8: eb7ff0500024 stmg %r7,%r15,80(%r15)
00000000000120be: c0d000195825 larl %r13,33d108
00000000000120c4: a7f13f00 tmll %r15,16128
00000000000120c8: a7840001 brc 8,120ca
Call Trace:
([<00000000000120b2>] rest_init+0x32/0x38)
[<00000000004be614>] start_kernel+0x37c/0x410
[<0000000000012020>] _ehead+0x20/0x80---
arch/s390/kernel/Makefile | 2 arch/s390/kernel/dis.c | 1278 +++++++++++++++++++++++++++++++++++++++++++ arch/s390/kernel/traps.c | 55 - include/asm-s390/processor.h | 1 4 files changed, 1297 insertions(+), 39 deletions(-)
arch/s390/kernel/dis.c new file +1278 -0
@@ -0,0 +1,1278 @@ +/* + * arch/s390/kernel/dis.c + * + * Disassemble s390 instructions. + * + * Copyright IBM Corp. 2007 + * Author(s): Martin Schwidefsky ([email protected]), + */ + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/ptrace.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/kallsyms.h> +#include <linux/reboot.h> +#include <linux/kprobes.h> + +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/atomic.h> +#include <asm/mathemu.h> +#include <asm/cpcmd.h> +#include <asm/s390_ext.h> +#include <asm/lowcore.h> +#include <asm/debug.h> +#include <asm/kdebug.h> + +#ifndef CONFIG_64BIT +#define ONELONG "%08lx: " +#else /* CONFIG_64BIT */ +#define ONELONG "%016lx: " +#endif /* CONFIG_64BIT */ + +#define OPERAND_GPR 0x1 /* Operand printed as %rx */ +#define OPERAND_FPR 0x2 /* Operand printed as %fx */ +#define OPERAND_AR 0x4 /* Operand printed as %ax */ +#define OPERAND_CR 0x8 /* Operand printed as %cx */ +#define OPERAND_DISP 0x10 /* Operand printed as displacement */ +#define OPERAND_BASE 0x20 /* Operand printed as base register */ +#define OPERAND_INDEX 0x40 /* Operand printed as index register */ +#define OPERAND_PCREL 0x80 /* Operand printed as pc-relative symbol */ +#define OPERAND_SIGNED 0x100 /* Operand printed as signed value */ +#define OPERAND_LENGTH 0x200 /* Operand printed as length (+1) */ + +enum { + UNUSED, /* Indicates the end of the operand list */ + R_8, /* GPR starting at position 8 */ + R_12, /* GPR starting at position 12 */ + R_16, /* GPR starting at position 16 */ + R_20, /* GPR starting at position 20 */ + R_24, /* GPR starting at position 24 */ + R_28, /* GPR starting at position 28 */ + R_32, /* GPR starting at position 32 */ + F_8, /* FPR starting at position 8 */ + F_12, /* FPR starting at position 12 */ + F_16, /* FPR starting at position 16 */ + F_20, /* FPR starting at position 16 */ + F_24, /* FPR starting at position 24 */ + F_28, /* FPR starting at position 28 */ + F_32, /* FPR starting at position 32 */ + A_8, /* Access reg. starting at position 8 */ + A_12, /* Access reg. starting at position 12 */ + A_24, /* Access reg. starting at position 24 */ + A_28, /* Access reg. starting at position 28 */ + C_8, /* Control reg. starting at position 8 */ + C_12, /* Control reg. starting at position 12 */ + B_16, /* Base register starting at position 16 */ + B_32, /* Base register starting at position 32 */ + X_12, /* Index register starting at position 12 */ + D_20, /* Displacement starting at position 20 */ + D_36, /* Displacement starting at position 36 */ + D20_20, /* 20 bit displacement starting at 20 */ + L4_8, /* 4 bit length starting at position 8 */ + L4_12, /* 4 bit length starting at position 12 */ + L8_8, /* 8 bit length starting at position 8 */ + U4_8, /* 4 bit unsigned value starting at 8 */ + U4_12, /* 4 bit unsigned value starting at 12 */ + U4_16, /* 4 bit unsigned value starting at 16 */ + U4_20, /* 4 bit unsigned value starting at 20 */ + U8_8, /* 8 bit unsigned value starting at 8 */ + U8_16, /* 8 bit unsigned value starting at 16 */ + I16_16, /* 16 bit signed value starting at 16 */ + U16_16, /* 16 bit unsigned value starting at 16 */ + J16_16, /* PC relative jump offset at 16 */ + J32_16, /* PC relative long offset at 16 */ + I32_16, /* 32 bit signed value starting at 16 */ + U32_16, /* 32 bit unsigned value starting at 16 */ + M_16, /* 4 bit optional mask starting at 16 */ + RO_28, /* optional GPR starting at position 28 */ +}; + +/* + * Enumeration of the different instruction formats. + * For details consult the principles of operation. + */ +enum { + INSTR_INVALID, + INSTR_E, INSTR_RIE_RRP, INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU, + INSTR_RIL_UP, INSTR_RI_RI, INSTR_RI_RP, INSTR_RI_RU, INSTR_RI_UP, + INSTR_RRE_00, INSTR_RRE_0R, INSTR_RRE_AA, INSTR_RRE_AR, INSTR_RRE_F0, + INSTR_RRE_FF, INSTR_RRE_R0, INSTR_RRE_RA, INSTR_RRE_RF, INSTR_RRE_RR, + INSTR_RRE_RR_OPT, INSTR_RRF_F0FF, INSTR_RRF_FUFF, INSTR_RRF_M0RR, + INSTR_RRF_R0RR, INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF, + INSTR_RR_FF, INSTR_RR_R0, INSTR_RR_RR, INSTR_RR_U0, INSTR_RR_UR, + INSTR_RSE_CCRD, INSTR_RSE_RRRD, INSTR_RSE_RURD, INSTR_RSI_RRP, + INSTR_RSL_R0RD, INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, + INSTR_RSY_RURD, INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, + INSTR_RS_RRRD, INSTR_RS_RURD, INSTR_RXE_FRRD, INSTR_RXE_RRRD, + INSTR_RXF_FRRDF, INSTR_RXY_FRRD, INSTR_RXY_RRRD, INSTR_RX_FRRD, + INSTR_RX_RRRD, INSTR_RX_URRD, INSTR_SIY_URD, INSTR_SI_URD, + INSTR_SSE_RDRD, INSTR_SSF_RRDRD, INSTR_SS_L0RDRD, INSTR_SS_LIRDRD, + INSTR_SS_LLRDRD, INSTR_SS_RRRDRD, INSTR_SS_RRRDRD2, INSTR_SS_RRRDRD3, + INSTR_S_00, INSTR_S_RD, +}; + +struct operand { + int bits; /* The number of bits in the operand. */ + int shift; /* The number of bits to shift. */ + int flags; /* One bit syntax flags. */ +}; + +struct insn { + const char name[5]; + unsigned char opfrag; + unsigned char format; +}; + +static const struct operand operands[] = +{ + [UNUSED] = { 0, 0, 0 }, + [R_8] = { 4, 8, OPERAND_GPR }, + [R_12] = { 4, 12, OPERAND_GPR }, + [R_16] = { 4, 16, OPERAND_GPR }, + [R_20] = { 4, 20, OPERAND_GPR }, + [R_24] = { 4, 24, OPERAND_GPR }, + [R_28] = { 4, 28, OPERAND_GPR }, + [R_32] = { 4, 32, OPERAND_GPR }, + [F_8] = { 4, 8, OPERAND_FPR }, + [F_12] = { 4, 12, OPERAND_FPR }, + [F_16] = { 4, 16, OPERAND_FPR }, + [F_20] = { 4, 16, OPERAND_FPR }, + [F_24] = { 4, 24, OPERAND_FPR }, + [F_28] = { 4, 28, OPERAND_FPR }, + [F_32] = { 4, 32, OPERAND_FPR }, + [A_8] = { 4, 8, OPERAND_AR }, + [A_12] = { 4, 12, OPERAND_AR }, + [A_24] = { 4, 24, OPERAND_AR }, + [A_28] = { 4, 28, OPERAND_AR }, + [C_8] = { 4, 8, OPERAND_CR }, + [C_12] = { 4, 12, OPERAND_CR }, + [B_16] = { 4, 16, OPERAND_BASE | OPERAND_GPR }, + [B_32] = { 4, 32, OPERAND_BASE | OPERAND_GPR }, + [X_12] = { 4, 12, OPERAND_INDEX | OPERAND_GPR }, + [D_20] = { 12, 20, OPERAND_DISP }, + [D_36] = { 12, 36, OPERAND_DISP }, + [D20_20] = { 20, 20, OPERAND_DISP | OPERAND_SIGNED }, + [L4_8] = { 4, 8, OPERAND_LENGTH }, + [L4_12] = { 4, 12, OPERAND_LENGTH }, + [L8_8] = { 8, 8, OPERAND_LENGTH }, + [U4_8] = { 4, 8, 0 }, + [U4_12] = { 4, 12, 0 }, + [U4_16] = { 4, 16, 0 }, + [U4_20] = { 4, 20, 0 }, + [U8_8] = { 8, 8, 0 }, + [U8_16] = { 8, 16, 0 }, + [I16_16] = { 16, 16, OPERAND_SIGNED }, + [U16_16] = { 16, 16, 0 }, + [J16_16] = { 16, 16, OPERAND_PCREL }, + [J32_16] = { 32, 16, OPERAND_PCREL }, + [I32_16] = { 32, 16, OPERAND_SIGNED }, + [U32_16] = { 32, 16, 0 }, + [M_16] = { 4, 16, 0 }, + [RO_28] = { 4, 28, OPERAND_GPR } +}; + +static const unsigned char formats[][7] = { + [INSTR_E] = { 0xff, 0,0,0,0,0,0 }, /* e.g. pr */ + [INSTR_RIE_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, /* e.g. brxhg */ + [INSTR_RIL_RP] = { 0x0f, R_8,J32_16,0,0,0,0 }, /* e.g. brasl */ + [INSTR_RIL_UP] = { 0x0f, U4_8,J32_16,0,0,0,0 }, /* e.g. brcl */ + [INSTR_RIL_RI] = { 0x0f, R_8,I32_16,0,0,0,0 }, /* e.g. afi */ + [INSTR_RIL_RU] = { 0x0f, R_8,U32_16,0,0,0,0 }, /* e.g. alfi */ + [INSTR_RI_RI] = { 0x0f, R_8,I16_16,0,0,0,0 }, /* e.g. ahi */ + [INSTR_RI_RP] = { 0x0f, R_8,J16_16,0,0,0,0 }, /* e.g. brct */ + [INSTR_RI_RU] = { 0x0f, R_8,U16_16,0,0,0,0 }, /* e.g. tml */ + [INSTR_RI_UP] = { 0x0f, U4_8,J16_16,0,0,0,0 }, /* e.g. brc */ + [INSTR_RRE_00] = { 0xff, 0,0,0,0,0,0 }, /* e.g. palb */ + [INSTR_RRE_0R] = { 0xff, R_28,0,0,0,0,0 }, /* e.g. tb */ + [INSTR_RRE_AA] = { 0xff, A_24,A_28,0,0,0,0 }, /* e.g. cpya */ + [INSTR_RRE_AR] = { 0xff, A_24,R_28,0,0,0,0 }, /* e.g. sar */ + [INSTR_RRE_F0] = { 0xff, F_24,0,0,0,0,0 }, /* e.g. sqer */ + [INSTR_RRE_FF] = { 0xff, F_24,F_28,0,0,0,0 }, /* e.g. debr */ + [INSTR_RRE_R0] = { 0xff, R_24,0,0,0,0,0 }, /* e.g. ipm */ + [INSTR_RRE_RA] = { 0xff, R_24,A_28,0,0,0,0 }, /* e.g. ear */ + [INSTR_RRE_RF] = { 0xff, R_24,F_28,0,0,0,0 }, /* e.g. cefbr */ + [INSTR_RRE_RR] = { 0xff, R_24,R_28,0,0,0,0 }, /* e.g. lura */ + [INSTR_RRE_RR_OPT]= { 0xff, R_24,RO_28,0,0,0,0 }, /* efpc, sfpc */ + [INSTR_RRF_F0FF] = { 0xff, F_16,F_24,F_28,0,0,0 }, /* e.g. madbr */ + [INSTR_RRF_FUFF] = { 0xff, F_24,F_16,F_28,U4_20,0,0 },/* e.g. didbr */ + [INSTR_RRF_RURR] = { 0xff, R_24,R_28,R_16,U4_20,0,0 },/* e.g. .insn */ + [INSTR_RRF_R0RR] = { 0xff, R_24,R_28,R_16,0,0,0 }, /* e.g. idte */ + [INSTR_RRF_U0FF] = { 0xff, F_24,U4_16,F_28,0,0,0 }, /* e.g. fixr */ + [INSTR_RRF_U0RF] = { 0xff, R_24,U4_16,F_28,0,0,0 }, /* e.g. cfebr */ + [INSTR_RRF_M0RR] = { 0xff, R_24,R_28,M_16,0,0,0 }, /* e.g. sske */ + [INSTR_RR_FF] = { 0xff, F_8,F_12,0,0,0,0 }, /* e.g. adr */ + [INSTR_RR_R0] = { 0xff, R_8, 0,0,0,0,0 }, /* e.g. spm */ + [INSTR_RR_RR] = { 0xff, R_8,R_12,0,0,0,0 }, /* e.g. lr */ + [INSTR_RR_U0] = { 0xff, U8_8, 0,0,0,0,0 }, /* e.g. svc */ + [INSTR_RR_UR] = { 0xff, U4_8,R_12,0,0,0,0 }, /* e.g. bcr */ + [INSTR_RSE_RRRD] = { 0xff, R_8,R_12,D_20,B_16,0,0 }, /* e.g. lmh */ + [INSTR_RSE_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 }, /* e.g. lmh */ + [INSTR_RSE_RURD] = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, /* e.g. icmh */ + [INSTR_RSL_R0RD] = { 0xff, R_8,D_20,B_16,0,0,0 }, /* e.g. tp */ + [INSTR_RSI_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, /* e.g. brxh */ + [INSTR_RSY_RRRD] = { 0xff, R_8,R_12,D20_20,B_16,0,0 },/* e.g. stmy */ + [INSTR_RSY_RURD] = { 0xff, R_8,U4_12,D20_20,B_16,0,0 }, + /* e.g. icmh */ + [INSTR_RSY_AARD] = { 0xff, A_8,A_12,D20_20,B_16,0,0 },/* e.g. lamy */ + [INSTR_RSY_CCRD] = { 0xff, C_8,C_12,D20_20,B_16,0,0 },/* e.g. lamy */ + [INSTR_RS_AARD] = { 0xff, A_8,A_12,D_20,B_16,0,0 }, /* e.g. lam */ + [INSTR_RS_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 }, /* e.g. lctl */ + [INSTR_RS_R0RD] = { 0xff, R_8,D_20,B_16,0,0,0 }, /* e.g. sll */ + [INSTR_RS_RRRD] = { 0xff, R_8,R_12,D_20,B_16,0,0 }, /* e.g. cs */ + [INSTR_RS_RURD] = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, /* e.g. icm */ + [INSTR_RXE_FRRD] = { 0xff, F_8,D_20,X_12,B_16,0,0 }, /* e.g. axbr */ + [INSTR_RXE_RRRD] = { 0xff, R_8,D_20,X_12,B_16,0,0 }, /* e.g. lg */ + [INSTR_RXF_FRRDF] = { 0xff, F_32,F_8,D_20,X_12,B_16,0 }, + /* e.g. madb */ + [INSTR_RXY_RRRD] = { 0xff, R_8,D20_20,X_12,B_16,0,0 },/* e.g. ly */ + [INSTR_RXY_FRRD] = { 0xff, F_8,D20_20,X_12,B_16,0,0 },/* e.g. ley */ + [INSTR_RX_FRRD] = { 0xff, F_8,D_20,X_12,B_16,0,0 }, /* e.g. ae */ + [INSTR_RX_RRRD] = { 0xff, R_8,D_20,X_12,B_16,0,0 }, /* e.g. l */ + [INSTR_RX_URRD] = { 0x00, U4_8,D_20,X_12,B_16,0,0 }, /* e.g. bc */ + [INSTR_SI_URD] = { 0x00, D_20,B_16,U8_8,0,0,0 }, /* e.g. cli */ + [INSTR_SIY_URD] = { 0xff, D20_20,B_16,U8_8,0,0,0 }, /* e.g. tmy */ + [INSTR_SSE_RDRD] = { 0xff, D_20,B_16,D_36,B_32,0,0 }, /* e.g. mvsdk */ + [INSTR_SS_L0RDRD] = { 0xff, D_20,L8_8,B_16,D_36,B_32,0 }, + /* e.g. mvc */ + [INSTR_SS_LIRDRD] = { 0xff, D_20,L4_8,B_16,D_36,B_32,U4_12 }, + /* e.g. srp */ + [INSTR_SS_LLRDRD] = { 0xff, D_20,L4_8,B_16,D_36,L4_12,B_32 }, + /* e.g. pack */ + [INSTR_SS_RRRDRD] = { 0xff, D_20,R_8,B_16,D_36,B_32,R_12 }, + /* e.g. mvck */ + [INSTR_SS_RRRDRD2]= { 0xff, R_8,D_20,B_16,R_12,D_36,B_32 }, + /* e.g. plo */ + [INSTR_SS_RRRDRD3]= { 0xff, R_8,R_12,D_20,B_16,D_36,B_32 }, + /* e.g. lmd */ + [INSTR_S_00] = { 0xff, 0,0,0,0,0,0 }, /* e.g. hsch */ + [INSTR_S_RD] = { 0xff, D_20,B_16,0,0,0,0 }, /* e.g. lpsw */ + [INSTR_SSF_RRDRD] = { 0x00, D_20,B_16,D_36,B_32,R_8,0 }, + /* e.g. mvcos */ +}; + +static struct insn opcode[] = { +#ifdef CONFIG_64BIT + { "lmd", 0xef, INSTR_SS_RRRDRD3 }, +#endif + { "spm", 0x04, INSTR_RR_R0 }, + { "balr", 0x05, INSTR_RR_RR }, + { "bctr", 0x06, INSTR_RR_RR }, + { "bcr", 0x07, INSTR_RR_UR }, + { "svc", 0x0a, INSTR_RR_U0 }, + { "bsm", 0x0b, INSTR_RR_RR }, + { "bassm", 0x0c, INSTR_RR_RR }, + { "basr", 0x0d, INSTR_RR_RR }, + { "mvcl", 0x0e, INSTR_RR_RR }, + { "clcl", 0x0f, INSTR_RR_RR }, + { "lpr", 0x10, INSTR_RR_RR }, + { "lnr", 0x11, INSTR_RR_RR }, + { "ltr", 0x12, INSTR_RR_RR }, + { "lcr", 0x13, INSTR_RR_RR }, + { "nr", 0x14, INSTR_RR_RR }, + { "clr", 0x15, INSTR_RR_RR }, + { "or", 0x16, INSTR_RR_RR }, + { "xr", 0x17, INSTR_RR_RR }, + { "lr", 0x18, INSTR_RR_RR }, + { "cr", 0x19, INSTR_RR_RR }, + { "ar", 0x1a, INSTR_RR_RR }, + { "sr", 0x1b, INSTR_RR_RR }, + { "mr", 0x1c, INSTR_RR_RR }, + { "dr", 0x1d, INSTR_RR_RR }, + { "alr", 0x1e, INSTR_RR_RR }, + { "slr", 0x1f, INSTR_RR_RR }, + { "lpdr", 0x20, INSTR_RR_FF }, + { "lndr", 0x21, INSTR_RR_FF }, + { "ltdr", 0x22, INSTR_RR_FF }, + { "lcdr", 0x23, INSTR_RR_FF }, + { "hdr", 0x24, INSTR_RR_FF }, + { "ldxr", 0x25, INSTR_RR_FF }, + { "lrdr", 0x25, INSTR_RR_FF }, + { "mxr", 0x26, INSTR_RR_FF }, + { "mxdr", 0x27, INSTR_RR_FF }, + { "ldr", 0x28, INSTR_RR_FF }, + { "cdr", 0x29, INSTR_RR_FF }, + { "adr", 0x2a, INSTR_RR_FF }, + { "sdr", 0x2b, INSTR_RR_FF }, + { "mdr", 0x2c, INSTR_RR_FF }, + { "ddr", 0x2d, INSTR_RR_FF }, + { "awr", 0x2e, INSTR_RR_FF }, + { "swr", 0x2f, INSTR_RR_FF }, + { "lper", 0x30, INSTR_RR_FF }, + { "lner", 0x31, INSTR_RR_FF }, + { "lter", 0x32, INSTR_RR_FF }, + { "lcer", 0x33, INSTR_RR_FF }, + { "her", 0x34, INSTR_RR_FF }, + { "ledr", 0x35, INSTR_RR_FF }, + { "lrer", 0x35, INSTR_RR_FF }, + { "axr", 0x36, INSTR_RR_FF }, + { "sxr", 0x37, INSTR_RR_FF }, + { "ler", 0x38, INSTR_RR_FF }, + { "cer", 0x39, INSTR_RR_FF }, + { "aer", 0x3a, INSTR_RR_FF }, + { "ser", 0x3b, INSTR_RR_FF }, + { "mder", 0x3c, INSTR_RR_FF }, + { "mer", 0x3c, INSTR_RR_FF }, + { "der", 0x3d, INSTR_RR_FF }, + { "aur", 0x3e, INSTR_RR_FF }, + { "sur", 0x3f, INSTR_RR_FF }, + { "sth", 0x40, INSTR_RX_RRRD }, + { "la", 0x41, INSTR_RX_RRRD }, + { "stc", 0x42, INSTR_RX_RRRD }, + { "ic", 0x43, INSTR_RX_RRRD }, + { "ex", 0x44, INSTR_RX_RRRD }, + { "bal", 0x45, INSTR_RX_RRRD }, + { "bct", 0x46, INSTR_RX_RRRD }, + { "bc", 0x47, INSTR_RX_URRD }, + { "lh", 0x48, INSTR_RX_RRRD }, + { "ch", 0x49, INSTR_RX_RRRD }, + { "ah", 0x4a, INSTR_RX_RRRD }, + { "sh", 0x4b, INSTR_RX_RRRD }, + { "mh", 0x4c, INSTR_RX_RRRD }, + { "bas", 0x4d, INSTR_RX_RRRD }, + { "cvd", 0x4e, INSTR_RX_RRRD }, + { "cvb", 0x4f, INSTR_RX_RRRD }, + { "st", 0x50, INSTR_RX_RRRD }, + { "lae", 0x51, INSTR_RX_RRRD }, + { "n", 0x54, INSTR_RX_RRRD }, + { "cl", 0x55, INSTR_RX_RRRD }, + { "o", 0x56, INSTR_RX_RRRD }, + { "x", 0x57, INSTR_RX_RRRD }, + { "l", 0x58, INSTR_RX_RRRD }, + { "c", 0x59, INSTR_RX_RRRD }, + { "a", 0x5a, INSTR_RX_RRRD }, + { "s", 0x5b, INSTR_RX_RRRD }, + { "m", 0x5c, INSTR_RX_RRRD }, + { "d", 0x5d, INSTR_RX_RRRD }, + { "al", 0x5e, INSTR_RX_RRRD }, + { "sl", 0x5f, INSTR_RX_RRRD }, + { "std", 0x60, INSTR_RX_FRRD }, + { "mxd", 0x67, INSTR_RX_FRRD }, + { "ld", 0x68, INSTR_RX_FRRD }, + { "cd", 0x69, INSTR_RX_FRRD }, + { "ad", 0x6a, INSTR_RX_FRRD }, + { "sd", 0x6b, INSTR_RX_FRRD }, + { "md", 0x6c, INSTR_RX_FRRD }, + { "dd", 0x6d, INSTR_RX_FRRD }, + { "aw", 0x6e, INSTR_RX_FRRD }, + { "sw", 0x6f, INSTR_RX_FRRD }, + { "ste", 0x70, INSTR_RX_FRRD }, + { "ms", 0x71, INSTR_RX_RRRD }, + { "le", 0x78, INSTR_RX_FRRD }, + { "ce", 0x79, INSTR_RX_FRRD }, + { "ae", 0x7a, INSTR_RX_FRRD }, + { "se", 0x7b, INSTR_RX_FRRD }, + { "mde", 0x7c, INSTR_RX_FRRD }, + { "me", 0x7c, INSTR_RX_FRRD }, + { "de", 0x7d, INSTR_RX_FRRD }, + { "au", 0x7e, INSTR_RX_FRRD }, + { "su", 0x7f, INSTR_RX_FRRD }, + { "ssm", 0x80, INSTR_S_RD }, + { "lpsw", 0x82, INSTR_S_RD }, + { "diag", 0x83, INSTR_RS_RRRD }, + { "brxh", 0x84, INSTR_RSI_RRP }, + { "brxle", 0x85, INSTR_RSI_RRP }, + { "bxh", 0x86, INSTR_RS_RRRD }, + { "bxle", 0x87, INSTR_RS_RRRD }, + { "srl", 0x88, INSTR_RS_R0RD }, + { "sll", 0x89, INSTR_RS_R0RD }, + { "sra", 0x8a, INSTR_RS_R0RD }, + { "sla", 0x8b, INSTR_RS_R0RD }, + { "srdl", 0x8c, INSTR_RS_R0RD }, + { "sldl", 0x8d, INSTR_RS_R0RD }, + { "srda", 0x8e, INSTR_RS_R0RD }, + { "slda", 0x8f, INSTR_RS_R0RD }, + { "stm", 0x90, INSTR_RS_RRRD }, + { "tm", 0x91, INSTR_SI_URD }, + { "mvi", 0x92, INSTR_SI_URD }, + { "ts", 0x93, INSTR_S_RD }, + { "ni", 0x94, INSTR_SI_URD }, + { "cli", 0x95, INSTR_SI_URD }, + { "oi", 0x96, INSTR_SI_URD }, + { "xi", 0x97, INSTR_SI_URD }, + { "lm", 0x98, INSTR_RS_RRRD }, + { "trace", 0x99, INSTR_RS_RRRD }, + { "lam", 0x9a, INSTR_RS_AARD }, + { "stam", 0x9b, INSTR_RS_AARD }, + { "mvcle", 0xa8, INSTR_RS_RRRD }, + { "clcle", 0xa9, INSTR_RS_RRRD }, + { "stnsm", 0xac, INSTR_SI_URD }, + { "stosm", 0xad, INSTR_SI_URD }, + { "sigp", 0xae, INSTR_RS_RRRD }, + { "mc", 0xaf, INSTR_SI_URD }, + { "lra", 0xb1, INSTR_RX_RRRD }, + { "stctl", 0xb6, INSTR_RS_CCRD }, + { "lctl", 0xb7, INSTR_RS_CCRD }, + { "cs", 0xba, INSTR_RS_RRRD }, + { "cds", 0xbb, INSTR_RS_RRRD }, + { "clm", 0xbd, INSTR_RS_RURD }, + { "stcm", 0xbe, INSTR_RS_RURD }, + { "icm", 0xbf, INSTR_RS_RURD }, + { "mvn", 0xd1, INSTR_SS_L0RDRD }, + { "mvc", 0xd2, INSTR_SS_L0RDRD }, + { "mvz", 0xd3, INSTR_SS_L0RDRD }, + { "nc", 0xd4, INSTR_SS_L0RDRD }, + { "clc", 0xd5, INSTR_SS_L0RDRD }, + { "oc", 0xd6, INSTR_SS_L0RDRD }, + { "xc", 0xd7, INSTR_SS_L0RDRD }, + { "mvck", 0xd9, INSTR_SS_RRRDRD }, + { "mvcp", 0xda, INSTR_SS_RRRDRD }, + { "mvcs", 0xdb, INSTR_SS_RRRDRD }, + { "tr", 0xdc, INSTR_SS_L0RDRD }, + { "trt", 0xdd, INSTR_SS_L0RDRD }, + { "ed", 0xde, INSTR_SS_L0RDRD }, + { "edmk", 0xdf, INSTR_SS_L0RDRD }, + { "pku", 0xe1, INSTR_SS_L0RDRD }, + { "unpku", 0xe2, INSTR_SS_L0RDRD }, + { "mvcin", 0xe8, INSTR_SS_L0RDRD }, + { "pka", 0xe9, INSTR_SS_L0RDRD }, + { "unpka", 0xea, INSTR_SS_L0RDRD }, + { "plo", 0xee, INSTR_SS_RRRDRD2 }, + { "srp", 0xf0, INSTR_SS_LIRDRD }, + { "mvo", 0xf1, INSTR_SS_LLRDRD }, + { "pack", 0xf2, INSTR_SS_LLRDRD }, + { "unpk", 0xf3, INSTR_SS_LLRDRD }, + { "zap", 0xf8, INSTR_SS_LLRDRD }, + { "cp", 0xf9, INSTR_SS_LLRDRD }, + { "ap", 0xfa, INSTR_SS_LLRDRD }, + { "sp", 0xfb, INSTR_SS_LLRDRD }, + { "mp", 0xfc, INSTR_SS_LLRDRD }, + { "dp", 0xfd, INSTR_SS_LLRDRD }, + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_01[] = { +#ifdef CONFIG_64BIT + { "sam64", 0x0e, INSTR_E }, +#endif + { "pr", 0x01, INSTR_E }, + { "upt", 0x02, INSTR_E }, + { "sckpf", 0x07, INSTR_E }, + { "tam", 0x0b, INSTR_E }, + { "sam24", 0x0c, INSTR_E }, + { "sam31", 0x0d, INSTR_E }, + { "trap2", 0xff, INSTR_E }, + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_a5[] = { +#ifdef CONFIG_64BIT + { "iihh", 0x00, INSTR_RI_RU }, + { "iihl", 0x01, INSTR_RI_RU }, + { "iilh", 0x02, INSTR_RI_RU }, + { "iill", 0x03, INSTR_RI_RU }, + { "nihh", 0x04, INSTR_RI_RU }, + { "nihl", 0x05, INSTR_RI_RU }, + { "nilh", 0x06, INSTR_RI_RU }, + { "nill", 0x07, INSTR_RI_RU }, + { "oihh", 0x08, INSTR_RI_RU }, + { "oihl", 0x09, INSTR_RI_RU }, + { "oilh", 0x0a, INSTR_RI_RU }, + { "oill", 0x0b, INSTR_RI_RU }, + { "llihh", 0x0c, INSTR_RI_RU }, + { "llihl", 0x0d, INSTR_RI_RU }, + { "llilh", 0x0e, INSTR_RI_RU }, + { "llill", 0x0f, INSTR_RI_RU }, +#endif + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_a7[] = { +#ifdef CONFIG_64BIT + { "tmhh", 0x02, INSTR_RI_RU }, + { "tmhl", 0x03, INSTR_RI_RU }, + { "brctg", 0x07, INSTR_RI_RP }, + { "lghi", 0x09, INSTR_RI_RI }, + { "aghi", 0x0b, INSTR_RI_RI }, + { "mghi", 0x0d, INSTR_RI_RI }, + { "cghi", 0x0f, INSTR_RI_RI }, +#endif + { "tmlh", 0x00, INSTR_RI_RU }, + { "tmll", 0x01, INSTR_RI_RU }, + { "brc", 0x04, INSTR_RI_UP }, + { "bras", 0x05, INSTR_RI_RP }, + { "brct", 0x06, INSTR_RI_RP }, + { "lhi", 0x08, INSTR_RI_RI }, + { "ahi", 0x0a, INSTR_RI_RI }, + { "mhi", 0x0c, INSTR_RI_RI }, + { "chi", 0x0e, INSTR_RI_RI }, + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_b2[] = { +#ifdef CONFIG_64BIT + { "sske", 0x2b, INSTR_RRF_M0RR }, + { "stckf", 0x7c, INSTR_S_RD }, + { "cu21", 0xa6, INSTR_RRF_M0RR }, + { "cuutf", 0xa6, INSTR_RRF_M0RR }, + { "cu12", 0xa7, INSTR_RRF_M0RR }, + { "cutfu", 0xa7, INSTR_RRF_M0RR }, + { "stfle", 0xb0, INSTR_S_RD }, + { "lpswe", 0xb2, INSTR_S_RD }, +#endif + { "stidp", 0x02, INSTR_S_RD }, + { "sck", 0x04, INSTR_S_RD }, + { "stck", 0x05, INSTR_S_RD }, + { "sckc", 0x06, INSTR_S_RD }, + { "stckc", 0x07, INSTR_S_RD }, + { "spt", 0x08, INSTR_S_RD }, + { "stpt", 0x09, INSTR_S_RD }, + { "spka", 0x0a, INSTR_S_RD }, + { "ipk", 0x0b, INSTR_S_00 }, + { "ptlb", 0x0d, INSTR_S_00 }, + { "spx", 0x10, INSTR_S_RD }, + { "stpx", 0x11, INSTR_S_RD }, + { "stap", 0x12, INSTR_S_RD }, + { "sie", 0x14, INSTR_S_RD }, + { "pc", 0x18, INSTR_S_RD }, + { "sac", 0x19, INSTR_S_RD }, + { "cfc", 0x1a, INSTR_S_RD }, + { "ipte", 0x21, INSTR_RRE_RR }, + { "ipm", 0x22, INSTR_RRE_R0 }, + { "ivsk", 0x23, INSTR_RRE_RR }, + { "iac", 0x24, INSTR_RRE_R0 }, + { "ssar", 0x25, INSTR_RRE_R0 }, + { "epar", 0x26, INSTR_RRE_R0 }, + { "esar", 0x27, INSTR_RRE_R0 }, + { "pt", 0x28, INSTR_RRE_RR }, + { "iske", 0x29, INSTR_RRE_RR }, + { "rrbe", 0x2a, INSTR_RRE_RR }, + { "sske", 0x2b, INSTR_RRE_RR }, + { "tb", 0x2c, INSTR_RRE_0R }, + { "dxr", 0x2d, INSTR_RRE_F0 }, + { "pgin", 0x2e, INSTR_RRE_RR }, + { "pgout", 0x2f, INSTR_RRE_RR }, + { "csch", 0x30, INSTR_S_00 }, + { "hsch", 0x31, INSTR_S_00 }, + { "msch", 0x32, INSTR_S_RD }, + { "ssch", 0x33, INSTR_S_RD }, + { "stsch", 0x34, INSTR_S_RD }, + { "tsch", 0x35, INSTR_S_RD }, + { "tpi", 0x36, INSTR_S_RD }, + { "sal", 0x37, INSTR_S_00 }, + { "rsch", 0x38, INSTR_S_00 }, + { "stcrw", 0x39, INSTR_S_RD }, + { "stcps", 0x3a, INSTR_S_RD }, + { "rchp", 0x3b, INSTR_S_00 }, + { "schm", 0x3c, INSTR_S_00 }, + { "bakr", 0x40, INSTR_RRE_RR }, + { "cksm", 0x41, INSTR_RRE_RR }, + { "sqdr", 0x44, INSTR_RRE_F0 }, + { "sqer", 0x45, INSTR_RRE_F0 }, + { "stura", 0x46, INSTR_RRE_RR }, + { "msta", 0x47, INSTR_RRE_R0 }, + { "palb", 0x48, INSTR_RRE_00 }, + { "ereg", 0x49, INSTR_RRE_RR }, + { "esta", 0x4a, INSTR_RRE_RR }, + { "lura", 0x4b, INSTR_RRE_RR }, + { "tar", 0x4c, INSTR_RRE_AR }, + { "cpya", INSTR_RRE_AA }, + { "sar", 0x4e, INSTR_RRE_AR }, + { "ear", 0x4f, INSTR_RRE_RA }, + { "csp", 0x50, INSTR_RRE_RR }, + { "msr", 0x52, INSTR_RRE_RR }, + { "mvpg", 0x54, INSTR_RRE_RR }, + { "mvst", 0x55, INSTR_RRE_RR }, + { "cuse", 0x57, INSTR_RRE_RR }, + { "bsg", 0x58, INSTR_RRE_RR }, + { "bsa", 0x5a, INSTR_RRE_RR }, + { "clst", 0x5d, INSTR_RRE_RR }, + { "srst", 0x5e, INSTR_RRE_RR }, + { "cmpsc", 0x63, INSTR_RRE_RR }, + { "cmpsc", 0x63, INSTR_RRE_RR }, + { "siga", 0x74, INSTR_S_RD }, + { "xsch", 0x76, INSTR_S_00 }, + { "rp", 0x77, INSTR_S_RD }, + { "stcke", 0x78, INSTR_S_RD }, + { "sacf", 0x79, INSTR_S_RD }, + { "stsi", 0x7d, INSTR_S_RD }, + { "srnm", 0x99, INSTR_S_RD }, + { "stfpc", 0x9c, INSTR_S_RD }, + { "lfpc", 0x9d, INSTR_S_RD }, + { "tre", 0xa5, INSTR_RRE_RR }, + { "cuutf", 0xa6, INSTR_RRE_RR }, + { "cutfu", 0xa7, INSTR_RRE_RR }, + { "stfl", 0xb1, INSTR_S_RD }, + { "trap4", 0xff, INSTR_S_RD }, + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_b3[] = { +#ifdef CONFIG_64BIT + { "maylr", 0x38, INSTR_RRF_F0FF }, + { "mylr", 0x39, INSTR_RRF_F0FF }, + { "mayr", 0x3a, INSTR_RRF_F0FF }, + { "myr", 0x3b, INSTR_RRF_F0FF }, + { "mayhr", 0x3c, INSTR_RRF_F0FF }, + { "myhr", 0x3d, INSTR_RRF_F0FF }, + { "cegbr", 0xa4, INSTR_RRE_RR }, + { "cdgbr", 0xa5, INSTR_RRE_RR }, + { "cxgbr", 0xa6, INSTR_RRE_RR }, + { "cgebr", 0xa8, INSTR_RRF_U0RF }, + { "cgdbr", 0xa9, INSTR_RRF_U0RF }, + { "cgxbr", 0xaa, INSTR_RRF_U0RF }, + { "cfer", 0xb8, INSTR_RRF_U0RF }, + { "cfdr", 0xb9, INSTR_RRF_U0RF }, + { "cfxr", 0xba, INSTR_RRF_U0RF }, + { "cegr", 0xc4, INSTR_RRE_RR }, + { "cdgr", 0xc5, INSTR_RRE_RR }, + { "cxgr", 0xc6, INSTR_RRE_RR }, + { "cger", 0xc8, INSTR_RRF_U0RF }, + { "cgdr", 0xc9, INSTR_RRF_U0RF }, + { "cgxr", 0xca, INSTR_RRF_U0RF }, +#endif + { "lpebr", 0x00, INSTR_RRE_FF }, + { "lnebr", 0x01, INSTR_RRE_FF }, + { "ltebr", 0x02, INSTR_RRE_FF }, + { "lcebr", 0x03, INSTR_RRE_FF }, + { "ldebr", 0x04, INSTR_RRE_FF }, + { "lxdbr", 0x05, INSTR_RRE_FF }, + { "lxebr", 0x06, INSTR_RRE_FF }, + { "mxdbr", 0x07, INSTR_RRE_FF }, + { "kebr", 0x08, INSTR_RRE_FF }, + { "cebr", 0x09, INSTR_RRE_FF }, + { "aebr", 0x0a, INSTR_RRE_FF }, + { "sebr", 0x0b, INSTR_RRE_FF }, + { "mdebr", 0x0c, INSTR_RRE_FF }, + { "debr", 0x0d, INSTR_RRE_FF }, + { "maebr", 0x0e, INSTR_RRF_F0FF }, + { "msebr", 0x0f, INSTR_RRF_F0FF }, + { "lpdbr", 0x10, INSTR_RRE_FF }, + { "lndbr", 0x11, INSTR_RRE_FF }, + { "ltdbr", 0x12, INSTR_RRE_FF }, + { "lcdbr", 0x13, INSTR_RRE_FF }, + { "sqebr", 0x14, INSTR_RRE_FF }, + { "sqdbr", 0x15, INSTR_RRE_FF }, + { "sqxbr", 0x16, INSTR_RRE_FF }, + { "meebr", 0x17, INSTR_RRE_FF }, + { "kdbr", 0x18, INSTR_RRE_FF }, + { "cdbr", 0x19, INSTR_RRE_FF }, + { "adbr", 0x1a, INSTR_RRE_FF }, + { "sdbr", 0x1b, INSTR_RRE_FF }, + { "mdbr", 0x1c, INSTR_RRE_FF }, + { "ddbr", 0x1d, INSTR_RRE_FF }, + { "madbr", 0x1e, INSTR_RRF_F0FF }, + { "msdbr", 0x1f, INSTR_RRF_F0FF }, + { "lder", 0x24, INSTR_RRE_FF }, + { "lxdr", 0x25, INSTR_RRE_FF }, + { "lxer", 0x26, INSTR_RRE_FF }, + { "maer", 0x2e, INSTR_RRF_F0FF }, + { "mser", 0x2f, INSTR_RRF_F0FF }, + { "sqxr", 0x36, INSTR_RRE_FF }, + { "meer", 0x37, INSTR_RRE_FF }, + { "madr", 0x3e, INSTR_RRF_F0FF }, + { "msdr", 0x3f, INSTR_RRF_F0FF }, + { "lpxbr", 0x40, INSTR_RRE_FF }, + { "lnxbr", 0x41, INSTR_RRE_FF }, + { "ltxbr", 0x42, INSTR_RRE_FF }, + { "lcxbr", 0x43, INSTR_RRE_FF }, + { "ledbr", 0x44, INSTR_RRE_FF }, + { "ldxbr", 0x45, INSTR_RRE_FF }, + { "lexbr", 0x46, INSTR_RRE_FF }, + { "fixbr", 0x47, INSTR_RRF_U0FF }, + { "kxbr", 0x48, INSTR_RRE_FF }, + { "cxbr", 0x49, INSTR_RRE_FF }, + { "axbr", 0x4a, INSTR_RRE_FF }, + { "sxbr", 0x4b, INSTR_RRE_FF }, + { "mxbr", 0x4c, INSTR_RRE_FF }, + { "dxbr", 0x4d, INSTR_RRE_FF }, + { "tbedr", 0x50, INSTR_RRF_U0FF }, + { "tbdr", 0x51, INSTR_RRF_U0FF }, + { "diebr", 0x53, INSTR_RRF_FUFF }, + { "fiebr", 0x57, INSTR_RRF_U0FF }, + { "thder", 0x58, INSTR_RRE_RR }, + { "thdr", 0x59, INSTR_RRE_RR }, + { "didbr", 0x5b, INSTR_RRF_FUFF }, + { "fidbr", 0x5f, INSTR_RRF_U0FF }, + { "lpxr", 0x60, INSTR_RRE_FF }, + { "lnxr", 0x61, INSTR_RRE_FF }, + { "ltxr", 0x62, INSTR_RRE_FF }, + { "lcxr", 0x63, INSTR_RRE_FF }, + { "lxr", 0x65, INSTR_RRE_RR }, + { "lexr", 0x66, INSTR_RRE_FF }, + { "fixr", 0x67, INSTR_RRF_U0FF }, + { "cxr", 0x69, INSTR_RRE_FF }, + { "lzer", 0x74, INSTR_RRE_R0 }, + { "lzdr", 0x75, INSTR_RRE_R0 }, + { "lzxr", 0x76, INSTR_RRE_R0 }, + { "fier", 0x77, INSTR_RRF_U0FF }, + { "fidr", 0x7f, INSTR_RRF_U0FF }, + { "sfpc", 0x84, INSTR_RRE_RR_OPT }, + { "efpc", 0x8c, INSTR_RRE_RR_OPT }, + { "cefbr", 0x94, INSTR_RRE_RF }, + { "cdfbr", 0x95, INSTR_RRE_RF }, + { "cxfbr", 0x96, INSTR_RRE_RF }, + { "cfebr", 0x98, INSTR_RRF_U0RF }, + { "cfdbr", 0x99, INSTR_RRF_U0RF }, + { "cfxbr", 0x9a, INSTR_RRF_U0RF }, + { "cefr", 0xb4, INSTR_RRE_RF }, + { "cdfr", 0xb5, INSTR_RRE_RF }, + { "cxfr", 0xb6, INSTR_RRE_RF }, + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_b9[] = { +#ifdef CONFIG_64BIT + { "lpgr", 0x00, INSTR_RRE_RR }, + { "lngr", 0x01, INSTR_RRE_RR }, + { "ltgr", 0x02, INSTR_RRE_RR }, + { "lcgr", 0x03, INSTR_RRE_RR }, + { "lgr", 0x04, INSTR_RRE_RR }, + { "lurag", 0x05, INSTR_RRE_RR }, + { "lgbr", 0x06, INSTR_RRE_RR }, + { "lghr", 0x07, INSTR_RRE_RR }, + { "agr", 0x08, INSTR_RRE_RR }, + { "sgr", 0x09, INSTR_RRE_RR }, + { "algr", 0x0a, INSTR_RRE_RR }, + { "slgr", 0x0b, INSTR_RRE_RR }, + { "msgr", 0x0c, INSTR_RRE_RR }, + { "dsgr", 0x0d, INSTR_RRE_RR }, + { "eregg", 0x0e, INSTR_RRE_RR }, + { "lrvgr", 0x0f, INSTR_RRE_RR }, + { "lpgfr", 0x10, INSTR_RRE_RR }, + { "lngfr", 0x11, INSTR_RRE_RR }, + { "ltgfr", 0x12, INSTR_RRE_RR }, + { "lcgfr", 0x13, INSTR_RRE_RR }, + { "lgfr", 0x14, INSTR_RRE_RR }, + { "llgfr", 0x16, INSTR_RRE_RR }, + { "llgtr", 0x17, INSTR_RRE_RR }, + { "agfr", 0x18, INSTR_RRE_RR }, + { "sgfr", 0x19, INSTR_RRE_RR }, + { "algfr", 0x1a, INSTR_RRE_RR }, + { "slgfr", 0x1b, INSTR_RRE_RR }, + { "msgfr", 0x1c, INSTR_RRE_RR }, + { "dsgfr", 0x1d, INSTR_RRE_RR }, + { "cgr", 0x20, INSTR_RRE_RR }, + { "clgr", 0x21, INSTR_RRE_RR }, + { "sturg", 0x25, INSTR_RRE_RR }, + { "lbr", 0x26, INSTR_RRE_RR }, + { "lhr", 0x27, INSTR_RRE_RR }, + { "cgfr", 0x30, INSTR_RRE_RR }, + { "clgfr", 0x31, INSTR_RRE_RR }, + { "bctgr", 0x46, INSTR_RRE_RR }, + { "ngr", 0x80, INSTR_RRE_RR }, + { "ogr", 0x81, INSTR_RRE_RR }, + { "xgr", 0x82, INSTR_RRE_RR }, + { "flogr", 0x83, INSTR_RRE_RR }, + { "llgcr", 0x84, INSTR_RRE_RR }, + { "llghr", 0x85, INSTR_RRE_RR }, + { "mlgr", 0x86, INSTR_RRE_RR }, + { "dlgr", 0x87, INSTR_RRE_RR }, + { "alcgr", 0x88, INSTR_RRE_RR }, + { "slbgr", 0x89, INSTR_RRE_RR }, + { "cspg", 0x8a, INSTR_RRE_RR }, + { "idte", 0x8e, INSTR_RRF_R0RR }, + { "llcr", 0x94, INSTR_RRE_RR }, + { "llhr", 0x95, INSTR_RRE_RR }, + { "esea", 0x9d, INSTR_RRE_R0 }, + { "lptea", 0xaa, INSTR_RRF_RURR }, + { "cu14", 0xb0, INSTR_RRF_M0RR }, + { "cu24", 0xb1, INSTR_RRF_M0RR }, + { "cu41", 0xb2, INSTR_RRF_M0RR }, + { "cu42", 0xb3, INSTR_RRF_M0RR }, +#endif + { "kmac", 0x1e, INSTR_RRE_RR }, + { "lrvr", 0x1f, INSTR_RRE_RR }, + { "km", 0x2e, INSTR_RRE_RR }, + { "kmc", 0x2f, INSTR_RRE_RR }, + { "kimd", 0x3e, INSTR_RRE_RR }, + { "klmd", 0x3f, INSTR_RRE_RR }, + { "epsw", 0x8d, INSTR_RRE_RR }, + { "trtt", 0x90, INSTR_RRE_RR }, + { "trtt", 0x90, INSTR_RRF_M0RR }, + { "trto", 0x91, INSTR_RRE_RR }, + { "trto", 0x91, INSTR_RRF_M0RR }, + { "trot", 0x92, INSTR_RRE_RR }, + { "trot", 0x92, INSTR_RRF_M0RR }, + { "troo", 0x93, INSTR_RRE_RR }, + { "troo", 0x93, INSTR_RRF_M0RR }, + { "mlr", 0x96, INSTR_RRE_RR }, + { "dlr", 0x97, INSTR_RRE_RR }, + { "alcr", 0x98, INSTR_RRE_RR }, + { "slbr", 0x99, INSTR_RRE_RR }, + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_c0[] = { +#ifdef CONFIG_64BIT + { "lgfi", 0x01, INSTR_RIL_RI }, + { "xihf", 0x06, INSTR_RIL_RU }, + { "xilf", 0x07, INSTR_RIL_RU }, + { "iihf", 0x08, INSTR_RIL_RU }, + { "iilf", 0x09, INSTR_RIL_RU }, + { "nihf", 0x0a, INSTR_RIL_RU }, + { "nilf", 0x0b, INSTR_RIL_RU }, + { "oihf", 0x0c, INSTR_RIL_RU }, + { "oilf", 0x0d, INSTR_RIL_RU }, + { "llihf", 0x0e, INSTR_RIL_RU }, + { "llilf", 0x0f, INSTR_RIL_RU }, +#endif + { "larl", 0x00, INSTR_RIL_RP }, + { "brcl", 0x04, INSTR_RIL_UP }, + { "brasl", 0x05, INSTR_RIL_RP }, + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_c2[] = { +#ifdef CONFIG_64BIT + { "slgfi", 0x04, INSTR_RIL_RU }, + { "slfi", 0x05, INSTR_RIL_RU }, + { "agfi", 0x08, INSTR_RIL_RI }, + { "afi", 0x09, INSTR_RIL_RI }, + { "algfi", 0x0a, INSTR_RIL_RU }, + { "alfi", 0x0b, INSTR_RIL_RU }, + { "cgfi", 0x0c, INSTR_RIL_RI }, + { "cfi", 0x0d, INSTR_RIL_RI }, + { "clgfi", 0x0e, INSTR_RIL_RU }, + { "clfi", 0x0f, INSTR_RIL_RU }, +#endif + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_c8[] = { +#ifdef CONFIG_64BIT + { "mvcos", 0x00, INSTR_SSF_RRDRD }, +#endif + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_e3[] = { +#ifdef CONFIG_64BIT + { "ltg", 0x02, INSTR_RXY_RRRD }, + { "lrag", 0x03, INSTR_RXY_RRRD }, + { "lg", 0x04, INSTR_RXY_RRRD }, + { "cvby", 0x06, INSTR_RXY_RRRD }, + { "ag", 0x08, INSTR_RXY_RRRD }, + { "sg", 0x09, INSTR_RXY_RRRD }, + { "alg", 0x0a, INSTR_RXY_RRRD }, + { "slg", 0x0b, INSTR_RXY_RRRD }, + { "msg", 0x0c, INSTR_RXY_RRRD }, + { "dsg", 0x0d, INSTR_RXY_RRRD }, + { "cvbg", 0x0e, INSTR_RXY_RRRD }, + { "lrvg", 0x0f, INSTR_RXY_RRRD }, + { "lt", 0x12, INSTR_RXY_RRRD }, + { "lray", 0x13, INSTR_RXY_RRRD }, + { "lgf", 0x14, INSTR_RXY_RRRD }, + { "lgh", 0x15, INSTR_RXY_RRRD }, + { "llgf", 0x16, INSTR_RXY_RRRD }, + { "llgt", 0x17, INSTR_RXY_RRRD }, + { "agf", 0x18, INSTR_RXY_RRRD }, + { "sgf", 0x19, INSTR_RXY_RRRD }, + { "algf", 0x1a, INSTR_RXY_RRRD }, + { "slgf", 0x1b, INSTR_RXY_RRRD }, + { "msgf", 0x1c, INSTR_RXY_RRRD }, + { "dsgf", 0x1d, INSTR_RXY_RRRD }, + { "cg", 0x20, INSTR_RXY_RRRD }, + { "clg", 0x21, INSTR_RXY_RRRD }, + { "stg", 0x24, INSTR_RXY_RRRD }, + { "cvdy", 0x26, INSTR_RXY_RRRD }, + { "cvdg", 0x2e, INSTR_RXY_RRRD }, + { "strvg", 0x2f, INSTR_RXY_RRRD }, + { "cgf", 0x30, INSTR_RXY_RRRD }, + { "clgf", 0x31, INSTR_RXY_RRRD }, + { "strvh", 0x3f, INSTR_RXY_RRRD }, + { "bctg", 0x46, INSTR_RXY_RRRD }, + { "sty", 0x50, INSTR_RXY_RRRD }, + { "msy", 0x51, INSTR_RXY_RRRD }, + { "ny", 0x54, INSTR_RXY_RRRD }, + { "cly", 0x55, INSTR_RXY_RRRD }, + { "oy", 0x56, INSTR_RXY_RRRD }, + { "xy", 0x57, INSTR_RXY_RRRD }, + { "ly", 0x58, INSTR_RXY_RRRD }, + { "cy", 0x59, INSTR_RXY_RRRD }, + { "ay", 0x5a, INSTR_RXY_RRRD }, + { "sy", 0x5b, INSTR_RXY_RRRD }, + { "aly", 0x5e, INSTR_RXY_RRRD }, + { "sly", 0x5f, INSTR_RXY_RRRD }, + { "sthy", 0x70, INSTR_RXY_RRRD }, + { "lay", 0x71, INSTR_RXY_RRRD }, + { "stcy", 0x72, INSTR_RXY_RRRD }, + { "icy", 0x73, INSTR_RXY_RRRD }, + { "lb", 0x76, INSTR_RXY_RRRD }, + { "lgb", 0x77, INSTR_RXY_RRRD }, + { "lhy", 0x78, INSTR_RXY_RRRD }, + { "chy", 0x79, INSTR_RXY_RRRD }, + { "ahy", 0x7a, INSTR_RXY_RRRD }, + { "shy", 0x7b, INSTR_RXY_RRRD }, + { "ng", 0x80, INSTR_RXY_RRRD }, + { "og", 0x81, INSTR_RXY_RRRD }, + { "xg", 0x82, INSTR_RXY_RRRD }, + { "mlg", 0x86, INSTR_RXY_RRRD }, + { "dlg", 0x87, INSTR_RXY_RRRD }, + { "alcg", 0x88, INSTR_RXY_RRRD }, + { "slbg", 0x89, INSTR_RXY_RRRD }, + { "stpq", 0x8e, INSTR_RXY_RRRD }, + { "lpq", 0x8f, INSTR_RXY_RRRD }, + { "llgc", 0x90, INSTR_RXY_RRRD }, + { "llgh", 0x91, INSTR_RXY_RRRD }, + { "llc", 0x94, INSTR_RXY_RRRD }, + { "llh", 0x95, INSTR_RXY_RRRD }, +#endif + { "lrv", 0x1e, INSTR_RXY_RRRD }, + { "lrvh", 0x1f, INSTR_RXY_RRRD }, + { "strv", 0x3e, INSTR_RXY_RRRD }, + { "ml", 0x96, INSTR_RXY_RRRD }, + { "dl", 0x97, INSTR_RXY_RRRD }, + { "alc", 0x98, INSTR_RXY_RRRD }, + { "slb", 0x99, INSTR_RXY_RRRD }, + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_e5[] = { +#ifdef CONFIG_64BIT + { "strag", 0x02, INSTR_SSE_RDRD }, +#endif + { "lasp", 0x00, INSTR_SSE_RDRD }, + { "tprot", 0x01, INSTR_SSE_RDRD }, + { "mvcsk", 0x0e, INSTR_SSE_RDRD }, + { "mvcdk", 0x0f, INSTR_SSE_RDRD }, + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_eb[] = { +#ifdef CONFIG_64BIT + { "lmg", 0x04, INSTR_RSY_RRRD }, + { "srag", 0x0a, INSTR_RSY_RRRD }, + { "slag", 0x0b, INSTR_RSY_RRRD }, + { "srlg", 0x0c, INSTR_RSY_RRRD }, + { "sllg", 0x0d, INSTR_RSY_RRRD }, + { "tracg", 0x0f, INSTR_RSY_RRRD }, + { "csy", 0x14, INSTR_RSY_RRRD }, + { "rllg", 0x1c, INSTR_RSY_RRRD }, + { "clmh", 0x20, INSTR_RSY_RURD }, + { "clmy", 0x21, INSTR_RSY_RURD }, + { "stmg", 0x24, INSTR_RSY_RRRD }, + { "stctg", 0x25, INSTR_RSY_CCRD }, + { "stmh", 0x26, INSTR_RSY_RRRD }, + { "stcmh", 0x2c, INSTR_RSY_RURD }, + { "stcmy", 0x2d, INSTR_RSY_RURD }, + { "lctlg", 0x2f, INSTR_RSY_CCRD }, + { "csg", 0x30, INSTR_RSY_RRRD }, + { "cdsy", 0x31, INSTR_RSY_RRRD }, + { "cdsg", 0x3e, INSTR_RSY_RRRD }, + { "bxhg", 0x44, INSTR_RSY_RRRD }, + { "bxleg", 0x45, INSTR_RSY_RRRD }, + { "tmy", 0x51, INSTR_SIY_URD }, + { "mviy", 0x52, INSTR_SIY_URD }, + { "niy", 0x54, INSTR_SIY_URD }, + { "cliy", 0x55, INSTR_SIY_URD }, + { "oiy", 0x56, INSTR_SIY_URD }, + { "xiy", 0x57, INSTR_SIY_URD }, + { "icmh", 0x80, INSTR_RSE_RURD }, + { "icmh", 0x80, INSTR_RSY_RURD }, + { "icmy", 0x81, INSTR_RSY_RURD }, + { "clclu", 0x8f, INSTR_RSY_RRRD }, + { "stmy", 0x90, INSTR_RSY_RRRD }, + { "lmh", 0x96, INSTR_RSY_RRRD }, + { "lmy", 0x98, INSTR_RSY_RRRD }, + { "lamy", 0x9a, INSTR_RSY_AARD }, + { "stamy", 0x9b, INSTR_RSY_AARD }, +#endif + { "rll", 0x1d, INSTR_RSY_RRRD }, + { "mvclu", 0x8e, INSTR_RSY_RRRD }, + { "tp", 0xc0, INSTR_RSL_R0RD }, + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_ec[] = { +#ifdef CONFIG_64BIT + { "brxhg", 0x44, INSTR_RIE_RRP }, + { "brxlg", 0x45, INSTR_RIE_RRP }, +#endif + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_ed[] = { +#ifdef CONFIG_64BIT + { "mayl", 0x38, INSTR_RXF_FRRDF }, + { "myl", 0x39, INSTR_RXF_FRRDF }, + { "may", 0x3a, INSTR_RXF_FRRDF }, + { "my", 0x3b, INSTR_RXF_FRRDF }, + { "mayh", 0x3c, INSTR_RXF_FRRDF }, + { "myh", 0x3d, INSTR_RXF_FRRDF }, + { "ley", 0x64, INSTR_RXY_FRRD }, + { "ldy", 0x65, INSTR_RXY_FRRD }, + { "stey", 0x66, INSTR_RXY_FRRD }, + { "stdy", 0x67, INSTR_RXY_FRRD }, +#endif + { "ldeb", 0x04, INSTR_RXE_FRRD }, + { "lxdb", 0x05, INSTR_RXE_FRRD }, + { "lxeb", 0x06, INSTR_RXE_FRRD }, + { "mxdb", 0x07, INSTR_RXE_FRRD }, + { "keb", 0x08, INSTR_RXE_FRRD }, + { "ceb", 0x09, INSTR_RXE_FRRD }, + { "aeb", 0x0a, INSTR_RXE_FRRD }, + { "seb", 0x0b, INSTR_RXE_FRRD }, + { "mdeb", 0x0c, INSTR_RXE_FRRD }, + { "deb", 0x0d, INSTR_RXE_FRRD }, + { "maeb", 0x0e, INSTR_RXF_FRRDF }, + { "mseb", 0x0f, INSTR_RXF_FRRDF }, + { "tceb", 0x10, INSTR_RXE_FRRD }, + { "tcdb", 0x11, INSTR_RXE_FRRD }, + { "tcxb", 0x12, INSTR_RXE_FRRD }, + { "sqeb", 0x14, INSTR_RXE_FRRD }, + { "sqdb", 0x15, INSTR_RXE_FRRD }, + { "meeb", 0x17, INSTR_RXE_FRRD }, + { "kdb", 0x18, INSTR_RXE_FRRD }, + { "cdb", 0x19, INSTR_RXE_FRRD }, + { "adb", 0x1a, INSTR_RXE_FRRD }, + { "sdb", 0x1b, INSTR_RXE_FRRD }, + { "mdb", 0x1c, INSTR_RXE_FRRD }, + { "ddb", 0x1d, INSTR_RXE_FRRD }, + { "madb", 0x1e, INSTR_RXF_FRRDF }, + { "msdb", 0x1f, INSTR_RXF_FRRDF }, + { "lde", 0x24, INSTR_RXE_FRRD }, + { "lxd", 0x25, INSTR_RXE_FRRD }, + { "lxe", 0x26, INSTR_RXE_FRRD }, + { "mae", 0x2e, INSTR_RXF_FRRDF }, + { "mse", 0x2f, INSTR_RXF_FRRDF }, + { "sqe", 0x34, INSTR_RXE_FRRD }, + { "mee", 0x37, INSTR_RXE_FRRD }, + { "mad", 0x3e, INSTR_RXF_FRRDF }, + { "msd", 0x3f, INSTR_RXF_FRRDF }, + { "", 0, INSTR_INVALID } +}; + +/* Extracts an operand value from an instruction. */ +static unsigned int extract_operand(unsigned char *code, + const struct operand *operand) +{ + unsigned int val; + int bits; + + /* Extract fragments of the operand byte for byte. */ + code += operand->shift / 8; + bits = (operand->shift & 7) + operand->bits; + val = 0; + do { + val <<= 8; + val |= (unsigned int) *code++; + bits -= 8; + } while (bits > 0); + val >>= -bits; + val &= ((1U << (operand->bits - 1)) << 1) - 1; + + /* Check for special long displacement case. */ + if (operand->bits == 20 && operand->shift == 20) + val = (val & 0xff) << 12 | (val & 0xfff00) >> 8; + + /* Sign extend value if the operand is signed or pc relative. */ + if ((operand->flags & (OPERAND_SIGNED | OPERAND_PCREL)) && + (val & (1U << (operand->bits - 1)))) + val |= (-1U << (operand->bits - 1)) << 1; + + /* Double value if the operand is pc relative. */ + if (operand->flags & OPERAND_PCREL) + val <<= 1; + + /* Length x in an instructions has real length x + 1. */ + if (operand->flags & OPERAND_LENGTH) + val++; + return val; +} + +static inline int insn_length(unsigned char code) +{ + return ((((int) code + 64) >> 7) + 1) << 1; +} + +static struct insn *find_insn(unsigned char *code) +{ + unsigned char opfrag = code[1]; + unsigned char opmask; + struct insn *table; + + switch (code[0]) { + case 0x01: + table = opcode_01; + break; + case 0xa5: + table = opcode_a5; + break; + case 0xa7: + table = opcode_a7; + break; + case 0xb2: + table = opcode_b2; + break; + case 0xb3: + table = opcode_b3; + break; + case 0xb9: + table = opcode_b9; + break; + case 0xc0: + table = opcode_c0; + break; + case 0xc2: + table = opcode_c2; + break; + case 0xc8: + table = opcode_c8; + break; + case 0xe3: + table = opcode_e3; + opfrag = code[5]; + break; + case 0xe5: + table = opcode_e5; + break; + case 0xeb: + table = opcode_eb; + opfrag = code[5]; + break; + case 0xec: + table = opcode_ec; + opfrag = code[5]; + break; + case 0xed: + table = opcode_ed; + opfrag = code[5]; + break; + default: + table = opcode; + opfrag = code[0]; + break; + } + while (table->format != INSTR_INVALID) { + opmask = formats[table->format][0]; + if (table->opfrag == (opfrag & opmask)) + return table; + table++; + } + return NULL; +} + +static int print_insn(char *buffer, unsigned char *code, unsigned long addr) +{ + struct insn *insn; + const unsigned char *ops; + const struct operand *operand; + unsigned int value; + char separator; + char *ptr; + + ptr = buffer; + insn = find_insn(code); + if (insn) { + ptr += sprintf(ptr, "%.5s\t", insn->name); + /* Extract the operands. */ + separator = 0; + for (ops = formats[insn->format] + 1; *ops != 0; ops++) { + operand = operands + *ops; + value = extract_operand(code, operand); + if ((operand->flags & OPERAND_INDEX) && value == 0) + continue; + if ((operand->flags & OPERAND_BASE) && + value == 0 && separator == '(') { + separator = ','; + continue; + } + if (separator) + ptr += sprintf(ptr, "%c", separator); + if (operand->flags & OPERAND_GPR) + ptr += sprintf(ptr, "%%r%i", value); + else if (operand->flags & OPERAND_FPR) + ptr += sprintf(ptr, "%%f%i", value); + else if (operand->flags & OPERAND_AR) + ptr += sprintf(ptr, "%%a%i", value); + else if (operand->flags & OPERAND_CR) + ptr += sprintf(ptr, "%%c%i", value); + else if (operand->flags & OPERAND_PCREL) + ptr += sprintf(ptr, "%lx", value + addr); + else if (operand->flags & OPERAND_SIGNED) + ptr += sprintf(ptr, "%i", value); + else + ptr += sprintf(ptr, "%u", value); + if (operand->flags & OPERAND_DISP) + separator = '('; + else if (operand->flags & OPERAND_BASE) { + ptr += sprintf(ptr, ")"); + separator = ','; + } else + separator = ','; + } + } else + ptr += sprintf(ptr, "unknown"); + return (int) (ptr - buffer); +} + +void show_code(struct pt_regs *regs) +{ + char *mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl"; + unsigned char code[64]; + char buffer[64], *ptr; + mm_segment_t old_fs; + unsigned long addr; + int start, end, opsize, hops, i; + + /* Get a snapshot of the 64 bytes surrounding the fault address. */ + old_fs = get_fs(); + set_fs((regs->psw.mask & PSW_MASK_PSTATE) ? USER_DS : KERNEL_DS); + for (start = 32; start && regs->psw.addr >= 34 - start; start -= 2) { + addr = regs->psw.addr - 34 + start; + if (__copy_from_user(code + start - 2, + (char __user *) addr, 2)) + break; + } + for (end = 32; end < 64; end += 2) { + addr = regs->psw.addr + end - 32; + if (__copy_from_user(code + end, + (char __user *) addr, 2)) + break; + } + set_fs(old_fs); + /* Code snapshot useable ? */ + if ((regs->psw.addr & 1) || start >= end) { + printk("%s Code: Bad PSW.\n", mode); + return; + } + /* Find a starting point for the disassembly. */ + while (start < 32) { + hops = 0; + for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) { + if (!find_insn(code + start + i)) + break; + i += insn_length(code[start + i]); + } + if (start + i == 32) + /* Looks good, sequence ends at PSW. */ + break; + start += 2; + } + /* Decode the instructions. */ + ptr = buffer; + ptr += sprintf(ptr, "%s Code:", mode); + hops = 0; + while (start < end && hops < 8) { + *ptr++ = (start == 32) ? '>' : ' '; + addr = regs->psw.addr + start - 32; + ptr += sprintf(ptr, ONELONG, addr); + opsize = insn_length(code[start]); + if (start + opsize >= end) + break; + for (i = 0; i < opsize; i++) + ptr += sprintf(ptr, "%02x", code[start + i]); + *ptr++ = '\t'; + if (i < 6) + *ptr++ = '\t'; + ptr += print_insn(ptr, code + start, addr); + start += opsize; + printk(buffer); + ptr = buffer; + ptr += sprintf(ptr, "\n "); + hops++; + } + printk("\n"); +}
arch/s390/kernel/Makefile +1 -1
@@ -6,7 +6,7 @@ obj-y := bitmap.o traps.o time.o process.o base.o early.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390_ext.o debug.o irq.o ipl.o + semaphore.o s390_ext.o debug.o irq.o ipl.o dis.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
arch/s390/kernel/traps.c +17 -38
76 lines not on this page · raw message
include/asm-s390/processor.h +1 -0
@@ -196,6 +196,7 @@extern char *task_show_regs (struct task_struct *task,char *buffer);extern void show_registers (struct pt_regs *regs); +extern void show_code (struct pt_regs *regs);extern void show_trace (struct task_struct *task,unsigned long *sp);unsigned long get_wchan (struct task_struct *p);
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
Re: [patch 18/38] Improved oops output.
Quoted 6 lines · Martin Schwidefsky
From: Martin Schwidefsky <[email protected]>
This patch adds two improvements to the oops output. First it adds an additional line after the PSW which decodes the different fields of it. Second a disassembler is added that decodes the instructions surrounding the faulting PSW. The output of a test oops now looks like this:
So we're growing in-kernel disassemblers now? :)
I wonder whether this is really worth it, but at least your handwritten one is much nicer than the copy & paste from gdb in the kdb patches.
Re: [patch 18/38] Improved oops output.
Quoted 8 lines · Christoph Hellwig
Quoted 6 lines · Martin Schwidefsky
From: Martin Schwidefsky <[email protected]>
This patch adds two improvements to the oops output. First it adds an additional line after the PSW which decodes the different fields of it. Second a disassembler is added that decodes the instructions surrounding the faulting PSW. The output of a test oops now looks like this:
Quoted 4 lines
So we're growing in-kernel disassemblers now? :)
I wonder whether this is really worth it, but at least your handwritten one is much nicer than the copy & paste from gdb in the kdb patches.
The disassembler uses about 8K of memory and it really helps in debugging. For me it is worth the cost.
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
Re: [patch 18/38] Improved oops output.
Quoted 8 lines · Martin Schwidefsky
Quoted 4 lines
So we're growing in-kernel disassemblers now? :)
I wonder whether this is really worth it, but at least your handwritten one is much nicer than the copy & paste from gdb in the kdb patches.
The disassembler uses about 8K of memory and it really helps in debugging. For me it is worth the cost.
No ksymoops for your architecture?
Re: [patch 18/38] Improved oops output.
Quoted 11 lines · Chuck Ebbert
Quoted 8 lines · Martin Schwidefsky
Quoted 4 lines
So we're growing in-kernel disassemblers now? :)
I wonder whether this is really worth it, but at least your handwritten one is much nicer than the copy & paste from gdb in the kdb patches.
The disassembler uses about 8K of memory and it really helps in debugging. For me it is worth the cost.
No ksymoops for your architecture?
There is ksymoops for s390 and it should be able to disassemble the code as well. But you need all sorts of files to feed into ksymoops to get something out of it. At least I often get bug reports with the console output attached and it simply saves time if I can see the disassembly without an extra step.
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
Re: [patch 18/38] Improved oops output.
Quoted 8 lines · Martin Schwidefsky
Quoted 1 line
No ksymoops for your architecture?
There is ksymoops for s390 and it should be able to disassemble the code as well. But you need all sorts of files to feed into ksymoops to get something out of it. At least I often get bug reports with the console output attached and it simply saves time if I can see the disassembly without an extra step.
The only file you need on i386 is the oops itself. ksymoops will scream about missing files but will still work for disassembly.
Re: [patch 18/38] Improved oops output.
In reply to Martin SchwidefskyQuoted 2 lines · Martin Schwidefsky
Second a disassembler is added that decodes the instructions surrounding the faulting PSW.
Is that really needed? I use a simple wrapper around as/objdump for this and it works great.
(ftp://ftp.firstfloor.org/pub/ak/shell/decodecode)
-Andi
Re: [patch 18/38] Improved oops output.
Quoted 9 lines · Andi Kleen
Quoted 2 lines · Martin Schwidefsky
Second a disassembler is added that decodes the instructions surrounding the faulting PSW.
Is that really needed? I use a simple wrapper around as/objdump for this and it works great.
(ftp://ftp.firstfloor.org/pub/ak/shell/decodecode)
It is not absolutly needed but it is damn convenient. Usually I can immediatly see the reason for the oops. And the size is only 8KB which is next to nothing.
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
Re: [patch 18/38] Improved oops output.
Quoted 5 lines · Martin Schwidefsky
Quoted 4 lines · Andi Kleen
Quoted 2 lines · Martin Schwidefsky
Second a disassembler is added that decodes the instructions surrounding the faulting PSW.
Quoted 9 lines
Quoted 4 lines
Is that really needed? I use a simple wrapper around as/objdump for this and it works great.
(ftp://ftp.firstfloor.org/pub/ak/shell/decodecode)
It is not absolutly needed but it is damn convenient. Usually I can immediatly see the reason for the oops. And the size is only 8KB which is next to nothing.
Yeah, well your instruction set is really simple anyway. :)
I wonder how big the x86 disassembler is...
PATCH 19/38 Use generic bug.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
Generic bug implementation for s390. Will increase the value of the console output on BUG() statements since registers r0-r5,r14 will not be clobbered by a printk() call that was previously done before the illegal instruction of BUG() was hit.
Also implements an architecture specific WARN_ON(). Output of that could be increased but requires common code change.
---
arch/s390/Kconfig | 5 ++ arch/s390/defconfig | 2 + arch/s390/kernel/module.c | 4 +- arch/s390/kernel/traps.c | 17 ++++++++-- arch/s390/kernel/vmlinux.lds.S | 10 +++++ include/asm-s390/bug.h | 69 +++++++++++++++++++++++++++++++++-------- 6 files changed, 89 insertions(+), 18 deletions(-)
arch/s390/defconfig +2 -0
@@ -12,6 +12,7 @@ # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_BUG=y CONFIG_NO_IOMEM=y CONFIG_S390=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -705,6 +706,7 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_VM is not set # CONFIG_DEBUG_LIST is not set
arch/s390/Kconfig +5 -0
@@ -41,6 +41,11 @@ config GENERIC_TIME def_bool y +config GENERIC_BUG + bool + depends on BUG + default y + config NO_IOMEM def_bool y
arch/s390/kernel/module.c +3 -1
@@ -31,6 +31,7 @@#include <linux/string.h> #include <linux/kernel.h> #include <linux/moduleloader.h> +#include <linux/bug.h> #if 0 #define DEBUGP printk
@@ -398,9 +399,10 @@ struct module *me) {vfree (me->arch.syminfo); -return 0 ; +return module_bug_finalize (hdr, sechdrs, me); }void module_arch_cleanup (struct module *mod) { +module_bug_cleanup (mod); }
arch/s390/kernel/traps.c +14 -3
@@ -30,7 +30,7 @@#include <linux/kallsyms.h> #include <linux/reboot.h> #include <linux/kprobes.h> - +#include <linux/bug.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/io.h>
@@ -297,6 +297,11 @@#endif } +int is_valid_bugaddr (unsigned long addr) +{ +return 1 ; +} +static void __kprobes inline do_trap (long interruption_code,int signr,char *str,struct pt_regs *regs,siginfo_t *info)
@@ -323,8 +328,14 @@ fixup =search_exception_tables (regs->psw.addr &PSW_ADDR_INSN );if (fixup) regs->psw.addr = fixup->fixup |PSW_ADDR_AMODE ; -else -die (str, regs, interruption_code); +else { +enum bug_trap_type btt; + + btt =report_bug (regs->psw.addr &PSW_ADDR_INSN ); +if (btt ==BUG_TRAP_TYPE_WARN ) +return ; +die (str, regs, interruption_code); + } } }
arch/s390/kernel/vmlinux.lds.S +9 -1
@@ -45,6 +45,8 @@ __ex_table : { *(__ex_table) } __stop___ex_table = .; + BUG_TABLE + .data : { /* Data */ *(.data) CONSTRUCTORS
@@ -77,6 +79,12 @@ *(.init.text) _einittext = .; } + /* + * .exit.text is discarded at runtime, not link time, + * to deal with references from __bug_table + */ + .exit.text : { *(.exit.text) } + .init.data : { *(.init.data) } . = ALIGN(256); __setup_start = .;
@@ -116,7 +124,7 @@ /* Sections to be discarded */ /DISCARD/ : { - *(.exit.text) *(.exit.data) *(.exitcall.exit) + *(.exit.data) *(.exitcall.exit) } /* Stabs debugging sections. */
include/asm-s390/bug.h +56 -13
83 lines not on this page · raw message
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 20/38 Minor fault path optimization.
In reply to Martin SchwidefskyFrom: Martin Schwidefsky <[email protected]>
The minor fault path has grown a lot in terms of cycles. In particular the kprobes hook is very costly. Optimize the path to save a couple of cycles. If kprobes is enabled more than 300 cycles can be avoided if kprobes_running() is false.
---
arch/s390/mm/fault.c | 259 +++++++++++++++++++++++++++------------------------ 1 files changed, 141 insertions(+), 118 deletions(-)
arch/s390/mm/fault.c +141 -118
@@ -63,21 +63,25 @@ return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); } -static inline int notify_page_fault (enum die_val val,const char *str, -struct pt_regs *regs,long err,int trap,int sig) +static int __kprobes __notify_page_fault (struct pt_regs *regs,long err) { -struct die_args args = { - .regs = regs, - .str = str, - .err = err, - .trapnr = trap, - .signr = sig - }; -return atomic_notifier_call_chain (¬ify_page_fault_chain, val, &args); +struct die_args args = { .str ="page fault" , + .trapnr =14 , + .signr =SIGSEGV }; + args.regs = regs; + args.err = err; +return atomic_notifier_call_chain (¬ify_page_fault_chain, +DIE_PAGE_FAULT , &args); +} + +static inline int notify_page_fault (struct pt_regs *regs,long err) +{ +if (unlikely (kprobe_running ())) +return __notify_page_fault (regs, err); +return NOTIFY_DONE ; }#else -static inline int notify_page_fault (enum die_val val,const char *str, -struct pt_regs *regs,long err,int trap,int sig) +static inline int notify_page_fault (struct pt_regs *regs,long err) {return NOTIFY_DONE ; }
@@ -170,6 +174,89 @@force_sig_info (SIGSEGV , &si, current); } +static void do_no_context (struct pt_regs *regs,unsigned long error_code, +unsigned long address) +{ +const struct exception_table_entry *fixup; + +/* Are we prepared to handle this kernel fault? */ + fixup =search_exception_tables (regs->psw.addr & __FIXUP_MASK); +if (fixup) { + regs->psw.addr = fixup->fixup |PSW_ADDR_AMODE ; +return ; + } + +/* +* Oops. The kernel tried to access some bad page. We'll have to +* terminate things with extreme prejudice. +*/ +if (check_space (current) ==0 ) +printk (KERN_ALERT "Unable to handle kernel pointer dereference" +" at virtual kernel address %p\n" , (void *)address); +else +printk (KERN_ALERT "Unable to handle kernel paging request" +" at virtual user address %p\n" , (void *)address); + +die ("Oops" , regs, error_code); +do_exit (SIGKILL ); +} + +static void do_low_address (struct pt_regs *regs,unsigned long error_code) +{ +/* Low-address protection hit in kernel mode means +NULL pointer write access in kernel mode. */ +if (regs->psw.mask &PSW_MASK_PSTATE ) { +/* Low-address protection hit in user mode 'cannot happen'. */ +die ("Low-address protection" , regs, error_code); +do_exit (SIGKILL ); + } + +do_no_context (regs, error_code,0 ); +} + +/* +* We ran out of memory, or some other thing happened to us that made +* us unable to handle the page fault gracefully. +*/ +static int do_out_of_memory (struct pt_regs *regs,unsigned long error_code, +unsigned long address) +{ +struct task_struct *tsk = current; +struct mm_struct *mm = tsk->mm; + +up_read (&mm->mmap_sem); +if (is_init (tsk)) { +yield (); +down_read (&mm->mmap_sem); +return 1 ; + } +printk ("VM: killing process %s\n" , tsk->comm); +if (regs->psw.mask &PSW_MASK_PSTATE ) +do_exit (SIGKILL ); +do_no_context (regs, error_code, address); +return 0 ; +} + +static void do_sigbus (struct pt_regs *regs,unsigned long error_code, +unsigned long address) +{ +struct task_struct *tsk = current; +struct mm_struct *mm = tsk->mm; + +up_read (&mm->mmap_sem); +/* +* Send a sigbus, regardless of whether we were in kernel +* or user mode. +*/ + tsk->thread.prot_addr = address; + tsk->thread.trap_no = error_code; +force_sig (SIGBUS , tsk); + +/* Kernel mode? Handle exceptions or die */ +if (!(regs->psw.mask &PSW_MASK_PSTATE )) +do_no_context (regs, error_code, address); +} +#ifdef CONFIG_S390_EXEC_PROTECT extern long sys_sigreturn (struct pt_regs *regs);extern long sys_rt_sigreturn (struct pt_regs *regs);
@@ -253,49 +340,23 @@* 3b Region third trans. -> Not present (nullification) */ static inline void -do_exception (struct pt_regs *regs,unsigned long error_code,int is_protection) +do_exception (struct pt_regs *regs,unsigned long error_code,int write) { -struct task_struct *tsk; -struct mm_struct *mm; -struct vm_area_struct * vma; -unsigned long address; -const struct exception_table_entry *fixup; -int si_code; +struct task_struct *tsk; +struct mm_struct *mm; +struct vm_area_struct *vma; +unsigned long address;int space; +int si_code; - tsk = current; - mm = tsk->mm; - -if (notify_page_fault (DIE_PAGE_FAULT ,"page fault" , regs, error_code,14 , -SIGSEGV ) ==NOTIFY_STOP ) +if (notify_page_fault (regs, error_code) ==NOTIFY_STOP )return ; -/* -* Check for low-address protection. This needs to be treated -* as a special case because the translation exception code -* field is not guaranteed to contain valid data in this case. -*/ -if (is_protection && !(S390_lowcore.trans_exc_code &4 )) { - -/* Low-address protection hit in kernel mode means -NULL pointer write access in kernel mode. */ -if (!(regs->psw.mask &PSW_MASK_PSTATE )) { - address =0 ; - space =0 ; - goto no_context; - } - -/* Low-address protection hit in user mode 'cannot happen'. */ -die ("Low-address protection" , regs, error_code); -do_exit (SIGKILL ); - } + tsk = current; + mm = tsk->mm; -/* -* get the failing address -* more specific the segment and page table portion of -* the address -*/ - address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK; +/* get the failing address and the affected space */ + address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK; space =check_space (tsk);/*
@@ -313,7 +374,7 @@*/ local_irq_enable (); -down_read (&mm->mmap_sem); +down_read (&mm->mmap_sem); si_code =SEGV_MAPERR ; vma =find_vma (mm, address);
@@ -330,19 +391,19 @@return ;#endif -if (vma->vm_start <= address) - goto good_area; -if (!(vma->vm_flags &VM_GROWSDOWN )) - goto bad_area; -if (expand_stack (vma, address)) - goto bad_area; +if (vma->vm_start <= address) + goto good_area; +if (!(vma->vm_flags &VM_GROWSDOWN )) + goto bad_area; +if (expand_stack (vma, address)) + goto bad_area;/* * Ok, we have a good vm_area for this memory access, so * we can handle it.. */ good_area: si_code =SEGV_ACCERR ; -if (!is_protection) { +if (!write) {/* page not present, check vm flags */ if (!(vma->vm_flags & (VM_READ |VM_EXEC |VM_WRITE ))) goto bad_area;
@@ -357,7 +418,7 @@* make sure we exit gracefully rather than endlessly redo * the fault. */ -switch (handle_mm_fault (mm, vma, address, is_protection)) { +switch (handle_mm_fault (mm, vma, address, write)) {case VM_FAULT_MINOR : tsk->min_flt++;break ;
@@ -365,9 +426,12 @@ tsk->maj_flt++;break ;case VM_FAULT_SIGBUS : - goto do_sigbus; +do_sigbus (regs, error_code, address); +return ;case VM_FAULT_OOM : - goto out_of_memory; +if (do_out_of_memory (regs, error_code, address)) + goto survive; +return ;default :BUG (); }
@@ -385,75 +449,34 @@* Fix it, but check if it's kernel or user first.. */ bad_area: -up_read (&mm->mmap_sem); +up_read (&mm->mmap_sem); -/* User mode accesses just cause a SIGSEGV */ -if (regs->psw.mask &PSW_MASK_PSTATE ) { - tsk->thread.prot_addr = address; - tsk->thread.trap_no = error_code; +/* User mode accesses just cause a SIGSEGV */ +if (regs->psw.mask &PSW_MASK_PSTATE ) { + tsk->thread.prot_addr = address; + tsk->thread.trap_no = error_code;do_sigsegv (regs, error_code, si_code, address); -return ; +return ; } no_context: -/* Are we prepared to handle this kernel fault? */ - fixup =search_exception_tables (regs->psw.addr & __FIXUP_MASK); -if (fixup) { - regs->psw.addr = fixup->fixup |PSW_ADDR_AMODE ; -return ; - } - -/* -* Oops. The kernel tried to access some bad page. We'll have to -* terminate things with extreme prejudice. -*/ -if (space ==0 ) -printk (KERN_ALERT "Unable to handle kernel pointer dereference" -" at virtual kernel address %p\n" , (void *)address); -else -printk (KERN_ALERT "Unable to handle kernel paging request" -" at virtual user address %p\n" , (void *)address); - -die ("Oops" , regs, error_code); -do_exit (SIGKILL ); - - -/* -* We ran out of memory, or some other thing happened to us that made -* us unable to handle the page fault gracefully. -*/ -out_of_memory: -up_read (&mm->mmap_sem); -if (is_init (tsk)) { -yield (); -down_read (&mm->mmap_sem); - goto survive; - } -printk ("VM: killing process %s\n" , tsk->comm); -if (regs->psw.mask &PSW_MASK_PSTATE ) -do_exit (SIGKILL ); - goto no_context; - -do_sigbus: -up_read (&mm->mmap_sem); - -/* -* Send a sigbus, regardless of whether we were in kernel -* or user mode. -*/ - tsk->thread.prot_addr = address; - tsk->thread.trap_no = error_code; -force_sig (SIGBUS , tsk); - -/* Kernel mode? Handle exceptions or die */ -if (!(regs->psw.mask &PSW_MASK_PSTATE )) - goto no_context; +do_no_context (regs, error_code, address); }void __kprobes do_protection_exception (struct pt_regs *regs,unsigned long error_code) { +/* Protection exception is supressing, decrement psw address. */ regs->psw.addr -= (error_code >>16 ); +/* +* Check for low-address protection. This needs to be treated +* as a special case because the translation exception code +* field is not guaranteed to contain valid data in this case. +*/ +if (unlikely (!(S390_lowcore.trans_exc_code &4 ))) { +do_low_address (regs, error_code); +return ; + }do_exception (regs,4 ,1 ); }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
Re: [patch 20/38] Minor fault path optimization.
Quoted 4 lines · Martin Schwidefsky
The minor fault path has grown a lot in terms of cycles. In particular the kprobes hook is very costly. Optimize the path to save a couple of cycles. If kprobes is enabled more than 300 cycles can be avoided if
kprobes_running()is false.
There's no good reason to use a notifier for page faults, since there's only one external piece of code that wants to know about them...
Regards,
Paul.
Re: [patch 20/38] Minor fault path optimization.
Quoted 10 lines · Paul Mackerras
Quoted 4 lines · Martin Schwidefsky
The minor fault path has grown a lot in terms of cycles. In particular the kprobes hook is very costly. Optimize the path to save a couple of cycles. If kprobes is enabled more than 300 cycles can be avoided if
kprobes_running()is false.There's no good reason to use a notifier for page faults, since there's only one external piece of code that wants to know about them...
Well, here's my powerpc patch to do the direct call that I sent out a few weeks ago. It not just speed up the pagefault path a lot, but also is a major code cleanup. Andi and Anton didn't like it because they have ambition for murky debugger code to possibly use it one day..
arch/powerpc/mm/fault.c +14 -26
@@ -39,37 +39,26 @@#include <asm/kdebug.h> #include <asm/siginfo.h> -#ifdef CONFIG_KPROBES -ATOMIC_NOTIFIER_HEAD (notify_page_fault_chain); -/* Hook to register for page fault notifications */ -int register_page_fault_notifier (struct notifier_block *nb) +#ifdef CONFIG_KPROBES +static inline int notify_page_fault (struct pt_regs *regs) { -return atomic_notifier_chain_register (¬ify_page_fault_chain, nb); -} +int ret =0 ; -int unregister_page_fault_notifier (struct notifier_block *nb) -{ -return atomic_notifier_chain_unregister (¬ify_page_fault_chain, nb); -} +/* kprobe_running() needs smp_processor_id() */ +if (!user_mode (regs)) { +preempt_disable (); +if (kprobe_running () &&kprobe_fault_handler (regs,11 )) + ret =1 ; +preempt_enable (); + } -static inline int notify_page_fault (enum die_val val,const char *str, -struct pt_regs *regs,long err,int trap,int sig) -{ -struct die_args args = { - .regs = regs, - .str = str, - .err = err, - .trapnr = trap, - .signr = sig - }; -return atomic_notifier_call_chain (¬ify_page_fault_chain, val, &args); +return ret; }#else -static inline int notify_page_fault (enum die_val val,const char *str, -struct pt_regs *regs,long err,int trap,int sig) +static inline int notify_page_fault (struct pt_regs *regs) { -return NOTIFY_DONE ; +return 0 ; }#endif
@@ -175,8 +164,7 @@ int __kprobes do_page_fault(struct pt_re is_write = error_code &ESR_DST ;#endif /* CONFIG_4xx || CONFIG_BOOKE */ -if (notify_page_fault (DIE_PAGE_FAULT ,"page_fault" , regs, error_code, -11 ,SIGSEGV ) ==NOTIFY_STOP ) +if (notify_page_fault (regs))return 0 ;if (trap ==0x300 ) {
arch/powerpc/kernel/kprobes.c +1 -9
@@ -376,7 +376,7 @@ out:return 1 ; } -static int __kprobes kprobe_fault_handler (struct pt_regs *regs,int trapnr) +int __kprobes kprobe_fault_handler (struct pt_regs *regs,int trapnr) {struct kprobe *cur =kprobe_running ();struct kprobe_ctlblk *kcb =get_kprobe_ctlblk ();
@@ -461,14 +461,6 @@ int __kprobes kprobe_exceptions_notify(sif (post_kprobe_handler (args->regs)) ret =NOTIFY_STOP ;break ; -case DIE_PAGE_FAULT : -/* kprobe_running() needs smp_processor_id() */ -preempt_disable (); -if (kprobe_running () && -kprobe_fault_handler (args->regs, args->trapnr)) - ret =NOTIFY_STOP ; -preempt_enable (); -break ;default :break ; }
include/asm-powerpc/kdebug.h +14 -3
@@ -18,8 +18,20 @@ struct die_args {extern int register_die_notifier (struct notifier_block *);extern int unregister_die_notifier (struct notifier_block *); -extern int register_page_fault_notifier (struct notifier_block *); -extern int unregister_page_fault_notifier (struct notifier_block *); + +/* +* These are only here because kprobes.c wants them to implement a +* blatant layer violation. Will hopefully go away soon once all +* architectures are updated. +*/ +static inline int register_page_fault_notifier (struct notifier_block *nb) +{ +return 0 ; +} +static inline int unregister_page_fault_notifier (struct notifier_block *nb) +{ +return 0 ; +}extern struct atomic_notifier_head powerpc_die_chain;/* Grossly misnamed. */
@@ -29,7 +41,6 @@ enum die_val {DIE_DABR_MATCH ,DIE_BPT , DIE_SSTEP, - DIE_PAGE_FAULT, };static inline int notify_die (enum die_val val,char *str,struct pt_regs *regs,long err,int trap,int sig)
include/asm-powerpc/kprobes.h +1 -0
@@ -100,5 +100,6 @@ struct kprobe_ctlblk {extern int kprobe_exceptions_notify (struct notifier_block *self,unsigned long val,void *data); +extern int kprobe_fault_handler (struct pt_regs *regs,int trapnr);#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_KPROBES_H */
Re: [patch 20/38] Minor fault path optimization.
Quoted 5 lines · Christoph Hellwig
Well, here's my powerpc patch to do the direct call that I sent out a few weeks ago. It not just speed up the pagefault path a lot, but also is a major code cleanup. Andi and Anton didn't like it because they have ambition for murky debugger code to possibly use it one day..
Looks good. Could you resend it to me with a proper description and a sign-off?
Thanks,
Paul.
PATCH 1/1 powerpc: minor fault path optimization
Call the kprobes pagefault handler directly instead of going through the complex notifier chain.
arch/powerpc/mm/fault.c +14 -26
@@ -39,37 +39,26 @@#include <asm/kdebug.h> #include <asm/siginfo.h> -#ifdef CONFIG_KPROBES -ATOMIC_NOTIFIER_HEAD (notify_page_fault_chain); -/* Hook to register for page fault notifications */ -int register_page_fault_notifier (struct notifier_block *nb) +#ifdef CONFIG_KPROBES +static inline int notify_page_fault (struct pt_regs *regs) { -return atomic_notifier_chain_register (¬ify_page_fault_chain, nb); -} +int ret =0 ; -int unregister_page_fault_notifier (struct notifier_block *nb) -{ -return atomic_notifier_chain_unregister (¬ify_page_fault_chain, nb); -} +/* kprobe_running() needs smp_processor_id() */ +if (!user_mode (regs)) { +preempt_disable (); +if (kprobe_running () &&kprobe_fault_handler (regs,11 )) + ret =1 ; +preempt_enable (); + } -static inline int notify_page_fault (enum die_val val,const char *str, -struct pt_regs *regs,long err,int trap,int sig) -{ -struct die_args args = { - .regs = regs, - .str = str, - .err = err, - .trapnr = trap, - .signr = sig - }; -return atomic_notifier_call_chain (¬ify_page_fault_chain, val, &args); +return ret; }#else -static inline int notify_page_fault (enum die_val val,const char *str, -struct pt_regs *regs,long err,int trap,int sig) +static inline int notify_page_fault (struct pt_regs *regs) { -return NOTIFY_DONE ; +return 0 ; }#endif
@@ -175,8 +164,7 @@ int __kprobes do_page_fault(struct pt_re is_write = error_code &ESR_DST ;#endif /* CONFIG_4xx || CONFIG_BOOKE */ -if (notify_page_fault (DIE_PAGE_FAULT ,"page_fault" , regs, error_code, -11 ,SIGSEGV ) ==NOTIFY_STOP ) +if (notify_page_fault (regs))return 0 ;if (trap ==0x300 ) {
arch/powerpc/kernel/kprobes.c +1 -9
@@ -376,7 +376,7 @@ out:return 1 ; } -static int __kprobes kprobe_fault_handler (struct pt_regs *regs,int trapnr) +int __kprobes kprobe_fault_handler (struct pt_regs *regs,int trapnr) {struct kprobe *cur =kprobe_running ();struct kprobe_ctlblk *kcb =get_kprobe_ctlblk ();
@@ -461,14 +461,6 @@ int __kprobes kprobe_exceptions_notify(sif (post_kprobe_handler (args->regs)) ret =NOTIFY_STOP ;break ; -case DIE_PAGE_FAULT : -/* kprobe_running() needs smp_processor_id() */ -preempt_disable (); -if (kprobe_running () && -kprobe_fault_handler (args->regs, args->trapnr)) - ret =NOTIFY_STOP ; -preempt_enable (); -break ;default :break ; }
include/asm-powerpc/kdebug.h +14 -3
@@ -18,8 +18,20 @@ struct die_args {extern int register_die_notifier (struct notifier_block *);extern int unregister_die_notifier (struct notifier_block *); -extern int register_page_fault_notifier (struct notifier_block *); -extern int unregister_page_fault_notifier (struct notifier_block *); + +/* +* These are only here because kprobes.c wants them to implement a +* blatant layering violation. Will hopefully go away soon once all +* architectures are updated. +*/ +static inline int register_page_fault_notifier (struct notifier_block *nb) +{ +return 0 ; +} +static inline int unregister_page_fault_notifier (struct notifier_block *nb) +{ +return 0 ; +}extern struct atomic_notifier_head powerpc_die_chain;/* Grossly misnamed. */
@@ -29,7 +41,6 @@ enum die_val {DIE_DABR_MATCH ,DIE_BPT , DIE_SSTEP, - DIE_PAGE_FAULT, };static inline int notify_die (enum die_val val,char *str,struct pt_regs *regs,long err,int trap,int sig)
include/asm-powerpc/kprobes.h +1 -0
@@ -105,5 +105,6 @@ struct kprobe_ctlblk {extern int kprobe_exceptions_notify (struct notifier_block *self,unsigned long val,void *data); +extern int kprobe_fault_handler (struct pt_regs *regs,int trapnr);#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_KPROBES_H */
Re: [patch 20/38] Minor fault path optimization.
In reply to Christoph HellwigQuoted 5 lines · Christoph Hellwig
Well, here's my powerpc patch to do the direct call that I sent out a few weeks ago. It not just speed up the pagefault path a lot, but also is a major code cleanup. Andi and Anton didn't like it because they have ambition for murky debugger code to possibly use it one day..
I thought about using a direct call for s390 as well. The advantage of a direct call is that it avoids the overhead of a notifier call even if kprobes is running. The disadvantage is that there cannot be a second consumer of the fault notifications. I choose the middle way: avoid the overhead if kprobes is not active and use the full notifier if kprobes is running. It should not hurt the performance too badly since kprobe_running is only true if the cpu gets a page fault while executing a kprobe.
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
Re: [patch 20/38] Minor fault path optimization.
Quoted 8 lines · Martin Schwidefsky
I thought about using a direct call for s390 as well. The advantage of a direct call is that it avoids the overhead of a notifier call even if kprobes is running. The disadvantage is that there cannot be a second consumer of the fault notifications. I choose the middle way: avoid the overhead if kprobes is not active and use the full notifier if kprobes is running. It should not hurt the performance too badly since
kprobe_runningis only true if the cpu gets a page fault while executing a kprobe.
There is not second caller :) Also it wouldn't work because you check for kprobe_running() which wouldn't be true for it. It also means you go through the whole notifier chain mechanism for every userspace page fault when kprobes are running which is the least of them.
So let's no do odd preparations for the future but optimize for the current case and add things if needed in the future. Note that I plan to send similar patches for all kprobes supporting architectures so that we have common code again. Eventually notify_page_fault should move into include/linux/kprobes.h
Quoted 8 lines
--kprobe_running
blue skies,
Martin."Reality continues to ruin my life." - Calvin.
---end quoted text---
PATCH 21/38 No execute support cleanup.
In reply to Martin SchwidefskyFrom: Martin Schwidefsky <[email protected]>
Simplify the signal_return function that checks for the two special system calls sigreturn and rt_sigreturn. No need to do a page table walk, a call to copy_from_user while disabled page faults will work as well.
---
arch/s390/mm/fault.c | 72 ++++++++++++++------------------------------------- 1 files changed, 21 insertions(+), 51 deletions(-)
arch/s390/mm/fault.c +21 -51
@@ -26,9 +26,9 @@#include <linux/module.h> #include <linux/hardirq.h> #include <linux/kprobes.h> +#include <linux/uaccess.h> #include <asm/system.h> -#include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/kdebug.h> #include <asm/s390_ext.h>
@@ -263,68 +263,38 @@extern long sys32_sigreturn (struct pt_regs *regs);extern long sys32_rt_sigreturn (struct pt_regs *regs); -static inline void do_sigreturn (struct mm_struct *mm,struct pt_regs *regs, -int rt) +static int signal_return (struct mm_struct *mm,struct pt_regs *regs, +unsigned long address,unsigned long error_code) { +u16 instruction; +int rc, compat; + +pagefault_disable (); + rc =__get_user (instruction, (u16 __user *) regs->psw.addr); +pagefault_enable (); +if (rc) +return -EFAULT ; +up_read (&mm->mmap_sem);clear_tsk_thread_flag (current,TIF_SINGLE_STEP );#ifdef CONFIG_COMPAT -if (test_tsk_thread_flag (current,TIF_31BIT )) { -if (rt) -sys32_rt_sigreturn (regs); -else -sys32_sigreturn (regs); -return ; - } -#endif /* CONFIG_COMPAT */ -if (rt) -sys_rt_sigreturn (regs); + compat =test_tsk_thread_flag (current,TIF_31BIT ); +if (compat && instruction ==0x0a77 ) +sys32_sigreturn (regs); +else if (compat && instruction ==0x0aad ) +sys32_rt_sigreturn (regs); else +#endif +if (instruction ==0x0a77 )sys_sigreturn (regs); -return ; -} - -static int signal_return (struct mm_struct *mm,struct pt_regs *regs, -unsigned long address,unsigned long error_code) -{ -pgd_t *pgd; -pmd_t *pmd; -pte_t *pte; -u16 *instruction; -unsigned long pfn, uaddr = regs->psw.addr; - -spin_lock (&mm->page_table_lock); - pgd =pgd_offset (mm, uaddr); -if (pgd_none (*pgd) ||unlikely (pgd_bad (*pgd))) - goto out_fault; - pmd =pmd_offset (pgd, uaddr); -if (pmd_none (*pmd) ||unlikely (pmd_bad (*pmd))) - goto out_fault; - pte =pte_offset_map (pmd_offset (pgd_offset (mm, uaddr), uaddr), uaddr); -if (!pte || !pte_present (*pte)) - goto out_fault; - pfn =pte_pfn (*pte); -if (!pfn_valid (pfn)) - goto out_fault; -spin_unlock (&mm->page_table_lock); - - instruction = (u16 *) ((pfn <<PAGE_SHIFT ) + (uaddr & (PAGE_SIZE -1 ))); -if (*instruction ==0x0a77 ) -do_sigreturn (mm, regs,0 ); -else if (*instruction ==0x0aad ) -do_sigreturn (mm, regs,1 ); +else if (instruction ==0x0aad ) +sys_rt_sigreturn (regs);else { -printk ("- XXX - do_exception: task = %s, primary, NO EXEC " -"-> SIGSEGV\n" , current->comm); -up_read (&mm->mmap_sem); current->thread.prot_addr = address; current->thread.trap_no = error_code;do_sigsegv (regs, error_code,SEGV_MAPERR , address); }return 0 ; -out_fault: -spin_unlock (&mm->page_table_lock); -return -EFAULT ; }#endif /* CONFIG_S390_EXEC_PROTECT */
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 22/38 Get rid of console setup functions.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
We get this:
Section mismatch: reference to .init.text:con3270_consetup from .data
between 'con3270' (at offset 0x45c8) and 'con3270_fn' Section mismatch: reference to .init.text:con3215_consetup from .data between 'con3215' (at offset 0x4678) and 'raw3215_ccw_driver'
Since there is no difference between a non present console setup function and one that returns only 0 remove them.
---
drivers/s390/char/con3215.c | 7 ------- drivers/s390/char/con3270.c | 7 ------- 2 files changed, 14 deletions(-)
drivers/s390/char/con3215.c +0 -7
@@ -813,12 +813,6 @@spin_unlock_irqrestore (get_ccwdev_lock (raw->cdev), flags); } -static int __init -con3215_consetup (struct console *co,char *options) -{ -return 0 ; -} -/* * The console structure for the 3215 console */
@@ -827,7 +821,6 @@ .write = con3215_write, .device = con3215_device, .unblank = con3215_unblank, - .setup = con3215_consetup, .flags = CON_PRINTBUFFER, };
drivers/s390/char/con3270.c +0 -7
@@ -555,12 +555,6 @@spin_unlock_irqrestore (&cp->view.lock, flags); } -static int __init -con3270_consetup (struct console *co,char *options) -{ -return 0 ; -} -/* * The console structure for the 3270 console */
@@ -569,7 +563,6 @@ .write = con3270_write, .device = con3270_device, .unblank = con3270_unblank, - .setup = con3270_consetup, .flags = CON_PRINTBUFFER, };
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 23/38 Improved kernel stack overflow checking.
In reply to Martin SchwidefskyFrom: Martin Schwidefsky <[email protected]>
Recent cvs versions of gcc have support for an improved stack overflow checking that calculates the size of the guard size for each function. If the compiler accepts -mstack-size without -mstack-guard then the new stack check is available. We always want to use the new stack checker.
---
arch/s390/Makefile | 2 ++ 1 files changed, 2 insertions(+)
arch/s390/Makefile +2 -0
@@ -67,8 +67,10 @@ ifeq ($(call cc-option-yn,-mstack-size=8192 -mstack-guard=128),y) cflags-$(CONFIG_CHECK_STACK) += -mstack-size=$(STACK_SIZE) +ifneq ($(call cc-option-yn,-mstack-size=8192),y) cflags-$(CONFIG_CHECK_STACK) += -mstack-guard=$(CONFIG_STACK_GUARD) endif +endif ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y) cflags-$(CONFIG_WARN_STACK) += -mwarn-dynamicstack
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 24/38 dasd: Add sysfs attribute status and generate uevents.
In reply to Martin SchwidefskyFrom: Horst Hummel <[email protected]>
This patch adds a sysfs-attribute 'status' to make the DASD device-status accessible from user-space. In addition, the DASD driver generates an uevent(CHANGE) for the ccw-device on each device-status change. This enables user-space applications (e.g. udev) to do related processing.
---
drivers/s390/block/dasd.c | 3 ++ drivers/s390/block/dasd_devmap.c | 41 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+)
drivers/s390/block/dasd.c +3 -0
@@ -398,6 +398,9 @@if (device->state == device->target)wake_up (&dasd_init_waitq); + +/* let user-space know that the device status changed */ +kobject_uevent (&device->cdev->dev.kobj,KOBJ_CHANGE ); }/*
drivers/s390/block/dasd_devmap.c +41 -0
53 lines not on this page · raw message
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 25/38 dasd: Add ipldev parameter.
In reply to Martin SchwidefskyFrom: Peter Oberparleiter <[email protected]>
Specifying 'ipldev' in the dasd= kernel parameter will automatically activate the boot device for use by the dasd driver.
---
drivers/s390/block/dasd_devmap.c | 17 +++++++++++++++++ 1 files changed, 17 insertions(+)
drivers/s390/block/dasd_devmap.c +17 -0
@@ -19,6 +19,7 @@#include <asm/debug.h> #include <asm/uaccess.h> +#include <asm/ipl.h> /* This is ugly... */ #define PRINTK_HEADER "dasd_devmap:"
@@ -133,6 +134,8 @@__setup ("dasd=" , dasd_call_setup);#endif /* #ifndef MODULE */ +#define DASD_IPLDEV "ipldev" +/* * Read a device busid/devno from a string. */
@@ -141,6 +144,20 @@ {int val, old_style; +/* Interpret ipldev busid */ +if (strncmp (DASD_IPLDEV , *str,strlen (DASD_IPLDEV )) ==0 ) { +if (ipl_info.type !=IPL_TYPE_CCW ) { +MESSAGE (KERN_ERR ,"%s" ,"ipl device is not a ccw " +"device" ); +return -EINVAL ; + } + *id0 =0 ; + *id1 = ipl_info.data.ccw.dev_id.ssid; + *devno = ipl_info.data.ccw.dev_id.devno; + *str +=strlen (DASD_IPLDEV ); + +return 0 ; + }/* check for leading '0x' */ old_style =0 ;if ((*str)[0 ] =='0' && (*str)[1 ] =='x' ) {
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 26/38 zfcpdump support.
In reply to Martin SchwidefskyFrom: Michael Holzheu <[email protected]>
s390 machines provide hardware support for creating Linux dumps on SCSI disks. For creating a dump a special purpose dump Linux is used. The first 32 MB of memory are saved by the hardware before the dump Linux is booted. Via an SCLP interface, the saved memory can be accessed from Linux. This patch exports memory and registers of the crashed Linux to userspace via a debugfs file. For more information refer to Documentation/s390/zfcpdump.txt, which is included in this patch.
---
Documentation/s390/zfcpdump.txt | 87 +++++ arch/s390/Kconfig | 8 arch/s390/Makefile | 3 arch/s390/defconfig | 1 arch/s390/kernel/head64.S | 72 ++++ arch/s390/kernel/ipl.c | 232 +++++++++----- arch/s390/kernel/setup.c | 38 ++ arch/s390/kernel/smp.c | 62 +++ drivers/s390/char/Makefile | 3 drivers/s390/char/sclp.h | 2 drivers/s390/char/sclp_sdias.c | 255 +++++++++++++++ drivers/s390/char/zcore.c | 651 ++++++++++++++++++++++++++++++++++++++++ include/asm-s390/ipl.h | 32 + include/asm-s390/lowcore.h | 46 ++ include/asm-s390/sclp.h | 2 include/asm-s390/setup.h | 2 include/asm-s390/smp.h | 1 17 files changed, 1411 insertions(+), 86 deletions(-)
arch/s390/defconfig +1 -0
@@ -167,6 +167,7 @@ CONFIG_NO_IDLE_HZ_INIT=y CONFIG_S390_HYPFS_FS=y CONFIG_KEXEC=y +# CONFIG_ZFCPDUMP is not set # # Networking
arch/s390/Kconfig +8 -0
@@ -519,6 +519,14 @@ current kernel, and to start another kernel. It is like a reboot but is independent of hardware/microcode support. +config ZFCPDUMP + tristate "zfcpdump support" + select SMP + default n + help + Select this option if you want to build an zfcpdump enabled kernel. + Refer to "Documentation/s390/zfcpdump.txt" for more details on this. + endmenu source "net/Kconfig"
arch/s390/kernel/head64.S +71 -1
84 lines not on this page · raw message
arch/s390/kernel/ipl.c +150 -82
450 lines not on this page · raw message
arch/s390/kernel/setup.c +35 -3
@@ -285,6 +285,26 @@ } } +#if defined(CONFIG_ZFCPDUMP ) || defined(CONFIG_ZFCPDUMP_MODULE ) +static void __init setup_zfcpdump (unsigned int console_devno) +{ +static char str[64 ]; + +if (ipl_info.type !=IPL_TYPE_FCP_DUMP ) +return ; +if (console_devno !=-1 ) +sprintf (str,"cio_ignore=all,!0.0.%04x,!0.0.%04x" , + ipl_info.data.fcp.dev_id.devno, console_devno); +else +sprintf (str,"cio_ignore=all,!0.0.%04x" , + ipl_info.data.fcp.dev_id.devno); +strcat (COMMAND_LINE , str); + console_loglevel =2 ; +} +#else +static inline void setup_zfcpdump (unsigned int console_devno) {} +#endif /* CONFIG_ZFCPDUMP */ +#ifdef CONFIG_SMP void (*_machine_restart)(char *command) = machine_restart_smp;void (*_machine_halt)(void ) = machine_halt_smp;
@@ -586,13 +606,20 @@ } } +unsigned long real_memory_size; +EXPORT_SYMBOL_GPL (real_memory_size); +static void __init setup_memory_end (void ) { -unsigned long real_size, memory_size; +unsigned long memory_size;unsigned long max_mem, max_phys;int i; - memory_size = real_size =0 ; +#if defined(CONFIG_ZFCPDUMP ) || defined(CONFIG_ZFCPDUMP_MODULE ) +if (ipl_info.type ==IPL_TYPE_FCP_DUMP ) + memory_end =ZFCPDUMP_HSA_SIZE ; +#endif + memory_size =0 ; max_phys =VMALLOC_END_INIT -VMALLOC_MIN_SIZE ; memory_end &=PAGE_MASK ;
@@ -601,7 +628,8 @@for (i =0 ; i <MEMORY_CHUNKS ; i++) {struct mem_chunk *chunk = &memory_chunk[i]; - real_size =max (real_size, chunk->addr + chunk->size); + real_memory_size =max (real_memory_size, + chunk->addr + chunk->size);if (chunk->addr >= max_mem) {memset (chunk,0 ,sizeof (*chunk));continue ;
@@ -765,6 +793,7 @@parse_early_param (); +setup_ipl_info ();setup_memory_end ();setup_addressing_mode ();setup_memory ();
@@ -782,6 +811,9 @@/* Setup default console */ conmode_default (); + +/* Setup zfcpdump support */ +setup_zfcpdump (console_devno); }void print_cpu_info (struct cpuinfo_S390 *cpuinfo)
arch/s390/kernel/smp.c +62 -0
86 lines not on this page · raw message
arch/s390/Makefile +3 -0
@@ -105,6 +105,9 @@ image: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ +zfcpdump: + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + archclean: $(Q)$(MAKE) $(clean)=$(boot)
Documentation/s390/zfcpdump.txt new file +87 -0
87 lines not on this page · raw message
drivers/s390/char/Makefile +3 -0
@@ -29,3 +29,6 @@ obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o obj-$(CONFIG_MONREADER) += monreader.o obj-$(CONFIG_MONWRITER) += monwriter.o + +zcore_mod-objs := sclp_sdias.o zcore.o +obj-$(CONFIG_ZFCPDUMP) += zcore_mod.o
drivers/s390/char/sclp.h +2 -0
@@ -27,6 +27,7 @@#define EvTyp_CntlProgIdent 0x0B#define EvTyp_SigQuiesce 0x1D#define EvTyp_VT220Msg 0x1A +#define EvTyp_SDIAS 0x1C#define EvTyp_OpCmd_Mask 0x80000000#define EvTyp_Msg_Mask 0x40000000
@@ -36,6 +37,7 @@#define EvTyp_CtlProgIdent_Mask 0x00200000#define EvTyp_SigQuiesce_Mask 0x00000008#define EvTyp_VT220Msg_Mask 0x00000040 +#define EvTyp_SDIAS_Mask 0x00000010#define GnrlMsgFlgs_DOM 0x8000#define GnrlMsgFlgs_SndAlrm 0x4000
drivers/s390/char/sclp_sdias.c new file +255 -0
255 lines not on this page · raw message
drivers/s390/char/zcore.c new file +651 -0
651 lines not on this page · raw message
include/asm-s390/ipl.h +32 -0
@@ -8,6 +8,8 @@#define _ASM_S390_IPL_H#include <asm/types.h> +#include <asm/cio.h> +#include <asm/setup.h> #define IPL_PARMBLOCK_ORIGIN 0x2000
@@ -79,6 +81,7 @@extern u32 ipl_flags;extern u32 dump_prefix_page; +extern void do_reipl (void );extern void ipl_save_parameters (void );
@@ -88,6 +91,35 @@ IPL_NSS_VALID = 4, }; +enum ipl_type { +IPL_TYPE_UNKNOWN =1 , +IPL_TYPE_CCW =2 , +IPL_TYPE_FCP =4 , +IPL_TYPE_FCP_DUMP =8 , +IPL_TYPE_NSS =16 , +}; + +struct ipl_info +{ +enum ipl_type type; +union { +struct { +struct ccw_dev_id dev_id; + } ccw; +struct { +struct ccw_dev_id dev_id; +u64 wwpn; +u64 lun; + } fcp; +struct { +char name[NSS_NAME_SIZE +1 ]; + } nss; + } data; +}; + +extern struct ipl_info ipl_info; +extern void setup_ipl_info (void ); +/* * DIAG 308 support */
include/asm-s390/lowcore.h +46 -0
52 lines not on this page · raw message
include/asm-s390/sclp.h +2 -0
@@ -44,6 +44,8 @@extern struct sclp_readinfo_sccb s390_readinfo_sccb;extern void sclp_readinfo_early (void ); +extern int sclp_sdias_blk_count (void ); +extern int sclp_sdias_copy (void *dest,int blk_num,int nr_blks);extern int sclp_chp_configure (struct chp_id chpid);extern int sclp_chp_deconfigure (struct chp_id chpid);extern int sclp_chp_read_info (struct sclp_chp_info *info);
include/asm-s390/setup.h +2 -0
@@ -40,6 +40,7 @@ };extern struct mem_chunk memory_chunk[]; +extern unsigned long real_memory_size;#ifdef CONFIG_S390_SWITCH_AMODE extern unsigned int switch_amode;
@@ -77,6 +78,7 @@#endif /* __s390x__ */ #define MACHINE_HAS_SCLP (!MACHINE_IS_P390) +#define ZFCPDUMP_HSA_SIZE (32UL<<20)/* * Console mode. Override with conmode=
include/asm-s390/smp.h +1 -0
@@ -119,4 +119,5 @@#define smp_setup_cpu_possible_map () do { } while (0)#endif +extern union save_area *zfcpdump_save_areas[NR_CPUS +1 ];#endif
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 27/38 ctc: kmalloc->kzalloc/casting cleanups.
In reply to Martin SchwidefskyFrom: "Ahmed S. Darwish" <[email protected]>
A patch for the CTC / ESCON network driver. Switch from kmalloc to kzalloc when appropriate, remove some unnecessary kmalloc casts too. Since I have no s390 machine, I didn't compile it but I examined it carefully.
---
drivers/s390/net/ctcmain.c | 23 +++++++++-------------- 1 files changed, 9 insertions(+), 14 deletions(-)
drivers/s390/net/ctcmain.c +9 -14
@@ -1638,21 +1638,19 @@struct channel *ch;DBF_TEXT (trace,2 , __FUNCTION__); -if ((ch = - (struct channel *)kmalloc (sizeof (struct channel ), -GFP_KERNEL )) ==NULL ) { + ch =kzalloc (sizeof (struct channel ),GFP_KERNEL ); +if (!ch) {ctc_pr_warn ("ctc: Out of memory in add_channel\n" );return -1 ; } -memset (ch,0 ,sizeof (struct channel )); -if ((ch->ccw =kmalloc (8 *sizeof (struct ccw1 ), -GFP_KERNEL |GFP_DMA )) ==NULL ) { +/* assure all flags and counters are reset */ + ch->ccw =kzalloc (8 *sizeof (struct ccw1 ),GFP_KERNEL |GFP_DMA ); +if (!ch->ccw) {kfree (ch);ctc_pr_warn ("ctc: Out of memory in add_channel\n" );return -1 ; } -memset (ch->ccw,0 ,8 *sizeof (struct ccw1 ));// assure all flags and counters are reset /** * "static" ccws are used in the following way:
@@ -1692,15 +1690,14 @@return -1 ; }fsm_newstate (ch->fsm,CH_STATE_IDLE ); -if ((ch->irb =kmalloc (sizeof (struct irb ), -GFP_KERNEL )) ==NULL ) { + ch->irb =kzalloc (sizeof (struct irb ),GFP_KERNEL ); +if (!ch->irb) {ctc_pr_warn ("ctc: Out of memory in add_channel\n" );kfree_fsm (ch->fsm);kfree (ch->ccw);kfree (ch);return -1 ; } -memset (ch->irb,0 ,sizeof (struct irb ));while (*c &&less_than ((*c)->id, ch->id)) c = &(*c)->next;if (*c && (!strncmp ((*c)->id, ch->id,CTC_ID_SIZE ))) {
@@ -2745,14 +2742,13 @@if (!get_device (&cgdev->dev))return -ENODEV ; - priv =kmalloc (sizeof (struct ctc_priv ),GFP_KERNEL ); + priv =kzalloc (sizeof (struct ctc_priv ),GFP_KERNEL );if (!priv) {ctc_pr_err ("%s: Out of memory\n" , __func__);put_device (&cgdev->dev);return -ENOMEM ; } -memset (priv,0 ,sizeof (struct ctc_priv )); rc =ctc_add_files (&cgdev->dev);if (rc) {kfree (priv);
@@ -2793,10 +2789,9 @@DBF_TEXT (setup,3 , __FUNCTION__);if (alloc_device) { - dev =kmalloc (sizeof (struct net_device ),GFP_KERNEL ); + dev =kzalloc (sizeof (struct net_device ),GFP_KERNEL );if (!dev)return NULL ; -memset (dev,0 ,sizeof (struct net_device )); } dev->priv = privptr;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 28/38 sclp: initialize early.
In reply to Martin SchwidefskyFrom: Peter Oberparleiter <[email protected]>
Add explicit sclp initialization for those sclp users that do not register with the interface.
---
drivers/s390/char/sclp.c | 8 ++++++++ 1 files changed, 8 insertions(+)
drivers/s390/char/sclp.c +8 -0
@@ -15,6 +15,7 @@#include <linux/timer.h> #include <linux/reboot.h> #include <linux/jiffies.h> +#include <linux/init.h> #include <asm/types.h> #include <asm/s390_ext.h>
@@ -930,3 +931,10 @@sclp_init_mask (1 );return 0 ; } + +static __init int sclp_initcall (void ) +{ +return sclp_init (); +} + +arch_initcall (sclp_initcall);
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 29/38 vmlogrdr: stop IUCV connection in vmlogrdr_release.
In reply to Martin SchwidefskyFrom: Ursula Braun <[email protected]>
Reopen of /dev/account failed. The IUCV path has to be terminated in vmlogrdr_release.
---
drivers/s390/char/vmlogrdr.c | 3 +++ 1 files changed, 3 insertions(+)
drivers/s390/char/vmlogrdr.c +3 -0
@@ -385,6 +385,9 @@struct vmlogrdr_priv_t * logptr = filp->private_data; +iucv_path_sever (logptr->path,NULL ); +kfree (logptr->path); + logptr->path =NULL ;if (logptr->autorecording) { ret =vmlogrdr_recording (logptr,0 ,logptr->autopurge);if (ret)
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 30/38 sclp: fix coding style.
In reply to Martin SchwidefskyFrom: Stefan Haberland <[email protected]>
Use only capital letters for defines.
---
drivers/s390/char/sclp.c | 2 - drivers/s390/char/sclp.h | 72 +++++++++++++++++++-------------------- drivers/s390/char/sclp_cpi.c | 4 +- drivers/s390/char/sclp_quiesce.c | 2 - drivers/s390/char/sclp_rw.c | 16 ++++---- drivers/s390/char/sclp_sdias.c | 6 +-- drivers/s390/char/sclp_tty.c | 6 +-- drivers/s390/char/sclp_vt220.c | 8 ++-- 8 files changed, 58 insertions(+), 58 deletions(-)
drivers/s390/char/sclp.c +1 -1
@@ -511,7 +511,7 @@ }static struct sclp_register sclp_state_change_event = { - .receive_mask = EvTyp_StateChange_Mask, + .receive_mask =EVTYP_STATECHANGE_MASK , .receiver_fn = sclp_state_change_cb };
drivers/s390/char/sclp_cpi.c +2 -2
@@ -46,7 +46,7 @@/* Event type structure for write message and write priority message */ static struct sclp_register sclp_cpi_event = { - .send_mask = EvTyp_CtlProgIdent_Mask + .send_mask =EVTYP_CTLPROGIDENT_MASK };MODULE_LICENSE ("GPL" );
@@ -201,7 +201,7 @@ "console.\n");return -EINVAL ; } -if (!(sclp_cpi_event.sclp_send_mask & EvTyp_CtlProgIdent_Mask)) { +if (!(sclp_cpi_event.sclp_send_mask &EVTYP_CTLPROGIDENT_MASK )) {printk (KERN_WARNING "cpi: no control program identification " "support\n" );sclp_unregister (&sclp_cpi_event);
drivers/s390/char/sclp.h +36 -36
86 lines not on this page · raw message
drivers/s390/char/sclp_quiesce.c +1 -1
@@ -43,7 +43,7 @@ }static struct sclp_register sclp_quiesce_event = { - .receive_mask = EvTyp_SigQuiesce_Mask, + .receive_mask =EVTYP_SIGQUIESCE_MASK , .receiver_fn = sclp_quiesce_handler };
drivers/s390/char/sclp_rw.c +8 -8
@@ -30,7 +30,7 @@/* Event type structure for write message and write priority message */ static struct sclp_register sclp_rw_event = { - .send_mask = EvTyp_Msg_Mask | EvTyp_PMsgCmd_Mask + .send_mask =EVTYP_MSG_MASK |EVTYP_PMSGCMD_MASK };/*
@@ -64,7 +64,7 @@memset (sccb,0 ,sizeof (struct write_sccb )); sccb->header.length =sizeof (struct write_sccb ); sccb->msg_buf.header.length =sizeof (struct msg_buf ); - sccb->msg_buf.header.type = EvTyp_Msg; + sccb->msg_buf.header.type =EVTYP_MSG ; sccb->msg_buf.mdb.header.length =sizeof (struct mdb ); sccb->msg_buf.mdb.header.type =1 ; sccb->msg_buf.mdb.header.tag =0xD4C4C240 ;/* ebcdic "MDB " */
@@ -114,7 +114,7 @@memset (mto,0 ,sizeof (struct mto )); mto->length =sizeof (struct mto ); mto->type =4 ;/* message text object */ - mto->line_type_flags = LnTpFlgs_EndText;/* end text */ + mto->line_type_flags =LNTPFLGS_ENDTEXT ;/* end text */ /* set pointer to first byte after struct mto. */ buffer->current_line = (char *) (mto +1 );
@@ -215,7 +215,7 @@case '\a' :/* bell, one for several times */ /* set SCLP sound alarm bit in General Object */ buffer->sccb->msg_buf.mdb.go.general_msg_flags |= - GnrlMsgFlgs_SndAlrm; +GNRLMSGFLGS_SNDALRM ;break ;case '\t' :/* horizontal tabulator */ /* check if new mto needs to be created */
@@ -452,12 +452,12 @@return -EIO ; sccb = buffer->sccb; -if (sclp_rw_event.sclp_send_mask & EvTyp_Msg_Mask) +if (sclp_rw_event.sclp_send_mask &EVTYP_MSG_MASK )/* Use normal write message */ - sccb->msg_buf.header.type = EvTyp_Msg; -else if (sclp_rw_event.sclp_send_mask & EvTyp_PMsgCmd_Mask) + sccb->msg_buf.header.type =EVTYP_MSG ; +else if (sclp_rw_event.sclp_send_mask &EVTYP_PMSGCMD_MASK )/* Use write priority message */ - sccb->msg_buf.header.type = EvTyp_PMsgCmd; + sccb->msg_buf.header.type =EVTYP_PMSGCMD ;else return -ENOSYS ; buffer->request.command =SCLP_CMDW_WRITE_EVENT_DATA ;
drivers/s390/char/sclp_sdias.c +3 -3
@@ -30,7 +30,7 @@static struct debug_info *sdias_dbf;static struct sclp_register sclp_sdias_register = { - .send_mask = EvTyp_SDIAS_Mask, + .send_mask =EVTYP_SDIAS_MASK , };struct sdias_evbuf {
@@ -118,7 +118,7 @@ sccb.hdr.length =sizeof (sccb); sccb.evbuf.hdr.length =sizeof (struct sdias_evbuf ); - sccb.evbuf.hdr.type = EvTyp_SDIAS; + sccb.evbuf.hdr.type =EVTYP_SDIAS ; sccb.evbuf.event_qual =EQ_SIZE ; sccb.evbuf.data_id =DI_FCP_DUMP ; sccb.evbuf.event_id =4712 ;
@@ -177,7 +177,7 @@ sccb.hdr.length =sizeof (sccb); sccb.evbuf.hdr.length =sizeof (struct sdias_evbuf ); - sccb.evbuf.hdr.type = EvTyp_SDIAS; + sccb.evbuf.hdr.type =EVTYP_SDIAS ; sccb.evbuf.hdr.flags =0 ; sccb.evbuf.event_qual =EQ_STORE_DATA ; sccb.evbuf.data_id =DI_FCP_DUMP ;
drivers/s390/char/sclp_tty.c +3 -3
@@ -648,7 +648,7 @@ subvec = start;while (subvec < end) { subvec =find_gds_subvector (subvec, end, - GDS_KEY_SelfDefTextMsg); +GDS_KEY_SELFDEFTEXTMSG );if (!subvec)break ; sclp_eval_selfdeftextmsg((struct gds_subvector *)(subvec + 1),
@@ -664,7 +664,7 @@ vec = start;while (vec < end) { - vec =find_gds_vector (vec, end, GDS_ID_TextCmd); + vec =find_gds_vector (vec, end,GDS_ID_TEXTCMD );if (!vec)break ; sclp_eval_textcmd((struct gds_subvector *)(vec + 1),
@@ -703,7 +703,7 @@static struct sclp_register sclp_input_event = { - .receive_mask = EvTyp_OpCmd_Mask | EvTyp_PMsgCmd_Mask, + .receive_mask =EVTYP_OPCMD_MASK |EVTYP_PMSGCMD_MASK , .state_change_fn = sclp_tty_state_change, .receiver_fn = sclp_tty_receiver };
drivers/s390/char/sclp_vt220.c +4 -4
@@ -99,8 +99,8 @@/* Registration structure for our interest in SCLP event buffers */ static struct sclp_register sclp_vt220_register = { - .send_mask = EvTyp_VT220Msg_Mask, - .receive_mask = EvTyp_VT220Msg_Mask, + .send_mask =EVTYP_VT220MSG_MASK , + .receive_mask =EVTYP_VT220MSG_MASK , .state_change_fn =NULL , .receiver_fn = sclp_vt220_receiver_fn };
@@ -202,7 +202,7 @@static int __sclp_vt220_emit (struct sclp_vt220_request *request) { -if (!(sclp_vt220_register.sclp_send_mask & EvTyp_VT220Msg_Mask)) { +if (!(sclp_vt220_register.sclp_send_mask &EVTYP_VT220MSG_MASK )) { request->sclp_req.status =SCLP_REQ_FAILED ;return -EIO ; }
@@ -284,7 +284,7 @@ sccb->header.length =sizeof (struct sclp_vt220_sccb ); sccb->header.function_code =SCLP_NORMAL_WRITE ; sccb->header.response_code =0x0000 ; - sccb->evbuf.type = EvTyp_VT220Msg; + sccb->evbuf.type =EVTYP_VT220MSG ; sccb->evbuf.length =sizeof (struct evbuf_header );return request;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 31/38 crypto: cleanup.
In reply to Martin SchwidefskyFrom: Jan Glauber <[email protected]>
Cleanup code and remove obsolete documentation.
---
Documentation/s390/crypto/crypto-API.txt | 79 ------------------- arch/s390/crypto/sha1_s390.c | 127 +++++++++++++++---------------- arch/s390/crypto/sha256_s390.c | 38 +++------ 3 files changed, 80 insertions(+), 164 deletions(-)
arch/s390/crypto/sha1_s390.c +64 -63
@@ -25,99 +25,100 @@*/ #include <linux/init.h> #include <linux/module.h> -#include <linux/mm.h> #include <linux/crypto.h> -#include <asm/scatterlist.h> -#include <asm/byteorder.h> +#include "crypt_s390.h" #define SHA1_DIGEST_SIZE 20#define SHA1_BLOCK_SIZE 64 -struct crypt_s390_sha1_ctx { -u64 count; +struct s390_sha1_ctx { +u64 count;/* message length */ u32 state[5 ]; -u32 buf_len; -u8 buffer[2 *SHA1_BLOCK_SIZE ]; +u8 buf[2 *SHA1_BLOCK_SIZE ]; };static void sha1_init (struct crypto_tfm *tfm) { -struct crypt_s390_sha1_ctx *ctx =crypto_tfm_ctx (tfm); - - ctx->state[0 ] =0x67452301 ; - ctx->state[1 ] =0xEFCDAB89 ; - ctx->state[2 ] =0x98BADCFE ; - ctx->state[3 ] =0x10325476 ; - ctx->state[4 ] =0xC3D2E1F0 ; +struct s390_sha1_ctx *sctx =crypto_tfm_ctx (tfm); - ctx->count =0 ; - ctx->buf_len =0 ; + sctx->state[0 ] =0x67452301 ; + sctx->state[1 ] =0xEFCDAB89 ; + sctx->state[2 ] =0x98BADCFE ; + sctx->state[3 ] =0x10325476 ; + sctx->state[4 ] =0xC3D2E1F0 ; + sctx->count =0 ; }static void sha1_update (struct crypto_tfm *tfm,const u8 *data,unsigned int len) { -struct crypt_s390_sha1_ctx *sctx; -long imd_len; - - sctx =crypto_tfm_ctx (tfm); - sctx->count += len *8 ;/* message bit length */ - -/* anything in buffer yet? -> must be completed */ -if (sctx->buf_len && (sctx->buf_len + len) >=SHA1_BLOCK_SIZE ) { -/* complete full block and hash */ -memcpy (sctx->buffer + sctx->buf_len, data, -SHA1_BLOCK_SIZE - sctx->buf_len); -crypt_s390_kimd (KIMD_SHA_1 , sctx->state, sctx->buffer, -SHA1_BLOCK_SIZE ); - data +=SHA1_BLOCK_SIZE - sctx->buf_len; - len -=SHA1_BLOCK_SIZE - sctx->buf_len; - sctx->buf_len =0 ; +struct s390_sha1_ctx *sctx =crypto_tfm_ctx (tfm); +unsigned int index; +int ret; + +/* how much is already in the buffer? */ + index = sctx->count &0x3f ; + + sctx->count += len; + +if (index + len <SHA1_BLOCK_SIZE ) + goto store; + +/* process one stored block */ +if (index) { +memcpy (sctx->buf + index, data,SHA1_BLOCK_SIZE - index); + ret =crypt_s390_kimd (KIMD_SHA_1 , sctx->state, sctx->buf, +SHA1_BLOCK_SIZE ); +BUG_ON (ret !=SHA1_BLOCK_SIZE ); + data +=SHA1_BLOCK_SIZE - index; + len -=SHA1_BLOCK_SIZE - index; } -/* rest of data contains full blocks? */ - imd_len = len & ~0x3ful ; -if (imd_len) { -crypt_s390_kimd (KIMD_SHA_1 , sctx->state, data, imd_len); - data += imd_len; - len -= imd_len; - } -/* anything left? store in buffer */ -if (len) { -memcpy (sctx->buffer + sctx->buf_len , data, len); - sctx->buf_len += len; +/* process as many blocks as possible */ +if (len >=SHA1_BLOCK_SIZE ) { + ret =crypt_s390_kimd (KIMD_SHA_1 , sctx->state, data, + len & ~(SHA1_BLOCK_SIZE -1 )); +BUG_ON (ret != (len & ~(SHA1_BLOCK_SIZE -1 ))); + data += ret; + len -= ret; } -} +store: +/* anything left? */ +if (len) +memcpy (sctx->buf + index , data, len); +} -static void pad_message (struct crypt_s390_sha1_ctx * sctx) +/* Add padding and return the message digest. */ +static void sha1_final (struct crypto_tfm *tfm,u8 *out) { -int index; +struct s390_sha1_ctx *sctx =crypto_tfm_ctx (tfm); +u64 bits; +unsigned int index, end; +int ret; + +/* must perform manual padding */ + index = sctx->count &0x3f ; + end = (index <56 ) ?SHA1_BLOCK_SIZE : (2 *SHA1_BLOCK_SIZE ); - index = sctx->buf_len; - sctx->buf_len = (sctx->buf_len <56 ) ? -SHA1_BLOCK_SIZE :2 *SHA1_BLOCK_SIZE ;/* start pad with 1 */ - sctx->buffer[index] =0x80 ; + sctx->buf[index] =0x80 ; +/* pad with zeros */ index++; -memset (sctx->buffer + index,0x00 , sctx->buf_len - index); -/* append length */ -memcpy (sctx->buffer + sctx->buf_len -8 , &sctx->count, -sizeof sctx->count); -} +memset (sctx->buf + index,0x00 , end - index -8 ); -/* Add padding and return the message digest. */ -static void sha1_final (struct crypto_tfm *tfm,u8 *out) -{ -struct crypt_s390_sha1_ctx *sctx =crypto_tfm_ctx (tfm); +/* append message length */ + bits = sctx->count *8 ; +memcpy (sctx->buf + end -8 , &bits,sizeof (bits)); + + ret =crypt_s390_kimd (KIMD_SHA_1 , sctx->state, sctx->buf, end); +BUG_ON (ret != end); -/* must perform manual padding */ -pad_message (sctx); -crypt_s390_kimd (KIMD_SHA_1 , sctx->state, sctx->buffer, sctx->buf_len);/* copy digest to out */ memcpy (out, sctx->state,SHA1_DIGEST_SIZE ); +/* wipe context */ memset (sctx,0 ,sizeof *sctx); }
@@ -128,7 +129,7 @@ .cra_priority = CRYPT_S390_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST, .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_sha1_ctx), + .cra_ctxsize = sizeof(struct s390_sha1_ctx), .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .digest = {
arch/s390/crypto/sha256_s390.c +16 -22
@@ -26,7 +26,7 @@#define SHA256_BLOCK_SIZE 64struct s390_sha256_ctx { -u64 count; +u64 count;/* message length */ u32 state[8 ];u8 buf[2 *SHA256_BLOCK_SIZE ]; };
@@ -54,10 +54,9 @@int ret;/* how much is already in the buffer? */ - index = sctx->count /8 &0x3f ; + index = sctx->count &0x3f ; -/* update message bit length */ - sctx->count += len *8 ; + sctx->count += len;if ((index + len) <SHA256_BLOCK_SIZE ) goto store;
@@ -87,12 +86,17 @@memcpy (sctx->buf + index , data, len); } -static void pad_message (struct s390_sha256_ctx * sctx) +/* Add padding and return the message digest */ +static void sha256_final (struct crypto_tfm *tfm,u8 *out) { -int index, end; +struct s390_sha256_ctx *sctx =crypto_tfm_ctx (tfm); +u64 bits; +unsigned int index, end; +int ret; - index = sctx->count /8 &0x3f ; - end = index <56 ?SHA256_BLOCK_SIZE :2 *SHA256_BLOCK_SIZE ; +/* must perform manual padding */ + index = sctx->count &0x3f ; + end = (index <56 ) ?SHA256_BLOCK_SIZE : (2 *SHA256_BLOCK_SIZE );/* start pad with 1 */ sctx->buf[index] =0x80 ;
@@ -102,21 +106,11 @@memset (sctx->buf + index,0x00 , end - index -8 );/* append message length */ -memcpy (sctx->buf + end -8 , &sctx->count,sizeof sctx->count); - - sctx->count = end *8 ; -} - -/* Add padding and return the message digest */ -static void sha256_final (struct crypto_tfm *tfm,u8 *out) -{ -struct s390_sha256_ctx *sctx =crypto_tfm_ctx (tfm); - -/* must perform manual padding */ -pad_message (sctx); + bits = sctx->count *8 ; +memcpy (sctx->buf + end -8 , &bits,sizeof (bits)); -crypt_s390_kimd (KIMD_SHA_256 , sctx->state, sctx->buf, - sctx->count /8 ); + ret =crypt_s390_kimd (KIMD_SHA_256 , sctx->state, sctx->buf, end); +BUG_ON (ret != end);/* copy digest to out */ memcpy (out, sctx->state,SHA256_DIGEST_SIZE );
Documentation/s390/crypto/crypto-API.txt deleted +0 -83
83 lines not on this page · raw message
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 32/38 vtime: cleanup per_cpu usage.
In reply to Martin SchwidefskyFrom: Jan Glauber <[email protected]>
Replace per_cpu(... , smp_processor_id()) with __get_cpu_var()
---
arch/s390/kernel/vtime.c | 16 +++++++--------- 1 files changed, 7 insertions(+), 9 deletions(-)
arch/s390/kernel/vtime.c +7 -9
@@ -128,7 +128,7 @@ S390_lowcore.last_update_timer = expires;/* store expire time for this CPU timer */ - per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires; + __get_cpu_var(virt_cpu_timer).to_expire = expires; }#else static inline void set_vtimer (__u64 expires)
@@ -137,7 +137,7 @@ asmvolatile ("SPT %0" : :"m" (S390_lowcore.last_update_timer));/* store expire time for this CPU timer */ - per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires; + __get_cpu_var(virt_cpu_timer).to_expire = expires; }#endif
@@ -145,7 +145,7 @@ {struct vtimer_queue *vt_list; - vt_list = &per_cpu (virt_cpu_timer,smp_processor_id ()); + vt_list = &__get_cpu_var (virt_cpu_timer);/* CPU timer interrupt is pending, don't reprogramm it */ if (vt_list->idle &1LL <<63 )
@@ -159,7 +159,7 @@ {struct vtimer_queue *vt_list; - vt_list = &per_cpu (virt_cpu_timer,smp_processor_id ()); + vt_list = &__get_cpu_var (virt_cpu_timer);/* nothing to do */ if (list_empty (&vt_list->list)) {
@@ -219,7 +219,7 @@if (list_empty (cb_list))return ; - vt_list = &per_cpu (virt_cpu_timer,smp_processor_id ()); + vt_list = &__get_cpu_var (virt_cpu_timer);list_for_each_entry_safe (event, tmp, cb_list, entry) { fn = event->function;
@@ -244,7 +244,6 @@*/ static void do_cpu_timer_interrupt (__u16 error_code) { -int cpu;__u64 next, delta;struct vtimer_queue *vt_list;struct vtimer_list *event, *tmp;
@@ -253,8 +252,7 @@struct list_head cb_list;INIT_LIST_HEAD (&cb_list); - cpu =smp_processor_id (); - vt_list = &per_cpu (virt_cpu_timer, cpu); + vt_list = &__get_cpu_var (virt_cpu_timer);/* walk timer list, fire all expired events */ spin_lock (&vt_list->lock);
@@ -534,7 +532,7 @@/* enable cpu timer interrupts */ __ctl_set_bit (0 ,10 ); - vt_list = &per_cpu (virt_cpu_timer,smp_processor_id ()); + vt_list = &__get_cpu_var (virt_cpu_timer);INIT_LIST_HEAD (&vt_list->list);spin_lock_init (&vt_list->lock); vt_list->to_expire =0 ;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 33/38 Processor degradation notification.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
Generate uevents for all cpus if cpu capability changes. This can happen e.g. because the cpus are overheating. The cpu capability can be read via /sys/devices/system/cpu/cpuN/capability.
---
arch/s390/kernel/smp.c | 48 ++++++++++++++++++++++--- drivers/s390/char/Makefile | 2 - drivers/s390/char/sclp.h | 2 + drivers/s390/char/sclp_config.c | 75 ++++++++++++++++++++++++++++++++++++++++ drivers/s390/sysinfo.c | 18 +++++++++ include/asm-s390/processor.h | 1 6 files changed, 140 insertions(+), 6 deletions(-)
arch/s390/kernel/smp.c +43 -5
@@ -821,19 +821,57 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices); +static ssize_t show_capability (struct sys_device *dev,char *buf) +{ +unsigned int capability; +int rc; + + rc =get_cpu_capability (&capability); +if (rc) +return rc; +return sprintf (buf,"%u\n" , capability); +} +static SYSDEV_ATTR(capability, 0444, show_capability, NULL); + +static int __cpuinit smp_cpu_notify (struct notifier_block *self, +unsigned long action,void *hcpu) +{ +unsigned int cpu = (unsigned int )(long )hcpu; +struct cpu *c = &per_cpu (cpu_devices, cpu); +struct sys_device *s = &c->sysdev; + +switch (action) { +case CPU_ONLINE : +if (sysdev_create_file (s, &attr_capability)) +return NOTIFY_BAD ; +break ; +case CPU_DEAD : +sysdev_remove_file (s, &attr_capability); +break ; + } +return NOTIFY_OK ; +} + +static struct notifier_block __cpuinitdata smp_cpu_nb = { + .notifier_call = smp_cpu_notify, +}; +static int __init topology_init (void ) {int cpu; -int ret; + +register_cpu_notifier (&smp_cpu_nb);for_each_possible_cpu (cpu) {struct cpu *c = &per_cpu (cpu_devices, cpu); +struct sys_device *s = &c->sysdev; c->hotpluggable =1 ; - ret =register_cpu (c, cpu); -if (ret) -printk (KERN_WARNING "topology_init: register_cpu %d " -"failed (%d)\n" , cpu, ret); +register_cpu (c, cpu); +if (!cpu_online (cpu)) +continue ; + s = &c->sysdev; +sysdev_create_file (s, &attr_capability); }return 0 ; }
drivers/s390/char/Makefile +1 -1
@@ -3,7 +3,7 @@ # obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ - sclp_info.o sclp_chp.o + sclp_info.o sclp_config.o sclp_chp.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
drivers/s390/char/sclp_config.c new file +75 -0
75 lines not on this page · raw message
drivers/s390/char/sclp.h +2 -0
@@ -27,6 +27,7 @@#define EVTYP_CNTLPROGIDENT 0x0B#define EVTYP_SIGQUIESCE 0x1D#define EVTYP_VT220MSG 0x1A +#define EVTYP_CONFMGMDATA 0x04#define EVTYP_SDIAS 0x1C#define EVTYP_OPCMD_MASK 0x80000000
@@ -37,6 +38,7 @@#define EVTYP_CTLPROGIDENT_MASK 0x00200000#define EVTYP_SIGQUIESCE_MASK 0x00000008#define EVTYP_VT220MSG_MASK 0x00000040 +#define EVTYP_CONFMGMDATA_MASK 0x10000000#define EVTYP_SDIAS_MASK 0x00000010#define GNRLMSGFLGS_DOM 0x8000
drivers/s390/sysinfo.c +18 -0
@@ -357,6 +357,24 @@__initcall (create_proc_sysinfo); +int get_cpu_capability (unsigned int *capability) +{ +struct sysinfo_1_2_2 *info; +int rc; + + info = (void *)get_zeroed_page (GFP_KERNEL ); +if (!info) +return -ENOMEM ; + rc =stsi (info,1 ,2 ,2 ); +if (rc == -ENOSYS ) + goto out; + rc =0 ; + *capability = info->capability; +out: +free_page ((unsigned long ) info); +return rc; +} +/* * CPU capability might have changed. Therefore recalculate loops_per_jiffy. */
include/asm-s390/processor.h +1 -0
@@ -57,6 +57,7 @@extern void s390_adjust_jiffies (void );extern void print_cpu_info (struct cpuinfo_S390 *); +extern int get_cpu_capability (unsigned int *);/* Lazy FPU handling on uni-processor */ extern struct task_struct *last_task_used_math;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 34/38 split page_test_and_clear_dirty.
In reply to Martin SchwidefskyFrom: Martin Schwidefsky <[email protected]>
The page_test_and_clear_dirty primitive really consists of two operations, page_test_dirty and the page_clear_dirty. The combination of the two is not an atomic operation, so it makes more sense to have two separate operations instead of one.
In addition to the improved readability of the s390 version of SetPageUptodate, it now avoids the page_test_dirty operation which is an insert-storage-key-extended (iske) instruction which is an expensive operation.
---
include/asm-generic/pgtable.h | 11 +++++++++-- include/asm-s390/pgtable.h | 15 ++++++++------- include/linux/page-flags.h | 2 +- mm/rmap.c | 8 ++++++-- 4 files changed, 24 insertions(+), 12 deletions(-)
include/asm-generic/pgtable.h +9 -2
@@ -139,8 +139,15 @@#define pte_same (A ,B ) (pte_val(A) == pte_val(B))#endif -#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY -#define page_test_and_clear_dirty (page) (0) +#ifndef __HAVE_ARCH_PAGE_TEST_DIRTY +#define page_test_dirty (page) (0) +#endif + +#ifndef __HAVE_ARCH_PAGE_CLEAR_DIRTY +#define page_clear_dirty (page) do { } while (0) +#endif + +#ifndef __HAVE_ARCH_PAGE_TEST_DIRTY#define pte_maybe_dirty (pte) pte_dirty(pte)#else #define pte_maybe_dirty (pte) (1)
include/asm-s390/pgtable.h +8 -7
@@ -753,14 +753,14 @@* should therefore only be called if it is not mapped in any * address space. */ -static inline int page_test_and_clear_dirty (struct page *page) +static inline int page_test_dirty (struct page *page) { -unsigned long physpage =page_to_phys (page); -int skey =page_get_storage_key (physpage); +return (page_get_storage_key (page_to_phys (page)) & _PAGE_CHANGED) !=0 ; +} -if (skey & _PAGE_CHANGED) -page_set_storage_key (physpage, skey & ~_PAGE_CHANGED); -return skey & _PAGE_CHANGED; +static inline void page_clear_dirty (struct page *page) +{ +page_set_storage_key (page_to_phys (page),PAGE_DEFAULT_KEY ); }/*
@@ -953,7 +953,8 @@#define __HAVE_ARCH_PTEP_CLEAR_FLUSH#define __HAVE_ARCH_PTEP_SET_WRPROTECT#define __HAVE_ARCH_PTE_SAME -#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY +#define __HAVE_ARCH_PAGE_TEST_DIRTY +#define __HAVE_ARCH_PAGE_CLEAR_DIRTY#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG#include <asm-generic/pgtable.h>
include/linux/page-flags.h +1 -1
@@ -133,7 +133,7 @@static inline void SetPageUptodate (struct page *page) {if (!test_and_set_bit (PG_uptodate, &page->flags)) -page_test_and_clear_dirty (page); +page_clear_dirty (page); }#else #define SetPageUptodate (page) set_bit(PG_uptodate, &(page)->flags)
mm/rmap.c +6 -2
@@ -498,8 +498,10 @@struct address_space *mapping =page_mapping (page);if (mapping) ret =page_mkclean_file (mapping, page); -if (page_test_and_clear_dirty (page)) +if (page_test_dirty (page)) { +page_clear_dirty (page); ret =1 ; + } }return ret;
@@ -605,8 +607,10 @@* Leaving it set also helps swapoff to reinstate ptes * faster for those pages still in swapcache. */ -if (page_test_and_clear_dirty (page)) +if (page_test_dirty (page)) { +page_clear_dirty (page);set_page_dirty (page); + }__dec_zone_page_state (page,PageAnon (page) ?NR_ANON_PAGES :NR_FILE_MAPPED ); }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 35/38 Switch etr from tasklet to workqueue.
In reply to Martin SchwidefskyFrom: Martin Schwidefsky <[email protected]>
The clock synchronization of the ETR code requires an smp_call_function to synchronize all cpus. Calling smp_call_function from a tasklet is illegal. Replace the tasklet with a job on the global workqueue. ETR work is rare and can be postponed to a be done by a kernel thread.
---
arch/s390/kernel/time.c | 34 +++++++++++++++++----------------- 1 files changed, 17 insertions(+), 17 deletions(-)
arch/s390/kernel/time.c +17 -17
@@ -280,7 +280,6 @@ }static void etr_reset (void ); -static void etr_init (void );static void etr_ext_handler (__u16 );/*
@@ -355,7 +354,6 @@#ifdef CONFIG_VIRT_TIMER vtime_init ();#endif -etr_init (); }/*
@@ -426,11 +424,11 @@static int etr_port1_uptodate;static unsigned long etr_events;static struct timer_list etr_timer; -static struct tasklet_struct etr_tasklet; static DEFINE_PER_CPU(atomic_t, etr_sync_word);static void etr_timeout (unsigned long dummy); -static void etr_tasklet_fn (unsigned long dummy); +static void etr_work_fn (struct work_struct *work); +static DECLARE_WORK(etr_work, etr_work_fn);/* * The etr get_clock function. It will write the current clock value
@@ -507,29 +505,31 @@ } } -static void etr_init (void ) +static int __init etr_init (void ) {struct etr_aib aib;if (test_bit (ETR_FLAG_ENOSYS , &etr_flags)) -return ; +return 0 ;/* Check if this machine has the steai instruction. */ if (etr_steai (&aib,ETR_STEAI_STEPPING_PORT ) ==0 )set_bit (ETR_FLAG_STEAI , &etr_flags);setup_timer (&etr_timer, etr_timeout,0UL ); -tasklet_init (&etr_tasklet, etr_tasklet_fn,0 );if (!etr_port0_online && !etr_port1_online)set_bit (ETR_FLAG_EACCES , &etr_flags);if (etr_port0_online) {set_bit (ETR_EVENT_PORT0_CHANGE , &etr_events); -tasklet_hi_schedule (&etr_tasklet); +schedule_work (&etr_work); }if (etr_port1_online) {set_bit (ETR_EVENT_PORT1_CHANGE , &etr_events); -tasklet_hi_schedule (&etr_tasklet); +schedule_work (&etr_work); } +return 0 ; } +arch_initcall (etr_init); +/* * Two sorts of ETR machine checks. The architecture reads: * "When a machine-check niterruption occurs and if a switch-to-local or
@@ -549,7 +549,7 @@return ;etr_disable_sync_clock (NULL );set_bit (ETR_EVENT_SWITCH_LOCAL , &etr_events); -tasklet_hi_schedule (&etr_tasklet); +schedule_work (&etr_work); }/*
@@ -564,7 +564,7 @@return ;etr_disable_sync_clock (NULL );set_bit (ETR_EVENT_SYNC_CHECK , &etr_events); -tasklet_hi_schedule (&etr_tasklet); +schedule_work (&etr_work); }/*
@@ -591,13 +591,13 @@* Both ports are not up-to-date now. */ set_bit (ETR_EVENT_PORT_ALERT , &etr_events); -tasklet_hi_schedule (&etr_tasklet); +schedule_work (&etr_work); }static void etr_timeout (unsigned long dummy) {set_bit (ETR_EVENT_UPDATE , &etr_events); -tasklet_hi_schedule (&etr_tasklet); +schedule_work (&etr_work); }/*
@@ -927,7 +927,7 @@if (!eacr.e0 && !eacr.e1)return eacr; -/* Update port0 or port1 with aib stored in etr_tasklet_fn. */ +/* Update port0 or port1 with aib stored in etr_work_fn. */ if (aib->esw.q ==0 ) {/* Information for port 0 stored. */ if (eacr.p0 && !etr_port0_uptodate) {
@@ -1007,7 +1007,7 @@* particular this is the only function that calls etr_update_eacr(), * it "controls" the etr control register. */ -static void etr_tasklet_fn (unsigned long dummy) +static void etr_work_fn (struct work_struct *work) {unsigned long long now;struct etr_eacr eacr;
@@ -1220,13 +1220,13 @@return count;/* Nothing to do. */ etr_port0_online = value;set_bit (ETR_EVENT_PORT0_CHANGE , &etr_events); -tasklet_hi_schedule (&etr_tasklet); +schedule_work (&etr_work); }else {if (etr_port1_online == value)return count;/* Nothing to do. */ etr_port1_online = value;set_bit (ETR_EVENT_PORT1_CHANGE , &etr_events); -tasklet_hi_schedule (&etr_tasklet); +schedule_work (&etr_work); }return count; }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 36/38 Remove debugging junk.
In reply to Martin SchwidefskyFrom: Martin Schwidefsky <[email protected]>
arch/s390/appldata/appldata_base.c has some confusing debugging code left over to allow compiling it as a module. In practice, it cannot be configured as module and there is no need to keep that code.
---
arch/s390/appldata/appldata_base.c | 38 ------------------------------------- 1 files changed, 38 deletions(-)
arch/s390/appldata/appldata_base.c +0 -38
@@ -668,45 +668,7 @@EXPORT_SYMBOL_GPL (appldata_unregister_ops);EXPORT_SYMBOL_GPL (appldata_diag); -#ifdef MODULE -/* -* Kernel symbols needed by appldata_mem and appldata_os modules. -* However, if this file is compiled as a module (for testing only), these -* symbols are not exported. In this case, we define them locally and export -* those. -*/ -void si_swapinfo (struct sysinfo *val) -{ - val->freeswap =-1ul ; - val->totalswap =-1ul ; -} - -unsigned long avenrun[3 ] = {-1 -FIXED_1 /200 ,-1 -FIXED_1 /200 , --1 -FIXED_1 /200 }; -int nr_threads =-1 ; - -void get_full_page_state (struct page_state *ps) -{ -memset (ps,-1 ,sizeof (struct page_state )); -} - -unsigned long nr_running (void ) -{ -return -1 ; -} - -unsigned long nr_iowait (void ) -{ -return -1 ; -} - -/*unsigned long nr_context_switches(void) -{ -return -1; -}*/ -#endif /* MODULE */ EXPORT_SYMBOL_GPL (si_swapinfo);EXPORT_SYMBOL_GPL (nr_threads);EXPORT_SYMBOL_GPL (nr_running);EXPORT_SYMBOL_GPL (nr_iowait); -//EXPORT_SYMBOL_GPL(nr_context_switches);
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 37/38 Clean up smp code in preparation for some larger changes.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
---
arch/s390/kernel/smp.c | 259 ++++++++++++++++++------------------------------- include/asm-s390/smp.h | 5 2 files changed, 99 insertions(+), 165 deletions(-)
arch/s390/kernel/smp.c +99 -160
@@ -1,12 +1,12 @@/* * arch/s390/kernel/smp.c * -* Copyright (C) IBM Corp. 1999,2006 +* Copyright IBM Corp. 1999,2007 * Author(s): Denis Joseph Barrow ([email protected],[email protected]), -* Martin Schwidefsky ([email protected]) -* Heiko Carstens ([email protected]) +* Martin Schwidefsky ([email protected]) +* Heiko Carstens ([email protected]) * -* based on other smp stuff by +* based on other smp stuff by * (c) 1995 Alan Cox, CymruNET Ltd <[email protected]> * (c) 1998 Ingo Molnar *
@@ -43,16 +43,17 @@#include <asm/timer.h> #include <asm/lowcore.h> -extern volatile int __cpu_logical_map[]; -/* * An array with a pointer the lowcore of every CPU. */ -struct _lowcore *lowcore_ptr[NR_CPUS ]; +EXPORT_SYMBOL (lowcore_ptr);cpumask_t cpu_online_map =CPU_MASK_NONE ; +EXPORT_SYMBOL (cpu_online_map); +cpumask_t cpu_possible_map =CPU_MASK_NONE ; +EXPORT_SYMBOL (cpu_possible_map);static struct task_struct *current_set[NR_CPUS ];
@@ -72,7 +73,7 @@int wait; }; -static struct call_data_struct * call_data; +static struct call_data_struct *call_data;/* * 'Call function' interrupt callback
@@ -152,8 +153,8 @@* * Run a function on all other CPUs. * -* You must not call this function with disabled interrupts or from a -* hardware interrupt handler. You may call it from a bottom half. +* You must not call this function with disabled interrupts, from a +* hardware interrupt handler or from a bottom half. */ int smp_call_function (void (*func) (void *info),void *info,int nonatomic,int wait)
@@ -179,11 +180,11 @@* * Run a function on one processor. * -* You must not call this function with disabled interrupts or from a -* hardware interrupt handler. You may call it from a bottom half. +* You must not call this function with disabled interrupts, from a +* hardware interrupt handler or from a bottom half. */ int smp_call_function_on (void (*func) (void *info),void *info,int nonatomic, -int wait,int cpu) +int wait,int cpu) {cpumask_t map =CPU_MASK_NONE ;
@@ -197,9 +198,9 @@static void do_send_stop (void ) { -int cpu, rc; +int cpu, rc; -/* stop all processors */ +/* stop all processors */ for_each_online_cpu (cpu) {if (cpu ==smp_processor_id ())continue ;
@@ -211,9 +212,9 @@static void do_store_status (void ) { -int cpu, rc; +int cpu, rc; -/* store status of all processors in their lowcores (real 0) */ +/* store status of all processors in their lowcores (real 0) */ for_each_online_cpu (cpu) {if (cpu ==smp_processor_id ())continue ;
@@ -221,8 +222,8 @@ rc =signal_processor_p ( (__u32 )(unsigned long ) lowcore_ptr[cpu], cpu, sigp_store_status_at_address); - }while (rc == sigp_busy); - } + }while (rc == sigp_busy); + } }static void do_wait_for_stop (void )
@@ -233,7 +234,7 @@for_each_online_cpu (cpu) {if (cpu ==smp_processor_id ())continue ; -while (!smp_cpu_not_running (cpu)) +while (!smp_cpu_not_running (cpu))cpu_relax (); } }
@@ -247,7 +248,7 @@/* Disable all interrupts/machine checks */ __load_psw_mask (psw_kernel_bits & ~PSW_MASK_MCHECK ); -/* write magic number to zero page (absolute 0) */ +/* write magic number to zero page (absolute 0) */ lowcore_ptr[smp_processor_id ()]->panic_magic = __PANIC_MAGIC;/* stop other processors. */
@@ -263,8 +264,7 @@/* * Reboot, halt and power_off routines for SMP. */ - -void machine_restart_smp (char * __unused) +void machine_restart_smp (char *__unused) {smp_send_stop ();do_reipl ();
@@ -295,17 +295,17 @@static void do_ext_call_interrupt (__u16 code) { -unsigned long bits; +unsigned long bits; -/* -* handle bit signal external calls -* -* For the ec_schedule signal we have to do nothing. All the work -* is done automatically when we return from the interrupt. -*/ +/* +* handle bit signal external calls +* +* For the ec_schedule signal we have to do nothing. All the work +* is done automatically when we return from the interrupt. +*/ bits =xchg (&S390_lowcore.ext_call_fast,0 ); -if (test_bit (ec_call_function, &bits)) +if (test_bit (ec_call_function, &bits))do_call_function (); }
@@ -315,11 +315,11 @@*/ static void smp_ext_bitcall (int cpu,ec_bit_sig sig) { -/* -* Set signaling bit in lowcore of target cpu and kick it -*/ +/* +* Set signaling bit in lowcore of target cpu and kick it +*/ set_bit (sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast); -while (signal_processor (cpu, sigp_emergency_signal) == sigp_busy) +while (signal_processor (cpu, sigp_emergency_signal) == sigp_busy)udelay (10 ); }
@@ -334,7 +334,7 @@void smp_ptlb_all (void ) { -on_each_cpu (smp_ptlb_callback,NULL ,0 ,1 ); +on_each_cpu (smp_ptlb_callback,NULL ,0 ,1 ); }EXPORT_SYMBOL (smp_ptlb_all);#endif /* ! CONFIG_64BIT */
@@ -346,7 +346,7 @@*/ void smp_send_reschedule (int cpu) { -smp_ext_bitcall (cpu, ec_schedule); +smp_ext_bitcall (cpu, ec_schedule); }/*
@@ -360,11 +360,12 @@/* * callback for setting/clearing control bits */ -static void smp_ctl_bit_callback (void *info) { +static void smp_ctl_bit_callback (void *info) +{struct ec_creg_mask_parms *pp = info;unsigned long cregs[16 ];int i; - +__ctl_store (cregs,0 ,15 );for (i =0 ; i <=15 ; i++) cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
@@ -383,6 +384,7 @@ parms.orvals[cr] =1 << bit;on_each_cpu (smp_ctl_bit_callback, &parms,0 ,1 ); } +EXPORT_SYMBOL (smp_ctl_set_bit);/* * Clear a bit in a control register of all cpus
@@ -396,6 +398,7 @@ parms.andvals[cr] = ~(1L << bit);on_each_cpu (smp_ctl_bit_callback, &parms,0 ,1 ); } +EXPORT_SYMBOL (smp_ctl_clear_bit);#if defined(CONFIG_ZFCPDUMP ) || defined(CONFIG_ZFCPDUMP_MODULE )
@@ -460,8 +463,7 @@* Lets check how many CPUs we have. */ -static unsigned int -__init smp_count_cpus (void ) +static unsigned int __init smp_count_cpus (void ) {unsigned int cpu, num_cpus;__u16 boot_cpu_addr;
@@ -477,31 +479,30 @@if ((__u16 ) cpu == boot_cpu_addr)continue ; __cpu_logical_map[1 ] = (__u16 ) cpu; -if (signal_processor (1 , sigp_sense) == - sigp_not_operational) +if (signal_processor (1 , sigp_sense) == sigp_not_operational)continue ; num_cpus++; } -printk ("Detected %d CPU's\n" ,(int ) num_cpus); +printk ("Detected %d CPU's\n" , (int ) num_cpus);printk ("Boot cpu address %2X\n" , boot_cpu_addr);return num_cpus; }/* -* Activate a secondary processor. +* Activate a secondary processor. */ int __devinit start_secondary (void *cpuvoid) { -/* Setup the cpu */ -cpu_init (); +/* Setup the cpu */ +cpu_init ();preempt_disable ();/* Enable TOD clock interrupts on the secondary cpu. */ -init_cpu_timer (); +init_cpu_timer ();#ifdef CONFIG_VIRT_TIMER /* Enable cpu timer interrupts on the secondary cpu. */ -init_cpu_vtimer (); +init_cpu_vtimer ();#endif /* Enable pfault pseudo page faults on this cpu. */ pfault_init ();
@@ -510,11 +511,11 @@cpu_set (smp_processor_id (), cpu_online_map);/* Switch on interrupts */ local_irq_enable (); -/* Print info about this processor */ -print_cpu_info (&S390_lowcore.cpu_data); -/* cpu_idle will call schedule for us */ -cpu_idle (); -return 0 ; +/* Print info about this processor */ +print_cpu_info (&S390_lowcore.cpu_data); +/* cpu_idle will call schedule for us */ +cpu_idle (); +return 0 ; }static void __init smp_create_idle (unsigned int cpu)
@@ -531,56 +532,13 @@ current_set[cpu] = p; } -/* Reserving and releasing of CPUs */ - -static DEFINE_SPINLOCK (smp_reserve_lock); -static int smp_cpu_reserved[NR_CPUS ]; - -int -smp_get_cpu (cpumask_t cpu_mask) -{ -unsigned long flags; -int cpu; - -spin_lock_irqsave (&smp_reserve_lock, flags); -/* Try to find an already reserved cpu. */ -for_each_cpu_mask (cpu, cpu_mask) { -if (smp_cpu_reserved[cpu] !=0 ) { - smp_cpu_reserved[cpu]++; -/* Found one. */ - goto out; - } - } -/* Reserve a new cpu from cpu_mask. */ -for_each_cpu_mask (cpu, cpu_mask) { -if (cpu_online (cpu)) { - smp_cpu_reserved[cpu]++; - goto out; - } - } - cpu = -ENODEV ; -out: -spin_unlock_irqrestore (&smp_reserve_lock, flags); -return cpu; -} - -void -smp_put_cpu (int cpu) -{ -unsigned long flags; - -spin_lock_irqsave (&smp_reserve_lock, flags); - smp_cpu_reserved[cpu]--; -spin_unlock_irqrestore (&smp_reserve_lock, flags); -} - -static int -cpu_stopped (int cpu) +static int cpu_stopped (int cpu) {__u32 status;/* Check for stopped state */ -if (signal_processor_ps (&status,0 , cpu, sigp_sense) == sigp_status_stored) { +if (signal_processor_ps (&status,0 , cpu, sigp_sense) == + sigp_status_stored) {if (status &0x40 )return 1 ; }
@@ -589,14 +547,13 @@/* Upping and downing of CPUs */ -int -__cpu_up (unsigned int cpu) +int __cpu_up (unsigned int cpu) {struct task_struct *idle; -struct _lowcore *cpu_lowcore; +struct _lowcore *cpu_lowcore;struct stack_frame *sf; -sigp_ccode ccode; -int curr_cpu; +sigp_ccode ccode; +int curr_cpu;for (curr_cpu =0 ; curr_cpu <=65535 ; curr_cpu++) { __cpu_logical_map[cpu] = (__u16 ) curr_cpu;
@@ -609,7 +566,7 @@ ccode =signal_processor_p ((__u32 )(unsigned long )(lowcore_ptr[cpu]), cpu, sigp_set_prefix); -if (ccode){ +if (ccode) {printk ("sigp_set_prefix failed for cpu %d " "with condition code %d\n" , (int ) cpu, (int ) ccode);
@@ -617,9 +574,9 @@ } idle = current_set[cpu]; - cpu_lowcore = lowcore_ptr[cpu]; + cpu_lowcore = lowcore_ptr[cpu]; cpu_lowcore->kernel_stack = (unsigned long ) -task_stack_page (idle) + (THREAD_SIZE ); +task_stack_page (idle) +THREAD_SIZE ; sf = (struct stack_frame *) (cpu_lowcore->kernel_stack -sizeof (struct pt_regs ) -sizeof (struct stack_frame ));
@@ -631,11 +588,11 @@ " stam 0,15,0(%0)" : : "a" (&cpu_lowcore->access_regs_save_area) : "memory"); cpu_lowcore->percpu_offset = __per_cpu_offset[cpu]; - cpu_lowcore->current_task = (unsigned long ) idle; - cpu_lowcore->cpu_data.cpu_nr = cpu; + cpu_lowcore->current_task = (unsigned long ) idle; + cpu_lowcore->cpu_data.cpu_nr = cpu;eieio (); -while (signal_processor (cpu,sigp_restart) == sigp_busy) +while (signal_processor (cpu, sigp_restart) == sigp_busy)udelay (10 );while (!cpu_online (cpu))
@@ -682,18 +639,11 @@ }early_param ("possible_cpus" , setup_possible_cpus); -int -__cpu_disable (void ) +int __cpu_disable (void ) { -unsigned long flags;struct ec_creg_mask_parms cr_parms;int cpu =smp_processor_id (); -spin_lock_irqsave (&smp_reserve_lock, flags); -if (smp_cpu_reserved[cpu] !=0 ) { -spin_unlock_irqrestore (&smp_reserve_lock, flags); -return -EBUSY ; - }cpu_clear (cpu, cpu_online_map);/* Disable pfault pseudo page faults on this cpu. */
@@ -704,24 +654,23 @@/* disable all external interrupts */ cr_parms.orvals[0 ] =0 ; - cr_parms.andvals[0 ] = ~(1 <<15 |1 <<14 |1 <<13 |1 <<12 | -1 <<11 |1 <<10 |1 <<6 |1 <<4 ); + cr_parms.andvals[0 ] = ~(1 <<15 |1 <<14 |1 <<13 |1 <<12 | +1 <<11 |1 <<10 |1 <<6 |1 <<4 );/* disable all I/O interrupts */ cr_parms.orvals[6 ] =0 ; - cr_parms.andvals[6 ] = ~(1 <<31 |1 <<30 |1 <<29 |1 <<28 | -1 <<27 |1 <<26 |1 <<25 |1 <<24 ); + cr_parms.andvals[6 ] = ~(1 <<31 |1 <<30 |1 <<29 |1 <<28 | +1 <<27 |1 <<26 |1 <<25 |1 <<24 );/* disable most machine checks */ cr_parms.orvals[14 ] =0 ; - cr_parms.andvals[14 ] = ~(1 <<28 |1 <<27 |1 <<26 |1 <<25 |1 <<24 ); + cr_parms.andvals[14 ] = ~(1 <<28 |1 <<27 |1 <<26 | +1 <<25 |1 <<24 );smp_ctl_bit_callback (&cr_parms); -spin_unlock_irqrestore (&smp_reserve_lock, flags);return 0 ; } -void -__cpu_die (unsigned int cpu) +void __cpu_die (unsigned int cpu) {/* Wait until target cpu is down */ while (!smp_cpu_not_running (cpu))
@@ -729,13 +678,12 @@printk ("Processor %d spun down\n" , cpu); } -void -cpu_die (void ) +void cpu_die (void ) {idle_task_exit ();signal_processor (smp_processor_id (), sigp_stop);BUG (); -for (;;); +for (;;); }#endif /* CONFIG_HOTPLUG_CPU */
@@ -748,36 +696,36 @@ {unsigned long stack;unsigned int cpu; -int i; +int i; -/* request the 0x1201 emergency signal external interrupt */ -if (register_external_interrupt (0x1201 , do_ext_call_interrupt) !=0 ) -panic ("Couldn't request external interrupt 0x1201" ); -memset (lowcore_ptr,0 ,sizeof (lowcore_ptr)); -/* -* Initialize prefix pages and stacks for all possible cpus -*/ +/* request the 0x1201 emergency signal external interrupt */ +if (register_external_interrupt (0x1201 , do_ext_call_interrupt) !=0 ) +panic ("Couldn't request external interrupt 0x1201" ); +memset (lowcore_ptr,0 ,sizeof (lowcore_ptr)); +/* +* Initialize prefix pages and stacks for all possible cpus +*/ print_cpu_info (&S390_lowcore.cpu_data); -for_each_possible_cpu (i) { +for_each_possible_cpu (i) { lowcore_ptr[i] = (struct _lowcore *) -__get_free_pages (GFP_KERNEL |GFP_DMA , -sizeof (void *) ==8 ?1 :0 ); - stack =__get_free_pages (GFP_KERNEL ,ASYNC_ORDER ); -if (lowcore_ptr[i] ==NULL || stack ==0ULL ) +__get_free_pages (GFP_KERNEL |GFP_DMA , +sizeof (void *) ==8 ?1 :0 ); + stack =__get_free_pages (GFP_KERNEL ,ASYNC_ORDER ); +if (!lowcore_ptr[i] || !stack)panic ("smp_boot_cpus failed to allocate memory\n" ); *(lowcore_ptr[i]) = S390_lowcore; - lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE ); - stack =__get_free_pages (GFP_KERNEL ,0 ); -if (stack ==0ULL ) + lowcore_ptr[i]->async_stack = stack +ASYNC_SIZE ; + stack =__get_free_pages (GFP_KERNEL ,0 ); +if (!stack)panic ("smp_boot_cpus failed to allocate memory\n" ); - lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE ); + lowcore_ptr[i]->panic_stack = stack +PAGE_SIZE ;#ifndef CONFIG_64BIT if (MACHINE_HAS_IEEE ) { lowcore_ptr[i]->extended_save_area_addr = - (__u32 )__get_free_pages (GFP_KERNEL ,0 ); -if (lowcore_ptr[i]->extended_save_area_addr ==0 ) + (__u32 )__get_free_pages (GFP_KERNEL ,0 ); +if (!lowcore_ptr[i]->extended_save_area_addr)panic ("smp_boot_cpus failed to " "allocate memory\n" ); }
@@ -816,7 +764,7 @@*/ int setup_profiling_timer (unsigned int multiplier) { -return 0 ; +return 0 ; } static DEFINE_PER_CPU(struct cpu, cpu_devices);
@@ -853,7 +801,7 @@ }static struct notifier_block __cpuinitdata smp_cpu_nb = { - .notifier_call = smp_cpu_notify, + .notifier_call = smp_cpu_notify, };static int __init topology_init (void )
@@ -875,13 +823,4 @@ }return 0 ; } -subsys_initcall (topology_init); - -EXPORT_SYMBOL (cpu_online_map); -EXPORT_SYMBOL (cpu_possible_map); -EXPORT_SYMBOL (lowcore_ptr); -EXPORT_SYMBOL (smp_ctl_set_bit); -EXPORT_SYMBOL (smp_ctl_clear_bit); -EXPORT_SYMBOL (smp_get_cpu); -EXPORT_SYMBOL (smp_put_cpu);
include/asm-s390/smp.h +0 -5
@@ -54,9 +54,6 @@#define raw_smp_processor_id () (S390_lowcore.cpu_data.cpu_nr) -extern int smp_get_cpu (cpumask_t cpu_map); -extern void smp_put_cpu (int cpu); -static inline __u16 hard_smp_processor_id (void ) {__u16 cpu_address;
@@ -114,8 +111,6 @@ }#define smp_cpu_not_running (cpu) 1 -#define smp_get_cpu (cpu) ({ 0; }) -#define smp_put_cpu (cpu) ({ 0; })#define smp_setup_cpu_possible_map () do { } while (0)#endif
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 38/38 SPIN_LOCK_UNLOCKED cleanup in drivers/s390
In reply to Martin SchwidefskyFrom: Milind Arun Choudhary <[email protected]>
SPIN_LOCK_UNLOCKED cleanup,use __SPIN_LOCK_UNLOCKED instead.
---
drivers/s390/char/vmlogrdr.c | 6 +++--- drivers/s390/cio/cmf.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-)
drivers/s390/char/vmlogrdr.c +3 -3
@@ -125,7 +125,7 @@ .recording_name = "EREP", .minor_num = 0, .buffer_free = 1, - .priv_lock = SPIN_LOCK_UNLOCKED, + .priv_lock = __SPIN_LOCK_UNLOCKED(sys_ser[0].priv_lock), .autorecording = 1, .autopurge = 1, },
@@ -134,7 +134,7 @@ .recording_name = "ACCOUNT", .minor_num = 1, .buffer_free = 1, - .priv_lock = SPIN_LOCK_UNLOCKED, + .priv_lock = __SPIN_LOCK_UNLOCKED(sys_ser[1].priv_lock), .autorecording = 1, .autopurge = 1, },
@@ -143,7 +143,7 @@ .recording_name = "SYMPTOM", .minor_num = 2, .buffer_free = 1, - .priv_lock = SPIN_LOCK_UNLOCKED, + .priv_lock = __SPIN_LOCK_UNLOCKED(sys_ser[2].priv_lock), .autorecording = 1, .autopurge = 1, }
drivers/s390/cio/cmf.c +1 -1
@@ -476,7 +476,7 @@ };static struct cmb_area cmb_area = { - .lock =SPIN_LOCK_UNLOCKED , + .lock =__SPIN_LOCK_UNLOCKED (cmb_area.lock), .list =LIST_HEAD_INIT (cmb_area.list), .num_channels =1024 , };
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.