Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1/*
  2 * Copyright(c) 2011-2017 Intel Corporation. All rights reserved.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a
  5 * copy of this software and associated documentation files (the "Software"),
  6 * to deal in the Software without restriction, including without limitation
  7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 * and/or sell copies of the Software, and to permit persons to whom the
  9 * Software is furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice (including the next
 12 * paragraph) shall be included in all copies or substantial portions of the
 13 * Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21 * SOFTWARE.
 22 */
 23#include "i915_drv.h"
 24#include "gvt.h"
 25
 26/**
 27 * intel_vgpu_find_page_track - find page track rcord of guest page
 28 * @vgpu: a vGPU
 29 * @gfn: the gfn of guest page
 30 *
 31 * Returns:
 32 * A pointer to struct intel_vgpu_page_track if found, else NULL returned.
 33 */
 34struct intel_vgpu_page_track *intel_vgpu_find_page_track(
 35		struct intel_vgpu *vgpu, unsigned long gfn)
 36{
 37	return radix_tree_lookup(&vgpu->page_track_tree, gfn);
 38}
 39
 40/**
 41 * intel_vgpu_register_page_track - register a guest page to be tacked
 42 * @vgpu: a vGPU
 43 * @gfn: the gfn of guest page
 44 * @handler: page track handler
 45 * @priv: tracker private
 46 *
 47 * Returns:
 48 * zero on success, negative error code if failed.
 49 */
 50int intel_vgpu_register_page_track(struct intel_vgpu *vgpu, unsigned long gfn,
 51		gvt_page_track_handler_t handler, void *priv)
 52{
 53	struct intel_vgpu_page_track *track;
 54	int ret;
 55
 56	track = intel_vgpu_find_page_track(vgpu, gfn);
 57	if (track)
 58		return -EEXIST;
 59
 60	track = kzalloc(sizeof(*track), GFP_KERNEL);
 61	if (!track)
 62		return -ENOMEM;
 63
 64	track->handler = handler;
 65	track->priv_data = priv;
 66
 67	ret = radix_tree_insert(&vgpu->page_track_tree, gfn, track);
 68	if (ret) {
 69		kfree(track);
 70		return ret;
 71	}
 72
 73	return 0;
 74}
 75
 76/**
 77 * intel_vgpu_unregister_page_track - unregister the tracked guest page
 78 * @vgpu: a vGPU
 79 * @gfn: the gfn of guest page
 80 *
 81 */
 82void intel_vgpu_unregister_page_track(struct intel_vgpu *vgpu,
 83		unsigned long gfn)
 84{
 85	struct intel_vgpu_page_track *track;
 86
 87	track = radix_tree_delete(&vgpu->page_track_tree, gfn);
 88	if (track) {
 89		if (track->tracked)
 90			intel_gvt_hypervisor_disable_page_track(vgpu, gfn);
 91		kfree(track);
 92	}
 93}
 94
 95/**
 96 * intel_vgpu_enable_page_track - set write-protection on guest page
 97 * @vgpu: a vGPU
 98 * @gfn: the gfn of guest page
 99 *
100 * Returns:
101 * zero on success, negative error code if failed.
102 */
103int intel_vgpu_enable_page_track(struct intel_vgpu *vgpu, unsigned long gfn)
104{
105	struct intel_vgpu_page_track *track;
106	int ret;
107
108	track = intel_vgpu_find_page_track(vgpu, gfn);
109	if (!track)
110		return -ENXIO;
111
112	if (track->tracked)
113		return 0;
114
115	ret = intel_gvt_hypervisor_enable_page_track(vgpu, gfn);
116	if (ret)
117		return ret;
118	track->tracked = true;
119	return 0;
120}
121
122/**
123 * intel_vgpu_enable_page_track - cancel write-protection on guest page
124 * @vgpu: a vGPU
125 * @gfn: the gfn of guest page
126 *
127 * Returns:
128 * zero on success, negative error code if failed.
129 */
130int intel_vgpu_disable_page_track(struct intel_vgpu *vgpu, unsigned long gfn)
131{
132	struct intel_vgpu_page_track *track;
133	int ret;
134
135	track = intel_vgpu_find_page_track(vgpu, gfn);
136	if (!track)
137		return -ENXIO;
138
139	if (!track->tracked)
140		return 0;
141
142	ret = intel_gvt_hypervisor_disable_page_track(vgpu, gfn);
143	if (ret)
144		return ret;
145	track->tracked = false;
146	return 0;
147}
148
149/**
150 * intel_vgpu_page_track_handler - called when write to write-protected page
151 * @vgpu: a vGPU
152 * @gpa: the gpa of this write
153 * @data: the writed data
154 * @bytes: the length of this write
155 *
156 * Returns:
157 * zero on success, negative error code if failed.
158 */
159int intel_vgpu_page_track_handler(struct intel_vgpu *vgpu, u64 gpa,
160		void *data, unsigned int bytes)
161{
162	struct intel_vgpu_page_track *page_track;
163	int ret = 0;
164
165	mutex_lock(&vgpu->vgpu_lock);
166
167	page_track = intel_vgpu_find_page_track(vgpu, gpa >> PAGE_SHIFT);
168	if (!page_track) {
169		ret = -ENXIO;
170		goto out;
171	}
172
173	if (unlikely(vgpu->failsafe)) {
174		/* Remove write protection to prevent furture traps. */
175		intel_vgpu_disable_page_track(vgpu, gpa >> PAGE_SHIFT);
176	} else {
177		ret = page_track->handler(page_track, gpa, data, bytes);
178		if (ret)
179			gvt_err("guest page write error, gpa %llx\n", gpa);
180	}
181
182out:
183	mutex_unlock(&vgpu->vgpu_lock);
184	return ret;
185}