sclp_config.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. * drivers/s390/char/sclp_config.c
  3. *
  4. * Copyright IBM Corp. 2007
  5. * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
  6. */
  7. #include <linux/init.h>
  8. #include <linux/errno.h>
  9. #include <linux/cpu.h>
  10. #include <linux/kthread.h>
  11. #include <linux/sysdev.h>
  12. #include <linux/workqueue.h>
  13. #include <asm/smp.h>
  14. #include "sclp.h"
  15. #define TAG "sclp_config: "
  16. struct conf_mgm_data {
  17. u8 reserved;
  18. u8 ev_qualifier;
  19. } __attribute__((packed));
  20. #define EV_QUAL_CPU_CHANGE 1
  21. #define EV_QUAL_CAP_CHANGE 3
  22. static struct work_struct sclp_cpu_capability_work;
  23. static struct work_struct sclp_cpu_change_work;
  24. static void sclp_cpu_capability_notify(struct work_struct *work)
  25. {
  26. int cpu;
  27. struct sys_device *sysdev;
  28. printk(KERN_WARNING TAG "cpu capability changed.\n");
  29. get_online_cpus();
  30. for_each_online_cpu(cpu) {
  31. sysdev = get_cpu_sysdev(cpu);
  32. kobject_uevent(&sysdev->kobj, KOBJ_CHANGE);
  33. }
  34. put_online_cpus();
  35. }
  36. static int sclp_cpu_kthread(void *data)
  37. {
  38. smp_rescan_cpus();
  39. return 0;
  40. }
  41. static void __ref sclp_cpu_change_notify(struct work_struct *work)
  42. {
  43. /* Can't call smp_rescan_cpus() from workqueue context since it may
  44. * deadlock in case of cpu hotplug. So we have to create a kernel
  45. * thread in order to call it.
  46. */
  47. kthread_run(sclp_cpu_kthread, NULL, "cpu_rescan");
  48. }
  49. static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
  50. {
  51. struct conf_mgm_data *cdata;
  52. cdata = (struct conf_mgm_data *)(evbuf + 1);
  53. switch (cdata->ev_qualifier) {
  54. case EV_QUAL_CPU_CHANGE:
  55. schedule_work(&sclp_cpu_change_work);
  56. break;
  57. case EV_QUAL_CAP_CHANGE:
  58. schedule_work(&sclp_cpu_capability_work);
  59. break;
  60. }
  61. }
  62. static struct sclp_register sclp_conf_register =
  63. {
  64. .receive_mask = EVTYP_CONFMGMDATA_MASK,
  65. .receiver_fn = sclp_conf_receiver_fn,
  66. };
  67. static int __init sclp_conf_init(void)
  68. {
  69. int rc;
  70. INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
  71. INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
  72. rc = sclp_register(&sclp_conf_register);
  73. if (rc)
  74. return rc;
  75. if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) {
  76. printk(KERN_WARNING TAG "no configuration management.\n");
  77. sclp_unregister(&sclp_conf_register);
  78. rc = -ENOSYS;
  79. }
  80. return rc;
  81. }
  82. __initcall(sclp_conf_init);