mshv_synic.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2023, Microsoft Corporation.
  4. *
  5. * mshv_root module's main interrupt handler and associated functionality.
  6. *
  7. * Authors: Microsoft Linux virtualization team
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/slab.h>
  11. #include <linux/mm.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/io.h>
  14. #include <linux/random.h>
  15. #include <linux/cpuhotplug.h>
  16. #include <linux/reboot.h>
  17. #include <asm/mshyperv.h>
  18. #include <linux/acpi.h>
  19. #include "mshv_eventfd.h"
  20. #include "mshv.h"
  21. static int synic_cpuhp_online;
  22. static struct hv_synic_pages __percpu *synic_pages;
  23. static int mshv_sint_vector = -1; /* hwirq for the SynIC SINTs */
  24. static int mshv_sint_irq = -1; /* Linux IRQ for mshv_sint_vector */
  25. static u32 synic_event_ring_get_queued_port(u32 sint_index)
  26. {
  27. struct hv_synic_event_ring_page **event_ring_page;
  28. volatile struct hv_synic_event_ring *ring;
  29. struct hv_synic_pages *spages;
  30. u8 **synic_eventring_tail;
  31. u32 message;
  32. u8 tail;
  33. spages = this_cpu_ptr(synic_pages);
  34. event_ring_page = &spages->synic_event_ring_page;
  35. synic_eventring_tail = (u8 **)this_cpu_ptr(hv_synic_eventring_tail);
  36. if (unlikely(!*synic_eventring_tail)) {
  37. pr_debug("Missing synic event ring tail!\n");
  38. return 0;
  39. }
  40. tail = (*synic_eventring_tail)[sint_index];
  41. if (unlikely(!*event_ring_page)) {
  42. pr_debug("Missing synic event ring page!\n");
  43. return 0;
  44. }
  45. ring = &(*event_ring_page)->sint_event_ring[sint_index];
  46. /*
  47. * Get the message.
  48. */
  49. message = ring->data[tail];
  50. if (!message) {
  51. if (ring->ring_full) {
  52. /*
  53. * Ring is marked full, but we would have consumed all
  54. * the messages. Notify the hypervisor that ring is now
  55. * empty and check again.
  56. */
  57. ring->ring_full = 0;
  58. hv_call_notify_port_ring_empty(sint_index);
  59. message = ring->data[tail];
  60. }
  61. if (!message) {
  62. ring->signal_masked = 0;
  63. /*
  64. * Unmask the signal and sync with hypervisor
  65. * before one last check for any message.
  66. */
  67. mb();
  68. message = ring->data[tail];
  69. /*
  70. * Ok, lets bail out.
  71. */
  72. if (!message)
  73. return 0;
  74. }
  75. ring->signal_masked = 1;
  76. }
  77. /*
  78. * Clear the message in the ring buffer.
  79. */
  80. ring->data[tail] = 0;
  81. if (++tail == HV_SYNIC_EVENT_RING_MESSAGE_COUNT)
  82. tail = 0;
  83. (*synic_eventring_tail)[sint_index] = tail;
  84. return message;
  85. }
  86. static bool
  87. mshv_doorbell_isr(struct hv_message *msg)
  88. {
  89. struct hv_notification_message_payload *notification;
  90. u32 port;
  91. if (msg->header.message_type != HVMSG_SYNIC_SINT_INTERCEPT)
  92. return false;
  93. notification = (struct hv_notification_message_payload *)msg->u.payload;
  94. if (notification->sint_index != HV_SYNIC_DOORBELL_SINT_INDEX)
  95. return false;
  96. while ((port = synic_event_ring_get_queued_port(HV_SYNIC_DOORBELL_SINT_INDEX))) {
  97. struct port_table_info ptinfo = { 0 };
  98. if (mshv_portid_lookup(port, &ptinfo)) {
  99. pr_debug("Failed to get port info from port_table!\n");
  100. continue;
  101. }
  102. if (ptinfo.hv_port_type != HV_PORT_TYPE_DOORBELL) {
  103. pr_debug("Not a doorbell port!, port: %d, port_type: %d\n",
  104. port, ptinfo.hv_port_type);
  105. continue;
  106. }
  107. /* Invoke the callback */
  108. ptinfo.hv_port_doorbell.doorbell_cb(port,
  109. ptinfo.hv_port_doorbell.data);
  110. }
  111. return true;
  112. }
  113. static bool mshv_async_call_completion_isr(struct hv_message *msg)
  114. {
  115. bool handled = false;
  116. struct hv_async_completion_message_payload *async_msg;
  117. struct mshv_partition *partition;
  118. u64 partition_id;
  119. if (msg->header.message_type != HVMSG_ASYNC_CALL_COMPLETION)
  120. goto out;
  121. async_msg =
  122. (struct hv_async_completion_message_payload *)msg->u.payload;
  123. partition_id = async_msg->partition_id;
  124. /*
  125. * Hold this lock for the rest of the isr, because the partition could
  126. * be released anytime.
  127. * e.g. the MSHV_RUN_VP thread could wake on another cpu; it could
  128. * release the partition unless we hold this!
  129. */
  130. rcu_read_lock();
  131. partition = mshv_partition_find(partition_id);
  132. if (unlikely(!partition)) {
  133. pr_debug("failed to find partition %llu\n", partition_id);
  134. goto unlock_out;
  135. }
  136. partition->async_hypercall_status = async_msg->status;
  137. complete(&partition->async_hypercall);
  138. handled = true;
  139. unlock_out:
  140. rcu_read_unlock();
  141. out:
  142. return handled;
  143. }
  144. static void kick_vp(struct mshv_vp *vp)
  145. {
  146. atomic64_inc(&vp->run.vp_signaled_count);
  147. vp->run.kicked_by_hv = 1;
  148. wake_up(&vp->run.vp_suspend_queue);
  149. }
  150. static void
  151. handle_bitset_message(const struct hv_vp_signal_bitset_scheduler_message *msg)
  152. {
  153. int bank_idx, vps_signaled = 0, bank_mask_size;
  154. struct mshv_partition *partition;
  155. const struct hv_vpset *vpset;
  156. const u64 *bank_contents;
  157. u64 partition_id = msg->partition_id;
  158. if (msg->vp_bitset.bitset.format != HV_GENERIC_SET_SPARSE_4K) {
  159. pr_debug("scheduler message format is not HV_GENERIC_SET_SPARSE_4K");
  160. return;
  161. }
  162. if (msg->vp_count == 0) {
  163. pr_debug("scheduler message with no VP specified");
  164. return;
  165. }
  166. rcu_read_lock();
  167. partition = mshv_partition_find(partition_id);
  168. if (unlikely(!partition)) {
  169. pr_debug("failed to find partition %llu\n", partition_id);
  170. goto unlock_out;
  171. }
  172. vpset = &msg->vp_bitset.bitset;
  173. bank_idx = -1;
  174. bank_contents = vpset->bank_contents;
  175. bank_mask_size = sizeof(vpset->valid_bank_mask) * BITS_PER_BYTE;
  176. while (true) {
  177. int vp_bank_idx = -1;
  178. int vp_bank_size = sizeof(*bank_contents) * BITS_PER_BYTE;
  179. int vp_index;
  180. bank_idx = find_next_bit((unsigned long *)&vpset->valid_bank_mask,
  181. bank_mask_size, bank_idx + 1);
  182. if (bank_idx == bank_mask_size)
  183. break;
  184. while (true) {
  185. struct mshv_vp *vp;
  186. vp_bank_idx = find_next_bit((unsigned long *)bank_contents,
  187. vp_bank_size, vp_bank_idx + 1);
  188. if (vp_bank_idx == vp_bank_size)
  189. break;
  190. vp_index = (bank_idx * vp_bank_size) + vp_bank_idx;
  191. /* This shouldn't happen, but just in case. */
  192. if (unlikely(vp_index >= MSHV_MAX_VPS)) {
  193. pr_debug("VP index %u out of bounds\n",
  194. vp_index);
  195. goto unlock_out;
  196. }
  197. vp = partition->pt_vp_array[vp_index];
  198. if (unlikely(!vp)) {
  199. pr_debug("failed to find VP %u\n", vp_index);
  200. goto unlock_out;
  201. }
  202. kick_vp(vp);
  203. vps_signaled++;
  204. }
  205. bank_contents++;
  206. }
  207. unlock_out:
  208. rcu_read_unlock();
  209. if (vps_signaled != msg->vp_count)
  210. pr_debug("asked to signal %u VPs but only did %u\n",
  211. msg->vp_count, vps_signaled);
  212. }
  213. static void
  214. handle_pair_message(const struct hv_vp_signal_pair_scheduler_message *msg)
  215. {
  216. struct mshv_partition *partition = NULL;
  217. struct mshv_vp *vp;
  218. int idx;
  219. rcu_read_lock();
  220. for (idx = 0; idx < msg->vp_count; idx++) {
  221. u64 partition_id = msg->partition_ids[idx];
  222. u32 vp_index = msg->vp_indexes[idx];
  223. if (idx == 0 || partition->pt_id != partition_id) {
  224. partition = mshv_partition_find(partition_id);
  225. if (unlikely(!partition)) {
  226. pr_debug("failed to find partition %llu\n",
  227. partition_id);
  228. break;
  229. }
  230. }
  231. /* This shouldn't happen, but just in case. */
  232. if (unlikely(vp_index >= MSHV_MAX_VPS)) {
  233. pr_debug("VP index %u out of bounds\n", vp_index);
  234. break;
  235. }
  236. vp = partition->pt_vp_array[vp_index];
  237. if (!vp) {
  238. pr_debug("failed to find VP %u\n", vp_index);
  239. break;
  240. }
  241. kick_vp(vp);
  242. }
  243. rcu_read_unlock();
  244. }
  245. static bool
  246. mshv_scheduler_isr(struct hv_message *msg)
  247. {
  248. if (msg->header.message_type != HVMSG_SCHEDULER_VP_SIGNAL_BITSET &&
  249. msg->header.message_type != HVMSG_SCHEDULER_VP_SIGNAL_PAIR)
  250. return false;
  251. if (msg->header.message_type == HVMSG_SCHEDULER_VP_SIGNAL_BITSET)
  252. handle_bitset_message((struct hv_vp_signal_bitset_scheduler_message *)
  253. msg->u.payload);
  254. else
  255. handle_pair_message((struct hv_vp_signal_pair_scheduler_message *)
  256. msg->u.payload);
  257. return true;
  258. }
  259. static bool
  260. mshv_intercept_isr(struct hv_message *msg)
  261. {
  262. struct mshv_partition *partition;
  263. bool handled = false;
  264. struct mshv_vp *vp;
  265. u64 partition_id;
  266. u32 vp_index;
  267. partition_id = msg->header.sender;
  268. rcu_read_lock();
  269. partition = mshv_partition_find(partition_id);
  270. if (unlikely(!partition)) {
  271. pr_debug("failed to find partition %llu\n",
  272. partition_id);
  273. goto unlock_out;
  274. }
  275. if (msg->header.message_type == HVMSG_X64_APIC_EOI) {
  276. /*
  277. * Check if this gsi is registered in the
  278. * ack_notifier list and invoke the callback
  279. * if registered.
  280. */
  281. /*
  282. * If there is a notifier, the ack callback is supposed
  283. * to handle the VMEXIT. So we need not pass this message
  284. * to vcpu thread.
  285. */
  286. struct hv_x64_apic_eoi_message *eoi_msg =
  287. (struct hv_x64_apic_eoi_message *)&msg->u.payload[0];
  288. if (mshv_notify_acked_gsi(partition, eoi_msg->interrupt_vector)) {
  289. handled = true;
  290. goto unlock_out;
  291. }
  292. }
  293. /*
  294. * We should get an opaque intercept message here for all intercept
  295. * messages, since we're using the mapped VP intercept message page.
  296. *
  297. * The intercept message will have been placed in intercept message
  298. * page at this point.
  299. *
  300. * Make sure the message type matches our expectation.
  301. */
  302. if (msg->header.message_type != HVMSG_OPAQUE_INTERCEPT) {
  303. pr_debug("wrong message type %d", msg->header.message_type);
  304. goto unlock_out;
  305. }
  306. /*
  307. * Since we directly index the vp, and it has to exist for us to be here
  308. * (because the vp is only deleted when the partition is), no additional
  309. * locking is needed here
  310. */
  311. vp_index =
  312. ((struct hv_opaque_intercept_message *)msg->u.payload)->vp_index;
  313. vp = partition->pt_vp_array[vp_index];
  314. if (unlikely(!vp)) {
  315. pr_debug("failed to find VP %u\n", vp_index);
  316. goto unlock_out;
  317. }
  318. kick_vp(vp);
  319. handled = true;
  320. unlock_out:
  321. rcu_read_unlock();
  322. return handled;
  323. }
  324. void mshv_isr(void)
  325. {
  326. struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
  327. struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
  328. struct hv_message *msg;
  329. bool handled;
  330. if (unlikely(!(*msg_page))) {
  331. pr_debug("Missing synic page!\n");
  332. return;
  333. }
  334. msg = &((*msg_page)->sint_message[HV_SYNIC_INTERCEPTION_SINT_INDEX]);
  335. /*
  336. * If the type isn't set, there isn't really a message;
  337. * it may be some other hyperv interrupt
  338. */
  339. if (msg->header.message_type == HVMSG_NONE)
  340. return;
  341. handled = mshv_doorbell_isr(msg);
  342. if (!handled)
  343. handled = mshv_scheduler_isr(msg);
  344. if (!handled)
  345. handled = mshv_async_call_completion_isr(msg);
  346. if (!handled)
  347. handled = mshv_intercept_isr(msg);
  348. if (handled) {
  349. /*
  350. * Acknowledge message with hypervisor if another message is
  351. * pending.
  352. */
  353. msg->header.message_type = HVMSG_NONE;
  354. /*
  355. * Ensure the write is complete so the hypervisor will deliver
  356. * the next message if available.
  357. */
  358. mb();
  359. if (msg->header.message_flags.msg_pending)
  360. hv_set_non_nested_msr(HV_MSR_EOM, 0);
  361. add_interrupt_randomness(mshv_sint_vector);
  362. } else {
  363. pr_warn_once("%s: unknown message type 0x%x\n", __func__,
  364. msg->header.message_type);
  365. }
  366. }
  367. static int mshv_synic_cpu_init(unsigned int cpu)
  368. {
  369. union hv_synic_simp simp;
  370. union hv_synic_siefp siefp;
  371. union hv_synic_sirbp sirbp;
  372. union hv_synic_sint sint;
  373. union hv_synic_scontrol sctrl;
  374. struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
  375. struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
  376. struct hv_synic_event_flags_page **event_flags_page =
  377. &spages->synic_event_flags_page;
  378. struct hv_synic_event_ring_page **event_ring_page =
  379. &spages->synic_event_ring_page;
  380. /* Setup the Synic's message page */
  381. simp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIMP);
  382. simp.simp_enabled = true;
  383. *msg_page = memremap(simp.base_simp_gpa << HV_HYP_PAGE_SHIFT,
  384. HV_HYP_PAGE_SIZE,
  385. MEMREMAP_WB);
  386. if (!(*msg_page))
  387. return -EFAULT;
  388. hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64);
  389. /* Setup the Synic's event flags page */
  390. siefp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIEFP);
  391. siefp.siefp_enabled = true;
  392. *event_flags_page = memremap(siefp.base_siefp_gpa << PAGE_SHIFT,
  393. PAGE_SIZE, MEMREMAP_WB);
  394. if (!(*event_flags_page))
  395. goto cleanup;
  396. hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64);
  397. /* Setup the Synic's event ring page */
  398. sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP);
  399. sirbp.sirbp_enabled = true;
  400. *event_ring_page = memremap(sirbp.base_sirbp_gpa << PAGE_SHIFT,
  401. PAGE_SIZE, MEMREMAP_WB);
  402. if (!(*event_ring_page))
  403. goto cleanup;
  404. hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
  405. if (mshv_sint_irq != -1)
  406. enable_percpu_irq(mshv_sint_irq, 0);
  407. /* Enable intercepts */
  408. sint.as_uint64 = 0;
  409. sint.vector = mshv_sint_vector;
  410. sint.masked = false;
  411. sint.auto_eoi = hv_recommend_using_aeoi();
  412. hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX,
  413. sint.as_uint64);
  414. /* Doorbell SINT */
  415. sint.as_uint64 = 0;
  416. sint.vector = mshv_sint_vector;
  417. sint.masked = false;
  418. sint.as_intercept = 1;
  419. sint.auto_eoi = hv_recommend_using_aeoi();
  420. hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX,
  421. sint.as_uint64);
  422. /* Enable global synic bit */
  423. sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL);
  424. sctrl.enable = 1;
  425. hv_set_non_nested_msr(HV_MSR_SCONTROL, sctrl.as_uint64);
  426. return 0;
  427. cleanup:
  428. if (*event_ring_page) {
  429. sirbp.sirbp_enabled = false;
  430. hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
  431. memunmap(*event_ring_page);
  432. }
  433. if (*event_flags_page) {
  434. siefp.siefp_enabled = false;
  435. hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64);
  436. memunmap(*event_flags_page);
  437. }
  438. if (*msg_page) {
  439. simp.simp_enabled = false;
  440. hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64);
  441. memunmap(*msg_page);
  442. }
  443. return -EFAULT;
  444. }
  445. static int mshv_synic_cpu_exit(unsigned int cpu)
  446. {
  447. union hv_synic_sint sint;
  448. union hv_synic_simp simp;
  449. union hv_synic_siefp siefp;
  450. union hv_synic_sirbp sirbp;
  451. union hv_synic_scontrol sctrl;
  452. struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
  453. struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
  454. struct hv_synic_event_flags_page **event_flags_page =
  455. &spages->synic_event_flags_page;
  456. struct hv_synic_event_ring_page **event_ring_page =
  457. &spages->synic_event_ring_page;
  458. /* Disable the interrupt */
  459. sint.as_uint64 = hv_get_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX);
  460. sint.masked = true;
  461. hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX,
  462. sint.as_uint64);
  463. /* Disable Doorbell SINT */
  464. sint.as_uint64 = hv_get_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX);
  465. sint.masked = true;
  466. hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX,
  467. sint.as_uint64);
  468. if (mshv_sint_irq != -1)
  469. disable_percpu_irq(mshv_sint_irq);
  470. /* Disable Synic's event ring page */
  471. sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP);
  472. sirbp.sirbp_enabled = false;
  473. hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
  474. memunmap(*event_ring_page);
  475. /* Disable Synic's event flags page */
  476. siefp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIEFP);
  477. siefp.siefp_enabled = false;
  478. hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64);
  479. memunmap(*event_flags_page);
  480. /* Disable Synic's message page */
  481. simp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIMP);
  482. simp.simp_enabled = false;
  483. hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64);
  484. memunmap(*msg_page);
  485. /* Disable global synic bit */
  486. sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL);
  487. sctrl.enable = 0;
  488. hv_set_non_nested_msr(HV_MSR_SCONTROL, sctrl.as_uint64);
  489. return 0;
  490. }
  491. int
  492. mshv_register_doorbell(u64 partition_id, doorbell_cb_t doorbell_cb, void *data,
  493. u64 gpa, u64 val, u64 flags)
  494. {
  495. struct hv_connection_info connection_info = { 0 };
  496. union hv_connection_id connection_id = { 0 };
  497. struct port_table_info *port_table_info;
  498. struct hv_port_info port_info = { 0 };
  499. union hv_port_id port_id = { 0 };
  500. int ret;
  501. port_table_info = kmalloc_obj(*port_table_info);
  502. if (!port_table_info)
  503. return -ENOMEM;
  504. port_table_info->hv_port_type = HV_PORT_TYPE_DOORBELL;
  505. port_table_info->hv_port_doorbell.doorbell_cb = doorbell_cb;
  506. port_table_info->hv_port_doorbell.data = data;
  507. ret = mshv_portid_alloc(port_table_info);
  508. if (ret < 0) {
  509. kfree(port_table_info);
  510. return ret;
  511. }
  512. port_id.u.id = ret;
  513. port_info.port_type = HV_PORT_TYPE_DOORBELL;
  514. port_info.doorbell_port_info.target_sint = HV_SYNIC_DOORBELL_SINT_INDEX;
  515. port_info.doorbell_port_info.target_vp = HV_ANY_VP;
  516. ret = hv_call_create_port(hv_current_partition_id, port_id, partition_id,
  517. &port_info,
  518. 0, 0, NUMA_NO_NODE);
  519. if (ret < 0) {
  520. mshv_portid_free(port_id.u.id);
  521. return ret;
  522. }
  523. connection_id.u.id = port_id.u.id;
  524. connection_info.port_type = HV_PORT_TYPE_DOORBELL;
  525. connection_info.doorbell_connection_info.gpa = gpa;
  526. connection_info.doorbell_connection_info.trigger_value = val;
  527. connection_info.doorbell_connection_info.flags = flags;
  528. ret = hv_call_connect_port(hv_current_partition_id, port_id, partition_id,
  529. connection_id, &connection_info, 0, NUMA_NO_NODE);
  530. if (ret < 0) {
  531. hv_call_delete_port(hv_current_partition_id, port_id);
  532. mshv_portid_free(port_id.u.id);
  533. return ret;
  534. }
  535. // lets use the port_id as the doorbell_id
  536. return port_id.u.id;
  537. }
  538. void
  539. mshv_unregister_doorbell(u64 partition_id, int doorbell_portid)
  540. {
  541. union hv_port_id port_id = { 0 };
  542. union hv_connection_id connection_id = { 0 };
  543. connection_id.u.id = doorbell_portid;
  544. hv_call_disconnect_port(partition_id, connection_id);
  545. port_id.u.id = doorbell_portid;
  546. hv_call_delete_port(hv_current_partition_id, port_id);
  547. mshv_portid_free(doorbell_portid);
  548. }
  549. static int mshv_synic_reboot_notify(struct notifier_block *nb,
  550. unsigned long code, void *unused)
  551. {
  552. if (!hv_root_partition())
  553. return 0;
  554. cpuhp_remove_state(synic_cpuhp_online);
  555. return 0;
  556. }
  557. static struct notifier_block mshv_synic_reboot_nb = {
  558. .notifier_call = mshv_synic_reboot_notify,
  559. };
  560. #ifndef HYPERVISOR_CALLBACK_VECTOR
  561. static DEFINE_PER_CPU(long, mshv_evt);
  562. static irqreturn_t mshv_percpu_isr(int irq, void *dev_id)
  563. {
  564. mshv_isr();
  565. return IRQ_HANDLED;
  566. }
  567. #ifdef CONFIG_ACPI
  568. static int __init mshv_acpi_setup_sint_irq(void)
  569. {
  570. return acpi_register_gsi(NULL, mshv_sint_vector, ACPI_EDGE_SENSITIVE,
  571. ACPI_ACTIVE_HIGH);
  572. }
  573. static void mshv_acpi_cleanup_sint_irq(void)
  574. {
  575. acpi_unregister_gsi(mshv_sint_vector);
  576. }
  577. #else
  578. static int __init mshv_acpi_setup_sint_irq(void)
  579. {
  580. return -ENODEV;
  581. }
  582. static void mshv_acpi_cleanup_sint_irq(void)
  583. {
  584. }
  585. #endif
  586. static int __init mshv_sint_vector_setup(void)
  587. {
  588. int ret;
  589. struct hv_register_assoc reg = {
  590. .name = HV_ARM64_REGISTER_SINT_RESERVED_INTERRUPT_ID,
  591. };
  592. union hv_input_vtl input_vtl = { 0 };
  593. if (acpi_disabled)
  594. return -ENODEV;
  595. ret = hv_call_get_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF,
  596. 1, input_vtl, &reg);
  597. if (ret || !reg.value.reg64)
  598. return -ENODEV;
  599. mshv_sint_vector = reg.value.reg64;
  600. ret = mshv_acpi_setup_sint_irq();
  601. if (ret < 0) {
  602. pr_err("Failed to setup IRQ for MSHV SINT vector %d: %d\n",
  603. mshv_sint_vector, ret);
  604. goto out_fail;
  605. }
  606. mshv_sint_irq = ret;
  607. ret = request_percpu_irq(mshv_sint_irq, mshv_percpu_isr, "MSHV",
  608. &mshv_evt);
  609. if (ret)
  610. goto out_unregister;
  611. return 0;
  612. out_unregister:
  613. mshv_acpi_cleanup_sint_irq();
  614. out_fail:
  615. return ret;
  616. }
  617. static void mshv_sint_vector_cleanup(void)
  618. {
  619. free_percpu_irq(mshv_sint_irq, &mshv_evt);
  620. mshv_acpi_cleanup_sint_irq();
  621. }
  622. #else /* !HYPERVISOR_CALLBACK_VECTOR */
  623. static int __init mshv_sint_vector_setup(void)
  624. {
  625. mshv_sint_vector = HYPERVISOR_CALLBACK_VECTOR;
  626. return 0;
  627. }
  628. static void mshv_sint_vector_cleanup(void)
  629. {
  630. }
  631. #endif /* HYPERVISOR_CALLBACK_VECTOR */
  632. int __init mshv_synic_init(struct device *dev)
  633. {
  634. int ret = 0;
  635. ret = mshv_sint_vector_setup();
  636. if (ret)
  637. return ret;
  638. synic_pages = alloc_percpu(struct hv_synic_pages);
  639. if (!synic_pages) {
  640. dev_err(dev, "Failed to allocate percpu synic page\n");
  641. ret = -ENOMEM;
  642. goto sint_vector_cleanup;
  643. }
  644. ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_synic",
  645. mshv_synic_cpu_init,
  646. mshv_synic_cpu_exit);
  647. if (ret < 0) {
  648. dev_err(dev, "Failed to setup cpu hotplug state: %i\n", ret);
  649. goto free_synic_pages;
  650. }
  651. synic_cpuhp_online = ret;
  652. ret = register_reboot_notifier(&mshv_synic_reboot_nb);
  653. if (ret)
  654. goto remove_cpuhp_state;
  655. return 0;
  656. remove_cpuhp_state:
  657. cpuhp_remove_state(synic_cpuhp_online);
  658. free_synic_pages:
  659. free_percpu(synic_pages);
  660. sint_vector_cleanup:
  661. mshv_sint_vector_cleanup();
  662. return ret;
  663. }
  664. void mshv_synic_exit(void)
  665. {
  666. unregister_reboot_notifier(&mshv_synic_reboot_nb);
  667. cpuhp_remove_state(synic_cpuhp_online);
  668. free_percpu(synic_pages);
  669. mshv_sint_vector_cleanup();
  670. }