xref: /linux/drivers/gpu/drm/i915/gvt/handlers.c (revision 12d14cc43b34706283246917329b2182163ba9aa)
1 /*
2  * Copyright(c) 2011-2016 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  * Authors:
24  *    Kevin Tian <kevin.tian@intel.com>
25  *    Eddie Dong <eddie.dong@intel.com>
26  *    Zhiyuan Lv <zhiyuan.lv@intel.com>
27  *
28  * Contributors:
29  *    Min He <min.he@intel.com>
30  *    Tina Zhang <tina.zhang@intel.com>
31  *    Pei Zhang <pei.zhang@intel.com>
32  *    Niu Bing <bing.niu@intel.com>
33  *    Ping Gao <ping.a.gao@intel.com>
34  *    Zhi Wang <zhi.a.wang@intel.com>
35  *
36 
37  */
38 
39 #include "i915_drv.h"
40 
41 /* Register contains RO bits */
42 #define F_RO		(1 << 0)
43 /* Register contains graphics address */
44 #define F_GMADR		(1 << 1)
45 /* Mode mask registers with high 16 bits as the mask bits */
46 #define F_MODE_MASK	(1 << 2)
47 /* This reg can be accessed by GPU commands */
48 #define F_CMD_ACCESS	(1 << 3)
49 /* This reg has been accessed by a VM */
50 #define F_ACCESSED	(1 << 4)
51 /* This reg has been accessed through GPU commands */
52 #define F_CMD_ACCESSED	(1 << 5)
53 /* This reg could be accessed by unaligned address */
54 #define F_UNALIGN	(1 << 6)
55 
56 unsigned long intel_gvt_get_device_type(struct intel_gvt *gvt)
57 {
58 	if (IS_BROADWELL(gvt->dev_priv))
59 		return D_BDW;
60 	else if (IS_SKYLAKE(gvt->dev_priv))
61 		return D_SKL;
62 
63 	return 0;
64 }
65 
66 bool intel_gvt_match_device(struct intel_gvt *gvt,
67 		unsigned long device)
68 {
69 	return intel_gvt_get_device_type(gvt) & device;
70 }
71 
72 static int new_mmio_info(struct intel_gvt *gvt,
73 		u32 offset, u32 flags, u32 size,
74 		u32 addr_mask, u32 ro_mask, u32 device,
75 		void *read, void *write)
76 {
77 	struct intel_gvt_mmio_info *info, *p;
78 	u32 start, end, i;
79 
80 	if (!intel_gvt_match_device(gvt, device))
81 		return 0;
82 
83 	if (WARN_ON(!IS_ALIGNED(offset, 4)))
84 		return -EINVAL;
85 
86 	start = offset;
87 	end = offset + size;
88 
89 	for (i = start; i < end; i += 4) {
90 		info = kzalloc(sizeof(*info), GFP_KERNEL);
91 		if (!info)
92 			return -ENOMEM;
93 
94 		info->offset = i;
95 		p = intel_gvt_find_mmio_info(gvt, info->offset);
96 		if (p)
97 			gvt_err("dup mmio definition offset %x\n",
98 				info->offset);
99 		info->size = size;
100 		info->length = (i + 4) < end ? 4 : (end - i);
101 		info->addr_mask = addr_mask;
102 		info->device = device;
103 		info->read = read;
104 		info->write = write;
105 		gvt->mmio.mmio_attribute[info->offset / 4] = flags;
106 		INIT_HLIST_NODE(&info->node);
107 		hash_add(gvt->mmio.mmio_info_table, &info->node, info->offset);
108 	}
109 	return 0;
110 }
111 
112 #define MMIO_F(reg, s, f, am, rm, d, r, w) do { \
113 	ret = new_mmio_info(gvt, INTEL_GVT_MMIO_OFFSET(reg), \
114 		f, s, am, rm, d, r, w); \
115 	if (ret) \
116 		return ret; \
117 } while (0)
118 
119 #define MMIO_D(reg, d) \
120 	MMIO_F(reg, 4, 0, 0, 0, d, NULL, NULL)
121 
122 #define MMIO_DH(reg, d, r, w) \
123 	MMIO_F(reg, 4, 0, 0, 0, d, r, w)
124 
125 #define MMIO_DFH(reg, d, f, r, w) \
126 	MMIO_F(reg, 4, f, 0, 0, d, r, w)
127 
128 #define MMIO_GM(reg, d, r, w) \
129 	MMIO_F(reg, 4, F_GMADR, 0xFFFFF000, 0, d, r, w)
130 
131 #define MMIO_RO(reg, d, f, rm, r, w) \
132 	MMIO_F(reg, 4, F_RO | f, 0, rm, d, r, w)
133 
134 #define MMIO_RING_F(prefix, s, f, am, rm, d, r, w) do { \
135 	MMIO_F(prefix(RENDER_RING_BASE), s, f, am, rm, d, r, w); \
136 	MMIO_F(prefix(BLT_RING_BASE), s, f, am, rm, d, r, w); \
137 	MMIO_F(prefix(GEN6_BSD_RING_BASE), s, f, am, rm, d, r, w); \
138 	MMIO_F(prefix(VEBOX_RING_BASE), s, f, am, rm, d, r, w); \
139 } while (0)
140 
141 #define MMIO_RING_D(prefix, d) \
142 	MMIO_RING_F(prefix, 4, 0, 0, 0, d, NULL, NULL)
143 
144 #define MMIO_RING_DFH(prefix, d, f, r, w) \
145 	MMIO_RING_F(prefix, 4, f, 0, 0, d, r, w)
146 
147 #define MMIO_RING_GM(prefix, d, r, w) \
148 	MMIO_RING_F(prefix, 4, F_GMADR, 0xFFFF0000, 0, d, r, w)
149 
150 #define MMIO_RING_RO(prefix, d, f, rm, r, w) \
151 	MMIO_RING_F(prefix, 4, F_RO | f, 0, rm, d, r, w)
152 
153 static int init_generic_mmio_info(struct intel_gvt *gvt)
154 {
155 	int ret;
156 
157 	MMIO_F(0, 0, 0, 0, 0, D_ALL, NULL, NULL);
158 	return 0;
159 }
160 
161 static int init_broadwell_mmio_info(struct intel_gvt *gvt)
162 {
163 	int ret;
164 
165 	MMIO_F(0, 0, 0, 0, 0, D_ALL, NULL, NULL);
166 	return 0;
167 }
168 
169 /**
170  * intel_gvt_find_mmio_info - find MMIO information entry by aligned offset
171  * @gvt: GVT device
172  * @offset: register offset
173  *
174  * This function is used to find the MMIO information entry from hash table
175  *
176  * Returns:
177  * pointer to MMIO information entry, NULL if not exists
178  */
179 struct intel_gvt_mmio_info *intel_gvt_find_mmio_info(struct intel_gvt *gvt,
180 	unsigned int offset)
181 {
182 	struct intel_gvt_mmio_info *e;
183 
184 	WARN_ON(!IS_ALIGNED(offset, 4));
185 
186 	hash_for_each_possible(gvt->mmio.mmio_info_table, e, node, offset) {
187 		if (e->offset == offset)
188 			return e;
189 	}
190 	return NULL;
191 }
192 
193 /**
194  * intel_gvt_clean_mmio_info - clean up MMIO information table for GVT device
195  * @gvt: GVT device
196  *
197  * This function is called at the driver unloading stage, to clean up the MMIO
198  * information table of GVT device
199  *
200  */
201 void intel_gvt_clean_mmio_info(struct intel_gvt *gvt)
202 {
203 	struct hlist_node *tmp;
204 	struct intel_gvt_mmio_info *e;
205 	int i;
206 
207 	hash_for_each_safe(gvt->mmio.mmio_info_table, i, tmp, e, node)
208 		kfree(e);
209 
210 	vfree(gvt->mmio.mmio_attribute);
211 	gvt->mmio.mmio_attribute = NULL;
212 }
213 
214 /**
215  * intel_gvt_setup_mmio_info - setup MMIO information table for GVT device
216  * @gvt: GVT device
217  *
218  * This function is called at the initialization stage, to setup the MMIO
219  * information table for GVT device
220  *
221  * Returns:
222  * zero on success, negative if failed.
223  */
224 int intel_gvt_setup_mmio_info(struct intel_gvt *gvt)
225 {
226 	struct intel_gvt_device_info *info = &gvt->device_info;
227 	struct drm_i915_private *dev_priv = gvt->dev_priv;
228 	int ret;
229 
230 	gvt->mmio.mmio_attribute = vzalloc(info->mmio_size);
231 	if (!gvt->mmio.mmio_attribute)
232 		return -ENOMEM;
233 
234 	ret = init_generic_mmio_info(gvt);
235 	if (ret)
236 		goto err;
237 
238 	if (IS_BROADWELL(dev_priv)) {
239 		ret = init_broadwell_mmio_info(gvt);
240 		if (ret)
241 			goto err;
242 	}
243 	return 0;
244 err:
245 	intel_gvt_clean_mmio_info(gvt);
246 	return ret;
247 }
248