Loading drivers/s390/cio/chsc.c +1 −2 Original line number Diff line number Diff line Loading @@ -549,8 +549,7 @@ chsc_add_cmg_attr(struct channel_subsystem *css) return ret; } static int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) { struct { struct chsc_header request; Loading drivers/s390/cio/chsc.h +1 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ extern void chsc_free_sei_area(void); extern int chsc_enable_facility(int); struct channel_subsystem; extern int chsc_secm(struct channel_subsystem *, int); int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page); int chsc_chp_vary(struct chp_id chpid, int on); int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, Loading drivers/s390/cio/css.c +152 −5 Original line number Diff line number Diff line /* * drivers/s390/cio/css.c * driver for channel subsystem * * Copyright IBM Corp. 2002,2008 * Copyright IBM Corp. 2002, 2009 * * Author(s): Arnd Bergmann (arndb@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) */ Loading @@ -17,6 +17,7 @@ #include <linux/errno.h> #include <linux/list.h> #include <linux/reboot.h> #include <linux/suspend.h> #include <asm/isc.h> #include <asm/crw.h> Loading Loading @@ -779,6 +780,79 @@ static struct notifier_block css_reboot_notifier = { .notifier_call = css_reboot_event, }; /* * Since the css devices are neither on a bus nor have a class * nor have a special device type, we cannot stop/restart channel * path measurements via the normal suspend/resume callbacks, but have * to use notifiers. */ static int css_power_event(struct notifier_block *this, unsigned long event, void *ptr) { void *secm_area; int ret, i; switch (event) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: ret = NOTIFY_DONE; for (i = 0; i <= __MAX_CSSID; i++) { struct channel_subsystem *css; css = channel_subsystems[i]; mutex_lock(&css->mutex); if (!css->cm_enabled) { mutex_unlock(&css->mutex); continue; } secm_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (secm_area) { if (__chsc_do_secm(css, 0, secm_area)) ret = NOTIFY_BAD; free_page((unsigned long)secm_area); } else ret = NOTIFY_BAD; mutex_unlock(&css->mutex); } break; case PM_POST_HIBERNATION: case PM_POST_SUSPEND: ret = NOTIFY_DONE; for (i = 0; i <= __MAX_CSSID; i++) { struct channel_subsystem *css; css = channel_subsystems[i]; mutex_lock(&css->mutex); if (!css->cm_enabled) { mutex_unlock(&css->mutex); continue; } secm_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (secm_area) { if (__chsc_do_secm(css, 1, secm_area)) ret = NOTIFY_BAD; free_page((unsigned long)secm_area); } else ret = NOTIFY_BAD; mutex_unlock(&css->mutex); } /* search for subchannels, which appeared during hibernation */ css_schedule_reprobe(); break; default: ret = NOTIFY_DONE; } return ret; } static struct notifier_block css_power_notifier = { .notifier_call = css_power_event, }; /* * Now that the driver core is running, we can setup our channel subsystem. * The struct subchannel's are created during probing (except for the Loading Loading @@ -852,6 +926,11 @@ init_channel_subsystem (void) ret = register_reboot_notifier(&css_reboot_notifier); if (ret) goto out_unregister; ret = register_pm_notifier(&css_power_notifier); if (ret) { unregister_reboot_notifier(&css_reboot_notifier); goto out_unregister; } css_init_done = 1; /* Enable default isc for I/O subchannels. */ Loading Loading @@ -953,6 +1032,73 @@ static int css_uevent(struct device *dev, struct kobj_uevent_env *env) return ret; } static int css_pm_prepare(struct device *dev) { struct subchannel *sch = to_subchannel(dev); struct css_driver *drv; if (mutex_is_locked(&sch->reg_mutex)) return -EAGAIN; if (!sch->dev.driver) return 0; drv = to_cssdriver(sch->dev.driver); /* Notify drivers that they may not register children. */ return drv->prepare ? drv->prepare(sch) : 0; } static void css_pm_complete(struct device *dev) { struct subchannel *sch = to_subchannel(dev); struct css_driver *drv; if (!sch->dev.driver) return; drv = to_cssdriver(sch->dev.driver); if (drv->complete) drv->complete(sch); } static int css_pm_freeze(struct device *dev) { struct subchannel *sch = to_subchannel(dev); struct css_driver *drv; if (!sch->dev.driver) return 0; drv = to_cssdriver(sch->dev.driver); return drv->freeze ? drv->freeze(sch) : 0; } static int css_pm_thaw(struct device *dev) { struct subchannel *sch = to_subchannel(dev); struct css_driver *drv; if (!sch->dev.driver) return 0; drv = to_cssdriver(sch->dev.driver); return drv->thaw ? drv->thaw(sch) : 0; } static int css_pm_restore(struct device *dev) { struct subchannel *sch = to_subchannel(dev); struct css_driver *drv; if (!sch->dev.driver) return 0; drv = to_cssdriver(sch->dev.driver); return drv->restore ? drv->restore(sch) : 0; } static struct dev_pm_ops css_pm_ops = { .prepare = css_pm_prepare, .complete = css_pm_complete, .freeze = css_pm_freeze, .thaw = css_pm_thaw, .restore = css_pm_restore, }; struct bus_type css_bus_type = { .name = "css", .match = css_bus_match, Loading @@ -960,6 +1106,7 @@ struct bus_type css_bus_type = { .remove = css_remove, .shutdown = css_shutdown, .uevent = css_uevent, .pm = &css_pm_ops, }; /** Loading drivers/s390/cio/css.h +10 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,11 @@ struct chp_link; * @probe: function called on probe * @remove: function called on remove * @shutdown: called at device shutdown * @prepare: prepare for pm state transition * @complete: undo work done in @prepare * @freeze: callback for freezing during hibernation snapshotting * @thaw: undo work done in @freeze * @restore: callback for restoring after hibernation * @name: name of the device driver */ struct css_driver { Loading @@ -82,6 +87,11 @@ struct css_driver { int (*probe)(struct subchannel *); int (*remove)(struct subchannel *); void (*shutdown)(struct subchannel *); int (*prepare) (struct subchannel *); void (*complete) (struct subchannel *); int (*freeze)(struct subchannel *); int (*thaw) (struct subchannel *); int (*restore)(struct subchannel *); const char *name; }; Loading Loading
drivers/s390/cio/chsc.c +1 −2 Original line number Diff line number Diff line Loading @@ -549,8 +549,7 @@ chsc_add_cmg_attr(struct channel_subsystem *css) return ret; } static int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) { struct { struct chsc_header request; Loading
drivers/s390/cio/chsc.h +1 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ extern void chsc_free_sei_area(void); extern int chsc_enable_facility(int); struct channel_subsystem; extern int chsc_secm(struct channel_subsystem *, int); int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page); int chsc_chp_vary(struct chp_id chpid, int on); int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, Loading
drivers/s390/cio/css.c +152 −5 Original line number Diff line number Diff line /* * drivers/s390/cio/css.c * driver for channel subsystem * * Copyright IBM Corp. 2002,2008 * Copyright IBM Corp. 2002, 2009 * * Author(s): Arnd Bergmann (arndb@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) */ Loading @@ -17,6 +17,7 @@ #include <linux/errno.h> #include <linux/list.h> #include <linux/reboot.h> #include <linux/suspend.h> #include <asm/isc.h> #include <asm/crw.h> Loading Loading @@ -779,6 +780,79 @@ static struct notifier_block css_reboot_notifier = { .notifier_call = css_reboot_event, }; /* * Since the css devices are neither on a bus nor have a class * nor have a special device type, we cannot stop/restart channel * path measurements via the normal suspend/resume callbacks, but have * to use notifiers. */ static int css_power_event(struct notifier_block *this, unsigned long event, void *ptr) { void *secm_area; int ret, i; switch (event) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: ret = NOTIFY_DONE; for (i = 0; i <= __MAX_CSSID; i++) { struct channel_subsystem *css; css = channel_subsystems[i]; mutex_lock(&css->mutex); if (!css->cm_enabled) { mutex_unlock(&css->mutex); continue; } secm_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (secm_area) { if (__chsc_do_secm(css, 0, secm_area)) ret = NOTIFY_BAD; free_page((unsigned long)secm_area); } else ret = NOTIFY_BAD; mutex_unlock(&css->mutex); } break; case PM_POST_HIBERNATION: case PM_POST_SUSPEND: ret = NOTIFY_DONE; for (i = 0; i <= __MAX_CSSID; i++) { struct channel_subsystem *css; css = channel_subsystems[i]; mutex_lock(&css->mutex); if (!css->cm_enabled) { mutex_unlock(&css->mutex); continue; } secm_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (secm_area) { if (__chsc_do_secm(css, 1, secm_area)) ret = NOTIFY_BAD; free_page((unsigned long)secm_area); } else ret = NOTIFY_BAD; mutex_unlock(&css->mutex); } /* search for subchannels, which appeared during hibernation */ css_schedule_reprobe(); break; default: ret = NOTIFY_DONE; } return ret; } static struct notifier_block css_power_notifier = { .notifier_call = css_power_event, }; /* * Now that the driver core is running, we can setup our channel subsystem. * The struct subchannel's are created during probing (except for the Loading Loading @@ -852,6 +926,11 @@ init_channel_subsystem (void) ret = register_reboot_notifier(&css_reboot_notifier); if (ret) goto out_unregister; ret = register_pm_notifier(&css_power_notifier); if (ret) { unregister_reboot_notifier(&css_reboot_notifier); goto out_unregister; } css_init_done = 1; /* Enable default isc for I/O subchannels. */ Loading Loading @@ -953,6 +1032,73 @@ static int css_uevent(struct device *dev, struct kobj_uevent_env *env) return ret; } static int css_pm_prepare(struct device *dev) { struct subchannel *sch = to_subchannel(dev); struct css_driver *drv; if (mutex_is_locked(&sch->reg_mutex)) return -EAGAIN; if (!sch->dev.driver) return 0; drv = to_cssdriver(sch->dev.driver); /* Notify drivers that they may not register children. */ return drv->prepare ? drv->prepare(sch) : 0; } static void css_pm_complete(struct device *dev) { struct subchannel *sch = to_subchannel(dev); struct css_driver *drv; if (!sch->dev.driver) return; drv = to_cssdriver(sch->dev.driver); if (drv->complete) drv->complete(sch); } static int css_pm_freeze(struct device *dev) { struct subchannel *sch = to_subchannel(dev); struct css_driver *drv; if (!sch->dev.driver) return 0; drv = to_cssdriver(sch->dev.driver); return drv->freeze ? drv->freeze(sch) : 0; } static int css_pm_thaw(struct device *dev) { struct subchannel *sch = to_subchannel(dev); struct css_driver *drv; if (!sch->dev.driver) return 0; drv = to_cssdriver(sch->dev.driver); return drv->thaw ? drv->thaw(sch) : 0; } static int css_pm_restore(struct device *dev) { struct subchannel *sch = to_subchannel(dev); struct css_driver *drv; if (!sch->dev.driver) return 0; drv = to_cssdriver(sch->dev.driver); return drv->restore ? drv->restore(sch) : 0; } static struct dev_pm_ops css_pm_ops = { .prepare = css_pm_prepare, .complete = css_pm_complete, .freeze = css_pm_freeze, .thaw = css_pm_thaw, .restore = css_pm_restore, }; struct bus_type css_bus_type = { .name = "css", .match = css_bus_match, Loading @@ -960,6 +1106,7 @@ struct bus_type css_bus_type = { .remove = css_remove, .shutdown = css_shutdown, .uevent = css_uevent, .pm = &css_pm_ops, }; /** Loading
drivers/s390/cio/css.h +10 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,11 @@ struct chp_link; * @probe: function called on probe * @remove: function called on remove * @shutdown: called at device shutdown * @prepare: prepare for pm state transition * @complete: undo work done in @prepare * @freeze: callback for freezing during hibernation snapshotting * @thaw: undo work done in @freeze * @restore: callback for restoring after hibernation * @name: name of the device driver */ struct css_driver { Loading @@ -82,6 +87,11 @@ struct css_driver { int (*probe)(struct subchannel *); int (*remove)(struct subchannel *); void (*shutdown)(struct subchannel *); int (*prepare) (struct subchannel *); void (*complete) (struct subchannel *); int (*freeze)(struct subchannel *); int (*thaw) (struct subchannel *); int (*restore)(struct subchannel *); const char *name; }; Loading