Lines Matching +full:single +full:- +full:channel
1 // SPDX-License-Identifier: GPL-2.0 OR MIT
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
93 * @channel: RPC channel
98 static int vmw_open_channel(struct rpc_channel *channel, unsigned int protocol) in vmw_open_channel() argument
109 return -EINVAL; in vmw_open_channel()
111 channel->channel_id = HIGH_WORD(edx); in vmw_open_channel()
112 channel->cookie_high = si; in vmw_open_channel()
113 channel->cookie_low = di; in vmw_open_channel()
123 * @channel: RPC channel
127 static int vmw_close_channel(struct rpc_channel *channel) in vmw_close_channel() argument
132 si = channel->cookie_high; in vmw_close_channel()
133 di = channel->cookie_low; in vmw_close_channel()
137 channel->channel_id << 16, in vmw_close_channel()
142 return -EINVAL; in vmw_close_channel()
148 * vmw_port_hb_out - Send the message payload either through the
149 * high-bandwidth port if available, or through the backdoor otherwise.
150 * @channel: The rpc channel.
151 * @msg: NULL-terminated message.
152 * @hb: Whether the high-bandwidth port is available.
156 static unsigned long vmw_port_hb_out(struct rpc_channel *channel, in vmw_port_hb_out() argument
164 unsigned long bp = channel->cookie_high; in vmw_port_hb_out()
165 u32 channel_id = (channel->channel_id << 16); in vmw_port_hb_out()
168 di = channel->cookie_low; in vmw_port_hb_out()
188 msg_len -= bytes; in vmw_port_hb_out()
190 si = channel->cookie_high; in vmw_port_hb_out()
191 di = channel->cookie_low; in vmw_port_hb_out()
195 channel->channel_id << 16, in vmw_port_hb_out()
204 * vmw_port_hb_in - Receive the message payload either through the
205 * high-bandwidth port if available, or through the backdoor otherwise.
206 * @channel: The rpc channel.
209 * @hb: Whether the high-bandwidth port is available.
213 static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply, in vmw_port_hb_in() argument
220 unsigned long bp = channel->cookie_low; in vmw_port_hb_in()
221 u32 channel_id = (channel->channel_id << 16); in vmw_port_hb_in()
223 si = channel->cookie_high; in vmw_port_hb_in()
241 si = channel->cookie_high; in vmw_port_hb_in()
242 di = channel->cookie_low; in vmw_port_hb_in()
246 channel->channel_id << 16, in vmw_port_hb_in()
254 reply_len -= bytes; in vmw_port_hb_in()
265 * @channel: RPC channel
270 static int vmw_send_msg(struct rpc_channel *channel, const char *msg) in vmw_send_msg() argument
280 si = channel->cookie_high; in vmw_send_msg()
281 di = channel->cookie_low; in vmw_send_msg()
285 channel->channel_id << 16, in vmw_send_msg()
291 return -EINVAL; in vmw_send_msg()
295 ebx = vmw_port_hb_out(channel, msg, in vmw_send_msg()
308 return -EINVAL; in vmw_send_msg()
318 * @channel: channel opened by vmw_open_channel
322 static int vmw_recv_msg(struct rpc_channel *channel, void **msg, in vmw_recv_msg() argument
338 si = channel->cookie_high; in vmw_recv_msg()
339 di = channel->cookie_low; in vmw_recv_msg()
343 channel->channel_id << 16, in vmw_recv_msg()
349 return -EINVAL; in vmw_recv_msg()
360 return -ENOMEM; in vmw_recv_msg()
365 ebx = vmw_port_hb_in(channel, reply, reply_len, in vmw_recv_msg()
375 return -EINVAL; in vmw_recv_msg()
382 si = channel->cookie_high; in vmw_recv_msg()
383 di = channel->cookie_low; in vmw_recv_msg()
387 channel->channel_id << 16, in vmw_recv_msg()
399 return -EINVAL; in vmw_recv_msg()
406 return -EINVAL; in vmw_recv_msg()
420 * a string, and it is up to the caller to post-process.
431 struct rpc_channel channel; in vmw_host_get_guestinfo() local
436 return -ENODEV; in vmw_host_get_guestinfo()
439 return -EINVAL; in vmw_host_get_guestinfo()
441 msg = kasprintf(GFP_KERNEL, "info-get %s", guest_info_param); in vmw_host_get_guestinfo()
445 return -ENOMEM; in vmw_host_get_guestinfo()
448 if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) in vmw_host_get_guestinfo()
451 if (vmw_send_msg(&channel, msg) || in vmw_host_get_guestinfo()
452 vmw_recv_msg(&channel, (void *) &reply, &reply_len)) in vmw_host_get_guestinfo()
455 vmw_close_channel(&channel); in vmw_host_get_guestinfo()
460 reply_len = max(reply_len - 2, (size_t) 0); in vmw_host_get_guestinfo()
475 vmw_close_channel(&channel); in vmw_host_get_guestinfo()
482 return -EINVAL; in vmw_host_get_guestinfo()
497 struct rpc_channel channel; in vmw_host_printf() local
503 return -ENODEV; in vmw_host_printf()
513 return -ENOMEM; in vmw_host_printf()
520 return -ENOMEM; in vmw_host_printf()
523 if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) in vmw_host_printf()
526 if (vmw_send_msg(&channel, msg)) in vmw_host_printf()
529 vmw_close_channel(&channel); in vmw_host_printf()
536 vmw_close_channel(&channel); in vmw_host_printf()
542 return -EINVAL; in vmw_host_printf()
547 * vmw_msg_ioctl: Sends and receveives a message to/from host from/to user-space
549 * Sends a message from user-space to host.
550 * Can also receive a result from host and return that to user-space.
563 struct rpc_channel channel; in vmw_msg_ioctl() local
570 return -ENOMEM; in vmw_msg_ioctl()
573 length = strncpy_from_user(msg, (void __user *)((unsigned long)arg->send), in vmw_msg_ioctl()
578 return -EINVAL; in vmw_msg_ioctl()
582 if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM)) { in vmw_msg_ioctl()
583 DRM_ERROR("Failed to open channel.\n"); in vmw_msg_ioctl()
587 if (vmw_send_msg(&channel, msg)) { in vmw_msg_ioctl()
592 if (!arg->send_only) { in vmw_msg_ioctl()
596 if (vmw_recv_msg(&channel, (void *) &reply, &reply_len)) { in vmw_msg_ioctl()
601 if (copy_to_user((void __user *)((unsigned long)arg->receive), in vmw_msg_ioctl()
607 arg->receive_len = (__u32)reply_len; in vmw_msg_ioctl()
612 vmw_close_channel(&channel); in vmw_msg_ioctl()
618 vmw_close_channel(&channel); in vmw_msg_ioctl()
622 return -EINVAL; in vmw_msg_ioctl()
658 * hypervisor_ppn_add: Adds a single mksGuestStat instance descriptor to the
675 * hypervisor_ppn_remove: Removes a single mksGuestStat instance descriptor from
693 /* Order of the total number of pages used for kernel-internal mksGuestStat; at least 2 */
705 * mksstat_init_record: Initializes an MKSGuestStatCounter-based record
708 * @stat_idx: Index of the MKSGuestStatCounter-based mksGuestStat record.
731 * mksstat_init_record_time: Initializes an MKSGuestStatCounterTime-based record
734 * @stat_idx: Index of the MKSGuestStatCounterTime-based mksGuestStat record.
757 * mksstat_init_kern_id: Creates a single mksGuestStat instance descriptor and
758 * kernel-internal counters. Adds PFN mapping to the hypervisor.
760 * Create a single mksGuestStat instance descriptor and corresponding structures
761 * for all kernel-internal counters. The corresponding PFNs are mapped with the
775 /* Allocate pages for the kernel-internal instance descriptor */ in mksstat_init_kern_id()
779 return -ENOMEM; in mksstat_init_kern_id()
786 /* Set up all kernel-internal counters and corresponding structures */ in mksstat_init_kern_id()
792 BUG_ON(pstrs_acc - pstrs > PAGE_SIZE); in mksstat_init_kern_id()
794 /* Set up the kernel-internal instance descriptor */ in mksstat_init_kern_id()
795 pdesc->reservedMBZ = 0; in mksstat_init_kern_id()
796 pdesc->statStartVA = (uintptr_t)pstat; in mksstat_init_kern_id()
797 pdesc->strsStartVA = (uintptr_t)pstrs; in mksstat_init_kern_id()
798 pdesc->statLength = sizeof(*pstat) * MKSSTAT_KERN_COUNT; in mksstat_init_kern_id()
799 pdesc->infoLength = sizeof(*pinfo) * MKSSTAT_KERN_COUNT; in mksstat_init_kern_id()
800 pdesc->strsLength = pstrs_acc - pstrs; in mksstat_init_kern_id()
801 snprintf(pdesc->description, ARRAY_SIZE(pdesc->description) - 1, "%s pid=%d", in mksstat_init_kern_id()
802 MKSSTAT_KERNEL_DESCRIPTION, current->pid); in mksstat_init_kern_id()
804 pdesc->statPPNs[0] = page_to_pfn(virt_to_page(pstat)); in mksstat_init_kern_id()
805 reset_ppn_array(pdesc->statPPNs + 1, ARRAY_SIZE(pdesc->statPPNs) - 1); in mksstat_init_kern_id()
807 pdesc->infoPPNs[0] = page_to_pfn(virt_to_page(pinfo)); in mksstat_init_kern_id()
808 reset_ppn_array(pdesc->infoPPNs + 1, ARRAY_SIZE(pdesc->infoPPNs) - 1); in mksstat_init_kern_id()
810 pdesc->strsPPNs[0] = page_to_pfn(virt_to_page(pstrs)); in mksstat_init_kern_id()
811 reset_ppn_array(pdesc->strsPPNs + 1, ARRAY_SIZE(pdesc->strsPPNs) - 1); in mksstat_init_kern_id()
821 * vmw_mksstat_get_kern_slot: Acquires a slot for a single kernel-internal
824 * Find a slot for a single kernel-internal mksGuestStat instance descriptor.
825 * In case no such was already present, allocate a new one and set up a kernel-
830 * Return: Non-negative slot on success, negative error code on error.
838 for (i = 0; i < ARRAY_SIZE(dev_priv->mksstat_kern_pids); ++i) { in vmw_mksstat_get_kern_slot()
839 const size_t slot = (i + base) % ARRAY_SIZE(dev_priv->mksstat_kern_pids); in vmw_mksstat_get_kern_slot()
842 if (pid == (pid_t)atomic_read(&dev_priv->mksstat_kern_pids[slot])) in vmw_mksstat_get_kern_slot()
846 if (!atomic_cmpxchg(&dev_priv->mksstat_kern_pids[slot], 0, MKSSTAT_PID_RESERVED)) { in vmw_mksstat_get_kern_slot()
847 const int ret = mksstat_init_kern_id(&dev_priv->mksstat_kern_pages[slot]); in vmw_mksstat_get_kern_slot()
850 /* Reset top-timer tracking for this slot */ in vmw_mksstat_get_kern_slot()
851 dev_priv->mksstat_kern_top_timer[slot] = MKSSTAT_KERN_COUNT; in vmw_mksstat_get_kern_slot()
853 atomic_set(&dev_priv->mksstat_kern_pids[slot], pid); in vmw_mksstat_get_kern_slot()
857 atomic_set(&dev_priv->mksstat_kern_pids[slot], 0); in vmw_mksstat_get_kern_slot()
862 return -ENOSPC; in vmw_mksstat_get_kern_slot()
868 * vmw_mksstat_cleanup_descriptor: Frees a single userspace-originating
869 * mksGuestStat instance-descriptor page and unpins all related user pages.
872 * the instance-descriptor page itself.
882 for (i = 0; i < ARRAY_SIZE(pdesc->statPPNs) && pdesc->statPPNs[i] != INVALID_PPN64; ++i) in vmw_mksstat_cleanup_descriptor()
883 unpin_user_page(pfn_to_page(pdesc->statPPNs[i])); in vmw_mksstat_cleanup_descriptor()
885 for (i = 0; i < ARRAY_SIZE(pdesc->infoPPNs) && pdesc->infoPPNs[i] != INVALID_PPN64; ++i) in vmw_mksstat_cleanup_descriptor()
886 unpin_user_page(pfn_to_page(pdesc->infoPPNs[i])); in vmw_mksstat_cleanup_descriptor()
888 for (i = 0; i < ARRAY_SIZE(pdesc->strsPPNs) && pdesc->strsPPNs[i] != INVALID_PPN64; ++i) in vmw_mksstat_cleanup_descriptor()
889 unpin_user_page(pfn_to_page(pdesc->strsPPNs[i])); in vmw_mksstat_cleanup_descriptor()
913 /* Discard all userspace-originating instance descriptors and unpin all related pages */ in vmw_mksstat_remove_all()
914 for (i = 0; i < ARRAY_SIZE(dev_priv->mksstat_user_pids); ++i) { in vmw_mksstat_remove_all()
915 const pid_t pid0 = (pid_t)atomic_read(&dev_priv->mksstat_user_pids[i]); in vmw_mksstat_remove_all()
921 const pid_t pid1 = atomic_cmpxchg(&dev_priv->mksstat_user_pids[i], pid0, MKSSTAT_PID_RESERVED); in vmw_mksstat_remove_all()
927 struct page *const page = dev_priv->mksstat_user_pages[i]; in vmw_mksstat_remove_all()
931 dev_priv->mksstat_user_pages[i] = NULL; in vmw_mksstat_remove_all()
932 atomic_set(&dev_priv->mksstat_user_pids[i], 0); in vmw_mksstat_remove_all()
939 ret = -EAGAIN; in vmw_mksstat_remove_all()
943 /* Discard all kernel-internal instance descriptors and free all related pages */ in vmw_mksstat_remove_all()
944 for (i = 0; i < ARRAY_SIZE(dev_priv->mksstat_kern_pids); ++i) { in vmw_mksstat_remove_all()
945 const pid_t pid0 = (pid_t)atomic_read(&dev_priv->mksstat_kern_pids[i]); in vmw_mksstat_remove_all()
951 const pid_t pid1 = atomic_cmpxchg(&dev_priv->mksstat_kern_pids[i], pid0, MKSSTAT_PID_RESERVED); in vmw_mksstat_remove_all()
957 struct page *const page = dev_priv->mksstat_kern_pages[i]; in vmw_mksstat_remove_all()
961 dev_priv->mksstat_kern_pages[i] = NULL; in vmw_mksstat_remove_all()
962 atomic_set(&dev_priv->mksstat_kern_pids[i], 0); in vmw_mksstat_remove_all()
969 ret = -EAGAIN; in vmw_mksstat_remove_all()
997 * vmw_mksstat_add_ioctl: Creates a single userspace-originating mksGuestStat
1000 * Create a hypervisor PFN mapping, containing a single mksGuestStat instance
1019 const size_t num_pages_stat = PFN_UP(arg->stat_len); in vmw_mksstat_add_ioctl()
1020 const size_t num_pages_info = PFN_UP(arg->info_len); in vmw_mksstat_add_ioctl()
1021 const size_t num_pages_strs = PFN_UP(arg->strs_len); in vmw_mksstat_add_ioctl()
1026 struct page *pages_stat[ARRAY_SIZE(pdesc->statPPNs)]; in vmw_mksstat_add_ioctl()
1027 struct page *pages_info[ARRAY_SIZE(pdesc->infoPPNs)]; in vmw_mksstat_add_ioctl()
1028 struct page *pages_strs[ARRAY_SIZE(pdesc->strsPPNs)]; in vmw_mksstat_add_ioctl()
1031 arg->id = -1; in vmw_mksstat_add_ioctl()
1033 if (!arg->stat || !arg->info || !arg->strs) in vmw_mksstat_add_ioctl()
1034 return -EINVAL; in vmw_mksstat_add_ioctl()
1036 if (!arg->stat_len || !arg->info_len || !arg->strs_len) in vmw_mksstat_add_ioctl()
1037 return -EINVAL; in vmw_mksstat_add_ioctl()
1039 if (!arg->description) in vmw_mksstat_add_ioctl()
1040 return -EINVAL; in vmw_mksstat_add_ioctl()
1042 if (num_pages_stat > ARRAY_SIZE(pdesc->statPPNs) || in vmw_mksstat_add_ioctl()
1043 num_pages_info > ARRAY_SIZE(pdesc->infoPPNs) || in vmw_mksstat_add_ioctl()
1044 num_pages_strs > ARRAY_SIZE(pdesc->strsPPNs)) in vmw_mksstat_add_ioctl()
1045 return -EINVAL; in vmw_mksstat_add_ioctl()
1048 for (slot = 0; slot < ARRAY_SIZE(dev_priv->mksstat_user_pids); ++slot) in vmw_mksstat_add_ioctl()
1049 if (!atomic_cmpxchg(&dev_priv->mksstat_user_pids[slot], 0, MKSSTAT_PID_RESERVED)) in vmw_mksstat_add_ioctl()
1052 if (slot == ARRAY_SIZE(dev_priv->mksstat_user_pids)) in vmw_mksstat_add_ioctl()
1053 return -ENOSPC; in vmw_mksstat_add_ioctl()
1055 BUG_ON(dev_priv->mksstat_user_pages[slot]); in vmw_mksstat_add_ioctl()
1061 atomic_set(&dev_priv->mksstat_user_pids[slot], 0); in vmw_mksstat_add_ioctl()
1062 return -ENOMEM; in vmw_mksstat_add_ioctl()
1068 pdesc->reservedMBZ = 0; in vmw_mksstat_add_ioctl()
1069 pdesc->statStartVA = arg->stat; in vmw_mksstat_add_ioctl()
1070 pdesc->strsStartVA = arg->strs; in vmw_mksstat_add_ioctl()
1071 pdesc->statLength = arg->stat_len; in vmw_mksstat_add_ioctl()
1072 pdesc->infoLength = arg->info_len; in vmw_mksstat_add_ioctl()
1073 pdesc->strsLength = arg->strs_len; in vmw_mksstat_add_ioctl()
1074 desc_len = strncpy_from_user(pdesc->description, u64_to_user_ptr(arg->description), in vmw_mksstat_add_ioctl()
1075 ARRAY_SIZE(pdesc->description) - 1); in vmw_mksstat_add_ioctl()
1078 atomic_set(&dev_priv->mksstat_user_pids[slot], 0); in vmw_mksstat_add_ioctl()
1080 return -EFAULT; in vmw_mksstat_add_ioctl()
1083 reset_ppn_array(pdesc->statPPNs, ARRAY_SIZE(pdesc->statPPNs)); in vmw_mksstat_add_ioctl()
1084 reset_ppn_array(pdesc->infoPPNs, ARRAY_SIZE(pdesc->infoPPNs)); in vmw_mksstat_add_ioctl()
1085 reset_ppn_array(pdesc->strsPPNs, ARRAY_SIZE(pdesc->strsPPNs)); in vmw_mksstat_add_ioctl()
1088 nr_pinned_stat = pin_user_pages_fast(arg->stat, num_pages_stat, FOLL_LONGTERM, pages_stat); in vmw_mksstat_add_ioctl()
1093 pdesc->statPPNs[i] = page_to_pfn(pages_stat[i]); in vmw_mksstat_add_ioctl()
1095 nr_pinned_info = pin_user_pages_fast(arg->info, num_pages_info, FOLL_LONGTERM, pages_info); in vmw_mksstat_add_ioctl()
1100 pdesc->infoPPNs[i] = page_to_pfn(pages_info[i]); in vmw_mksstat_add_ioctl()
1102 nr_pinned_strs = pin_user_pages_fast(arg->strs, num_pages_strs, FOLL_LONGTERM, pages_strs); in vmw_mksstat_add_ioctl()
1107 pdesc->strsPPNs[i] = page_to_pfn(pages_strs[i]); in vmw_mksstat_add_ioctl()
1114 dev_priv->mksstat_user_pages[slot] = page; in vmw_mksstat_add_ioctl()
1115 atomic_set(&dev_priv->mksstat_user_pids[slot], task_pgrp_vnr(current)); in vmw_mksstat_add_ioctl()
1117 arg->id = slot; in vmw_mksstat_add_ioctl()
1119 …DRM_DEV_INFO(dev->dev, "pid=%d arg.description='%.*s' id=%zu\n", current->pid, (int)desc_len, pdes… in vmw_mksstat_add_ioctl()
1135 atomic_set(&dev_priv->mksstat_user_pids[slot], 0); in vmw_mksstat_add_ioctl()
1137 return -ENOMEM; in vmw_mksstat_add_ioctl()
1141 * vmw_mksstat_remove_ioctl: Removes a single userspace-originating mksGuestStat
1144 * Discard a hypervisor PFN mapping, containing a single mksGuestStat instance
1161 const size_t slot = arg->id; in vmw_mksstat_remove_ioctl()
1164 if (slot >= ARRAY_SIZE(dev_priv->mksstat_user_pids)) in vmw_mksstat_remove_ioctl()
1165 return -EINVAL; in vmw_mksstat_remove_ioctl()
1167 DRM_DEV_INFO(dev->dev, "pid=%d arg.id=%zu\n", current->pid, slot); in vmw_mksstat_remove_ioctl()
1170 pid = atomic_cmpxchg(&dev_priv->mksstat_user_pids[slot], pgid, MKSSTAT_PID_RESERVED); in vmw_mksstat_remove_ioctl()
1176 struct page *const page = dev_priv->mksstat_user_pages[slot]; in vmw_mksstat_remove_ioctl()
1180 dev_priv->mksstat_user_pages[slot] = NULL; in vmw_mksstat_remove_ioctl()
1181 atomic_set(&dev_priv->mksstat_user_pids[slot], 0); in vmw_mksstat_remove_ioctl()
1189 return -EAGAIN; in vmw_mksstat_remove_ioctl()