hypfs_diag0c.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Hypervisor filesystem for Linux on s390
  4. *
  5. * Diag 0C implementation
  6. *
  7. * Copyright IBM Corp. 2014
  8. */
  9. #include <linux/slab.h>
  10. #include <linux/cpu.h>
  11. #include <asm/diag.h>
  12. #include <asm/hypfs.h>
  13. #include "hypfs.h"
  14. #define DBFS_D0C_HDR_VERSION 0
  15. /*
  16. * Get hypfs_diag0c_entry from CPU vector and store diag0c data
  17. */
  18. static void diag0c_fn(void *data)
  19. {
  20. diag_stat_inc(DIAG_STAT_X00C);
  21. diag_amode31_ops.diag0c(((void **)data)[smp_processor_id()]);
  22. }
  23. /*
  24. * Allocate buffer and store diag 0c data
  25. */
  26. static void *diag0c_store(unsigned int *count)
  27. {
  28. struct hypfs_diag0c_data *diag0c_data;
  29. unsigned int cpu_count, cpu, i;
  30. void **cpu_vec;
  31. cpus_read_lock();
  32. cpu_count = num_online_cpus();
  33. cpu_vec = kmalloc_array(num_possible_cpus(), sizeof(*cpu_vec),
  34. GFP_KERNEL);
  35. if (!cpu_vec)
  36. goto fail_unlock_cpus;
  37. /* Note: Diag 0c needs 8 byte alignment and real storage */
  38. diag0c_data = kzalloc(struct_size(diag0c_data, entry, cpu_count),
  39. GFP_KERNEL | GFP_DMA);
  40. if (!diag0c_data)
  41. goto fail_kfree_cpu_vec;
  42. i = 0;
  43. /* Fill CPU vector for each online CPU */
  44. for_each_online_cpu(cpu) {
  45. diag0c_data->entry[i].cpu = cpu;
  46. cpu_vec[cpu] = &diag0c_data->entry[i++];
  47. }
  48. /* Collect data all CPUs */
  49. on_each_cpu(diag0c_fn, cpu_vec, 1);
  50. *count = cpu_count;
  51. kfree(cpu_vec);
  52. cpus_read_unlock();
  53. return diag0c_data;
  54. fail_kfree_cpu_vec:
  55. kfree(cpu_vec);
  56. fail_unlock_cpus:
  57. cpus_read_unlock();
  58. return ERR_PTR(-ENOMEM);
  59. }
  60. /*
  61. * Hypfs DBFS callback: Free diag 0c data
  62. */
  63. static void dbfs_diag0c_free(const void *data)
  64. {
  65. kfree(data);
  66. }
  67. /*
  68. * Hypfs DBFS callback: Create diag 0c data
  69. */
  70. static int dbfs_diag0c_create(void **data, void **data_free_ptr, size_t *size)
  71. {
  72. struct hypfs_diag0c_data *diag0c_data;
  73. unsigned int count;
  74. diag0c_data = diag0c_store(&count);
  75. if (IS_ERR(diag0c_data))
  76. return PTR_ERR(diag0c_data);
  77. memset(&diag0c_data->hdr, 0, sizeof(diag0c_data->hdr));
  78. store_tod_clock_ext((union tod_clock *)diag0c_data->hdr.tod_ext);
  79. diag0c_data->hdr.len = count * sizeof(struct hypfs_diag0c_entry);
  80. diag0c_data->hdr.version = DBFS_D0C_HDR_VERSION;
  81. diag0c_data->hdr.count = count;
  82. *data = diag0c_data;
  83. *data_free_ptr = diag0c_data;
  84. *size = diag0c_data->hdr.len + sizeof(struct hypfs_diag0c_hdr);
  85. return 0;
  86. }
  87. /*
  88. * Hypfs DBFS file structure
  89. */
  90. static struct hypfs_dbfs_file dbfs_file_0c = {
  91. .name = "diag_0c",
  92. .data_create = dbfs_diag0c_create,
  93. .data_free = dbfs_diag0c_free,
  94. };
  95. /*
  96. * Initialize diag 0c interface for z/VM
  97. */
  98. int __init hypfs_diag0c_init(void)
  99. {
  100. if (!MACHINE_IS_VM)
  101. return 0;
  102. hypfs_dbfs_create_file(&dbfs_file_0c);
  103. return 0;
  104. }
  105. /*
  106. * Shutdown diag 0c interface for z/VM
  107. */
  108. void hypfs_diag0c_exit(void)
  109. {
  110. if (!MACHINE_IS_VM)
  111. return;
  112. hypfs_dbfs_remove_file(&dbfs_file_0c);
  113. }