blob: 62222189906b8860a43e9150c4b036711abd136a [file] [log] [blame]
Zhi Wang12d14cc2016-08-30 11:06:17 +08001/*
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
56unsigned 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
66bool intel_gvt_match_device(struct intel_gvt *gvt,
67 unsigned long device)
68{
69 return intel_gvt_get_device_type(gvt) & device;
70}
71
72static 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
153static 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
161static 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 */
179struct 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 */
201void 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 */
224int 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;
244err:
245 intel_gvt_clean_mmio_info(gvt);
246 return ret;
247}